@2112-lab/central-plant 0.1.13 → 0.1.16

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -4,6 +4,465 @@ Object.defineProperty(exports, '__esModule', { value: true });
4
4
 
5
5
  var THREE = require('three');
6
6
 
7
+ /**
8
+ * Merges a set of geometries into a single instance. All geometries must have compatible attributes.
9
+ *
10
+ * @param {Array<BufferGeometry>} geometries - The geometries to merge.
11
+ * @param {boolean} [useGroups=false] - Whether to use groups or not.
12
+ * @return {?BufferGeometry} The merged geometry. Returns `null` if the merge does not succeed.
13
+ */
14
+ function mergeGeometries( geometries, useGroups = false ) {
15
+
16
+ const isIndexed = geometries[ 0 ].index !== null;
17
+
18
+ const attributesUsed = new Set( Object.keys( geometries[ 0 ].attributes ) );
19
+ const morphAttributesUsed = new Set( Object.keys( geometries[ 0 ].morphAttributes ) );
20
+
21
+ const attributes = {};
22
+ const morphAttributes = {};
23
+
24
+ const morphTargetsRelative = geometries[ 0 ].morphTargetsRelative;
25
+
26
+ const mergedGeometry = new THREE.BufferGeometry();
27
+
28
+ let offset = 0;
29
+
30
+ for ( let i = 0; i < geometries.length; ++ i ) {
31
+
32
+ const geometry = geometries[ i ];
33
+ let attributesCount = 0;
34
+
35
+ // ensure that all geometries are indexed, or none
36
+
37
+ if ( isIndexed !== ( geometry.index !== null ) ) {
38
+
39
+ console.error( 'THREE.BufferGeometryUtils: .mergeGeometries() failed with geometry at index ' + i + '. All geometries must have compatible attributes; make sure index attribute exists among all geometries, or in none of them.' );
40
+ return null;
41
+
42
+ }
43
+
44
+ // gather attributes, exit early if they're different
45
+
46
+ for ( const name in geometry.attributes ) {
47
+
48
+ if ( ! attributesUsed.has( name ) ) {
49
+
50
+ console.error( 'THREE.BufferGeometryUtils: .mergeGeometries() failed with geometry at index ' + i + '. All geometries must have compatible attributes; make sure "' + name + '" attribute exists among all geometries, or in none of them.' );
51
+ return null;
52
+
53
+ }
54
+
55
+ if ( attributes[ name ] === undefined ) attributes[ name ] = [];
56
+
57
+ attributes[ name ].push( geometry.attributes[ name ] );
58
+
59
+ attributesCount ++;
60
+
61
+ }
62
+
63
+ // ensure geometries have the same number of attributes
64
+
65
+ if ( attributesCount !== attributesUsed.size ) {
66
+
67
+ console.error( 'THREE.BufferGeometryUtils: .mergeGeometries() failed with geometry at index ' + i + '. Make sure all geometries have the same number of attributes.' );
68
+ return null;
69
+
70
+ }
71
+
72
+ // gather morph attributes, exit early if they're different
73
+
74
+ if ( morphTargetsRelative !== geometry.morphTargetsRelative ) {
75
+
76
+ console.error( 'THREE.BufferGeometryUtils: .mergeGeometries() failed with geometry at index ' + i + '. .morphTargetsRelative must be consistent throughout all geometries.' );
77
+ return null;
78
+
79
+ }
80
+
81
+ for ( const name in geometry.morphAttributes ) {
82
+
83
+ if ( ! morphAttributesUsed.has( name ) ) {
84
+
85
+ console.error( 'THREE.BufferGeometryUtils: .mergeGeometries() failed with geometry at index ' + i + '. .morphAttributes must be consistent throughout all geometries.' );
86
+ return null;
87
+
88
+ }
89
+
90
+ if ( morphAttributes[ name ] === undefined ) morphAttributes[ name ] = [];
91
+
92
+ morphAttributes[ name ].push( geometry.morphAttributes[ name ] );
93
+
94
+ }
95
+
96
+ if ( useGroups ) {
97
+
98
+ let count;
99
+
100
+ if ( isIndexed ) {
101
+
102
+ count = geometry.index.count;
103
+
104
+ } else if ( geometry.attributes.position !== undefined ) {
105
+
106
+ count = geometry.attributes.position.count;
107
+
108
+ } else {
109
+
110
+ console.error( 'THREE.BufferGeometryUtils: .mergeGeometries() failed with geometry at index ' + i + '. The geometry must have either an index or a position attribute' );
111
+ return null;
112
+
113
+ }
114
+
115
+ mergedGeometry.addGroup( offset, count, i );
116
+
117
+ offset += count;
118
+
119
+ }
120
+
121
+ }
122
+
123
+ // merge indices
124
+
125
+ if ( isIndexed ) {
126
+
127
+ let indexOffset = 0;
128
+ const mergedIndex = [];
129
+
130
+ for ( let i = 0; i < geometries.length; ++ i ) {
131
+
132
+ const index = geometries[ i ].index;
133
+
134
+ for ( let j = 0; j < index.count; ++ j ) {
135
+
136
+ mergedIndex.push( index.getX( j ) + indexOffset );
137
+
138
+ }
139
+
140
+ indexOffset += geometries[ i ].attributes.position.count;
141
+
142
+ }
143
+
144
+ mergedGeometry.setIndex( mergedIndex );
145
+
146
+ }
147
+
148
+ // merge attributes
149
+
150
+ for ( const name in attributes ) {
151
+
152
+ const mergedAttribute = mergeAttributes( attributes[ name ] );
153
+
154
+ if ( ! mergedAttribute ) {
155
+
156
+ console.error( 'THREE.BufferGeometryUtils: .mergeGeometries() failed while trying to merge the ' + name + ' attribute.' );
157
+ return null;
158
+
159
+ }
160
+
161
+ mergedGeometry.setAttribute( name, mergedAttribute );
162
+
163
+ }
164
+
165
+ // merge morph attributes
166
+
167
+ for ( const name in morphAttributes ) {
168
+
169
+ const numMorphTargets = morphAttributes[ name ][ 0 ].length;
170
+
171
+ if ( numMorphTargets === 0 ) break;
172
+
173
+ mergedGeometry.morphAttributes = mergedGeometry.morphAttributes || {};
174
+ mergedGeometry.morphAttributes[ name ] = [];
175
+
176
+ for ( let i = 0; i < numMorphTargets; ++ i ) {
177
+
178
+ const morphAttributesToMerge = [];
179
+
180
+ for ( let j = 0; j < morphAttributes[ name ].length; ++ j ) {
181
+
182
+ morphAttributesToMerge.push( morphAttributes[ name ][ j ][ i ] );
183
+
184
+ }
185
+
186
+ const mergedMorphAttribute = mergeAttributes( morphAttributesToMerge );
187
+
188
+ if ( ! mergedMorphAttribute ) {
189
+
190
+ console.error( 'THREE.BufferGeometryUtils: .mergeGeometries() failed while trying to merge the ' + name + ' morphAttribute.' );
191
+ return null;
192
+
193
+ }
194
+
195
+ mergedGeometry.morphAttributes[ name ].push( mergedMorphAttribute );
196
+
197
+ }
198
+
199
+ }
200
+
201
+ return mergedGeometry;
202
+
203
+ }
204
+
205
+ /**
206
+ * Merges a set of attributes into a single instance. All attributes must have compatible properties and types.
207
+ * Instances of {@link InterleavedBufferAttribute} are not supported.
208
+ *
209
+ * @param {Array<BufferAttribute>} attributes - The attributes to merge.
210
+ * @return {?BufferAttribute} The merged attribute. Returns `null` if the merge does not succeed.
211
+ */
212
+ function mergeAttributes( attributes ) {
213
+
214
+ let TypedArray;
215
+ let itemSize;
216
+ let normalized;
217
+ let gpuType = - 1;
218
+ let arrayLength = 0;
219
+
220
+ for ( let i = 0; i < attributes.length; ++ i ) {
221
+
222
+ const attribute = attributes[ i ];
223
+
224
+ if ( TypedArray === undefined ) TypedArray = attribute.array.constructor;
225
+ if ( TypedArray !== attribute.array.constructor ) {
226
+
227
+ console.error( 'THREE.BufferGeometryUtils: .mergeAttributes() failed. BufferAttribute.array must be of consistent array types across matching attributes.' );
228
+ return null;
229
+
230
+ }
231
+
232
+ if ( itemSize === undefined ) itemSize = attribute.itemSize;
233
+ if ( itemSize !== attribute.itemSize ) {
234
+
235
+ console.error( 'THREE.BufferGeometryUtils: .mergeAttributes() failed. BufferAttribute.itemSize must be consistent across matching attributes.' );
236
+ return null;
237
+
238
+ }
239
+
240
+ if ( normalized === undefined ) normalized = attribute.normalized;
241
+ if ( normalized !== attribute.normalized ) {
242
+
243
+ console.error( 'THREE.BufferGeometryUtils: .mergeAttributes() failed. BufferAttribute.normalized must be consistent across matching attributes.' );
244
+ return null;
245
+
246
+ }
247
+
248
+ if ( gpuType === - 1 ) gpuType = attribute.gpuType;
249
+ if ( gpuType !== attribute.gpuType ) {
250
+
251
+ console.error( 'THREE.BufferGeometryUtils: .mergeAttributes() failed. BufferAttribute.gpuType must be consistent across matching attributes.' );
252
+ return null;
253
+
254
+ }
255
+
256
+ arrayLength += attribute.count * itemSize;
257
+
258
+ }
259
+
260
+ const array = new TypedArray( arrayLength );
261
+ const result = new THREE.BufferAttribute( array, itemSize, normalized );
262
+ let offset = 0;
263
+
264
+ for ( let i = 0; i < attributes.length; ++ i ) {
265
+
266
+ const attribute = attributes[ i ];
267
+ if ( attribute.isInterleavedBufferAttribute ) {
268
+
269
+ const tupleOffset = offset / itemSize;
270
+ for ( let j = 0, l = attribute.count; j < l; j ++ ) {
271
+
272
+ for ( let c = 0; c < itemSize; c ++ ) {
273
+
274
+ const value = attribute.getComponent( j, c );
275
+ result.setComponent( j + tupleOffset, c, value );
276
+
277
+ }
278
+
279
+ }
280
+
281
+ } else {
282
+
283
+ array.set( attribute.array, offset );
284
+
285
+ }
286
+
287
+ offset += attribute.count * itemSize;
288
+
289
+ }
290
+
291
+ if ( gpuType !== undefined ) {
292
+
293
+ result.gpuType = gpuType;
294
+
295
+ }
296
+
297
+ return result;
298
+
299
+ }
300
+
301
+ /**
302
+ * Returns a new geometry with vertices for which all similar vertex attributes (within tolerance) are merged.
303
+ *
304
+ * @param {BufferGeometry} geometry - The geometry to merge vertices for.
305
+ * @param {number} [tolerance=1e-4] - The tolerance value.
306
+ * @return {BufferGeometry} - The new geometry with merged vertices.
307
+ */
308
+ function mergeVertices( geometry, tolerance = 1e-4 ) {
309
+
310
+ tolerance = Math.max( tolerance, Number.EPSILON );
311
+
312
+ // Generate an index buffer if the geometry doesn't have one, or optimize it
313
+ // if it's already available.
314
+ const hashToIndex = {};
315
+ const indices = geometry.getIndex();
316
+ const positions = geometry.getAttribute( 'position' );
317
+ const vertexCount = indices ? indices.count : positions.count;
318
+
319
+ // next value for triangle indices
320
+ let nextIndex = 0;
321
+
322
+ // attributes and new attribute arrays
323
+ const attributeNames = Object.keys( geometry.attributes );
324
+ const tmpAttributes = {};
325
+ const tmpMorphAttributes = {};
326
+ const newIndices = [];
327
+ const getters = [ 'getX', 'getY', 'getZ', 'getW' ];
328
+ const setters = [ 'setX', 'setY', 'setZ', 'setW' ];
329
+
330
+ // Initialize the arrays, allocating space conservatively. Extra
331
+ // space will be trimmed in the last step.
332
+ for ( let i = 0, l = attributeNames.length; i < l; i ++ ) {
333
+
334
+ const name = attributeNames[ i ];
335
+ const attr = geometry.attributes[ name ];
336
+
337
+ tmpAttributes[ name ] = new attr.constructor(
338
+ new attr.array.constructor( attr.count * attr.itemSize ),
339
+ attr.itemSize,
340
+ attr.normalized
341
+ );
342
+
343
+ const morphAttributes = geometry.morphAttributes[ name ];
344
+ if ( morphAttributes ) {
345
+
346
+ if ( ! tmpMorphAttributes[ name ] ) tmpMorphAttributes[ name ] = [];
347
+ morphAttributes.forEach( ( morphAttr, i ) => {
348
+
349
+ const array = new morphAttr.array.constructor( morphAttr.count * morphAttr.itemSize );
350
+ tmpMorphAttributes[ name ][ i ] = new morphAttr.constructor( array, morphAttr.itemSize, morphAttr.normalized );
351
+
352
+ } );
353
+
354
+ }
355
+
356
+ }
357
+
358
+ // convert the error tolerance to an amount of decimal places to truncate to
359
+ const halfTolerance = tolerance * 0.5;
360
+ const exponent = Math.log10( 1 / tolerance );
361
+ const hashMultiplier = Math.pow( 10, exponent );
362
+ const hashAdditive = halfTolerance * hashMultiplier;
363
+ for ( let i = 0; i < vertexCount; i ++ ) {
364
+
365
+ const index = indices ? indices.getX( i ) : i;
366
+
367
+ // Generate a hash for the vertex attributes at the current index 'i'
368
+ let hash = '';
369
+ for ( let j = 0, l = attributeNames.length; j < l; j ++ ) {
370
+
371
+ const name = attributeNames[ j ];
372
+ const attribute = geometry.getAttribute( name );
373
+ const itemSize = attribute.itemSize;
374
+
375
+ for ( let k = 0; k < itemSize; k ++ ) {
376
+
377
+ // double tilde truncates the decimal value
378
+ hash += `${ ~ ~ ( attribute[ getters[ k ] ]( index ) * hashMultiplier + hashAdditive ) },`;
379
+
380
+ }
381
+
382
+ }
383
+
384
+ // Add another reference to the vertex if it's already
385
+ // used by another index
386
+ if ( hash in hashToIndex ) {
387
+
388
+ newIndices.push( hashToIndex[ hash ] );
389
+
390
+ } else {
391
+
392
+ // copy data to the new index in the temporary attributes
393
+ for ( let j = 0, l = attributeNames.length; j < l; j ++ ) {
394
+
395
+ const name = attributeNames[ j ];
396
+ const attribute = geometry.getAttribute( name );
397
+ const morphAttributes = geometry.morphAttributes[ name ];
398
+ const itemSize = attribute.itemSize;
399
+ const newArray = tmpAttributes[ name ];
400
+ const newMorphArrays = tmpMorphAttributes[ name ];
401
+
402
+ for ( let k = 0; k < itemSize; k ++ ) {
403
+
404
+ const getterFunc = getters[ k ];
405
+ const setterFunc = setters[ k ];
406
+ newArray[ setterFunc ]( nextIndex, attribute[ getterFunc ]( index ) );
407
+
408
+ if ( morphAttributes ) {
409
+
410
+ for ( let m = 0, ml = morphAttributes.length; m < ml; m ++ ) {
411
+
412
+ newMorphArrays[ m ][ setterFunc ]( nextIndex, morphAttributes[ m ][ getterFunc ]( index ) );
413
+
414
+ }
415
+
416
+ }
417
+
418
+ }
419
+
420
+ }
421
+
422
+ hashToIndex[ hash ] = nextIndex;
423
+ newIndices.push( nextIndex );
424
+ nextIndex ++;
425
+
426
+ }
427
+
428
+ }
429
+
430
+ // generate result BufferGeometry
431
+ const result = geometry.clone();
432
+ for ( const name in geometry.attributes ) {
433
+
434
+ const tmpAttribute = tmpAttributes[ name ];
435
+
436
+ result.setAttribute( name, new tmpAttribute.constructor(
437
+ tmpAttribute.array.slice( 0, nextIndex * tmpAttribute.itemSize ),
438
+ tmpAttribute.itemSize,
439
+ tmpAttribute.normalized,
440
+ ) );
441
+
442
+ if ( ! ( name in tmpMorphAttributes ) ) continue;
443
+
444
+ for ( let j = 0; j < tmpMorphAttributes[ name ].length; j ++ ) {
445
+
446
+ const tmpMorphAttribute = tmpMorphAttributes[ name ][ j ];
447
+
448
+ result.morphAttributes[ name ][ j ] = new tmpMorphAttribute.constructor(
449
+ tmpMorphAttribute.array.slice( 0, nextIndex * tmpMorphAttribute.itemSize ),
450
+ tmpMorphAttribute.itemSize,
451
+ tmpMorphAttribute.normalized,
452
+ );
453
+
454
+ }
455
+
456
+ }
457
+
458
+ // indices
459
+
460
+ result.setIndex( newIndices );
461
+
462
+ return result;
463
+
464
+ }
465
+
7
466
  /**
8
467
  * Returns a new indexed geometry based on `TrianglesDrawMode` draw mode.
9
468
  * This mode corresponds to the `gl.TRIANGLES` primitive in WebGL.
@@ -117,4 +576,7 @@ function toTrianglesDrawMode( geometry, drawMode ) {
117
576
 
118
577
  }
119
578
 
579
+ exports.mergeAttributes = mergeAttributes;
580
+ exports.mergeGeometries = mergeGeometries;
581
+ exports.mergeVertices = mergeVertices;
120
582
  exports.toTrianglesDrawMode = toTrianglesDrawMode;
@@ -24,6 +24,7 @@ var hotReloadManager = require('./managers/system/hotReloadManager.js');
24
24
  var disposalManager = require('./managers/system/disposalManager.js');
25
25
  var performanceMonitor = require('./managers/system/performanceMonitor.js');
26
26
  var modelPreloader = require('./rendering/modelPreloader.js');
27
+ var objProcessor = require('./rendering/objProcessor.js');
27
28
  var rendering2D = require('./rendering/rendering2D.js');
28
29
  var rendering3D = require('./rendering/rendering3D.js');
29
30
  var _import = require('./data/import.js');
@@ -31,6 +32,7 @@ var _export = require('./data/export.js');
31
32
  var numerics = require('./data/numerics.js');
32
33
  var analysis = require('./analysis/analysis.js');
33
34
  var testing = require('./analysis/testing.js');
35
+ var objProcessingDemo = require('./testing/objProcessingDemo.js');
34
36
 
35
37
 
36
38
 
@@ -62,6 +64,7 @@ exports.HotReloadManager = hotReloadManager.HotReloadManager;
62
64
  exports.DisposalManager = disposalManager.DisposalManager;
63
65
  exports.PerformanceMonitor = performanceMonitor.PerformanceMonitor;
64
66
  exports.modelPreloader = modelPreloader["default"];
67
+ exports.ObjProcessor = objProcessor["default"];
65
68
  exports.Rendering2D = rendering2D;
66
69
  exports.Rendering3D = rendering3D;
67
70
  exports.ImportUtils = _import;
@@ -69,3 +72,4 @@ exports.ExportUtils = _export;
69
72
  exports.Numerics = numerics;
70
73
  exports.Analysis = analysis;
71
74
  exports.Testing = testing;
75
+ exports.ObjProcessingDemo = objProcessingDemo["default"];