three-bvh-csg
Version:
A fast, flexible, dynamic CSG implementation on top of three-mesh-bvh
135 lines (87 loc) • 2.88 kB
JavaScript
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;
}
}