fl-web-component 2.0.8 → 2.0.9
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.
- package/README.md +2 -0
- package/dist/fl-web-component.common.js +7198 -1250
- package/dist/fl-web-component.common.js.map +1 -1
- package/dist/fl-web-component.css +1 -1
- package/package.json +1 -1
- package/packages/components/com-graphics/component/context.js +123 -0
- package/packages/components/com-graphics/index.vue +1148 -69
- package/packages/utils/StreamLoader.js +73 -16
- package/src/utils/threejs/editor/command.js +36 -0
- package/src/utils/threejs/editor/commands/add-element-command.js +41 -0
- package/src/utils/threejs/editor/commands/add-group-command.js +10 -0
- package/src/utils/threejs/editor/commands/clone-element-command.js +100 -0
- package/src/utils/threejs/editor/commands/move-element-command.js +57 -0
- package/src/utils/threejs/editor/commands/multi-command.js +29 -0
- package/src/utils/threejs/editor/commands/remove-element-command.js +46 -0
- package/src/utils/threejs/editor/commands/reset-original-model-style-command.js +30 -0
- package/src/utils/threejs/editor/commands/set-geometry-params-command.js +41 -0
- package/src/utils/threejs/editor/commands/set-original-model-style-command.js +56 -0
- package/src/utils/threejs/editor/commands/set-position-command.js +54 -0
- package/src/utils/threejs/editor/commands/set-rotation-command.js +53 -0
- package/src/utils/threejs/editor/commands/set-scale-command.js +54 -0
- package/src/utils/threejs/editor/commands/set-value-command.js +107 -0
- package/src/utils/threejs/editor/constants.js +107 -0
- package/src/utils/threejs/editor/element-factory.js +163 -0
- package/src/utils/threejs/editor/event-bus.js +34 -0
- package/src/utils/threejs/editor/history.js +80 -0
- package/src/utils/threejs/editor/scene-command-service.js +1529 -0
- package/src/utils/threejs/editor/scene-event-bridge.js +32 -0
- package/src/utils/threejs/editor/scene-helpers.js +415 -0
|
@@ -128,6 +128,7 @@ import { RoomEnvironment } from 'three/examples/jsm/environments/RoomEnvironment
|
|
|
128
128
|
import { CSS2DObject } from 'three/examples/jsm/renderers/CSS2DRenderer';
|
|
129
129
|
import { CSS2DRenderer } from 'three/examples/jsm/renderers/CSS2DRenderer';
|
|
130
130
|
import { PointerLockControls } from 'three/examples/jsm/controls/PointerLockControls.js';
|
|
131
|
+
import { TransformControls } from 'three/examples/jsm/controls/TransformControls.js';
|
|
131
132
|
import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader';
|
|
132
133
|
import { GUI } from 'three/examples/jsm/libs/lil-gui.module.min.js';
|
|
133
134
|
import MeasureDistance from '@/utils/threejs/measure-distance.js';
|
|
@@ -155,6 +156,10 @@ import { OBB } from 'three/examples/jsm/math/OBB.js';
|
|
|
155
156
|
import boxJson from './box.json';
|
|
156
157
|
import { StreamLoader } from '../../utils/StreamLoader.js';
|
|
157
158
|
import StreamLoaderParserWorker from '../../utils/StreamLoaderParser.worker.js';
|
|
159
|
+
import SceneCommandService from '@/utils/threejs/editor/scene-command-service.js';
|
|
160
|
+
import { EDITOR_EVENT, SCENE_NODE_TYPE, TRANSFORM_MODE } from '@/utils/threejs/editor/constants.js';
|
|
161
|
+
import { isCustomRoot, isTransformAttachableObject } from '@/utils/threejs/editor/scene-helpers.js';
|
|
162
|
+
import { onContextHandle } from './component/context';
|
|
158
163
|
|
|
159
164
|
const isDebug = process.env.NODE_ENV !== 'production' || process.env.VUE_APP_IS_WATCH === true;
|
|
160
165
|
// const isDebug = false;
|
|
@@ -168,6 +173,10 @@ export default {
|
|
|
168
173
|
return {};
|
|
169
174
|
},
|
|
170
175
|
},
|
|
176
|
+
transformEditDisabled: {
|
|
177
|
+
type: Boolean,
|
|
178
|
+
default: false,
|
|
179
|
+
},
|
|
171
180
|
containId: {
|
|
172
181
|
type: String,
|
|
173
182
|
default: 'fl-model',
|
|
@@ -200,8 +209,16 @@ export default {
|
|
|
200
209
|
totalCount: 0,
|
|
201
210
|
isPaused: false,
|
|
202
211
|
},
|
|
212
|
+
isolateMode: false,
|
|
203
213
|
};
|
|
204
214
|
},
|
|
215
|
+
watch: {
|
|
216
|
+
transformEditDisabled(val) {
|
|
217
|
+
if (val) {
|
|
218
|
+
this.detachTransformControls();
|
|
219
|
+
}
|
|
220
|
+
},
|
|
221
|
+
},
|
|
205
222
|
beforeCreate() {
|
|
206
223
|
this.spaceUp = true;
|
|
207
224
|
let arr = [
|
|
@@ -345,6 +362,23 @@ export default {
|
|
|
345
362
|
occlusionWorkerRequestMap: new Map(),
|
|
346
363
|
occlusionWorkerRequestId: 0,
|
|
347
364
|
};
|
|
365
|
+
this.sceneCommandService = null;
|
|
366
|
+
this.sceneCommandEventDisposers = [];
|
|
367
|
+
this.transformEditor = {
|
|
368
|
+
transformControls: null,
|
|
369
|
+
transformHelper: null,
|
|
370
|
+
transformMode: TRANSFORM_MODE.TRANSLATE,
|
|
371
|
+
transforming: false,
|
|
372
|
+
transformTargetUuid: '',
|
|
373
|
+
transformStartSnapshot: null,
|
|
374
|
+
suppressSelectionOnce: false,
|
|
375
|
+
suppressSelectionTimer: null,
|
|
376
|
+
cameraControlsEnabled: true,
|
|
377
|
+
pointerCameraGuard: false,
|
|
378
|
+
pointerCameraEnabled: true,
|
|
379
|
+
keydownHandler: null,
|
|
380
|
+
handlers: {},
|
|
381
|
+
};
|
|
348
382
|
this.modelGroups = [];
|
|
349
383
|
this.modelActions = [];
|
|
350
384
|
this.lastMiddleClickTime = 0;
|
|
@@ -369,8 +403,10 @@ export default {
|
|
|
369
403
|
this.instructions = document.getElementById(this.containId); // 'fl-model'
|
|
370
404
|
this.initRender();
|
|
371
405
|
this.initScene();
|
|
406
|
+
this.initSceneCommandService();
|
|
372
407
|
this.initCamera();
|
|
373
408
|
this.initControl();
|
|
409
|
+
this.initTransformControls();
|
|
374
410
|
this.initPostProcessing();
|
|
375
411
|
// 初始化统一的相机事件监听
|
|
376
412
|
this.initCameraChangeObserver();
|
|
@@ -379,14 +415,7 @@ export default {
|
|
|
379
415
|
this.exportParmas();
|
|
380
416
|
|
|
381
417
|
// 判断是设备是手机还是电脑
|
|
382
|
-
|
|
383
|
-
if (isMobileDevice) {
|
|
384
|
-
this.renderer.domElement.addEventListener('pointerup', this.mouseClick, false);
|
|
385
|
-
this.renderer.domElement.addEventListener('pointerdown', this.mouseDown, false);
|
|
386
|
-
} else {
|
|
387
|
-
this.renderer.domElement.addEventListener('mouseup', this.mouseClick, false);
|
|
388
|
-
this.renderer.domElement.addEventListener('mousedown', this.mouseDown, false);
|
|
389
|
-
}
|
|
418
|
+
this.bindScenePointerEvents();
|
|
390
419
|
this.animate();
|
|
391
420
|
},
|
|
392
421
|
beforeDestroy() {
|
|
@@ -394,6 +423,764 @@ export default {
|
|
|
394
423
|
this.destroyScene();
|
|
395
424
|
},
|
|
396
425
|
methods: {
|
|
426
|
+
bindScenePointerEvents() {
|
|
427
|
+
if (!this.renderer || !this.renderer.domElement) return;
|
|
428
|
+
this.renderer.domElement.addEventListener('pointerup', this.mouseClick, true);
|
|
429
|
+
this.renderer.domElement.addEventListener('pointerdown', this.mouseDown, true);
|
|
430
|
+
},
|
|
431
|
+
unbindScenePointerEvents() {
|
|
432
|
+
if (!this.renderer || !this.renderer.domElement) return;
|
|
433
|
+
this.renderer.domElement.removeEventListener('pointerup', this.mouseClick, true);
|
|
434
|
+
this.renderer.domElement.removeEventListener('pointerdown', this.mouseDown, true);
|
|
435
|
+
this.renderer.domElement.removeEventListener('mouseup', this.mouseClick, false);
|
|
436
|
+
this.renderer.domElement.removeEventListener('mousedown', this.mouseDown, false);
|
|
437
|
+
this.renderer.domElement.removeEventListener('pointerup', this.mouseClick, false);
|
|
438
|
+
this.renderer.domElement.removeEventListener('pointerdown', this.mouseDown, false);
|
|
439
|
+
},
|
|
440
|
+
setPointerCameraGuard(active) {
|
|
441
|
+
const editor = this.transformEditor;
|
|
442
|
+
if (!editor || !this.cameraControls) return;
|
|
443
|
+
if (active) {
|
|
444
|
+
if (editor.pointerCameraGuard) return;
|
|
445
|
+
editor.pointerCameraEnabled = this.cameraControls.enabled;
|
|
446
|
+
editor.pointerCameraGuard = true;
|
|
447
|
+
this.cameraControls.enabled = false;
|
|
448
|
+
return;
|
|
449
|
+
}
|
|
450
|
+
if (!editor.pointerCameraGuard) {
|
|
451
|
+
this.restoreTransformCameraControls();
|
|
452
|
+
return;
|
|
453
|
+
}
|
|
454
|
+
if (!(this.firstPerSign && this.pointControls && this.pointControls.isLocked)) {
|
|
455
|
+
this.cameraControls.enabled = editor.pointerCameraEnabled || editor.cameraControlsEnabled;
|
|
456
|
+
}
|
|
457
|
+
editor.pointerCameraGuard = false;
|
|
458
|
+
},
|
|
459
|
+
restoreTransformCameraControls() {
|
|
460
|
+
const editor = this.transformEditor;
|
|
461
|
+
if (!editor || !this.cameraControls) return;
|
|
462
|
+
const isFirstPersonLocked = !!(
|
|
463
|
+
this.firstPerSign &&
|
|
464
|
+
this.pointControls &&
|
|
465
|
+
this.pointControls.isLocked
|
|
466
|
+
);
|
|
467
|
+
editor.pointerCameraGuard = false;
|
|
468
|
+
editor.transforming = false;
|
|
469
|
+
if (!isFirstPersonLocked) {
|
|
470
|
+
this.cameraControls.enabled = true;
|
|
471
|
+
editor.cameraControlsEnabled = true;
|
|
472
|
+
editor.pointerCameraEnabled = true;
|
|
473
|
+
}
|
|
474
|
+
},
|
|
475
|
+
scheduleSuppressSelectionOnce() {
|
|
476
|
+
const editor = this.transformEditor;
|
|
477
|
+
if (!editor) return;
|
|
478
|
+
editor.suppressSelectionOnce = true;
|
|
479
|
+
if (editor.suppressSelectionTimer) {
|
|
480
|
+
clearTimeout(editor.suppressSelectionTimer);
|
|
481
|
+
}
|
|
482
|
+
editor.suppressSelectionTimer = setTimeout(() => {
|
|
483
|
+
editor.suppressSelectionOnce = false;
|
|
484
|
+
editor.suppressSelectionTimer = null;
|
|
485
|
+
}, 0);
|
|
486
|
+
},
|
|
487
|
+
initSceneCommandService() {
|
|
488
|
+
if (!this.scene || this.sceneCommandService) return;
|
|
489
|
+
this.sceneCommandService = new SceneCommandService({
|
|
490
|
+
THREE: this.THREE,
|
|
491
|
+
getScene: () => this.scene,
|
|
492
|
+
requestRender: () => {
|
|
493
|
+
if (typeof this.notifyCameraChange === 'function') {
|
|
494
|
+
this.notifyCameraChange('customEdit');
|
|
495
|
+
}
|
|
496
|
+
},
|
|
497
|
+
});
|
|
498
|
+
Object.values(EDITOR_EVENT).forEach(eventName => {
|
|
499
|
+
const dispose = this.sceneCommandService.subscribe(eventName, payload => {
|
|
500
|
+
this.handleSceneCommandEvent(eventName, payload);
|
|
501
|
+
this.$emit(eventName, payload);
|
|
502
|
+
});
|
|
503
|
+
this.sceneCommandEventDisposers.push(dispose);
|
|
504
|
+
});
|
|
505
|
+
},
|
|
506
|
+
handleSceneCommandEvent(eventName, payload) {
|
|
507
|
+
switch (eventName) {
|
|
508
|
+
case EDITOR_EVENT.OBJECT_SELECTED:
|
|
509
|
+
this.syncTransformSelection(payload && payload.uuid ? payload.uuid : '');
|
|
510
|
+
break;
|
|
511
|
+
case EDITOR_EVENT.TRANSFORM_MODE_CHANGED:
|
|
512
|
+
this.applyTransformMode(
|
|
513
|
+
payload && payload.mode ? payload.mode : TRANSFORM_MODE.TRANSLATE
|
|
514
|
+
);
|
|
515
|
+
break;
|
|
516
|
+
case EDITOR_EVENT.OBJECT_ADDED:
|
|
517
|
+
case EDITOR_EVENT.OBJECT_REMOVED:
|
|
518
|
+
case EDITOR_EVENT.OBJECT_CHANGED:
|
|
519
|
+
case EDITOR_EVENT.HISTORY_CHANGED:
|
|
520
|
+
case EDITOR_EVENT.SCENE_GRAPH_CHANGED:
|
|
521
|
+
this.ensureTransformSelectionValid();
|
|
522
|
+
break;
|
|
523
|
+
}
|
|
524
|
+
},
|
|
525
|
+
initTransformControls() {
|
|
526
|
+
if (!this.scene || !this.camera || !this.renderer || this.transformEditor.transformControls)
|
|
527
|
+
return;
|
|
528
|
+
const controls = new TransformControls(this.camera, this.renderer.domElement);
|
|
529
|
+
const helper = controls.getHelper();
|
|
530
|
+
controls.setMode(this.getTransformMode());
|
|
531
|
+
helper.visible = false;
|
|
532
|
+
helper.traverse(item => {
|
|
533
|
+
if (!item.userData) {
|
|
534
|
+
item.userData = {};
|
|
535
|
+
}
|
|
536
|
+
item.userData.transformControlHelper = true;
|
|
537
|
+
});
|
|
538
|
+
this.transformEditor.handlers = {
|
|
539
|
+
change: () => {
|
|
540
|
+
if (typeof this.notifyCameraChange === 'function') {
|
|
541
|
+
this.notifyCameraChange('customTransformControl');
|
|
542
|
+
}
|
|
543
|
+
},
|
|
544
|
+
objectChange: () => {
|
|
545
|
+
this.handleTransformObjectChange();
|
|
546
|
+
},
|
|
547
|
+
mouseUp: () => {
|
|
548
|
+
this.scheduleSuppressSelectionOnce();
|
|
549
|
+
this.restoreTransformCameraControls();
|
|
550
|
+
},
|
|
551
|
+
draggingChanged: event => {
|
|
552
|
+
this.handleTransformDraggingChanged(event);
|
|
553
|
+
},
|
|
554
|
+
};
|
|
555
|
+
controls.addEventListener('change', this.transformEditor.handlers.change);
|
|
556
|
+
controls.addEventListener('objectChange', this.transformEditor.handlers.objectChange);
|
|
557
|
+
controls.addEventListener('mouseUp', this.transformEditor.handlers.mouseUp);
|
|
558
|
+
controls.addEventListener('dragging-changed', this.transformEditor.handlers.draggingChanged);
|
|
559
|
+
this.scene.add(helper);
|
|
560
|
+
this.transformEditor.transformControls = controls;
|
|
561
|
+
this.transformEditor.transformHelper = helper;
|
|
562
|
+
this.transformEditor.keydownHandler = event => {
|
|
563
|
+
const isEscape = event && (event.key === 'Escape' || event.keyCode === 27);
|
|
564
|
+
if (!isEscape) return;
|
|
565
|
+
if (this.sceneCommandService && this.sceneCommandService.selectedUuid) {
|
|
566
|
+
this.clearCustomSelection();
|
|
567
|
+
}
|
|
568
|
+
};
|
|
569
|
+
window.addEventListener('keydown', this.transformEditor.keydownHandler, false);
|
|
570
|
+
},
|
|
571
|
+
disposeTransformControls() {
|
|
572
|
+
const editor = this.transformEditor;
|
|
573
|
+
if (!editor) return;
|
|
574
|
+
if (editor.keydownHandler) {
|
|
575
|
+
window.removeEventListener('keydown', editor.keydownHandler, false);
|
|
576
|
+
editor.keydownHandler = null;
|
|
577
|
+
}
|
|
578
|
+
const controls = editor.transformControls;
|
|
579
|
+
const helper = editor.transformHelper;
|
|
580
|
+
if (editor.suppressSelectionTimer) {
|
|
581
|
+
clearTimeout(editor.suppressSelectionTimer);
|
|
582
|
+
editor.suppressSelectionTimer = null;
|
|
583
|
+
}
|
|
584
|
+
if (controls) {
|
|
585
|
+
if (editor.handlers.change) {
|
|
586
|
+
controls.removeEventListener('change', editor.handlers.change);
|
|
587
|
+
}
|
|
588
|
+
if (editor.handlers.objectChange) {
|
|
589
|
+
controls.removeEventListener('objectChange', editor.handlers.objectChange);
|
|
590
|
+
}
|
|
591
|
+
if (editor.handlers.mouseUp) {
|
|
592
|
+
controls.removeEventListener('mouseUp', editor.handlers.mouseUp);
|
|
593
|
+
}
|
|
594
|
+
if (editor.handlers.draggingChanged) {
|
|
595
|
+
controls.removeEventListener('dragging-changed', editor.handlers.draggingChanged);
|
|
596
|
+
}
|
|
597
|
+
controls.detach();
|
|
598
|
+
}
|
|
599
|
+
if (helper && this.scene) {
|
|
600
|
+
this.scene.remove(helper);
|
|
601
|
+
}
|
|
602
|
+
editor.handlers = {};
|
|
603
|
+
editor.transformControls = null;
|
|
604
|
+
editor.transformHelper = null;
|
|
605
|
+
editor.transforming = false;
|
|
606
|
+
editor.transformTargetUuid = '';
|
|
607
|
+
editor.transformStartSnapshot = null;
|
|
608
|
+
editor.suppressSelectionOnce = false;
|
|
609
|
+
},
|
|
610
|
+
isTransformEditBlocked() {
|
|
611
|
+
return !!(this.firstPerSign && this.pointControls && this.pointControls.isLocked);
|
|
612
|
+
},
|
|
613
|
+
isTransformControlDisabled() {
|
|
614
|
+
return !!this.transformEditDisabled || this.isTransformEditBlocked();
|
|
615
|
+
},
|
|
616
|
+
applyTransformMode(mode) {
|
|
617
|
+
const nextMode =
|
|
618
|
+
Object.values(TRANSFORM_MODE).indexOf(mode) !== -1 ? mode : TRANSFORM_MODE.TRANSLATE;
|
|
619
|
+
this.transformEditor.transformMode = nextMode;
|
|
620
|
+
if (this.transformEditor.transformControls) {
|
|
621
|
+
this.transformEditor.transformControls.setMode(nextMode);
|
|
622
|
+
}
|
|
623
|
+
return nextMode;
|
|
624
|
+
},
|
|
625
|
+
getSelectableSceneObject(target) {
|
|
626
|
+
if (!this.sceneCommandService || !target) return null;
|
|
627
|
+
return this.sceneCommandService.findSelectableObject(target);
|
|
628
|
+
},
|
|
629
|
+
getSelectableCustomObject(target) {
|
|
630
|
+
const object = this.getSelectableSceneObject(target);
|
|
631
|
+
if (!object || !this.sceneCommandService) return null;
|
|
632
|
+
const nodeType = this.sceneCommandService.getNodeType(object.uuid);
|
|
633
|
+
return nodeType === 'custom-element' ||
|
|
634
|
+
nodeType === 'custom-group' ||
|
|
635
|
+
nodeType === 'custom-root'
|
|
636
|
+
? object
|
|
637
|
+
: null;
|
|
638
|
+
},
|
|
639
|
+
selectSceneObject(uuid, options = {}) {
|
|
640
|
+
if (!this.sceneCommandService) return null;
|
|
641
|
+
if (this.isTransformEditBlocked()) return null;
|
|
642
|
+
return this.sceneCommandService.selectObject(uuid, options);
|
|
643
|
+
},
|
|
644
|
+
selectElement(uuid, options = {}) {
|
|
645
|
+
if (!this.sceneCommandService) return null;
|
|
646
|
+
if (this.isTransformEditBlocked()) return null;
|
|
647
|
+
return this.sceneCommandService.selectElement(uuid, options);
|
|
648
|
+
},
|
|
649
|
+
clearCustomSelection(options = {}) {
|
|
650
|
+
if (!this.sceneCommandService) {
|
|
651
|
+
this.detachTransformControls();
|
|
652
|
+
return;
|
|
653
|
+
}
|
|
654
|
+
this.sceneCommandService.clearSelection(options);
|
|
655
|
+
},
|
|
656
|
+
getDefaultPrimitivePlacement() {
|
|
657
|
+
const defaultPosition = { x: 0, y: 0, z: 0 };
|
|
658
|
+
const defaultSize = 100;
|
|
659
|
+
if (!this.cameraControls) {
|
|
660
|
+
return {
|
|
661
|
+
position: defaultPosition,
|
|
662
|
+
size: defaultSize,
|
|
663
|
+
};
|
|
664
|
+
}
|
|
665
|
+
const target = new this.THREE.Vector3();
|
|
666
|
+
if (typeof this.cameraControls.getTarget === 'function') {
|
|
667
|
+
this.cameraControls.getTarget(target);
|
|
668
|
+
} else if (this.cameraControls._target) {
|
|
669
|
+
target.copy(this.cameraControls._target);
|
|
670
|
+
}
|
|
671
|
+
const distance =
|
|
672
|
+
this.camera && this.camera.position && typeof this.camera.position.distanceTo === 'function'
|
|
673
|
+
? this.camera.position.distanceTo(target)
|
|
674
|
+
: 0;
|
|
675
|
+
const size = Math.min(Math.max(distance * 0.008, 20), 100) || defaultSize;
|
|
676
|
+
return {
|
|
677
|
+
position: {
|
|
678
|
+
x: target.x,
|
|
679
|
+
y: target.y,
|
|
680
|
+
z: target.z,
|
|
681
|
+
},
|
|
682
|
+
size,
|
|
683
|
+
};
|
|
684
|
+
},
|
|
685
|
+
buildDefaultPrimitiveTransform(transform, position) {
|
|
686
|
+
const nextTransform = transform && typeof transform === 'object' ? { ...transform } : {};
|
|
687
|
+
if (!Array.isArray(nextTransform.position)) {
|
|
688
|
+
nextTransform.position = [position.x, position.y, position.z];
|
|
689
|
+
}
|
|
690
|
+
if (!Array.isArray(nextTransform.rotation)) {
|
|
691
|
+
nextTransform.rotation = [0, 0, 0];
|
|
692
|
+
}
|
|
693
|
+
if (!Array.isArray(nextTransform.scale)) {
|
|
694
|
+
nextTransform.scale = [1, 1, 1];
|
|
695
|
+
}
|
|
696
|
+
return nextTransform;
|
|
697
|
+
},
|
|
698
|
+
buildDefaultPrimitiveGeometryParams(type, size) {
|
|
699
|
+
const primitiveSize = Number.isFinite(size) ? size : 100;
|
|
700
|
+
switch (type) {
|
|
701
|
+
case 'box':
|
|
702
|
+
return {
|
|
703
|
+
width: primitiveSize,
|
|
704
|
+
height: primitiveSize,
|
|
705
|
+
depth: primitiveSize,
|
|
706
|
+
};
|
|
707
|
+
case 'sphere':
|
|
708
|
+
return {
|
|
709
|
+
radius: primitiveSize / 2,
|
|
710
|
+
phiStart: 0,
|
|
711
|
+
phiLength: 360,
|
|
712
|
+
thetaStart: 0,
|
|
713
|
+
thetaLength: 180,
|
|
714
|
+
};
|
|
715
|
+
case 'cylinder':
|
|
716
|
+
return {
|
|
717
|
+
radiusTop: primitiveSize / 2,
|
|
718
|
+
radiusBottom: primitiveSize / 2,
|
|
719
|
+
height: primitiveSize,
|
|
720
|
+
};
|
|
721
|
+
case 'capsule':
|
|
722
|
+
return {
|
|
723
|
+
radius: primitiveSize / 3,
|
|
724
|
+
length: primitiveSize,
|
|
725
|
+
};
|
|
726
|
+
case 'tetrahedron':
|
|
727
|
+
case 'octahedron':
|
|
728
|
+
return {
|
|
729
|
+
radius: primitiveSize / 2,
|
|
730
|
+
};
|
|
731
|
+
case 'ring':
|
|
732
|
+
return {
|
|
733
|
+
radius: primitiveSize / 2,
|
|
734
|
+
tube: primitiveSize / 8,
|
|
735
|
+
arc: 360,
|
|
736
|
+
};
|
|
737
|
+
default:
|
|
738
|
+
return {};
|
|
739
|
+
}
|
|
740
|
+
},
|
|
741
|
+
normalizeAddElementOptions(options = {}) {
|
|
742
|
+
const placement = this.getDefaultPrimitivePlacement();
|
|
743
|
+
const nextOptions = { ...options };
|
|
744
|
+
nextOptions.transform = this.buildDefaultPrimitiveTransform(
|
|
745
|
+
nextOptions.transform,
|
|
746
|
+
placement.position
|
|
747
|
+
);
|
|
748
|
+
if (!nextOptions.geometryParams) {
|
|
749
|
+
nextOptions.geometryParams = this.buildDefaultPrimitiveGeometryParams(
|
|
750
|
+
nextOptions.type,
|
|
751
|
+
placement.size
|
|
752
|
+
);
|
|
753
|
+
}
|
|
754
|
+
return nextOptions;
|
|
755
|
+
},
|
|
756
|
+
normalizeAddGroupOptions(options = {}) {
|
|
757
|
+
const placement = this.getDefaultPrimitivePlacement();
|
|
758
|
+
return {
|
|
759
|
+
...options,
|
|
760
|
+
transform: this.buildDefaultPrimitiveTransform(options.transform, placement.position),
|
|
761
|
+
};
|
|
762
|
+
},
|
|
763
|
+
addElement(options) {
|
|
764
|
+
if (!this.sceneCommandService) return null;
|
|
765
|
+
return this.sceneCommandService.addElement(this.normalizeAddElementOptions(options));
|
|
766
|
+
},
|
|
767
|
+
addGroup(options = {}) {
|
|
768
|
+
if (!this.sceneCommandService) return null;
|
|
769
|
+
return this.sceneCommandService.addGroup(this.normalizeAddGroupOptions(options));
|
|
770
|
+
},
|
|
771
|
+
removeElement(uuid) {
|
|
772
|
+
if (!this.sceneCommandService) return;
|
|
773
|
+
this.sceneCommandService.removeElement(uuid);
|
|
774
|
+
},
|
|
775
|
+
cloneElement(uuid, options = {}) {
|
|
776
|
+
if (!this.sceneCommandService) return null;
|
|
777
|
+
return this.sceneCommandService.cloneElement(uuid, options);
|
|
778
|
+
},
|
|
779
|
+
moveElement(uuid, targetParentUuid, referenceUuid, insertMode = 'append') {
|
|
780
|
+
if (!this.sceneCommandService) return null;
|
|
781
|
+
return this.sceneCommandService.moveElement(
|
|
782
|
+
uuid,
|
|
783
|
+
targetParentUuid,
|
|
784
|
+
referenceUuid,
|
|
785
|
+
insertMode
|
|
786
|
+
);
|
|
787
|
+
},
|
|
788
|
+
updateElement(options) {
|
|
789
|
+
if (!this.sceneCommandService) return null;
|
|
790
|
+
return this.sceneCommandService.updateElement(options);
|
|
791
|
+
},
|
|
792
|
+
updateOriginalModelStyle(options) {
|
|
793
|
+
if (!this.sceneCommandService) return null;
|
|
794
|
+
return this.sceneCommandService.updateOriginalModelStyle(options);
|
|
795
|
+
},
|
|
796
|
+
resetOriginalModelStyle(uuid) {
|
|
797
|
+
if (!this.sceneCommandService) return null;
|
|
798
|
+
return this.sceneCommandService.resetOriginalModelStyle(uuid);
|
|
799
|
+
},
|
|
800
|
+
setElementPosition(uuid, position, oldPosition) {
|
|
801
|
+
if (!this.sceneCommandService) return null;
|
|
802
|
+
return this.sceneCommandService.setElementPosition(uuid, position, oldPosition);
|
|
803
|
+
},
|
|
804
|
+
setElementRotation(uuid, rotation, oldRotation) {
|
|
805
|
+
if (!this.sceneCommandService) return null;
|
|
806
|
+
return this.sceneCommandService.setElementRotation(uuid, rotation, oldRotation);
|
|
807
|
+
},
|
|
808
|
+
setElementScale(uuid, scale, oldScale) {
|
|
809
|
+
if (!this.sceneCommandService) return null;
|
|
810
|
+
return this.sceneCommandService.setElementScale(uuid, scale, oldScale);
|
|
811
|
+
},
|
|
812
|
+
renameElement(uuid, name) {
|
|
813
|
+
if (!this.sceneCommandService) return null;
|
|
814
|
+
return this.sceneCommandService.renameElement(uuid, name);
|
|
815
|
+
},
|
|
816
|
+
setElementVisible(uuid, visible) {
|
|
817
|
+
if (!this.sceneCommandService) return null;
|
|
818
|
+
return this.sceneCommandService.setElementVisible(uuid, visible);
|
|
819
|
+
},
|
|
820
|
+
setTransformMode(mode) {
|
|
821
|
+
if (!this.sceneCommandService) return null;
|
|
822
|
+
return this.sceneCommandService.setTransformMode(mode, {
|
|
823
|
+
forceEmit: true,
|
|
824
|
+
});
|
|
825
|
+
},
|
|
826
|
+
getTransformMode() {
|
|
827
|
+
if (!this.sceneCommandService) {
|
|
828
|
+
return this.transformEditor.transformMode;
|
|
829
|
+
}
|
|
830
|
+
return this.sceneCommandService.getTransformMode();
|
|
831
|
+
},
|
|
832
|
+
getCustomObjectSnapshot(uuid) {
|
|
833
|
+
if (!this.sceneCommandService) return null;
|
|
834
|
+
return this.sceneCommandService.getObjectSnapshot(uuid);
|
|
835
|
+
},
|
|
836
|
+
getModelReviseLocateName(uuid) {
|
|
837
|
+
if (!uuid || !this.sceneCommandService) return '';
|
|
838
|
+
const snapshot = this.sceneCommandService.getObjectSnapshot(uuid);
|
|
839
|
+
if (snapshot && snapshot.name) {
|
|
840
|
+
return snapshot.name;
|
|
841
|
+
}
|
|
842
|
+
const originalRecord = this.sceneCommandService.getOriginalModelStyle(uuid);
|
|
843
|
+
return originalRecord && originalRecord.name ? originalRecord.name : '';
|
|
844
|
+
},
|
|
845
|
+
setOriginalModelNodeName(options = {}) {
|
|
846
|
+
if (!this.sceneCommandService || !this.sceneCommandService.setOriginalModelNodeName) {
|
|
847
|
+
return '';
|
|
848
|
+
}
|
|
849
|
+
return this.sceneCommandService.setOriginalModelNodeName(options);
|
|
850
|
+
},
|
|
851
|
+
getOriginalModelSelectablePriority(object) {
|
|
852
|
+
if (!object) return -1;
|
|
853
|
+
let priority = 0;
|
|
854
|
+
if (object.isInstancedMesh === true) {
|
|
855
|
+
priority += 8;
|
|
856
|
+
}
|
|
857
|
+
if (object.type && object.type !== 'Group') {
|
|
858
|
+
priority += 4;
|
|
859
|
+
}
|
|
860
|
+
if (object.material) {
|
|
861
|
+
priority += 2;
|
|
862
|
+
}
|
|
863
|
+
return priority;
|
|
864
|
+
},
|
|
865
|
+
findOriginalModelSelectableObject(uuid, name) {
|
|
866
|
+
if (
|
|
867
|
+
this.sceneCommandService &&
|
|
868
|
+
typeof this.sceneCommandService.resolveOriginalModelObject === 'function'
|
|
869
|
+
) {
|
|
870
|
+
const originalObject = this.sceneCommandService.resolveOriginalModelObject({
|
|
871
|
+
uuid,
|
|
872
|
+
name,
|
|
873
|
+
});
|
|
874
|
+
if (originalObject && originalObject.uuid) {
|
|
875
|
+
return originalObject;
|
|
876
|
+
}
|
|
877
|
+
}
|
|
878
|
+
const objectByUuid = this.sceneCommandService
|
|
879
|
+
? this.sceneCommandService.getObjectByUuid(uuid)
|
|
880
|
+
: null;
|
|
881
|
+
if (objectByUuid) {
|
|
882
|
+
return objectByUuid;
|
|
883
|
+
}
|
|
884
|
+
if (!name) {
|
|
885
|
+
return null;
|
|
886
|
+
}
|
|
887
|
+
const objectList = this.getObjectByName(name, '');
|
|
888
|
+
if (!Array.isArray(objectList) || objectList.length === 0) {
|
|
889
|
+
return null;
|
|
890
|
+
}
|
|
891
|
+
return (
|
|
892
|
+
objectList
|
|
893
|
+
.filter(item => item && item.uuid)
|
|
894
|
+
.sort(
|
|
895
|
+
(left, right) =>
|
|
896
|
+
this.getOriginalModelSelectablePriority(right) -
|
|
897
|
+
this.getOriginalModelSelectablePriority(left)
|
|
898
|
+
)[0] || null
|
|
899
|
+
);
|
|
900
|
+
},
|
|
901
|
+
async locateModelByUuid(uuid) {
|
|
902
|
+
if (!uuid || !this.sceneCommandService) return false;
|
|
903
|
+
const originalRecord = this.sceneCommandService.getOriginalModelStyle(uuid);
|
|
904
|
+
const nodeType =
|
|
905
|
+
this.sceneCommandService.getNodeType(uuid) ||
|
|
906
|
+
(originalRecord ? SCENE_NODE_TYPE.ORIGINAL_MODEL : '');
|
|
907
|
+
if (uuid === SCENE_NODE_TYPE.ORIGINAL_MODEL || nodeType === SCENE_NODE_TYPE.CUSTOM_ROOT) {
|
|
908
|
+
this.selectElement();
|
|
909
|
+
return false;
|
|
910
|
+
}
|
|
911
|
+
if (
|
|
912
|
+
nodeType === SCENE_NODE_TYPE.CUSTOM_GROUP ||
|
|
913
|
+
nodeType === SCENE_NODE_TYPE.CUSTOM_ELEMENT
|
|
914
|
+
) {
|
|
915
|
+
this.selectElement(uuid);
|
|
916
|
+
return this.locateModel(uuid);
|
|
917
|
+
}
|
|
918
|
+
const name =
|
|
919
|
+
originalRecord && originalRecord.name
|
|
920
|
+
? originalRecord.name
|
|
921
|
+
: this.getModelReviseLocateName(uuid);
|
|
922
|
+
if (nodeType !== SCENE_NODE_TYPE.ORIGINAL_MODEL && !name) {
|
|
923
|
+
return false;
|
|
924
|
+
}
|
|
925
|
+
if (!name) return false;
|
|
926
|
+
try {
|
|
927
|
+
const targetObject = this.findOriginalModelSelectableObject(uuid, name);
|
|
928
|
+
if (targetObject && targetObject.uuid) {
|
|
929
|
+
this.selectSceneObject(targetObject.uuid);
|
|
930
|
+
} else {
|
|
931
|
+
this.selectElement();
|
|
932
|
+
}
|
|
933
|
+
await this.loadModelByIds({
|
|
934
|
+
params: {
|
|
935
|
+
ids: [name],
|
|
936
|
+
},
|
|
937
|
+
onComplete: () => {
|
|
938
|
+
this.locateModel([name]);
|
|
939
|
+
const loadedObject = this.findOriginalModelSelectableObject(uuid, name);
|
|
940
|
+
if (loadedObject && loadedObject.uuid) {
|
|
941
|
+
this.selectSceneObject(loadedObject.uuid);
|
|
942
|
+
}
|
|
943
|
+
},
|
|
944
|
+
});
|
|
945
|
+
return true;
|
|
946
|
+
} catch (error) {
|
|
947
|
+
return false;
|
|
948
|
+
}
|
|
949
|
+
},
|
|
950
|
+
getSelectedSceneObjectSnapshot() {
|
|
951
|
+
if (!this.sceneCommandService) return null;
|
|
952
|
+
return this.sceneCommandService.getSelectedObjectSnapshot();
|
|
953
|
+
},
|
|
954
|
+
getSelectedCustomObjectSnapshot() {
|
|
955
|
+
if (!this.sceneCommandService) return null;
|
|
956
|
+
if (this.sceneCommandService.getSelectedNodeType() === 'original-model') {
|
|
957
|
+
return null;
|
|
958
|
+
}
|
|
959
|
+
return this.sceneCommandService.getSelectedObjectSnapshot();
|
|
960
|
+
},
|
|
961
|
+
getSelectedOriginalModelStyleSnapshot() {
|
|
962
|
+
if (!this.sceneCommandService) return null;
|
|
963
|
+
return this.sceneCommandService.getSelectedOriginalModelStyleSnapshot();
|
|
964
|
+
},
|
|
965
|
+
getOriginalModelStyleChanges() {
|
|
966
|
+
if (!this.sceneCommandService) return [];
|
|
967
|
+
return this.sceneCommandService.getOriginalModelStyleChanges();
|
|
968
|
+
},
|
|
969
|
+
undo() {
|
|
970
|
+
if (!this.sceneCommandService) return null;
|
|
971
|
+
return this.sceneCommandService.undo();
|
|
972
|
+
},
|
|
973
|
+
redo() {
|
|
974
|
+
if (!this.sceneCommandService) return null;
|
|
975
|
+
return this.sceneCommandService.redo();
|
|
976
|
+
},
|
|
977
|
+
subscribe(eventName, handler) {
|
|
978
|
+
if (!this.sceneCommandService) {
|
|
979
|
+
return function () {};
|
|
980
|
+
}
|
|
981
|
+
return this.sceneCommandService.subscribe(eventName, handler);
|
|
982
|
+
},
|
|
983
|
+
getCustomTree() {
|
|
984
|
+
if (!this.sceneCommandService) return null;
|
|
985
|
+
return this.sceneCommandService.getCustomTree();
|
|
986
|
+
},
|
|
987
|
+
getCustomSaveTree() {
|
|
988
|
+
if (!this.sceneCommandService) return null;
|
|
989
|
+
return this.sceneCommandService.getCustomSaveTree();
|
|
990
|
+
},
|
|
991
|
+
getSaveSnapshot() {
|
|
992
|
+
if (!this.sceneCommandService) return null;
|
|
993
|
+
return this.sceneCommandService.getSaveSnapshot();
|
|
994
|
+
},
|
|
995
|
+
applySaveSnapshot(snapshot) {
|
|
996
|
+
if (!this.sceneCommandService) return null;
|
|
997
|
+
return this.sceneCommandService.applySaveSnapshot(snapshot);
|
|
998
|
+
},
|
|
999
|
+
serializeCustomElements() {
|
|
1000
|
+
if (!this.sceneCommandService) return null;
|
|
1001
|
+
return this.sceneCommandService.serializeCustomElements();
|
|
1002
|
+
},
|
|
1003
|
+
deserializeCustomElements(json) {
|
|
1004
|
+
if (!this.sceneCommandService) return null;
|
|
1005
|
+
return this.sceneCommandService.deserializeCustomElements(json);
|
|
1006
|
+
},
|
|
1007
|
+
removeAllCustomElements() {
|
|
1008
|
+
if (!this.sceneCommandService) return;
|
|
1009
|
+
this.sceneCommandService.removeAllCustomElements();
|
|
1010
|
+
},
|
|
1011
|
+
resolveInsertTarget(selectedUuid) {
|
|
1012
|
+
if (!this.sceneCommandService) return null;
|
|
1013
|
+
return this.sceneCommandService.resolveInsertTarget(selectedUuid);
|
|
1014
|
+
},
|
|
1015
|
+
detachTransformControls() {
|
|
1016
|
+
const editor = this.transformEditor;
|
|
1017
|
+
if (!editor) return;
|
|
1018
|
+
const controls = editor.transformControls;
|
|
1019
|
+
const helper = editor.transformHelper;
|
|
1020
|
+
if (controls) {
|
|
1021
|
+
controls.detach();
|
|
1022
|
+
}
|
|
1023
|
+
if (helper) {
|
|
1024
|
+
helper.visible = false;
|
|
1025
|
+
}
|
|
1026
|
+
editor.transforming = false;
|
|
1027
|
+
editor.transformTargetUuid = '';
|
|
1028
|
+
editor.transformStartSnapshot = null;
|
|
1029
|
+
this.restoreTransformCameraControls();
|
|
1030
|
+
if (typeof this.notifyCameraChange === 'function') {
|
|
1031
|
+
this.notifyCameraChange('customTransformDetach');
|
|
1032
|
+
}
|
|
1033
|
+
},
|
|
1034
|
+
attachTransformControls(object) {
|
|
1035
|
+
const editor = this.transformEditor;
|
|
1036
|
+
if (!editor || !editor.transformControls) return null;
|
|
1037
|
+
if (this.isTransformControlDisabled()) {
|
|
1038
|
+
this.detachTransformControls();
|
|
1039
|
+
return null;
|
|
1040
|
+
}
|
|
1041
|
+
if (!object || isCustomRoot(object) || !isTransformAttachableObject(object)) {
|
|
1042
|
+
this.detachTransformControls();
|
|
1043
|
+
return null;
|
|
1044
|
+
}
|
|
1045
|
+
object.updateMatrixWorld(true);
|
|
1046
|
+
editor.transformControls.attach(object);
|
|
1047
|
+
if (editor.transformHelper) {
|
|
1048
|
+
editor.transformHelper.visible = true;
|
|
1049
|
+
}
|
|
1050
|
+
editor.transformTargetUuid = object.uuid;
|
|
1051
|
+
this.applyTransformMode(this.getTransformMode());
|
|
1052
|
+
if (typeof this.notifyCameraChange === 'function') {
|
|
1053
|
+
this.notifyCameraChange('customTransformAttach');
|
|
1054
|
+
}
|
|
1055
|
+
return object;
|
|
1056
|
+
},
|
|
1057
|
+
syncTransformSelection(uuid) {
|
|
1058
|
+
if (!this.sceneCommandService) return null;
|
|
1059
|
+
if (!uuid) {
|
|
1060
|
+
this.detachTransformControls();
|
|
1061
|
+
return null;
|
|
1062
|
+
}
|
|
1063
|
+
const object = this.sceneCommandService.getObjectByUuid(uuid);
|
|
1064
|
+
return this.attachTransformControls(object);
|
|
1065
|
+
},
|
|
1066
|
+
ensureTransformSelectionValid() {
|
|
1067
|
+
if (!this.sceneCommandService) return null;
|
|
1068
|
+
const selectedUuid = this.sceneCommandService.selectedUuid;
|
|
1069
|
+
if (!selectedUuid) {
|
|
1070
|
+
this.detachTransformControls();
|
|
1071
|
+
return null;
|
|
1072
|
+
}
|
|
1073
|
+
const object = this.sceneCommandService.getObjectByUuid(selectedUuid);
|
|
1074
|
+
if (!object || !isTransformAttachableObject(object)) {
|
|
1075
|
+
this.detachTransformControls();
|
|
1076
|
+
return null;
|
|
1077
|
+
}
|
|
1078
|
+
return this.attachTransformControls(object);
|
|
1079
|
+
},
|
|
1080
|
+
buildTransformPayload(objectData, options = {}) {
|
|
1081
|
+
if (!objectData) return null;
|
|
1082
|
+
return {
|
|
1083
|
+
...objectData,
|
|
1084
|
+
isTransforming: !!options.isTransforming,
|
|
1085
|
+
mode: this.getTransformMode(),
|
|
1086
|
+
};
|
|
1087
|
+
},
|
|
1088
|
+
emitTransformEvent(eventName, objectData, options = {}) {
|
|
1089
|
+
const payload = this.buildTransformPayload(objectData, options);
|
|
1090
|
+
if (!payload || !this.sceneCommandService) return;
|
|
1091
|
+
this.sceneCommandService.emitEvent(eventName, payload);
|
|
1092
|
+
},
|
|
1093
|
+
isTransformValueChanged(oldValue = [], newValue = []) {
|
|
1094
|
+
if (
|
|
1095
|
+
!Array.isArray(oldValue) ||
|
|
1096
|
+
!Array.isArray(newValue) ||
|
|
1097
|
+
oldValue.length !== newValue.length
|
|
1098
|
+
) {
|
|
1099
|
+
return true;
|
|
1100
|
+
}
|
|
1101
|
+
for (let index = 0; index < oldValue.length; index += 1) {
|
|
1102
|
+
const currentDiff = Math.abs(
|
|
1103
|
+
(Number(oldValue[index]) || 0) - (Number(newValue[index]) || 0)
|
|
1104
|
+
);
|
|
1105
|
+
if (currentDiff > 0.000001) {
|
|
1106
|
+
return true;
|
|
1107
|
+
}
|
|
1108
|
+
}
|
|
1109
|
+
return false;
|
|
1110
|
+
},
|
|
1111
|
+
commitTransformChanges(object) {
|
|
1112
|
+
if (!object || !this.sceneCommandService) return null;
|
|
1113
|
+
const startSnapshot = this.transformEditor.transformStartSnapshot;
|
|
1114
|
+
const endSnapshot = this.getCustomObjectSnapshot(object.uuid);
|
|
1115
|
+
if (!startSnapshot || !endSnapshot) {
|
|
1116
|
+
return endSnapshot;
|
|
1117
|
+
}
|
|
1118
|
+
const mode = this.getTransformMode();
|
|
1119
|
+
if (mode === TRANSFORM_MODE.TRANSLATE) {
|
|
1120
|
+
if (this.isTransformValueChanged(startSnapshot.position, endSnapshot.position)) {
|
|
1121
|
+
this.setElementPosition(object.uuid, endSnapshot.position, startSnapshot.position);
|
|
1122
|
+
}
|
|
1123
|
+
} else if (mode === TRANSFORM_MODE.ROTATE) {
|
|
1124
|
+
if (this.isTransformValueChanged(startSnapshot.rotation, endSnapshot.rotation)) {
|
|
1125
|
+
this.setElementRotation(object.uuid, endSnapshot.rotation, startSnapshot.rotation);
|
|
1126
|
+
}
|
|
1127
|
+
} else if (mode === TRANSFORM_MODE.SCALE) {
|
|
1128
|
+
if (this.isTransformValueChanged(startSnapshot.scale, endSnapshot.scale)) {
|
|
1129
|
+
this.setElementScale(object.uuid, endSnapshot.scale, startSnapshot.scale);
|
|
1130
|
+
}
|
|
1131
|
+
}
|
|
1132
|
+
return this.getCustomObjectSnapshot(object.uuid);
|
|
1133
|
+
},
|
|
1134
|
+
handleTransformObjectChange() {
|
|
1135
|
+
const editor = this.transformEditor;
|
|
1136
|
+
const controls = editor && editor.transformControls;
|
|
1137
|
+
if (!editor || !controls || !controls.object || !editor.transforming) return;
|
|
1138
|
+
controls.object.updateMatrixWorld(true);
|
|
1139
|
+
this.emitTransformEvent(
|
|
1140
|
+
EDITOR_EVENT.OBJECT_TRANSFORM_CHANGING,
|
|
1141
|
+
this.getCustomObjectSnapshot(controls.object.uuid),
|
|
1142
|
+
{
|
|
1143
|
+
isTransforming: true,
|
|
1144
|
+
}
|
|
1145
|
+
);
|
|
1146
|
+
if (typeof this.notifyCameraChange === 'function') {
|
|
1147
|
+
this.notifyCameraChange('customTransform');
|
|
1148
|
+
}
|
|
1149
|
+
},
|
|
1150
|
+
handleTransformDraggingChanged(event) {
|
|
1151
|
+
const editor = this.transformEditor;
|
|
1152
|
+
if (!editor) return;
|
|
1153
|
+
const isDraggingNow = !!(event && event.value);
|
|
1154
|
+
editor.transforming = isDraggingNow;
|
|
1155
|
+
if (this.cameraControls) {
|
|
1156
|
+
if (isDraggingNow) {
|
|
1157
|
+
editor.cameraControlsEnabled = editor.pointerCameraGuard
|
|
1158
|
+
? editor.pointerCameraEnabled
|
|
1159
|
+
: this.cameraControls.enabled;
|
|
1160
|
+
this.cameraControls.enabled = false;
|
|
1161
|
+
} else {
|
|
1162
|
+
this.restoreTransformCameraControls();
|
|
1163
|
+
}
|
|
1164
|
+
}
|
|
1165
|
+
const controls = editor.transformControls;
|
|
1166
|
+
const object = controls && controls.object ? controls.object : null;
|
|
1167
|
+
if (isDraggingNow) {
|
|
1168
|
+
editor.transformStartSnapshot = object ? this.getCustomObjectSnapshot(object.uuid) : null;
|
|
1169
|
+
this.emitTransformEvent(
|
|
1170
|
+
EDITOR_EVENT.OBJECT_TRANSFORM_CHANGING,
|
|
1171
|
+
editor.transformStartSnapshot,
|
|
1172
|
+
{
|
|
1173
|
+
isTransforming: true,
|
|
1174
|
+
}
|
|
1175
|
+
);
|
|
1176
|
+
return;
|
|
1177
|
+
}
|
|
1178
|
+
const resultSnapshot = this.commitTransformChanges(object);
|
|
1179
|
+
editor.transformStartSnapshot = null;
|
|
1180
|
+
this.emitTransformEvent(EDITOR_EVENT.OBJECT_TRANSFORM_CHANGED, resultSnapshot, {
|
|
1181
|
+
isTransforming: false,
|
|
1182
|
+
});
|
|
1183
|
+
},
|
|
397
1184
|
getOutlineInstanceProxyKey(instancedMesh, instanceIndex) {
|
|
398
1185
|
return `${instancedMesh.uuid}:${instanceIndex}`;
|
|
399
1186
|
},
|
|
@@ -490,20 +1277,6 @@ export default {
|
|
|
490
1277
|
if (proxy.material) proxy.material.dispose && proxy.material.dispose();
|
|
491
1278
|
return proxy;
|
|
492
1279
|
},
|
|
493
|
-
// 判断是设备是手机还是电脑
|
|
494
|
-
isMobileDevice() {
|
|
495
|
-
const userAgent = navigator.userAgent || navigator.vendor || window.opera;
|
|
496
|
-
if (/windows phone/i.test(userAgent)) {
|
|
497
|
-
return true;
|
|
498
|
-
}
|
|
499
|
-
if (/android/i.test(userAgent)) {
|
|
500
|
-
return true;
|
|
501
|
-
}
|
|
502
|
-
if (/iPad|iPhone|iPod/.test(userAgent) && !window.MSStream) {
|
|
503
|
-
return true;
|
|
504
|
-
}
|
|
505
|
-
return false;
|
|
506
|
-
},
|
|
507
1280
|
// 节流工具方法
|
|
508
1281
|
throttle(func, limit) {
|
|
509
1282
|
let lastFunc;
|
|
@@ -2306,6 +3079,7 @@ export default {
|
|
|
2306
3079
|
projectId,
|
|
2307
3080
|
debug: isDebug,
|
|
2308
3081
|
renderModelData: this.renderModelData.bind(this),
|
|
3082
|
+
onRangeStreamComplete: this.handleRangeStreamComplete.bind(this),
|
|
2309
3083
|
ensureNotInteracting: async abortSignal => {
|
|
2310
3084
|
if (
|
|
2311
3085
|
this.userInteracting ||
|
|
@@ -2415,6 +3189,19 @@ export default {
|
|
|
2415
3189
|
this.setSceneBox(null, documentId, false);
|
|
2416
3190
|
this.setBoxIndex(null, documentId, false);
|
|
2417
3191
|
},
|
|
3192
|
+
locateSceneBoxByDocumentId(documentId, options = {}) {
|
|
3193
|
+
if (!documentId || !this.noObserver || !this.noObserver.sceneBoxes) {
|
|
3194
|
+
return false;
|
|
3195
|
+
}
|
|
3196
|
+
const box = this.noObserver.sceneBoxes.get(String(documentId));
|
|
3197
|
+
if (!box || !box.isBox3 || box.isEmpty()) {
|
|
3198
|
+
return false;
|
|
3199
|
+
}
|
|
3200
|
+
const center = box.getCenter(new this.THREE.Vector3());
|
|
3201
|
+
const size = box.getSize(new this.THREE.Vector3());
|
|
3202
|
+
this.locateByCenterBox(center, size, options);
|
|
3203
|
+
return true;
|
|
3204
|
+
},
|
|
2418
3205
|
/**
|
|
2419
3206
|
* 同步获取当前WebGL画面的截图数据,解决preserveDrawingBuffer为false时html2canvas截黑屏的问题
|
|
2420
3207
|
*/
|
|
@@ -2434,7 +3221,15 @@ export default {
|
|
|
2434
3221
|
/**
|
|
2435
3222
|
* 内部渲染流式数据方法
|
|
2436
3223
|
*/
|
|
2437
|
-
renderModelData(
|
|
3224
|
+
renderModelData(
|
|
3225
|
+
meshes,
|
|
3226
|
+
primitives,
|
|
3227
|
+
list,
|
|
3228
|
+
range,
|
|
3229
|
+
onComplete,
|
|
3230
|
+
immediateUpdate,
|
|
3231
|
+
renderOptions = {}
|
|
3232
|
+
) {
|
|
2438
3233
|
// 构造 drawModel 需要的数据格式
|
|
2439
3234
|
const modelRegistry = this.noObserver.streamLoader.modelRegistry;
|
|
2440
3235
|
const modelRecords = Array.from(modelRegistry.values());
|
|
@@ -2481,10 +3276,56 @@ export default {
|
|
|
2481
3276
|
version: list ? list.version : '',
|
|
2482
3277
|
};
|
|
2483
3278
|
|
|
2484
|
-
options.
|
|
3279
|
+
options.suppressLoadComplete = !!renderOptions.suppressLoadComplete;
|
|
2485
3280
|
options.immediateUpdate = immediateUpdate;
|
|
2486
3281
|
|
|
2487
|
-
|
|
3282
|
+
return new Promise(resolve => {
|
|
3283
|
+
let finished = false;
|
|
3284
|
+
const finish = result => {
|
|
3285
|
+
if (finished) return;
|
|
3286
|
+
finished = true;
|
|
3287
|
+
resolve(result || {});
|
|
3288
|
+
};
|
|
3289
|
+
|
|
3290
|
+
options.onComplete = complete => {
|
|
3291
|
+
if (
|
|
3292
|
+
this.sceneCommandService &&
|
|
3293
|
+
typeof this.sceneCommandService.retryPendingOriginalModelSaveChanges === 'function'
|
|
3294
|
+
) {
|
|
3295
|
+
this.sceneCommandService.retryPendingOriginalModelSaveChanges();
|
|
3296
|
+
}
|
|
3297
|
+
onComplete?.(complete);
|
|
3298
|
+
finish(complete);
|
|
3299
|
+
};
|
|
3300
|
+
options.onCancel = cancelInfo => {
|
|
3301
|
+
finish({
|
|
3302
|
+
canceled: true,
|
|
3303
|
+
...(cancelInfo || {}),
|
|
3304
|
+
});
|
|
3305
|
+
};
|
|
3306
|
+
|
|
3307
|
+
this.drawModel(regionModelData, '', meshNameConfig, options);
|
|
3308
|
+
});
|
|
3309
|
+
},
|
|
3310
|
+
|
|
3311
|
+
waitNextRenderFrame() {
|
|
3312
|
+
return new Promise(resolve => {
|
|
3313
|
+
if (typeof requestAnimationFrame === 'function') {
|
|
3314
|
+
requestAnimationFrame(() => {
|
|
3315
|
+
resolve();
|
|
3316
|
+
});
|
|
3317
|
+
return;
|
|
3318
|
+
}
|
|
3319
|
+
setTimeout(resolve, 0);
|
|
3320
|
+
});
|
|
3321
|
+
},
|
|
3322
|
+
|
|
3323
|
+
async handleRangeStreamComplete(payload = {}) {
|
|
3324
|
+
await this.waitNextRenderFrame();
|
|
3325
|
+
this.$emit('loadComplete', {
|
|
3326
|
+
source: 'inRangeDis2',
|
|
3327
|
+
...payload,
|
|
3328
|
+
});
|
|
2488
3329
|
},
|
|
2489
3330
|
|
|
2490
3331
|
getRangeStream(options) {
|
|
@@ -2570,6 +3411,9 @@ export default {
|
|
|
2570
3411
|
this.renderer.debug.checkShaderErrors = false;
|
|
2571
3412
|
this.renderer.info.autoReset = false;
|
|
2572
3413
|
this.renderer.setPixelRatio(window.devicePixelRatio);
|
|
3414
|
+
if (this.instructions && window.getComputedStyle(this.instructions).position === 'static') {
|
|
3415
|
+
this.instructions.style.position = 'relative';
|
|
3416
|
+
}
|
|
2573
3417
|
const rect = this.instructions.getBoundingClientRect();
|
|
2574
3418
|
this.renderer.setSize(rect.width, rect.height);
|
|
2575
3419
|
this.renderer.domElement.id = 'three-model-' + this.containId;
|
|
@@ -2825,7 +3669,7 @@ export default {
|
|
|
2825
3669
|
const rect = this.instructions.getBoundingClientRect();
|
|
2826
3670
|
this.labelRenderer.setSize(rect.width, rect.height);
|
|
2827
3671
|
this.labelRenderer.domElement.style.position = 'absolute';
|
|
2828
|
-
|
|
3672
|
+
this.labelRenderer.domElement.style.left = '0';
|
|
2829
3673
|
this.labelRenderer.domElement.style.top = '0';
|
|
2830
3674
|
this.labelRenderer.domElement.style.pointerEvents = 'none';
|
|
2831
3675
|
this.instructions.appendChild(this.labelRenderer.domElement);
|
|
@@ -2853,7 +3697,9 @@ export default {
|
|
|
2853
3697
|
options?.onComplete?.(complete);
|
|
2854
3698
|
console.log('加载完成');
|
|
2855
3699
|
// 触发原有的完成事件
|
|
2856
|
-
|
|
3700
|
+
if (!options?.suppressLoadComplete) {
|
|
3701
|
+
this.$emit('loadComplete');
|
|
3702
|
+
}
|
|
2857
3703
|
}
|
|
2858
3704
|
);
|
|
2859
3705
|
},
|
|
@@ -2885,6 +3731,14 @@ export default {
|
|
|
2885
3731
|
this.skipNextRenderFrame = true;
|
|
2886
3732
|
|
|
2887
3733
|
const intersects = this.getRaycasterObjects(event);
|
|
3734
|
+
const shouldBlockCamera = intersects.some(item =>
|
|
3735
|
+
this.isActiveTransformControlIntersection(item)
|
|
3736
|
+
);
|
|
3737
|
+
if (shouldBlockCamera) {
|
|
3738
|
+
this.setPointerCameraGuard(true);
|
|
3739
|
+
} else {
|
|
3740
|
+
this.setPointerCameraGuard(false);
|
|
3741
|
+
}
|
|
2888
3742
|
this.firstTime = new Date().getTime();
|
|
2889
3743
|
let params = {
|
|
2890
3744
|
event,
|
|
@@ -2915,6 +3769,87 @@ export default {
|
|
|
2915
3769
|
? this.raycaster.intersectObjects(this.scene.children, true)
|
|
2916
3770
|
: [];
|
|
2917
3771
|
},
|
|
3772
|
+
isTransformControlIntersection(intersection) {
|
|
3773
|
+
let current = intersection && intersection.object ? intersection.object : null;
|
|
3774
|
+
while (current) {
|
|
3775
|
+
if (current.userData && current.userData.transformControlHelper === true) {
|
|
3776
|
+
return true;
|
|
3777
|
+
}
|
|
3778
|
+
current = current.parent;
|
|
3779
|
+
}
|
|
3780
|
+
return false;
|
|
3781
|
+
},
|
|
3782
|
+
isActiveTransformControlIntersection(intersection) {
|
|
3783
|
+
const editor = this.transformEditor;
|
|
3784
|
+
const controls = editor && editor.transformControls;
|
|
3785
|
+
const helper = editor && editor.transformHelper;
|
|
3786
|
+
if (!controls || !controls.object || !helper || !helper.visible) {
|
|
3787
|
+
return false;
|
|
3788
|
+
}
|
|
3789
|
+
return this.isTransformControlIntersection(intersection);
|
|
3790
|
+
},
|
|
3791
|
+
getPrimaryIntersection(intersects = []) {
|
|
3792
|
+
if (!Array.isArray(intersects) || intersects.length === 0) {
|
|
3793
|
+
return null;
|
|
3794
|
+
}
|
|
3795
|
+
const validIntersects = intersects.filter(
|
|
3796
|
+
item => item && item.object && !this.isTransformControlIntersection(item)
|
|
3797
|
+
);
|
|
3798
|
+
if (validIntersects.length === 0) {
|
|
3799
|
+
return null;
|
|
3800
|
+
}
|
|
3801
|
+
const selectableIntersect = validIntersects.find(item =>
|
|
3802
|
+
this.getSelectableSceneObject(item.object)
|
|
3803
|
+
);
|
|
3804
|
+
return selectableIntersect || validIntersects[0] || null;
|
|
3805
|
+
},
|
|
3806
|
+
buildIntersectionParams(intersection, event, cameraData) {
|
|
3807
|
+
if (!intersection) {
|
|
3808
|
+
return {
|
|
3809
|
+
objects: [],
|
|
3810
|
+
mousePosition: { x: event.clientX, y: event.clientY },
|
|
3811
|
+
camera: cameraData,
|
|
3812
|
+
v3Position: {
|
|
3813
|
+
x: -1,
|
|
3814
|
+
y: -1,
|
|
3815
|
+
z: -1,
|
|
3816
|
+
},
|
|
3817
|
+
};
|
|
3818
|
+
}
|
|
3819
|
+
const selectableObject = this.getSelectableSceneObject(intersection.object);
|
|
3820
|
+
const params = {
|
|
3821
|
+
objects: [intersection.object],
|
|
3822
|
+
mousePosition: { x: event.clientX, y: event.clientY },
|
|
3823
|
+
camera: cameraData,
|
|
3824
|
+
v3Position: {
|
|
3825
|
+
x: intersection.point.x,
|
|
3826
|
+
y: intersection.point.y,
|
|
3827
|
+
z: intersection.point.z,
|
|
3828
|
+
},
|
|
3829
|
+
instanceId: this.getInstanceId(intersection.object, intersection.instanceId),
|
|
3830
|
+
};
|
|
3831
|
+
if (selectableObject) {
|
|
3832
|
+
const nodeType = this.sceneCommandService
|
|
3833
|
+
? this.sceneCommandService.getNodeType(selectableObject.uuid)
|
|
3834
|
+
: '';
|
|
3835
|
+
params.selectedObject = selectableObject;
|
|
3836
|
+
params.selectedObjectUuid = selectableObject.uuid;
|
|
3837
|
+
params.selectedNodeType = nodeType;
|
|
3838
|
+
if (
|
|
3839
|
+
nodeType === 'custom-element' ||
|
|
3840
|
+
nodeType === 'custom-group' ||
|
|
3841
|
+
nodeType === 'custom-root'
|
|
3842
|
+
) {
|
|
3843
|
+
params.customObject = selectableObject;
|
|
3844
|
+
params.customObjectUuid = selectableObject.uuid;
|
|
3845
|
+
}
|
|
3846
|
+
if (nodeType === 'original-model') {
|
|
3847
|
+
params.originalModel = selectableObject;
|
|
3848
|
+
params.originalModelUuid = selectableObject.uuid;
|
|
3849
|
+
}
|
|
3850
|
+
}
|
|
3851
|
+
return params;
|
|
3852
|
+
},
|
|
2918
3853
|
getInstanceId(instancedMesh, instanceIndex, options) {
|
|
2919
3854
|
if (!instancedMesh || instanceIndex === undefined || instanceIndex === null) {
|
|
2920
3855
|
return null;
|
|
@@ -2936,10 +3871,14 @@ export default {
|
|
|
2936
3871
|
}, 50); // 短暂延迟确保交互完成
|
|
2937
3872
|
|
|
2938
3873
|
// 在测量模式下,不进行事件暴露
|
|
3874
|
+
if (!this.transformEditor.transforming) {
|
|
3875
|
+
this.setPointerCameraGuard(false);
|
|
3876
|
+
}
|
|
2939
3877
|
if (!this.measureFlag) {
|
|
2940
3878
|
this.lastTime = new Date().getTime();
|
|
2941
3879
|
if (this.lastTime - this.firstTime < 300) {
|
|
2942
3880
|
const intersects = this.getRaycasterObjects(event);
|
|
3881
|
+
const primaryIntersection = this.getPrimaryIntersection(intersects);
|
|
2943
3882
|
let params = {};
|
|
2944
3883
|
let cameraData = {
|
|
2945
3884
|
position: {
|
|
@@ -2953,43 +3892,101 @@ export default {
|
|
|
2953
3892
|
roll: this.cameraControls._target.z,
|
|
2954
3893
|
},
|
|
2955
3894
|
};
|
|
2956
|
-
if (
|
|
3895
|
+
if (primaryIntersection) {
|
|
2957
3896
|
this.clearBypassCullingModelIds();
|
|
2958
|
-
|
|
2959
|
-
params = {
|
|
2960
|
-
objects: [intersects[0].object],
|
|
2961
|
-
mousePosition: { x: event.clientX, y: event.clientY },
|
|
2962
|
-
camera: cameraData,
|
|
2963
|
-
v3Position: {
|
|
2964
|
-
x: intersects[0].point.x,
|
|
2965
|
-
y: intersects[0].point.y,
|
|
2966
|
-
z: intersects[0].point.z,
|
|
2967
|
-
},
|
|
2968
|
-
// inHighPriorityRegion: inHighPriority,
|
|
2969
|
-
instanceId,
|
|
2970
|
-
};
|
|
3897
|
+
params = this.buildIntersectionParams(primaryIntersection, event, cameraData);
|
|
2971
3898
|
} else {
|
|
2972
|
-
params =
|
|
2973
|
-
objects: [],
|
|
2974
|
-
mousePosition: { x: event.clientX, y: event.clientY },
|
|
2975
|
-
camera: cameraData,
|
|
2976
|
-
v3Position: {
|
|
2977
|
-
x: -1,
|
|
2978
|
-
y: -1,
|
|
2979
|
-
z: -1,
|
|
2980
|
-
},
|
|
2981
|
-
// inHighPriorityRegion: false,
|
|
2982
|
-
};
|
|
3899
|
+
params = this.buildIntersectionParams(null, event, cameraData);
|
|
2983
3900
|
}
|
|
2984
3901
|
if (event.button === 0) {
|
|
3902
|
+
if (this.transformEditor && this.transformEditor.suppressSelectionOnce) {
|
|
3903
|
+
this.transformEditor.suppressSelectionOnce = false;
|
|
3904
|
+
this.setPointerCameraGuard(false);
|
|
3905
|
+
return;
|
|
3906
|
+
}
|
|
3907
|
+
if (params.selectedObjectUuid) {
|
|
3908
|
+
this.selectSceneObject(params.selectedObjectUuid);
|
|
3909
|
+
} else if (this.sceneCommandService) {
|
|
3910
|
+
this.clearCustomSelection();
|
|
3911
|
+
}
|
|
3912
|
+
if (!this.transformEditor.transforming) {
|
|
3913
|
+
this.setPointerCameraGuard(false);
|
|
3914
|
+
}
|
|
2985
3915
|
this.$emit('leftClick', params);
|
|
2986
3916
|
} else if (event.button === 1) {
|
|
3917
|
+
this.setPointerCameraGuard(false);
|
|
2987
3918
|
if (this.lastTime - this.lastMiddleClickTime < 2000) {
|
|
2988
3919
|
this.$emit('middleDblClick', params);
|
|
2989
3920
|
this.lastMiddleClickTime = 0;
|
|
2990
3921
|
} else {
|
|
2991
3922
|
this.lastMiddleClickTime = this.lastTime;
|
|
2992
3923
|
}
|
|
3924
|
+
} else if (event.button === 2) {
|
|
3925
|
+
if ((params.objects && params.objects.length > 0) || this.isolateMode) {
|
|
3926
|
+
this.setPointerCameraGuard(false);
|
|
3927
|
+
this.$emit('rightClick', params);
|
|
3928
|
+
onContextHandle(
|
|
3929
|
+
event,
|
|
3930
|
+
'fl-model',
|
|
3931
|
+
'隐藏',
|
|
3932
|
+
this.isolateMode ? '取消隔离' : '隔离',
|
|
3933
|
+
() => {
|
|
3934
|
+
this.updateProperty([
|
|
3935
|
+
{
|
|
3936
|
+
name: params.instanceId,
|
|
3937
|
+
attr: {
|
|
3938
|
+
visible: false,
|
|
3939
|
+
},
|
|
3940
|
+
},
|
|
3941
|
+
]);
|
|
3942
|
+
},
|
|
3943
|
+
() => {
|
|
3944
|
+
this.setAllModelVisible(this.isolateMode);
|
|
3945
|
+
this.updateProperty([
|
|
3946
|
+
{
|
|
3947
|
+
name: params.instanceId,
|
|
3948
|
+
attr: {
|
|
3949
|
+
visible: true,
|
|
3950
|
+
},
|
|
3951
|
+
},
|
|
3952
|
+
]);
|
|
3953
|
+
this.isolateMode = !this.isolateMode;
|
|
3954
|
+
}
|
|
3955
|
+
);
|
|
3956
|
+
}
|
|
3957
|
+
} else if (event.button === 2) {
|
|
3958
|
+
if ((params.objects && params.objects.length > 0) || this.isolateMode) {
|
|
3959
|
+
this.setPointerCameraGuard(false);
|
|
3960
|
+
this.$emit('rightClick', params);
|
|
3961
|
+
onContextHandle(
|
|
3962
|
+
event,
|
|
3963
|
+
'fl-model',
|
|
3964
|
+
'隐藏',
|
|
3965
|
+
this.isolateMode ? '取消隔离' : '隔离',
|
|
3966
|
+
() => {
|
|
3967
|
+
this.updateProperty([
|
|
3968
|
+
{
|
|
3969
|
+
name: params.instanceId,
|
|
3970
|
+
attr: {
|
|
3971
|
+
visible: false,
|
|
3972
|
+
},
|
|
3973
|
+
},
|
|
3974
|
+
]);
|
|
3975
|
+
},
|
|
3976
|
+
() => {
|
|
3977
|
+
this.setAllModelVisible(this.isolateMode);
|
|
3978
|
+
this.updateProperty([
|
|
3979
|
+
{
|
|
3980
|
+
name: params.instanceId,
|
|
3981
|
+
attr: {
|
|
3982
|
+
visible: true,
|
|
3983
|
+
},
|
|
3984
|
+
},
|
|
3985
|
+
]);
|
|
3986
|
+
this.isolateMode = !this.isolateMode;
|
|
3987
|
+
}
|
|
3988
|
+
);
|
|
3989
|
+
}
|
|
2993
3990
|
}
|
|
2994
3991
|
}
|
|
2995
3992
|
}
|
|
@@ -3411,24 +4408,56 @@ export default {
|
|
|
3411
4408
|
}
|
|
3412
4409
|
}
|
|
3413
4410
|
},
|
|
4411
|
+
expandLocateBoxByObject(box3, object) {
|
|
4412
|
+
if (!box3 || !object) return;
|
|
4413
|
+
if (object.isGroup) {
|
|
4414
|
+
object.traverseVisible(child => {
|
|
4415
|
+
if (child.isMesh || child.isLine || child.isPoints) {
|
|
4416
|
+
box3.expandByObject(child);
|
|
4417
|
+
}
|
|
4418
|
+
});
|
|
4419
|
+
return;
|
|
4420
|
+
}
|
|
4421
|
+
box3.expandByObject(object);
|
|
4422
|
+
},
|
|
4423
|
+
locateObjectByBox(object, options = {}) {
|
|
4424
|
+
if (!object) return false;
|
|
4425
|
+
const box3 = new this.THREE.Box3();
|
|
4426
|
+
this.expandLocateBoxByObject(box3, object);
|
|
4427
|
+
if (box3.isEmpty()) return false;
|
|
4428
|
+
const center = box3.getCenter(new this.THREE.Vector3());
|
|
4429
|
+
const size = box3.getSize(new this.THREE.Vector3());
|
|
4430
|
+
this.locateByCenterBox(center, size, options);
|
|
4431
|
+
return true;
|
|
4432
|
+
},
|
|
3414
4433
|
// 定位到模型
|
|
3415
|
-
// name
|
|
4434
|
+
// name 模型名称或运行态 uuid,可以是数组
|
|
3416
4435
|
locateModel(name) {
|
|
3417
|
-
if (!this.scene) return;
|
|
4436
|
+
if (!this.scene) return false;
|
|
3418
4437
|
if (Array.isArray(name)) {
|
|
3419
4438
|
const box3 = new this.THREE.Box3();
|
|
3420
4439
|
name.forEach(n => {
|
|
4440
|
+
const objectByUuid = this.getObjectByUuid(n);
|
|
4441
|
+
if (objectByUuid) {
|
|
4442
|
+
this.expandLocateBoxByObject(box3, objectByUuid);
|
|
4443
|
+
return;
|
|
4444
|
+
}
|
|
3421
4445
|
const arr = this.getObjectByName(n);
|
|
3422
4446
|
arr.forEach(o => {
|
|
3423
|
-
|
|
4447
|
+
this.expandLocateBoxByObject(box3, o);
|
|
3424
4448
|
});
|
|
3425
4449
|
});
|
|
3426
4450
|
if (!box3.isEmpty()) {
|
|
3427
4451
|
const center = box3.getCenter(new this.THREE.Vector3());
|
|
3428
4452
|
const size = box3.getSize(new this.THREE.Vector3());
|
|
3429
4453
|
this.locateByCenterBox(center, size, { viewAll: true });
|
|
4454
|
+
return true;
|
|
3430
4455
|
}
|
|
3431
|
-
return;
|
|
4456
|
+
return false;
|
|
4457
|
+
}
|
|
4458
|
+
const objectByUuid = this.getObjectByUuid(name);
|
|
4459
|
+
if (objectByUuid && this.locateObjectByBox(objectByUuid)) {
|
|
4460
|
+
return true;
|
|
3432
4461
|
}
|
|
3433
4462
|
let obj = this.getObjectByName(name)[0];
|
|
3434
4463
|
if (obj) {
|
|
@@ -3440,7 +4469,9 @@ export default {
|
|
|
3440
4469
|
let size = this.getSize(obj);
|
|
3441
4470
|
this.locateByCenterBox(center, size);
|
|
3442
4471
|
}
|
|
4472
|
+
return true;
|
|
3443
4473
|
}
|
|
4474
|
+
return false;
|
|
3444
4475
|
},
|
|
3445
4476
|
// 根据自定义参数修改模型
|
|
3446
4477
|
/*
|
|
@@ -3569,6 +4600,11 @@ export default {
|
|
|
3569
4600
|
});
|
|
3570
4601
|
return object;
|
|
3571
4602
|
},
|
|
4603
|
+
// 通过 uuid 获取实体对象
|
|
4604
|
+
getObjectByUuid(uuid) {
|
|
4605
|
+
if (!this.scene || !uuid) return null;
|
|
4606
|
+
return this.scene.getObjectByProperty('uuid', uuid) || null;
|
|
4607
|
+
},
|
|
3572
4608
|
// 通过id获取实体对象, 返回查找到的对象
|
|
3573
4609
|
getObjectById(id) {
|
|
3574
4610
|
if (!this.scene) return null;
|
|
@@ -3654,6 +4690,7 @@ export default {
|
|
|
3654
4690
|
removeAll() {
|
|
3655
4691
|
return new Promise(resolve => {
|
|
3656
4692
|
if (this.scene) {
|
|
4693
|
+
this.removeAllCustomElements();
|
|
3657
4694
|
this.removeTraverse();
|
|
3658
4695
|
this.removeModelByDocumentId();
|
|
3659
4696
|
resolve();
|
|
@@ -3693,6 +4730,16 @@ export default {
|
|
|
3693
4730
|
// 销毁场景 释放内存
|
|
3694
4731
|
destroyScene() {
|
|
3695
4732
|
cancelAnimationFrame(this.animateId);
|
|
4733
|
+
this.disposeTransformControls();
|
|
4734
|
+
|
|
4735
|
+
if (this.sceneCommandEventDisposers.length > 0) {
|
|
4736
|
+
this.sceneCommandEventDisposers.forEach(dispose => dispose && dispose());
|
|
4737
|
+
this.sceneCommandEventDisposers = [];
|
|
4738
|
+
}
|
|
4739
|
+
if (this.sceneCommandService) {
|
|
4740
|
+
this.sceneCommandService.destroy();
|
|
4741
|
+
this.sceneCommandService = null;
|
|
4742
|
+
}
|
|
3696
4743
|
|
|
3697
4744
|
if (this.noObserver && this.noObserver.outlineInstanceProxyMap) {
|
|
3698
4745
|
this.noObserver.outlineInstanceProxyMap.forEach(proxy => {
|
|
@@ -3755,12 +4802,7 @@ export default {
|
|
|
3755
4802
|
}
|
|
3756
4803
|
|
|
3757
4804
|
// 移除鼠标点击/按下事件监听器
|
|
3758
|
-
|
|
3759
|
-
this.renderer.domElement.removeEventListener('mouseup', this.mouseClick, false);
|
|
3760
|
-
this.renderer.domElement.removeEventListener('mousedown', this.mouseDown, false);
|
|
3761
|
-
this.renderer.domElement.removeEventListener('pointerup', this.mouseClick, false);
|
|
3762
|
-
this.renderer.domElement.removeEventListener('pointerdown', this.mouseDown, false);
|
|
3763
|
-
}
|
|
4805
|
+
this.unbindScenePointerEvents();
|
|
3764
4806
|
|
|
3765
4807
|
// 取消 pointer lock 并移除相关键盘事件
|
|
3766
4808
|
if (this.pointControls) {
|
|
@@ -4002,13 +5044,46 @@ export default {
|
|
|
4002
5044
|
});
|
|
4003
5045
|
return clippingPlanesConstant;
|
|
4004
5046
|
},
|
|
5047
|
+
isGlobalClippingExcludedNode(object) {
|
|
5048
|
+
if (!object) return true;
|
|
5049
|
+
const userData = object.userData || {};
|
|
5050
|
+
const nodeType = userData.nodeType || userData.rootType || '';
|
|
5051
|
+
if (nodeType === 'custom-root') return true;
|
|
5052
|
+
if (userData.transformControlHelper === true) return true;
|
|
5053
|
+
if (object.isCamera || object.isLight) return true;
|
|
5054
|
+
if (typeof object.type === 'string' && /Helper$/i.test(object.type)) return true;
|
|
5055
|
+
return object.type === 'CSS2DObject' || object.type === 'TransformControlsRoot';
|
|
5056
|
+
},
|
|
5057
|
+
getGlobalClippingRoots() {
|
|
5058
|
+
if (this.modelGroup && this.modelGroup.children && this.modelGroup.children.length) {
|
|
5059
|
+
return [this.modelGroup];
|
|
5060
|
+
}
|
|
5061
|
+
if (!this.scene || !this.scene.children || this.scene.children.length === 0) return [];
|
|
5062
|
+
return this.scene.children.filter(child => !this.isGlobalClippingExcludedNode(child));
|
|
5063
|
+
},
|
|
5064
|
+
getGlobalClippingBox() {
|
|
5065
|
+
if (!this.scene) return null;
|
|
5066
|
+
const roots = this.getGlobalClippingRoots();
|
|
5067
|
+
if (roots.length === 0) return null;
|
|
5068
|
+
const box3 = new this.THREE.Box3();
|
|
5069
|
+
roots.forEach(root => {
|
|
5070
|
+
box3.expandByObject(root);
|
|
5071
|
+
});
|
|
5072
|
+
return box3.isEmpty() ? null : box3;
|
|
5073
|
+
},
|
|
4005
5074
|
// 设置全局整体剖切
|
|
4006
5075
|
/*
|
|
4007
5076
|
先开启模型全局剖切模式, 会返回剖切值的最大最小值
|
|
4008
5077
|
剖切值变换时, 使用
|
|
4009
5078
|
*/
|
|
4010
5079
|
setGlobalClipping(flag = true) {
|
|
4011
|
-
const box3 =
|
|
5080
|
+
const box3 = this.getGlobalClippingBox();
|
|
5081
|
+
if (!box3) {
|
|
5082
|
+
return {
|
|
5083
|
+
min: null,
|
|
5084
|
+
max: null,
|
|
5085
|
+
};
|
|
5086
|
+
}
|
|
4012
5087
|
let max = box3.max;
|
|
4013
5088
|
let min = box3.min;
|
|
4014
5089
|
const clippingPlanes = [
|
|
@@ -4280,11 +5355,11 @@ export default {
|
|
|
4280
5355
|
} catch (e) {}
|
|
4281
5356
|
// 锁定
|
|
4282
5357
|
this.pointControls.addEventListener('lock', () => {
|
|
5358
|
+
this.detachTransformControls();
|
|
4283
5359
|
this.cameraControls.enabled = false;
|
|
4284
5360
|
window.addEventListener('keydown', this.onKeyDown, false);
|
|
4285
5361
|
window.addEventListener('keyup', this.onKeyUp, false);
|
|
4286
|
-
this.
|
|
4287
|
-
this.renderer.domElement.removeEventListener('mousedown', this.mouseDown, false);
|
|
5362
|
+
this.unbindScenePointerEvents();
|
|
4288
5363
|
if (typeof this._cameraChangeObserver === 'function') {
|
|
4289
5364
|
this._cameraChangeObserver('firstPersonLock');
|
|
4290
5365
|
}
|
|
@@ -4306,8 +5381,8 @@ export default {
|
|
|
4306
5381
|
setTimeout(() => {
|
|
4307
5382
|
window.removeEventListener('keydown', this.onKeyDown);
|
|
4308
5383
|
window.removeEventListener('keyup', this.onKeyUp);
|
|
4309
|
-
this.
|
|
4310
|
-
this.
|
|
5384
|
+
this.bindScenePointerEvents();
|
|
5385
|
+
this.ensureTransformSelectionValid();
|
|
4311
5386
|
// this.timeRender()
|
|
4312
5387
|
}, 0);
|
|
4313
5388
|
if (typeof this._cameraChangeObserver === 'function') {
|
|
@@ -5002,7 +6077,7 @@ export default {
|
|
|
5002
6077
|
: this.batchLoadingState;
|
|
5003
6078
|
// 如果已经在加载中,先停止之前的加载
|
|
5004
6079
|
if (loadingState.isLoading) {
|
|
5005
|
-
this.stopBatchLoading();
|
|
6080
|
+
this.stopBatchLoading('restart');
|
|
5006
6081
|
}
|
|
5007
6082
|
|
|
5008
6083
|
// 重置instance-parser的处理状态
|
|
@@ -5337,7 +6412,7 @@ export default {
|
|
|
5337
6412
|
/**
|
|
5338
6413
|
* 停止批量加载
|
|
5339
6414
|
*/
|
|
5340
|
-
stopBatchLoading() {
|
|
6415
|
+
stopBatchLoading(reason = 'stop') {
|
|
5341
6416
|
const loadingState = this.noObserver
|
|
5342
6417
|
? this.noObserver.batchLoadingState
|
|
5343
6418
|
: this.batchLoadingState;
|
|
@@ -5345,6 +6420,9 @@ export default {
|
|
|
5345
6420
|
cancelAnimationFrame(loadingState.animationFrameId);
|
|
5346
6421
|
loadingState.animationFrameId = null;
|
|
5347
6422
|
}
|
|
6423
|
+
if (loadingState.isLoading && typeof loadingState.options?.onCancel === 'function') {
|
|
6424
|
+
loadingState.options.onCancel({ reason });
|
|
6425
|
+
}
|
|
5348
6426
|
loadingState.isLoading = false;
|
|
5349
6427
|
this.batchLoadingState.isLoading = false;
|
|
5350
6428
|
},
|
|
@@ -5592,6 +6670,7 @@ export default {
|
|
|
5592
6670
|
.fl-model-containor {
|
|
5593
6671
|
width: 100%;
|
|
5594
6672
|
height: 100%;
|
|
6673
|
+
position: relative;
|
|
5595
6674
|
cursor: pointer;
|
|
5596
6675
|
}
|
|
5597
6676
|
::v-deep .tips-label {
|