brep-io-kernel 1.0.21 → 1.0.22
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 +4 -1
- package/dist-kernel/brep-kernel.js +11065 -10512
- package/package.json +3 -2
- package/src/BREP/Edge.js +2 -0
- package/src/BREP/Face.js +2 -0
- package/src/BREP/SolidMethods/visualize.js +372 -365
- package/src/BREP/Vertex.js +2 -17
- package/src/PartHistory.js +4 -25
- package/src/SketchSolver2D.js +3 -0
- package/src/UI/AccordionWidget.js +1 -1
- package/src/UI/EnvMonacoEditor.js +0 -3
- package/src/UI/HistoryWidget.js +3 -0
- package/src/UI/SceneListing.js +45 -7
- package/src/UI/SelectionFilter.js +469 -442
- package/src/UI/SelectionState.js +464 -0
- package/src/UI/assembly/AssemblyConstraintCollectionWidget.js +40 -1
- package/src/UI/assembly/AssemblyConstraintsWidget.js +17 -3
- package/src/UI/assembly/constraintSelectionUtils.js +3 -182
- package/src/UI/{assembly/constraintFaceUtils.js → faceUtils.js} +30 -5
- package/src/UI/featureDialogs.js +99 -69
- package/src/UI/pmi/LabelOverlay.js +32 -0
- package/src/UI/pmi/PMIMode.js +23 -0
- package/src/UI/pmi/dimensions/HoleCalloutAnnotation.js +7 -1
- package/src/UI/toolbarButtons/orientToFaceButton.js +3 -36
- package/src/UI/toolbarButtons/registerDefaultButtons.js +2 -0
- package/src/UI/toolbarButtons/selectionStateButton.js +206 -0
- package/src/UI/viewer.js +16 -16
- package/src/assemblyConstraints/AssemblyConstraintHistory.js +18 -42
- package/src/assemblyConstraints/constraints/AngleConstraint.js +1 -0
- package/src/assemblyConstraints/constraints/DistanceConstraint.js +1 -0
- package/src/features/selectionUtils.js +21 -5
- package/src/features/sketch/SketchFeature.js +2 -2
- package/src/features/sketch/sketchSolver2D/constraintDefinitions.js +3 -2
- package/src/utils/selectionResolver.js +258 -0
package/src/BREP/Vertex.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import * as THREE from "three";
|
|
2
2
|
import { CADmaterials } from "../UI/CADmaterials.js";
|
|
3
|
+
import { SelectionState } from "../UI/SelectionState.js";
|
|
3
4
|
|
|
4
5
|
// Vertex: container at a specific position with a point marker.
|
|
5
6
|
// When selected, swaps to the selected PointsMaterial; no extra sphere.
|
|
@@ -22,22 +23,6 @@ export class Vertex extends THREE.Object3D {
|
|
|
22
23
|
this._point = new THREE.Points(ptGeom, ptMat);
|
|
23
24
|
this.add(this._point);
|
|
24
25
|
|
|
25
|
-
|
|
26
|
-
this._selected = false;
|
|
27
|
-
Object.defineProperty(this, 'selected', {
|
|
28
|
-
get: () => this._selected,
|
|
29
|
-
set: (v) => {
|
|
30
|
-
const nv = !!v;
|
|
31
|
-
this._selected = nv;
|
|
32
|
-
try {
|
|
33
|
-
if (this._point && this._point.material && CADmaterials?.VERTEX) {
|
|
34
|
-
this._point.material = nv ? (CADmaterials.VERTEX.SELECTED || this._point.material)
|
|
35
|
-
: (CADmaterials.VERTEX.BASE || this._point.material);
|
|
36
|
-
}
|
|
37
|
-
} catch { }
|
|
38
|
-
},
|
|
39
|
-
configurable: true,
|
|
40
|
-
enumerable: true,
|
|
41
|
-
});
|
|
26
|
+
SelectionState.attach(this);
|
|
42
27
|
}
|
|
43
28
|
}
|
package/src/PartHistory.js
CHANGED
|
@@ -572,11 +572,12 @@ export class PartHistory {
|
|
|
572
572
|
const objType = String(obj.type || '').toUpperCase();
|
|
573
573
|
const sourceUuid = obj.uuid || null;
|
|
574
574
|
const sourceFeatureId = obj.owningFeatureID ?? null;
|
|
575
|
+
const sourceTimestamp = (obj.timestamp ?? obj.userData?.timestamp ?? null);
|
|
575
576
|
if (objType === SelectionFilter.EDGE || objType === 'EDGE') {
|
|
576
577
|
const positions = extractEdgeWorldPositions(obj);
|
|
577
578
|
if (positions && positions.length >= 6) {
|
|
578
579
|
for (const bucket of buckets) {
|
|
579
|
-
bucket[refName] = { type: 'EDGE', positions, sourceUuid, sourceFeatureId };
|
|
580
|
+
bucket[refName] = { type: 'EDGE', positions, sourceUuid, sourceFeatureId, sourceTimestamp };
|
|
580
581
|
}
|
|
581
582
|
}
|
|
582
583
|
} else if (objType === SelectionFilter.FACE || objType === 'FACE' || objType === SelectionFilter.PLANE || objType === 'PLANE') {
|
|
@@ -584,7 +585,7 @@ export class PartHistory {
|
|
|
584
585
|
if (edgePositions && edgePositions.length) {
|
|
585
586
|
const snapType = (objType === SelectionFilter.PLANE || objType === 'PLANE') ? 'PLANE' : 'FACE';
|
|
586
587
|
for (const bucket of buckets) {
|
|
587
|
-
bucket[refName] = { type: snapType, edgePositions, sourceUuid, sourceFeatureId };
|
|
588
|
+
bucket[refName] = { type: snapType, edgePositions, sourceUuid, sourceFeatureId, sourceTimestamp };
|
|
588
589
|
}
|
|
589
590
|
}
|
|
590
591
|
} else if (objType === SelectionFilter.VERTEX || objType === 'VERTEX') {
|
|
@@ -594,7 +595,7 @@ export class PartHistory {
|
|
|
594
595
|
else pos.set(obj.position?.x || 0, obj.position?.y || 0, obj.position?.z || 0);
|
|
595
596
|
} catch { }
|
|
596
597
|
for (const bucket of buckets) {
|
|
597
|
-
bucket[refName] = { type: 'VERTEX', position: [pos.x, pos.y, pos.z], sourceUuid, sourceFeatureId };
|
|
598
|
+
bucket[refName] = { type: 'VERTEX', position: [pos.x, pos.y, pos.z], sourceUuid, sourceFeatureId, sourceTimestamp };
|
|
598
599
|
}
|
|
599
600
|
}
|
|
600
601
|
}
|
|
@@ -662,7 +663,6 @@ export class PartHistory {
|
|
|
662
663
|
applyTimeStampToChildrenRecursively(a, feature.timestamp);
|
|
663
664
|
} catch { }
|
|
664
665
|
|
|
665
|
-
this._attachSelectionHandlers(a);
|
|
666
666
|
}
|
|
667
667
|
}
|
|
668
668
|
|
|
@@ -677,27 +677,6 @@ export class PartHistory {
|
|
|
677
677
|
|
|
678
678
|
|
|
679
679
|
|
|
680
|
-
_attachSelectionHandlers(obj) {
|
|
681
|
-
if (!obj || typeof obj !== 'object') return;
|
|
682
|
-
obj.onClick = () => {
|
|
683
|
-
try {
|
|
684
|
-
if (obj.type === SelectionFilter.SOLID && obj.parent && obj.parent.type === SelectionFilter.COMPONENT) {
|
|
685
|
-
const handledByParent = SelectionFilter.toggleSelection(obj.parent);
|
|
686
|
-
if (!handledByParent) SelectionFilter.toggleSelection(obj);
|
|
687
|
-
return;
|
|
688
|
-
}
|
|
689
|
-
SelectionFilter.toggleSelection(obj);
|
|
690
|
-
} catch (error) {
|
|
691
|
-
try { console.warn('[PartHistory] toggleSelection failed:', error); }
|
|
692
|
-
catch (_) { /* no-op */ }
|
|
693
|
-
}
|
|
694
|
-
};
|
|
695
|
-
const children = Array.isArray(obj.children) ? obj.children : [];
|
|
696
|
-
for (const child of children) {
|
|
697
|
-
this._attachSelectionHandlers(child);
|
|
698
|
-
}
|
|
699
|
-
}
|
|
700
|
-
|
|
701
680
|
_safeRemove(obj) {
|
|
702
681
|
if (!obj) return;
|
|
703
682
|
try {
|
package/src/UI/HistoryWidget.js
CHANGED
|
@@ -386,6 +386,9 @@ export class HistoryWidget extends HistoryCollectionWidget {
|
|
|
386
386
|
if (this._extractEntryId(entry, i) !== String(target)) continue;
|
|
387
387
|
if (!this.#shouldExpandEntry(entry)) return;
|
|
388
388
|
this._expandedId = String(target);
|
|
389
|
+
if (this._autoFocusOnExpand) {
|
|
390
|
+
this._pendingFocusEntryId = String(target);
|
|
391
|
+
}
|
|
389
392
|
this.render();
|
|
390
393
|
return;
|
|
391
394
|
}
|
package/src/UI/SceneListing.js
CHANGED
|
@@ -38,11 +38,14 @@ export class SceneListing {
|
|
|
38
38
|
this._expandedByName = new Map(); // name -> boolean
|
|
39
39
|
// Remember expand/collapse state for non-solid nodes when showing all objects
|
|
40
40
|
this._expandedByUuid = new Map(); // uuid -> boolean
|
|
41
|
+
this._hoveredUuids = new Set();
|
|
41
42
|
this._running = false;
|
|
42
43
|
this._raf = 0;
|
|
43
44
|
|
|
44
45
|
this.#attachTypeVisibilityButtons();
|
|
45
46
|
this.#attachDisplayModeToggle();
|
|
47
|
+
this._hoverListener = (ev) => this.#syncHoverFromScene(ev);
|
|
48
|
+
window.addEventListener('hover-changed', this._hoverListener);
|
|
46
49
|
|
|
47
50
|
// Wire toolbar
|
|
48
51
|
// this.toolbar.querySelector(".st-expand").addEventListener("click", () => this.#setAllOpen(true));
|
|
@@ -99,6 +102,10 @@ export class SceneListing {
|
|
|
99
102
|
dispose() {
|
|
100
103
|
this.stop();
|
|
101
104
|
this.clear();
|
|
105
|
+
if (this._hoverListener) {
|
|
106
|
+
try { window.removeEventListener('hover-changed', this._hoverListener); } catch { }
|
|
107
|
+
this._hoverListener = null;
|
|
108
|
+
}
|
|
102
109
|
this.uiElement.remove();
|
|
103
110
|
}
|
|
104
111
|
|
|
@@ -228,6 +235,13 @@ export class SceneListing {
|
|
|
228
235
|
e.stopPropagation();
|
|
229
236
|
});
|
|
230
237
|
|
|
238
|
+
const hoverOn = () => {
|
|
239
|
+
try { SelectionFilter.setHoverObject(obj, { ignoreFilter: true }); } catch (_) { }
|
|
240
|
+
};
|
|
241
|
+
const hoverOff = () => {
|
|
242
|
+
try { SelectionFilter.clearHover(); } catch (_) { }
|
|
243
|
+
};
|
|
244
|
+
|
|
231
245
|
// Selection: name click -> recursive toggle selection (unchanged)
|
|
232
246
|
nameBtn.addEventListener("click", (e) => {
|
|
233
247
|
// If any descendant (including self) is not selected, select all; otherwise deselect all.
|
|
@@ -243,13 +257,9 @@ export class SceneListing {
|
|
|
243
257
|
e.stopPropagation();
|
|
244
258
|
});
|
|
245
259
|
|
|
246
|
-
// Hover highlight
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
});
|
|
250
|
-
nameBtn.addEventListener('mouseleave', () => {
|
|
251
|
-
try { SelectionFilter.clearHover(); } catch (_) { }
|
|
252
|
-
});
|
|
260
|
+
// Hover highlight for the full row (ignore selection filter)
|
|
261
|
+
row.addEventListener('pointerenter', hoverOn);
|
|
262
|
+
row.addEventListener('pointerleave', hoverOff);
|
|
253
263
|
|
|
254
264
|
// Row assembly
|
|
255
265
|
row.appendChild(toggle);
|
|
@@ -300,6 +310,8 @@ export class SceneListing {
|
|
|
300
310
|
info.lastSelected = sel;
|
|
301
311
|
info.li.classList.toggle("is-selected", sel);
|
|
302
312
|
}
|
|
313
|
+
const hovered = this._hoveredUuids.has(obj.uuid);
|
|
314
|
+
info.li.classList.toggle("is-hovered", hovered);
|
|
303
315
|
|
|
304
316
|
// Keep label fresh (names may change externally)
|
|
305
317
|
const wantLabel = this.#labelFor(obj);
|
|
@@ -310,6 +322,28 @@ export class SceneListing {
|
|
|
310
322
|
}
|
|
311
323
|
}
|
|
312
324
|
|
|
325
|
+
#syncHoverFromScene(ev) {
|
|
326
|
+
const detail = ev?.detail || {};
|
|
327
|
+
let uuids = [];
|
|
328
|
+
if (Array.isArray(detail.uuids) && detail.uuids.length) {
|
|
329
|
+
uuids = detail.uuids;
|
|
330
|
+
} else if (Array.isArray(detail.objects)) {
|
|
331
|
+
uuids = detail.objects.map((obj) => obj?.uuid).filter(Boolean);
|
|
332
|
+
}
|
|
333
|
+
const next = new Set(uuids);
|
|
334
|
+
for (const uuid of this._hoveredUuids) {
|
|
335
|
+
if (next.has(uuid)) continue;
|
|
336
|
+
const info = this.nodes.get(uuid);
|
|
337
|
+
if (info) info.li.classList.remove('is-hovered');
|
|
338
|
+
}
|
|
339
|
+
for (const uuid of next) {
|
|
340
|
+
if (this._hoveredUuids.has(uuid)) continue;
|
|
341
|
+
const info = this.nodes.get(uuid);
|
|
342
|
+
if (info) info.li.classList.add('is-hovered');
|
|
343
|
+
}
|
|
344
|
+
this._hoveredUuids = next;
|
|
345
|
+
}
|
|
346
|
+
|
|
313
347
|
// ---- Actions --------------------------------------------------------------
|
|
314
348
|
|
|
315
349
|
#setSelectedRecursive(obj, sel) {
|
|
@@ -568,6 +602,10 @@ export class SceneListing {
|
|
|
568
602
|
background: var(--sel);
|
|
569
603
|
box-shadow: inset 0 0 0 1px var(--accent);
|
|
570
604
|
}
|
|
605
|
+
.scene-tree__item.is-hovered > .scene-tree__row{
|
|
606
|
+
background: #142033;
|
|
607
|
+
box-shadow: inset 0 0 0 1px rgba(74,163,255,.45);
|
|
608
|
+
}
|
|
571
609
|
.scene-tree__item.is-parent.open > .scene-tree__row{ border-bottom:1px solid #111a26; }
|
|
572
610
|
.st-caret{
|
|
573
611
|
width:20px; height:20px; border:0; background:transparent; color:var(--muted);
|