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.
Files changed (34) hide show
  1. package/README.md +4 -1
  2. package/dist-kernel/brep-kernel.js +11065 -10512
  3. package/package.json +3 -2
  4. package/src/BREP/Edge.js +2 -0
  5. package/src/BREP/Face.js +2 -0
  6. package/src/BREP/SolidMethods/visualize.js +372 -365
  7. package/src/BREP/Vertex.js +2 -17
  8. package/src/PartHistory.js +4 -25
  9. package/src/SketchSolver2D.js +3 -0
  10. package/src/UI/AccordionWidget.js +1 -1
  11. package/src/UI/EnvMonacoEditor.js +0 -3
  12. package/src/UI/HistoryWidget.js +3 -0
  13. package/src/UI/SceneListing.js +45 -7
  14. package/src/UI/SelectionFilter.js +469 -442
  15. package/src/UI/SelectionState.js +464 -0
  16. package/src/UI/assembly/AssemblyConstraintCollectionWidget.js +40 -1
  17. package/src/UI/assembly/AssemblyConstraintsWidget.js +17 -3
  18. package/src/UI/assembly/constraintSelectionUtils.js +3 -182
  19. package/src/UI/{assembly/constraintFaceUtils.js → faceUtils.js} +30 -5
  20. package/src/UI/featureDialogs.js +99 -69
  21. package/src/UI/pmi/LabelOverlay.js +32 -0
  22. package/src/UI/pmi/PMIMode.js +23 -0
  23. package/src/UI/pmi/dimensions/HoleCalloutAnnotation.js +7 -1
  24. package/src/UI/toolbarButtons/orientToFaceButton.js +3 -36
  25. package/src/UI/toolbarButtons/registerDefaultButtons.js +2 -0
  26. package/src/UI/toolbarButtons/selectionStateButton.js +206 -0
  27. package/src/UI/viewer.js +16 -16
  28. package/src/assemblyConstraints/AssemblyConstraintHistory.js +18 -42
  29. package/src/assemblyConstraints/constraints/AngleConstraint.js +1 -0
  30. package/src/assemblyConstraints/constraints/DistanceConstraint.js +1 -0
  31. package/src/features/selectionUtils.js +21 -5
  32. package/src/features/sketch/SketchFeature.js +2 -2
  33. package/src/features/sketch/sketchSolver2D/constraintDefinitions.js +3 -2
  34. package/src/utils/selectionResolver.js +258 -0
@@ -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
- // Selection flag accessor toggles point material
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
  }
@@ -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 {
@@ -0,0 +1,3 @@
1
+ // Standalone 2D sketch solver entry point
2
+ export { ConstraintSolver, ConstraintEngine } from './features/sketch/sketchSolver2D/ConstraintEngine.js';
3
+ export { constraints } from './features/sketch/sketchSolver2D/constraintDefinitions.js';
@@ -2,7 +2,7 @@
2
2
  // ES6, framework-free, dark mode, no animations.
3
3
  // All public methods are async and resolve AFTER the DOM has painted.
4
4
 
5
- export class AccordionSection {
5
+ class AccordionSection {
6
6
  /**
7
7
  * Represents a single accordion section.
8
8
  * Properties:
@@ -517,6 +517,3 @@ EnvMonacoEditor._runtimeCompletionRegistered = false;
517
517
  if (!customElements.get('env-monaco-editor')) {
518
518
  customElements.define('env-monaco-editor', EnvMonacoEditor);
519
519
  }
520
-
521
- export { EnvMonacoEditor };
522
- export default EnvMonacoEditor;
@@ -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
  }
@@ -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 respecting selection filter
247
- nameBtn.addEventListener('mouseenter', () => {
248
- try { SelectionFilter.setHoverByName(this.scene, obj.name); } catch (_) { }
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);