UNPKG

@jscad/modeling

Version:

Constructive Solid Geometry (CSG) Library for JSCAD

147 lines (119 loc) 4.38 kB
const flatten = require('../utils/flatten') const vec2 = require('../maths/vec2') const vec3 = require('../maths/vec3') const geom2 = require('../geometries/geom2') const geom3 = require('../geometries/geom3') const path2 = require('../geometries/path2') const poly3 = require('../geometries/poly3') const cacheOfBoundingSpheres = new WeakMap() /* * Measure the bounding sphere of the given (path2) geometry. * @return {[[x, y, z], radius]} the bounding sphere for the geometry */ const measureBoundingSphereOfPath2 = (geometry) => { let boundingSphere = cacheOfBoundingSpheres.get(geometry) if (boundingSphere !== undefined) return boundingSphere const centroid = vec3.create() let radius = 0 const points = path2.toPoints(geometry) if (points.length > 0) { // calculate the centroid of the geometry let numPoints = 0 const temp = vec3.create() points.forEach((point) => { vec3.add(centroid, centroid, vec3.fromVec2(temp, point, 0)) numPoints++ }) vec3.scale(centroid, centroid, 1 / numPoints) // find the farthest point from the centroid points.forEach((point) => { radius = Math.max(radius, vec2.squaredDistance(centroid, point)) }) radius = Math.sqrt(radius) } boundingSphere = [centroid, radius] cacheOfBoundingSpheres.set(geometry, boundingSphere) return boundingSphere } /* * Measure the bounding sphere of the given (geom2) geometry. * @return {[[x, y, z], radius]} the bounding sphere for the geometry */ const measureBoundingSphereOfGeom2 = (geometry) => { let boundingSphere = cacheOfBoundingSpheres.get(geometry) if (boundingSphere !== undefined) return boundingSphere const centroid = vec3.create() let radius = 0 const sides = geom2.toSides(geometry) if (sides.length > 0) { // calculate the centroid of the geometry let numPoints = 0 const temp = vec3.create() sides.forEach((side) => { vec3.add(centroid, centroid, vec3.fromVec2(temp, side[0], 0)) numPoints++ }) vec3.scale(centroid, centroid, 1 / numPoints) // find the farthest point from the centroid sides.forEach((side) => { radius = Math.max(radius, vec2.squaredDistance(centroid, side[0])) }) radius = Math.sqrt(radius) } boundingSphere = [centroid, radius] cacheOfBoundingSpheres.set(geometry, boundingSphere) return boundingSphere } /* * Measure the bounding sphere of the given (geom3) geometry. * @return {[[x, y, z], radius]} the bounding sphere for the geometry */ const measureBoundingSphereOfGeom3 = (geometry) => { let boundingSphere = cacheOfBoundingSpheres.get(geometry) if (boundingSphere !== undefined) return boundingSphere const centroid = vec3.create() let radius = 0 const polygons = geom3.toPolygons(geometry) if (polygons.length > 0) { // calculate the centroid of the geometry let numPoints = 0 polygons.forEach((polygon) => { poly3.toPoints(polygon).forEach((point) => { vec3.add(centroid, centroid, point) numPoints++ }) }) vec3.scale(centroid, centroid, 1 / numPoints) // find the farthest point from the centroid polygons.forEach((polygon) => { poly3.toPoints(polygon).forEach((point) => { radius = Math.max(radius, vec3.squaredDistance(centroid, point)) }) }) radius = Math.sqrt(radius) } boundingSphere = [centroid, radius] cacheOfBoundingSpheres.set(geometry, boundingSphere) return boundingSphere } /** * Measure the (approximate) bounding sphere of the given geometries. * @see https://en.wikipedia.org/wiki/Bounding_sphere * @param {...Object} geometries - the geometries to measure * @return {Array} the bounding sphere for each geometry, i.e. [centroid, radius] * @alias module:modeling/measurements.measureBoundingSphere * * @example * let bounds = measureBoundingSphere(cube()) */ const measureBoundingSphere = (...geometries) => { geometries = flatten(geometries) const results = geometries.map((geometry) => { if (path2.isA(geometry)) return measureBoundingSphereOfPath2(geometry) if (geom2.isA(geometry)) return measureBoundingSphereOfGeom2(geometry) if (geom3.isA(geometry)) return measureBoundingSphereOfGeom3(geometry) return [[0, 0, 0], 0] }) return results.length === 1 ? results[0] : results } module.exports = measureBoundingSphere