brep-io-kernel 1.0.0-ci.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE.md +32 -0
- package/README.md +154 -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,507 @@
|
|
|
1
|
+
// ViewTransformAnnotation.js
|
|
2
|
+
// View-specific solid transforms for PMI mode
|
|
3
|
+
|
|
4
|
+
import * as THREE from 'three';
|
|
5
|
+
import { BaseAnnotation } from '../BaseAnnotation.js';
|
|
6
|
+
import { makeOverlayDashedLine } from '../annUtils.js';
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
const inputParamsSchema = {
|
|
10
|
+
id: {
|
|
11
|
+
type: 'string',
|
|
12
|
+
default_value: null,
|
|
13
|
+
hint: 'unique identifier for the view transform',
|
|
14
|
+
},
|
|
15
|
+
targets: {
|
|
16
|
+
type: 'reference_selection',
|
|
17
|
+
multiple: true,
|
|
18
|
+
default_value: [],
|
|
19
|
+
label: 'Target Objects',
|
|
20
|
+
selectionFilter: ['SOLID'],
|
|
21
|
+
hint: 'Choose the solids to reposition in this view',
|
|
22
|
+
},
|
|
23
|
+
transform: {
|
|
24
|
+
type: 'transform',
|
|
25
|
+
label: 'Transform',
|
|
26
|
+
hint: 'Translation and rotation applied relative to the reference point',
|
|
27
|
+
},
|
|
28
|
+
showTraceLine: {
|
|
29
|
+
type: 'boolean',
|
|
30
|
+
default_value: true,
|
|
31
|
+
label: 'Show trace lines',
|
|
32
|
+
hint: 'Draw a line from the original position to the transformed position',
|
|
33
|
+
},
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
export class ExplodeBodyAnnotation extends BaseAnnotation {
|
|
37
|
+
static entityType = 'exp';
|
|
38
|
+
static type = 'exp';
|
|
39
|
+
static shortName = 'EXP';
|
|
40
|
+
static longName = 'Explode Body';
|
|
41
|
+
static title = 'Explode Body';
|
|
42
|
+
static inputParamsSchema = inputParamsSchema;
|
|
43
|
+
static aliases = ['viewTransform'];
|
|
44
|
+
|
|
45
|
+
constructor(opts = {}) {
|
|
46
|
+
super(opts);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
async run(renderingContext) {
|
|
50
|
+
const { pmimode, group } = renderingContext;
|
|
51
|
+
if (!pmimode || !group) return [];
|
|
52
|
+
|
|
53
|
+
const ann = this.inputParams || {};
|
|
54
|
+
ensurePersistent(ann);
|
|
55
|
+
ann.transform = sanitizeTransform(ann.transform);
|
|
56
|
+
|
|
57
|
+
const solids = ExplodeBodyAnnotation._resolveSolidReferences(ann, pmimode, true);
|
|
58
|
+
if (!solids.length) return [];
|
|
59
|
+
|
|
60
|
+
const snapshots = ExplodeBodyAnnotation._ensureOriginalSnapshots(ann, solids, false, pmimode?.viewer);
|
|
61
|
+
const shouldDrawTrace = ann.showTraceLine !== false;
|
|
62
|
+
|
|
63
|
+
let traceState = pmimode?.__explodeTraceState;
|
|
64
|
+
if (!(traceState instanceof Map)) {
|
|
65
|
+
traceState = new Map();
|
|
66
|
+
if (pmimode) pmimode.__explodeTraceState = traceState;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
const deltaPos = vectorFromArray(ann.transform.position, new THREE.Vector3(0, 0, 0));
|
|
70
|
+
const deltaQuat = quaternionFromEuler(ann.transform.rotationEuler);
|
|
71
|
+
const deltaScale = vectorFromArray(ann.transform.scale, new THREE.Vector3(1, 1, 1));
|
|
72
|
+
|
|
73
|
+
solids.forEach((solid) => {
|
|
74
|
+
try {
|
|
75
|
+
const snap = snapshots.get(solid.uuid);
|
|
76
|
+
const centerLocal = vectorFromArray(snap?.centerLocal)
|
|
77
|
+
|| getSolidLocalCenter(solid);
|
|
78
|
+
const baseEntry = traceState?.get(solid.uuid)?.clone()
|
|
79
|
+
|| transformEntryFromSnapshot(snap);
|
|
80
|
+
const start = applyTransformEntryToPoint(baseEntry, centerLocal)
|
|
81
|
+
|| vectorFromArray(snap?.centerWorld) || vectorFromArray(snap?.worldPosition);
|
|
82
|
+
const endEntry = composeTransformEntry(baseEntry, deltaPos, deltaQuat, deltaScale);
|
|
83
|
+
const end = applyTransformEntryToPoint(endEntry, centerLocal)
|
|
84
|
+
|| getSolidWorldCenter(solid);
|
|
85
|
+
if (isFiniteVec3(start) && isFiniteVec3(end) && start.distanceToSquared(end) >= 1e-8 && shouldDrawTrace) {
|
|
86
|
+
group.add(makeOverlayDashedLine(start, end, 0xf5a524, { viewer: pmimode?.viewer }));
|
|
87
|
+
}
|
|
88
|
+
traceState?.set(solid.uuid, endEntry);
|
|
89
|
+
} catch {
|
|
90
|
+
/* ignore trace failures */
|
|
91
|
+
}
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
return [];
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
static _resolveSolidReferences(ann, pmimode, refresh = false) {
|
|
98
|
+
if (!ann || !pmimode) return [];
|
|
99
|
+
const viewer = pmimode.viewer;
|
|
100
|
+
const scene = viewer?.partHistory?.scene || viewer?.scene;
|
|
101
|
+
if (!scene) return [];
|
|
102
|
+
|
|
103
|
+
if (!refresh && Array.isArray(ann.__resolvedSolids) && ann.__resolvedSolids.length) {
|
|
104
|
+
const filtered = ann.__resolvedSolids.filter((obj) => obj && obj.isObject3D);
|
|
105
|
+
setHiddenProperty(ann, '__resolvedSolids', filtered);
|
|
106
|
+
setHiddenProperty(ann, 'solids', filtered);
|
|
107
|
+
return filtered;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
const refs = Array.isArray(ann.targets) ? ann.targets : [];
|
|
111
|
+
const out = [];
|
|
112
|
+
refs.forEach((ref) => {
|
|
113
|
+
const obj = resolveSolidObject(ref, scene);
|
|
114
|
+
if (obj && obj.isObject3D) out.push(obj);
|
|
115
|
+
});
|
|
116
|
+
setHiddenProperty(ann, '__resolvedSolids', out);
|
|
117
|
+
setHiddenProperty(ann, 'solids', out);
|
|
118
|
+
return out;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
static _ensureOriginalSnapshots(ann, solids, forceRefresh = false, viewer = null) {
|
|
122
|
+
ensurePersistent(ann);
|
|
123
|
+
let map = ann.__originalSnapshots;
|
|
124
|
+
if (!(map instanceof Map)) {
|
|
125
|
+
map = snapshotArrayToMap(ann.persistentData?.originalTransforms);
|
|
126
|
+
}
|
|
127
|
+
if (!(map instanceof Map)) map = new Map();
|
|
128
|
+
|
|
129
|
+
const list = Array.isArray(solids) ? solids : [];
|
|
130
|
+
list.forEach((solid) => {
|
|
131
|
+
if (!solid || !solid.uuid) return;
|
|
132
|
+
if (forceRefresh || !map.has(solid.uuid)) {
|
|
133
|
+
map.set(solid.uuid, captureSnapshot(solid, viewer));
|
|
134
|
+
}
|
|
135
|
+
});
|
|
136
|
+
|
|
137
|
+
setHiddenProperty(ann, '__originalSnapshots', map);
|
|
138
|
+
ann.persistentData.originalTransforms = snapshotMapToArray(map);
|
|
139
|
+
return map;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
static getOriginalSnapshotMap(ann) {
|
|
143
|
+
if (!ann) return new Map();
|
|
144
|
+
if (ann.__originalSnapshots instanceof Map) return ann.__originalSnapshots;
|
|
145
|
+
const map = snapshotArrayToMap(ann?.persistentData?.originalTransforms);
|
|
146
|
+
setHiddenProperty(ann, '__originalSnapshots', map instanceof Map ? map : new Map());
|
|
147
|
+
return ann.__originalSnapshots;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
static applyTransformsToSolids(ann, pmimode, options = {}) {
|
|
151
|
+
if (!ann || !pmimode) return;
|
|
152
|
+
const solids = ExplodeBodyAnnotation._resolveSolidReferences(ann, pmimode, true);
|
|
153
|
+
if (!solids.length) return;
|
|
154
|
+
|
|
155
|
+
const startSnapshots = (options && options.startSnapshots instanceof Map)
|
|
156
|
+
? options.startSnapshots
|
|
157
|
+
: ExplodeBodyAnnotation.getOriginalSnapshotMap(ann);
|
|
158
|
+
const cumulativeState = options?.cumulativeState instanceof Map ? options.cumulativeState : null;
|
|
159
|
+
|
|
160
|
+
const delta = sanitizeTransform(ann.transform);
|
|
161
|
+
ann.transform = delta;
|
|
162
|
+
const deltaPos = vectorFromArray(delta.position, new THREE.Vector3(0, 0, 0));
|
|
163
|
+
const deltaQuat = quaternionFromEuler(delta.rotationEuler);
|
|
164
|
+
const deltaScale = vectorFromArray(delta.scale, new THREE.Vector3(1, 1, 1));
|
|
165
|
+
|
|
166
|
+
solids.forEach((solid) => {
|
|
167
|
+
if (!solid || !solid.uuid) return;
|
|
168
|
+
const snap = startSnapshots.get(solid.uuid)
|
|
169
|
+
|| ExplodeBodyAnnotation.getOriginalSnapshotMap(ann).get(solid.uuid)
|
|
170
|
+
|| captureSnapshot(solid, pmimode?.viewer);
|
|
171
|
+
if (!snap) return;
|
|
172
|
+
|
|
173
|
+
const basePos = vectorFromArray(snap.position, new THREE.Vector3(0, 0, 0));
|
|
174
|
+
const baseQuat = quaternionFromArray(snap.quaternion, new THREE.Quaternion());
|
|
175
|
+
const baseScale = vectorFromArray(snap.scale, new THREE.Vector3(1, 1, 1));
|
|
176
|
+
|
|
177
|
+
const finalPos = basePos.clone().add(deltaPos);
|
|
178
|
+
const finalQuat = baseQuat.clone().multiply(deltaQuat);
|
|
179
|
+
const finalScale = baseScale.clone().multiply(deltaScale);
|
|
180
|
+
|
|
181
|
+
solid.position.copy(finalPos);
|
|
182
|
+
solid.quaternion.copy(finalQuat);
|
|
183
|
+
solid.scale.copy(finalScale);
|
|
184
|
+
solid.updateMatrixWorld(true);
|
|
185
|
+
|
|
186
|
+
if (cumulativeState) {
|
|
187
|
+
const wp = solid.getWorldPosition(new THREE.Vector3());
|
|
188
|
+
cumulativeState.set(solid.uuid, {
|
|
189
|
+
position: finalPos.toArray(),
|
|
190
|
+
quaternion: finalQuat.toArray(),
|
|
191
|
+
scale: finalScale.toArray(),
|
|
192
|
+
worldPosition: wp.toArray(),
|
|
193
|
+
});
|
|
194
|
+
}
|
|
195
|
+
});
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
static restoreOriginalTransforms(ann, pmimode) {
|
|
199
|
+
if (!ann || !pmimode) return;
|
|
200
|
+
const solids = ExplodeBodyAnnotation._resolveSolidReferences(ann, pmimode, true);
|
|
201
|
+
if (!solids.length) return;
|
|
202
|
+
const originals = ExplodeBodyAnnotation.getOriginalSnapshotMap(ann);
|
|
203
|
+
|
|
204
|
+
solids.forEach((solid) => {
|
|
205
|
+
if (!solid || !solid.uuid) return;
|
|
206
|
+
const snap = originals.get(solid.uuid);
|
|
207
|
+
if (!snap) return;
|
|
208
|
+
const pos = vectorFromArray(snap.position, new THREE.Vector3(0, 0, 0));
|
|
209
|
+
const quat = quaternionFromArray(snap.quaternion, new THREE.Quaternion());
|
|
210
|
+
const scale = vectorFromArray(snap.scale, new THREE.Vector3(1, 1, 1));
|
|
211
|
+
solid.position.copy(pos);
|
|
212
|
+
solid.quaternion.copy(quat);
|
|
213
|
+
solid.scale.copy(scale);
|
|
214
|
+
solid.updateMatrixWorld(true);
|
|
215
|
+
});
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
static applyParams(pmimode, ann, params) {
|
|
219
|
+
super.applyParams(pmimode, ann, params);
|
|
220
|
+
ann.targets = arrayOfStrings(ann.targets);
|
|
221
|
+
ann.transform = sanitizeTransform(ann.transform);
|
|
222
|
+
ann.showTraceLine = ann.showTraceLine === false ? false : true;
|
|
223
|
+
try {
|
|
224
|
+
if (pmimode && typeof pmimode.applyViewTransformsSequential === 'function') {
|
|
225
|
+
pmimode.applyViewTransformsSequential();
|
|
226
|
+
}
|
|
227
|
+
} catch { }
|
|
228
|
+
return { paramsPatch: {} };
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
function ensurePersistent(ann) {
|
|
233
|
+
if (!ann.persistentData || typeof ann.persistentData !== 'object') {
|
|
234
|
+
ann.persistentData = {};
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
function setHiddenProperty(obj, key, value) {
|
|
239
|
+
if (!obj || typeof obj !== 'object') return;
|
|
240
|
+
try {
|
|
241
|
+
Object.defineProperty(obj, key, {
|
|
242
|
+
value,
|
|
243
|
+
configurable: true,
|
|
244
|
+
enumerable: false,
|
|
245
|
+
writable: true,
|
|
246
|
+
});
|
|
247
|
+
} catch {
|
|
248
|
+
obj[key] = value;
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
function sanitizeTransform(value) {
|
|
253
|
+
const obj = (value && typeof value === 'object') ? value : {};
|
|
254
|
+
const sanitizeArray = (arr, fallback) => {
|
|
255
|
+
if (!Array.isArray(arr)) return fallback.slice();
|
|
256
|
+
const out = fallback.slice();
|
|
257
|
+
for (let i = 0; i < out.length; i += 1) {
|
|
258
|
+
const num = Number(arr[i]);
|
|
259
|
+
out[i] = Number.isFinite(num) ? num : out[i];
|
|
260
|
+
}
|
|
261
|
+
return out;
|
|
262
|
+
};
|
|
263
|
+
return {
|
|
264
|
+
position: sanitizeArray(obj.position, [0, 0, 0]),
|
|
265
|
+
rotationEuler: sanitizeArray(obj.rotationEuler, [0, 0, 0]),
|
|
266
|
+
scale: sanitizeArray(obj.scale, [1, 1, 1]),
|
|
267
|
+
};
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
function arrayOfStrings(values) {
|
|
271
|
+
if (!Array.isArray(values)) return [];
|
|
272
|
+
return values
|
|
273
|
+
.map((v) => (v == null ? '' : String(v).trim()))
|
|
274
|
+
.filter((s) => s.length);
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
function resolveSolidObject(ref, scene) {
|
|
278
|
+
if (!scene) return null;
|
|
279
|
+
if (!ref && ref !== 0) return null;
|
|
280
|
+
let info = null;
|
|
281
|
+
if (typeof ref === 'string' && ref.trim().length) {
|
|
282
|
+
const trimmed = ref.trim();
|
|
283
|
+
if (trimmed[0] === '{') {
|
|
284
|
+
try { info = JSON.parse(trimmed); }
|
|
285
|
+
catch { info = { name: trimmed }; }
|
|
286
|
+
} else {
|
|
287
|
+
info = { name: trimmed };
|
|
288
|
+
}
|
|
289
|
+
} else if (typeof ref === 'object') {
|
|
290
|
+
info = { ...ref };
|
|
291
|
+
}
|
|
292
|
+
if (!info) return null;
|
|
293
|
+
|
|
294
|
+
const tryNames = [];
|
|
295
|
+
if (info.name && typeof info.name === 'string') tryNames.push(info.name.trim());
|
|
296
|
+
if (Array.isArray(info.path) && info.path.length) {
|
|
297
|
+
tryNames.push(String(info.path[info.path.length - 1]));
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
for (const name of tryNames) {
|
|
301
|
+
if (!name) continue;
|
|
302
|
+
const found = scene.getObjectByName(name);
|
|
303
|
+
if (found && found.type === 'SOLID') return found;
|
|
304
|
+
if (found) return found;
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
if (typeof info.uuid === 'string') {
|
|
308
|
+
const obj = scene.getObjectByProperty('uuid', info.uuid);
|
|
309
|
+
if (obj) return obj;
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
if (Number.isInteger(info.id)) {
|
|
313
|
+
try {
|
|
314
|
+
const obj = scene.getObjectById(info.id);
|
|
315
|
+
if (obj) return obj;
|
|
316
|
+
} catch {
|
|
317
|
+
/* ignore */
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
return null;
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
function captureSnapshot(object, viewer = null) {
|
|
325
|
+
try { object.updateMatrixWorld(true); } catch { }
|
|
326
|
+
const pos = object.position.clone();
|
|
327
|
+
const quat = object.quaternion.clone();
|
|
328
|
+
const scale = object.scale.clone();
|
|
329
|
+
const world = object.getWorldPosition(new THREE.Vector3());
|
|
330
|
+
const centerLocal = getSolidLocalCenter(object);
|
|
331
|
+
const centerWorld = centerLocal.clone().applyMatrix4(new THREE.Matrix4().compose(pos.clone(), quat.clone(), scale.clone()));
|
|
332
|
+
return {
|
|
333
|
+
position: pos.toArray(),
|
|
334
|
+
quaternion: quat.toArray(),
|
|
335
|
+
scale: scale.toArray(),
|
|
336
|
+
worldPosition: world.toArray(),
|
|
337
|
+
centerWorld: centerWorld.toArray(),
|
|
338
|
+
centerLocal: centerLocal.toArray(),
|
|
339
|
+
};
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
function snapshotArrayToMap(arr) {
|
|
343
|
+
if (!Array.isArray(arr)) return new Map();
|
|
344
|
+
const map = new Map();
|
|
345
|
+
arr.forEach((item) => {
|
|
346
|
+
if (!item || typeof item !== 'object' || !item.uuid) return;
|
|
347
|
+
map.set(item.uuid, {
|
|
348
|
+
position: toArray(item.position, [0, 0, 0]),
|
|
349
|
+
quaternion: toArray(item.quaternion, [0, 0, 0, 1]),
|
|
350
|
+
scale: toArray(item.scale, [1, 1, 1]),
|
|
351
|
+
worldPosition: toArray(item.worldPosition, null),
|
|
352
|
+
centerWorld: toArray(item.centerWorld, null),
|
|
353
|
+
centerLocal: toArray(item.centerLocal, null),
|
|
354
|
+
});
|
|
355
|
+
});
|
|
356
|
+
return map;
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
function snapshotMapToArray(map) {
|
|
360
|
+
if (!(map instanceof Map)) return [];
|
|
361
|
+
const arr = [];
|
|
362
|
+
map.forEach((value, key) => {
|
|
363
|
+
if (!key) return;
|
|
364
|
+
arr.push({
|
|
365
|
+
uuid: key,
|
|
366
|
+
position: toArray(value.position, [0, 0, 0]),
|
|
367
|
+
quaternion: toArray(value.quaternion, [0, 0, 0, 1]),
|
|
368
|
+
scale: toArray(value.scale, [1, 1, 1]),
|
|
369
|
+
worldPosition: toArray(value.worldPosition, null),
|
|
370
|
+
centerWorld: toArray(value.centerWorld, null),
|
|
371
|
+
centerLocal: toArray(value.centerLocal, null),
|
|
372
|
+
});
|
|
373
|
+
});
|
|
374
|
+
return arr;
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
function toArray(src, fallback) {
|
|
378
|
+
if (Array.isArray(src)) return src.slice();
|
|
379
|
+
if (src && typeof src === 'object' && typeof src.length === 'number') {
|
|
380
|
+
const out = [];
|
|
381
|
+
for (let i = 0; i < src.length; i += 1) out.push(Number(src[i]));
|
|
382
|
+
return out;
|
|
383
|
+
}
|
|
384
|
+
if (src && typeof src.x === 'number' && typeof src.y === 'number' && typeof src.z === 'number') {
|
|
385
|
+
if (typeof src.w === 'number') return [src.x, src.y, src.z, src.w];
|
|
386
|
+
return [src.x, src.y, src.z];
|
|
387
|
+
}
|
|
388
|
+
return fallback ? fallback.slice() : fallback;
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
function vectorFromArray(arr, fallbackVector) {
|
|
392
|
+
if (arr instanceof THREE.Vector3) return arr.clone();
|
|
393
|
+
if (Array.isArray(arr) && arr.length >= 3) {
|
|
394
|
+
const x = Number(arr[0]);
|
|
395
|
+
const y = Number(arr[1]);
|
|
396
|
+
const z = Number(arr[2]);
|
|
397
|
+
if ([x, y, z].every((n) => Number.isFinite(n))) return new THREE.Vector3(x, y, z);
|
|
398
|
+
}
|
|
399
|
+
if (arr && typeof arr === 'object' && Number.isFinite(arr.x) && Number.isFinite(arr.y) && Number.isFinite(arr.z)) {
|
|
400
|
+
return new THREE.Vector3(arr.x, arr.y, arr.z);
|
|
401
|
+
}
|
|
402
|
+
if (fallbackVector && fallbackVector.isVector3) return fallbackVector.clone();
|
|
403
|
+
return new THREE.Vector3();
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
function quaternionFromArray(arr, fallbackQuat) {
|
|
407
|
+
if (Array.isArray(arr) && arr.length >= 4) {
|
|
408
|
+
const x = Number(arr[0]);
|
|
409
|
+
const y = Number(arr[1]);
|
|
410
|
+
const z = Number(arr[2]);
|
|
411
|
+
const w = Number(arr[3]);
|
|
412
|
+
if ([x, y, z, w].every((n) => Number.isFinite(n))) return new THREE.Quaternion(x, y, z, w);
|
|
413
|
+
}
|
|
414
|
+
if (arr && typeof arr === 'object' && Number.isFinite(arr.x) && Number.isFinite(arr.y)
|
|
415
|
+
&& Number.isFinite(arr.z) && Number.isFinite(arr.w)) {
|
|
416
|
+
return new THREE.Quaternion(arr.x, arr.y, arr.z, arr.w);
|
|
417
|
+
}
|
|
418
|
+
if (fallbackQuat && fallbackQuat.isQuaternion) return fallbackQuat.clone();
|
|
419
|
+
return new THREE.Quaternion();
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
function quaternionFromEuler(eulerArray) {
|
|
423
|
+
const euler = Array.isArray(eulerArray) ? eulerArray : [0, 0, 0];
|
|
424
|
+
const x = Number(euler[0]) || 0;
|
|
425
|
+
const y = Number(euler[1]) || 0;
|
|
426
|
+
const z = Number(euler[2]) || 0;
|
|
427
|
+
try {
|
|
428
|
+
// rotationEuler is stored in degrees for human readability
|
|
429
|
+
return new THREE.Quaternion().setFromEuler(new THREE.Euler(
|
|
430
|
+
THREE.MathUtils.degToRad(x),
|
|
431
|
+
THREE.MathUtils.degToRad(y),
|
|
432
|
+
THREE.MathUtils.degToRad(z),
|
|
433
|
+
'XYZ'
|
|
434
|
+
));
|
|
435
|
+
} catch {
|
|
436
|
+
return new THREE.Quaternion();
|
|
437
|
+
}
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
function getSolidLocalCenter(solid) {
|
|
441
|
+
try {
|
|
442
|
+
if (!solid) return new THREE.Vector3();
|
|
443
|
+
solid.updateMatrixWorld?.(true);
|
|
444
|
+
const box = new THREE.Box3().setFromObject(solid);
|
|
445
|
+
if (!box.isEmpty()) {
|
|
446
|
+
const worldCenter = box.getCenter(new THREE.Vector3());
|
|
447
|
+
const localCenter = worldCenter.clone();
|
|
448
|
+
solid.worldToLocal(localCenter);
|
|
449
|
+
return localCenter;
|
|
450
|
+
}
|
|
451
|
+
} catch { }
|
|
452
|
+
return new THREE.Vector3();
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
function getSolidWorldCenter(solid) {
|
|
456
|
+
try {
|
|
457
|
+
if (!solid) return new THREE.Vector3();
|
|
458
|
+
solid.updateMatrixWorld?.(true);
|
|
459
|
+
const box = new THREE.Box3().setFromObject(solid);
|
|
460
|
+
if (!box.isEmpty()) {
|
|
461
|
+
return box.getCenter(new THREE.Vector3());
|
|
462
|
+
}
|
|
463
|
+
} catch { }
|
|
464
|
+
try { return solid.getWorldPosition(new THREE.Vector3()); }
|
|
465
|
+
catch { return new THREE.Vector3(); }
|
|
466
|
+
}
|
|
467
|
+
|
|
468
|
+
function isFiniteVec3(vec) {
|
|
469
|
+
if (!vec || !vec.isVector3) return false;
|
|
470
|
+
return Number.isFinite(vec.x) && Number.isFinite(vec.y) && Number.isFinite(vec.z);
|
|
471
|
+
}
|
|
472
|
+
|
|
473
|
+
function transformEntryFromSnapshot(snap) {
|
|
474
|
+
if (!snap || typeof snap !== 'object') {
|
|
475
|
+
return makeTransformEntry(new THREE.Vector3(), new THREE.Quaternion(), new THREE.Vector3(1, 1, 1));
|
|
476
|
+
}
|
|
477
|
+
const position = vectorFromArray(snap.position, new THREE.Vector3());
|
|
478
|
+
const quaternion = quaternionFromArray(snap.quaternion, new THREE.Quaternion());
|
|
479
|
+
const scale = vectorFromArray(snap.scale, new THREE.Vector3(1, 1, 1));
|
|
480
|
+
return makeTransformEntry(position, quaternion, scale);
|
|
481
|
+
}
|
|
482
|
+
|
|
483
|
+
function composeTransformEntry(base, deltaPos, deltaQuat, deltaScale) {
|
|
484
|
+
const origin = base || makeTransformEntry(new THREE.Vector3(), new THREE.Quaternion(), new THREE.Vector3(1, 1, 1));
|
|
485
|
+
const pos = origin.position.clone().add(deltaPos || new THREE.Vector3());
|
|
486
|
+
const quat = origin.quaternion.clone().multiply(deltaQuat || new THREE.Quaternion());
|
|
487
|
+
const scale = origin.scale.clone().multiply(deltaScale || new THREE.Vector3(1, 1, 1));
|
|
488
|
+
return makeTransformEntry(pos, quat, scale);
|
|
489
|
+
}
|
|
490
|
+
|
|
491
|
+
function applyTransformEntryToPoint(entry, localPoint) {
|
|
492
|
+
if (!entry || !localPoint || !localPoint.isVector3) return null;
|
|
493
|
+
const matrix = new THREE.Matrix4().compose(entry.position.clone(), entry.quaternion.clone(), entry.scale.clone());
|
|
494
|
+
return localPoint.clone().applyMatrix4(matrix);
|
|
495
|
+
}
|
|
496
|
+
|
|
497
|
+
function makeTransformEntry(position, quaternion, scale) {
|
|
498
|
+
const entry = {
|
|
499
|
+
position: position.clone(),
|
|
500
|
+
quaternion: quaternion.clone(),
|
|
501
|
+
scale: scale.clone(),
|
|
502
|
+
clone() {
|
|
503
|
+
return makeTransformEntry(this.position, this.quaternion, this.scale);
|
|
504
|
+
},
|
|
505
|
+
};
|
|
506
|
+
return entry;
|
|
507
|
+
}
|