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,56 @@
|
|
|
1
|
+
import { AssemblyConstraintRegistry } from '../assemblyConstraints/AssemblyConstraintRegistry.js';
|
|
2
|
+
import { renderDialogCapturePage } from './dialogCapturePageFactory.js';
|
|
3
|
+
|
|
4
|
+
const registry = new AssemblyConstraintRegistry();
|
|
5
|
+
|
|
6
|
+
const entries = registry.list()
|
|
7
|
+
.filter(Boolean)
|
|
8
|
+
.map((ConstraintClass) => {
|
|
9
|
+
const displayName = pickName(
|
|
10
|
+
ConstraintClass.longName,
|
|
11
|
+
ConstraintClass.constraintName,
|
|
12
|
+
ConstraintClass.name,
|
|
13
|
+
'Constraint',
|
|
14
|
+
);
|
|
15
|
+
const shortName = pickName(
|
|
16
|
+
ConstraintClass.shortName,
|
|
17
|
+
ConstraintClass.constraintShortName,
|
|
18
|
+
ConstraintClass.constraintType,
|
|
19
|
+
displayName,
|
|
20
|
+
'Constraint',
|
|
21
|
+
);
|
|
22
|
+
const schema = (ConstraintClass && typeof ConstraintClass.inputParamsSchema === 'object')
|
|
23
|
+
? ConstraintClass.inputParamsSchema
|
|
24
|
+
: {};
|
|
25
|
+
const initialParams = buildConstraintParams(schema, shortName);
|
|
26
|
+
return {
|
|
27
|
+
displayName,
|
|
28
|
+
shortName,
|
|
29
|
+
captureName: displayName,
|
|
30
|
+
schema,
|
|
31
|
+
initialParams,
|
|
32
|
+
};
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
renderDialogCapturePage({
|
|
36
|
+
title: 'Assembly Constraint Dialog Reference',
|
|
37
|
+
description: 'Dialogs for built-in assembly constraints captured from the constraint registry.',
|
|
38
|
+
entries,
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
function pickName(...values) {
|
|
42
|
+
for (const value of values) {
|
|
43
|
+
if (value == null && value !== 0) continue;
|
|
44
|
+
const str = String(value).trim();
|
|
45
|
+
if (str.length) return str;
|
|
46
|
+
}
|
|
47
|
+
return 'Constraint';
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
function buildConstraintParams(schema, shortName) {
|
|
51
|
+
if (!schema || typeof schema !== 'object') return {};
|
|
52
|
+
const idKey = Object.keys(schema).find((key) => key.toLowerCase() === 'constraintid');
|
|
53
|
+
if (!idKey) return {};
|
|
54
|
+
const safe = String(shortName || 'constraint').replace(/[^a-z0-9._-]+/gi, '_');
|
|
55
|
+
return { [idKey]: `${safe}-constraint` };
|
|
56
|
+
}
|
|
@@ -0,0 +1,227 @@
|
|
|
1
|
+
import { SchemaForm } from '../UI/featureDialogs.js';
|
|
2
|
+
|
|
3
|
+
let stylesInjected = false;
|
|
4
|
+
|
|
5
|
+
const DEFAULT_DESCRIPTION = 'Dialogs are rendered live using SchemaForm. Use the automated capture script to export PNGs.';
|
|
6
|
+
|
|
7
|
+
export function renderDialogCapturePage({
|
|
8
|
+
title = 'Dialog Reference',
|
|
9
|
+
description = DEFAULT_DESCRIPTION,
|
|
10
|
+
entries = [],
|
|
11
|
+
} = {}) {
|
|
12
|
+
injectPageStyles();
|
|
13
|
+
|
|
14
|
+
const appRoot = document.getElementById('app') || document.body;
|
|
15
|
+
appRoot.classList.add('dialog-capture-page');
|
|
16
|
+
appRoot.innerHTML = '';
|
|
17
|
+
|
|
18
|
+
const header = document.createElement('header');
|
|
19
|
+
header.className = 'dialog-capture-header';
|
|
20
|
+
header.innerHTML = `
|
|
21
|
+
<h1>${escapeHtml(title)}</h1>
|
|
22
|
+
<p>${escapeHtml(description || DEFAULT_DESCRIPTION)}</p>
|
|
23
|
+
`;
|
|
24
|
+
|
|
25
|
+
const grid = document.createElement('section');
|
|
26
|
+
grid.className = 'dialog-capture-grid';
|
|
27
|
+
|
|
28
|
+
entries.forEach((entry) => {
|
|
29
|
+
const displayName = formatName(entry?.displayName, 'Dialog');
|
|
30
|
+
const shortName = formatName(entry?.shortName, displayName || 'Dialog');
|
|
31
|
+
const captureName = entry?.captureName
|
|
32
|
+
? formatName(entry.captureName, displayName)
|
|
33
|
+
: displayName;
|
|
34
|
+
|
|
35
|
+
const params = clone(entry?.initialParams) || {};
|
|
36
|
+
const schema = sanitizeSchema(entry?.schema);
|
|
37
|
+
const options = entry?.formOptions && typeof entry.formOptions === 'object'
|
|
38
|
+
? entry.formOptions
|
|
39
|
+
: undefined;
|
|
40
|
+
|
|
41
|
+
let formHost = null;
|
|
42
|
+
try {
|
|
43
|
+
const form = new SchemaForm(schema, params, options);
|
|
44
|
+
try { form.refreshFromParams?.(); } catch { /* ignore */ }
|
|
45
|
+
formHost = form.uiElement;
|
|
46
|
+
try {
|
|
47
|
+
if (formHost) {
|
|
48
|
+
formHost.style.width = '100%';
|
|
49
|
+
formHost.style.maxWidth = '100%';
|
|
50
|
+
}
|
|
51
|
+
} catch {
|
|
52
|
+
/* ignore width styling errors */
|
|
53
|
+
}
|
|
54
|
+
} catch (error) {
|
|
55
|
+
formHost = buildErrorState(error);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
const card = document.createElement('article');
|
|
59
|
+
card.className = 'dialog-card';
|
|
60
|
+
card.dataset.featureName = captureName;
|
|
61
|
+
card.dataset.featureShortName = shortName;
|
|
62
|
+
|
|
63
|
+
const head = document.createElement('div');
|
|
64
|
+
head.className = 'dialog-card-head';
|
|
65
|
+
|
|
66
|
+
const badge = document.createElement('span');
|
|
67
|
+
badge.className = 'dialog-short';
|
|
68
|
+
badge.textContent = shortName;
|
|
69
|
+
|
|
70
|
+
const titleEl = document.createElement('h2');
|
|
71
|
+
titleEl.className = 'dialog-title';
|
|
72
|
+
titleEl.textContent = displayName;
|
|
73
|
+
|
|
74
|
+
head.append(badge, titleEl);
|
|
75
|
+
|
|
76
|
+
const formWrap = document.createElement('div');
|
|
77
|
+
formWrap.className = 'dialog-form';
|
|
78
|
+
if (formHost) {
|
|
79
|
+
formWrap.appendChild(formHost);
|
|
80
|
+
} else {
|
|
81
|
+
formWrap.appendChild(buildErrorState(new Error('Form host missing')));
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
card.append(head, formWrap);
|
|
85
|
+
grid.appendChild(card);
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
appRoot.append(header, grid);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
function sanitizeSchema(schema) {
|
|
92
|
+
if (!schema || typeof schema !== 'object') return {};
|
|
93
|
+
return schema;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
function formatName(value, fallback = '') {
|
|
97
|
+
if (value == null && value !== 0) return fallback;
|
|
98
|
+
const trimmed = String(value).trim();
|
|
99
|
+
return trimmed.length ? trimmed : fallback;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
function clone(value) {
|
|
103
|
+
if (Array.isArray(value)) {
|
|
104
|
+
return value.map((item) => clone(item));
|
|
105
|
+
}
|
|
106
|
+
if (value && typeof value === 'object') {
|
|
107
|
+
const out = {};
|
|
108
|
+
for (const key of Object.keys(value)) {
|
|
109
|
+
out[key] = clone(value[key]);
|
|
110
|
+
}
|
|
111
|
+
return out;
|
|
112
|
+
}
|
|
113
|
+
return value;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
function buildErrorState(error) {
|
|
117
|
+
const container = document.createElement('div');
|
|
118
|
+
container.className = 'dialog-error';
|
|
119
|
+
container.textContent = `Failed to render: ${error?.message || error || 'Unknown error'}`;
|
|
120
|
+
return container;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
function escapeHtml(value) {
|
|
124
|
+
return String(value ?? '')
|
|
125
|
+
.replace(/&/g, '&')
|
|
126
|
+
.replace(/</g, '<')
|
|
127
|
+
.replace(/>/g, '>')
|
|
128
|
+
.replace(/"/g, '"')
|
|
129
|
+
.replace(/'/g, ''');
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
function injectPageStyles() {
|
|
133
|
+
if (stylesInjected) return;
|
|
134
|
+
stylesInjected = true;
|
|
135
|
+
const style = document.createElement('style');
|
|
136
|
+
style.textContent = `
|
|
137
|
+
:root {
|
|
138
|
+
color-scheme: dark;
|
|
139
|
+
font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
|
|
140
|
+
background: #05070d;
|
|
141
|
+
color: #e5ecff;
|
|
142
|
+
}
|
|
143
|
+
body {
|
|
144
|
+
margin: 0;
|
|
145
|
+
padding: 32px;
|
|
146
|
+
min-height: 100vh;
|
|
147
|
+
background: radial-gradient(circle at top, rgba(19,27,47,0.75), rgba(8,11,20,1) 55%);
|
|
148
|
+
display: flex;
|
|
149
|
+
justify-content: center;
|
|
150
|
+
}
|
|
151
|
+
.dialog-capture-page {
|
|
152
|
+
width: min(1040px, 100%);
|
|
153
|
+
}
|
|
154
|
+
.dialog-capture-header {
|
|
155
|
+
text-align: center;
|
|
156
|
+
margin-bottom: 32px;
|
|
157
|
+
}
|
|
158
|
+
.dialog-capture-header h1 {
|
|
159
|
+
margin: 0 0 12px 0;
|
|
160
|
+
font-size: clamp(26px, 4vw, 38px);
|
|
161
|
+
font-weight: 600;
|
|
162
|
+
letter-spacing: -0.01em;
|
|
163
|
+
}
|
|
164
|
+
.dialog-capture-header p {
|
|
165
|
+
margin: 0;
|
|
166
|
+
color: #94a3b8;
|
|
167
|
+
font-size: 14px;
|
|
168
|
+
}
|
|
169
|
+
.dialog-capture-grid {
|
|
170
|
+
display: flex;
|
|
171
|
+
flex-direction: column;
|
|
172
|
+
gap: 32px;
|
|
173
|
+
padding-bottom: 80px;
|
|
174
|
+
}
|
|
175
|
+
.dialog-card {
|
|
176
|
+
background: rgba(13,17,27,0.92);
|
|
177
|
+
border-radius: 18px;
|
|
178
|
+
border: 1px solid rgba(71,85,105,0.42);
|
|
179
|
+
padding: 24px;
|
|
180
|
+
box-shadow: 0 20px 40px rgba(0,0,0,0.45);
|
|
181
|
+
display: flex;
|
|
182
|
+
flex-direction: column;
|
|
183
|
+
gap: 20px;
|
|
184
|
+
}
|
|
185
|
+
.dialog-card-head {
|
|
186
|
+
display: flex;
|
|
187
|
+
align-items: baseline;
|
|
188
|
+
gap: 14px;
|
|
189
|
+
}
|
|
190
|
+
.dialog-short {
|
|
191
|
+
display: inline-flex;
|
|
192
|
+
align-items: center;
|
|
193
|
+
justify-content: center;
|
|
194
|
+
min-width: 64px;
|
|
195
|
+
padding: 4px 14px;
|
|
196
|
+
border-radius: 999px;
|
|
197
|
+
border: 1px solid rgba(96, 165, 250, 0.45);
|
|
198
|
+
background: rgba(51, 65, 85, 0.45);
|
|
199
|
+
color: #cbd5ff;
|
|
200
|
+
font-weight: 600;
|
|
201
|
+
letter-spacing: 0.08em;
|
|
202
|
+
font-size: 13px;
|
|
203
|
+
text-transform: uppercase;
|
|
204
|
+
}
|
|
205
|
+
.dialog-title {
|
|
206
|
+
margin: 0;
|
|
207
|
+
font-size: 20px;
|
|
208
|
+
font-weight: 600;
|
|
209
|
+
color: #f8fafc;
|
|
210
|
+
}
|
|
211
|
+
.dialog-form {
|
|
212
|
+
background: #0b0f16;
|
|
213
|
+
width: 300px;
|
|
214
|
+
border-radius: 16px;
|
|
215
|
+
padding: 20px;
|
|
216
|
+
border: 1px solid rgba(59,77,109,0.45);
|
|
217
|
+
box-shadow: inset 0 0 0 1px rgba(71,85,105,0.18);
|
|
218
|
+
box-sizing: border-box;
|
|
219
|
+
}
|
|
220
|
+
.dialog-error {
|
|
221
|
+
font-size: 13px;
|
|
222
|
+
color: #f87171;
|
|
223
|
+
line-height: 1.4;
|
|
224
|
+
}
|
|
225
|
+
`;
|
|
226
|
+
document.head.appendChild(style);
|
|
227
|
+
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { FeatureRegistry } from '../FeatureRegistry.js';
|
|
2
|
+
import { renderDialogCapturePage } from './dialogCapturePageFactory.js';
|
|
3
|
+
|
|
4
|
+
const registry = new FeatureRegistry();
|
|
5
|
+
|
|
6
|
+
const entries = registry.features
|
|
7
|
+
.filter(Boolean)
|
|
8
|
+
.map((FeatureClass) => {
|
|
9
|
+
const featureName = pickName(FeatureClass.longName, FeatureClass.featureName, FeatureClass.name, 'Feature');
|
|
10
|
+
const shortName = pickName(FeatureClass.shortName, FeatureClass.featureShortName, featureName, 'Feature');
|
|
11
|
+
const schema = (FeatureClass && typeof FeatureClass.inputParamsSchema === 'object')
|
|
12
|
+
? FeatureClass.inputParamsSchema
|
|
13
|
+
: {};
|
|
14
|
+
const initialParams = buildFeatureParams(schema, shortName);
|
|
15
|
+
return {
|
|
16
|
+
displayName: featureName,
|
|
17
|
+
shortName,
|
|
18
|
+
captureName: featureName,
|
|
19
|
+
schema,
|
|
20
|
+
initialParams,
|
|
21
|
+
};
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
renderDialogCapturePage({
|
|
25
|
+
title: 'Feature Dialog Reference',
|
|
26
|
+
description: 'Dialogs are rendered live using SchemaForm. Use the automated capture script to export PNGs.',
|
|
27
|
+
entries,
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
function pickName(...values) {
|
|
31
|
+
for (const value of values) {
|
|
32
|
+
if (value == null && value !== 0) continue;
|
|
33
|
+
const str = String(value).trim();
|
|
34
|
+
if (str.length) return str;
|
|
35
|
+
}
|
|
36
|
+
return 'Feature';
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
function buildFeatureParams(schema, shortName) {
|
|
40
|
+
if (!schema || typeof schema !== 'object') return {};
|
|
41
|
+
let key = null;
|
|
42
|
+
if (Object.prototype.hasOwnProperty.call(schema, 'id')) key = 'id';
|
|
43
|
+
else if (Object.prototype.hasOwnProperty.call(schema, 'featureID')) key = 'featureID';
|
|
44
|
+
if (!key) return {};
|
|
45
|
+
const fallback = String(shortName || 'feature').replace(/[^a-z0-9._-]+/gi, '_');
|
|
46
|
+
return { [key]: `${fallback}-capture` };
|
|
47
|
+
}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { annotationRegistry } from '../UI/pmi/AnnotationRegistry.js';
|
|
2
|
+
import { renderDialogCapturePage } from './dialogCapturePageFactory.js';
|
|
3
|
+
|
|
4
|
+
const handlers = annotationRegistry.list();
|
|
5
|
+
|
|
6
|
+
const entries = handlers
|
|
7
|
+
.filter(Boolean)
|
|
8
|
+
.map((Handler) => {
|
|
9
|
+
const displayName = pickName(
|
|
10
|
+
Handler.longName,
|
|
11
|
+
Handler.title,
|
|
12
|
+
Handler.featureName,
|
|
13
|
+
Handler.name,
|
|
14
|
+
'Annotation',
|
|
15
|
+
);
|
|
16
|
+
const shortName = pickName(
|
|
17
|
+
Handler.shortName,
|
|
18
|
+
Handler.featureShortName,
|
|
19
|
+
Handler.type,
|
|
20
|
+
displayName,
|
|
21
|
+
'Annotation',
|
|
22
|
+
);
|
|
23
|
+
const schema = (Handler && typeof Handler.inputParamsSchema === 'object')
|
|
24
|
+
? Handler.inputParamsSchema
|
|
25
|
+
: {};
|
|
26
|
+
const initialParams = buildAnnotationParams(schema, shortName);
|
|
27
|
+
return {
|
|
28
|
+
displayName,
|
|
29
|
+
shortName,
|
|
30
|
+
captureName: displayName,
|
|
31
|
+
schema,
|
|
32
|
+
initialParams,
|
|
33
|
+
};
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
renderDialogCapturePage({
|
|
37
|
+
title: 'PMI Annotation Dialog Reference',
|
|
38
|
+
description: 'PMI annotation dialogs rendered directly from the annotation registry.',
|
|
39
|
+
entries,
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
function pickName(...values) {
|
|
43
|
+
for (const value of values) {
|
|
44
|
+
if (value == null && value !== 0) continue;
|
|
45
|
+
const str = String(value).trim();
|
|
46
|
+
if (str.length) return str;
|
|
47
|
+
}
|
|
48
|
+
return 'Annotation';
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
function buildAnnotationParams(schema, shortName) {
|
|
52
|
+
if (!schema || typeof schema !== 'object') return {};
|
|
53
|
+
const idKey = Object.keys(schema).find((key) => {
|
|
54
|
+
const lower = key.toLowerCase();
|
|
55
|
+
return lower === 'id' || lower === 'annotationid';
|
|
56
|
+
});
|
|
57
|
+
if (!idKey) return {};
|
|
58
|
+
const safe = String(shortName || 'annotation').replace(/[^a-z0-9._-]+/gi, '_');
|
|
59
|
+
return { [idKey]: `${safe}-annotation` };
|
|
60
|
+
}
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import { BREP } from "../BREP/BREP.js";
|
|
2
|
+
import { Line2, LineGeometry, LineMaterial } from "three/examples/jsm/Addons.js";
|
|
3
|
+
|
|
4
|
+
const THREE = BREP.THREE;
|
|
5
|
+
|
|
6
|
+
export const DEFAULT_AXIS_HELPER_PX = 70;
|
|
7
|
+
|
|
8
|
+
const DEFAULT_AXIS_COLORS = {
|
|
9
|
+
x: 0xff4d4d,
|
|
10
|
+
y: 0x4dff4d,
|
|
11
|
+
z: 0x4d7dff,
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
function buildAxisLine({
|
|
15
|
+
axis,
|
|
16
|
+
dir,
|
|
17
|
+
color,
|
|
18
|
+
name,
|
|
19
|
+
selectable,
|
|
20
|
+
lineWidth,
|
|
21
|
+
depthTest,
|
|
22
|
+
opacity,
|
|
23
|
+
renderOrder,
|
|
24
|
+
}) {
|
|
25
|
+
const geom = new LineGeometry();
|
|
26
|
+
geom.setPositions([0, 0, 0, dir[0], dir[1], dir[2]]);
|
|
27
|
+
const mat = new LineMaterial({
|
|
28
|
+
color,
|
|
29
|
+
linewidth: lineWidth,
|
|
30
|
+
transparent: true,
|
|
31
|
+
opacity,
|
|
32
|
+
dashed: false,
|
|
33
|
+
worldUnits: false,
|
|
34
|
+
depthTest,
|
|
35
|
+
depthWrite: false,
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
let line = null;
|
|
39
|
+
if (selectable) {
|
|
40
|
+
line = new BREP.Edge(geom);
|
|
41
|
+
line.material = mat;
|
|
42
|
+
} else {
|
|
43
|
+
line = new Line2(geom, mat);
|
|
44
|
+
line.type = "AXIS_HELPER";
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
line.name = `${name}:${axis}`;
|
|
48
|
+
line.renderOrder = renderOrder;
|
|
49
|
+
line.userData = line.userData || {};
|
|
50
|
+
line.userData.axisHelperAxis = axis;
|
|
51
|
+
line.userData.__baseMaterial = mat;
|
|
52
|
+
line.userData.__defaultMaterial = mat;
|
|
53
|
+
line.userData.polylineLocal = [
|
|
54
|
+
[0, 0, 0],
|
|
55
|
+
[dir[0], dir[1], dir[2]],
|
|
56
|
+
];
|
|
57
|
+
line.userData.polylineWorld = false;
|
|
58
|
+
return line;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
export function createAxisHelperGroup(options = {}) {
|
|
62
|
+
const {
|
|
63
|
+
name = "AxisHelper",
|
|
64
|
+
selectable = false,
|
|
65
|
+
axisHelperPx = DEFAULT_AXIS_HELPER_PX,
|
|
66
|
+
lineWidth = 2,
|
|
67
|
+
depthTest = false,
|
|
68
|
+
opacity = 1,
|
|
69
|
+
renderOrder = 1000,
|
|
70
|
+
colors = DEFAULT_AXIS_COLORS,
|
|
71
|
+
} = options;
|
|
72
|
+
|
|
73
|
+
const group = new THREE.Group();
|
|
74
|
+
group.name = name;
|
|
75
|
+
group.userData = group.userData || {};
|
|
76
|
+
group.userData.axisHelper = true;
|
|
77
|
+
group.userData.axisHelperPx = Number.isFinite(axisHelperPx)
|
|
78
|
+
? axisHelperPx
|
|
79
|
+
: DEFAULT_AXIS_HELPER_PX;
|
|
80
|
+
group.userData.axisHelperCompensateScale = true;
|
|
81
|
+
group.userData.excludeFromFit = true;
|
|
82
|
+
|
|
83
|
+
const base = {
|
|
84
|
+
name,
|
|
85
|
+
selectable,
|
|
86
|
+
lineWidth,
|
|
87
|
+
depthTest,
|
|
88
|
+
opacity,
|
|
89
|
+
renderOrder,
|
|
90
|
+
};
|
|
91
|
+
|
|
92
|
+
group.add(
|
|
93
|
+
buildAxisLine({ axis: "X", dir: [1, 0, 0], color: colors.x, ...base }),
|
|
94
|
+
buildAxisLine({ axis: "Y", dir: [0, 1, 0], color: colors.y, ...base }),
|
|
95
|
+
buildAxisLine({ axis: "Z", dir: [0, 0, 1], color: colors.z, ...base }),
|
|
96
|
+
);
|
|
97
|
+
|
|
98
|
+
return group;
|
|
99
|
+
}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
// deepClone.js
|
|
2
|
+
// Shared deep clone utility for plain objects, arrays, Maps/Sets, and simple primitives.
|
|
3
|
+
|
|
4
|
+
function clonePlainObject(obj) {
|
|
5
|
+
const out = {};
|
|
6
|
+
for (const key of Object.keys(obj)) {
|
|
7
|
+
out[key] = deepClone(obj[key]);
|
|
8
|
+
}
|
|
9
|
+
return out;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
function cloneMap(map) {
|
|
13
|
+
const out = new Map();
|
|
14
|
+
for (const [key, value] of map.entries()) {
|
|
15
|
+
out.set(key, deepClone(value));
|
|
16
|
+
}
|
|
17
|
+
return out;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
function cloneSet(set) {
|
|
21
|
+
const out = new Set();
|
|
22
|
+
for (const value of set.values()) {
|
|
23
|
+
out.add(deepClone(value));
|
|
24
|
+
}
|
|
25
|
+
return out;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
function cloneTypedArray(value) {
|
|
29
|
+
if (typeof value.slice === 'function') {
|
|
30
|
+
try { return value.slice(); } catch { /* fallthrough */ }
|
|
31
|
+
}
|
|
32
|
+
const Ctor = value.constructor;
|
|
33
|
+
try { return new Ctor(value); } catch { return value; }
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export function deepClone(value) {
|
|
37
|
+
if (value == null) return value;
|
|
38
|
+
|
|
39
|
+
if (Array.isArray(value)) {
|
|
40
|
+
return value.map((item) => deepClone(item));
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
if (value instanceof Date) {
|
|
44
|
+
return new Date(value.getTime());
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
if (value instanceof Map) {
|
|
48
|
+
return cloneMap(value);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
if (value instanceof Set) {
|
|
52
|
+
return cloneSet(value);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
if (ArrayBuffer.isView(value) && !(value instanceof DataView)) {
|
|
56
|
+
return cloneTypedArray(value);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
if (typeof value === 'object') {
|
|
60
|
+
const proto = Object.getPrototypeOf(value);
|
|
61
|
+
if (proto === Object.prototype || proto === null) {
|
|
62
|
+
return clonePlainObject(value);
|
|
63
|
+
}
|
|
64
|
+
// Fall back to identity for non-plain objects (class instances, DOM nodes, etc.)
|
|
65
|
+
return value;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
return value;
|
|
69
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
export function deriveTolerance(polys, baseTol = 1e-5) {
|
|
2
|
+
if (!Array.isArray(polys) || polys.length === 0) return baseTol;
|
|
3
|
+
if (baseTol !== 1e-5) return baseTol;
|
|
4
|
+
|
|
5
|
+
let minX = Infinity, minY = Infinity, minZ = Infinity;
|
|
6
|
+
let maxX = -Infinity, maxY = -Infinity, maxZ = -Infinity;
|
|
7
|
+
const segLens = [];
|
|
8
|
+
for (const p of polys) {
|
|
9
|
+
for (let i = 0; i < p.length; i++) {
|
|
10
|
+
const v = p[i];
|
|
11
|
+
if (v[0] < minX) minX = v[0]; if (v[0] > maxX) maxX = v[0];
|
|
12
|
+
if (v[1] < minY) minY = v[1]; if (v[1] > maxY) maxY = v[1];
|
|
13
|
+
if (v[2] < minZ) minZ = v[2]; if (v[2] > maxZ) maxZ = v[2];
|
|
14
|
+
if (i > 0) {
|
|
15
|
+
const a = p[i - 1];
|
|
16
|
+
const dx = a[0] - v[0], dy = a[1] - v[1], dz = a[2] - v[2];
|
|
17
|
+
segLens.push(Math.hypot(dx, dy, dz));
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
const dx = maxX - minX, dy = maxY - minY, dz = maxZ - minZ;
|
|
22
|
+
const diag = Math.hypot(dx, dy, dz) || 1;
|
|
23
|
+
segLens.sort((a, b) => a - b);
|
|
24
|
+
const med = segLens.length ? segLens[(segLens.length >> 1)] : diag;
|
|
25
|
+
return Math.min(Math.max(1e-5, diag * 1e-3), med * 0.1);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export function createQuantizer(tol) {
|
|
29
|
+
const t = tol || 1e-5;
|
|
30
|
+
const q = (v) => [
|
|
31
|
+
Math.round(v[0] / t) * t,
|
|
32
|
+
Math.round(v[1] / t) * t,
|
|
33
|
+
Math.round(v[2] / t) * t,
|
|
34
|
+
];
|
|
35
|
+
const k = (v) => `${v[0]},${v[1]},${v[2]}`;
|
|
36
|
+
return { q, k };
|
|
37
|
+
}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import * as THREE_NS from 'three';
|
|
2
|
+
|
|
3
|
+
// Utility: compose a Matrix4 from TRS values where rotationEuler is in degrees.
|
|
4
|
+
// Accepts an optional THREE-like namespace; defaults to imported three.
|
|
5
|
+
export function composeTrsMatrixDeg(trs, THREE = THREE_NS) {
|
|
6
|
+
const p = Array.isArray(trs?.position) ? trs.position : [0, 0, 0];
|
|
7
|
+
const r = Array.isArray(trs?.rotationEuler) ? trs.rotationEuler : [0, 0, 0];
|
|
8
|
+
const s = Array.isArray(trs?.scale) ? trs.scale : [1, 1, 1];
|
|
9
|
+
const pos = new THREE.Vector3(
|
|
10
|
+
Number(p[0] || 0),
|
|
11
|
+
Number(p[1] || 0),
|
|
12
|
+
Number(p[2] || 0)
|
|
13
|
+
);
|
|
14
|
+
const eul = new THREE.Euler(
|
|
15
|
+
THREE.MathUtils.degToRad(Number(r[0] || 0)),
|
|
16
|
+
THREE.MathUtils.degToRad(Number(r[1] || 0)),
|
|
17
|
+
THREE.MathUtils.degToRad(Number(r[2] || 0)),
|
|
18
|
+
'XYZ'
|
|
19
|
+
);
|
|
20
|
+
const quat = new THREE.Quaternion().setFromEuler(eul);
|
|
21
|
+
const scl = new THREE.Vector3(
|
|
22
|
+
Number(s[0] || 1),
|
|
23
|
+
Number(s[1] || 1),
|
|
24
|
+
Number(s[2] || 1)
|
|
25
|
+
);
|
|
26
|
+
return new THREE.Matrix4().compose(pos, quat, scl);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
// Compose absolute transform matrix from a base (pos, quaternion, scale arrays)
|
|
30
|
+
// and a delta TRS where rotationEuler is degrees.
|
|
31
|
+
export function combineBaseWithDeltaDeg(base, delta, THREE = THREE_NS) {
|
|
32
|
+
const basePos = new THREE.Vector3(
|
|
33
|
+
Number(base?.position?.[0] || 0),
|
|
34
|
+
Number(base?.position?.[1] || 0),
|
|
35
|
+
Number(base?.position?.[2] || 0)
|
|
36
|
+
);
|
|
37
|
+
const baseQuat = new THREE.Quaternion().fromArray(
|
|
38
|
+
Array.isArray(base?.quaternion) && base.quaternion.length >= 4
|
|
39
|
+
? base.quaternion
|
|
40
|
+
: [0, 0, 0, 1]
|
|
41
|
+
);
|
|
42
|
+
const baseScale = new THREE.Vector3(
|
|
43
|
+
Number(base?.scale?.[0] || 1),
|
|
44
|
+
Number(base?.scale?.[1] || 1),
|
|
45
|
+
Number(base?.scale?.[2] || 1)
|
|
46
|
+
);
|
|
47
|
+
const Mbase = new THREE.Matrix4().compose(basePos, baseQuat, baseScale);
|
|
48
|
+
const Mdelta = composeTrsMatrixDeg(delta, THREE);
|
|
49
|
+
return Mbase.multiply(Mdelta);
|
|
50
|
+
}
|
|
51
|
+
|