brep-io-kernel 1.0.0-ci.10
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/LICENSE.md +32 -0
- package/README.md +157 -0
- package/dist-kernel/brep-kernel.js +74699 -0
- package/package.json +58 -0
- package/src/BREP/AssemblyComponent.js +42 -0
- package/src/BREP/BREP.js +43 -0
- package/src/BREP/BetterSolid.js +805 -0
- package/src/BREP/Edge.js +103 -0
- package/src/BREP/Extrude.js +403 -0
- package/src/BREP/Face.js +187 -0
- package/src/BREP/MeshRepairer.js +634 -0
- package/src/BREP/OffsetShellSolid.js +614 -0
- package/src/BREP/PointCloudWrap.js +302 -0
- package/src/BREP/Revolve.js +345 -0
- package/src/BREP/SolidMethods/authoring.js +112 -0
- package/src/BREP/SolidMethods/booleanOps.js +230 -0
- package/src/BREP/SolidMethods/chamfer.js +122 -0
- package/src/BREP/SolidMethods/edgeResolution.js +25 -0
- package/src/BREP/SolidMethods/fillet.js +792 -0
- package/src/BREP/SolidMethods/index.js +72 -0
- package/src/BREP/SolidMethods/io.js +105 -0
- package/src/BREP/SolidMethods/lifecycle.js +103 -0
- package/src/BREP/SolidMethods/manifoldOps.js +375 -0
- package/src/BREP/SolidMethods/meshCleanup.js +2512 -0
- package/src/BREP/SolidMethods/meshQueries.js +264 -0
- package/src/BREP/SolidMethods/metadata.js +106 -0
- package/src/BREP/SolidMethods/metrics.js +51 -0
- package/src/BREP/SolidMethods/transforms.js +361 -0
- package/src/BREP/SolidMethods/visualize.js +508 -0
- package/src/BREP/SolidShared.js +26 -0
- package/src/BREP/Sweep.js +1596 -0
- package/src/BREP/Tube.js +857 -0
- package/src/BREP/Vertex.js +43 -0
- package/src/BREP/applyBooleanOperation.js +704 -0
- package/src/BREP/boundsUtils.js +48 -0
- package/src/BREP/chamfer.js +551 -0
- package/src/BREP/edgePolylineUtils.js +85 -0
- package/src/BREP/fillets/common.js +388 -0
- package/src/BREP/fillets/fillet.js +1422 -0
- package/src/BREP/fillets/filletGeometry.js +15 -0
- package/src/BREP/fillets/inset.js +389 -0
- package/src/BREP/fillets/offsetHelper.js +143 -0
- package/src/BREP/fillets/outset.js +88 -0
- package/src/BREP/helix.js +193 -0
- package/src/BREP/meshToBrep.js +234 -0
- package/src/BREP/primitives.js +279 -0
- package/src/BREP/setupManifold.js +71 -0
- package/src/BREP/threadGeometry.js +1120 -0
- package/src/BREP/triangleUtils.js +8 -0
- package/src/BREP/triangulate.js +608 -0
- package/src/FeatureRegistry.js +183 -0
- package/src/PartHistory.js +1132 -0
- package/src/UI/AccordionWidget.js +292 -0
- package/src/UI/CADmaterials.js +850 -0
- package/src/UI/EnvMonacoEditor.js +522 -0
- package/src/UI/FloatingWindow.js +396 -0
- package/src/UI/HistoryWidget.js +457 -0
- package/src/UI/MainToolbar.js +131 -0
- package/src/UI/ModelLibraryView.js +194 -0
- package/src/UI/OrthoCameraIdle.js +206 -0
- package/src/UI/PluginsWidget.js +280 -0
- package/src/UI/SceneListing.js +606 -0
- package/src/UI/SelectionFilter.js +629 -0
- package/src/UI/ViewCube.js +389 -0
- package/src/UI/assembly/AssemblyConstraintCollectionWidget.js +329 -0
- package/src/UI/assembly/AssemblyConstraintControlsWidget.js +282 -0
- package/src/UI/assembly/AssemblyConstraintsWidget.css +292 -0
- package/src/UI/assembly/AssemblyConstraintsWidget.js +1373 -0
- package/src/UI/assembly/constraintFaceUtils.js +115 -0
- package/src/UI/assembly/constraintHighlightUtils.js +70 -0
- package/src/UI/assembly/constraintLabelUtils.js +31 -0
- package/src/UI/assembly/constraintPointUtils.js +64 -0
- package/src/UI/assembly/constraintSelectionUtils.js +185 -0
- package/src/UI/assembly/constraintStatusUtils.js +142 -0
- package/src/UI/componentSelectorModal.js +240 -0
- package/src/UI/controls/CombinedTransformControls.js +386 -0
- package/src/UI/dialogs.js +351 -0
- package/src/UI/expressionsManager.js +100 -0
- package/src/UI/featureDialogWidgets/booleanField.js +25 -0
- package/src/UI/featureDialogWidgets/booleanOperationField.js +97 -0
- package/src/UI/featureDialogWidgets/buttonField.js +45 -0
- package/src/UI/featureDialogWidgets/componentSelectorField.js +102 -0
- package/src/UI/featureDialogWidgets/defaultField.js +23 -0
- package/src/UI/featureDialogWidgets/fileField.js +66 -0
- package/src/UI/featureDialogWidgets/index.js +34 -0
- package/src/UI/featureDialogWidgets/numberField.js +165 -0
- package/src/UI/featureDialogWidgets/optionsField.js +33 -0
- package/src/UI/featureDialogWidgets/referenceSelectionField.js +208 -0
- package/src/UI/featureDialogWidgets/stringField.js +24 -0
- package/src/UI/featureDialogWidgets/textareaField.js +28 -0
- package/src/UI/featureDialogWidgets/threadDesignationField.js +160 -0
- package/src/UI/featureDialogWidgets/transformField.js +252 -0
- package/src/UI/featureDialogWidgets/utils.js +43 -0
- package/src/UI/featureDialogWidgets/vec3Field.js +133 -0
- package/src/UI/featureDialogs.js +1414 -0
- package/src/UI/fileManagerWidget.js +615 -0
- package/src/UI/history/HistoryCollectionWidget.js +1294 -0
- package/src/UI/history/historyCollectionWidget.css.js +257 -0
- package/src/UI/history/historyDisplayInfo.js +133 -0
- package/src/UI/mobile.js +28 -0
- package/src/UI/objectDump.js +442 -0
- package/src/UI/pmi/AnnotationCollectionWidget.js +120 -0
- package/src/UI/pmi/AnnotationHistory.js +353 -0
- package/src/UI/pmi/AnnotationRegistry.js +90 -0
- package/src/UI/pmi/BaseAnnotation.js +269 -0
- package/src/UI/pmi/LabelOverlay.css +102 -0
- package/src/UI/pmi/LabelOverlay.js +191 -0
- package/src/UI/pmi/PMIMode.js +1550 -0
- package/src/UI/pmi/PMIViewsWidget.js +1098 -0
- package/src/UI/pmi/annUtils.js +729 -0
- package/src/UI/pmi/dimensions/AngleDimensionAnnotation.js +647 -0
- package/src/UI/pmi/dimensions/ExplodeBodyAnnotation.js +507 -0
- package/src/UI/pmi/dimensions/HoleCalloutAnnotation.js +462 -0
- package/src/UI/pmi/dimensions/LeaderAnnotation.js +403 -0
- package/src/UI/pmi/dimensions/LinearDimensionAnnotation.js +532 -0
- package/src/UI/pmi/dimensions/NoteAnnotation.js +110 -0
- package/src/UI/pmi/dimensions/RadialDimensionAnnotation.js +659 -0
- package/src/UI/pmi/pmiStyle.js +44 -0
- package/src/UI/sketcher/SketchMode3D.js +4095 -0
- package/src/UI/sketcher/dimensions.js +674 -0
- package/src/UI/sketcher/glyphs.js +236 -0
- package/src/UI/sketcher/highlights.js +60 -0
- package/src/UI/toolbarButtons/aboutButton.js +5 -0
- package/src/UI/toolbarButtons/exportButton.js +609 -0
- package/src/UI/toolbarButtons/flatPatternButton.js +307 -0
- package/src/UI/toolbarButtons/importButton.js +160 -0
- package/src/UI/toolbarButtons/inspectorToggleButton.js +12 -0
- package/src/UI/toolbarButtons/metadataButton.js +1063 -0
- package/src/UI/toolbarButtons/orientToFaceButton.js +114 -0
- package/src/UI/toolbarButtons/registerDefaultButtons.js +46 -0
- package/src/UI/toolbarButtons/saveButton.js +99 -0
- package/src/UI/toolbarButtons/scriptRunnerButton.js +302 -0
- package/src/UI/toolbarButtons/testsButton.js +26 -0
- package/src/UI/toolbarButtons/undoRedoButtons.js +25 -0
- package/src/UI/toolbarButtons/wireframeToggleButton.js +5 -0
- package/src/UI/toolbarButtons/zoomToFitButton.js +5 -0
- package/src/UI/triangleDebuggerWindow.js +945 -0
- package/src/UI/viewer.js +4228 -0
- package/src/assemblyConstraints/AssemblyConstraintHistory.js +1576 -0
- package/src/assemblyConstraints/AssemblyConstraintRegistry.js +120 -0
- package/src/assemblyConstraints/BaseAssemblyConstraint.js +66 -0
- package/src/assemblyConstraints/constraintExpressionUtils.js +35 -0
- package/src/assemblyConstraints/constraintUtils/parallelAlignment.js +676 -0
- package/src/assemblyConstraints/constraints/AngleConstraint.js +485 -0
- package/src/assemblyConstraints/constraints/CoincidentConstraint.js +194 -0
- package/src/assemblyConstraints/constraints/DistanceConstraint.js +616 -0
- package/src/assemblyConstraints/constraints/FixedConstraint.js +78 -0
- package/src/assemblyConstraints/constraints/ParallelConstraint.js +252 -0
- package/src/assemblyConstraints/constraints/TouchAlignConstraint.js +961 -0
- package/src/core/entities/HistoryCollectionBase.js +72 -0
- package/src/core/entities/ListEntityBase.js +109 -0
- package/src/core/entities/schemaProcesser.js +121 -0
- package/src/exporters/sheetMetalFlatPattern.js +659 -0
- package/src/exporters/sheetMetalUnfold.js +862 -0
- package/src/exporters/step.js +1135 -0
- package/src/exporters/threeMF.js +575 -0
- package/src/features/assemblyComponent/AssemblyComponentFeature.js +780 -0
- package/src/features/boolean/BooleanFeature.js +94 -0
- package/src/features/chamfer/ChamferFeature.js +116 -0
- package/src/features/datium/DatiumFeature.js +80 -0
- package/src/features/edgeFeatureUtils.js +41 -0
- package/src/features/extrude/ExtrudeFeature.js +143 -0
- package/src/features/fillet/FilletFeature.js +197 -0
- package/src/features/helix/HelixFeature.js +405 -0
- package/src/features/hole/HoleFeature.js +1050 -0
- package/src/features/hole/screwClearance.js +86 -0
- package/src/features/hole/threadDesignationCatalog.js +149 -0
- package/src/features/imageHeightSolid/ImageHeightmapSolidFeature.js +463 -0
- package/src/features/imageToFace/ImageToFaceFeature.js +727 -0
- package/src/features/imageToFace/imageEditor.js +1270 -0
- package/src/features/imageToFace/traceUtils.js +971 -0
- package/src/features/import3dModel/Import3dModelFeature.js +151 -0
- package/src/features/loft/LoftFeature.js +605 -0
- package/src/features/mirror/MirrorFeature.js +151 -0
- package/src/features/offsetFace/OffsetFaceFeature.js +370 -0
- package/src/features/offsetShell/OffsetShellFeature.js +89 -0
- package/src/features/overlapCleanup/OverlapCleanupFeature.js +85 -0
- package/src/features/pattern/PatternFeature.js +275 -0
- package/src/features/patternLinear/PatternLinearFeature.js +120 -0
- package/src/features/patternRadial/PatternRadialFeature.js +186 -0
- package/src/features/plane/PlaneFeature.js +154 -0
- package/src/features/primitiveCone/primitiveConeFeature.js +99 -0
- package/src/features/primitiveCube/primitiveCubeFeature.js +70 -0
- package/src/features/primitiveCylinder/primitiveCylinderFeature.js +91 -0
- package/src/features/primitivePyramid/primitivePyramidFeature.js +72 -0
- package/src/features/primitiveSphere/primitiveSphereFeature.js +62 -0
- package/src/features/primitiveTorus/primitiveTorusFeature.js +109 -0
- package/src/features/remesh/RemeshFeature.js +97 -0
- package/src/features/revolve/RevolveFeature.js +111 -0
- package/src/features/selectionUtils.js +118 -0
- package/src/features/sheetMetal/SheetMetalContourFlangeFeature.js +1656 -0
- package/src/features/sheetMetal/SheetMetalCutoutFeature.js +1056 -0
- package/src/features/sheetMetal/SheetMetalFlangeFeature.js +1568 -0
- package/src/features/sheetMetal/SheetMetalHemFeature.js +43 -0
- package/src/features/sheetMetal/SheetMetalObject.js +141 -0
- package/src/features/sheetMetal/SheetMetalTabFeature.js +176 -0
- package/src/features/sheetMetal/UNFOLD_NEUTRAL_REQUIREMENTS.md +153 -0
- package/src/features/sheetMetal/contour-flange-rebuild-spec.md +261 -0
- package/src/features/sheetMetal/profileUtils.js +25 -0
- package/src/features/sheetMetal/sheetMetalCleanup.js +9 -0
- package/src/features/sheetMetal/sheetMetalFaceTypes.js +146 -0
- package/src/features/sheetMetal/sheetMetalMetadata.js +165 -0
- package/src/features/sheetMetal/sheetMetalPipeline.js +169 -0
- package/src/features/sheetMetal/sheetMetalProfileUtils.js +216 -0
- package/src/features/sheetMetal/sheetMetalTabUtils.js +29 -0
- package/src/features/sheetMetal/sheetMetalTree.js +210 -0
- package/src/features/sketch/SketchFeature.js +955 -0
- package/src/features/sketch/sketchSolver2D/ConstraintEngine.js +800 -0
- package/src/features/sketch/sketchSolver2D/constraintDefinitions.js +704 -0
- package/src/features/sketch/sketchSolver2D/mathHelpersMod.js +307 -0
- package/src/features/spline/SplineEditorSession.js +988 -0
- package/src/features/spline/SplineFeature.js +1388 -0
- package/src/features/spline/splineUtils.js +218 -0
- package/src/features/sweep/SweepFeature.js +110 -0
- package/src/features/transform/TransformFeature.js +152 -0
- package/src/features/tube/TubeFeature.js +635 -0
- package/src/fs.proxy.js +625 -0
- package/src/idbStorage.js +254 -0
- package/src/index.js +12 -0
- package/src/main.js +15 -0
- package/src/metadataManager.js +64 -0
- package/src/path.proxy.js +277 -0
- package/src/plugins/ghLoader.worker.js +151 -0
- package/src/plugins/pluginManager.js +286 -0
- package/src/pmi/PMIViewsManager.js +134 -0
- package/src/services/componentLibrary.js +198 -0
- package/src/tests/ConsoleCapture.js +189 -0
- package/src/tests/S7-diagnostics-2025-12-23T18-37-23-570Z.json +630 -0
- package/src/tests/browserTests.js +597 -0
- package/src/tests/debugBoolean.js +225 -0
- package/src/tests/partFiles/badBoolean.json +957 -0
- package/src/tests/partFiles/extrudeTest.json +88 -0
- package/src/tests/partFiles/filletFail.json +58 -0
- package/src/tests/partFiles/import_TEst.part.part.json +646 -0
- package/src/tests/partFiles/sheetMetalHem.BREP.json +734 -0
- package/src/tests/test_boolean_subtract.js +27 -0
- package/src/tests/test_chamfer.js +17 -0
- package/src/tests/test_extrudeFace.js +24 -0
- package/src/tests/test_fillet.js +17 -0
- package/src/tests/test_fillet_nonClosed.js +45 -0
- package/src/tests/test_filletsMoreDifficult.js +46 -0
- package/src/tests/test_history_features_basic.js +149 -0
- package/src/tests/test_hole.js +282 -0
- package/src/tests/test_mirror.js +16 -0
- package/src/tests/test_offsetShellGrouping.js +85 -0
- package/src/tests/test_plane.js +4 -0
- package/src/tests/test_primitiveCone.js +11 -0
- package/src/tests/test_primitiveCube.js +7 -0
- package/src/tests/test_primitiveCylinder.js +8 -0
- package/src/tests/test_primitivePyramid.js +9 -0
- package/src/tests/test_primitiveSphere.js +17 -0
- package/src/tests/test_primitiveTorus.js +21 -0
- package/src/tests/test_pushFace.js +126 -0
- package/src/tests/test_sheetMetalContourFlange.js +125 -0
- package/src/tests/test_sheetMetal_features.js +80 -0
- package/src/tests/test_sketch_openLoop.js +45 -0
- package/src/tests/test_solidMetrics.js +58 -0
- package/src/tests/test_stlLoader.js +1889 -0
- package/src/tests/test_sweepFace.js +55 -0
- package/src/tests/test_tube.js +45 -0
- package/src/tests/test_tube_closedLoop.js +67 -0
- package/src/tests/tests.js +493 -0
- package/src/tools/assemblyConstraintDialogCapturePage.js +56 -0
- package/src/tools/dialogCapturePageFactory.js +227 -0
- package/src/tools/featureDialogCapturePage.js +47 -0
- package/src/tools/pmiAnnotationDialogCapturePage.js +60 -0
- package/src/utils/axisHelpers.js +99 -0
- package/src/utils/deepClone.js +69 -0
- package/src/utils/geometryTolerance.js +37 -0
- package/src/utils/normalizeTypeString.js +8 -0
- package/src/utils/xformMath.js +51 -0
|
@@ -0,0 +1,236 @@
|
|
|
1
|
+
import * as THREE from 'three';
|
|
2
|
+
|
|
3
|
+
const COLOR_DEFAULT = 0x69a8ff;
|
|
4
|
+
const COLOR_HOVER = 0xffd54a;
|
|
5
|
+
const COLOR_SELECTED = 0x6fe26f;
|
|
6
|
+
|
|
7
|
+
// Grouped glyph renderer: draws small glyphs for non-dimension constraints,
|
|
8
|
+
// grouping those that act on the same set of points at a single location.
|
|
9
|
+
// Also records per-constraint centers for hit-testing.
|
|
10
|
+
export function drawConstraintGlyphs(inst, constraints) {
|
|
11
|
+
if (!inst || !inst._dim3D || !inst._lock || !inst._solver) return;
|
|
12
|
+
const s = inst._solver.sketchObject;
|
|
13
|
+
inst._glyphCenters = new Map();
|
|
14
|
+
const to3 = (u, v) => new THREE.Vector3()
|
|
15
|
+
.copy(inst._lock.basis.origin)
|
|
16
|
+
.addScaledVector(inst._lock.basis.x, u)
|
|
17
|
+
.addScaledVector(inst._lock.basis.y, v);
|
|
18
|
+
// Project plane (u,v) to screen and place an HTML glyph label with the unicode char
|
|
19
|
+
const placeGlyphLabel = (c, text, u, v, colorHex) => {
|
|
20
|
+
try {
|
|
21
|
+
if (!inst._dimRoot) return;
|
|
22
|
+
const world = to3(u, v);
|
|
23
|
+
const pt = world.project(inst.viewer.camera);
|
|
24
|
+
const rect = inst.viewer.renderer.domElement.getBoundingClientRect();
|
|
25
|
+
const x = (pt.x * 0.5 + 0.5) * rect.width;
|
|
26
|
+
const y = (-pt.y * 0.5 + 0.5) * rect.height;
|
|
27
|
+
const el = document.createElement('div');
|
|
28
|
+
el.className = 'glyph-label';
|
|
29
|
+
el.textContent = String(text);
|
|
30
|
+
el.style.position = 'absolute';
|
|
31
|
+
el.style.left = `${Math.round(x)}px`;
|
|
32
|
+
el.style.top = `${Math.round(y)}px`;
|
|
33
|
+
el.style.transform = 'translate(-50%, -50%)';
|
|
34
|
+
el.style.pointerEvents = 'auto';
|
|
35
|
+
// Prevent selecting glyph text while dragging/hovering
|
|
36
|
+
el.style.userSelect = 'none';
|
|
37
|
+
el.style.webkitUserSelect = 'none';
|
|
38
|
+
el.style.MozUserSelect = 'none';
|
|
39
|
+
el.setAttribute('draggable', 'false');
|
|
40
|
+
el.onselectstart = () => false;
|
|
41
|
+
el.style.font = '14px ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace';
|
|
42
|
+
el.style.lineHeight = '1';
|
|
43
|
+
el.style.color = '#e6e6e6';
|
|
44
|
+
el.style.padding = '1px 6px';
|
|
45
|
+
el.style.borderRadius = '6px';
|
|
46
|
+
el.style.border = '1px solid #364053';
|
|
47
|
+
el.style.background = 'rgba(20,24,30,.85)';
|
|
48
|
+
if (colorHex === COLOR_SELECTED) {
|
|
49
|
+
el.style.background = 'rgba(111,226,111,.16)';
|
|
50
|
+
el.style.border = '1px solid #2f6d2f';
|
|
51
|
+
} else if (colorHex === COLOR_HOVER) {
|
|
52
|
+
el.style.background = 'rgba(255,213,74,.12)';
|
|
53
|
+
el.style.border = '1px solid #6f5a12';
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// Interactions: click to toggle selection; hover to reflect
|
|
57
|
+
el.addEventListener('pointerdown', (e) => {
|
|
58
|
+
try { if (inst.viewer?.controls) inst.viewer.controls.enabled = false; } catch { }
|
|
59
|
+
try { el.setPointerCapture(e.pointerId); } catch { }
|
|
60
|
+
e.preventDefault(); e.stopPropagation();
|
|
61
|
+
});
|
|
62
|
+
el.addEventListener('pointerup', (e) => {
|
|
63
|
+
try { el.releasePointerCapture(e.pointerId); } catch { }
|
|
64
|
+
try { if (inst.viewer?.controls) inst.viewer.controls.enabled = true; } catch { }
|
|
65
|
+
try { inst.toggleSelectConstraint?.(c.id); } catch { }
|
|
66
|
+
e.preventDefault(); e.stopPropagation();
|
|
67
|
+
});
|
|
68
|
+
el.addEventListener('pointerenter', () => { try { inst.hoverConstraintFromLabel?.(c.id); } catch { } });
|
|
69
|
+
el.addEventListener('pointerleave', () => { try { inst.clearHoverFromLabel?.(c.id); } catch { } });
|
|
70
|
+
|
|
71
|
+
inst._dimRoot.appendChild(el);
|
|
72
|
+
} catch { }
|
|
73
|
+
};
|
|
74
|
+
const rect = inst.viewer.renderer.domElement.getBoundingClientRect();
|
|
75
|
+
const wpp = worldPerPixel(inst.viewer.camera, rect.width, rect.height);
|
|
76
|
+
const base = Math.max(0.1, wpp * 14);
|
|
77
|
+
const handleR = Math.max(0.02, wpp * 8 * 0.5);
|
|
78
|
+
const iconR = Math.max(base * 0.9, handleR * 1.9); // approx glyph half size in world units
|
|
79
|
+
const P = (id) => s.points.find((p) => p.id === id);
|
|
80
|
+
|
|
81
|
+
// Nudge a (u,v) position away from nearby sketch points to avoid overlap
|
|
82
|
+
const nudgeFromPoints = (u, v) => {
|
|
83
|
+
const pts = (s && Array.isArray(s.points)) ? s.points : [];
|
|
84
|
+
// Ensure clearance relative to both handle size and glyph label size
|
|
85
|
+
const minDist = iconR;
|
|
86
|
+
let uu = u, vv = v;
|
|
87
|
+
let iter = 0;
|
|
88
|
+
while (iter++ < 10) {
|
|
89
|
+
let nearest = null, nd = Infinity;
|
|
90
|
+
for (const p of pts) {
|
|
91
|
+
const d = Math.hypot(uu - p.x, vv - p.y);
|
|
92
|
+
if (d < nd) { nd = d; nearest = p; }
|
|
93
|
+
}
|
|
94
|
+
if (!nearest || nd >= minDist) break;
|
|
95
|
+
let dx = uu - nearest.x, dy = vv - nearest.y;
|
|
96
|
+
let L = Math.hypot(dx, dy);
|
|
97
|
+
if (L < 1e-6) { dx = 0.70710678; dy = 0.70710678; L = 1; }
|
|
98
|
+
const push = (minDist - nd) + (0.35 * minDist);
|
|
99
|
+
uu = nearest.x + (dx / L) * (nd + push);
|
|
100
|
+
vv = nearest.y + (dy / L) * (nd + push);
|
|
101
|
+
}
|
|
102
|
+
return { u: uu, v: vv };
|
|
103
|
+
};
|
|
104
|
+
|
|
105
|
+
// Avoid both points and existing glyphs; keeps result near (u0,v0)
|
|
106
|
+
const placedIcons = [];
|
|
107
|
+
const freeFromIcons = (u, v) => placedIcons.every(p => Math.hypot(u - p.u, v - p.v) >= iconR * 1.2);
|
|
108
|
+
const avoidAll = (u0, v0) => {
|
|
109
|
+
// First clear from points
|
|
110
|
+
let p = nudgeFromPoints(u0, v0);
|
|
111
|
+
if (freeFromIcons(p.u, p.v)) return p;
|
|
112
|
+
// Spiral search outwards
|
|
113
|
+
const step = iconR * 0.6;
|
|
114
|
+
const maxRings = 16;
|
|
115
|
+
for (let ring = 1; ring <= maxRings; ring++) {
|
|
116
|
+
const r = ring * step;
|
|
117
|
+
const spokes = 8 + ring * 2;
|
|
118
|
+
for (let i = 0; i < spokes; i++) {
|
|
119
|
+
const ang = (i / spokes) * Math.PI * 2;
|
|
120
|
+
const cu = u0 + Math.cos(ang) * r;
|
|
121
|
+
const cv = v0 + Math.sin(ang) * r;
|
|
122
|
+
const q = nudgeFromPoints(cu, cv);
|
|
123
|
+
if (freeFromIcons(q.u, q.v)) return q;
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
return p; // fallback
|
|
127
|
+
};
|
|
128
|
+
// Build groups by sorted unique point set
|
|
129
|
+
const groups = new Map();
|
|
130
|
+
for (const c of (constraints || [])) {
|
|
131
|
+
if (!c || c.type === '⟺' || c.type === '∠') continue;
|
|
132
|
+
const ids = Array.from(new Set((c.points || []).map(Number))).sort((a, b) => a - b);
|
|
133
|
+
if (!ids.length) continue;
|
|
134
|
+
const key = ids.join(',');
|
|
135
|
+
const arr = groups.get(key) || []; arr.push(c); groups.set(key, arr);
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
// Compute anchor per group
|
|
139
|
+
const lineIntersect = (A, B, C, D) => {
|
|
140
|
+
// Returns intersection of infinite lines AB and CD; fallback to average of midpoints
|
|
141
|
+
const A1 = B.y - A.y; const B1 = A.x - B.x; const C1 = A1 * A.x + B1 * A.y;
|
|
142
|
+
const A2 = D.y - C.y; const B2 = C.x - D.x; const C2 = A2 * C.x + B2 * C.y;
|
|
143
|
+
const den = A1 * B2 - A2 * B1;
|
|
144
|
+
if (Math.abs(den) < 1e-9) {
|
|
145
|
+
const m1 = { x: (A.x + B.x) * 0.5, y: (A.y + B.y) * 0.5 };
|
|
146
|
+
const m2 = { x: (C.x + D.x) * 0.5, y: (C.y + D.y) * 0.5 };
|
|
147
|
+
return { x: (m1.x + m2.x) * 0.5, y: (m1.y + m2.y) * 0.5 };
|
|
148
|
+
}
|
|
149
|
+
const x = (B2 * C1 - B1 * C2) / den;
|
|
150
|
+
const y = (A1 * C2 - A2 * C1) / den;
|
|
151
|
+
return { x, y };
|
|
152
|
+
};
|
|
153
|
+
const anchorFor = (ids, arr) => {
|
|
154
|
+
// If any perpendicular exists in this group, use line intersection of its two lines as anchor
|
|
155
|
+
const perp = (arr || []).find(c => c && c.type === '⟂' && Array.isArray(c.points) && c.points.length >= 4);
|
|
156
|
+
if (perp) {
|
|
157
|
+
const A = P(perp.points[0]); const B = P(perp.points[1]);
|
|
158
|
+
const C = P(perp.points[2]); const D = P(perp.points[3]);
|
|
159
|
+
if (A && B && C && D) {
|
|
160
|
+
const I = lineIntersect(A, B, C, D);
|
|
161
|
+
const off = nudgeFromPoints(I.x, I.y);
|
|
162
|
+
return { u: off.u, v: off.v };
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
// If the group is only coincident constraints, anchor near the first point
|
|
166
|
+
if ((arr || []).length && (arr || []).every(c => c && c.type === '≡')) {
|
|
167
|
+
const p0 = P(ids[0]);
|
|
168
|
+
if (p0) {
|
|
169
|
+
const off = nudgeFromPoints(p0.x, p0.y);
|
|
170
|
+
return { u: off.u, v: off.v };
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
// Default: centroid of unique points, nudged slightly for visibility
|
|
174
|
+
let sx = 0, sy = 0, n = 0;
|
|
175
|
+
for (const id of ids) { const p = P(id); if (p) { sx += p.x; sy += p.y; n++; } }
|
|
176
|
+
if (!n) return { u: 0, v: 0 };
|
|
177
|
+
const u = sx / n, v = sy / n;
|
|
178
|
+
const off = nudgeFromPoints(u, v);
|
|
179
|
+
return { u: off.u, v: off.v };
|
|
180
|
+
};
|
|
181
|
+
|
|
182
|
+
// Draw each group: lay out symbols in a row centered at anchor
|
|
183
|
+
const selSet = new Set(Array.from(inst._selection || []).filter(it => it.type === 'constraint').map(it => it.id));
|
|
184
|
+
const hovId = (inst._hover && inst._hover.type === 'constraint') ? inst._hover.id : null;
|
|
185
|
+
|
|
186
|
+
for (const [key, arr] of groups.entries()) {
|
|
187
|
+
const ids = key.split(',').map(Number);
|
|
188
|
+
const anchor = anchorFor(ids, arr);
|
|
189
|
+
const spacing = base * 0.7;
|
|
190
|
+
const startU = anchor.u - spacing * (arr.length - 1) / 2;
|
|
191
|
+
const y = anchor.v;
|
|
192
|
+
for (let i = 0; i < arr.length; i++) {
|
|
193
|
+
const c = arr[i];
|
|
194
|
+
const cx = startU + i * spacing;
|
|
195
|
+
const adj = avoidAll(cx, y);
|
|
196
|
+
// Record for hit-testing
|
|
197
|
+
try { inst._glyphCenters.set(c.id, { u: adj.u, v: adj.v }); } catch { }
|
|
198
|
+
placedIcons.push({ u: adj.u, v: adj.v });
|
|
199
|
+
// Small pick radius disk (invisible) for selection
|
|
200
|
+
try {
|
|
201
|
+
const pickR = iconR;
|
|
202
|
+
const g = new THREE.CircleGeometry(pickR, 20);
|
|
203
|
+
// Orient the circle in plane XY mapped to sketch plane
|
|
204
|
+
const X = inst._lock.basis.x.clone().normalize();
|
|
205
|
+
const Y = inst._lock.basis.y.clone().normalize();
|
|
206
|
+
const Z = new THREE.Vector3().crossVectors(X, Y).normalize();
|
|
207
|
+
const m = new THREE.Matrix4().makeBasis(X, Y, Z).setPosition(to3(adj.u, adj.v));
|
|
208
|
+
const mat = new THREE.MeshBasicMaterial({ visible: false });
|
|
209
|
+
const mesh = new THREE.Mesh(g, mat);
|
|
210
|
+
mesh.applyMatrix4(m);
|
|
211
|
+
mesh.renderOrder = 10030;
|
|
212
|
+
|
|
213
|
+
mesh.userData = { kind: 'glyphHit', cid: c.id };
|
|
214
|
+
inst._dim3D.add(mesh);
|
|
215
|
+
} catch { }
|
|
216
|
+
|
|
217
|
+
// Draw the glyph symbol itself as unicode character from constraint.type
|
|
218
|
+
try {
|
|
219
|
+
const color = selSet.has(c.id) ? COLOR_SELECTED : (hovId === c.id ? COLOR_HOVER : COLOR_DEFAULT);
|
|
220
|
+
placeGlyphLabel(c, c.type || '?', adj.u, adj.v, color);
|
|
221
|
+
} catch { }
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
function worldPerPixel(camera, width, height) {
|
|
227
|
+
if (camera && camera.isOrthographicCamera) {
|
|
228
|
+
const zoom = typeof camera.zoom === 'number' && camera.zoom > 0 ? camera.zoom : 1;
|
|
229
|
+
const wppX = (camera.right - camera.left) / (width * zoom);
|
|
230
|
+
const wppY = (camera.top - camera.bottom) / (height * zoom);
|
|
231
|
+
return Math.max(wppX, wppY);
|
|
232
|
+
}
|
|
233
|
+
const dist = camera.position.length();
|
|
234
|
+
const fovRad = (camera.fov * Math.PI) / 180;
|
|
235
|
+
return (2 * Math.tan(fovRad / 2) * dist) / height;
|
|
236
|
+
}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
// Sidebar + 3D hover/selection coloring helpers
|
|
2
|
+
|
|
3
|
+
export function updateListHighlights(inst) {
|
|
4
|
+
if (!inst || !inst._acc) return;
|
|
5
|
+
const mapKey = (t, id) => (t === 'point' ? `p:${id}` : t === 'geometry' ? `g:${id}` : t === 'constraint' ? `c:${id}` : null);
|
|
6
|
+
const sel = new Set(Array.from(inst._selection || []).map((i) => mapKey(i.type, i.id)).filter(Boolean));
|
|
7
|
+
const hov = inst._hover ? mapKey(inst._hover.type, inst._hover.id) : null;
|
|
8
|
+
|
|
9
|
+
const rows = Array.from(inst._acc.uiElement.querySelectorAll('.sk-row'));
|
|
10
|
+
for (const r of rows) {
|
|
11
|
+
const btn = r.querySelector('[data-act]');
|
|
12
|
+
const key = btn ? btn.getAttribute('data-act') : null;
|
|
13
|
+
const selected = key && sel.has(key);
|
|
14
|
+
const hovered = key && hov === key;
|
|
15
|
+
|
|
16
|
+
// Row tint
|
|
17
|
+
r.style.background = selected
|
|
18
|
+
? 'rgba(111,226,111,.12)'
|
|
19
|
+
: hovered
|
|
20
|
+
? 'rgba(255,213,74,.10)'
|
|
21
|
+
: 'transparent';
|
|
22
|
+
r.style.borderRadius = '6px';
|
|
23
|
+
|
|
24
|
+
// Button visual state
|
|
25
|
+
if (btn) {
|
|
26
|
+
if (selected) {
|
|
27
|
+
btn.style.background = 'rgba(111,226,111,.10)';
|
|
28
|
+
btn.style.border = '1px solid #2f6d2f';
|
|
29
|
+
btn.style.color = '#d7ffd7';
|
|
30
|
+
} else if (hovered) {
|
|
31
|
+
btn.style.background = 'rgba(255,213,74,.08)';
|
|
32
|
+
btn.style.border = '1px solid #6f5a12';
|
|
33
|
+
btn.style.color = '#ffe599';
|
|
34
|
+
} else {
|
|
35
|
+
// Reset to defaults used when rendering the list
|
|
36
|
+
btn.style.background = 'transparent';
|
|
37
|
+
btn.style.border = '1px solid #364053';
|
|
38
|
+
btn.style.color = '#ddd';
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export function applyHoverAndSelectionColors(inst) {
|
|
45
|
+
if (!inst || !inst._sketchGroup) return;
|
|
46
|
+
const hov = inst._hover;
|
|
47
|
+
const isSel = (kind, id) => Array.from(inst._selection).some(s => s.type === (kind === 'point' ? 'point' : 'geometry') && s.id === id);
|
|
48
|
+
const isHov = (kind, id) => hov && ((hov.type === 'point' && kind === 'point' && hov.id === id) || (hov.type === 'geometry' && kind === 'geometry' && hov.id === id));
|
|
49
|
+
for (const ch of inst._sketchGroup.children) {
|
|
50
|
+
const ud = ch.userData || {};
|
|
51
|
+
if (ud.kind === 'point') {
|
|
52
|
+
const base = ud.underConstrained ? 0xffb347 : 0x9ec9ff;
|
|
53
|
+
const col = isSel('point', ud.id) ? 0x6fe26f : (isHov('point', ud.id) ? 0xffd54a : base);
|
|
54
|
+
try { ch.material.color.setHex(col); } catch {}
|
|
55
|
+
} else if (ud.kind === 'geometry') {
|
|
56
|
+
const col = isSel('geometry', ud.id) ? 0x6fe26f : (isHov('geometry', ud.id) ? 0xffd54a : 0xffff88);
|
|
57
|
+
try { ch.material.color.setHex(col); } catch {}
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
}
|