UNPKG

three-bvh-csg

Version:

A fast, flexible, dynamic CSG implementation on top of three-mesh-bvh

1,894 lines (1,560 loc) 164 kB
import { BufferAttribute, Vector3, Ray, Vector2, Vector4, Mesh, Matrix4, Line3, Plane, Triangle, DoubleSide, Matrix3, BufferGeometry, Group, Color, MeshPhongMaterial, MathUtils, LineSegments, LineBasicMaterial, InstancedMesh, SphereGeometry, MeshBasicMaterial } from 'three'; import { MeshBVH, ExtendedTriangle } from 'three-mesh-bvh'; const HASH_WIDTH = 1e-6; const HASH_HALF_WIDTH = HASH_WIDTH * 0.5; const HASH_MULTIPLIER = Math.pow( 10, - Math.log10( HASH_WIDTH ) ); const HASH_ADDITION = HASH_HALF_WIDTH * HASH_MULTIPLIER; function hashNumber( v ) { return ~ ~ ( v * HASH_MULTIPLIER + HASH_ADDITION ); } function hashVertex2( v ) { return `${ hashNumber( v.x ) },${ hashNumber( v.y ) }`; } function hashVertex3( v ) { return `${ hashNumber( v.x ) },${ hashNumber( v.y ) },${ hashNumber( v.z ) }`; } function hashVertex4( v ) { return `${ hashNumber( v.x ) },${ hashNumber( v.y ) },${ hashNumber( v.z ) },${ hashNumber( v.w ) }`; } function hashRay( r ) { return `${ hashVertex3( r.origin ) }-${ hashVertex3( r.direction ) }`; } function toNormalizedRay( v0, v1, target ) { // get a normalized direction target .direction .subVectors( v1, v0 ) .normalize(); // project the origin onto the perpendicular plane that // passes through 0, 0, 0 const scalar = v0.dot( target.direction ); target. origin .copy( v0 ) .addScaledVector( target.direction, - scalar ); return target; } function areSharedArrayBuffersSupported() { return typeof SharedArrayBuffer !== 'undefined'; } function convertToSharedArrayBuffer( array ) { if ( array.buffer instanceof SharedArrayBuffer ) { return array; } const cons = array.constructor; const buffer = array.buffer; const sharedBuffer = new SharedArrayBuffer( buffer.byteLength ); const uintArray = new Uint8Array( buffer ); const sharedUintArray = new Uint8Array( sharedBuffer ); sharedUintArray.set( uintArray, 0 ); return new cons( sharedBuffer ); } function getIndexArray( vertexCount, BufferConstructor = ArrayBuffer ) { if ( vertexCount > 65535 ) { return new Uint32Array( new BufferConstructor( 4 * vertexCount ) ); } else { return new Uint16Array( new BufferConstructor( 2 * vertexCount ) ); } } function ensureIndex( geo, options ) { if ( ! geo.index ) { const vertexCount = geo.attributes.position.count; const BufferConstructor = options.useSharedArrayBuffer ? SharedArrayBuffer : ArrayBuffer; const index = getIndexArray( vertexCount, BufferConstructor ); geo.setIndex( new BufferAttribute( index, 1 ) ); for ( let i = 0; i < vertexCount; i ++ ) { index[ i ] = i; } } } function getVertexCount( geo ) { return geo.index ? geo.index.count : geo.attributes.position.count; } function getTriCount( geo ) { return getVertexCount( geo ) / 3; } const DEGENERATE_EPSILON = 1e-8; const _tempVec = new Vector3(); function toTriIndex( v ) { return ~ ~ ( v / 3 ); } function toEdgeIndex( v ) { return v % 3; } function sortEdgeFunc( a, b ) { return a.start - b.start; } function getProjectedDistance( ray, vec ) { return _tempVec.subVectors( vec, ray.origin ).dot( ray.direction ); } function hasOverlaps( arr ) { arr = [ ...arr ].sort( sortEdgeFunc ); for ( let i = 0, l = arr.length; i < l - 1; i ++ ) { const info0 = arr[ i ]; const info1 = arr[ i + 1 ]; if ( info1.start < info0.end && Math.abs( info1.start - info0.end ) > 1e-5 ) { return true; } } return false; } function getEdgeSetLength( arr ) { let tot = 0; arr.forEach( ( { start, end } ) => tot += end - start ); return tot; } function matchEdges( forward, reverse, disjointConnectivityMap, eps = DEGENERATE_EPSILON ) { forward.sort( sortEdgeFunc ); reverse.sort( sortEdgeFunc ); for ( let i = 0; i < forward.length; i ++ ) { const e0 = forward[ i ]; for ( let o = 0; o < reverse.length; o ++ ) { const e1 = reverse[ o ]; if ( e1.start > e0.end ) { // e2 is completely after e1 // break; // NOTE: there are cases where there are overlaps due to precision issues or // thin / degenerate triangles. Assuming the sibling side has the same issues // we let the matching work here. Long term we should remove the degenerate // triangles before this. } else if ( e0.end < e1.start || e1.end < e0.start ) { // e1 is completely before e2 continue; } else if ( e0.start <= e1.start && e0.end >= e1.end ) { // e1 is larger than and e2 is completely within e1 if ( ! areDistancesDegenerate( e1.end, e0.end ) ) { forward.splice( i + 1, 0, { start: e1.end, end: e0.end, index: e0.index, } ); } e0.end = e1.start; e1.start = 0; e1.end = 0; } else if ( e0.start >= e1.start && e0.end <= e1.end ) { // e2 is larger than and e1 is completely within e2 if ( ! areDistancesDegenerate( e0.end, e1.end ) ) { reverse.splice( o + 1, 0, { start: e0.end, end: e1.end, index: e1.index, } ); } e1.end = e0.start; e0.start = 0; e0.end = 0; } else if ( e0.start <= e1.start && e0.end <= e1.end ) { // e1 overlaps e2 at the beginning const tmp = e0.end; e0.end = e1.start; e1.start = tmp; } else if ( e0.start >= e1.start && e0.end >= e1.end ) { // e1 overlaps e2 at the end const tmp = e1.end; e1.end = e0.start; e0.start = tmp; } else { throw new Error(); } // Add the connectivity information if ( ! disjointConnectivityMap.has( e0.index ) ) { disjointConnectivityMap.set( e0.index, [] ); } if ( ! disjointConnectivityMap.has( e1.index ) ) { disjointConnectivityMap.set( e1.index, [] ); } disjointConnectivityMap .get( e0.index ) .push( e1.index ); disjointConnectivityMap .get( e1.index ) .push( e0.index ); if ( isEdgeDegenerate( e1 ) ) { reverse.splice( o, 1 ); o --; } if ( isEdgeDegenerate( e0 ) ) { // and if we have to remove the current original edge then exit this loop // so we can work on the next one forward.splice( i, 1 ); i --; break; } } } cleanUpEdgeSet( forward ); cleanUpEdgeSet( reverse ); function cleanUpEdgeSet( arr ) { for ( let i = 0; i < arr.length; i ++ ) { if ( isEdgeDegenerate( arr[ i ] ) ) { arr.splice( i, 1 ); i --; } } } function areDistancesDegenerate( start, end ) { return Math.abs( end - start ) < eps; } function isEdgeDegenerate( e ) { return Math.abs( e.end - e.start ) < eps; } } const DIST_EPSILON = 1e-5; const ANGLE_EPSILON = 1e-4; class RaySet { constructor() { this._rays = []; } addRay( ray ) { this._rays.push( ray ); } findClosestRay( ray ) { const rays = this._rays; const inv = ray.clone(); inv.direction.multiplyScalar( - 1 ); let bestScore = Infinity; let bestRay = null; for ( let i = 0, l = rays.length; i < l; i ++ ) { const r = rays[ i ]; if ( skipRay( r, ray ) && skipRay( r, inv ) ) { continue; } const rayScore = scoreRays( r, ray ); const invScore = scoreRays( r, inv ); const score = Math.min( rayScore, invScore ); if ( score < bestScore ) { bestScore = score; bestRay = r; } } return bestRay; function skipRay( r0, r1 ) { const distOutOfThreshold = r0.origin.distanceTo( r1.origin ) > DIST_EPSILON; const angleOutOfThreshold = r0.direction.angleTo( r1.direction ) > ANGLE_EPSILON; return angleOutOfThreshold || distOutOfThreshold; } function scoreRays( r0, r1 ) { const originDistance = r0.origin.distanceTo( r1.origin ); const angleDistance = r0.direction.angleTo( r1.direction ); return originDistance / DIST_EPSILON + angleDistance / ANGLE_EPSILON; } } } const _v0 = new Vector3(); const _v1 = new Vector3(); const _ray$2 = new Ray(); function computeDisjointEdges( geometry, unmatchedSet, eps, ) { const attributes = geometry.attributes; const indexAttr = geometry.index; const posAttr = attributes.position; const disjointConnectivityMap = new Map(); const fragmentMap = new Map(); const edges = Array.from( unmatchedSet ); const rays = new RaySet(); for ( let i = 0, l = edges.length; i < l; i ++ ) { // get the triangle edge const index = edges[ i ]; const triIndex = toTriIndex( index ); const edgeIndex = toEdgeIndex( index ); let i0 = 3 * triIndex + edgeIndex; let i1 = 3 * triIndex + ( edgeIndex + 1 ) % 3; if ( indexAttr ) { i0 = indexAttr.getX( i0 ); i1 = indexAttr.getX( i1 ); } _v0.fromBufferAttribute( posAttr, i0 ); _v1.fromBufferAttribute( posAttr, i1 ); // get the ray corresponding to the edge toNormalizedRay( _v0, _v1, _ray$2 ); // find the shared ray with other edges let info; let commonRay = rays.findClosestRay( _ray$2 ); if ( commonRay === null ) { commonRay = _ray$2.clone(); rays.addRay( commonRay ); } if ( ! fragmentMap.has( commonRay ) ) { fragmentMap.set( commonRay, { forward: [], reverse: [], ray: commonRay, } ); } info = fragmentMap.get( commonRay ); // store the stride of edge endpoints along the ray let start = getProjectedDistance( commonRay, _v0 ); let end = getProjectedDistance( commonRay, _v1 ); if ( start > end ) { [ start, end ] = [ end, start ]; } if ( _ray$2.direction.dot( commonRay.direction ) < 0 ) { info.reverse.push( { start, end, index } ); } else { info.forward.push( { start, end, index } ); } } // match the found sibling edges fragmentMap.forEach( ( { forward, reverse }, ray ) => { matchEdges( forward, reverse, disjointConnectivityMap, eps ); if ( forward.length === 0 && reverse.length === 0 ) { fragmentMap.delete( ray ); } } ); return { disjointConnectivityMap, fragmentMap, }; } const _vec2$2 = new Vector2(); const _vec3$1 = new Vector3(); const _vec4$1 = new Vector4(); const _hashes = [ '', '', '' ]; class HalfEdgeMap { constructor() { // result data this.data = null; this.disjointConnections = null; this.unmatchedDisjointEdges = null; this.unmatchedEdges = - 1; this.matchedEdges = - 1; // options this.useDrawRange = true; this.useAllAttributes = false; this.matchDisjointEdges = false; this.degenerateEpsilon = 1e-8; } getSiblingTriangleIndex( triIndex, edgeIndex ) { const otherIndex = this.data[ triIndex * 3 + edgeIndex ]; return otherIndex === - 1 ? - 1 : ~ ~ ( otherIndex / 3 ); } getSiblingEdgeIndex( triIndex, edgeIndex ) { const otherIndex = this.data[ triIndex * 3 + edgeIndex ]; return otherIndex === - 1 ? - 1 : ( otherIndex % 3 ); } getDisjointSiblingTriangleIndices( triIndex, edgeIndex ) { const index = triIndex * 3 + edgeIndex; const arr = this.disjointConnections.get( index ); return arr ? arr.map( i => ~ ~ ( i / 3 ) ) : []; } getDisjointSiblingEdgeIndices( triIndex, edgeIndex ) { const index = triIndex * 3 + edgeIndex; const arr = this.disjointConnections.get( index ); return arr ? arr.map( i => i % 3 ) : []; } isFullyConnected() { return this.unmatchedEdges === 0; } updateFrom( geometry ) { const { useAllAttributes, useDrawRange, matchDisjointEdges, degenerateEpsilon } = this; const hashFunction = useAllAttributes ? hashAllAttributes : hashPositionAttribute; // runs on the assumption that there is a 1 : 1 match of edges const map = new Map(); // attributes const { attributes } = geometry; const attrKeys = useAllAttributes ? Object.keys( attributes ) : null; const indexAttr = geometry.index; const posAttr = attributes.position; // get the potential number of triangles let triCount = getTriCount( geometry ); const maxTriCount = triCount; // get the real number of triangles from the based on the draw range let offset = 0; if ( useDrawRange ) { offset = geometry.drawRange.start; if ( geometry.drawRange.count !== Infinity ) { triCount = ~ ~ ( geometry.drawRange.count / 3 ); } } // initialize the connectivity buffer - 1 means no connectivity let data = this.data; if ( ! data || data.length < 3 * maxTriCount ) { data = new Int32Array( 3 * maxTriCount ); } data.fill( - 1 ); // iterate over all triangles let matchedEdges = 0; let unmatchedSet = new Set(); for ( let i = offset, l = triCount * 3 + offset; i < l; i += 3 ) { const i3 = i; for ( let e = 0; e < 3; e ++ ) { let i0 = i3 + e; if ( indexAttr ) { i0 = indexAttr.getX( i0 ); } _hashes[ e ] = hashFunction( i0 ); } for ( let e = 0; e < 3; e ++ ) { const nextE = ( e + 1 ) % 3; const vh0 = _hashes[ e ]; const vh1 = _hashes[ nextE ]; const reverseHash = `${ vh1 }_${ vh0 }`; if ( map.has( reverseHash ) ) { // create a reference between the two triangles and clear the hash const index = i3 + e; const otherIndex = map.get( reverseHash ); data[ index ] = otherIndex; data[ otherIndex ] = index; map.delete( reverseHash ); matchedEdges += 2; unmatchedSet.delete( otherIndex ); } else { // save the triangle and triangle edge index captured in one value // triIndex = ~ ~ ( i0 / 3 ); // edgeIndex = i0 % 3; const hash = `${ vh0 }_${ vh1 }`; const index = i3 + e; map.set( hash, index ); unmatchedSet.add( index ); } } } if ( matchDisjointEdges ) { const { fragmentMap, disjointConnectivityMap, } = computeDisjointEdges( geometry, unmatchedSet, degenerateEpsilon ); unmatchedSet.clear(); fragmentMap.forEach( ( { forward, reverse } ) => { forward.forEach( ( { index } ) => unmatchedSet.add( index ) ); reverse.forEach( ( { index } ) => unmatchedSet.add( index ) ); } ); this.unmatchedDisjointEdges = fragmentMap; this.disjointConnections = disjointConnectivityMap; matchedEdges = triCount * 3 - unmatchedSet.size; } this.matchedEdges = matchedEdges; this.unmatchedEdges = unmatchedSet.size; this.data = data; function hashPositionAttribute( i ) { _vec3$1.fromBufferAttribute( posAttr, i ); return hashVertex3( _vec3$1 ); } function hashAllAttributes( i ) { let result = ''; for ( let k = 0, l = attrKeys.length; k < l; k ++ ) { const attr = attributes[ attrKeys[ k ] ]; let str; switch ( attr.itemSize ) { case 1: str = hashNumber( attr.getX( i ) ); break; case 2: str = hashVertex2( _vec2$2.fromBufferAttribute( attr, i ) ); break; case 3: str = hashVertex3( _vec3$1.fromBufferAttribute( attr, i ) ); break; case 4: str = hashVertex4( _vec4$1.fromBufferAttribute( attr, i ) ); break; } if ( result !== '' ) { result += '|'; } result += str; } return result; } } } class Brush extends Mesh { constructor( ...args ) { super( ...args ); this.isBrush = true; this._previousMatrix = new Matrix4(); this._previousMatrix.elements.fill( 0 ); this._halfEdges = null; this._boundsTree = null; this._groupIndices = null; this._hash = null; } markUpdated() { this._previousMatrix.copy( this.matrix ); } isDirty() { const { matrix, _previousMatrix } = this; const el1 = matrix.elements; const el2 = _previousMatrix.elements; for ( let i = 0; i < 16; i ++ ) { if ( el1[ i ] !== el2[ i ] ) { return true; } } return false; } prepareGeometry() { // generate shared array buffers const geometry = this.geometry; const attributes = geometry.attributes; const useSharedArrayBuffer = areSharedArrayBuffersSupported(); const index = geometry.index; const posAttr = geometry.attributes.position; const indexHash = index ? `${ index.uuid }_${ index.count }_${ index.version }` : '-1_-1_-1'; const posHash = `${ posAttr.uuid }_${ posAttr.count }_${ posAttr.version }`; const hash = `${ geometry.uuid }_${ indexHash }_${ posHash }`; if ( this._hash === hash ) { return; } this._hash = hash; if ( useSharedArrayBuffer ) { for ( const key in attributes ) { const attribute = attributes[ key ]; if ( attribute.isInterleavedBufferAttribute ) { throw new Error( 'Brush: InterleavedBufferAttributes are not supported.' ); } attribute.array = convertToSharedArrayBuffer( attribute.array ); } } // generate bounds tree geometry.boundsTree = new MeshBVH( geometry, { maxLeafSize: 3, indirect: true, useSharedArrayBuffer } ); // generate half edges if ( ! geometry.halfEdges ) { geometry.halfEdges = new HalfEdgeMap(); } geometry.halfEdges.updateFrom( geometry ); // save group indices for materials const triCount = getTriCount( geometry ); if ( ! geometry.groupIndices || geometry.groupIndices.length !== triCount ) { geometry.groupIndices = new Uint16Array( triCount ); } const array = geometry.groupIndices; const groups = geometry.groups; for ( let i = 0, l = groups.length; i < l; i ++ ) { const { start, count } = groups[ i ]; for ( let g = start / 3, lg = ( start + count ) / 3; g < lg; g ++ ) { array[ g ] = i; } } } disposeCacheData() { const { geometry } = this; geometry.halfEdges = null; geometry.boundsTree = null; geometry.groupIndices = null; } } // Auto-generated ESM bundle of cdt2d var __getOwnPropNames = Object.getOwnPropertyNames; var __commonJS = (cb, mod) => function __require() { return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports; }; // node_modules/binary-search-bounds/search-bounds.js var require_search_bounds = __commonJS({ "node_modules/binary-search-bounds/search-bounds.js"(exports, module) { "use strict"; function ge(a, y, c, l, h) { var i = h + 1; while (l <= h) { var m = l + h >>> 1, x = a[m]; var p = c !== void 0 ? c(x, y) : x - y; if (p >= 0) { i = m; h = m - 1; } else { l = m + 1; } } return i; } function gt(a, y, c, l, h) { var i = h + 1; while (l <= h) { var m = l + h >>> 1, x = a[m]; var p = c !== void 0 ? c(x, y) : x - y; if (p > 0) { i = m; h = m - 1; } else { l = m + 1; } } return i; } function lt(a, y, c, l, h) { var i = l - 1; while (l <= h) { var m = l + h >>> 1, x = a[m]; var p = c !== void 0 ? c(x, y) : x - y; if (p < 0) { i = m; l = m + 1; } else { h = m - 1; } } return i; } function le(a, y, c, l, h) { var i = l - 1; while (l <= h) { var m = l + h >>> 1, x = a[m]; var p = c !== void 0 ? c(x, y) : x - y; if (p <= 0) { i = m; l = m + 1; } else { h = m - 1; } } return i; } function eq(a, y, c, l, h) { while (l <= h) { var m = l + h >>> 1, x = a[m]; var p = c !== void 0 ? c(x, y) : x - y; if (p === 0) { return m; } if (p <= 0) { l = m + 1; } else { h = m - 1; } } return -1; } function norm(a, y, c, l, h, f) { if (typeof c === "function") { return f(a, y, c, l === void 0 ? 0 : l | 0, h === void 0 ? a.length - 1 : h | 0); } return f(a, y, void 0, c === void 0 ? 0 : c | 0, l === void 0 ? a.length - 1 : l | 0); } module.exports = { ge: function(a, y, c, l, h) { return norm(a, y, c, l, h, ge); }, gt: function(a, y, c, l, h) { return norm(a, y, c, l, h, gt); }, lt: function(a, y, c, l, h) { return norm(a, y, c, l, h, lt); }, le: function(a, y, c, l, h) { return norm(a, y, c, l, h, le); }, eq: function(a, y, c, l, h) { return norm(a, y, c, l, h, eq); } }; } }); // node_modules/two-product/two-product.js var require_two_product = __commonJS({ "node_modules/two-product/two-product.js"(exports, module) { "use strict"; module.exports = twoProduct; var SPLITTER = +(Math.pow(2, 27) + 1); function twoProduct(a, b, result) { var x = a * b; var c = SPLITTER * a; var abig = c - a; var ahi = c - abig; var alo = a - ahi; var d = SPLITTER * b; var bbig = d - b; var bhi = d - bbig; var blo = b - bhi; var err1 = x - ahi * bhi; var err2 = err1 - alo * bhi; var err3 = err2 - ahi * blo; var y = alo * blo - err3; if (result) { result[0] = y; result[1] = x; return result; } return [y, x]; } } }); // node_modules/robust-sum/robust-sum.js var require_robust_sum = __commonJS({ "node_modules/robust-sum/robust-sum.js"(exports, module) { "use strict"; module.exports = linearExpansionSum; function scalarScalar(a, b) { var x = a + b; var bv = x - a; var av = x - bv; var br = b - bv; var ar = a - av; var y = ar + br; if (y) { return [y, x]; } return [x]; } function linearExpansionSum(e, f) { var ne = e.length | 0; var nf = f.length | 0; if (ne === 1 && nf === 1) { return scalarScalar(e[0], f[0]); } var n = ne + nf; var g = new Array(n); var count = 0; var eptr = 0; var fptr = 0; var abs = Math.abs; var ei = e[eptr]; var ea = abs(ei); var fi = f[fptr]; var fa = abs(fi); var a, b; if (ea < fa) { b = ei; eptr += 1; if (eptr < ne) { ei = e[eptr]; ea = abs(ei); } } else { b = fi; fptr += 1; if (fptr < nf) { fi = f[fptr]; fa = abs(fi); } } if (eptr < ne && ea < fa || fptr >= nf) { a = ei; eptr += 1; if (eptr < ne) { ei = e[eptr]; ea = abs(ei); } } else { a = fi; fptr += 1; if (fptr < nf) { fi = f[fptr]; fa = abs(fi); } } var x = a + b; var bv = x - a; var y = b - bv; var q0 = y; var q1 = x; var _x, _bv, _av, _br, _ar; while (eptr < ne && fptr < nf) { if (ea < fa) { a = ei; eptr += 1; if (eptr < ne) { ei = e[eptr]; ea = abs(ei); } } else { a = fi; fptr += 1; if (fptr < nf) { fi = f[fptr]; fa = abs(fi); } } b = q0; x = a + b; bv = x - a; y = b - bv; if (y) { g[count++] = y; } _x = q1 + x; _bv = _x - q1; _av = _x - _bv; _br = x - _bv; _ar = q1 - _av; q0 = _ar + _br; q1 = _x; } while (eptr < ne) { a = ei; b = q0; x = a + b; bv = x - a; y = b - bv; if (y) { g[count++] = y; } _x = q1 + x; _bv = _x - q1; _av = _x - _bv; _br = x - _bv; _ar = q1 - _av; q0 = _ar + _br; q1 = _x; eptr += 1; if (eptr < ne) { ei = e[eptr]; } } while (fptr < nf) { a = fi; b = q0; x = a + b; bv = x - a; y = b - bv; if (y) { g[count++] = y; } _x = q1 + x; _bv = _x - q1; _av = _x - _bv; _br = x - _bv; _ar = q1 - _av; q0 = _ar + _br; q1 = _x; fptr += 1; if (fptr < nf) { fi = f[fptr]; } } if (q0) { g[count++] = q0; } if (q1) { g[count++] = q1; } if (!count) { g[count++] = 0; } g.length = count; return g; } } }); // node_modules/two-sum/two-sum.js var require_two_sum = __commonJS({ "node_modules/two-sum/two-sum.js"(exports, module) { "use strict"; module.exports = fastTwoSum; function fastTwoSum(a, b, result) { var x = a + b; var bv = x - a; var av = x - bv; var br = b - bv; var ar = a - av; if (result) { result[0] = ar + br; result[1] = x; return result; } return [ar + br, x]; } } }); // node_modules/robust-scale/robust-scale.js var require_robust_scale = __commonJS({ "node_modules/robust-scale/robust-scale.js"(exports, module) { "use strict"; var twoProduct = require_two_product(); var twoSum = require_two_sum(); module.exports = scaleLinearExpansion; function scaleLinearExpansion(e, scale) { var n = e.length; if (n === 1) { var ts = twoProduct(e[0], scale); if (ts[0]) { return ts; } return [ts[1]]; } var g = new Array(2 * n); var q = [0.1, 0.1]; var t = [0.1, 0.1]; var count = 0; twoProduct(e[0], scale, q); if (q[0]) { g[count++] = q[0]; } for (var i = 1; i < n; ++i) { twoProduct(e[i], scale, t); var pq = q[1]; twoSum(pq, t[0], q); if (q[0]) { g[count++] = q[0]; } var a = t[1]; var b = q[1]; var x = a + b; var bv = x - a; var y = b - bv; q[1] = x; if (y) { g[count++] = y; } } if (q[1]) { g[count++] = q[1]; } if (count === 0) { g[count++] = 0; } g.length = count; return g; } } }); // node_modules/robust-subtract/robust-diff.js var require_robust_diff = __commonJS({ "node_modules/robust-subtract/robust-diff.js"(exports, module) { "use strict"; module.exports = robustSubtract; function scalarScalar(a, b) { var x = a + b; var bv = x - a; var av = x - bv; var br = b - bv; var ar = a - av; var y = ar + br; if (y) { return [y, x]; } return [x]; } function robustSubtract(e, f) { var ne = e.length | 0; var nf = f.length | 0; if (ne === 1 && nf === 1) { return scalarScalar(e[0], -f[0]); } var n = ne + nf; var g = new Array(n); var count = 0; var eptr = 0; var fptr = 0; var abs = Math.abs; var ei = e[eptr]; var ea = abs(ei); var fi = -f[fptr]; var fa = abs(fi); var a, b; if (ea < fa) { b = ei; eptr += 1; if (eptr < ne) { ei = e[eptr]; ea = abs(ei); } } else { b = fi; fptr += 1; if (fptr < nf) { fi = -f[fptr]; fa = abs(fi); } } if (eptr < ne && ea < fa || fptr >= nf) { a = ei; eptr += 1; if (eptr < ne) { ei = e[eptr]; ea = abs(ei); } } else { a = fi; fptr += 1; if (fptr < nf) { fi = -f[fptr]; fa = abs(fi); } } var x = a + b; var bv = x - a; var y = b - bv; var q0 = y; var q1 = x; var _x, _bv, _av, _br, _ar; while (eptr < ne && fptr < nf) { if (ea < fa) { a = ei; eptr += 1; if (eptr < ne) { ei = e[eptr]; ea = abs(ei); } } else { a = fi; fptr += 1; if (fptr < nf) { fi = -f[fptr]; fa = abs(fi); } } b = q0; x = a + b; bv = x - a; y = b - bv; if (y) { g[count++] = y; } _x = q1 + x; _bv = _x - q1; _av = _x - _bv; _br = x - _bv; _ar = q1 - _av; q0 = _ar + _br; q1 = _x; } while (eptr < ne) { a = ei; b = q0; x = a + b; bv = x - a; y = b - bv; if (y) { g[count++] = y; } _x = q1 + x; _bv = _x - q1; _av = _x - _bv; _br = x - _bv; _ar = q1 - _av; q0 = _ar + _br; q1 = _x; eptr += 1; if (eptr < ne) { ei = e[eptr]; } } while (fptr < nf) { a = fi; b = q0; x = a + b; bv = x - a; y = b - bv; if (y) { g[count++] = y; } _x = q1 + x; _bv = _x - q1; _av = _x - _bv; _br = x - _bv; _ar = q1 - _av; q0 = _ar + _br; q1 = _x; fptr += 1; if (fptr < nf) { fi = -f[fptr]; } } if (q0) { g[count++] = q0; } if (q1) { g[count++] = q1; } if (!count) { g[count++] = 0; } g.length = count; return g; } } }); // node_modules/robust-orientation/orientation.js var require_orientation = __commonJS({ "node_modules/robust-orientation/orientation.js"(exports, module) { "use strict"; var twoProduct = require_two_product(); var robustSum = require_robust_sum(); var robustScale = require_robust_scale(); var robustSubtract = require_robust_diff(); var NUM_EXPAND = 5; var EPSILON = 11102230246251565e-32; var ERRBOUND3 = (3 + 16 * EPSILON) * EPSILON; var ERRBOUND4 = (7 + 56 * EPSILON) * EPSILON; function orientation_3(sum, prod, scale, sub) { return function orientation3Exact2(m0, m1, m2) { var p = sum(sum(prod(m1[1], m2[0]), prod(-m2[1], m1[0])), sum(prod(m0[1], m1[0]), prod(-m1[1], m0[0]))); var n = sum(prod(m0[1], m2[0]), prod(-m2[1], m0[0])); var d = sub(p, n); return d[d.length - 1]; }; } function orientation_4(sum, prod, scale, sub) { return function orientation4Exact2(m0, m1, m2, m3) { var p = sum(sum(scale(sum(prod(m2[1], m3[0]), prod(-m3[1], m2[0])), m1[2]), sum(scale(sum(prod(m1[1], m3[0]), prod(-m3[1], m1[0])), -m2[2]), scale(sum(prod(m1[1], m2[0]), prod(-m2[1], m1[0])), m3[2]))), sum(scale(sum(prod(m1[1], m3[0]), prod(-m3[1], m1[0])), m0[2]), sum(scale(sum(prod(m0[1], m3[0]), prod(-m3[1], m0[0])), -m1[2]), scale(sum(prod(m0[1], m1[0]), prod(-m1[1], m0[0])), m3[2])))); var n = sum(sum(scale(sum(prod(m2[1], m3[0]), prod(-m3[1], m2[0])), m0[2]), sum(scale(sum(prod(m0[1], m3[0]), prod(-m3[1], m0[0])), -m2[2]), scale(sum(prod(m0[1], m2[0]), prod(-m2[1], m0[0])), m3[2]))), sum(scale(sum(prod(m1[1], m2[0]), prod(-m2[1], m1[0])), m0[2]), sum(scale(sum(prod(m0[1], m2[0]), prod(-m2[1], m0[0])), -m1[2]), scale(sum(prod(m0[1], m1[0]), prod(-m1[1], m0[0])), m2[2])))); var d = sub(p, n); return d[d.length - 1]; }; } function orientation_5(sum, prod, scale, sub) { return function orientation5Exact(m0, m1, m2, m3, m4) { var p = sum(sum(sum(scale(sum(scale(sum(prod(m3[1], m4[0]), prod(-m4[1], m3[0])), m2[2]), sum(scale(sum(prod(m2[1], m4[0]), prod(-m4[1], m2[0])), -m3[2]), scale(sum(prod(m2[1], m3[0]), prod(-m3[1], m2[0])), m4[2]))), m1[3]), sum(scale(sum(scale(sum(prod(m3[1], m4[0]), prod(-m4[1], m3[0])), m1[2]), sum(scale(sum(prod(m1[1], m4[0]), prod(-m4[1], m1[0])), -m3[2]), scale(sum(prod(m1[1], m3[0]), prod(-m3[1], m1[0])), m4[2]))), -m2[3]), scale(sum(scale(sum(prod(m2[1], m4[0]), prod(-m4[1], m2[0])), m1[2]), sum(scale(sum(prod(m1[1], m4[0]), prod(-m4[1], m1[0])), -m2[2]), scale(sum(prod(m1[1], m2[0]), prod(-m2[1], m1[0])), m4[2]))), m3[3]))), sum(scale(sum(scale(sum(prod(m2[1], m3[0]), prod(-m3[1], m2[0])), m1[2]), sum(scale(sum(prod(m1[1], m3[0]), prod(-m3[1], m1[0])), -m2[2]), scale(sum(prod(m1[1], m2[0]), prod(-m2[1], m1[0])), m3[2]))), -m4[3]), sum(scale(sum(scale(sum(prod(m3[1], m4[0]), prod(-m4[1], m3[0])), m1[2]), sum(scale(sum(prod(m1[1], m4[0]), prod(-m4[1], m1[0])), -m3[2]), scale(sum(prod(m1[1], m3[0]), prod(-m3[1], m1[0])), m4[2]))), m0[3]), scale(sum(scale(sum(prod(m3[1], m4[0]), prod(-m4[1], m3[0])), m0[2]), sum(scale(sum(prod(m0[1], m4[0]), prod(-m4[1], m0[0])), -m3[2]), scale(sum(prod(m0[1], m3[0]), prod(-m3[1], m0[0])), m4[2]))), -m1[3])))), sum(sum(scale(sum(scale(sum(prod(m1[1], m4[0]), prod(-m4[1], m1[0])), m0[2]), sum(scale(sum(prod(m0[1], m4[0]), prod(-m4[1], m0[0])), -m1[2]), scale(sum(prod(m0[1], m1[0]), prod(-m1[1], m0[0])), m4[2]))), m3[3]), sum(scale(sum(scale(sum(prod(m1[1], m3[0]), prod(-m3[1], m1[0])), m0[2]), sum(scale(sum(prod(m0[1], m3[0]), prod(-m3[1], m0[0])), -m1[2]), scale(sum(prod(m0[1], m1[0]), prod(-m1[1], m0[0])), m3[2]))), -m4[3]), scale(sum(scale(sum(prod(m2[1], m3[0]), prod(-m3[1], m2[0])), m1[2]), sum(scale(sum(prod(m1[1], m3[0]), prod(-m3[1], m1[0])), -m2[2]), scale(sum(prod(m1[1], m2[0]), prod(-m2[1], m1[0])), m3[2]))), m0[3]))), sum(scale(sum(scale(sum(prod(m2[1], m3[0]), prod(-m3[1], m2[0])), m0[2]), sum(scale(sum(prod(m0[1], m3[0]), prod(-m3[1], m0[0])), -m2[2]), scale(sum(prod(m0[1], m2[0]), prod(-m2[1], m0[0])), m3[2]))), -m1[3]), sum(scale(sum(scale(sum(prod(m1[1], m3[0]), prod(-m3[1], m1[0])), m0[2]), sum(scale(sum(prod(m0[1], m3[0]), prod(-m3[1], m0[0])), -m1[2]), scale(sum(prod(m0[1], m1[0]), prod(-m1[1], m0[0])), m3[2]))), m2[3]), scale(sum(scale(sum(prod(m1[1], m2[0]), prod(-m2[1], m1[0])), m0[2]), sum(scale(sum(prod(m0[1], m2[0]), prod(-m2[1], m0[0])), -m1[2]), scale(sum(prod(m0[1], m1[0]), prod(-m1[1], m0[0])), m2[2]))), -m3[3]))))); var n = sum(sum(sum(scale(sum(scale(sum(prod(m3[1], m4[0]), prod(-m4[1], m3[0])), m2[2]), sum(scale(sum(prod(m2[1], m4[0]), prod(-m4[1], m2[0])), -m3[2]), scale(sum(prod(m2[1], m3[0]), prod(-m3[1], m2[0])), m4[2]))), m0[3]), scale(sum(scale(sum(prod(m3[1], m4[0]), prod(-m4[1], m3[0])), m0[2]), sum(scale(sum(prod(m0[1], m4[0]), prod(-m4[1], m0[0])), -m3[2]), scale(sum(prod(m0[1], m3[0]), prod(-m3[1], m0[0])), m4[2]))), -m2[3])), sum(scale(sum(scale(sum(prod(m2[1], m4[0]), prod(-m4[1], m2[0])), m0[2]), sum(scale(sum(prod(m0[1], m4[0]), prod(-m4[1], m0[0])), -m2[2]), scale(sum(prod(m0[1], m2[0]), prod(-m2[1], m0[0])), m4[2]))), m3[3]), scale(sum(scale(sum(prod(m2[1], m3[0]), prod(-m3[1], m2[0])), m0[2]), sum(scale(sum(prod(m0[1], m3[0]), prod(-m3[1], m0[0])), -m2[2]), scale(sum(prod(m0[1], m2[0]), prod(-m2[1], m0[0])), m3[2]))), -m4[3]))), sum(sum(scale(sum(scale(sum(prod(m2[1], m4[0]), prod(-m4[1], m2[0])), m1[2]), sum(scale(sum(prod(m1[1], m4[0]), prod(-m4[1], m1[0])), -m2[2]), scale(sum(prod(m1[1], m2[0]), prod(-m2[1], m1[0])), m4[2]))), m0[3]), scale(sum(scale(sum(prod(m2[1], m4[0]), prod(-m4[1], m2[0])), m0[2]), sum(scale(sum(prod(m0[1], m4[0]), prod(-m4[1], m0[0])), -m2[2]), scale(sum(prod(m0[1], m2[0]), prod(-m2[1], m0[0])), m4[2]))), -m1[3])), sum(scale(sum(scale(sum(prod(m1[1], m4[0]), prod(-m4[1], m1[0])), m0[2]), sum(scale(sum(prod(m0[1], m4[0]), prod(-m4[1], m0[0])), -m1[2]), scale(sum(prod(m0[1], m1[0]), prod(-m1[1], m0[0])), m4[2]))), m2[3]), scale(sum(scale(sum(prod(m1[1], m2[0]), prod(-m2[1], m1[0])), m0[2]), sum(scale(sum(prod(m0[1], m2[0]), prod(-m2[1], m0[0])), -m1[2]), scale(sum(prod(m0[1], m1[0]), prod(-m1[1], m0[0])), m2[2]))), -m4[3])))); var d = sub(p, n); return d[d.length - 1]; }; } function orientation(n) { var fn = n === 3 ? orientation_3 : n === 4 ? orientation_4 : orientation_5; return fn(robustSum, twoProduct, robustScale, robustSubtract); } var orientation3Exact = orientation(3); var orientation4Exact = orientation(4); var CACHED = [ function orientation0() { return 0; }, function orientation1() { return 0; }, function orientation2(a, b) { return b[0] - a[0]; }, function orientation3(a, b, c) { var l = (a[1] - c[1]) * (b[0] - c[0]); var r = (a[0] - c[0]) * (b[1] - c[1]); var det = l - r; var s; if (l > 0) { if (r <= 0) { return det; } else { s = l + r; } } else if (l < 0) { if (r >= 0) { return det; } else { s = -(l + r); } } else { return det; } var tol = ERRBOUND3 * s; if (det >= tol || det <= -tol) { return det; } return orientation3Exact(a, b, c); }, function orientation4(a, b, c, d) { var adx = a[0] - d[0]; var bdx = b[0] - d[0]; var cdx = c[0] - d[0]; var ady = a[1] - d[1]; var bdy = b[1] - d[1]; var cdy = c[1] - d[1]; var adz = a[2] - d[2]; var bdz = b[2] - d[2]; var cdz = c[2] - d[2]; var bdxcdy = bdx * cdy; var cdxbdy = cdx * bdy; var cdxady = cdx * ady; var adxcdy = adx * cdy; var adxbdy = adx * bdy; var bdxady = bdx * ady; var det = adz * (bdxcdy - cdxbdy) + bdz * (cdxady - adxcdy) + cdz * (adxbdy - bdxady); var permanent = (Math.abs(bdxcdy) + Math.abs(cdxbdy)) * Math.abs(adz) + (Math.abs(cdxady) + Math.abs(adxcdy)) * Math.abs(bdz) + (Math.abs(adxbdy) + Math.abs(bdxady)) * Math.abs(cdz); var tol = ERRBOUND4 * permanent; if (det > tol || -det > tol) { return det; } return orientation4Exact(a, b, c, d); } ]; function slowOrient(args) { var proc2 = CACHED[args.length]; if (!proc2) { proc2 = CACHED[args.length] = orientation(args.length); } return proc2.apply(void 0, args); } function proc(slow, o0, o1, o2, o3, o4, o5) { return function getOrientation(a0, a1, a2, a3, a4) { switch (arguments.length) { case 0: case 1: return 0; case 2: return o2(a0, a1); case 3: return o3(a0, a1, a2); case 4: return o4(a0, a1, a2, a3); case 5: return o5(a0, a1, a2, a3, a4); } var s = new Array(arguments.length); for (var i = 0; i < arguments.length; ++i) { s[i] = arguments[i]; } return slow(s); }; } function generateOrientationProc() { while (CACHED.length <= NUM_EXPAND) { CACHED.push(orientation(CACHED.length)); } module.exports = proc.apply(void 0, [slowOrient].concat(CACHED)); for (var i = 0; i <= NUM_EXPAND; ++i) { module.exports[i] = CACHED[i]; } } generateOrientationProc(); } }); // node_modules/cdt2d/lib/monotone.js var require_monotone = __commonJS({ "node_modules/cdt2d/lib/monotone.js"(exports, module) { "use strict"; var bsearch = require_search_bounds(); var orient = require_orientation()[3]; var EVENT_POINT = 0; var EVENT_END = 1; var EVENT_START = 2; module.exports = monotoneTriangulate; function PartialHull(a, b, idx, lowerIds, upperIds) { this.a = a; this.b = b; this.idx = idx; this.lowerIds = lowerIds; this.upperIds = upperIds; } function Event(a, b, type, idx) { this.a = a; this.b = b; this.type = type; this.idx = idx; } function compareEvent(a, b) { var d = a.a[0] - b.a[0] || a.a[1] - b.a[1] || a.type - b.type; if (d) { return d; } if (a.type !== EVENT_POINT) { d = orient(a.a, a.b, b.b); if (d) { return d; } } return a.idx - b.idx; } function testPoint(hull, p) { return orient(hull.a, hull.b, p); } function addPoint(cells, hulls, points, p, idx) { var lo = bsearch.lt(hulls, p, testPoint); var hi = bsearch.gt(hulls, p, testPoint); for (var i = lo; i < hi; ++i) { var hull = hulls[i]; var lowerIds = hull.lowerIds; var m = lowerIds.length; while (m > 1 && orient( points[lowerIds[m - 2]], points[lowerIds[m - 1]], p ) > 0) { cells.push( [ lowerIds[m - 1], lowerIds[m - 2], idx ] ); m -= 1; } lowerIds.length = m; lowerIds.push(idx); var upperIds = hull.upperIds; var m = upperIds.length; while (m > 1 && orient( points[upperIds[m - 2]], points[upperIds[m - 1]], p ) < 0) { cells.push( [ upperIds[m - 2], upperIds[m - 1], idx ] ); m -= 1; } upperIds.length = m; upperIds.push(idx); } } function findSplit(hull, edge) { var d; if (hull.a[0] < edge.a[0]) { d = orient(hull.a, hull.b, edge.a); } else { d = orient(edge.b, edge.a, hull.a); } if (d) { return d; } if (edge.b[0] < hull.b[0]) { d = orient(hull.a, hull.b, edge.b); } else { d = orient(edge.b, edge.a, hull.b); } return d || hull.idx - edge.idx; } function splitHulls(hulls, points, event) { var splitIdx = bsearch.le(hulls, event, findSplit); var hull = hulls[splitIdx]; var upperIds = hull.upperIds; var x = upperIds[upperIds.length - 1]; hull.upperIds = [x]; hulls.splice( splitIdx + 1, 0, new PartialHull(event.a, event.b, event.idx, [x], upperIds) ); } function mergeHulls(hulls, points, event) { var tmp = event.a; event.a = event.b; event.b = tmp; var mergeIdx = bsearch.eq(hulls, event, findSplit); var upper = hulls[mergeIdx]; var lower = hulls[mergeIdx - 1]; lower.upperIds = upper.upperIds; hulls.splice(mergeIdx, 1); } function monotoneTriangulate(points, edges) { var numPoints = points.length; var numEdges = edges.length; var events = []; for (var i = 0; i < numPoints; ++i) { events.push(new Event( points[i], null, EVENT_POINT, i )); } for (var i = 0; i < numEdges; ++i) { var e = edges[i]; var a = points[e[0]]; var b = points[e[1]]; if (a[0] < b[0]) { events.push( new Event(a, b, EVENT_START, i), new Event(b, a, EVENT_END, i) ); } else if (a[0] > b[0]) { events.push( new Event(b, a, EVENT_START, i), new Event(a, b, EVENT_END, i) ); } } events.sort(compareEvent); var minX = events[0].a[0] - (1 + Math.abs(events[0].a[0])) * Math.pow(2, -52); var hull = [new PartialHull([minX, 1], [minX, 0], -1, [], [], [], [])]; var cells = []; for (var i = 0, numEvents = events.length; i < numEvents; ++i) { var event = events[i]; var type = event.type; if (type === EVENT_POINT) { addPoint(cells, hull, points, event.a, event.idx); } else if (type === EVENT_START) { splitHulls(hull, points, event); } else { mergeHulls(hull, points, event); } } return cells; } } }); // node_modules/cdt2d/lib/triangulation.js var require_triangulation = __commonJS({ "node_modules/cdt2d/lib/triangulation.js"(exports, module) { "use strict"; var bsearch = require_search_bounds(); module.exports = createTriangulation; function Triangulation(stars, edges) { this.stars = stars; this.edges = edges; } var proto = Triangulation.prototype; function removePair(list, j, k) { for (var i = 1, n = list.length; i < n; i += 2) { if (list[i - 1] === j && list[i] === k) { list[i - 1] = list[n - 2]; list[i] = list[n - 1]; list.length = n - 2; return; } } } proto.isConstraint = /* @__PURE__ */ (function() { var e = [0, 0]; function compareLex(a, b) { return a[0] - b[0] || a[1] - b[1]; } return function(i, j) { e[0] = Math.min(i, j); e[1] = Math.max(i, j); return bsearch.eq(this.edges, e, compareLex) >= 0; }; })(); proto.removeTriangle = function(i, j, k) { var stars = this.stars; removePair(stars[i], j, k); removePair(stars[j], k, i); removePair(stars[k], i, j); }; proto.addTriangle = function(i, j, k) { var stars = this.stars; stars[i].push(j, k); stars[j].push(k, i); stars[k].push(i, j); }; proto.opposite = function(j, i) { var list = this.stars[i]; for (var k = 1, n = list.length; k < n; k += 2) { if (list[k] === j) { return list[k - 1]; } } return -1; }; proto.flip = function(i, j) { var a = this.opposite(i, j); var b = this.opposite(j, i); this.removeTriangle(i, j, a); this.removeTriangle(j, i, b); this.addTriangle(i, b, a); this.addTriangle(j, a, b); }; proto.edges = function() { var stars = this.stars; var result = []; for (var i = 0, n = stars.length; i < n; ++i) { var list = stars[i]; for (var j = 0, m = list.length; j < m; j += 2) { result.push([list[j], list[j + 1]]); } } return result; }; proto.cells = function() { var stars = this.stars; var result = []; for (var i = 0, n = stars.length; i < n; ++i) { var list = stars[i]; for (var j = 0, m = list.length; j < m; j += 2) { var s = list[j]; var t = list[j + 1]; if (i < Math.min(s, t)) { result.push([i, s, t]); } } } return result; }; function createTriangulation(numVerts, edges) { var stars = new Array(numVerts); for (var i = 0; i < numVerts; ++i) { stars[i] = []; } return new Triangulation(stars, edges); } } }); // node_modules/robust-in-sphere/in-sphere.js var require_in_sphere = __commonJS({ "node_modules/robust-in-sphere/in-sphere.js"(exports, module) { "use strict"; var twoProduct = require_two_product(); var robustSum = require_robust_sum(); var robustDiff = require_robust_diff(); var robustScale = require_robust_scale(); var NUM_EXPAND = 6; function orientation(n) { var fn = n === 3 ? inSphere3 : n === 4 ? inSphere4 : n === 5 ? inSphere5 : inSphere6; return fn(robustSum, robustDiff, twoProduct, robustScale); } function inSphere0() { return 0; } function inSphere1() { return 0; } function inSphere2() { return 0; } function inSphere3(sum, diff, prod, scale) { function exactInSphere3(m0, m1, m2) { var w0 = prod(m0[0], m0[0]); var w0m1 = scale(w0, m1[0]); var w0m2 = scale(w0, m2[0]); var w1 = prod(m1[0], m1[0]); var w1m0 = scale(w1, m0[0]); var w1m2 = scale(w1, m2[0]); var w2 = prod(m2[0], m2[0]); var w2m0 = scale(w2, m0[0]); var w2m1 = scale(w2, m1[0]); var p = sum(diff(w2m1, w1m2), diff(w1m0, w0m1)); var n = diff(w2m0, w0m2); var d = diff(p, n); return d[d.length - 1]; } return exactInSphere3; } function inSphere4(sum, diff, prod, scale) { function exactInSphere4(m0, m1, m2, m3) { var w0 = sum(prod(m0[0], m0[0]), prod(m0[1], m0[1])); var w0m1 = scale(w0, m1[0]); var w0m2 = scale(w0, m2[0]); var w0m3 = scale(w0, m3[0]); var w1 = sum(prod(m1[0], m1[0]), prod(m1[1], m1[1])); var w1m0 = scale(w1, m0[0]); var w1m2 = scale(w1, m2[0]); var w1m3 = scale(w1, m3[0]); var w2 = sum(prod(m2[0], m2[0]), prod(m2[1], m2[1])); var w2m0 = scale(w2, m0[0]); var w2m1 = scale(w2, m1[0]); var w2m3 = scale(w2, m3[0]); var w3 = sum(prod(m3[0], m3[0]), prod(m3[1], m3[1])); var w3m0 = scale(w3, m0[0]); var w3m1 = scale(w3, m1[0]); var w3m2 = scale(w3, m2[0]); var p = sum(sum(scale(diff(w3m2, w2m3), m1[1]), sum(scale(diff(w3m1, w1m3), -m2[1]), scale(diff(w2m1, w1m2), m3[1]))), sum(scale(diff(w3m1, w1m3), m0[1]), sum(scale(diff(w3m0, w0m3), -m1[1]), scale(diff(w1m0, w0m1), m3[1])))); var n = sum(sum(scale(diff(w3m2, w2m3), m0[1]), sum(scale(diff(w3m0, w0m3), -m2[1]), scale(diff(w2m0, w0m2), m3[1]))), sum(scale(diff(w2m1, w1m2), m0[1]), sum(scale(diff(w2m0, w0m2), -m1[1]), scale(diff(w1m0, w0m1), m2[1])))); var d = diff(p, n); return d[d.length - 1]; } return exactInSphere4; } function inSphere5(sum, diff, prod, scale) { function exactInSphere5(m0, m1, m2, m3, m4) { var w0 = sum(prod(m0[0], m0[0]), sum(prod(m0[1], m0[1]), prod(m0[2], m0[2]))); var w0m1 = scale(w0, m1[0]); var w0m2 = scale(w0, m2[0]); var w0m3 = scale(w0, m3[0]); var w0m4 = scale(w0, m4[0]); var w1 = sum(prod(m1[0], m1[0]), sum(prod(m1[1], m1[1]), prod(m1[2], m1[2]))); var w1m0 = scale(w1, m0[0]); var w1m2 = scale(w1, m2[0]); var w1m3 = scale(w1, m3[0]); var w1m4 = scale(w1, m4[0]); var w2 = sum(prod(m2[0], m2[0]), sum(prod(m2[1], m2[1]), prod(m2[2], m2[2]))); var w2m0 = scale(w2, m0[0]); var w2m1 = scale(w2, m1[0]); var w2m3 = scale(w2, m3[0]); var w2m4 = scale(w2, m4[0]); var w3 = sum(prod(m3[0], m3[0]), sum(prod(m3[1], m3[1]), prod(m3[2], m3[2]))); var w3m0 = scale(w3, m0[0]); var w3m1 = scale(w3, m1[0]); var w3m2 = scale(w3, m2[0]); var w3m4 = scale(w3, m4[0]); var w4 = sum(prod(m4[0], m4[0]), sum(prod(m4[1], m4[1]), prod(m4[2], m4[2]))); var w4m0 = scale(w4, m0[0]); var w4m1 = scale(w4, m1[0]); var w4m2 = scale(w4, m2[0]); var w4m3 = scale(w4, m3[0]);