@@ -12,27 +12,40 @@ export function _combineIdMaps(other) {
1212 return merged ;
1313}
1414
15+ function _invertFaceNameMap ( nameToId ) {
16+ const idToName = new Map ( ) ;
17+ if ( ! nameToId || typeof nameToId . entries !== 'function' ) return idToName ;
18+ for ( const [ name , id ] of nameToId . entries ( ) ) {
19+ idToName . set ( id , name ) ;
20+ }
21+ return idToName ;
22+ }
23+
1524function _collapseFaceIdsByName ( solid ) {
1625 if ( ! solid || ! solid . _faceNameToID || ! solid . _idToFaceName || ! Array . isArray ( solid . _triIDs ) ) return false ;
1726 const nameToId = solid . _faceNameToID ;
27+ const idToName = solid . _idToFaceName ;
28+ const triIDs = solid . _triIDs ;
29+ const canonicalById = new Map ( ) ;
1830 let changed = false ;
1931
20- for ( let i = 0 ; i < solid . _triIDs . length ; i ++ ) {
21- const id = solid . _triIDs [ i ] ;
22- const name = solid . _idToFaceName . get ( id ) ;
23- if ( ! name ) continue ;
24- const canonical = nameToId . get ( name ) ;
25- if ( canonical !== undefined && canonical !== id ) {
26- solid . _triIDs [ i ] = canonical ;
32+ for ( let i = 0 ; i < triIDs . length ; i ++ ) {
33+ const id = triIDs [ i ] ;
34+ let canonical = canonicalById . get ( id ) ;
35+ if ( canonical === undefined ) {
36+ const name = idToName . get ( id ) ;
37+ canonical = ( name !== undefined ) ? ( nameToId . get ( name ) ?? id ) : id ;
38+ canonicalById . set ( id , canonical ) ;
39+ }
40+ if ( canonical !== id ) {
41+ triIDs [ i ] = canonical ;
2742 changed = true ;
2843 }
2944 }
3045
3146 if ( ! changed ) return false ;
3247
33- solid . _idToFaceName = new Map (
34- [ ...solid . _faceNameToID . entries ( ) ] . map ( ( [ name , id ] ) => [ id , name ] ) ,
35- ) ;
48+ solid . _idToFaceName = _invertFaceNameMap ( solid . _faceNameToID ) ;
3649 solid . _faceIndex = null ;
3750 solid . _dirty = true ;
3851 try { if ( solid . _manifold && typeof solid . _manifold . delete === 'function' ) solid . _manifold . delete ( ) ; } catch { }
@@ -54,7 +67,6 @@ export function union(other) {
5467 try { out . _auxEdges = [ ...( this . _auxEdges || [ ] ) , ...( other ?. _auxEdges || [ ] ) ] ; } catch { }
5568 try { out . _faceMetadata = this . _combineFaceMetadata ( other ) ; } catch { }
5669 try { out . _edgeMetadata = this . _combineEdgeMetadata ( other ) ; } catch { }
57- _collapseFaceIdsByName ( out ) ;
5870 return out ;
5971}
6072
@@ -68,7 +80,6 @@ export function subtract(other) {
6880 try { out . _auxEdges = [ ...( this . _auxEdges || [ ] ) , ...( other ?. _auxEdges || [ ] ) ] ; } catch { }
6981 try { out . _faceMetadata = this . _combineFaceMetadata ( other ) ; } catch { }
7082 try { out . _edgeMetadata = this . _combineEdgeMetadata ( other ) ; } catch { }
71- _collapseFaceIdsByName ( out ) ;
7283
7384 return out ;
7485}
@@ -82,7 +93,6 @@ export function intersect(other) {
8293 try { out . _auxEdges = [ ...( this . _auxEdges || [ ] ) , ...( other ?. _auxEdges || [ ] ) ] ; } catch { }
8394 try { out . _faceMetadata = this . _combineFaceMetadata ( other ) ; } catch { }
8495 try { out . _edgeMetadata = this . _combineEdgeMetadata ( other ) ; } catch { }
85- _collapseFaceIdsByName ( out ) ;
8696 return out ;
8797}
8898
@@ -99,7 +109,6 @@ export function difference(other) {
99109 try { out . _auxEdges = [ ...( this . _auxEdges || [ ] ) , ...( other ?. _auxEdges || [ ] ) ] ; } catch { }
100110 try { out . _faceMetadata = this . _combineFaceMetadata ( other ) ; } catch { }
101111 try { out . _edgeMetadata = this . _combineEdgeMetadata ( other ) ; } catch { }
102- _collapseFaceIdsByName ( out ) ;
103112 return out ;
104113}
105114
@@ -112,7 +121,6 @@ export function setTolerance(tolerance) {
112121 try { out . _auxEdges = Array . isArray ( this . _auxEdges ) ? this . _auxEdges . slice ( ) : [ ] ; } catch { }
113122 try { out . _faceMetadata = new Map ( this . _faceMetadata ) ; } catch { }
114123 try { out . _edgeMetadata = new Map ( this . _edgeMetadata ) ; } catch { }
115- _collapseFaceIdsByName ( out ) ;
116124 return out ;
117125}
118126export function simplify ( tolerance = undefined , updateInPlace = false ) {
@@ -133,14 +141,8 @@ export function simplify(tolerance = undefined, updateInPlace = false) {
133141 this . _triVerts = Array . from ( meshOut . triVerts ) ;
134142 this . _triIDs = Solid . _expandTriIDsFromMesh ( meshOut ) ;
135143
136- // Rebuild vertex key map
144+ // Defer rebuilding key map until authoring methods need it.
137145 this . _vertKeyToIndex = new Map ( ) ;
138- for ( let i = 0 ; i < this . _vertProperties . length ; i += 3 ) {
139- const x = this . _vertProperties [ i + 0 ] ;
140- const y = this . _vertProperties [ i + 1 ] ;
141- const z = this . _vertProperties [ i + 2 ] ;
142- this . _vertKeyToIndex . set ( `${ x } ,${ y } ,${ z } ` , ( i / 3 ) | 0 ) ;
143- }
144146
145147 // Keep existing face name map; best-effort completion for any new IDs
146148 const completeMap = new Map ( this . _idToFaceName ) ;
@@ -160,9 +162,10 @@ export function simplify(tolerance = undefined, updateInPlace = false) {
160162 }
161163 } catch { /* ignore */ }
162164 this . _idToFaceName = completeMap ;
163- this . _faceNameToID = new Map (
164- [ ...this . _idToFaceName . entries ( ) ] . map ( ( [ id , name ] ) => [ name , id ] ) ,
165- ) ;
165+ this . _faceNameToID = new Map ( ) ;
166+ for ( const [ id , name ] of this . _idToFaceName . entries ( ) ) {
167+ this . _faceNameToID . set ( name , id ) ;
168+ }
166169
167170 // Replace cached manifold and reset caches
168171 try { if ( this . _manifold && this . _manifold !== outM && typeof this . _manifold . delete === 'function' ) this . _manifold . delete ( ) ; } catch { }
@@ -209,13 +212,8 @@ export function _fromManifold(manifoldObj, idToFaceName) {
209212 solid . _vertProperties = Array . from ( mesh . vertProperties ) ;
210213 solid . _triVerts = Array . from ( mesh . triVerts ) ;
211214 solid . _triIDs = Solid . _expandTriIDsFromMesh ( mesh ) ;
212-
213- for ( let i = 0 ; i < mesh . vertProperties . length ; i += 3 ) {
214- const x = mesh . vertProperties [ i + 0 ] ;
215- const y = mesh . vertProperties [ i + 1 ] ;
216- const z = mesh . vertProperties [ i + 2 ] ;
217- solid . _vertKeyToIndex . set ( `${ x } ,${ y } ,${ z } ` , i / 3 ) ;
218- }
215+ // Avoid O(vertexCount) string allocations here; authoring methods lazily rebuild this map.
216+ solid . _vertKeyToIndex = new Map ( ) ;
219217
220218 const completeMap = new Map ( idToFaceName ) ;
221219 try {
@@ -235,9 +233,10 @@ export function _fromManifold(manifoldObj, idToFaceName) {
235233 } catch ( _ ) { /* best-effort completion */ }
236234
237235 solid . _idToFaceName = new Map ( completeMap ) ;
238- solid . _faceNameToID = new Map (
239- [ ...solid . _idToFaceName . entries ( ) ] . map ( ( [ id , name ] ) => [ name , id ] ) ,
240- ) ;
236+ solid . _faceNameToID = new Map ( ) ;
237+ for ( const [ id , name ] of solid . _idToFaceName . entries ( ) ) {
238+ solid . _faceNameToID . set ( name , id ) ;
239+ }
241240
242241 solid . _manifold = manifoldObj ;
243242 solid . _dirty = false ;
0 commit comments