UNPKG

three-bvh-csg

Version:

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

135 lines (87 loc) 2.88 kB
import { Vector3 } from 'three'; import { hashVertex } from '../utils/hashUtils.js'; const _vertices = [ new Vector3(), new Vector3(), new Vector3() ]; export class HalfEdgeMap { constructor( geometry = null ) { this.data = null; this.unmatchedEdges = null; this.matchedEdges = null; this.useDrawRange = true; if ( geometry ) { this.updateFrom( geometry ); } } 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 ); } updateFrom( geometry ) { // runs on the assumption that there is a 1 : 1 match of edges const map = new Map(); // attributes const { attributes } = geometry; const indexAttr = geometry.index; const posAttr = attributes.position; // get the potential number of triangles let triCount = indexAttr ? indexAttr.count / 3 : posAttr.count / 3; const maxTriCount = triCount; // get the real number of triangles from the based on the draw range let offset = 0; if ( this.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 unmatchedEdges = 0; let matchedEdges = 0; for ( let i = 0; i < triCount; i ++ ) { const i3 = 3 * i + offset; for ( let e = 0; e < 3; e ++ ) { let i0 = i3 + e; if ( indexAttr ) { i0 = indexAttr.getX( i0 ); } _vertices[ e ].fromBufferAttribute( posAttr, i0 ); } for ( let e = 0; e < 3; e ++ ) { const nextE = ( e + 1 ) % 3; const _vec0 = _vertices[ e ]; const _vec1 = _vertices[ nextE ]; const vh0 = hashVertex( _vec0 ); const vh1 = hashVertex( _vec1 ); const reverseHash = `${ vh1 }_${ vh0 }`; if ( map.has( reverseHash ) ) { // create a reference between the two triangles and clear the hash const otherIndex = map.get( reverseHash ); data[ i3 + e ] = otherIndex; data[ otherIndex ] = i3 + e; map.delete( reverseHash ); unmatchedEdges --; matchedEdges ++; } else { // save the triangle and triangle edge index captured in one value // triIndex = ~ ~ ( i0 / 3 ); // edgeIndex = i0 % 3; const hash = `${ vh0 }_${ vh1 }`; map.set( hash, i3 + e ); unmatchedEdges ++; } } } this.matchedEdges = matchedEdges; this.unmatchedEdges = unmatchedEdges; this.data = data; } }