brep-io-kernel 1.0.17 → 1.0.19
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/dist-kernel/brep-kernel.js +13547 -12034
- package/package.json +1 -1
- package/src/FeatureRegistry.js +3 -0
- package/src/PartHistory.js +141 -0
- package/src/UI/CADmaterials.js +2 -2
- package/src/UI/MainToolbar.js +39 -2
- package/src/UI/SelectionFilter.js +438 -0
- package/src/UI/featureDialogWidgets/booleanOperationField.js +33 -52
- package/src/UI/featureDialogWidgets/referenceSelectionField.js +10 -0
- package/src/UI/featureDialogs.js +841 -8
- package/src/UI/history/HistoryCollectionWidget.js +20 -1
- package/src/UI/pmi/AnnotationRegistry.js +3 -0
- package/src/UI/toolbarButtons/orientToFaceButton.js +3 -0
- package/src/UI/toolbarButtons/registerDefaultButtons.js +0 -6
- package/src/UI/toolbarButtons/registerSelectionButtons.js +68 -0
- package/src/UI/viewer.js +22 -4
- package/src/assemblyConstraints/AssemblyConstraintRegistry.js +3 -0
- package/src/features/boolean/BooleanFeature.js +15 -0
- package/src/features/chamfer/ChamferFeature.js +12 -0
- package/src/features/extrude/ExtrudeFeature.js +11 -0
- package/src/features/fillet/FilletFeature.js +12 -0
- package/src/features/hole/HoleFeature.js +15 -0
- package/src/features/loft/LoftFeature.js +17 -0
- package/src/features/mirror/MirrorFeature.js +14 -0
- package/src/features/patternLinear/PatternLinearFeature.js +9 -0
- package/src/features/patternRadial/PatternRadialFeature.js +13 -0
- package/src/features/plane/PlaneFeature.js +10 -0
- package/src/features/revolve/RevolveFeature.js +15 -0
- package/src/features/sketch/SketchFeature.js +11 -0
- package/src/features/sweep/SweepFeature.js +17 -0
- package/src/features/transform/TransformFeature.js +12 -0
- package/src/features/tube/TubeFeature.js +12 -0
package/src/UI/featureDialogs.js
CHANGED
|
@@ -2,11 +2,17 @@
|
|
|
2
2
|
|
|
3
3
|
import { SelectionFilter } from './SelectionFilter.js';
|
|
4
4
|
import * as THREE from 'three';
|
|
5
|
+
import { Line2, LineGeometry, LineMaterial } from 'three/examples/jsm/Addons.js';
|
|
5
6
|
// Use hybrid translate+rotate gizmo used by the Viewer
|
|
6
7
|
import { CombinedTransformControls } from './controls/CombinedTransformControls.js';
|
|
7
8
|
import { getWidgetRenderer } from './featureDialogWidgets/index.js';
|
|
8
9
|
import { normalizeReferenceList, normalizeReferenceName } from './featureDialogWidgets/utils.js';
|
|
9
|
-
|
|
10
|
+
const REF_PREVIEW_COLORS = {
|
|
11
|
+
EDGE: '#ff00ff',
|
|
12
|
+
FACE: '#ffc400',
|
|
13
|
+
PLANE: '#2eff2e',
|
|
14
|
+
VERTEX: '#00ffff',
|
|
15
|
+
};
|
|
10
16
|
|
|
11
17
|
|
|
12
18
|
|
|
@@ -29,6 +35,7 @@ export class SchemaForm {
|
|
|
29
35
|
if (prev && prev !== el) {
|
|
30
36
|
try { prev.style.filter = 'none'; } catch (_) { }
|
|
31
37
|
try { prev.removeAttribute('active-reference-selection'); } catch (_) { }
|
|
38
|
+
try { if (typeof prev.__refPreviewCleanup === 'function') prev.__refPreviewCleanup(); } catch (_) { }
|
|
32
39
|
}
|
|
33
40
|
} catch (_) { }
|
|
34
41
|
SchemaForm.__activeRefInput = el || null;
|
|
@@ -198,6 +205,7 @@ export class SchemaForm {
|
|
|
198
205
|
// If target is inside the same active element (e.g., clicking within the input), skip
|
|
199
206
|
if (target && typeof target.closest === 'function') {
|
|
200
207
|
if (target.closest('[active-reference-selection]')) return;
|
|
208
|
+
if (target.closest('.ref-active')) return;
|
|
201
209
|
}
|
|
202
210
|
this._stopActiveReferenceSelection();
|
|
203
211
|
} catch (_) { }
|
|
@@ -494,6 +502,626 @@ export class SchemaForm {
|
|
|
494
502
|
|| null;
|
|
495
503
|
}
|
|
496
504
|
|
|
505
|
+
_getReferencePreviewCacheRoot() {
|
|
506
|
+
const holder = this.options?.featureRef || this;
|
|
507
|
+
if (!holder) return null;
|
|
508
|
+
if (!holder.__refPreviewCache) {
|
|
509
|
+
try {
|
|
510
|
+
Object.defineProperty(holder, '__refPreviewCache', {
|
|
511
|
+
value: new Map(),
|
|
512
|
+
configurable: true,
|
|
513
|
+
enumerable: false,
|
|
514
|
+
writable: true,
|
|
515
|
+
});
|
|
516
|
+
} catch (_) {
|
|
517
|
+
holder.__refPreviewCache = new Map();
|
|
518
|
+
}
|
|
519
|
+
}
|
|
520
|
+
return holder.__refPreviewCache;
|
|
521
|
+
}
|
|
522
|
+
|
|
523
|
+
_getReferencePreviewCache(inputEl) {
|
|
524
|
+
const root = this._getReferencePreviewCacheRoot();
|
|
525
|
+
if (!root) return null;
|
|
526
|
+
const key = (inputEl?.dataset?.key || inputEl?.dataset?.refKey || inputEl?.__refPreviewKey || '__default');
|
|
527
|
+
let bucket = root.get(key);
|
|
528
|
+
if (!bucket) {
|
|
529
|
+
bucket = new Map();
|
|
530
|
+
root.set(key, bucket);
|
|
531
|
+
}
|
|
532
|
+
return bucket;
|
|
533
|
+
}
|
|
534
|
+
|
|
535
|
+
_getReferencePreviewPersistentBucket(inputEl) {
|
|
536
|
+
const entry = this.options?.featureRef || null;
|
|
537
|
+
if (!entry) return null;
|
|
538
|
+
if (!entry.persistentData || typeof entry.persistentData !== 'object') {
|
|
539
|
+
entry.persistentData = {};
|
|
540
|
+
}
|
|
541
|
+
if (!entry.persistentData.__refPreviewSnapshots || typeof entry.persistentData.__refPreviewSnapshots !== 'object') {
|
|
542
|
+
entry.persistentData.__refPreviewSnapshots = {};
|
|
543
|
+
}
|
|
544
|
+
const key = (inputEl?.dataset?.key || inputEl?.dataset?.refKey || inputEl?.__refPreviewKey || '__default');
|
|
545
|
+
if (!entry.persistentData.__refPreviewSnapshots[key] || typeof entry.persistentData.__refPreviewSnapshots[key] !== 'object') {
|
|
546
|
+
entry.persistentData.__refPreviewSnapshots[key] = {};
|
|
547
|
+
}
|
|
548
|
+
return entry.persistentData.__refPreviewSnapshots[key];
|
|
549
|
+
}
|
|
550
|
+
|
|
551
|
+
_resolveReferencePreviewName(obj) {
|
|
552
|
+
if (!obj) return null;
|
|
553
|
+
const raw = obj.name != null ? String(obj.name).trim() : '';
|
|
554
|
+
if (raw) return raw;
|
|
555
|
+
const type = obj.type || 'OBJECT';
|
|
556
|
+
const pos = obj.position || {};
|
|
557
|
+
const x = Number.isFinite(pos.x) ? pos.x : 0;
|
|
558
|
+
const y = Number.isFinite(pos.y) ? pos.y : 0;
|
|
559
|
+
const z = Number.isFinite(pos.z) ? pos.z : 0;
|
|
560
|
+
return `${type}(${x},${y},${z})`;
|
|
561
|
+
}
|
|
562
|
+
|
|
563
|
+
_extractEdgeWorldPositions(obj) {
|
|
564
|
+
if (!obj) return [];
|
|
565
|
+
try {
|
|
566
|
+
if (typeof obj.points === 'function') {
|
|
567
|
+
const pts = obj.points(true);
|
|
568
|
+
if (Array.isArray(pts) && pts.length) {
|
|
569
|
+
const flat = [];
|
|
570
|
+
for (const p of pts) {
|
|
571
|
+
if (!p) continue;
|
|
572
|
+
const x = Number(p.x);
|
|
573
|
+
const y = Number(p.y);
|
|
574
|
+
const z = Number(p.z);
|
|
575
|
+
if (!Number.isFinite(x) || !Number.isFinite(y) || !Number.isFinite(z)) continue;
|
|
576
|
+
flat.push(x, y, z);
|
|
577
|
+
}
|
|
578
|
+
if (flat.length >= 6) return flat;
|
|
579
|
+
}
|
|
580
|
+
}
|
|
581
|
+
} catch (_) { /* ignore */ }
|
|
582
|
+
|
|
583
|
+
try {
|
|
584
|
+
const geom = obj.geometry;
|
|
585
|
+
const pos = geom && typeof geom.getAttribute === 'function' ? geom.getAttribute('position') : null;
|
|
586
|
+
if (!pos || pos.itemSize !== 3 || pos.count < 2) return [];
|
|
587
|
+
const tmp = new THREE.Vector3();
|
|
588
|
+
const flat = [];
|
|
589
|
+
for (let i = 0; i < pos.count; i++) {
|
|
590
|
+
tmp.set(pos.getX(i), pos.getY(i), pos.getZ(i));
|
|
591
|
+
tmp.applyMatrix4(obj.matrixWorld);
|
|
592
|
+
flat.push(tmp.x, tmp.y, tmp.z);
|
|
593
|
+
}
|
|
594
|
+
return flat.length >= 6 ? flat : [];
|
|
595
|
+
} catch (_) { /* ignore */ }
|
|
596
|
+
return [];
|
|
597
|
+
}
|
|
598
|
+
|
|
599
|
+
_syncPreviewLineResolution(mat) {
|
|
600
|
+
if (!mat || !mat.resolution || typeof mat.resolution.set !== 'function') return;
|
|
601
|
+
let width = 0;
|
|
602
|
+
let height = 0;
|
|
603
|
+
try {
|
|
604
|
+
const viewer = this.options?.viewer || null;
|
|
605
|
+
const el = viewer?.renderer?.domElement || null;
|
|
606
|
+
if (el && typeof el.getBoundingClientRect === 'function') {
|
|
607
|
+
const rect = el.getBoundingClientRect();
|
|
608
|
+
width = rect.width || rect.right - rect.left;
|
|
609
|
+
height = rect.height || rect.bottom - rect.top;
|
|
610
|
+
}
|
|
611
|
+
if ((!width || !height) && viewer?.container) {
|
|
612
|
+
width = viewer.container.clientWidth || width;
|
|
613
|
+
height = viewer.container.clientHeight || height;
|
|
614
|
+
}
|
|
615
|
+
} catch (_) { /* ignore */ }
|
|
616
|
+
if (!width || !height) {
|
|
617
|
+
try {
|
|
618
|
+
if (typeof window !== 'undefined') {
|
|
619
|
+
width = window.innerWidth || width;
|
|
620
|
+
height = window.innerHeight || height;
|
|
621
|
+
}
|
|
622
|
+
} catch (_) { /* ignore */ }
|
|
623
|
+
}
|
|
624
|
+
if (Number.isFinite(width) && Number.isFinite(height) && width > 0 && height > 0) {
|
|
625
|
+
try { mat.resolution.set(width, height); } catch (_) { }
|
|
626
|
+
}
|
|
627
|
+
}
|
|
628
|
+
|
|
629
|
+
_createPreviewLineMaterial(sourceMat, colorHex = REF_PREVIEW_COLORS.EDGE) {
|
|
630
|
+
let mat = null;
|
|
631
|
+
if (sourceMat && typeof sourceMat.clone === 'function') {
|
|
632
|
+
try { mat = sourceMat.clone(); } catch (_) { mat = null; }
|
|
633
|
+
}
|
|
634
|
+
if (!mat) {
|
|
635
|
+
try {
|
|
636
|
+
mat = new LineMaterial({ color: colorHex, linewidth: 3, transparent: true, opacity: 0.95, worldUnits: false, dashed: false });
|
|
637
|
+
} catch (_) { mat = null; }
|
|
638
|
+
}
|
|
639
|
+
if (mat && mat.color && typeof mat.color.set === 'function') {
|
|
640
|
+
try { mat.color.set(colorHex); } catch (_) { }
|
|
641
|
+
}
|
|
642
|
+
if (mat) {
|
|
643
|
+
try { mat.transparent = true; } catch (_) { }
|
|
644
|
+
try { mat.opacity = Number.isFinite(mat.opacity) ? Math.min(0.95, mat.opacity) : 0.95; } catch (_) { }
|
|
645
|
+
try { mat.depthTest = false; } catch (_) { }
|
|
646
|
+
try { mat.depthWrite = false; } catch (_) { }
|
|
647
|
+
try { if (typeof mat.dashed !== 'undefined') mat.dashed = false; } catch (_) { }
|
|
648
|
+
try { if (typeof mat.dashScale !== 'undefined') mat.dashScale = 1; } catch (_) { }
|
|
649
|
+
try { if (typeof mat.dashSize !== 'undefined') mat.dashSize = 1; } catch (_) { }
|
|
650
|
+
try { if (typeof mat.gapSize !== 'undefined') mat.gapSize = 0; } catch (_) { }
|
|
651
|
+
try { this._syncPreviewLineResolution(mat); } catch (_) { }
|
|
652
|
+
}
|
|
653
|
+
return mat;
|
|
654
|
+
}
|
|
655
|
+
|
|
656
|
+
_createPreviewMeshMaterial(sourceMat, colorHex = REF_PREVIEW_COLORS.FACE) {
|
|
657
|
+
let mat = null;
|
|
658
|
+
if (sourceMat && typeof sourceMat.clone === 'function') {
|
|
659
|
+
try { mat = sourceMat.clone(); } catch (_) { mat = null; }
|
|
660
|
+
}
|
|
661
|
+
if (!mat) {
|
|
662
|
+
try {
|
|
663
|
+
mat = new THREE.MeshStandardMaterial({
|
|
664
|
+
color: colorHex,
|
|
665
|
+
transparent: true,
|
|
666
|
+
opacity: 0.25,
|
|
667
|
+
depthWrite: false,
|
|
668
|
+
side: THREE.DoubleSide,
|
|
669
|
+
});
|
|
670
|
+
} catch (_) { mat = null; }
|
|
671
|
+
}
|
|
672
|
+
if (mat && mat.color && typeof mat.color.set === 'function') {
|
|
673
|
+
try { mat.color.set(colorHex); } catch (_) { }
|
|
674
|
+
}
|
|
675
|
+
if (mat) {
|
|
676
|
+
try { mat.transparent = true; } catch (_) { }
|
|
677
|
+
try { mat.opacity = 0.25; } catch (_) { }
|
|
678
|
+
try { mat.depthWrite = false; } catch (_) { }
|
|
679
|
+
try { mat.depthTest = true; } catch (_) { }
|
|
680
|
+
try { mat.side = THREE.DoubleSide; } catch (_) { }
|
|
681
|
+
try { mat.polygonOffset = true; mat.polygonOffsetFactor = -1; mat.polygonOffsetUnits = -1; } catch (_) { }
|
|
682
|
+
}
|
|
683
|
+
return mat;
|
|
684
|
+
}
|
|
685
|
+
|
|
686
|
+
_createPreviewPointMaterial(sourceMat, colorHex = REF_PREVIEW_COLORS.VERTEX) {
|
|
687
|
+
let mat = null;
|
|
688
|
+
if (sourceMat && typeof sourceMat.clone === 'function') {
|
|
689
|
+
try { mat = sourceMat.clone(); } catch (_) { mat = null; }
|
|
690
|
+
}
|
|
691
|
+
if (!mat || !mat.isPointsMaterial) {
|
|
692
|
+
try {
|
|
693
|
+
mat = new THREE.PointsMaterial({
|
|
694
|
+
color: colorHex,
|
|
695
|
+
size: 7,
|
|
696
|
+
sizeAttenuation: false,
|
|
697
|
+
transparent: true,
|
|
698
|
+
opacity: 0.9,
|
|
699
|
+
});
|
|
700
|
+
} catch (_) { mat = null; }
|
|
701
|
+
}
|
|
702
|
+
if (mat && mat.color && typeof mat.color.set === 'function') {
|
|
703
|
+
try { mat.color.set(colorHex); } catch (_) { }
|
|
704
|
+
}
|
|
705
|
+
if (mat) {
|
|
706
|
+
try { mat.transparent = true; } catch (_) { }
|
|
707
|
+
try { mat.opacity = 0.9; } catch (_) { }
|
|
708
|
+
}
|
|
709
|
+
return mat;
|
|
710
|
+
}
|
|
711
|
+
|
|
712
|
+
_configurePreviewObject(obj, refName, previewType) {
|
|
713
|
+
if (!obj) return obj;
|
|
714
|
+
try { obj.name = `__refPreview__${refName}`; } catch (_) { }
|
|
715
|
+
try {
|
|
716
|
+
obj.userData = obj.userData || {};
|
|
717
|
+
obj.userData.refPreview = true;
|
|
718
|
+
obj.userData.refName = refName;
|
|
719
|
+
obj.userData.previewType = previewType;
|
|
720
|
+
obj.userData.excludeFromFit = true;
|
|
721
|
+
} catch (_) { }
|
|
722
|
+
try { obj.renderOrder = Math.max(10050, obj.renderOrder || 0); } catch (_) { }
|
|
723
|
+
try { obj.raycast = () => { }; } catch (_) { }
|
|
724
|
+
try {
|
|
725
|
+
obj.traverse?.((child) => {
|
|
726
|
+
if (!child || child === obj) return;
|
|
727
|
+
try { child.raycast = () => { }; } catch (_) { }
|
|
728
|
+
try {
|
|
729
|
+
child.userData = child.userData || {};
|
|
730
|
+
child.userData.refPreview = true;
|
|
731
|
+
child.userData.refName = refName;
|
|
732
|
+
if (!child.userData.previewType && child.type) child.userData.previewType = child.type;
|
|
733
|
+
} catch (_) { }
|
|
734
|
+
});
|
|
735
|
+
} catch (_) { }
|
|
736
|
+
return obj;
|
|
737
|
+
}
|
|
738
|
+
|
|
739
|
+
_getOwningFeatureIdForObject(obj) {
|
|
740
|
+
let cur = obj;
|
|
741
|
+
let guard = 0;
|
|
742
|
+
while (cur && guard < 8) {
|
|
743
|
+
if (cur.owningFeatureID != null) return cur.owningFeatureID;
|
|
744
|
+
cur = cur.parent || null;
|
|
745
|
+
guard += 1;
|
|
746
|
+
}
|
|
747
|
+
return null;
|
|
748
|
+
}
|
|
749
|
+
|
|
750
|
+
_buildEdgePreviewFromObject(obj, refName, colorHex = REF_PREVIEW_COLORS.EDGE) {
|
|
751
|
+
if (!obj) return null;
|
|
752
|
+
const positions = this._extractEdgeWorldPositions(obj);
|
|
753
|
+
if (!positions || positions.length < 6) return null;
|
|
754
|
+
const geom = new LineGeometry();
|
|
755
|
+
geom.setPositions(positions);
|
|
756
|
+
try { geom.computeBoundingSphere(); } catch (_) { }
|
|
757
|
+
const mat = this._createPreviewLineMaterial(obj.material, colorHex);
|
|
758
|
+
const line = new Line2(geom, mat || undefined);
|
|
759
|
+
try { line.computeLineDistances?.(); } catch (_) { }
|
|
760
|
+
try { if (line.material && typeof line.material.dashed !== 'undefined') line.material.dashed = false; } catch (_) { }
|
|
761
|
+
line.type = 'REF_PREVIEW_EDGE';
|
|
762
|
+
return this._configurePreviewObject(line, refName, 'EDGE');
|
|
763
|
+
}
|
|
764
|
+
|
|
765
|
+
_extractFaceEdgePositions(face) {
|
|
766
|
+
if (!face) return [];
|
|
767
|
+
const out = [];
|
|
768
|
+
const addEdge = (edge) => {
|
|
769
|
+
const positions = this._extractEdgeWorldPositions(edge);
|
|
770
|
+
if (positions && positions.length >= 6) out.push(positions);
|
|
771
|
+
};
|
|
772
|
+
|
|
773
|
+
if (Array.isArray(face.edges) && face.edges.length) {
|
|
774
|
+
for (const edge of face.edges) addEdge(edge);
|
|
775
|
+
return out;
|
|
776
|
+
}
|
|
777
|
+
|
|
778
|
+
const faceName = face?.name || face?.userData?.faceName || null;
|
|
779
|
+
const parentSolid = face?.parentSolid || face?.userData?.parentSolid || face?.parent || null;
|
|
780
|
+
if (!faceName || !parentSolid || !Array.isArray(parentSolid.children)) return out;
|
|
781
|
+
|
|
782
|
+
for (const child of parentSolid.children) {
|
|
783
|
+
if (!child || child.type !== SelectionFilter.EDGE) continue;
|
|
784
|
+
const faceA = child?.userData?.faceA || null;
|
|
785
|
+
const faceB = child?.userData?.faceB || null;
|
|
786
|
+
if (faceA === faceName || faceB === faceName) {
|
|
787
|
+
addEdge(child);
|
|
788
|
+
}
|
|
789
|
+
}
|
|
790
|
+
return out;
|
|
791
|
+
}
|
|
792
|
+
|
|
793
|
+
_buildReferencePreviewObject(obj, refName) {
|
|
794
|
+
if (!obj) return null;
|
|
795
|
+
const type = String(obj.type || '').toUpperCase();
|
|
796
|
+
if (type === SelectionFilter.EDGE || type === 'EDGE') {
|
|
797
|
+
return this._buildEdgePreviewFromObject(obj, refName, REF_PREVIEW_COLORS.EDGE);
|
|
798
|
+
}
|
|
799
|
+
if (type === SelectionFilter.FACE || type === SelectionFilter.PLANE || type === 'FACE' || type === 'PLANE') {
|
|
800
|
+
const geom = obj.geometry && typeof obj.geometry.clone === 'function' ? obj.geometry.clone() : null;
|
|
801
|
+
if (!geom) return null;
|
|
802
|
+
try { geom.applyMatrix4(obj.matrixWorld); } catch (_) { }
|
|
803
|
+
const color = (type === SelectionFilter.PLANE || type === 'PLANE') ? REF_PREVIEW_COLORS.PLANE : REF_PREVIEW_COLORS.FACE;
|
|
804
|
+
const mat = this._createPreviewMeshMaterial(obj.material, color);
|
|
805
|
+
const mesh = new THREE.Mesh(geom, mat || undefined);
|
|
806
|
+
mesh.type = (type === SelectionFilter.PLANE || type === 'PLANE') ? 'REF_PREVIEW_PLANE' : 'REF_PREVIEW_FACE';
|
|
807
|
+
try { mesh.matrixAutoUpdate = false; } catch (_) { }
|
|
808
|
+
const edges = Array.isArray(obj.edges) ? obj.edges : [];
|
|
809
|
+
if (edges.length) {
|
|
810
|
+
const group = new THREE.Group();
|
|
811
|
+
group.type = mesh.type;
|
|
812
|
+
try { group.userData = group.userData || {}; } catch (_) { }
|
|
813
|
+
try { group.userData.previewHasEdges = true; } catch (_) { }
|
|
814
|
+
try { group.userData.previewHasFace = true; } catch (_) { }
|
|
815
|
+
group.add(mesh);
|
|
816
|
+
for (const edge of edges) {
|
|
817
|
+
const edgePreview = this._buildEdgePreviewFromObject(edge, refName, REF_PREVIEW_COLORS.EDGE);
|
|
818
|
+
if (edgePreview) group.add(edgePreview);
|
|
819
|
+
}
|
|
820
|
+
return this._configurePreviewObject(group, refName, mesh.type);
|
|
821
|
+
}
|
|
822
|
+
return this._configurePreviewObject(mesh, refName, mesh.type);
|
|
823
|
+
}
|
|
824
|
+
if (type === SelectionFilter.VERTEX || type === 'VERTEX') {
|
|
825
|
+
const pos = new THREE.Vector3();
|
|
826
|
+
try {
|
|
827
|
+
if (typeof obj.getWorldPosition === 'function') obj.getWorldPosition(pos);
|
|
828
|
+
else pos.set(obj.position?.x || 0, obj.position?.y || 0, obj.position?.z || 0);
|
|
829
|
+
} catch (_) { }
|
|
830
|
+
const geom = new THREE.BufferGeometry();
|
|
831
|
+
geom.setAttribute('position', new THREE.Float32BufferAttribute([0, 0, 0], 3));
|
|
832
|
+
const mat = this._createPreviewPointMaterial(obj.material, REF_PREVIEW_COLORS.VERTEX);
|
|
833
|
+
const pts = new THREE.Points(geom, mat || undefined);
|
|
834
|
+
pts.position.copy(pos);
|
|
835
|
+
pts.type = 'REF_PREVIEW_VERTEX';
|
|
836
|
+
return this._configurePreviewObject(pts, refName, 'VERTEX');
|
|
837
|
+
}
|
|
838
|
+
return null;
|
|
839
|
+
}
|
|
840
|
+
|
|
841
|
+
_buildReferencePreviewFromSnapshot(refName, snapshot) {
|
|
842
|
+
if (!snapshot || !refName) return null;
|
|
843
|
+
const type = String(snapshot.type || '').toUpperCase();
|
|
844
|
+
if (type === 'EDGE') {
|
|
845
|
+
const positions = Array.isArray(snapshot.positions) ? snapshot.positions : null;
|
|
846
|
+
if (!positions || positions.length < 6) return null;
|
|
847
|
+
const geom = new LineGeometry();
|
|
848
|
+
geom.setPositions(positions);
|
|
849
|
+
try { geom.computeBoundingSphere(); } catch (_) { }
|
|
850
|
+
const mat = this._createPreviewLineMaterial(null, REF_PREVIEW_COLORS.EDGE);
|
|
851
|
+
const line = new Line2(geom, mat || undefined);
|
|
852
|
+
try { line.computeLineDistances?.(); } catch (_) { }
|
|
853
|
+
try { if (line.material && typeof line.material.dashed !== 'undefined') line.material.dashed = false; } catch (_) { }
|
|
854
|
+
line.type = 'REF_PREVIEW_EDGE';
|
|
855
|
+
return this._configurePreviewObject(line, refName, 'EDGE');
|
|
856
|
+
}
|
|
857
|
+
if (type === 'FACE' || type === 'PLANE') {
|
|
858
|
+
const group = new THREE.Group();
|
|
859
|
+
group.type = type === 'PLANE' ? 'REF_PREVIEW_PLANE' : 'REF_PREVIEW_FACE';
|
|
860
|
+
try { group.userData = group.userData || {}; } catch (_) { }
|
|
861
|
+
try { group.userData.previewHasEdges = true; } catch (_) { }
|
|
862
|
+
const edges = Array.isArray(snapshot.edgePositions) ? snapshot.edgePositions : [];
|
|
863
|
+
for (const positions of edges) {
|
|
864
|
+
if (!Array.isArray(positions) || positions.length < 6) continue;
|
|
865
|
+
const geom = new LineGeometry();
|
|
866
|
+
geom.setPositions(positions);
|
|
867
|
+
try { geom.computeBoundingSphere(); } catch (_) { }
|
|
868
|
+
const mat = this._createPreviewLineMaterial(null, REF_PREVIEW_COLORS.EDGE);
|
|
869
|
+
const line = new Line2(geom, mat || undefined);
|
|
870
|
+
try { line.computeLineDistances?.(); } catch (_) { }
|
|
871
|
+
try { if (line.material && typeof line.material.dashed !== 'undefined') line.material.dashed = false; } catch (_) { }
|
|
872
|
+
line.type = 'REF_PREVIEW_EDGE';
|
|
873
|
+
this._configurePreviewObject(line, refName, 'EDGE');
|
|
874
|
+
group.add(line);
|
|
875
|
+
}
|
|
876
|
+
if (group.children.length === 0) return null;
|
|
877
|
+
return this._configurePreviewObject(group, refName, group.type);
|
|
878
|
+
}
|
|
879
|
+
if (type === 'VERTEX') {
|
|
880
|
+
const pos = snapshot.position;
|
|
881
|
+
if (!Array.isArray(pos) || pos.length < 3) return null;
|
|
882
|
+
const geom = new THREE.BufferGeometry();
|
|
883
|
+
geom.setAttribute('position', new THREE.Float32BufferAttribute([0, 0, 0], 3));
|
|
884
|
+
const mat = this._createPreviewPointMaterial(null, REF_PREVIEW_COLORS.VERTEX);
|
|
885
|
+
const pts = new THREE.Points(geom, mat || undefined);
|
|
886
|
+
pts.position.set(Number(pos[0]) || 0, Number(pos[1]) || 0, Number(pos[2]) || 0);
|
|
887
|
+
pts.type = 'REF_PREVIEW_VERTEX';
|
|
888
|
+
return this._configurePreviewObject(pts, refName, 'VERTEX');
|
|
889
|
+
}
|
|
890
|
+
return null;
|
|
891
|
+
}
|
|
892
|
+
|
|
893
|
+
_ensureReferencePreviewGroup(inputEl) {
|
|
894
|
+
const scene = this._getReferenceSelectionScene();
|
|
895
|
+
if (!scene || !inputEl) return null;
|
|
896
|
+
const existing = inputEl.__refPreviewGroup;
|
|
897
|
+
if (existing && existing.isObject3D) {
|
|
898
|
+
if (existing.parent !== scene) {
|
|
899
|
+
try { scene.add(existing); } catch (_) { }
|
|
900
|
+
}
|
|
901
|
+
return existing;
|
|
902
|
+
}
|
|
903
|
+
const group = new THREE.Group();
|
|
904
|
+
try { group.name = `__REF_PREVIEW_GROUP__${inputEl?.dataset?.key || ''}`; } catch (_) { }
|
|
905
|
+
try {
|
|
906
|
+
group.userData = group.userData || {};
|
|
907
|
+
group.userData.preventRemove = true;
|
|
908
|
+
group.userData.excludeFromFit = true;
|
|
909
|
+
group.userData.refPreview = true;
|
|
910
|
+
} catch (_) { }
|
|
911
|
+
try { group.renderOrder = 10040; } catch (_) { }
|
|
912
|
+
try { group.raycast = () => { }; } catch (_) { }
|
|
913
|
+
inputEl.__refPreviewGroup = group;
|
|
914
|
+
try { scene.add(group); } catch (_) { }
|
|
915
|
+
return group;
|
|
916
|
+
}
|
|
917
|
+
|
|
918
|
+
_removeReferencePreviewGroup(inputEl) {
|
|
919
|
+
const group = inputEl?.__refPreviewGroup;
|
|
920
|
+
if (!group || !group.isObject3D) return;
|
|
921
|
+
try { if (group.userData) group.userData.preventRemove = false; } catch (_) { }
|
|
922
|
+
try { if (group.parent) group.parent.remove(group); } catch (_) { }
|
|
923
|
+
}
|
|
924
|
+
|
|
925
|
+
_syncActiveReferenceSelectionPreview(inputEl, def = null) {
|
|
926
|
+
try {
|
|
927
|
+
const active = SchemaForm.__activeRefInput;
|
|
928
|
+
if (!active || active !== inputEl) return;
|
|
929
|
+
const scene = this._getReferenceSelectionScene();
|
|
930
|
+
if (!scene) return;
|
|
931
|
+
const names = this._collectReferenceSelectionNames(inputEl, def);
|
|
932
|
+
if (!names.length) {
|
|
933
|
+
this._removeReferencePreviewGroup(inputEl);
|
|
934
|
+
return;
|
|
935
|
+
}
|
|
936
|
+
const cache = this._getReferencePreviewCache(inputEl);
|
|
937
|
+
if (!cache || cache.size === 0) return;
|
|
938
|
+
const group = this._ensureReferencePreviewGroup(inputEl);
|
|
939
|
+
const wanted = new Set(names);
|
|
940
|
+
if (group && Array.isArray(group.children)) {
|
|
941
|
+
for (const child of group.children.slice()) {
|
|
942
|
+
const refName = child?.userData?.refName;
|
|
943
|
+
if (!refName || !wanted.has(refName)) {
|
|
944
|
+
try { group.remove(child); } catch (_) { }
|
|
945
|
+
}
|
|
946
|
+
}
|
|
947
|
+
}
|
|
948
|
+
for (const name of names) {
|
|
949
|
+
const entry = cache.get(name);
|
|
950
|
+
let ghost = entry && entry.object ? entry.object : entry;
|
|
951
|
+
if (!ghost) continue;
|
|
952
|
+
const sourceUuid = entry?.sourceUuid || null;
|
|
953
|
+
let originalPresent = false;
|
|
954
|
+
if (sourceUuid && typeof scene.getObjectByProperty === 'function') {
|
|
955
|
+
try { originalPresent = !!scene.getObjectByProperty('uuid', sourceUuid); } catch (_) { originalPresent = false; }
|
|
956
|
+
} else {
|
|
957
|
+
const real = scene.getObjectByName(name);
|
|
958
|
+
originalPresent = !!real;
|
|
959
|
+
}
|
|
960
|
+
if (originalPresent) {
|
|
961
|
+
const keepGhost = !!(entry?.showWhenOriginalPresent || ghost?.userData?.previewHasEdges);
|
|
962
|
+
if (!keepGhost) {
|
|
963
|
+
if (ghost.parent === group) {
|
|
964
|
+
try { group.remove(ghost); } catch (_) { }
|
|
965
|
+
}
|
|
966
|
+
continue;
|
|
967
|
+
}
|
|
968
|
+
try {
|
|
969
|
+
ghost.traverse?.((child) => {
|
|
970
|
+
if (!child || !child.userData?.refPreview) return;
|
|
971
|
+
const pType = String(child.userData.previewType || child.type || '').toUpperCase();
|
|
972
|
+
if (pType.includes('REF_PREVIEW_FACE') || pType.includes('REF_PREVIEW_PLANE')) {
|
|
973
|
+
child.visible = false;
|
|
974
|
+
} else if (child.type === 'REF_PREVIEW_EDGE') {
|
|
975
|
+
child.visible = true;
|
|
976
|
+
}
|
|
977
|
+
});
|
|
978
|
+
} catch (_) { }
|
|
979
|
+
if (ghost.parent !== group) {
|
|
980
|
+
try { group.add(ghost); } catch (_) { }
|
|
981
|
+
}
|
|
982
|
+
continue;
|
|
983
|
+
}
|
|
984
|
+
if (ghost.parent !== group) {
|
|
985
|
+
try { group.add(ghost); } catch (_) { }
|
|
986
|
+
}
|
|
987
|
+
try { ghost.visible = true; } catch (_) { }
|
|
988
|
+
}
|
|
989
|
+
} catch (_) { }
|
|
990
|
+
}
|
|
991
|
+
|
|
992
|
+
_seedReferencePreviewCacheFromScene(inputEl, def = null, names = null, sceneOverride = null) {
|
|
993
|
+
if (!inputEl) return;
|
|
994
|
+
const scene = sceneOverride || this._getReferenceSelectionScene();
|
|
995
|
+
if (!scene) return;
|
|
996
|
+
const list = Array.isArray(names) ? names : this._collectReferenceSelectionNames(inputEl, def);
|
|
997
|
+
if (!list.length) return;
|
|
998
|
+
const cache = this._getReferencePreviewCache(inputEl);
|
|
999
|
+
if (!cache) return;
|
|
1000
|
+
const store = this._getReferencePreviewPersistentBucket(inputEl);
|
|
1001
|
+
for (const name of list) {
|
|
1002
|
+
if (!name) continue;
|
|
1003
|
+
const existing = cache.get(name) || null;
|
|
1004
|
+
const snapshot = store ? store[name] : null;
|
|
1005
|
+
if (snapshot) {
|
|
1006
|
+
const snapType = String(snapshot.type || '').toUpperCase();
|
|
1007
|
+
const snapEdges = Array.isArray(snapshot.edgePositions) ? snapshot.edgePositions : null;
|
|
1008
|
+
const isFaceSnap = (snapType === 'FACE' || snapType === 'PLANE') && snapEdges && snapEdges.length;
|
|
1009
|
+
const isEdgeSnap = snapType === 'EDGE' && Array.isArray(snapshot.positions) && snapshot.positions.length >= 6;
|
|
1010
|
+
const isVertexSnap = snapType === 'VERTEX' && Array.isArray(snapshot.position) && snapshot.position.length >= 3;
|
|
1011
|
+
if (isFaceSnap || isEdgeSnap || isVertexSnap) {
|
|
1012
|
+
const shouldOverride = !existing || !existing.fromSnapshot || isFaceSnap;
|
|
1013
|
+
if (shouldOverride) {
|
|
1014
|
+
const ghost = this._buildReferencePreviewFromSnapshot(name, snapshot);
|
|
1015
|
+
if (ghost) {
|
|
1016
|
+
cache.set(name, {
|
|
1017
|
+
object: ghost,
|
|
1018
|
+
type: snapshot.type || null,
|
|
1019
|
+
sourceUuid: snapshot.sourceUuid || null,
|
|
1020
|
+
sourceFeatureId: snapshot.sourceFeatureId || null,
|
|
1021
|
+
showWhenOriginalPresent: isFaceSnap || !!ghost?.userData?.previewHasEdges,
|
|
1022
|
+
fromSnapshot: true,
|
|
1023
|
+
});
|
|
1024
|
+
continue;
|
|
1025
|
+
}
|
|
1026
|
+
}
|
|
1027
|
+
}
|
|
1028
|
+
}
|
|
1029
|
+
if (cache.has(name)) continue;
|
|
1030
|
+
const obj = scene.getObjectByName(name);
|
|
1031
|
+
if (obj && !obj?.userData?.refPreview) {
|
|
1032
|
+
this._storeReferencePreviewSnapshot(inputEl, def, obj);
|
|
1033
|
+
continue;
|
|
1034
|
+
}
|
|
1035
|
+
if (store && store[name]) {
|
|
1036
|
+
const snapshot = store[name];
|
|
1037
|
+
const ghost = this._buildReferencePreviewFromSnapshot(name, snapshot);
|
|
1038
|
+
if (ghost) {
|
|
1039
|
+
cache.set(name, {
|
|
1040
|
+
object: ghost,
|
|
1041
|
+
type: snapshot.type || null,
|
|
1042
|
+
sourceUuid: snapshot.sourceUuid || null,
|
|
1043
|
+
sourceFeatureId: snapshot.sourceFeatureId || null,
|
|
1044
|
+
showWhenOriginalPresent: String(snapshot.type || '').toUpperCase() === 'FACE' || String(snapshot.type || '').toUpperCase() === 'PLANE' || !!ghost?.userData?.previewHasEdges,
|
|
1045
|
+
fromSnapshot: true,
|
|
1046
|
+
});
|
|
1047
|
+
}
|
|
1048
|
+
}
|
|
1049
|
+
}
|
|
1050
|
+
}
|
|
1051
|
+
|
|
1052
|
+
_storeReferencePreviewSnapshot(inputEl, def, obj) {
|
|
1053
|
+
try {
|
|
1054
|
+
if (!inputEl || !obj) return;
|
|
1055
|
+
const refName = this._resolveReferencePreviewName(obj);
|
|
1056
|
+
if (!refName) return;
|
|
1057
|
+
const cache = this._getReferencePreviewCache(inputEl);
|
|
1058
|
+
if (!cache) return;
|
|
1059
|
+
const ghost = this._buildReferencePreviewObject(obj, refName);
|
|
1060
|
+
if (!ghost) return;
|
|
1061
|
+
const sourceUuid = obj.uuid || null;
|
|
1062
|
+
const sourceFeatureId = this._getOwningFeatureIdForObject(obj);
|
|
1063
|
+
cache.set(refName, {
|
|
1064
|
+
object: ghost,
|
|
1065
|
+
type: obj.type || null,
|
|
1066
|
+
sourceUuid,
|
|
1067
|
+
sourceFeatureId,
|
|
1068
|
+
showWhenOriginalPresent: !!ghost?.userData?.previewHasEdges,
|
|
1069
|
+
});
|
|
1070
|
+
try {
|
|
1071
|
+
const store = this._getReferencePreviewPersistentBucket(inputEl);
|
|
1072
|
+
if (store) {
|
|
1073
|
+
const objType = String(obj.type || '').toUpperCase();
|
|
1074
|
+
if (objType === SelectionFilter.EDGE || objType === 'EDGE') {
|
|
1075
|
+
const positions = this._extractEdgeWorldPositions(obj);
|
|
1076
|
+
if (positions && positions.length >= 6) {
|
|
1077
|
+
store[refName] = { type: 'EDGE', positions, sourceUuid, sourceFeatureId };
|
|
1078
|
+
}
|
|
1079
|
+
} else if (objType === SelectionFilter.VERTEX || objType === 'VERTEX') {
|
|
1080
|
+
const pos = new THREE.Vector3();
|
|
1081
|
+
try {
|
|
1082
|
+
if (typeof obj.getWorldPosition === 'function') obj.getWorldPosition(pos);
|
|
1083
|
+
else pos.set(obj.position?.x || 0, obj.position?.y || 0, obj.position?.z || 0);
|
|
1084
|
+
} catch (_) { }
|
|
1085
|
+
store[refName] = { type: 'VERTEX', position: [pos.x, pos.y, pos.z], sourceUuid, sourceFeatureId };
|
|
1086
|
+
}
|
|
1087
|
+
}
|
|
1088
|
+
} catch (_) { }
|
|
1089
|
+
if (SchemaForm.__activeRefInput === inputEl) {
|
|
1090
|
+
try { this._syncActiveReferenceSelectionPreview(inputEl, def); } catch (_) { }
|
|
1091
|
+
}
|
|
1092
|
+
} catch (_) { }
|
|
1093
|
+
}
|
|
1094
|
+
|
|
1095
|
+
_startReferencePreviewWatcher(inputEl, def) {
|
|
1096
|
+
if (!inputEl) return;
|
|
1097
|
+
if (this._refPreviewWatcher && this._refPreviewWatcher.inputEl === inputEl) return;
|
|
1098
|
+
this._stopReferencePreviewWatcher();
|
|
1099
|
+
const tick = () => {
|
|
1100
|
+
if (!this._refPreviewWatcher || this._refPreviewWatcher.inputEl !== inputEl) return;
|
|
1101
|
+
if (SchemaForm.__activeRefInput !== inputEl) {
|
|
1102
|
+
this._stopReferencePreviewWatcher();
|
|
1103
|
+
return;
|
|
1104
|
+
}
|
|
1105
|
+
try { this._syncActiveReferenceSelectionPreview(inputEl, def); } catch (_) { }
|
|
1106
|
+
this._refPreviewWatcher.timer = setTimeout(tick, 300);
|
|
1107
|
+
};
|
|
1108
|
+
this._refPreviewWatcher = { inputEl, timer: null };
|
|
1109
|
+
inputEl.__refPreviewCleanup = () => {
|
|
1110
|
+
try { this._stopReferencePreviewWatcher(); } catch (_) { }
|
|
1111
|
+
try { this._removeReferencePreviewGroup(inputEl); } catch (_) { }
|
|
1112
|
+
};
|
|
1113
|
+
tick();
|
|
1114
|
+
}
|
|
1115
|
+
|
|
1116
|
+
_stopReferencePreviewWatcher() {
|
|
1117
|
+
if (!this._refPreviewWatcher) return;
|
|
1118
|
+
const timer = this._refPreviewWatcher.timer;
|
|
1119
|
+
if (timer) {
|
|
1120
|
+
clearTimeout(timer);
|
|
1121
|
+
}
|
|
1122
|
+
this._refPreviewWatcher = null;
|
|
1123
|
+
}
|
|
1124
|
+
|
|
497
1125
|
_collectReferenceSelectionNames(inputEl, def = null) {
|
|
498
1126
|
if (!inputEl) return [];
|
|
499
1127
|
const isMulti = Boolean(def && def.multiple) || (inputEl.dataset && inputEl.dataset.multiple === 'true');
|
|
@@ -530,11 +1158,131 @@ export class SchemaForm {
|
|
|
530
1158
|
const scene = this._getReferenceSelectionScene();
|
|
531
1159
|
if (!scene) return;
|
|
532
1160
|
const names = this._collectReferenceSelectionNames(inputEl, def);
|
|
1161
|
+
try { this._seedReferencePreviewCacheFromScene(inputEl, def, names, scene); } catch (_) { }
|
|
533
1162
|
SelectionFilter.unselectAll(scene);
|
|
534
1163
|
for (const name of names) {
|
|
535
1164
|
if (!name) continue;
|
|
536
1165
|
try { SelectionFilter.selectItem(scene, name); } catch (_) { }
|
|
537
1166
|
}
|
|
1167
|
+
try { this._syncActiveReferenceSelectionPreview(inputEl, def); } catch (_) { }
|
|
1168
|
+
} catch (_) { }
|
|
1169
|
+
}
|
|
1170
|
+
|
|
1171
|
+
_ensureReferencePreviewSnapshots(inputEl, def) {
|
|
1172
|
+
try {
|
|
1173
|
+
if (!inputEl) return;
|
|
1174
|
+
if (inputEl.__refPreviewBackfillPromise) return;
|
|
1175
|
+
const names = this._collectReferenceSelectionNames(inputEl, def);
|
|
1176
|
+
if (!names.length) return;
|
|
1177
|
+
const store = this._getReferencePreviewPersistentBucket(inputEl);
|
|
1178
|
+
let missing = false;
|
|
1179
|
+
if (!store) missing = true;
|
|
1180
|
+
if (!missing) {
|
|
1181
|
+
for (const name of names) {
|
|
1182
|
+
const snap = store ? store[name] : null;
|
|
1183
|
+
const type = String(snap?.type || '').toUpperCase();
|
|
1184
|
+
if (!snap) { missing = true; break; }
|
|
1185
|
+
if (type === 'EDGE') {
|
|
1186
|
+
if (!Array.isArray(snap.positions) || snap.positions.length < 6) { missing = true; break; }
|
|
1187
|
+
} else if (type === 'VERTEX') {
|
|
1188
|
+
if (!Array.isArray(snap.position) || snap.position.length < 3) { missing = true; break; }
|
|
1189
|
+
} else if (type === 'FACE' || type === 'PLANE') {
|
|
1190
|
+
if (!Array.isArray(snap.edgePositions) || snap.edgePositions.length === 0) { missing = true; break; }
|
|
1191
|
+
} else {
|
|
1192
|
+
missing = true;
|
|
1193
|
+
break;
|
|
1194
|
+
}
|
|
1195
|
+
}
|
|
1196
|
+
}
|
|
1197
|
+
if (!missing) return;
|
|
1198
|
+
|
|
1199
|
+
const partHistory = this.options?.partHistory || this.options?.viewer?.partHistory || null;
|
|
1200
|
+
if (!partHistory || typeof partHistory.runHistory !== 'function') return;
|
|
1201
|
+
|
|
1202
|
+
const prevStep = partHistory.currentHistoryStepId;
|
|
1203
|
+
const featureId = this.params?.id ?? this.params?.featureID ?? this.params?.featureId ?? null;
|
|
1204
|
+
if (featureId != null) {
|
|
1205
|
+
try { partHistory.currentHistoryStepId = String(featureId); } catch (_) { }
|
|
1206
|
+
}
|
|
1207
|
+
inputEl.__refPreviewBackfillPromise = Promise.resolve()
|
|
1208
|
+
.then(() => partHistory.runHistory())
|
|
1209
|
+
.catch(() => { /* ignore */ })
|
|
1210
|
+
.then(() => {
|
|
1211
|
+
if (featureId != null) {
|
|
1212
|
+
try { partHistory.currentHistoryStepId = prevStep; } catch (_) { }
|
|
1213
|
+
}
|
|
1214
|
+
})
|
|
1215
|
+
.then(() => {
|
|
1216
|
+
inputEl.__refPreviewBackfillPromise = null;
|
|
1217
|
+
if (SchemaForm.__activeRefInput !== inputEl) return;
|
|
1218
|
+
const scene = this._getReferenceSelectionScene();
|
|
1219
|
+
const latest = this._collectReferenceSelectionNames(inputEl, def);
|
|
1220
|
+
try { this._seedReferencePreviewCacheFromScene(inputEl, def, latest, scene); } catch (_) { }
|
|
1221
|
+
try { this._syncActiveReferenceSelectionPreview(inputEl, def); } catch (_) { }
|
|
1222
|
+
})
|
|
1223
|
+
.finally(() => {
|
|
1224
|
+
inputEl.__refPreviewBackfillPromise = null;
|
|
1225
|
+
});
|
|
1226
|
+
} catch (_) { }
|
|
1227
|
+
}
|
|
1228
|
+
|
|
1229
|
+
_hoverReferenceSelectionItem(inputEl, def, name) {
|
|
1230
|
+
try {
|
|
1231
|
+
if (!inputEl) return;
|
|
1232
|
+
const activeInput = SchemaForm.__activeRefInput || null;
|
|
1233
|
+
if (activeInput !== inputEl) {
|
|
1234
|
+
const wrap = inputEl.closest?.('.ref-active') || null;
|
|
1235
|
+
if (!wrap) return;
|
|
1236
|
+
}
|
|
1237
|
+
const normalized = normalizeReferenceName(name);
|
|
1238
|
+
if (!normalized) return;
|
|
1239
|
+
const scene = this._getReferenceSelectionScene();
|
|
1240
|
+
if (!scene) return;
|
|
1241
|
+
try { console.log('[ReferenceSelection] Hover', { name: normalized }); } catch (_) { }
|
|
1242
|
+
try { this._ensureReferencePreviewSnapshots(inputEl, def); } catch (_) { }
|
|
1243
|
+
try { this._seedReferencePreviewCacheFromScene(inputEl, def, [normalized], scene); } catch (_) { }
|
|
1244
|
+
try { this._syncActiveReferenceSelectionPreview(inputEl, def); } catch (_) { }
|
|
1245
|
+
|
|
1246
|
+
let target = null;
|
|
1247
|
+
try { target = scene.getObjectByName(normalized); } catch (_) { target = null; }
|
|
1248
|
+
if (!target) {
|
|
1249
|
+
const cache = this._getReferencePreviewCache(inputEl);
|
|
1250
|
+
const entry = cache ? cache.get(normalized) : null;
|
|
1251
|
+
target = entry?.object || entry || null;
|
|
1252
|
+
}
|
|
1253
|
+
if (!target) {
|
|
1254
|
+
try { target = scene.getObjectByName(`__refPreview__${normalized}`); } catch (_) { target = null; }
|
|
1255
|
+
}
|
|
1256
|
+
if (!target) return;
|
|
1257
|
+
if (!target.material && target.traverse) {
|
|
1258
|
+
let candidate = null;
|
|
1259
|
+
try {
|
|
1260
|
+
target.traverse((child) => {
|
|
1261
|
+
if (!child || candidate) return;
|
|
1262
|
+
if (child.type === 'REF_PREVIEW_EDGE') { candidate = child; return; }
|
|
1263
|
+
if (child.material) candidate = child;
|
|
1264
|
+
});
|
|
1265
|
+
} catch (_) { }
|
|
1266
|
+
if (candidate) target = candidate;
|
|
1267
|
+
}
|
|
1268
|
+
try {
|
|
1269
|
+
console.log('[ReferenceSelection] Hover target', {
|
|
1270
|
+
name: normalized,
|
|
1271
|
+
target: target || null,
|
|
1272
|
+
inScene: !!(target && target.parent),
|
|
1273
|
+
});
|
|
1274
|
+
} catch (_) { }
|
|
1275
|
+
inputEl.__refChipHoverActive = true;
|
|
1276
|
+
try { SelectionFilter.setHoverObject(target, { ignoreFilter: true }); } catch (_) { }
|
|
1277
|
+
} catch (_) { }
|
|
1278
|
+
}
|
|
1279
|
+
|
|
1280
|
+
_clearReferenceSelectionHover(inputEl) {
|
|
1281
|
+
try {
|
|
1282
|
+
if (!inputEl || SchemaForm.__activeRefInput !== inputEl) return;
|
|
1283
|
+
if (!inputEl.__refChipHoverActive) return;
|
|
1284
|
+
inputEl.__refChipHoverActive = false;
|
|
1285
|
+
SelectionFilter.clearHover();
|
|
538
1286
|
} catch (_) { }
|
|
539
1287
|
}
|
|
540
1288
|
|
|
@@ -581,8 +1329,38 @@ export class SchemaForm {
|
|
|
581
1329
|
SelectionFilter.SetSelectionTypes(def.selectionFilter);
|
|
582
1330
|
try { window.__BREP_activeRefInput = inputEl; } catch (_) { }
|
|
583
1331
|
|
|
1332
|
+
// Log current selected objects for this reference field on activation
|
|
1333
|
+
try {
|
|
1334
|
+
const scene = this._getReferenceSelectionScene();
|
|
1335
|
+
const names = this._collectReferenceSelectionNames(inputEl, def);
|
|
1336
|
+
const keyLabel = inputEl?.dataset?.key ? ` (${inputEl.dataset.key})` : '';
|
|
1337
|
+
if (!names.length) {
|
|
1338
|
+
console.log(`[ReferenceSelection] Activated${keyLabel}: no selections`);
|
|
1339
|
+
} else {
|
|
1340
|
+
const cache = this._getReferencePreviewCache(inputEl);
|
|
1341
|
+
for (const name of names) {
|
|
1342
|
+
if (!name) continue;
|
|
1343
|
+
const obj = scene ? scene.getObjectByName(name) : null;
|
|
1344
|
+
const cached = cache ? cache.get(name) : null;
|
|
1345
|
+
const cachedObj = cached && cached.object ? cached.object : null;
|
|
1346
|
+
console.log(`[ReferenceSelection] Selected${keyLabel}: ${name}`, {
|
|
1347
|
+
object: obj || cachedObj || null,
|
|
1348
|
+
inScene: !!obj,
|
|
1349
|
+
cached: !!cachedObj,
|
|
1350
|
+
});
|
|
1351
|
+
}
|
|
1352
|
+
}
|
|
1353
|
+
} catch (_) { }
|
|
1354
|
+
|
|
584
1355
|
// Highlight existing selections while this reference field is active
|
|
585
1356
|
try { this._syncActiveReferenceSelectionHighlight(inputEl, def); } catch (_) { }
|
|
1357
|
+
try { this._ensureReferencePreviewSnapshots(inputEl, def); } catch (_) { }
|
|
1358
|
+
try {
|
|
1359
|
+
if (typeof inputEl.__captureReferencePreview !== 'function') {
|
|
1360
|
+
inputEl.__captureReferencePreview = (obj) => this._storeReferencePreviewSnapshot(inputEl, def, obj);
|
|
1361
|
+
}
|
|
1362
|
+
} catch (_) { }
|
|
1363
|
+
try { this._startReferencePreviewWatcher(inputEl, def); } catch (_) { }
|
|
586
1364
|
}
|
|
587
1365
|
|
|
588
1366
|
// Activate a TransformControls session for a transform widget
|
|
@@ -1044,17 +1822,25 @@ export class SchemaForm {
|
|
|
1044
1822
|
|
|
1045
1823
|
_stopActiveReferenceSelection() {
|
|
1046
1824
|
// Clear global active if it belongs to this instance
|
|
1825
|
+
const activeInput = SchemaForm.__activeRefInput || null;
|
|
1047
1826
|
try {
|
|
1048
|
-
if (
|
|
1049
|
-
try {
|
|
1050
|
-
try {
|
|
1827
|
+
if (activeInput) {
|
|
1828
|
+
try { activeInput.style.filter = 'none'; } catch (_) { }
|
|
1829
|
+
try { activeInput.removeAttribute('active-reference-selection'); } catch (_) { }
|
|
1051
1830
|
try {
|
|
1052
|
-
const wrap =
|
|
1831
|
+
const wrap = activeInput.closest('.ref-single-wrap, .ref-multi-wrap');
|
|
1053
1832
|
if (wrap) wrap.classList.remove('ref-active');
|
|
1054
1833
|
} catch (_) { }
|
|
1055
1834
|
}
|
|
1056
1835
|
} catch (_) { }
|
|
1057
|
-
const hadActive = !!
|
|
1836
|
+
const hadActive = !!activeInput;
|
|
1837
|
+
try {
|
|
1838
|
+
if (activeInput && typeof activeInput.__refPreviewCleanup === 'function') {
|
|
1839
|
+
activeInput.__refPreviewCleanup();
|
|
1840
|
+
} else if (activeInput) {
|
|
1841
|
+
this._removeReferencePreviewGroup(activeInput);
|
|
1842
|
+
}
|
|
1843
|
+
} catch (_) { }
|
|
1058
1844
|
SchemaForm.__activeRefInput = null;
|
|
1059
1845
|
try { if (window.__BREP_activeRefInput === undefined || window.__BREP_activeRefInput === SchemaForm.__activeRefInput) window.__BREP_activeRefInput = null; } catch (_) { }
|
|
1060
1846
|
if (hadActive) {
|
|
@@ -1070,7 +1856,41 @@ export class SchemaForm {
|
|
|
1070
1856
|
chipsWrap.textContent = '';
|
|
1071
1857
|
const arr = Array.isArray(values) ? values : [];
|
|
1072
1858
|
const normalizedValues = normalizeReferenceList(arr);
|
|
1073
|
-
|
|
1859
|
+
let inputEl = (this._inputs && typeof this._inputs.get === 'function') ? this._inputs.get(key) : null;
|
|
1860
|
+
const resolveInput = () => {
|
|
1861
|
+
if (inputEl) return inputEl;
|
|
1862
|
+
const wrap = chipsWrap?.closest?.('.ref-multi-wrap, .ref-single-wrap') || null;
|
|
1863
|
+
const hidden = wrap ? wrap.querySelector('input[type="hidden"]') : null;
|
|
1864
|
+
if (hidden) inputEl = hidden;
|
|
1865
|
+
return inputEl;
|
|
1866
|
+
};
|
|
1867
|
+
const resolveDef = () => {
|
|
1868
|
+
const el = resolveInput();
|
|
1869
|
+
return (el && el.__refSelectionDef) || (this.schema ? (this.schema[key] || null) : null);
|
|
1870
|
+
};
|
|
1871
|
+
const def = resolveDef();
|
|
1872
|
+
if (chipsWrap && !chipsWrap.__refHoverBound) {
|
|
1873
|
+
chipsWrap.__refHoverBound = true;
|
|
1874
|
+
chipsWrap.__refHoverName = null;
|
|
1875
|
+
chipsWrap.addEventListener('mousemove', (ev) => {
|
|
1876
|
+
try {
|
|
1877
|
+
const chip = ev.target?.closest?.('.ref-chip');
|
|
1878
|
+
const refName = chip?.dataset?.refName || null;
|
|
1879
|
+
if (!refName) {
|
|
1880
|
+
chipsWrap.__refHoverName = null;
|
|
1881
|
+
this._clearReferenceSelectionHover(resolveInput());
|
|
1882
|
+
return;
|
|
1883
|
+
}
|
|
1884
|
+
if (chipsWrap.__refHoverName === refName) return;
|
|
1885
|
+
chipsWrap.__refHoverName = refName;
|
|
1886
|
+
this._hoverReferenceSelectionItem(resolveInput(), resolveDef(), refName);
|
|
1887
|
+
} catch (_) { }
|
|
1888
|
+
});
|
|
1889
|
+
chipsWrap.addEventListener('mouseleave', () => {
|
|
1890
|
+
chipsWrap.__refHoverName = null;
|
|
1891
|
+
this._clearReferenceSelectionHover(resolveInput());
|
|
1892
|
+
});
|
|
1893
|
+
}
|
|
1074
1894
|
if (inputEl) {
|
|
1075
1895
|
if (typeof inputEl.__updateSelectionMetadata === 'function') {
|
|
1076
1896
|
try { inputEl.__updateSelectionMetadata(normalizedValues); } catch (_) { }
|
|
@@ -1087,6 +1907,7 @@ export class SchemaForm {
|
|
|
1087
1907
|
for (const name of normalizedValues) {
|
|
1088
1908
|
const chip = document.createElement('span');
|
|
1089
1909
|
chip.className = 'ref-chip';
|
|
1910
|
+
try { chip.dataset.refName = name; } catch (_) { }
|
|
1090
1911
|
|
|
1091
1912
|
const label = document.createElement('span');
|
|
1092
1913
|
label.className = 'ref-chip-label';
|
|
@@ -1095,9 +1916,21 @@ export class SchemaForm {
|
|
|
1095
1916
|
|
|
1096
1917
|
// Hover highlight on chip hover
|
|
1097
1918
|
chip.addEventListener('mouseenter', () => {
|
|
1919
|
+
const liveInput = resolveInput();
|
|
1920
|
+
const liveDef = resolveDef();
|
|
1921
|
+
if (liveDef && liveDef.type === 'reference_selection') {
|
|
1922
|
+
this._hoverReferenceSelectionItem(liveInput, liveDef, name);
|
|
1923
|
+
return;
|
|
1924
|
+
}
|
|
1098
1925
|
try { SelectionFilter.setHoverByName(this.options?.scene || null, name); } catch (_) { }
|
|
1099
1926
|
});
|
|
1100
1927
|
chip.addEventListener('mouseleave', () => {
|
|
1928
|
+
const liveInput = resolveInput();
|
|
1929
|
+
const liveDef = resolveDef();
|
|
1930
|
+
if (liveDef && liveDef.type === 'reference_selection') {
|
|
1931
|
+
this._clearReferenceSelectionHover(liveInput);
|
|
1932
|
+
return;
|
|
1933
|
+
}
|
|
1101
1934
|
try { SelectionFilter.clearHover(); } catch (_) { }
|
|
1102
1935
|
});
|
|
1103
1936
|
|
|
@@ -1158,7 +1991,7 @@ export class SchemaForm {
|
|
|
1158
1991
|
|
|
1159
1992
|
try {
|
|
1160
1993
|
if (inputEl && inputEl === SchemaForm.__activeRefInput) {
|
|
1161
|
-
const def = this.schema ? (this.schema[key] || {}) : null;
|
|
1994
|
+
const def = (inputEl && inputEl.__refSelectionDef) || (this.schema ? (this.schema[key] || {}) : null);
|
|
1162
1995
|
this._syncActiveReferenceSelectionHighlight(inputEl, def);
|
|
1163
1996
|
}
|
|
1164
1997
|
} catch (_) { }
|