UNPKG

three-bvh-csg

Version:

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

1 lines 434 kB
{"version":3,"file":"index.umd.cjs","sources":["../src/core/utils/hashUtils.js","../src/core/utils/geometryUtils.js","../src/core/utils/halfEdgeUtils.js","../src/core/utils/RaySet.js","../src/core/utils/computeDisjointEdges.js","../src/core/HalfEdgeMap.js","../src/core/Brush.js","../src/libs/cdt2d.js","../src/core/utils/Pool.js","../src/core/CDTTriangleSplitter.js","../src/core/utils/triangleUtils.js","../src/core/LegacyTriangleSplitter.js","../src/core/IntersectionMap.js","../src/core/constants.js","../src/core/utils/intersectionUtils.js","../src/core/operations/operationsUtils.js","../src/core/debug/OperationDebugData.js","../src/core/operations/operations.js","../src/core/TypeBackedArray.js","../src/core/operations/GeometryBuilder.js","../src/core/operations/GeometryUtils.js","../src/core/Evaluator.js","../src/core/operations/Operation.js","../src/core/operations/OperationGroup.js","../src/materials/shaderUtils.js","../src/materials/GridMaterial.js","../src/core/debug/debugUtils.js","../src/objects/TriangleSetHelper.js","../src/objects/EdgesHelper.js","../src/objects/PointsHelper.js","../src/objects/HalfEdgeHelper.js","../src/utils/computeMeshVolume.js"],"sourcesContent":["const HASH_WIDTH = 1e-6;\nconst HASH_HALF_WIDTH = HASH_WIDTH * 0.5;\nconst HASH_MULTIPLIER = Math.pow( 10, - Math.log10( HASH_WIDTH ) );\nconst HASH_ADDITION = HASH_HALF_WIDTH * HASH_MULTIPLIER;\nexport function hashNumber( v ) {\n\n\treturn ~ ~ ( v * HASH_MULTIPLIER + HASH_ADDITION );\n\n}\n\nexport function hashVertex2( v ) {\n\n\treturn `${ hashNumber( v.x ) },${ hashNumber( v.y ) }`;\n\n}\n\nexport function hashVertex3( v ) {\n\n\treturn `${ hashNumber( v.x ) },${ hashNumber( v.y ) },${ hashNumber( v.z ) }`;\n\n}\n\nexport function hashVertex4( v ) {\n\n\treturn `${ hashNumber( v.x ) },${ hashNumber( v.y ) },${ hashNumber( v.z ) },${ hashNumber( v.w ) }`;\n\n}\n\nexport function hashRay( r ) {\n\n\treturn `${ hashVertex3( r.origin ) }-${ hashVertex3( r.direction ) }`;\n\n}\n\nexport function toNormalizedRay( v0, v1, target ) {\n\n\t// get a normalized direction\n\ttarget\n\t\t.direction\n\t\t.subVectors( v1, v0 )\n\t\t.normalize();\n\n\t// project the origin onto the perpendicular plane that\n\t// passes through 0, 0, 0\n\tconst scalar = v0.dot( target.direction );\n\ttarget.\n\t\torigin\n\t\t.copy( v0 )\n\t\t.addScaledVector( target.direction, - scalar );\n\n\treturn target;\n\n}\n","import { BufferAttribute } from 'three';\n\nexport function areSharedArrayBuffersSupported() {\n\n\treturn typeof SharedArrayBuffer !== 'undefined';\n\n}\n\nexport function convertToSharedArrayBuffer( array ) {\n\n\tif ( array.buffer instanceof SharedArrayBuffer ) {\n\n\t\treturn array;\n\n\t}\n\n\tconst cons = array.constructor;\n\tconst buffer = array.buffer;\n\tconst sharedBuffer = new SharedArrayBuffer( buffer.byteLength );\n\n\tconst uintArray = new Uint8Array( buffer );\n\tconst sharedUintArray = new Uint8Array( sharedBuffer );\n\tsharedUintArray.set( uintArray, 0 );\n\n\treturn new cons( sharedBuffer );\n\n}\n\nexport function getIndexArray( vertexCount, BufferConstructor = ArrayBuffer ) {\n\n\tif ( vertexCount > 65535 ) {\n\n\t\treturn new Uint32Array( new BufferConstructor( 4 * vertexCount ) );\n\n\t} else {\n\n\t\treturn new Uint16Array( new BufferConstructor( 2 * vertexCount ) );\n\n\t}\n\n}\n\nexport function ensureIndex( geo, options ) {\n\n\tif ( ! geo.index ) {\n\n\t\tconst vertexCount = geo.attributes.position.count;\n\t\tconst BufferConstructor = options.useSharedArrayBuffer ? SharedArrayBuffer : ArrayBuffer;\n\t\tconst index = getIndexArray( vertexCount, BufferConstructor );\n\t\tgeo.setIndex( new BufferAttribute( index, 1 ) );\n\n\t\tfor ( let i = 0; i < vertexCount; i ++ ) {\n\n\t\t\tindex[ i ] = i;\n\n\t\t}\n\n\t}\n\n}\n\nexport function getVertexCount( geo ) {\n\n\treturn geo.index ? geo.index.count : geo.attributes.position.count;\n\n}\n\nexport function getTriCount( geo ) {\n\n\treturn getVertexCount( geo ) / 3;\n\n}\n","import { Vector3 } from 'three';\n\nconst DEGENERATE_EPSILON = 1e-8;\nconst _tempVec = new Vector3();\n\nexport function toTriIndex( v ) {\n\n\treturn ~ ~ ( v / 3 );\n\n}\n\nexport function toEdgeIndex( v ) {\n\n\treturn v % 3;\n\n}\n\nexport function sortEdgeFunc( a, b ) {\n\n\treturn a.start - b.start;\n\n}\n\nexport function getProjectedDistance( ray, vec ) {\n\n\treturn _tempVec.subVectors( vec, ray.origin ).dot( ray.direction );\n\n}\n\nexport function hasOverlaps( arr ) {\n\n\tarr = [ ...arr ].sort( sortEdgeFunc );\n\tfor ( let i = 0, l = arr.length; i < l - 1; i ++ ) {\n\n\t\tconst info0 = arr[ i ];\n\t\tconst info1 = arr[ i + 1 ];\n\n\t\tif ( info1.start < info0.end && Math.abs( info1.start - info0.end ) > 1e-5 ) {\n\n\t\t\treturn true;\n\n\t\t}\n\n\t}\n\n\treturn false;\n\n}\n\nexport function getEdgeSetLength( arr ) {\n\n\tlet tot = 0;\n\tarr.forEach( ( { start, end } ) => tot += end - start );\n\treturn tot;\n\n}\n\nexport function matchEdges( forward, reverse, disjointConnectivityMap, eps = DEGENERATE_EPSILON ) {\n\n\tforward.sort( sortEdgeFunc );\n\treverse.sort( sortEdgeFunc );\n\n\tfor ( let i = 0; i < forward.length; i ++ ) {\n\n\t\tconst e0 = forward[ i ];\n\t\tfor ( let o = 0; o < reverse.length; o ++ ) {\n\n\t\t\tconst e1 = reverse[ o ];\n\t\t\tif ( e1.start > e0.end ) {\n\n\t\t\t\t// e2 is completely after e1\n\t\t\t\t// break;\n\n\t\t\t\t// NOTE: there are cases where there are overlaps due to precision issues or\n\t\t\t\t// thin / degenerate triangles. Assuming the sibling side has the same issues\n\t\t\t\t// we let the matching work here. Long term we should remove the degenerate\n\t\t\t\t// triangles before this.\n\n\t\t\t} else if ( e0.end < e1.start || e1.end < e0.start ) {\n\n\t\t\t\t// e1 is completely before e2\n\t\t\t\tcontinue;\n\n\t\t\t} else if ( e0.start <= e1.start && e0.end >= e1.end ) {\n\n\t\t\t\t// e1 is larger than and e2 is completely within e1\n\t\t\t\tif ( ! areDistancesDegenerate( e1.end, e0.end ) ) {\n\n\t\t\t\t\tforward.splice( i + 1, 0, {\n\t\t\t\t\t\tstart: e1.end,\n\t\t\t\t\t\tend: e0.end,\n\t\t\t\t\t\tindex: e0.index,\n\t\t\t\t\t} );\n\n\t\t\t\t}\n\n\t\t\t\te0.end = e1.start;\n\n\t\t\t\te1.start = 0;\n\t\t\t\te1.end = 0;\n\n\t\t\t} else if ( e0.start >= e1.start && e0.end <= e1.end ) {\n\n\t\t\t\t// e2 is larger than and e1 is completely within e2\n\t\t\t\tif ( ! areDistancesDegenerate( e0.end, e1.end ) ) {\n\n\t\t\t\t\treverse.splice( o + 1, 0, {\n\t\t\t\t\t\tstart: e0.end,\n\t\t\t\t\t\tend: e1.end,\n\t\t\t\t\t\tindex: e1.index,\n\t\t\t\t\t} );\n\n\t\t\t\t}\n\n\t\t\t\te1.end = e0.start;\n\n\t\t\t\te0.start = 0;\n\t\t\t\te0.end = 0;\n\n\t\t\t} else if ( e0.start <= e1.start && e0.end <= e1.end ) {\n\n\t\t\t\t// e1 overlaps e2 at the beginning\n\t\t\t\tconst tmp = e0.end;\n\t\t\t\te0.end = e1.start;\n\t\t\t\te1.start = tmp;\n\n\t\t\t} else if ( e0.start >= e1.start && e0.end >= e1.end ) {\n\n\t\t\t\t// e1 overlaps e2 at the end\n\t\t\t\tconst tmp = e1.end;\n\t\t\t\te1.end = e0.start;\n\t\t\t\te0.start = tmp;\n\n\t\t\t} else {\n\n\t\t\t\tthrow new Error();\n\n\t\t\t}\n\n\t\t\t// Add the connectivity information\n\t\t\tif ( ! disjointConnectivityMap.has( e0.index ) ) {\n\n\t\t\t\tdisjointConnectivityMap.set( e0.index, [] );\n\n\t\t\t}\n\n\t\t\tif ( ! disjointConnectivityMap.has( e1.index ) ) {\n\n\t\t\t\tdisjointConnectivityMap.set( e1.index, [] );\n\n\t\t\t}\n\n\t\t\tdisjointConnectivityMap\n\t\t\t\t.get( e0.index )\n\t\t\t\t.push( e1.index );\n\n\t\t\tdisjointConnectivityMap\n\t\t\t\t.get( e1.index )\n\t\t\t\t.push( e0.index );\n\n\t\t\tif ( isEdgeDegenerate( e1 ) ) {\n\n\t\t\t\treverse.splice( o, 1 );\n\t\t\t\to --;\n\n\t\t\t}\n\n\t\t\tif ( isEdgeDegenerate( e0 ) ) {\n\n\t\t\t\t// and if we have to remove the current original edge then exit this loop\n\t\t\t\t// so we can work on the next one\n\t\t\t\tforward.splice( i, 1 );\n\t\t\t\ti --;\n\t\t\t\tbreak;\n\n\t\t\t}\n\n\t\t}\n\n\t}\n\n\tcleanUpEdgeSet( forward );\n\tcleanUpEdgeSet( reverse );\n\n\tfunction cleanUpEdgeSet( arr ) {\n\n\t\tfor ( let i = 0; i < arr.length; i ++ ) {\n\n\t\t\tif ( isEdgeDegenerate( arr[ i ] ) ) {\n\n\t\t\t\tarr.splice( i, 1 );\n\t\t\t\ti --;\n\n\t\t\t}\n\n\t\t}\n\n\t}\n\n\tfunction areDistancesDegenerate( start, end ) {\n\n\t\treturn Math.abs( end - start ) < eps;\n\n\t}\n\n\tfunction isEdgeDegenerate( e ) {\n\n\t\treturn Math.abs( e.end - e.start ) < eps;\n\n\t}\n\n}\n","const DIST_EPSILON = 1e-5;\nconst ANGLE_EPSILON = 1e-4;\n\nexport class RaySet {\n\n\tconstructor() {\n\n\t\tthis._rays = [];\n\n\t}\n\n\taddRay( ray ) {\n\n\t\tthis._rays.push( ray );\n\n\t}\n\n\tfindClosestRay( ray ) {\n\n\t\tconst rays = this._rays;\n\t\tconst inv = ray.clone();\n\t\tinv.direction.multiplyScalar( - 1 );\n\n\t\tlet bestScore = Infinity;\n\t\tlet bestRay = null;\n\t\tfor ( let i = 0, l = rays.length; i < l; i ++ ) {\n\n\t\t\tconst r = rays[ i ];\n\t\t\tif ( skipRay( r, ray ) && skipRay( r, inv ) ) {\n\n\t\t\t\tcontinue;\n\n\t\t\t}\n\n\t\t\tconst rayScore = scoreRays( r, ray );\n\t\t\tconst invScore = scoreRays( r, inv );\n\t\t\tconst score = Math.min( rayScore, invScore );\n\t\t\tif ( score < bestScore ) {\n\n\t\t\t\tbestScore = score;\n\t\t\t\tbestRay = r;\n\n\t\t\t}\n\n\t\t}\n\n\t\treturn bestRay;\n\n\t\tfunction skipRay( r0, r1 ) {\n\n\t\t\tconst distOutOfThreshold = r0.origin.distanceTo( r1.origin ) > DIST_EPSILON;\n\t\t\tconst angleOutOfThreshold = r0.direction.angleTo( r1.direction ) > ANGLE_EPSILON;\n\t\t\treturn angleOutOfThreshold || distOutOfThreshold;\n\n\t\t}\n\n\t\tfunction scoreRays( r0, r1 ) {\n\n\t\t\tconst originDistance = r0.origin.distanceTo( r1.origin );\n\t\t\tconst angleDistance = r0.direction.angleTo( r1.direction );\n\t\t\treturn originDistance / DIST_EPSILON + angleDistance / ANGLE_EPSILON;\n\n\t\t}\n\n\t}\n\n}\n","import { Vector3, Ray } from 'three';\nimport { toEdgeIndex, toTriIndex, matchEdges, getProjectedDistance } from './halfEdgeUtils.js';\nimport { toNormalizedRay } from './hashUtils.js';\nimport { RaySet } from './RaySet.js';\n\nconst _v0 = new Vector3();\nconst _v1 = new Vector3();\nconst _ray = new Ray();\n\nexport function computeDisjointEdges(\n\tgeometry,\n\tunmatchedSet,\n\teps,\n) {\n\n\tconst attributes = geometry.attributes;\n\tconst indexAttr = geometry.index;\n\tconst posAttr = attributes.position;\n\n\tconst disjointConnectivityMap = new Map();\n\tconst fragmentMap = new Map();\n\tconst edges = Array.from( unmatchedSet );\n\tconst rays = new RaySet();\n\n\tfor ( let i = 0, l = edges.length; i < l; i ++ ) {\n\n\t\t// get the triangle edge\n\t\tconst index = edges[ i ];\n\t\tconst triIndex = toTriIndex( index );\n\t\tconst edgeIndex = toEdgeIndex( index );\n\n\t\tlet i0 = 3 * triIndex + edgeIndex;\n\t\tlet i1 = 3 * triIndex + ( edgeIndex + 1 ) % 3;\n\t\tif ( indexAttr ) {\n\n\t\t\ti0 = indexAttr.getX( i0 );\n\t\t\ti1 = indexAttr.getX( i1 );\n\n\t\t}\n\n\t\t_v0.fromBufferAttribute( posAttr, i0 );\n\t\t_v1.fromBufferAttribute( posAttr, i1 );\n\n\t\t// get the ray corresponding to the edge\n\t\ttoNormalizedRay( _v0, _v1, _ray );\n\n\t\t// find the shared ray with other edges\n\t\tlet info;\n\t\tlet commonRay = rays.findClosestRay( _ray );\n\t\tif ( commonRay === null ) {\n\n\t\t\tcommonRay = _ray.clone();\n\t\t\trays.addRay( commonRay );\n\n\t\t}\n\n\t\tif ( ! fragmentMap.has( commonRay ) ) {\n\n\t\t\tfragmentMap.set( commonRay, {\n\n\t\t\t\tforward: [],\n\t\t\t\treverse: [],\n\t\t\t\tray: commonRay,\n\n\t\t\t} );\n\n\t\t}\n\n\t\tinfo = fragmentMap.get( commonRay );\n\n\t\t// store the stride of edge endpoints along the ray\n\t\tlet start = getProjectedDistance( commonRay, _v0 );\n\t\tlet end = getProjectedDistance( commonRay, _v1 );\n\t\tif ( start > end ) {\n\n\t\t\t[ start, end ] = [ end, start ];\n\n\t\t}\n\n\t\tif ( _ray.direction.dot( commonRay.direction ) < 0 ) {\n\n\t\t\tinfo.reverse.push( { start, end, index } );\n\n\t\t} else {\n\n\t\t\tinfo.forward.push( { start, end, index } );\n\n\t\t}\n\n\t}\n\n\t// match the found sibling edges\n\tfragmentMap.forEach( ( { forward, reverse }, ray ) => {\n\n\t\tmatchEdges( forward, reverse, disjointConnectivityMap, eps );\n\n\t\tif ( forward.length === 0 && reverse.length === 0 ) {\n\n\t\t\tfragmentMap.delete( ray );\n\n\t\t}\n\n\t} );\n\n\treturn {\n\t\tdisjointConnectivityMap,\n\t\tfragmentMap,\n\t};\n\n}\n\n","import { Vector2, Vector3, Vector4 } from 'three';\nimport { hashNumber, hashVertex2, hashVertex3, hashVertex4 } from './utils/hashUtils.js';\nimport { getTriCount } from './utils/geometryUtils.js';\nimport { computeDisjointEdges } from './utils/computeDisjointEdges.js';\n\nconst _vec2 = new Vector2();\nconst _vec3 = new Vector3();\nconst _vec4 = new Vector4();\nconst _hashes = [ '', '', '' ];\n\nexport class HalfEdgeMap {\n\n\tconstructor() {\n\n\t\t// result data\n\t\tthis.data = null;\n\t\tthis.disjointConnections = null;\n\t\tthis.unmatchedDisjointEdges = null;\n\t\tthis.unmatchedEdges = - 1;\n\t\tthis.matchedEdges = - 1;\n\n\t\t// options\n\t\tthis.useDrawRange = true;\n\t\tthis.useAllAttributes = false;\n\t\tthis.matchDisjointEdges = false;\n\t\tthis.degenerateEpsilon = 1e-8;\n\n\t}\n\n\tgetSiblingTriangleIndex( triIndex, edgeIndex ) {\n\n\t\tconst otherIndex = this.data[ triIndex * 3 + edgeIndex ];\n\t\treturn otherIndex === - 1 ? - 1 : ~ ~ ( otherIndex / 3 );\n\n\t}\n\n\tgetSiblingEdgeIndex( triIndex, edgeIndex ) {\n\n\t\tconst otherIndex = this.data[ triIndex * 3 + edgeIndex ];\n\t\treturn otherIndex === - 1 ? - 1 : ( otherIndex % 3 );\n\n\t}\n\n\tgetDisjointSiblingTriangleIndices( triIndex, edgeIndex ) {\n\n\t\tconst index = triIndex * 3 + edgeIndex;\n\t\tconst arr = this.disjointConnections.get( index );\n\t\treturn arr ? arr.map( i => ~ ~ ( i / 3 ) ) : [];\n\n\t}\n\n\tgetDisjointSiblingEdgeIndices( triIndex, edgeIndex ) {\n\n\t\tconst index = triIndex * 3 + edgeIndex;\n\t\tconst arr = this.disjointConnections.get( index );\n\t\treturn arr ? arr.map( i => i % 3 ) : [];\n\n\t}\n\n\tisFullyConnected() {\n\n\t\treturn this.unmatchedEdges === 0;\n\n\t}\n\n\tupdateFrom( geometry ) {\n\n\t\tconst { useAllAttributes, useDrawRange, matchDisjointEdges, degenerateEpsilon } = this;\n\t\tconst hashFunction = useAllAttributes ? hashAllAttributes : hashPositionAttribute;\n\n\t\t// runs on the assumption that there is a 1 : 1 match of edges\n\t\tconst map = new Map();\n\n\t\t// attributes\n\t\tconst { attributes } = geometry;\n\t\tconst attrKeys = useAllAttributes ? Object.keys( attributes ) : null;\n\t\tconst indexAttr = geometry.index;\n\t\tconst posAttr = attributes.position;\n\n\t\t// get the potential number of triangles\n\t\tlet triCount = getTriCount( geometry );\n\t\tconst maxTriCount = triCount;\n\n\t\t// get the real number of triangles from the based on the draw range\n\t\tlet offset = 0;\n\t\tif ( useDrawRange ) {\n\n\t\t\toffset = geometry.drawRange.start;\n\t\t\tif ( geometry.drawRange.count !== Infinity ) {\n\n\t\t\t\ttriCount = ~ ~ ( geometry.drawRange.count / 3 );\n\n\t\t\t}\n\n\t\t}\n\n\t\t// initialize the connectivity buffer - 1 means no connectivity\n\t\tlet data = this.data;\n\t\tif ( ! data || data.length < 3 * maxTriCount ) {\n\n\t\t\tdata = new Int32Array( 3 * maxTriCount );\n\n\t\t}\n\n\t\tdata.fill( - 1 );\n\n\t\t// iterate over all triangles\n\t\tlet matchedEdges = 0;\n\t\tlet unmatchedSet = new Set();\n\t\tfor ( let i = offset, l = triCount * 3 + offset; i < l; i += 3 ) {\n\n\t\t\tconst i3 = i;\n\t\t\tfor ( let e = 0; e < 3; e ++ ) {\n\n\t\t\t\tlet i0 = i3 + e;\n\t\t\t\tif ( indexAttr ) {\n\n\t\t\t\t\ti0 = indexAttr.getX( i0 );\n\n\t\t\t\t}\n\n\t\t\t\t_hashes[ e ] = hashFunction( i0 );\n\n\t\t\t}\n\n\t\t\tfor ( let e = 0; e < 3; e ++ ) {\n\n\t\t\t\tconst nextE = ( e + 1 ) % 3;\n\t\t\t\tconst vh0 = _hashes[ e ];\n\t\t\t\tconst vh1 = _hashes[ nextE ];\n\n\t\t\t\tconst reverseHash = `${ vh1 }_${ vh0 }`;\n\t\t\t\tif ( map.has( reverseHash ) ) {\n\n\t\t\t\t\t// create a reference between the two triangles and clear the hash\n\t\t\t\t\tconst index = i3 + e;\n\t\t\t\t\tconst otherIndex = map.get( reverseHash );\n\t\t\t\t\tdata[ index ] = otherIndex;\n\t\t\t\t\tdata[ otherIndex ] = index;\n\t\t\t\t\tmap.delete( reverseHash );\n\t\t\t\t\tmatchedEdges += 2;\n\t\t\t\t\tunmatchedSet.delete( otherIndex );\n\n\t\t\t\t} else {\n\n\t\t\t\t\t// save the triangle and triangle edge index captured in one value\n\t\t\t\t\t// triIndex = ~ ~ ( i0 / 3 );\n\t\t\t\t\t// edgeIndex = i0 % 3;\n\t\t\t\t\tconst hash = `${ vh0 }_${ vh1 }`;\n\t\t\t\t\tconst index = i3 + e;\n\t\t\t\t\tmap.set( hash, index );\n\t\t\t\t\tunmatchedSet.add( index );\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t}\n\n\t\tif ( matchDisjointEdges ) {\n\n\t\t\tconst {\n\t\t\t\tfragmentMap,\n\t\t\t\tdisjointConnectivityMap,\n\t\t\t} = computeDisjointEdges( geometry, unmatchedSet, degenerateEpsilon );\n\n\t\t\tunmatchedSet.clear();\n\t\t\tfragmentMap.forEach( ( { forward, reverse } ) => {\n\n\t\t\t\tforward.forEach( ( { index } ) => unmatchedSet.add( index ) );\n\t\t\t\treverse.forEach( ( { index } ) => unmatchedSet.add( index ) );\n\n\t\t\t} );\n\n\t\t\tthis.unmatchedDisjointEdges = fragmentMap;\n\t\t\tthis.disjointConnections = disjointConnectivityMap;\n\t\t\tmatchedEdges = triCount * 3 - unmatchedSet.size;\n\n\t\t}\n\n\t\tthis.matchedEdges = matchedEdges;\n\t\tthis.unmatchedEdges = unmatchedSet.size;\n\t\tthis.data = data;\n\n\t\tfunction hashPositionAttribute( i ) {\n\n\t\t\t_vec3.fromBufferAttribute( posAttr, i );\n\t\t\treturn hashVertex3( _vec3 );\n\n\t\t}\n\n\t\tfunction hashAllAttributes( i ) {\n\n\t\t\tlet result = '';\n\t\t\tfor ( let k = 0, l = attrKeys.length; k < l; k ++ ) {\n\n\t\t\t\tconst attr = attributes[ attrKeys[ k ] ];\n\t\t\t\tlet str;\n\t\t\t\tswitch ( attr.itemSize ) {\n\n\t\t\t\t\tcase 1:\n\t\t\t\t\t\tstr = hashNumber( attr.getX( i ) );\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 2:\n\t\t\t\t\t\tstr = hashVertex2( _vec2.fromBufferAttribute( attr, i ) );\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 3:\n\t\t\t\t\t\tstr = hashVertex3( _vec3.fromBufferAttribute( attr, i ) );\n\t\t\t\t\t\tbreak;\n\t\t\t\t\tcase 4:\n\t\t\t\t\t\tstr = hashVertex4( _vec4.fromBufferAttribute( attr, i ) );\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t}\n\n\t\t\t\tif ( result !== '' ) {\n\n\t\t\t\t\tresult += '|';\n\n\t\t\t\t}\n\n\t\t\t\tresult += str;\n\n\t\t\t}\n\n\t\t\treturn result;\n\n\t\t}\n\n\t}\n\n}\n","import { Mesh, Matrix4 } from 'three';\nimport { MeshBVH } from 'three-mesh-bvh';\nimport { HalfEdgeMap } from './HalfEdgeMap.js';\nimport { areSharedArrayBuffersSupported, convertToSharedArrayBuffer, getTriCount } from './utils/geometryUtils.js';\n\nexport class Brush extends Mesh {\n\n\tconstructor( ...args ) {\n\n\t\tsuper( ...args );\n\n\t\tthis.isBrush = true;\n\t\tthis._previousMatrix = new Matrix4();\n\t\tthis._previousMatrix.elements.fill( 0 );\n\t\tthis._halfEdges = null;\n\t\tthis._boundsTree = null;\n\t\tthis._groupIndices = null;\n\t\tthis._hash = null;\n\n\t}\n\n\tmarkUpdated() {\n\n\t\tthis._previousMatrix.copy( this.matrix );\n\n\t}\n\n\tisDirty() {\n\n\t\tconst { matrix, _previousMatrix } = this;\n\t\tconst el1 = matrix.elements;\n\t\tconst el2 = _previousMatrix.elements;\n\t\tfor ( let i = 0; i < 16; i ++ ) {\n\n\t\t\tif ( el1[ i ] !== el2[ i ] ) {\n\n\t\t\t\treturn true;\n\n\t\t\t}\n\n\t\t}\n\n\t\treturn false;\n\n\t}\n\n\tprepareGeometry() {\n\n\t\t// generate shared array buffers\n\t\tconst geometry = this.geometry;\n\t\tconst attributes = geometry.attributes;\n\t\tconst useSharedArrayBuffer = areSharedArrayBuffersSupported();\n\n\t\tconst index = geometry.index;\n\t\tconst posAttr = geometry.attributes.position;\n\t\tconst indexHash = index ? `${ index.uuid }_${ index.count }_${ index.version }` : '-1_-1_-1';\n\t\tconst posHash = `${ posAttr.uuid }_${ posAttr.count }_${ posAttr.version }`;\n\t\tconst hash = `${ geometry.uuid }_${ indexHash }_${ posHash }`;\n\t\tif ( this._hash === hash ) {\n\n\t\t\treturn;\n\n\t\t}\n\n\t\tthis._hash = hash;\n\t\tif ( useSharedArrayBuffer ) {\n\n\t\t\tfor ( const key in attributes ) {\n\n\t\t\t\tconst attribute = attributes[ key ];\n\t\t\t\tif ( attribute.isInterleavedBufferAttribute ) {\n\n\t\t\t\t\tthrow new Error( 'Brush: InterleavedBufferAttributes are not supported.' );\n\n\t\t\t\t}\n\n\t\t\t\tattribute.array = convertToSharedArrayBuffer( attribute.array );\n\n\t\t\t}\n\n\t\t}\n\n\t\t// generate bounds tree\n\t\tgeometry.boundsTree = new MeshBVH( geometry, { maxLeafSize: 3, indirect: true, useSharedArrayBuffer } );\n\n\t\t// generate half edges\n\t\tif ( ! geometry.halfEdges ) {\n\n\t\t\tgeometry.halfEdges = new HalfEdgeMap();\n\n\t\t}\n\n\t\tgeometry.halfEdges.updateFrom( geometry );\n\n\t\t// save group indices for materials\n\t\tconst triCount = getTriCount( geometry );\n\t\tif ( ! geometry.groupIndices || geometry.groupIndices.length !== triCount ) {\n\n\t\t\tgeometry.groupIndices = new Uint16Array( triCount );\n\n\t\t}\n\n\t\tconst array = geometry.groupIndices;\n\t\tconst groups = geometry.groups;\n\t\tfor ( let i = 0, l = groups.length; i < l; i ++ ) {\n\n\t\t\tconst { start, count } = groups[ i ];\n\t\t\tfor ( let g = start / 3, lg = ( start + count ) / 3; g < lg; g ++ ) {\n\n\t\t\t\tarray[ g ] = i;\n\n\t\t\t}\n\n\t\t}\n\n\t}\n\n\tdisposeCacheData() {\n\n\t\tconst { geometry } = this;\n\t\tgeometry.halfEdges = null;\n\t\tgeometry.boundsTree = null;\n\t\tgeometry.groupIndices = null;\n\n\t}\n\n}\n","// Auto-generated ESM bundle of cdt2d\nvar __getOwnPropNames = Object.getOwnPropertyNames;\nvar __commonJS = (cb, mod) => function __require() {\n return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;\n};\n\n// node_modules/binary-search-bounds/search-bounds.js\nvar require_search_bounds = __commonJS({\n \"node_modules/binary-search-bounds/search-bounds.js\"(exports, module) {\n \"use strict\";\n function ge(a, y, c, l, h) {\n var i = h + 1;\n while (l <= h) {\n var m = l + h >>> 1, x = a[m];\n var p = c !== void 0 ? c(x, y) : x - y;\n if (p >= 0) {\n i = m;\n h = m - 1;\n } else {\n l = m + 1;\n }\n }\n return i;\n }\n function gt(a, y, c, l, h) {\n var i = h + 1;\n while (l <= h) {\n var m = l + h >>> 1, x = a[m];\n var p = c !== void 0 ? c(x, y) : x - y;\n if (p > 0) {\n i = m;\n h = m - 1;\n } else {\n l = m + 1;\n }\n }\n return i;\n }\n function lt(a, y, c, l, h) {\n var i = l - 1;\n while (l <= h) {\n var m = l + h >>> 1, x = a[m];\n var p = c !== void 0 ? c(x, y) : x - y;\n if (p < 0) {\n i = m;\n l = m + 1;\n } else {\n h = m - 1;\n }\n }\n return i;\n }\n function le(a, y, c, l, h) {\n var i = l - 1;\n while (l <= h) {\n var m = l + h >>> 1, x = a[m];\n var p = c !== void 0 ? c(x, y) : x - y;\n if (p <= 0) {\n i = m;\n l = m + 1;\n } else {\n h = m - 1;\n }\n }\n return i;\n }\n function eq(a, y, c, l, h) {\n while (l <= h) {\n var m = l + h >>> 1, x = a[m];\n var p = c !== void 0 ? c(x, y) : x - y;\n if (p === 0) {\n return m;\n }\n if (p <= 0) {\n l = m + 1;\n } else {\n h = m - 1;\n }\n }\n return -1;\n }\n function norm(a, y, c, l, h, f) {\n if (typeof c === \"function\") {\n return f(a, y, c, l === void 0 ? 0 : l | 0, h === void 0 ? a.length - 1 : h | 0);\n }\n return f(a, y, void 0, c === void 0 ? 0 : c | 0, l === void 0 ? a.length - 1 : l | 0);\n }\n module.exports = {\n ge: function(a, y, c, l, h) {\n return norm(a, y, c, l, h, ge);\n },\n gt: function(a, y, c, l, h) {\n return norm(a, y, c, l, h, gt);\n },\n lt: function(a, y, c, l, h) {\n return norm(a, y, c, l, h, lt);\n },\n le: function(a, y, c, l, h) {\n return norm(a, y, c, l, h, le);\n },\n eq: function(a, y, c, l, h) {\n return norm(a, y, c, l, h, eq);\n }\n };\n }\n});\n\n// node_modules/two-product/two-product.js\nvar require_two_product = __commonJS({\n \"node_modules/two-product/two-product.js\"(exports, module) {\n \"use strict\";\n module.exports = twoProduct;\n var SPLITTER = +(Math.pow(2, 27) + 1);\n function twoProduct(a, b, result) {\n var x = a * b;\n var c = SPLITTER * a;\n var abig = c - a;\n var ahi = c - abig;\n var alo = a - ahi;\n var d = SPLITTER * b;\n var bbig = d - b;\n var bhi = d - bbig;\n var blo = b - bhi;\n var err1 = x - ahi * bhi;\n var err2 = err1 - alo * bhi;\n var err3 = err2 - ahi * blo;\n var y = alo * blo - err3;\n if (result) {\n result[0] = y;\n result[1] = x;\n return result;\n }\n return [y, x];\n }\n }\n});\n\n// node_modules/robust-sum/robust-sum.js\nvar require_robust_sum = __commonJS({\n \"node_modules/robust-sum/robust-sum.js\"(exports, module) {\n \"use strict\";\n module.exports = linearExpansionSum;\n function scalarScalar(a, b) {\n var x = a + b;\n var bv = x - a;\n var av = x - bv;\n var br = b - bv;\n var ar = a - av;\n var y = ar + br;\n if (y) {\n return [y, x];\n }\n return [x];\n }\n function linearExpansionSum(e, f) {\n var ne = e.length | 0;\n var nf = f.length | 0;\n if (ne === 1 && nf === 1) {\n return scalarScalar(e[0], f[0]);\n }\n var n = ne + nf;\n var g = new Array(n);\n var count = 0;\n var eptr = 0;\n var fptr = 0;\n var abs = Math.abs;\n var ei = e[eptr];\n var ea = abs(ei);\n var fi = f[fptr];\n var fa = abs(fi);\n var a, b;\n if (ea < fa) {\n b = ei;\n eptr += 1;\n if (eptr < ne) {\n ei = e[eptr];\n ea = abs(ei);\n }\n } else {\n b = fi;\n fptr += 1;\n if (fptr < nf) {\n fi = f[fptr];\n fa = abs(fi);\n }\n }\n if (eptr < ne && ea < fa || fptr >= nf) {\n a = ei;\n eptr += 1;\n if (eptr < ne) {\n ei = e[eptr];\n ea = abs(ei);\n }\n } else {\n a = fi;\n fptr += 1;\n if (fptr < nf) {\n fi = f[fptr];\n fa = abs(fi);\n }\n }\n var x = a + b;\n var bv = x - a;\n var y = b - bv;\n var q0 = y;\n var q1 = x;\n var _x, _bv, _av, _br, _ar;\n while (eptr < ne && fptr < nf) {\n if (ea < fa) {\n a = ei;\n eptr += 1;\n if (eptr < ne) {\n ei = e[eptr];\n ea = abs(ei);\n }\n } else {\n a = fi;\n fptr += 1;\n if (fptr < nf) {\n fi = f[fptr];\n fa = abs(fi);\n }\n }\n b = q0;\n x = a + b;\n bv = x - a;\n y = b - bv;\n if (y) {\n g[count++] = y;\n }\n _x = q1 + x;\n _bv = _x - q1;\n _av = _x - _bv;\n _br = x - _bv;\n _ar = q1 - _av;\n q0 = _ar + _br;\n q1 = _x;\n }\n while (eptr < ne) {\n a = ei;\n b = q0;\n x = a + b;\n bv = x - a;\n y = b - bv;\n if (y) {\n g[count++] = y;\n }\n _x = q1 + x;\n _bv = _x - q1;\n _av = _x - _bv;\n _br = x - _bv;\n _ar = q1 - _av;\n q0 = _ar + _br;\n q1 = _x;\n eptr += 1;\n if (eptr < ne) {\n ei = e[eptr];\n }\n }\n while (fptr < nf) {\n a = fi;\n b = q0;\n x = a + b;\n bv = x - a;\n y = b - bv;\n if (y) {\n g[count++] = y;\n }\n _x = q1 + x;\n _bv = _x - q1;\n _av = _x - _bv;\n _br = x - _bv;\n _ar = q1 - _av;\n q0 = _ar + _br;\n q1 = _x;\n fptr += 1;\n if (fptr < nf) {\n fi = f[fptr];\n }\n }\n if (q0) {\n g[count++] = q0;\n }\n if (q1) {\n g[count++] = q1;\n }\n if (!count) {\n g[count++] = 0;\n }\n g.length = count;\n return g;\n }\n }\n});\n\n// node_modules/two-sum/two-sum.js\nvar require_two_sum = __commonJS({\n \"node_modules/two-sum/two-sum.js\"(exports, module) {\n \"use strict\";\n module.exports = fastTwoSum;\n function fastTwoSum(a, b, result) {\n var x = a + b;\n var bv = x - a;\n var av = x - bv;\n var br = b - bv;\n var ar = a - av;\n if (result) {\n result[0] = ar + br;\n result[1] = x;\n return result;\n }\n return [ar + br, x];\n }\n }\n});\n\n// node_modules/robust-scale/robust-scale.js\nvar require_robust_scale = __commonJS({\n \"node_modules/robust-scale/robust-scale.js\"(exports, module) {\n \"use strict\";\n var twoProduct = require_two_product();\n var twoSum = require_two_sum();\n module.exports = scaleLinearExpansion;\n function scaleLinearExpansion(e, scale) {\n var n = e.length;\n if (n === 1) {\n var ts = twoProduct(e[0], scale);\n if (ts[0]) {\n return ts;\n }\n return [ts[1]];\n }\n var g = new Array(2 * n);\n var q = [0.1, 0.1];\n var t = [0.1, 0.1];\n var count = 0;\n twoProduct(e[0], scale, q);\n if (q[0]) {\n g[count++] = q[0];\n }\n for (var i = 1; i < n; ++i) {\n twoProduct(e[i], scale, t);\n var pq = q[1];\n twoSum(pq, t[0], q);\n if (q[0]) {\n g[count++] = q[0];\n }\n var a = t[1];\n var b = q[1];\n var x = a + b;\n var bv = x - a;\n var y = b - bv;\n q[1] = x;\n if (y) {\n g[count++] = y;\n }\n }\n if (q[1]) {\n g[count++] = q[1];\n }\n if (count === 0) {\n g[count++] = 0;\n }\n g.length = count;\n return g;\n }\n }\n});\n\n// node_modules/robust-subtract/robust-diff.js\nvar require_robust_diff = __commonJS({\n \"node_modules/robust-subtract/robust-diff.js\"(exports, module) {\n \"use strict\";\n module.exports = robustSubtract;\n function scalarScalar(a, b) {\n var x = a + b;\n var bv = x - a;\n var av = x - bv;\n var br = b - bv;\n var ar = a - av;\n var y = ar + br;\n if (y) {\n return [y, x];\n }\n return [x];\n }\n function robustSubtract(e, f) {\n var ne = e.length | 0;\n var nf = f.length | 0;\n if (ne === 1 && nf === 1) {\n return scalarScalar(e[0], -f[0]);\n }\n var n = ne + nf;\n var g = new Array(n);\n var count = 0;\n var eptr = 0;\n var fptr = 0;\n var abs = Math.abs;\n var ei = e[eptr];\n var ea = abs(ei);\n var fi = -f[fptr];\n var fa = abs(fi);\n var a, b;\n if (ea < fa) {\n b = ei;\n eptr += 1;\n if (eptr < ne) {\n ei = e[eptr];\n ea = abs(ei);\n }\n } else {\n b = fi;\n fptr += 1;\n if (fptr < nf) {\n fi = -f[fptr];\n fa = abs(fi);\n }\n }\n if (eptr < ne && ea < fa || fptr >= nf) {\n a = ei;\n eptr += 1;\n if (eptr < ne) {\n ei = e[eptr];\n ea = abs(ei);\n }\n } else {\n a = fi;\n fptr += 1;\n if (fptr < nf) {\n fi = -f[fptr];\n fa = abs(fi);\n }\n }\n var x = a + b;\n var bv = x - a;\n var y = b - bv;\n var q0 = y;\n var q1 = x;\n var _x, _bv, _av, _br, _ar;\n while (eptr < ne && fptr < nf) {\n if (ea < fa) {\n a = ei;\n eptr += 1;\n if (eptr < ne) {\n ei = e[eptr];\n ea = abs(ei);\n }\n } else {\n a = fi;\n fptr += 1;\n if (fptr < nf) {\n fi = -f[fptr];\n fa = abs(fi);\n }\n }\n b = q0;\n x = a + b;\n bv = x - a;\n y = b - bv;\n if (y) {\n g[count++] = y;\n }\n _x = q1 + x;\n _bv = _x - q1;\n _av = _x - _bv;\n _br = x - _bv;\n _ar = q1 - _av;\n q0 = _ar + _br;\n q1 = _x;\n }\n while (eptr < ne) {\n a = ei;\n b = q0;\n x = a + b;\n bv = x - a;\n y = b - bv;\n if (y) {\n g[count++] = y;\n }\n _x = q1 + x;\n _bv = _x - q1;\n _av = _x - _bv;\n _br = x - _bv;\n _ar = q1 - _av;\n q0 = _ar + _br;\n q1 = _x;\n eptr += 1;\n if (eptr < ne) {\n ei = e[eptr];\n }\n }\n while (fptr < nf) {\n a = fi;\n b = q0;\n x = a + b;\n bv = x - a;\n y = b - bv;\n if (y) {\n g[count++] = y;\n }\n _x = q1 + x;\n _bv = _x - q1;\n _av = _x - _bv;\n _br = x - _bv;\n _ar = q1 - _av;\n q0 = _ar + _br;\n q1 = _x;\n fptr += 1;\n if (fptr < nf) {\n fi = -f[fptr];\n }\n }\n if (q0) {\n g[count++] = q0;\n }\n if (q1) {\n g[count++] = q1;\n }\n if (!count) {\n g[count++] = 0;\n }\n g.length = count;\n return g;\n }\n }\n});\n\n// node_modules/robust-orientation/orientation.js\nvar require_orientation = __commonJS({\n \"node_modules/robust-orientation/orientation.js\"(exports, module) {\n \"use strict\";\n var twoProduct = require_two_product();\n var robustSum = require_robust_sum();\n var robustScale = require_robust_scale();\n var robustSubtract = require_robust_diff();\n var NUM_EXPAND = 5;\n var EPSILON = 11102230246251565e-32;\n var ERRBOUND3 = (3 + 16 * EPSILON) * EPSILON;\n var ERRBOUND4 = (7 + 56 * EPSILON) * EPSILON;\n function orientation_3(sum, prod, scale, sub) {\n return function orientation3Exact2(m0, m1, m2) {\n 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])));\n var n = sum(prod(m0[1], m2[0]), prod(-m2[1], m0[0]));\n var d = sub(p, n);\n return d[d.length - 1];\n };\n }\n function orientation_4(sum, prod, scale, sub) {\n return function orientation4Exact2(m0, m1, m2, m3) {\n 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]))));\n 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]))));\n var d = sub(p, n);\n return d[d.length - 1];\n };\n }\n function orientation_5(sum, prod, scale, sub) {\n return function orientation5Exact(m0, m1, m2, m3, m4) {\n 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])))));\n 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]))));\n var d = sub(p, n);\n return d[d.length - 1];\n };\n }\n function orientation(n) {\n var fn = n === 3 ? orientation_3 : n === 4 ? orientation_4 : orientation_5;\n return fn(robustSum, twoProduct, robustScale, robustSubtract);\n }\n var orientation3Exact = orientation(3);\n var orientation4Exact = orientation(4);\n var CACHED = [\n function orientation0() {\n return 0;\n },\n function orientation1() {\n return 0;\n },\n function orientation2(a, b) {\n return b[0] - a[0];\n },\n function orientation3(a, b, c) {\n var l = (a[1] - c[1]) * (b[0] - c[0]);\n var r = (a[0] - c[0]) * (b[1] - c[1]);\n var det = l - r;\n var s;\n if (l > 0) {\n if (r <= 0) {\n return det;\n } else {\n s = l + r;\n }\n } else if (l < 0) {\n if (r >= 0) {\n return det;\n } else {\n s = -(l + r);\n }\n } else {\n return det;\n }\n var tol = ERRBOUND3 * s;\n if (det >= tol || det <= -tol) {\n return det;\n }\n return orientation3Exact(a, b, c);\n },\n function orientation4(a, b, c, d) {\n var adx = a[0] - d[0];\n var bdx = b[0] - d[0];\n var cdx = c[0] - d[0];\n var ady = a[1] - d[1];\n var bdy = b[1] - d[1];\n var cdy = c[1] - d[1];\n var adz = a[2] - d[2];\n var bdz = b[2] - d[2];\n var cdz = c[2] - d[2];\n var bdxcdy = bdx * cdy;\n var cdxbdy = cdx * bdy;\n var cdxady = cdx * ady;\n var adxcdy = adx * cdy;\n var adxbdy = adx * bdy;\n var bdxady = bdx * ady;\n var det = adz * (bdxcdy - cdxbdy) + bdz * (cdxady - adxcdy) + cdz * (adxbdy - bdxady);\n 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);\n var tol = ERRBOUND4 * permanent;\n if (det > tol || -det > tol) {\n return det;\n }\n return orientation4Exact(a, b, c, d);\n }\n ];\n function slowOrient(args) {\n var proc2 = CACHED[args.length];\n if (!proc2) {\n proc2 = CACHED[args.length] = orientation(args.length);\n }\n return proc2.apply(void 0, args);\n }\n function proc(slow, o0, o1, o2, o3, o4, o5) {\n return function getOrientation(a0, a1, a2, a3, a4) {\n switch (arguments.length) {\n case 0:\n case 1:\n return 0;\n case 2:\n return o2(a0, a1);\n case 3:\n return o3(a0, a1, a2);\n case 4:\n return o4(a0, a1, a2, a3);\n case 5:\n return o5(a0, a1, a2, a3, a4);\n }\n var s = new Array(arguments.length);\n for (var i = 0; i < arguments.length; ++i) {\n s[i] = arguments[i];\n }\n return slow(s);\n };\n }\n function generateOrientationProc() {\n while (CACHED.length <= NUM_EXPAND) {\n CACHED.push(orientation(CACHED.length));\n }\n module.exports = proc.apply(void 0, [slowOrient].concat(CACHED));\n for (var i = 0; i <= NUM_EXPAND; ++i) {\n module.exports[i] = CACHED[i];\n }\n }\n generateOrientationProc();\n }\n});\n\n// node_modules/cdt2d/lib/monotone.js\nvar require_monotone = __commonJS({\n \"node_modules/cdt2d/lib/monotone.js\"(exports, module) {\n \"use strict\";\n var bsearch = require_search_bounds();\n var orient = require_orientation()[3];\n var EVENT_POINT = 0;\n var EVENT_END = 1;\n var EVENT_START = 2;\n module.exports = monotoneTriangulate;\n function PartialHull(a, b, idx, lowerIds, upperIds) {\n this.a = a;\n this.b = b;\n this.idx = idx;\n this.lowerIds = lowerIds;\n this.upperIds = upperIds;\n }\n function Event(a, b, type, idx) {\n this.a = a;\n this.b = b;\n this.type = type;\n this.idx = idx;\n }\n function compareEvent(a, b) {\n var d = a.a[0] - b.a[0] || a.a[1] - b.a[1] || a.type - b.type;\n if (d) {\n return d;\n }\n if (a.type !== EVENT_POINT) {\n d = orient(a.a, a.b, b.b);\n if (d) {\n return d;\n }\n }\n return a.idx - b.idx;\n }\n function testPoint(hull, p) {\n return orient(hull.a, hull.b, p);\n }\n function addPoint(cells, hulls, points, p, idx) {\n var lo = bsearch.lt(hulls, p, testPoint);\n var hi = bsearch.gt(hulls, p, testPoint);\n for (var i = lo; i < hi; ++i) {\n var hull = hulls[i];\n var lowerIds = hull.lowerIds;\n var m = lowerIds.length;\n while (m > 1 && orient(\n points[lowerIds[m - 2]],\n points[lowerIds[m - 1]],\n p\n ) > 0) {\n cells.push(\n [\n lowerIds[m - 1],\n lowerIds[m - 2],\n idx\n ]\n );\n m -= 1;\n }\n lowerIds.length = m;\n lowerIds.push(idx);\n var upperIds = hull.upperIds;\n var m = upperIds.length;\n while (m > 1 && orient(\n points[upperIds[m - 2]],\n points[upperIds[m - 1]],\n p\n ) < 0) {\n cells.push(\n [\n upperIds[m - 2],\n upperIds[m - 1],\n idx\n ]\n );\n m -= 1;\n }\n upperIds.length = m;\n upperIds.push(idx);\n }\n }\n function findSplit(hull, edge) {\n var d;\n if (hull.a[0] < edge.a[0]) {\n d = orient(hull.a, hull.b, edge.a);\n } else {\n d = orient(edge.b, edge.a, hull.a);\n }\n if (d) {\n return d;\n }\n if (edge.b[0] < hull.b[0]) {\n d = orient(hull.a, hull.b, edge.b);\n } else {\n d = orient(edge.b, edge.a, hull.b);\n }\n return d || hull.idx - edge.idx;\n }\n function splitHulls(hulls, points, event) {\n var splitIdx = bsearch.le(hulls, event, findSplit);\n var hull = hulls[splitIdx];\n var upperIds = hull.upperIds;\n var x = upperIds[upperIds.length - 1];\n hull.upperIds = [x];\n hulls.splice(\n splitIdx + 1,\n 0,\n new PartialHull(event.a, event.b, event.idx, [x], upperIds)\n );\n }\n function mergeHulls(hulls, points, event) {\n var tmp = event.a;\n event.a = event.b;\n event.b = tmp;\n var mergeIdx = bsearch.eq(hulls, event, findSplit);\n var upper = hulls[mergeIdx];\n var lower = hulls[mergeIdx - 1];\n lower.upperIds = upper.upperIds;\n hulls.splice(mergeIdx, 1);\n }\n function monotoneTriangulate(points, edges) {\n var numPoints = points.length;\n var numEdges = edges.length;\n var events = [];\n for (var i = 0; i < numPoints; ++i) {\n events.push(new Event(\n points[i],\n null,\n EVENT_POINT,\n i\n ));\n }\n for (var i = 0; i < numEdges; ++i) {\n var e = edges[i];\n var a = points[e[0]];\n var b = points[e[1]];\n if (a[0] < b[0]) {\n events.push(\n new Event(a, b, EVENT_START, i),\n new Event(b, a, EVENT_END, i)\n );\n } else if (a[0] > b[0]) {\n events.push(\n new Event(b, a, EVENT_START, i),\n new Event(a, b, EVENT_END, i)\n );\n }\n }\n events.sort(compareEvent);\n var minX = events[0].a[0] - (1 + Math.abs(events[0].a[0])) * Math.pow(2, -52);\n var hull = [new PartialHull([minX, 1], [minX, 0], -1, [], [], [], [])];\n var cells = [];\n for (var i = 0, numEvents = events.length; i < numEvents; ++i) {\n var event = events[i];\n var type = event.type;\n if (type === EVENT_POINT) {\n addPoint(cells, hull, points, event.a, event.idx);\n } else if (type === EVENT_START) {\n splitHulls(hull, points, event);\n } else {\n mergeHulls(hull, points, event);\n }\n }\n return cells;\n }\n }\n});\n\n// node_modules/cdt2d/lib/triangulation.js\nvar require_triangulation = __commonJS({\n \"node_modules/cdt2d/lib/triangulation.js\"(exports, module) {\n \"use strict\";\n var bsearch = require_search_bounds();\n module.exports = createTriangulation;\n function Triangulation(stars, edges) {\n this.stars = stars;\n this.edges = edges;\n }\n var proto = Triangulation.prototype;\n function removePair(list, j, k) {\n for (var i = 1, n = list.length; i < n; i += 2) {\n if (list[i - 1] === j && list[i] === k) {\n list[i - 1] = list[n - 2];\n list[i] = list[n - 1];\n list.length = n - 2;\n return;\n }\n }\n }\n proto.isConstraint = /* @__PURE__ */ (function() {\n var e = [0, 0];\n function compareLex(a, b) {\n return a[0] - b[0] || a[1] - b[1];\n }\n return function(i, j) {\n e[0] = Math.min(i, j);\n e[1] = Math.max(i, j);\n return bsearch.eq(this.edges, e, compareLex) >= 0;\n };\n })();\n proto.removeTriangle = function(i, j, k) {\n var stars = this.stars;\n removePair(stars[i], j, k);\n removePair(stars[j], k, i);\n removePair(stars[k], i, j);\n };\n proto.addTriangle = function(i, j, k) {\n var stars = this.stars;\n stars[i].push(j, k);\n stars[j].push(k, i);\n stars[k].push(i, j);\n };\n proto.opposite = function(j, i) {\n var list = this.stars[i];\n for (var k = 1, n = list.length; k < n; k += 2) {\n if (list[k] === j) {\n return list[k - 1];\n }\n }\n return -1;\n };\n proto.flip = function(i, j) {\n var a = this.opposite(i, j);\n var b = this.opposite(j, i);\n this.removeTriangle(i, j, a);\n this.removeTriangle(j, i, b);\n this.addTriangle(i, b, a);\n this.addTriangle(j, a, b);\n };\n proto.edges = function() {\n var stars = this.sta