UNPKG

ts-scikit

Version:

A scientific toolkit written in Typescript

391 lines 13.7 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.BoundingSphere = void 0; const utils_1 = require("../utils"); const bounding_box_1 = require("./bounding-box"); const point3_1 = require("./point3"); /** * A bounding sphere. * * A bounding sphere may be empty. An empty sphere contains no points. * A non-empty sphere contains at least one point. Some attributes, * such as the sphere center and radius, are defined only for spheres * that are not empty. * * A bouding sphere may be infinite. An infinite sphere contains all points. */ class BoundingSphere { /** * Constructs a new bounding sphere. * @param x the center x-coordinate. * @param y the center y-coordinate. * @param z the center z-coordinate. * @param r the radius. */ constructor(x, y, z, r) { utils_1.Check.argument(r >= 0.0, 'r >= 0.0'); this._x = x; this._y = y; this._z = z; this._r = r; } /** * Constructs an empty sphere. */ static AsEmpty() { const bs = new BoundingSphere(0, 0, 0, 0); bs.setEmpty(); return bs; } /** * Constructs an infinite sphere. */ static AsInfinite() { const bs = BoundingSphere.AsEmpty(); bs.setInfinite(); return bs; } /** * Constructs a new bounding sphere from a provided center and radius. * @param c the center point. * @param r the radius. */ static FromParameters(c, r) { return new BoundingSphere(c.x, c.y, c.z, r); } /** * Constructs a new bounding sphere from a bounding box. * @param bbox the bounding box. */ static FromBoundingBox(bbox) { const sphere = BoundingSphere.AsEmpty(); sphere.expandBy(bbox); return sphere; } /** * Gets the center of this bounding sphere. */ get center() { return new point3_1.Point3(this._x, this._y, this._z); } /** * Gets the radius fo this bounding sphere. */ get radius() { return this._r; } /** * Determines whether this sphere is infinite or not. */ get isInfinite() { return this._r === Number.POSITIVE_INFINITY; } /** * Determines whether this sphere is empty or not. */ get isEmpty() { return this._r < 0.0; } /** * Expands this bounding sphere to fit the provided feature. * @param b the feature by which to expand this sphere. */ expandBy(b) { if (b instanceof bounding_box_1.BoundingBox) { this.expandByBoundingBox(b); } else if (b instanceof BoundingSphere) { this.expandByBoundingSphere(b); } else if (b instanceof point3_1.Point3) { this.expandByPoint(b); } else if (b instanceof Array) { const n = b.length; if (n > 0) { if (typeof n[0] === 'number') { const xyz = b; utils_1.Check.argument(b.length % 3 === 0, 'number array length divisible by 3'); for (let i = 0; i < n; i += 3) { this.expandByPoint(new point3_1.Point3(xyz[i], xyz[i + 1], xyz[i + 2])); } } else if (b[0] instanceof point3_1.Point3) { for (const point of b) { this.expandByPoint(point); } } } } } /** * Expands the radius of this bounding sphere by a specified feature. * @param b the feature by which to expand this sphere's radius. */ expandRadiusBy(b) { if (b instanceof bounding_box_1.BoundingBox) { this.expandRadiusByBoundingBox(b); } else if (b instanceof BoundingSphere) { this.expandRadiusByBoundingSphere(b); } else if (b instanceof point3_1.Point3) { this.expandRadiusByPoint(b); } } /** * Sets this sphere to an empty sphere. * @returns a reference to this sphere. */ setEmpty() { this._x = 0; this._y = 0; this._z = 0; this._r = -1; return this; } /** * Sets this sphere to an infinite sphere. * @returns a reference to this sphere. */ setInfinite() { this._x = 0; this._y = 0; this._z = 0; this._r = Number.POSITIVE_INFINITY; return this; } /** * Expands this sphere to include the specified bounding sphere. * <p> * Changes only the radius, if necessary, not the center of the sphere. * @param bs the bounding sphere. */ expandRadiusByBoundingSphere(bs) { if (!this.isInfinite) { if (!bs.isInfinite) { if (!bs.isEmpty) { if (!this.isEmpty) { const dx = bs.center.x - this._x, dy = bs.center.y - this._y, dz = bs.center.z - this._z; const d = Math.sqrt(dx * dx + dy * dy + dz * dz); const r = d + bs.radius; if (r > this._r) { this._r = r; } } else { this._r = bs.radius; this._x = bs.center.x; this._y = bs.center.y; this._z = bs.center.z; } } } else { this.setInfinite(); } } } /** * Expands this sphere to include the specified point. * <p> * Expands only the radius, if necessary, not the center of this sphere. * @param p the point. */ expandRadiusByPoint(p) { if (!this.isInfinite) { if (!this.isEmpty) { const dx = p.x - this._x, dy = p.y - this._y, dz = p.z - this._z; const d = Math.sqrt(dx * dx + dy * dy + dz * dz); if (d > this._r) { this._r = d; } } else { this._x = p.x; this._y = p.y; this._z = p.z; this._r = 0.0; } } } /** * Expands this sphere to include the specified bounding box. * <p> * Changes only the radius, if necessary, not the center of this sphere. * @param bbox the bounding box. */ expandRadiusByBoundingBox(bbox) { if (!this.isInfinite) { if (!bbox.isInfinite) { if (!bbox.isEmpty) { const pmin = bbox.min; const pmax = bbox.max; const xmin = pmin.x, ymin = pmin.y, zmin = pmin.z; const xmax = pmax.x, ymax = pmax.y, zmax = pmax.z; if (!this.isEmpty) { for (let i = 0; i < 8; ++i) { const x = ((i & 1) === 0) ? xmin : xmax; const y = ((i & 2) === 0) ? ymin : ymax; const z = ((i & 4) === 0) ? zmin : zmax; this.expandRadiusByPoint(new point3_1.Point3(x, y, z)); } } else { const dx = xmax - xmin, dy = ymax - ymin, dz = zmax - zmin; this._r = 0.5 * Math.sqrt(dx * dx + dy * dy + dz * dz); this._x = 0.5 * (xmin + xmax); this._y = 0.5 * (ymin + ymax); this._z = 0.5 * (zmin + zmax); } } } else { this.setInfinite(); } } } /** * Expands this sphere to include the specified bounding sphere. * <p> * Adjusts the sphere center to minimize any increase in radius. * @param bs */ expandByBoundingSphere(bs) { if (!this.isInfinite) { if (!bs.isInfinite) { if (!bs.isEmpty) { if (!this.isEmpty) { let dx = bs.center.x - this._x, dy = bs.center.y - this._y, dz = bs.center.z - this._z; const d = Math.sqrt(dx * dx + dy * dy + dz * dz); if (d === 0.0 && bs.radius > this._r) { this._r = bs.radius; } else if (d + bs.radius > this._r) { const da = this._r / d; const xa = this._x - dx * da, ya = this._y - dy * da, za = this._z - dz * da; const db = bs.radius / d; const xb = bs.center.x + dx * db, yb = bs.center.y + dy * db, zb = bs.center.z + dz * db; dx = xb - this._x; dy = yb - this._y; dz = zb - this._z; this._r = Math.sqrt(dx * dx + dy * dy + dz * dz); this._x = 0.5 * (xa + xb); this._y = 0.5 * (ya + yb); this._z = 0.5 * (za + zb); } } else { this._r = bs.radius; this._x = bs.center.x; this._y = bs.center.y; this._z = bs.center.z; } } } else { this.setInfinite(); } } } /** * Expands this bounding sphere to include a specified coordinate. * <p> * Adjusts the sphere center to minimize any increase in radius. * @param p the point. */ expandByPoint(p) { if (!this.isInfinite) { if (!this.isEmpty) { const dx = p.x - this._x, dy = p.y - this._y, dz = p.z - this._z; const d = Math.sqrt(dx * dx + dy * dy + dz * dz); if (d > this._r) { const dr = 0.5 * (d - this._r); const ds = dr / d; this._x += dx * ds; this._y += dy * ds; this._z += dz * ds; this._r += dr; } } else { this._x = p.x; this._y = p.y; this._z = p.z; this._r = 0.0; } } } /** * Expands this sphere to include the specified bounding box. * <p> * Adjusts the sphere center to minimize any increase in radius. * @param bbox the bounding box. */ expandByBoundingBox(bbox) { if (!this.isInfinite) { if (!bbox.isInfinite) { if (!bbox.isEmpty) { let xmin = bbox.xmin; let ymin = bbox.ymin; let zmin = bbox.zmin; let xmax = bbox.xmax; let ymax = bbox.ymax; let zmax = bbox.zmax; if (!this.isEmpty) { for (let i = 0; i < 8; i++) { let x = ((i & 1) === 0) ? xmin : xmax; let y = ((i & 2) === 0) ? ymin : ymax; let z = ((i & 4) === 0) ? zmin : zmax; const dx = x - this._x; const dy = y - this._y; const dz = z - this._z; const d = Math.sqrt(dx * dx + dy * dy + dz * dz); const ds = (d > 0.0) ? this._r / d : this._r; x = this._x - dx * ds; y = this._y - dy * ds; z = this._z - dz * ds; if (x < xmin) { xmin = x; } if (y < ymin) { ymin = y; } if (z < zmin) { zmin = z; } if (x > xmax) { xmax = x; } if (y > ymax) { ymax = y; } if (z > zmax) { zmax = z; } } } const dx = xmax - xmin; const dy = ymax - ymin; const dz = zmax - zmin; this._r = 0.5 * Math.sqrt(dx * dx + dy * dy + dz * dz); this._x = 0.5 * (xmin + xmax); this._y = 0.5 * (ymin + ymax); this._z = 0.5 * (zmin + zmax); } } else { this.setInfinite(); } } } /** * Determines whether this sphere contains the specified point. * @param p the point. * @returns true, if this sphere contains the point; false, otherwise. */ contains(p) { if (this.isEmpty) { return false; } if (this.isInfinite) { return true; } const dx = this._x - p.x, dy = this._y - p.y, dz = this._z - p.z, rs = this._r * this._r; return dx * dx + dy * dy + dz * dz <= rs; } } exports.BoundingSphere = BoundingSphere; //# sourceMappingURL=bounding-sphere.js.map