@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.
@@ -2,6 +2,7 @@ import { createClass as _createClass, typeof as _typeof, classCallCheck as _clas
2
2
  import * as THREE from 'three';
3
3
  import { GLTFLoader } from '../../node_modules/three/examples/jsm/loaders/GLTFLoader.js';
4
4
  import { OBJLoader } from '../../node_modules/three/examples/jsm/loaders/OBJLoader.js';
5
+ import ObjProcessor from './objProcessor.js';
5
6
 
6
7
  var ModelPreloader = /*#__PURE__*/function () {
7
8
  function ModelPreloader() {
@@ -10,10 +11,12 @@ var ModelPreloader = /*#__PURE__*/function () {
10
11
  this.loadingPromises = new Map(); // Track ongoing loads to prevent duplicates
11
12
  this.gltfLoader = new GLTFLoader();
12
13
  this.objLoader = new OBJLoader();
14
+ this.objProcessor = new ObjProcessor(); // Initialize OBJ processor
13
15
  this.isPreloading = false;
14
16
  this.preloadingPromise = null;
15
17
  this.componentDictionary = null;
16
18
  console.log('🚀 ModelPreloader initialized with GLB and OBJ support');
19
+ console.log('🔧 OBJ Processor integrated for indexed BufferGeometry conversion');
17
20
  }
18
21
 
19
22
  /**
@@ -119,93 +122,137 @@ var ModelPreloader = /*#__PURE__*/function () {
119
122
  }, {
120
123
  key: "preloadSingleModel",
121
124
  value: (function () {
122
- var _preloadSingleModel = _asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee2(modelKey) {
125
+ var _preloadSingleModel = _asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee3(modelKey) {
123
126
  var _this2 = this;
124
127
  var modelType,
125
128
  loadPromise,
126
- _args2 = arguments;
127
- return _regenerator().w(function (_context2) {
128
- while (1) switch (_context2.n) {
129
+ _args3 = arguments;
130
+ return _regenerator().w(function (_context3) {
131
+ while (1) switch (_context3.n) {
129
132
  case 0:
130
- modelType = _args2.length > 1 && _args2[1] !== undefined ? _args2[1] : 'glb';
133
+ modelType = _args3.length > 1 && _args3[1] !== undefined ? _args3[1] : 'glb';
131
134
  if (!this.modelCache.has(modelKey)) {
132
- _context2.n = 1;
135
+ _context3.n = 1;
133
136
  break;
134
137
  }
135
138
  console.log("\uD83C\uDFAF Model ".concat(modelKey, " already cached, skipping"));
136
- return _context2.a(2, this.modelCache.get(modelKey));
139
+ return _context3.a(2, this.modelCache.get(modelKey));
137
140
  case 1:
138
141
  if (!this.loadingPromises.has(modelKey)) {
139
- _context2.n = 2;
142
+ _context3.n = 2;
140
143
  break;
141
144
  }
142
145
  console.log("\u23F3 Model ".concat(modelKey, " already loading, waiting for completion"));
143
- return _context2.a(2, this.loadingPromises.get(modelKey));
146
+ return _context3.a(2, this.loadingPromises.get(modelKey));
144
147
  case 2:
145
148
  console.log("\uD83D\uDD04 Starting preload of ".concat(modelType.toUpperCase(), " model: ").concat(modelKey));
146
149
  loadPromise = new Promise(function (resolve, reject) {
147
150
  var modelPath = "/library/models/".concat(modelKey);
148
151
  if (modelType === 'obj') {
149
- // Load OBJ model
150
- _this2.objLoader.load(modelPath, function (object) {
151
- console.log("\u2705 Successfully preloaded OBJ model: ".concat(modelKey));
152
-
153
- // Apply double-sided materials to OBJ models with both solid and wireframe
154
- object.traverse(function (child) {
155
- if (child.isMesh) {
156
- // Create a solid material first
157
- var solidMaterial = new THREE.MeshStandardMaterial({
158
- color: child.material.color || 0x888888,
159
- side: THREE.DoubleSide,
160
- wireframe: false
161
- });
162
-
163
- // Set the solid material
164
- child.material = solidMaterial;
165
-
166
- // Create wireframe overlay by cloning the geometry
167
- var wireframeGeometry = child.geometry.clone();
168
- var wireframeMaterial = new THREE.MeshBasicMaterial({
169
- color: 0x000000,
170
- wireframe: true,
171
- transparent: true,
172
- opacity: 0.8
173
- });
174
-
175
- // Create wireframe mesh with same geometry
176
- var wireframeMesh = new THREE.Mesh(wireframeGeometry, wireframeMaterial);
177
- wireframeMesh.name = child.name + '_wireframe';
178
-
179
- // Position wireframe slightly forward to avoid z-fighting
180
- wireframeMesh.position.copy(child.position);
181
- wireframeMesh.rotation.copy(child.rotation);
182
- wireframeMesh.scale.copy(child.scale);
183
- wireframeMesh.scale.multiplyScalar(1.001); // Slightly larger to sit on top
184
-
185
- // Add wireframe as sibling to the parent
186
- if (child.parent) {
187
- child.parent.add(wireframeMesh);
152
+ // Load OBJ model with advanced processing
153
+ _this2.objLoader.load(modelPath, /*#__PURE__*/function () {
154
+ var _ref = _asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee2(object) {
155
+ var processedResult, modelData, _t;
156
+ return _regenerator().w(function (_context2) {
157
+ while (1) switch (_context2.n) {
158
+ case 0:
159
+ _context2.p = 0;
160
+ console.log("\u2705 Successfully loaded OBJ model: ".concat(modelKey));
161
+
162
+ // Process OBJ with the new processor for indexed BufferGeometry
163
+ _context2.n = 1;
164
+ return _this2.objProcessor.processObjObject(object, modelKey, true);
165
+ case 1:
166
+ processedResult = _context2.v;
167
+ if (!processedResult) {
168
+ _context2.n = 2;
169
+ break;
170
+ }
171
+ console.log("\uD83D\uDD27 OBJ processed to indexed BufferGeometry: ".concat(modelKey));
172
+ console.log("\uD83D\uDCCA Geometry stats:", processedResult.stats);
173
+
174
+ // Apply double-sided materials with solid + wireframe overlay
175
+ object.traverse(function (child) {
176
+ if (child.isMesh) {
177
+ // Create solid material
178
+ var solidMaterial = new THREE.MeshStandardMaterial({
179
+ color: child.material.color || 0x888888,
180
+ side: THREE.DoubleSide,
181
+ wireframe: false
182
+ // transparent: true,
183
+ // opacity: 0.8 // Slightly transparent to show wireframe better
184
+ });
185
+
186
+ // Create wireframe material
187
+ var wireframeMaterial = new THREE.MeshBasicMaterial({
188
+ color: 0x000000,
189
+ // Black wireframe
190
+ wireframe: true,
191
+ // transparent: true,
192
+ // opacity: 0.6,
193
+ side: THREE.DoubleSide
194
+ });
195
+
196
+ // Apply solid material to the original mesh
197
+ child.material = solidMaterial;
198
+
199
+ // Create a wireframe mesh clone and add it as a child
200
+ var wireframeMesh = new THREE.Mesh(child.geometry, wireframeMaterial);
201
+ wireframeMesh.position.copy(child.position);
202
+ wireframeMesh.rotation.copy(child.rotation);
203
+ wireframeMesh.scale.copy(child.scale);
204
+ wireframeMesh.name = child.name + '_wireframe';
205
+ wireframeMesh.userData.isWireframeOverlay = true;
206
+
207
+ // Add wireframe mesh to the same parent
208
+ if (child.parent) {
209
+ child.parent.add(wireframeMesh);
210
+ }
211
+ }
212
+ });
213
+ // Store both the original object and processed data
214
+ modelData = {
215
+ originalObject: object,
216
+ processedGeometry: processedResult.geometry,
217
+ geometryStats: processedResult.stats,
218
+ materials: processedResult.materials,
219
+ isObjModel: true
220
+ }; // Cache the model data
221
+ _this2.modelCache.set(modelKey, modelData);
222
+ _this2.loadingPromises.delete(modelKey);
223
+ resolve(modelData);
224
+ _context2.n = 3;
225
+ break;
226
+ case 2:
227
+ throw new Error('Failed to process OBJ to indexed geometry');
228
+ case 3:
229
+ _context2.n = 5;
230
+ break;
231
+ case 4:
232
+ _context2.p = 4;
233
+ _t = _context2.v;
234
+ console.error("\u274C Error processing OBJ model ".concat(modelKey, ":"), _t);
235
+ // Fallback: cache the original object without processing
236
+ _this2.modelCache.set(modelKey, object);
237
+ _this2.loadingPromises.delete(modelKey);
238
+ resolve(object);
239
+ case 5:
240
+ return _context2.a(2);
188
241
  }
189
- }
190
- });
191
-
192
- // Cache the object for future use
193
- _this2.modelCache.set(modelKey, object);
194
- // Remove from loading promises
195
- _this2.loadingPromises.delete(modelKey);
196
- resolve(object);
197
- }, function (progress) {
198
- // Optional: track loading progress
242
+ }, _callee2, null, [[0, 4]]);
243
+ }));
244
+ return function (_x3) {
245
+ return _ref.apply(this, arguments);
246
+ };
247
+ }(), function (progress) {
199
248
  if (progress.lengthComputable) {
200
249
  var percentage = progress.loaded / progress.total * 100;
201
250
  if (percentage % 25 === 0) {
202
- // Log every 25%
203
251
  console.log("\uD83D\uDCCA Loading OBJ ".concat(modelKey, ": ").concat(percentage.toFixed(0), "%"));
204
252
  }
205
253
  }
206
254
  }, function (error) {
207
255
  console.error("\u274C Failed to preload OBJ model ".concat(modelKey, ":"), error);
208
- // Remove from loading promises
209
256
  _this2.loadingPromises.delete(modelKey);
210
257
  reject(error);
211
258
  });
@@ -236,9 +283,9 @@ var ModelPreloader = /*#__PURE__*/function () {
236
283
  }
237
284
  }); // Cache the loading promise
238
285
  this.loadingPromises.set(modelKey, loadPromise);
239
- return _context2.a(2, loadPromise);
286
+ return _context3.a(2, loadPromise);
240
287
  }
241
- }, _callee2, this);
288
+ }, _callee3, this);
242
289
  }));
243
290
  function preloadSingleModel(_x2) {
244
291
  return _preloadSingleModel.apply(this, arguments);
@@ -248,18 +295,42 @@ var ModelPreloader = /*#__PURE__*/function () {
248
295
  /**
249
296
  * Get a cached model (cloned for use)
250
297
  * @param {string} modelKey - The model key
298
+ * @param {boolean} useIndexedGeometry - Whether to use indexed geometry for OBJ models
251
299
  * @returns {THREE.Object3D|null} Cloned model or null if not found
252
300
  */
253
301
  )
254
302
  }, {
255
303
  key: "getCachedModel",
256
304
  value: function getCachedModel(modelKey) {
305
+ var useIndexedGeometry = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : false;
257
306
  if (this.modelCache.has(modelKey)) {
258
307
  console.log("\uD83C\uDFAF Returning cached model: ".concat(modelKey));
259
- var clonedModel = this.modelCache.get(modelKey).clone();
308
+ var cachedData = this.modelCache.get(modelKey);
309
+
310
+ // Handle OBJ models with processed geometry
311
+ if (cachedData && cachedData.isObjModel && useIndexedGeometry && cachedData.processedGeometry) {
312
+ console.log("\uD83D\uDD27 Using indexed BufferGeometry for OBJ: ".concat(modelKey));
260
313
 
261
- // Determine model type from the modelKey extension
262
- modelKey.toLowerCase().endsWith('.obj') ? 'obj' : 'glb';
314
+ // Create a mesh from the processed indexed geometry
315
+ var mesh = new THREE.Mesh(cachedData.processedGeometry.clone(), cachedData.materials.clone());
316
+
317
+ // Add metadata
318
+ mesh.userData.modelKey = modelKey;
319
+ mesh.userData.geometryStats = cachedData.geometryStats;
320
+ mesh.userData.isIndexedGeometry = true;
321
+ mesh.userData.originalSizeKB = cachedData.geometryStats.sizeKB;
322
+ return mesh;
323
+ }
324
+
325
+ // Handle regular models or OBJ models without indexed geometry
326
+ var modelToClone = cachedData.isObjModel ? cachedData.originalObject : cachedData;
327
+ var clonedModel = modelToClone.clone();
328
+
329
+ // Add OBJ stats if available
330
+ if (cachedData.isObjModel && cachedData.geometryStats) {
331
+ clonedModel.userData.geometryStats = cachedData.geometryStats;
332
+ clonedModel.userData.isObjModel = true;
333
+ }
263
334
  return clonedModel;
264
335
  }
265
336
  console.warn("\u26A0\uFE0F Model ".concat(modelKey, " not found in cache"));
@@ -278,7 +349,26 @@ var ModelPreloader = /*#__PURE__*/function () {
278
349
  var libraryId = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : null;
279
350
  if (this.modelCache.has(modelKey)) {
280
351
  console.log("\uD83C\uDFAF Returning cached model with dimensions: ".concat(modelKey));
281
- var clonedModel = this.modelCache.get(modelKey).clone();
352
+ var cachedData = this.modelCache.get(modelKey);
353
+
354
+ // Handle OBJ models with processed geometry structure
355
+ var clonedModel;
356
+ if (cachedData && cachedData.isObjModel) {
357
+ // Clone the original OBJ object
358
+ clonedModel = cachedData.originalObject.clone();
359
+
360
+ // Add OBJ stats if available
361
+ if (cachedData.geometryStats) {
362
+ if (!clonedModel.userData) {
363
+ clonedModel.userData = {};
364
+ }
365
+ clonedModel.userData.geometryStats = cachedData.geometryStats;
366
+ clonedModel.userData.isObjModel = true;
367
+ }
368
+ } else {
369
+ // Handle regular GLB models
370
+ clonedModel = cachedData.clone();
371
+ }
282
372
 
283
373
  // Add dimensions from component dictionary if available
284
374
  if (libraryId && this.componentDictionary) {
@@ -367,41 +457,41 @@ var ModelPreloader = /*#__PURE__*/function () {
367
457
  }, {
368
458
  key: "reloadModel",
369
459
  value: (function () {
370
- var _reloadModel = _asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee3(modelKey) {
460
+ var _reloadModel = _asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee4(modelKey) {
371
461
  var modelType,
372
462
  _i,
373
463
  _Object$keys,
374
464
  componentType,
375
465
  component,
376
- _args3 = arguments;
377
- return _regenerator().w(function (_context3) {
378
- while (1) switch (_context3.n) {
466
+ _args4 = arguments;
467
+ return _regenerator().w(function (_context4) {
468
+ while (1) switch (_context4.n) {
379
469
  case 0:
380
- modelType = _args3.length > 1 && _args3[1] !== undefined ? _args3[1] : null;
470
+ modelType = _args4.length > 1 && _args4[1] !== undefined ? _args4[1] : null;
381
471
  console.log("\uD83D\uDD04 Force reloading model: ".concat(modelKey));
382
472
 
383
473
  // Try to determine model type from component dictionary if not provided
384
474
  if (!(!modelType && this.componentDictionary)) {
385
- _context3.n = 3;
475
+ _context4.n = 3;
386
476
  break;
387
477
  }
388
478
  _i = 0, _Object$keys = Object.keys(this.componentDictionary);
389
479
  case 1:
390
480
  if (!(_i < _Object$keys.length)) {
391
- _context3.n = 3;
481
+ _context4.n = 3;
392
482
  break;
393
483
  }
394
484
  componentType = _Object$keys[_i];
395
485
  component = this.componentDictionary[componentType];
396
486
  if (!(component && component.modelKey === modelKey)) {
397
- _context3.n = 2;
487
+ _context4.n = 2;
398
488
  break;
399
489
  }
400
490
  modelType = component.modelType || 'glb';
401
- return _context3.a(3, 3);
491
+ return _context4.a(3, 3);
402
492
  case 2:
403
493
  _i++;
404
- _context3.n = 1;
494
+ _context4.n = 1;
405
495
  break;
406
496
  case 3:
407
497
  // Default to GLB if still not determined
@@ -412,11 +502,11 @@ var ModelPreloader = /*#__PURE__*/function () {
412
502
  this.loadingPromises.delete(modelKey);
413
503
 
414
504
  // Preload again
415
- return _context3.a(2, this.preloadSingleModel(modelKey, modelType));
505
+ return _context4.a(2, this.preloadSingleModel(modelKey, modelType));
416
506
  }
417
- }, _callee3, this);
507
+ }, _callee4, this);
418
508
  }));
419
- function reloadModel(_x3) {
509
+ function reloadModel(_x4) {
420
510
  return _reloadModel.apply(this, arguments);
421
511
  }
422
512
  return reloadModel;
@@ -433,7 +523,42 @@ var ModelPreloader = /*#__PURE__*/function () {
433
523
  // Dispose of all cached models
434
524
  this.modelCache.forEach(function (model, modelKey) {
435
525
  console.log("\uD83D\uDDD1\uFE0F Disposing cached model: ".concat(modelKey));
436
- if (model && model.traverse) {
526
+ if (model && model.isObjModel) {
527
+ // Handle OBJ model data structure
528
+ if (model.originalObject && model.originalObject.traverse) {
529
+ model.originalObject.traverse(function (child) {
530
+ if (child.geometry) {
531
+ child.geometry.dispose();
532
+ }
533
+ if (child.material) {
534
+ if (Array.isArray(child.material)) {
535
+ child.material.forEach(function (material) {
536
+ return material.dispose();
537
+ });
538
+ } else {
539
+ child.material.dispose();
540
+ }
541
+ }
542
+ });
543
+ }
544
+
545
+ // Dispose processed geometry
546
+ if (model.processedGeometry) {
547
+ model.processedGeometry.dispose();
548
+ }
549
+
550
+ // Dispose materials
551
+ if (model.materials) {
552
+ if (Array.isArray(model.materials)) {
553
+ model.materials.forEach(function (material) {
554
+ return material.dispose();
555
+ });
556
+ } else {
557
+ model.materials.dispose();
558
+ }
559
+ }
560
+ } else if (model && model.traverse) {
561
+ // Handle regular model
437
562
  model.traverse(function (child) {
438
563
  if (child.geometry) {
439
564
  child.geometry.dispose();
@@ -454,6 +579,9 @@ var ModelPreloader = /*#__PURE__*/function () {
454
579
  this.loadingPromises.clear();
455
580
  this.isPreloading = false;
456
581
  this.preloadingPromise = null;
582
+
583
+ // Clear OBJ processor caches
584
+ this.objProcessor.clearCaches();
457
585
  console.log('✅ Model preloader cache cleared');
458
586
  }
459
587
 
@@ -526,7 +654,24 @@ var ModelPreloader = /*#__PURE__*/function () {
526
654
  console.log("\uD83D\uDD04 Loading model for library ID ".concat(libraryId, ": ").concat(modelKey, " (").concat(modelType.toUpperCase(), ")"));
527
655
  this.preloadSingleModel(modelKey, modelType).then(function (model) {
528
656
  if (model) {
529
- var _clonedModel = model.clone();
657
+ // Handle OBJ models with processed geometry structure
658
+ var _clonedModel;
659
+ if (model && model.isObjModel) {
660
+ // Clone the original OBJ object
661
+ _clonedModel = model.originalObject.clone();
662
+
663
+ // Add OBJ stats if available
664
+ if (model.geometryStats) {
665
+ if (!_clonedModel.userData) {
666
+ _clonedModel.userData = {};
667
+ }
668
+ _clonedModel.userData.geometryStats = model.geometryStats;
669
+ _clonedModel.userData.isObjModel = true;
670
+ }
671
+ } else {
672
+ // Handle regular GLB models
673
+ _clonedModel = model.clone();
674
+ }
530
675
 
531
676
  // Add dimensions if available
532
677
  if (componentData.boundingBox) {
@@ -562,13 +707,15 @@ var ModelPreloader = /*#__PURE__*/function () {
562
707
  totalModels: this.modelCache.size,
563
708
  loadingModels: this.loadingPromises.size,
564
709
  isPreloading: this.isPreloading,
565
- memoryUsage: 0
710
+ memoryUsage: 0,
711
+ objProcessorStats: this.objProcessor.getStatus()
566
712
  };
567
713
 
568
714
  // Estimate memory usage (rough calculation)
569
715
  this.modelCache.forEach(function (model) {
570
716
  if (model && model.traverse) {
571
- model.traverse(function (child) {
717
+ var modelToAnalyze = model.isObjModel ? model.originalObject : model;
718
+ modelToAnalyze.traverse(function (child) {
572
719
  if (child.geometry) {
573
720
  var _child$geometry$attri;
574
721
  stats.memoryUsage += (((_child$geometry$attri = child.geometry.attributes.position) === null || _child$geometry$attri === void 0 ? void 0 : _child$geometry$attri.count) || 0) * 12; // Rough estimate
@@ -578,6 +725,124 @@ var ModelPreloader = /*#__PURE__*/function () {
578
725
  });
579
726
  return stats;
580
727
  }
728
+
729
+ /**
730
+ * Get all OBJ geometry statistics
731
+ * @returns {Array} Array of OBJ geometry statistics
732
+ */
733
+ }, {
734
+ key: "getObjGeometryStats",
735
+ value: function getObjGeometryStats() {
736
+ return this.objProcessor.getAllGeometryStats();
737
+ }
738
+
739
+ /**
740
+ * Get OBJ processor memory usage
741
+ * @returns {Object} Memory usage statistics
742
+ */
743
+ }, {
744
+ key: "getObjMemoryUsage",
745
+ value: function getObjMemoryUsage() {
746
+ return this.objProcessor.getMemoryUsage();
747
+ }
748
+
749
+ /**
750
+ * Create a custom mesh from indexed OBJ geometry
751
+ * @param {string} modelKey - The model key (must be an OBJ)
752
+ * @param {THREE.Material} material - Optional material to use
753
+ * @returns {THREE.Mesh|null} The created mesh or null if not found
754
+ */
755
+ }, {
756
+ key: "createCustomObjMesh",
757
+ value: function createCustomObjMesh(modelKey) {
758
+ var material = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : null;
759
+ return this.objProcessor.createCustomMesh(modelKey, material);
760
+ }
761
+
762
+ /**
763
+ * Get indexed geometry directly from processor
764
+ * @param {string} modelKey - The model key
765
+ * @returns {THREE.BufferGeometry|null} The indexed geometry or null
766
+ */
767
+ }, {
768
+ key: "getIndexedGeometry",
769
+ value: function getIndexedGeometry(modelKey) {
770
+ var result = this.objProcessor.indexedGeometryCache.get(modelKey);
771
+ return result ? result.geometry.clone() : null;
772
+ }
773
+
774
+ /**
775
+ * Toggle wireframe visibility on an OBJ model
776
+ * @param {THREE.Object3D} model - The model to toggle wireframe on
777
+ * @param {boolean} visible - Whether wireframe should be visible
778
+ */
779
+ }, {
780
+ key: "toggleWireframe",
781
+ value: function toggleWireframe(model) {
782
+ var visible = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : true;
783
+ if (!model) return;
784
+ model.traverse(function (child) {
785
+ if (child.userData && child.userData.isWireframeOverlay) {
786
+ child.visible = visible;
787
+ }
788
+ });
789
+ }
790
+
791
+ /**
792
+ * Update wireframe appearance on an OBJ model
793
+ * @param {THREE.Object3D} model - The model to update
794
+ * @param {Object} options - Wireframe options {color, opacity, visible}
795
+ */
796
+ }, {
797
+ key: "updateWireframeAppearance",
798
+ value: function updateWireframeAppearance(model) {
799
+ var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
800
+ if (!model) return;
801
+ var _options$color = options.color,
802
+ color = _options$color === void 0 ? 0x000000 : _options$color,
803
+ _options$opacity = options.opacity,
804
+ opacity = _options$opacity === void 0 ? 0.6 : _options$opacity,
805
+ _options$visible = options.visible,
806
+ visible = _options$visible === void 0 ? true : _options$visible;
807
+ model.traverse(function (child) {
808
+ if (child.userData && child.userData.isWireframeOverlay && child.material) {
809
+ child.material.color.setHex(color);
810
+ child.material.opacity = opacity;
811
+ child.visible = visible;
812
+ }
813
+ });
814
+ }
815
+
816
+ /**
817
+ * Force reload and reprocess an OBJ model
818
+ * @param {string} modelKey - The model key to reload
819
+ * @returns {Promise} Promise that resolves with the reloaded model
820
+ */
821
+ }, {
822
+ key: "reloadObjModel",
823
+ value: (function () {
824
+ var _reloadObjModel = _asyncToGenerator(/*#__PURE__*/_regenerator().m(function _callee5(modelKey) {
825
+ return _regenerator().w(function (_context5) {
826
+ while (1) switch (_context5.n) {
827
+ case 0:
828
+ console.log("\uD83D\uDD04 Force reloading OBJ model: ".concat(modelKey));
829
+
830
+ // Clear from both caches
831
+ this.modelCache.delete(modelKey);
832
+ this.loadingPromises.delete(modelKey);
833
+ this.objProcessor.indexedGeometryCache.delete(modelKey);
834
+ this.objProcessor.geometrySizeCache.delete(modelKey);
835
+
836
+ // Reload with OBJ processing
837
+ return _context5.a(2, this.preloadSingleModel(modelKey, 'obj'));
838
+ }
839
+ }, _callee5, this);
840
+ }));
841
+ function reloadObjModel(_x5) {
842
+ return _reloadObjModel.apply(this, arguments);
843
+ }
844
+ return reloadObjModel;
845
+ }())
581
846
  }]);
582
847
  }(); // Create singleton instance
583
848
  var modelPreloader = new ModelPreloader();