forgecad 0.9.14 → 0.9.16
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 +6 -4
- package/README.md +8 -4
- package/dist/assets/{AdminPage-eWGs2K6H.js → AdminPage-CXvls4-J.js} +2 -2
- package/dist/assets/{BenchmarkPage-CTrLKfpo.js → BenchmarkPage-B27zk8xL.js} +4 -15
- package/dist/assets/{BlogPage-5nPesyds.js → BlogPage-CMAVvgQL.js} +2 -2
- package/dist/assets/{DocsPage-C4Y3nbYc.js → DocsPage-knf4I4h7.js} +9 -3
- package/dist/assets/EditorApp-BHMQlJ-D.js +14686 -0
- package/dist/assets/{EditorApp-BAnckbsk.css → EditorApp-BpjZgzk0.css} +846 -0
- package/dist/assets/{EmbedViewer-C8fB4n5U.js → EmbedViewer-D7ZGlFjx.js} +3 -3
- package/dist/assets/{LandingPageProofDriven-jSz0LaMM.js → LandingPageProofDriven-CnevhTE8.js} +36 -38
- package/dist/assets/LegalPage-BPTUmqeg.js +39 -0
- package/dist/assets/LegalPage-BRlScr9A.css +91 -0
- package/dist/assets/{PricingPage-B83B90zh.js → PricingPage-B0D4goG_.js} +19 -19
- package/dist/assets/{PricingPage-BMedqFef.css → PricingPage-BPF6HKyO.css} +25 -0
- package/dist/assets/{SettingsPage-DY889pcu.js → SettingsPage-CFF-UgjI.js} +2 -2
- package/dist/assets/app-CE3sYcV7.css +3890 -0
- package/dist/assets/{app-bEww1ic4.js → app-T0pDcSX4.js} +3382 -1069
- package/dist/assets/cli/{render-Cho2uKG_.js → render-C5pcIISc.js} +477 -29
- package/dist/assets/{constructionHistoryWorker-HYwzJY4m.js → constructionHistoryWorker-Ba2Hm58b.js} +928 -243
- package/dist/assets/{evalWorker-CjQwJSE-.js → evalWorker-vkx310U2.js} +8883 -6040
- package/dist/assets/{forgecad_geometry-CH2nvuLA.js → forgecad_geometry-Dgceylq9.js} +43 -1
- package/dist/assets/forgecad_geometry_bg-dD4RNQF1.wasm +0 -0
- package/dist/assets/{inspectWorker-DeRnMVv1.js → inspectWorker-BuTJDVX6.js} +1179 -273
- package/dist/assets/{javascript-70-4uGcz.js → javascript-1kQXfVaz.js} +1 -1
- package/dist/assets/{targets-D6PWsv6X.js → jointPose-B_Cgedn9.js} +71 -3
- package/dist/assets/landing-proof-driven-DiGqdtWa.js +18 -0
- package/dist/assets/{landing-proof-driven-oFYW6mjz.css → landing-proof-driven-ORyigZ6p.css} +13 -7
- package/dist/assets/legalContent-ZfFGMmi4.js +251 -0
- package/dist/assets/{manifold-rmfAcdwF.js → manifold-BWgsjmAM.js} +1 -1
- package/dist/assets/{manifold-uRzgk5O8.js → manifold-D6IFSkhH.js} +2 -2
- package/dist/assets/{manifold-CG9Fokx-.js → manifold-rZexZI0G.js} +1 -1
- package/dist/assets/{reportWorker-4cW_ZpoS.js → reportWorker-0AGij1Ru.js} +8659 -12771
- package/dist/assets/{scalar-sampling-budget-CfDiFvh7.js → scalar-sampling-budget-J5cuzxT1.js} +8050 -6203
- package/dist/assets/{scanProxyWorker-Bs2TDgLw.js → scanProxyWorker-Vl4Wxa1y.js} +50 -6
- package/dist/assets/{solver-DuJAO8S6.js → solver-BZ9LPTHs.js} +1 -1
- package/dist/assets/solver_bg-DAHZJ_rw.wasm +0 -0
- package/dist/assets/{vendor-react-Da3A2QmU.js → vendor-react-6j1Kke-Y.js} +6 -5
- package/dist/cli/render.html +1 -1
- package/dist/docs/index.html +2 -2
- package/dist/docs-raw/AI/ai-native-cad.md +50 -0
- package/dist/docs-raw/AI/usage.md +5 -12
- package/dist/docs-raw/CLI.md +34 -10
- package/dist/docs-raw/component-model.md +27 -11
- package/dist/docs-raw/generated/assembly.md +374 -187
- package/dist/docs-raw/generated/concepts.md +245 -237
- package/dist/docs-raw/generated/core.md +283 -6
- package/dist/docs-raw/generated/curves.md +274 -361
- package/dist/docs-raw/generated/lib.md +9 -19
- package/dist/docs-raw/generated/output.md +29 -4
- package/dist/docs-raw/generated/runtime-names.md +49 -0
- package/dist/docs-raw/generated/sdf.md +31 -0
- package/dist/docs-raw/generated/sheet-metal.md +9 -0
- package/dist/docs-raw/generated/sketch.md +44 -1
- package/dist/docs-raw/generated/viewport.md +11 -3
- package/dist/docs-raw/guides/coordinate-system.md +20 -16
- package/dist/docs-raw/guides/geometry-conventions.md +2 -2
- package/dist/docs-raw/guides/inspection-bundles.md +2 -1
- package/dist/docs-raw/guides/joint-design.md +24 -0
- package/dist/docs-raw/guides/positioning.md +13 -3
- package/dist/docs-raw/legal/privacy.md +63 -0
- package/dist/docs-raw/legal/software-license.md +55 -0
- package/dist/docs-raw/legal/terms.md +87 -0
- package/dist/docs-raw/skills/forgecad-3d-reconstruction.md +1 -1
- package/dist/docs-raw/skills/forgecad-blockout-model.md +1 -1
- package/dist/docs-raw/skills/forgecad-component-model.md +11 -2
- package/dist/docs-raw/skills/forgecad-high-level-spec.md +1 -1
- package/dist/docs-raw/skills/forgecad-image-replicator.md +8 -8
- package/dist/docs-raw/skills/forgecad-lld.md +1 -1
- package/dist/docs-raw/skills/forgecad-make-a-model.md +40 -39
- package/dist/docs-raw/skills/forgecad-model-grader.md +2 -2
- package/dist/docs-raw/skills/forgecad-prepare-prompt.md +2 -2
- package/dist/docs-raw/skills/forgecad-project.md +3 -1
- package/dist/docs-raw/skills/forgecad-reconstruction-benchmark.md +1 -1
- package/dist/docs-raw/skills/forgecad-render-inspect.md +4 -2
- package/dist/docs-raw/skills/forgecad-visual-spec.md +1 -1
- package/dist/docs-raw/skills/forgecad.md +4 -3
- package/dist/docs-raw/welcome.md +2 -0
- package/dist/index.html +40 -12
- package/dist/llms.txt +8 -0
- package/dist/site.webmanifest +1 -1
- package/dist/sitemap.xml +49 -13
- package/dist-cli/{check-compiler-U5SOPN7X.js → check-compiler-SYQ2PWOB.js} +1 -2
- package/dist-cli/{check-query-propagation-XOKNSSYU.js → check-query-propagation-HIAGV62W.js} +1 -2
- package/dist-cli/{chunk-EXWGNL6K.js → chunk-SPZE3DUY.js} +20659 -17930
- package/dist-cli/forgecad.js +3568 -1250
- package/dist-cli/{forgecad_geometry-GYVNKPIE.js → forgecad_geometry-QOQIIP53.js} +42 -1
- package/dist-cli/forgecad_geometry_bg.wasm +0 -0
- package/dist-cli/{solver-46FFSK2U.js → solver-OK4HECRH.js} +0 -1
- package/dist-cli/solver_bg.wasm +0 -0
- package/dist-skill/CONTEXT.md +1192 -725
- package/dist-skill/SKILL.md +3 -2
- package/dist-skill/docs/API/core/concepts.md +64 -1
- package/dist-skill/docs/CLI.md +34 -10
- package/dist-skill/docs/generated/assembly.md +339 -213
- package/dist-skill/docs/generated/core.md +283 -6
- package/dist-skill/docs/generated/curves.md +272 -362
- package/dist-skill/docs/generated/lib.md +9 -19
- package/dist-skill/docs/generated/output.md +29 -4
- package/dist-skill/docs/generated/runtime-names.md +40 -0
- package/dist-skill/docs/generated/sdf.md +31 -0
- package/dist-skill/docs/generated/sheet-metal.md +9 -0
- package/dist-skill/docs/generated/sketch.md +44 -2
- package/dist-skill/docs/generated/viewport.md +2 -87
- package/dist-skill/docs/guides/coordinate-system.md +20 -16
- package/dist-skill/docs/guides/geometry-conventions.md +2 -2
- package/dist-skill/docs/guides/inspection-bundles.md +2 -1
- package/dist-skill/docs/guides/joint-design.md +24 -0
- package/dist-skill/docs/guides/positioning.md +13 -3
- package/dist-skill/library/forgecad-component-model/SKILL.md +10 -1
- package/dist-skill/library/forgecad-image-replicator/SKILL.md +6 -6
- package/dist-skill/library/forgecad-image-replicator/scripts/compare_images.py +166 -0
- package/dist-skill/library/forgecad-make-a-model/SKILL.md +39 -38
- package/dist-skill/library/forgecad-model-grader/SKILL.md +1 -1
- package/dist-skill/library/forgecad-prepare-prompt/SKILL.md +1 -1
- package/dist-skill/library/forgecad-project/SKILL.md +2 -0
- package/dist-skill/library/forgecad-render-inspect/SKILL.md +3 -1
- package/examples/api/assembly-kinematics-foundation.forge.js +65 -0
- package/examples/api/assembly-kinematics-four-bar.forge.js +115 -0
- package/examples/api/assembly-kinematics-limb.forge.js +116 -0
- package/examples/api/connector-frame-rig-chain.forge.js +102 -0
- package/examples/api/exact-sheet-shell-assembly.forge.js +0 -2
- package/examples/api/exact-surface-studio.forge.js +6 -8
- package/examples/api/helix-basics.forge.js +8 -8
- package/examples/api/lean-foundations/README.md +12 -0
- package/examples/api/lean-foundations/curve-blend-exact.forge.js +22 -0
- package/examples/api/lean-foundations/curve-fit-interpolation.forge.js +18 -0
- package/examples/api/lean-foundations/curve-helix-canonicalization.forge.js +27 -0
- package/examples/api/lean-foundations/curve-route-canonicalization.forge.js +16 -0
- package/examples/api/lean-foundations/curve-trim-reverse.forge.js +24 -0
- package/examples/api/lean-foundations/exact-curve-arc.forge.js +36 -0
- package/examples/api/mixed-edge-finishes-proof.forge.js +8 -11
- package/examples/api/route3d-elbow.forge.js +71 -0
- package/examples/api/transition-curves.forge.js +44 -15
- package/examples/api/variable-sweep-test.forge.js +3 -1
- package/examples/api/y-blend-corner-showcase.forge.js +0 -2
- package/examples/generative/coral-vase.forge.js +1 -1
- package/examples/nurbs-tube.forge.js +1 -1
- package/package.json +17 -13
- package/dist/assets/EditorApp-lXv53A1m.js +0 -13610
- package/dist/assets/app-CsHnaBWt.css +0 -1789
- package/dist/assets/forgecad_geometry_bg-C5_E9Oa9.wasm +0 -0
- package/dist/assets/solver_bg-CWvv4lnN.wasm +0 -0
- package/dist/docs-raw/API/README.md +0 -16
- package/dist/docs-raw/API/core/concepts.md +0 -118
- package/dist/docs-raw/INDEX.md +0 -138
- package/dist/docs-raw/RELEASING.md +0 -87
- package/dist/docs-raw/agent-native-api.md +0 -27
- package/dist/docs-raw/beta-deployment.md +0 -304
- package/dist/docs-raw/beta-operations.md +0 -325
- package/dist/docs-raw/blueprint-first.md +0 -145
- package/dist/docs-raw/cli-monetization.md +0 -112
- package/dist/docs-raw/coding-best-practices.md +0 -120
- package/dist/docs-raw/coding.md +0 -340
- package/dist/docs-raw/deployment.md +0 -374
- package/dist/docs-raw/guides/skill-maintenance.md +0 -161
- package/dist/docs-raw/guides/surface-members.md +0 -82
- package/dist/docs-raw/harbor-cli.md +0 -854
- package/dist/docs-raw/internals/backend-vocabulary.md +0 -35
- package/dist/docs-raw/internals/compiler.md +0 -307
- package/dist/docs-raw/internals/constraint-solver-quality.md +0 -161
- package/dist/docs-raw/internals/constraint-solver.md +0 -176
- package/dist/docs-raw/internals/shape-from-slices.md +0 -152
- package/dist/docs-raw/internals/sketch-2d-pipeline.md +0 -108
- package/dist/docs-raw/platform/admin.md +0 -45
- package/dist/docs-raw/platform/architecture.md +0 -82
- package/dist/docs-raw/platform/auth.md +0 -139
- package/dist/docs-raw/platform/email.md +0 -67
- package/dist/docs-raw/platform/google-oauth-setup.md +0 -88
- package/dist/docs-raw/platform/observability.md +0 -197
- package/dist/docs-raw/platform/projects.md +0 -111
- package/dist/docs-raw/platform/sharing.md +0 -90
- package/dist/docs-raw/product/README.md +0 -39
- package/dist/docs-raw/product/api-as-product-language.md +0 -13
- package/dist/docs-raw/product/business-model.md +0 -15
- package/dist/docs-raw/product/competitive-positioning.md +0 -17
- package/dist/docs-raw/product/creative-manufacturing.md +0 -15
- package/dist/docs-raw/product/founder-story.md +0 -11
- package/dist/docs-raw/product/manufacturing-workflows.md +0 -15
- package/dist/docs-raw/product/onboarding-first-experience.md +0 -256
- package/dist/docs-raw/product/product-loop.md +0 -17
- package/dist/docs-raw/product/strategic-decisions.md +0 -22
- package/dist/docs-raw/product/user-outreach-email-templates.md +0 -161
- package/dist/docs-raw/product/user-segments.md +0 -15
- package/dist/docs-raw/product/vision.md +0 -26
- package/dist/docs-raw/rl-environments.md +0 -350
- package/dist/docs-raw/runbook.md +0 -611
- package/dist-cli/check-compiler-U5SOPN7X.js.map +0 -1
- package/dist-cli/check-query-propagation-XOKNSSYU.js.map +0 -1
- package/dist-cli/chunk-EXWGNL6K.js.map +0 -1
- package/dist-cli/forgecad.js.map +0 -1
- package/dist-cli/forgecad_geometry-GYVNKPIE.js.map +0 -1
- package/dist-cli/solver-46FFSK2U.js.map +0 -1
- package/dist-skill/SKILL-dev.md +0 -145
- package/dist-skill/docs-dev/API/core/concepts.md +0 -118
- package/dist-skill/docs-dev/CLI.md +0 -677
- package/dist-skill/docs-dev/agent-native-api.md +0 -27
- package/dist-skill/docs-dev/blueprint-first.md +0 -145
- package/dist-skill/docs-dev/coding-best-practices.md +0 -120
- package/dist-skill/docs-dev/coding.md +0 -340
- package/dist-skill/docs-dev/component-model.md +0 -164
- package/dist-skill/docs-dev/generated/assembly.md +0 -794
- package/dist-skill/docs-dev/generated/core.md +0 -2117
- package/dist-skill/docs-dev/generated/curves.md +0 -2583
- package/dist-skill/docs-dev/generated/lib.md +0 -169
- package/dist-skill/docs-dev/generated/output.md +0 -247
- package/dist-skill/docs-dev/generated/sdf.md +0 -446
- package/dist-skill/docs-dev/generated/sheet-metal.md +0 -504
- package/dist-skill/docs-dev/generated/sketch.md +0 -1811
- package/dist-skill/docs-dev/generated/viewport.md +0 -585
- package/dist-skill/docs-dev/generated/wood.md +0 -108
- package/dist-skill/docs-dev/guides/coordinate-system.md +0 -46
- package/dist-skill/docs-dev/guides/geometry-conventions.md +0 -52
- package/dist-skill/docs-dev/guides/inspection-bundles.md +0 -485
- package/dist-skill/docs-dev/guides/joint-design.md +0 -78
- package/dist-skill/docs-dev/guides/modeling-recipes.md +0 -78
- package/dist-skill/docs-dev/guides/positioning.md +0 -161
- package/dist-skill/docs-dev/guides/skill-maintenance.md +0 -161
- package/dist-skill/docs-dev/internals/backend-vocabulary.md +0 -35
- package/dist-skill/docs-dev/internals/compiler.md +0 -307
- package/dist-skill/docs-dev/internals/constraint-solver-quality.md +0 -161
- package/dist-skill/docs-dev/internals/constraint-solver.md +0 -176
- package/dist-skill/docs-dev/internals/sketch-2d-pipeline.md +0 -108
- package/dist-skill/library/forgecad-image-replicator/scripts/compare_images.mjs +0 -289
- package/examples/api/bolted-service-cover.forge.js +0 -17
- package/examples/api/cable-gland-anchor.forge.js +0 -14
- package/examples/api/captured-cartridge-guide.forge.js +0 -14
- package/examples/api/captured-linear-slide.forge.js +0 -13
- package/examples/api/clevis-pin-joint.forge.js +0 -13
- package/examples/api/datum-enclosure.forge.js +0 -16
- package/examples/api/hose-barb-port.forge.js +0 -14
- package/examples/api/knuckled-hinge-assembly.forge.js +0 -15
- package/examples/api/living-hinge-cover.forge.js +0 -14
- package/examples/api/pcb-terminal-block.forge.js +0 -22
- package/examples/api/pinned-lever-pivot-stack.forge.js +0 -14
- package/examples/api/retained-shaft-knob-stack.forge.js +0 -15
- package/examples/api/routed-tube-clip.forge.js +0 -15
- package/examples/api/seated-bearing-stack.forge.js +0 -30
- package/examples/api/snap-latch-cover.forge.js +0 -14
- package/examples/api/thumb-screw-clamp.forge.js +0 -15
|
@@ -235,7 +235,7 @@ function denormalize(value, array) {
|
|
|
235
235
|
throw new Error("Invalid component type.");
|
|
236
236
|
}
|
|
237
237
|
}
|
|
238
|
-
function normalize$
|
|
238
|
+
function normalize$4(value, array) {
|
|
239
239
|
switch (array.constructor) {
|
|
240
240
|
case Float32Array:
|
|
241
241
|
return value;
|
|
@@ -487,7 +487,7 @@ const MathUtils = {
|
|
|
487
487
|
* @param {TypedArray} array - The typed array that defines the data type of the value.
|
|
488
488
|
* @return {number} The normalize value.
|
|
489
489
|
*/
|
|
490
|
-
normalize: normalize$
|
|
490
|
+
normalize: normalize$4,
|
|
491
491
|
/**
|
|
492
492
|
* Denormalizes the given value according to the given typed array.
|
|
493
493
|
*
|
|
@@ -9728,7 +9728,7 @@ class BufferAttribute {
|
|
|
9728
9728
|
* @return {BufferAttribute} A reference to this instance.
|
|
9729
9729
|
*/
|
|
9730
9730
|
setComponent(index2, component, value) {
|
|
9731
|
-
if (this.normalized) value = normalize$
|
|
9731
|
+
if (this.normalized) value = normalize$4(value, this.array);
|
|
9732
9732
|
this.array[index2 * this.itemSize + component] = value;
|
|
9733
9733
|
return this;
|
|
9734
9734
|
}
|
|
@@ -9751,7 +9751,7 @@ class BufferAttribute {
|
|
|
9751
9751
|
* @return {BufferAttribute} A reference to this instance.
|
|
9752
9752
|
*/
|
|
9753
9753
|
setX(index2, x2) {
|
|
9754
|
-
if (this.normalized) x2 = normalize$
|
|
9754
|
+
if (this.normalized) x2 = normalize$4(x2, this.array);
|
|
9755
9755
|
this.array[index2 * this.itemSize] = x2;
|
|
9756
9756
|
return this;
|
|
9757
9757
|
}
|
|
@@ -9774,7 +9774,7 @@ class BufferAttribute {
|
|
|
9774
9774
|
* @return {BufferAttribute} A reference to this instance.
|
|
9775
9775
|
*/
|
|
9776
9776
|
setY(index2, y2) {
|
|
9777
|
-
if (this.normalized) y2 = normalize$
|
|
9777
|
+
if (this.normalized) y2 = normalize$4(y2, this.array);
|
|
9778
9778
|
this.array[index2 * this.itemSize + 1] = y2;
|
|
9779
9779
|
return this;
|
|
9780
9780
|
}
|
|
@@ -9797,7 +9797,7 @@ class BufferAttribute {
|
|
|
9797
9797
|
* @return {BufferAttribute} A reference to this instance.
|
|
9798
9798
|
*/
|
|
9799
9799
|
setZ(index2, z2) {
|
|
9800
|
-
if (this.normalized) z2 = normalize$
|
|
9800
|
+
if (this.normalized) z2 = normalize$4(z2, this.array);
|
|
9801
9801
|
this.array[index2 * this.itemSize + 2] = z2;
|
|
9802
9802
|
return this;
|
|
9803
9803
|
}
|
|
@@ -9820,7 +9820,7 @@ class BufferAttribute {
|
|
|
9820
9820
|
* @return {BufferAttribute} A reference to this instance.
|
|
9821
9821
|
*/
|
|
9822
9822
|
setW(index2, w2) {
|
|
9823
|
-
if (this.normalized) w2 = normalize$
|
|
9823
|
+
if (this.normalized) w2 = normalize$4(w2, this.array);
|
|
9824
9824
|
this.array[index2 * this.itemSize + 3] = w2;
|
|
9825
9825
|
return this;
|
|
9826
9826
|
}
|
|
@@ -9835,8 +9835,8 @@ class BufferAttribute {
|
|
|
9835
9835
|
setXY(index2, x2, y2) {
|
|
9836
9836
|
index2 *= this.itemSize;
|
|
9837
9837
|
if (this.normalized) {
|
|
9838
|
-
x2 = normalize$
|
|
9839
|
-
y2 = normalize$
|
|
9838
|
+
x2 = normalize$4(x2, this.array);
|
|
9839
|
+
y2 = normalize$4(y2, this.array);
|
|
9840
9840
|
}
|
|
9841
9841
|
this.array[index2 + 0] = x2;
|
|
9842
9842
|
this.array[index2 + 1] = y2;
|
|
@@ -9854,9 +9854,9 @@ class BufferAttribute {
|
|
|
9854
9854
|
setXYZ(index2, x2, y2, z2) {
|
|
9855
9855
|
index2 *= this.itemSize;
|
|
9856
9856
|
if (this.normalized) {
|
|
9857
|
-
x2 = normalize$
|
|
9858
|
-
y2 = normalize$
|
|
9859
|
-
z2 = normalize$
|
|
9857
|
+
x2 = normalize$4(x2, this.array);
|
|
9858
|
+
y2 = normalize$4(y2, this.array);
|
|
9859
|
+
z2 = normalize$4(z2, this.array);
|
|
9860
9860
|
}
|
|
9861
9861
|
this.array[index2 + 0] = x2;
|
|
9862
9862
|
this.array[index2 + 1] = y2;
|
|
@@ -9876,10 +9876,10 @@ class BufferAttribute {
|
|
|
9876
9876
|
setXYZW(index2, x2, y2, z2, w2) {
|
|
9877
9877
|
index2 *= this.itemSize;
|
|
9878
9878
|
if (this.normalized) {
|
|
9879
|
-
x2 = normalize$
|
|
9880
|
-
y2 = normalize$
|
|
9881
|
-
z2 = normalize$
|
|
9882
|
-
w2 = normalize$
|
|
9879
|
+
x2 = normalize$4(x2, this.array);
|
|
9880
|
+
y2 = normalize$4(y2, this.array);
|
|
9881
|
+
z2 = normalize$4(z2, this.array);
|
|
9882
|
+
w2 = normalize$4(w2, this.array);
|
|
9883
9883
|
}
|
|
9884
9884
|
this.array[index2 + 0] = x2;
|
|
9885
9885
|
this.array[index2 + 1] = y2;
|
|
@@ -12298,6 +12298,55 @@ function cloneShapeWorkplanePlacement(placement) {
|
|
|
12298
12298
|
placement: cloneSketchPlacementModel(placement.placement)
|
|
12299
12299
|
};
|
|
12300
12300
|
}
|
|
12301
|
+
function formatValidationValue(value) {
|
|
12302
|
+
if (typeof value === "number") return Number.isNaN(value) ? "NaN" : String(value);
|
|
12303
|
+
if (value === void 0) return "undefined";
|
|
12304
|
+
if (typeof value === "string") return JSON.stringify(value);
|
|
12305
|
+
try {
|
|
12306
|
+
return JSON.stringify(value) ?? String(value);
|
|
12307
|
+
} catch {
|
|
12308
|
+
return String(value);
|
|
12309
|
+
}
|
|
12310
|
+
}
|
|
12311
|
+
function requireFiniteNumber(value, label) {
|
|
12312
|
+
if (typeof value !== "number" || !Number.isFinite(value)) {
|
|
12313
|
+
throw new Error(`${label} must be a finite number, got ${formatValidationValue(value)}`);
|
|
12314
|
+
}
|
|
12315
|
+
return value;
|
|
12316
|
+
}
|
|
12317
|
+
function requirePositiveFiniteNumber(value, label) {
|
|
12318
|
+
const n = requireFiniteNumber(value, label);
|
|
12319
|
+
if (n <= 0) throw new Error(`${label} must be a positive finite number, got ${formatValidationValue(value)}`);
|
|
12320
|
+
return n;
|
|
12321
|
+
}
|
|
12322
|
+
function requireFiniteVec3$1(value, label) {
|
|
12323
|
+
if (!Array.isArray(value) || value.length !== 3) {
|
|
12324
|
+
throw new Error(`${label} must be [x, y, z] with finite numbers, got ${formatValidationValue(value)}`);
|
|
12325
|
+
}
|
|
12326
|
+
return [
|
|
12327
|
+
requireFiniteNumber(value[0], `${label}[0]`),
|
|
12328
|
+
requireFiniteNumber(value[1], `${label}[1]`),
|
|
12329
|
+
requireFiniteNumber(value[2], `${label}[2]`)
|
|
12330
|
+
];
|
|
12331
|
+
}
|
|
12332
|
+
function requireNonZeroFiniteVec3(value, label) {
|
|
12333
|
+
const v = requireFiniteVec3$1(value, label);
|
|
12334
|
+
if (v[0] === 0 && v[1] === 0 && v[2] === 0) throw new Error(`${label} must not be [0, 0, 0]`);
|
|
12335
|
+
return v;
|
|
12336
|
+
}
|
|
12337
|
+
function requireFiniteMat4(value, label) {
|
|
12338
|
+
if (!Array.isArray(value) || value.length !== 16) {
|
|
12339
|
+
throw new Error(`${label} must be a 4x4 matrix array with 16 finite numbers, got ${formatValidationValue(value)}`);
|
|
12340
|
+
}
|
|
12341
|
+
return value.map((entry, index2) => requireFiniteNumber(entry, `${label}[${index2}]`));
|
|
12342
|
+
}
|
|
12343
|
+
function requireNonZeroFiniteScale3(value, label) {
|
|
12344
|
+
const scale2 = typeof value === "number" ? [requireFiniteNumber(value, label), requireFiniteNumber(value, label), requireFiniteNumber(value, label)] : requireFiniteVec3$1(value, label);
|
|
12345
|
+
if (Math.abs(scale2[0]) < 1e-12 || Math.abs(scale2[1]) < 1e-12 || Math.abs(scale2[2]) < 1e-12) {
|
|
12346
|
+
throw new Error(`${label} must have finite non-zero components, got ${formatValidationValue(value)}`);
|
|
12347
|
+
}
|
|
12348
|
+
return scale2;
|
|
12349
|
+
}
|
|
12301
12350
|
const EPS$3 = 1e-10;
|
|
12302
12351
|
function subVec3(a2, b) {
|
|
12303
12352
|
return [a2[0] - b[0], a2[1] - b[1], a2[2] - b[2]];
|
|
@@ -12379,9 +12428,6 @@ function solveRotateAroundAngle(axis, pivot, movingPoint, targetPoint, options =
|
|
|
12379
12428
|
function identityMatrix() {
|
|
12380
12429
|
return [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1];
|
|
12381
12430
|
}
|
|
12382
|
-
function toMat4(input) {
|
|
12383
|
-
return input instanceof Transform ? input.toArray() : input;
|
|
12384
|
-
}
|
|
12385
12431
|
function multiplyMat4(a2, b) {
|
|
12386
12432
|
const out = new Array(16).fill(0);
|
|
12387
12433
|
for (let col = 0; col < 4; col++) {
|
|
@@ -12458,23 +12504,40 @@ class Transform {
|
|
|
12458
12504
|
}
|
|
12459
12505
|
/** Wrap an existing `Transform` or raw 4x4 matrix as a `Transform`. */
|
|
12460
12506
|
static from(input) {
|
|
12461
|
-
return input instanceof Transform ? input : new Transform(input);
|
|
12507
|
+
return input instanceof Transform ? input : new Transform(requireFiniteMat4(input, "Transform.from() matrix"));
|
|
12462
12508
|
}
|
|
12463
12509
|
/** Create a translation transform. */
|
|
12464
12510
|
static translation(x2, y2, z2) {
|
|
12465
|
-
return new Transform([
|
|
12511
|
+
return new Transform([
|
|
12512
|
+
1,
|
|
12513
|
+
0,
|
|
12514
|
+
0,
|
|
12515
|
+
0,
|
|
12516
|
+
0,
|
|
12517
|
+
1,
|
|
12518
|
+
0,
|
|
12519
|
+
0,
|
|
12520
|
+
0,
|
|
12521
|
+
0,
|
|
12522
|
+
1,
|
|
12523
|
+
0,
|
|
12524
|
+
requireFiniteNumber(x2, "Transform.translation() x"),
|
|
12525
|
+
requireFiniteNumber(y2, "Transform.translation() y"),
|
|
12526
|
+
requireFiniteNumber(z2, "Transform.translation() z"),
|
|
12527
|
+
1
|
|
12528
|
+
]);
|
|
12466
12529
|
}
|
|
12467
12530
|
/** Create a uniform or per-axis scale transform. */
|
|
12468
12531
|
static scale(v) {
|
|
12469
|
-
const sx =
|
|
12470
|
-
const sy = typeof v === "number" ? v : v[1];
|
|
12471
|
-
const sz = typeof v === "number" ? v : v[2];
|
|
12532
|
+
const [sx, sy, sz] = requireNonZeroFiniteScale3(v, "Transform.scale() scale");
|
|
12472
12533
|
return new Transform([sx, 0, 0, 0, 0, sy, 0, 0, 0, 0, sz, 0, 0, 0, 0, 1]);
|
|
12473
12534
|
}
|
|
12474
12535
|
/** Create a rotation around an arbitrary axis, optionally about a pivot. */
|
|
12475
12536
|
static rotationAxis(axis, angleDeg, pivot = [0, 0, 0]) {
|
|
12476
|
-
const [ux, uy, uz] = normalizeVec3$3(axis);
|
|
12477
|
-
const
|
|
12537
|
+
const [ux, uy, uz] = normalizeVec3$3(requireNonZeroFiniteVec3(axis, "Transform.rotationAxis() axis"));
|
|
12538
|
+
const degrees = requireFiniteNumber(angleDeg, "Transform.rotationAxis() angleDeg");
|
|
12539
|
+
const [px, py, pz] = requireFiniteVec3$1(pivot, "Transform.rotationAxis() pivot");
|
|
12540
|
+
const rad = degrees * Math.PI / 180;
|
|
12478
12541
|
const cos2 = Math.cos(rad);
|
|
12479
12542
|
const sin2 = Math.sin(rad);
|
|
12480
12543
|
const m00 = cos2 + ux * ux * (1 - cos2);
|
|
@@ -12486,7 +12549,6 @@ class Transform {
|
|
|
12486
12549
|
const m20 = uz * ux * (1 - cos2) - uy * sin2;
|
|
12487
12550
|
const m21 = uz * uy * (1 - cos2) + ux * sin2;
|
|
12488
12551
|
const m22 = cos2 + uz * uz * (1 - cos2);
|
|
12489
|
-
const [px, py, pz] = pivot;
|
|
12490
12552
|
const tx = px - (m00 * px + m01 * py + m02 * pz);
|
|
12491
12553
|
const ty = py - (m10 * px + m11 * py + m12 * pz);
|
|
12492
12554
|
const tz = pz - (m20 * px + m21 * py + m22 * pz);
|
|
@@ -12494,12 +12556,16 @@ class Transform {
|
|
|
12494
12556
|
}
|
|
12495
12557
|
/** Solve the rotation needed to move one point onto a target line or plane. */
|
|
12496
12558
|
static rotateAroundTo(axis, pivot, movingPoint, targetPoint, options = {}) {
|
|
12497
|
-
const
|
|
12498
|
-
|
|
12559
|
+
const rotateAxis = requireNonZeroFiniteVec3(axis, "Transform.rotateAroundTo() axis");
|
|
12560
|
+
const rotatePivot = requireFiniteVec3$1(pivot, "Transform.rotateAroundTo() pivot");
|
|
12561
|
+
const moving = requireFiniteVec3$1(movingPoint, "Transform.rotateAroundTo() movingPoint");
|
|
12562
|
+
const target = requireFiniteVec3$1(targetPoint, "Transform.rotateAroundTo() targetPoint");
|
|
12563
|
+
const angleDeg = solveRotateAroundAngle(rotateAxis, rotatePivot, moving, target, options);
|
|
12564
|
+
return Transform.rotationAxis(rotateAxis, angleDeg, rotatePivot);
|
|
12499
12565
|
}
|
|
12500
12566
|
/** Compose transforms in chain order: `a.mul(b)` applies `a`, then `b`. */
|
|
12501
12567
|
mul(other) {
|
|
12502
|
-
const rhs =
|
|
12568
|
+
const rhs = other instanceof Transform ? other.toArray() : requireFiniteMat4(other, "Transform.mul() matrix");
|
|
12503
12569
|
return new Transform(multiplyMat4(rhs, this.m));
|
|
12504
12570
|
}
|
|
12505
12571
|
/** Translate after the current transform. */
|
|
@@ -12510,7 +12576,20 @@ class Transform {
|
|
|
12510
12576
|
rotateAxis(axis, angleDeg, pivot = [0, 0, 0]) {
|
|
12511
12577
|
return this.mul(Transform.rotationAxis(axis, angleDeg, pivot));
|
|
12512
12578
|
}
|
|
12579
|
+
/** Rotate about the X axis after the current transform (parity with `Shape.rotateX`). */
|
|
12580
|
+
rotateX(angleDeg, pivot = [0, 0, 0]) {
|
|
12581
|
+
return this.rotateAxis([1, 0, 0], angleDeg, pivot);
|
|
12582
|
+
}
|
|
12583
|
+
/** Rotate about the Y axis after the current transform (parity with `Shape.rotateY`). */
|
|
12584
|
+
rotateY(angleDeg, pivot = [0, 0, 0]) {
|
|
12585
|
+
return this.rotateAxis([0, 1, 0], angleDeg, pivot);
|
|
12586
|
+
}
|
|
12587
|
+
/** Rotate about the Z axis after the current transform (parity with `Shape.rotateZ`). */
|
|
12588
|
+
rotateZ(angleDeg, pivot = [0, 0, 0]) {
|
|
12589
|
+
return this.rotateAxis([0, 0, 1], angleDeg, pivot);
|
|
12590
|
+
}
|
|
12513
12591
|
/** Scale after the current transform. */
|
|
12592
|
+
// biome-ignore lint/suspicious/useAdjacentOverloadSignatures: Static Transform.scale() and chainable instance scale() intentionally share the CAD API name.
|
|
12514
12593
|
scale(v) {
|
|
12515
12594
|
return this.mul(Transform.scale(v));
|
|
12516
12595
|
}
|
|
@@ -12520,11 +12599,11 @@ class Transform {
|
|
|
12520
12599
|
}
|
|
12521
12600
|
/** Transform a point using homogeneous coordinates. */
|
|
12522
12601
|
point(p2) {
|
|
12523
|
-
return transformPoint$1(this.m, p2, 1);
|
|
12602
|
+
return transformPoint$1(this.m, requireFiniteVec3$1(p2, "Transform.point() point"), 1);
|
|
12524
12603
|
}
|
|
12525
12604
|
/** Transform a direction vector without translation. */
|
|
12526
12605
|
vector(v) {
|
|
12527
|
-
return transformPoint$1(this.m, v, 0);
|
|
12606
|
+
return transformPoint$1(this.m, requireFiniteVec3$1(v, "Transform.vector() vector"), 0);
|
|
12528
12607
|
}
|
|
12529
12608
|
/** Return the transform as a raw 4x4 matrix array. */
|
|
12530
12609
|
toArray() {
|
|
@@ -12913,6 +12992,42 @@ function cloneCutTaperCompilePlan(plan) {
|
|
|
12913
12992
|
scale: [canonicalNumber(plan.scale[0]), canonicalNumber(plan.scale[1])]
|
|
12914
12993
|
};
|
|
12915
12994
|
}
|
|
12995
|
+
function cloneEdgeFeatureTarget(target) {
|
|
12996
|
+
return {
|
|
12997
|
+
midpoint: [target.midpoint[0], target.midpoint[1], target.midpoint[2]],
|
|
12998
|
+
start: [target.start[0], target.start[1], target.start[2]],
|
|
12999
|
+
end: [target.end[0], target.end[1], target.end[2]],
|
|
13000
|
+
convex: target.convex,
|
|
13001
|
+
...target.nativeTopology ? { nativeTopology: { backend: target.nativeTopology.backend, edge: target.nativeTopology.edge } } : {}
|
|
13002
|
+
};
|
|
13003
|
+
}
|
|
13004
|
+
function cloneEdgeFeatureQuery(query) {
|
|
13005
|
+
if (!query) return void 0;
|
|
13006
|
+
return {
|
|
13007
|
+
...query.near ? { near: [query.near[0], query.near[1], query.near[2]] } : {},
|
|
13008
|
+
...query.parallel ? { parallel: [query.parallel[0], query.parallel[1], query.parallel[2]] } : {},
|
|
13009
|
+
...query.perpendicular ? { perpendicular: [query.perpendicular[0], query.perpendicular[1], query.perpendicular[2]] } : {},
|
|
13010
|
+
...query.convex !== void 0 ? { convex: query.convex } : {},
|
|
13011
|
+
...query.concave !== void 0 ? { concave: query.concave } : {},
|
|
13012
|
+
...query.minAngle !== void 0 ? { minAngle: canonicalNumber(query.minAngle) } : {},
|
|
13013
|
+
...query.maxAngle !== void 0 ? { maxAngle: canonicalNumber(query.maxAngle) } : {},
|
|
13014
|
+
...query.minLength !== void 0 ? { minLength: canonicalNumber(query.minLength) } : {},
|
|
13015
|
+
...query.maxLength !== void 0 ? { maxLength: canonicalNumber(query.maxLength) } : {},
|
|
13016
|
+
...query.within ? {
|
|
13017
|
+
within: {
|
|
13018
|
+
...query.within.xMin !== void 0 ? { xMin: canonicalNumber(query.within.xMin) } : {},
|
|
13019
|
+
...query.within.xMax !== void 0 ? { xMax: canonicalNumber(query.within.xMax) } : {},
|
|
13020
|
+
...query.within.yMin !== void 0 ? { yMin: canonicalNumber(query.within.yMin) } : {},
|
|
13021
|
+
...query.within.yMax !== void 0 ? { yMax: canonicalNumber(query.within.yMax) } : {},
|
|
13022
|
+
...query.within.zMin !== void 0 ? { zMin: canonicalNumber(query.within.zMin) } : {},
|
|
13023
|
+
...query.within.zMax !== void 0 ? { zMax: canonicalNumber(query.within.zMax) } : {}
|
|
13024
|
+
}
|
|
13025
|
+
} : {},
|
|
13026
|
+
...query.atZ !== void 0 ? { atZ: canonicalNumber(query.atZ) } : {},
|
|
13027
|
+
...query.tolerance !== void 0 ? { tolerance: canonicalNumber(query.tolerance) } : {},
|
|
13028
|
+
...query.angleTolerance !== void 0 ? { angleTolerance: canonicalNumber(query.angleTolerance) } : {}
|
|
13029
|
+
};
|
|
13030
|
+
}
|
|
12916
13031
|
function featureCutExtentForwardSide(extent) {
|
|
12917
13032
|
return extent.kind === "two-sided" ? extent.forward : extent;
|
|
12918
13033
|
}
|
|
@@ -13009,6 +13124,41 @@ function cloneSweepPathCompilePlan(path) {
|
|
|
13009
13124
|
degree: path.degree,
|
|
13010
13125
|
closed: path.closed
|
|
13011
13126
|
};
|
|
13127
|
+
case "route3d":
|
|
13128
|
+
return {
|
|
13129
|
+
kind: "route3d",
|
|
13130
|
+
segments: path.segments.map(
|
|
13131
|
+
(segment) => segment.kind === "line" ? {
|
|
13132
|
+
kind: "line",
|
|
13133
|
+
from: canonicalVec3(segment.from),
|
|
13134
|
+
to: canonicalVec3(segment.to),
|
|
13135
|
+
length: canonicalNumber(segment.length)
|
|
13136
|
+
} : {
|
|
13137
|
+
kind: "arc",
|
|
13138
|
+
center: canonicalVec3(segment.center),
|
|
13139
|
+
radius: canonicalNumber(segment.radius),
|
|
13140
|
+
axis: canonicalVec3(segment.axis),
|
|
13141
|
+
start: canonicalVec3(segment.start),
|
|
13142
|
+
end: canonicalVec3(segment.end),
|
|
13143
|
+
sweepDeg: canonicalNumber(segment.sweepDeg),
|
|
13144
|
+
length: canonicalNumber(segment.length)
|
|
13145
|
+
}
|
|
13146
|
+
),
|
|
13147
|
+
ports: Object.fromEntries(
|
|
13148
|
+
Object.entries(path.ports).map(([name, port]) => [
|
|
13149
|
+
name,
|
|
13150
|
+
{
|
|
13151
|
+
name: port.name,
|
|
13152
|
+
origin: canonicalVec3(port.origin),
|
|
13153
|
+
axis: canonicalVec3(port.axis),
|
|
13154
|
+
xAxis: canonicalVec3(port.xAxis),
|
|
13155
|
+
yAxis: canonicalVec3(port.yAxis),
|
|
13156
|
+
station: canonicalNumber(port.station)
|
|
13157
|
+
}
|
|
13158
|
+
])
|
|
13159
|
+
),
|
|
13160
|
+
length: canonicalNumber(path.length)
|
|
13161
|
+
};
|
|
13012
13162
|
default:
|
|
13013
13163
|
assertExhaustive(path);
|
|
13014
13164
|
}
|
|
@@ -13103,6 +13253,7 @@ function cloneProfileEdge(edge) {
|
|
|
13103
13253
|
}
|
|
13104
13254
|
}
|
|
13105
13255
|
function cloneShapeCompilePlan(plan) {
|
|
13256
|
+
var _a3, _b3, _c2;
|
|
13106
13257
|
if (!plan) return null;
|
|
13107
13258
|
let result;
|
|
13108
13259
|
switch (plan.kind) {
|
|
@@ -13281,13 +13432,9 @@ function cloneShapeCompilePlan(plan) {
|
|
|
13281
13432
|
radius: plan.radius,
|
|
13282
13433
|
segments: plan.segments,
|
|
13283
13434
|
continuity: plan.continuity,
|
|
13284
|
-
edgeTargets: plan.edgeTargets.map(
|
|
13285
|
-
|
|
13286
|
-
|
|
13287
|
-
end: [t.end[0], t.end[1], t.end[2]],
|
|
13288
|
-
convex: t.convex,
|
|
13289
|
-
...t.nativeTopology ? { nativeTopology: { backend: t.nativeTopology.backend, edge: t.nativeTopology.edge } } : {}
|
|
13290
|
-
}))
|
|
13435
|
+
edgeTargets: (_a3 = plan.edgeTargets) == null ? void 0 : _a3.map(cloneEdgeFeatureTarget),
|
|
13436
|
+
edgeQuery: cloneEdgeFeatureQuery(plan.edgeQuery),
|
|
13437
|
+
edgeSelection: plan.edgeSelection
|
|
13291
13438
|
};
|
|
13292
13439
|
break;
|
|
13293
13440
|
case "cornerYBlend":
|
|
@@ -13297,13 +13444,7 @@ function cloneShapeCompilePlan(plan) {
|
|
|
13297
13444
|
radius: plan.radius,
|
|
13298
13445
|
segments: plan.segments,
|
|
13299
13446
|
continuity: plan.continuity,
|
|
13300
|
-
edgeTargets: plan.edgeTargets.map(
|
|
13301
|
-
midpoint: [t.midpoint[0], t.midpoint[1], t.midpoint[2]],
|
|
13302
|
-
start: [t.start[0], t.start[1], t.start[2]],
|
|
13303
|
-
end: [t.end[0], t.end[1], t.end[2]],
|
|
13304
|
-
convex: t.convex,
|
|
13305
|
-
...t.nativeTopology ? { nativeTopology: { backend: t.nativeTopology.backend, edge: t.nativeTopology.edge } } : {}
|
|
13306
|
-
})),
|
|
13447
|
+
edgeTargets: ((_b3 = plan.edgeTargets) == null ? void 0 : _b3.map(cloneEdgeFeatureTarget)) ?? [],
|
|
13307
13448
|
cornerPoint: [plan.cornerPoint[0], plan.cornerPoint[1], plan.cornerPoint[2]],
|
|
13308
13449
|
cornerTolerance: canonicalNumber(plan.cornerTolerance),
|
|
13309
13450
|
minBranchAngleDeg: canonicalNumber(plan.minBranchAngleDeg)
|
|
@@ -13314,13 +13455,9 @@ function cloneShapeCompilePlan(plan) {
|
|
|
13314
13455
|
kind: "chamferEdges",
|
|
13315
13456
|
base: cloneShapeCompilePlan(plan.base),
|
|
13316
13457
|
size: plan.size,
|
|
13317
|
-
edgeTargets: plan.edgeTargets.map(
|
|
13318
|
-
|
|
13319
|
-
|
|
13320
|
-
end: [t.end[0], t.end[1], t.end[2]],
|
|
13321
|
-
convex: t.convex,
|
|
13322
|
-
...t.nativeTopology ? { nativeTopology: { backend: t.nativeTopology.backend, edge: t.nativeTopology.edge } } : {}
|
|
13323
|
-
}))
|
|
13458
|
+
edgeTargets: (_c2 = plan.edgeTargets) == null ? void 0 : _c2.map(cloneEdgeFeatureTarget),
|
|
13459
|
+
edgeQuery: cloneEdgeFeatureQuery(plan.edgeQuery),
|
|
13460
|
+
edgeSelection: plan.edgeSelection
|
|
13324
13461
|
};
|
|
13325
13462
|
break;
|
|
13326
13463
|
case "draft":
|
|
@@ -13340,7 +13477,13 @@ function cloneShapeCompilePlan(plan) {
|
|
|
13340
13477
|
};
|
|
13341
13478
|
break;
|
|
13342
13479
|
case "importedMesh":
|
|
13343
|
-
result = {
|
|
13480
|
+
result = {
|
|
13481
|
+
kind: "importedMesh",
|
|
13482
|
+
filePath: plan.filePath,
|
|
13483
|
+
format: plan.format,
|
|
13484
|
+
...plan.object ? { object: plan.object } : {},
|
|
13485
|
+
fileData: plan.fileData
|
|
13486
|
+
};
|
|
13344
13487
|
break;
|
|
13345
13488
|
case "sdf":
|
|
13346
13489
|
result = {
|
|
@@ -13655,6 +13798,83 @@ function remapToKnotDomain(t, n, degree, knots) {
|
|
|
13655
13798
|
const uMax = knots[n];
|
|
13656
13799
|
return uMin + Math.max(0, Math.min(1, t)) * (uMax - uMin);
|
|
13657
13800
|
}
|
|
13801
|
+
const EPSILON$2 = 1e-9;
|
|
13802
|
+
function add$2(a2, b) {
|
|
13803
|
+
return [a2[0] + b[0], a2[1] + b[1], a2[2] + b[2]];
|
|
13804
|
+
}
|
|
13805
|
+
function scale$2(v, factor) {
|
|
13806
|
+
return [v[0] * factor, v[1] * factor, v[2] * factor];
|
|
13807
|
+
}
|
|
13808
|
+
function sub$2(a2, b) {
|
|
13809
|
+
return [a2[0] - b[0], a2[1] - b[1], a2[2] - b[2]];
|
|
13810
|
+
}
|
|
13811
|
+
function dot$3(a2, b) {
|
|
13812
|
+
return a2[0] * b[0] + a2[1] * b[1] + a2[2] * b[2];
|
|
13813
|
+
}
|
|
13814
|
+
function cross$4(a2, b) {
|
|
13815
|
+
return [a2[1] * b[2] - a2[2] * b[1], a2[2] * b[0] - a2[0] * b[2], a2[0] * b[1] - a2[1] * b[0]];
|
|
13816
|
+
}
|
|
13817
|
+
function rotateAroundAxis(v, axis, angleRad) {
|
|
13818
|
+
const c2 = Math.cos(angleRad);
|
|
13819
|
+
const s = Math.sin(angleRad);
|
|
13820
|
+
const term1 = scale$2(v, c2);
|
|
13821
|
+
const term2 = scale$2(cross$4(axis, v), s);
|
|
13822
|
+
const term3 = scale$2(axis, dot$3(axis, v) * (1 - c2));
|
|
13823
|
+
return add$2(add$2(term1, term2), term3);
|
|
13824
|
+
}
|
|
13825
|
+
function arcPointAt(segment, t) {
|
|
13826
|
+
const sweepRad = segment.sweepDeg * Math.PI / 180 * t;
|
|
13827
|
+
return add$2(segment.center, rotateAroundAxis(sub$2(segment.start, segment.center), segment.axis, sweepRad));
|
|
13828
|
+
}
|
|
13829
|
+
function pushUnique(points, point) {
|
|
13830
|
+
const prev = points[points.length - 1];
|
|
13831
|
+
if (!prev || Math.hypot(prev[0] - point[0], prev[1] - point[1], prev[2] - point[2]) > EPSILON$2) {
|
|
13832
|
+
points.push([point[0], point[1], point[2]]);
|
|
13833
|
+
}
|
|
13834
|
+
}
|
|
13835
|
+
function resolveOptions(options) {
|
|
13836
|
+
if (typeof options === "number") return { samples: Math.max(2, Math.floor(options)), maxAngleDeg: 6 };
|
|
13837
|
+
return {
|
|
13838
|
+
samples: Math.max(2, Math.floor((options == null ? void 0 : options.samples) ?? 48)),
|
|
13839
|
+
maxAngleDeg: Math.max(0.25, (options == null ? void 0 : options.maxAngleDeg) ?? 6)
|
|
13840
|
+
};
|
|
13841
|
+
}
|
|
13842
|
+
function routePointAt(plan, t) {
|
|
13843
|
+
if (plan.segments.length === 0) return [0, 0, 0];
|
|
13844
|
+
const target = Math.max(0, Math.min(1, t)) * plan.length;
|
|
13845
|
+
let station = 0;
|
|
13846
|
+
for (const segment of plan.segments) {
|
|
13847
|
+
const next = station + segment.length;
|
|
13848
|
+
if (target <= next || segment === plan.segments[plan.segments.length - 1]) {
|
|
13849
|
+
const localT = segment.length <= EPSILON$2 ? 1 : Math.max(0, Math.min(1, (target - station) / segment.length));
|
|
13850
|
+
if (segment.kind === "line") return add$2(segment.from, scale$2(sub$2(segment.to, segment.from), localT));
|
|
13851
|
+
return arcPointAt(segment, localT);
|
|
13852
|
+
}
|
|
13853
|
+
station = next;
|
|
13854
|
+
}
|
|
13855
|
+
const last = plan.segments[plan.segments.length - 1];
|
|
13856
|
+
return last.kind === "line" ? last.to : last.end;
|
|
13857
|
+
}
|
|
13858
|
+
function sampleRoute3DCompilePlan(plan, options) {
|
|
13859
|
+
const resolved = resolveOptions(options);
|
|
13860
|
+
const points = [];
|
|
13861
|
+
const totalIntervals = Math.max(1, resolved.samples - 1);
|
|
13862
|
+
for (const segment of plan.segments) {
|
|
13863
|
+
const proportional = plan.length > EPSILON$2 ? Math.ceil(segment.length / plan.length * totalIntervals) : 1;
|
|
13864
|
+
const arcIntervals = segment.kind === "arc" ? Math.ceil(Math.abs(segment.sweepDeg) / resolved.maxAngleDeg) : 1;
|
|
13865
|
+
const intervals = Math.max(1, proportional, arcIntervals);
|
|
13866
|
+
const start = segment.kind === "line" ? segment.from : segment.start;
|
|
13867
|
+
pushUnique(points, start);
|
|
13868
|
+
for (let i = 1; i <= intervals; i += 1) {
|
|
13869
|
+
if (segment.kind === "line") {
|
|
13870
|
+
pushUnique(points, add$2(segment.from, scale$2(sub$2(segment.to, segment.from), i / intervals)));
|
|
13871
|
+
} else {
|
|
13872
|
+
pushUnique(points, arcPointAt(segment, i / intervals));
|
|
13873
|
+
}
|
|
13874
|
+
}
|
|
13875
|
+
}
|
|
13876
|
+
return points;
|
|
13877
|
+
}
|
|
13658
13878
|
function catmullRom3D$1(p0, p1, p2, p3, t, tension) {
|
|
13659
13879
|
const tt = t * t;
|
|
13660
13880
|
const ttt = tt * t;
|
|
@@ -13793,6 +14013,8 @@ function evalPathAt(path, t) {
|
|
|
13793
14013
|
const u2 = remapToKnotDomain(Math.max(0, Math.min(1, t)), path.controlPoints.length, path.degree, path.knots);
|
|
13794
14014
|
return deBoor3D(path.controlPoints, path.weights, path.knots, path.degree, u2);
|
|
13795
14015
|
}
|
|
14016
|
+
case "route3d":
|
|
14017
|
+
return routePointAt(path, t);
|
|
13796
14018
|
}
|
|
13797
14019
|
}
|
|
13798
14020
|
function estimateCurvatureAt(path, t) {
|
|
@@ -13839,10 +14061,13 @@ function sweepPathToPolyline(path, samples = 48) {
|
|
|
13839
14061
|
}
|
|
13840
14062
|
return result;
|
|
13841
14063
|
}
|
|
14064
|
+
case "route3d":
|
|
14065
|
+
return sampleRoute3DCompilePlan(path, samples);
|
|
13842
14066
|
}
|
|
13843
14067
|
}
|
|
13844
14068
|
function sweepPathToPolylineAdaptive(path, baseSamples = 48) {
|
|
13845
14069
|
if (path.kind === "polyline") return path.points;
|
|
14070
|
+
if (path.kind === "route3d") return sampleRoute3DCompilePlan(path, baseSamples);
|
|
13846
14071
|
const probeCount = 64;
|
|
13847
14072
|
const curvatures = [];
|
|
13848
14073
|
for (let i = 0; i <= probeCount; i++) {
|
|
@@ -13873,7 +14098,7 @@ const EPS$2 = 1e-8;
|
|
|
13873
14098
|
function midpoint$1(start, end) {
|
|
13874
14099
|
return [(start[0] + end[0]) * 0.5, (start[1] + end[1]) * 0.5, (start[2] + end[2]) * 0.5];
|
|
13875
14100
|
}
|
|
13876
|
-
function normalize$
|
|
14101
|
+
function normalize$3(v) {
|
|
13877
14102
|
const len = Math.hypot(v[0], v[1], v[2]);
|
|
13878
14103
|
if (len <= EPS$2) throw new Error("Edge feature selection requires a non-zero direction vector");
|
|
13879
14104
|
return [v[0] / len, v[1] / len, v[2] / len];
|
|
@@ -14292,8 +14517,8 @@ function extrudeEdgeSelection(plan, edgeName) {
|
|
|
14292
14517
|
}
|
|
14293
14518
|
const points = plan.profile.points;
|
|
14294
14519
|
const [bl, br, _tr, tl] = points;
|
|
14295
|
-
const u2 = normalize$
|
|
14296
|
-
const v = normalize$
|
|
14520
|
+
const u2 = normalize$3([br[0] - bl[0], br[1] - bl[1], 0]);
|
|
14521
|
+
const v = normalize$3([tl[0] - bl[0], tl[1] - bl[1], 0]);
|
|
14297
14522
|
const vertex = points[index2];
|
|
14298
14523
|
const quadrant = index2 === 0 ? [1, -1] : index2 === 1 ? [-1, -1] : index2 === 2 ? [-1, 1] : [1, 1];
|
|
14299
14524
|
return {
|
|
@@ -14314,9 +14539,9 @@ function extrudeEdgeSelection(plan, edgeName) {
|
|
|
14314
14539
|
function applySelectionTransform(selection, transform) {
|
|
14315
14540
|
const start = transform.point(selection.start);
|
|
14316
14541
|
const end = transform.point(selection.end);
|
|
14317
|
-
const basisX = normalize$
|
|
14318
|
-
const basisY = normalize$
|
|
14319
|
-
const axis = normalize$
|
|
14542
|
+
const basisX = normalize$3(transform.vector(selection.basisX));
|
|
14543
|
+
const basisY = normalize$3(transform.vector(selection.basisY));
|
|
14544
|
+
const axis = normalize$3(subtract(end, start));
|
|
14320
14545
|
return {
|
|
14321
14546
|
kind: "line-segment",
|
|
14322
14547
|
edgeName: selection.edgeName,
|
|
@@ -15591,6 +15816,20 @@ function cleanName(value) {
|
|
|
15591
15816
|
const trimmed = value == null ? void 0 : value.replace(/\s+/g, " ").trim();
|
|
15592
15817
|
return trimmed && trimmed.length > 0 ? trimmed : null;
|
|
15593
15818
|
}
|
|
15819
|
+
function uniqueNames(baseNames) {
|
|
15820
|
+
const totals = /* @__PURE__ */ new Map();
|
|
15821
|
+
const seen = /* @__PURE__ */ new Map();
|
|
15822
|
+
for (const baseName of baseNames) totals.set(baseName, (totals.get(baseName) ?? 0) + 1);
|
|
15823
|
+
return baseNames.map((baseName) => {
|
|
15824
|
+
if ((totals.get(baseName) ?? 0) <= 1) return baseName;
|
|
15825
|
+
const ordinal = (seen.get(baseName) ?? 0) + 1;
|
|
15826
|
+
seen.set(baseName, ordinal);
|
|
15827
|
+
return `${baseName} #${String(ordinal).padStart(3, "0")}`;
|
|
15828
|
+
});
|
|
15829
|
+
}
|
|
15830
|
+
function normalizeSelector(value) {
|
|
15831
|
+
return value.trim().replace(/\s+/g, " ").toLowerCase();
|
|
15832
|
+
}
|
|
15594
15833
|
function extractModelXml(data) {
|
|
15595
15834
|
const zip = unzipSync(new Uint8Array(data));
|
|
15596
15835
|
const path = Object.keys(zip).find((entry) => entry.toLowerCase() === "3d/3dmodel.model");
|
|
@@ -15662,14 +15901,105 @@ function collectObjectGeometry(model, objectId, transforms = [], visiting = /* @
|
|
|
15662
15901
|
}
|
|
15663
15902
|
return { vertices, triangles, bbox };
|
|
15664
15903
|
}
|
|
15904
|
+
function buildBuildEntries(model) {
|
|
15905
|
+
const buildBaseNames = model.buildItems.map(
|
|
15906
|
+
(item) => {
|
|
15907
|
+
var _a3;
|
|
15908
|
+
return cleanName((_a3 = model.objectsById.get(item.objectId)) == null ? void 0 : _a3.sourceName) ?? `object-${item.objectId}`;
|
|
15909
|
+
}
|
|
15910
|
+
);
|
|
15911
|
+
const buildNames = uniqueNames(buildBaseNames);
|
|
15912
|
+
return model.buildItems.map((item, index2) => {
|
|
15913
|
+
const object = model.objectsById.get(item.objectId);
|
|
15914
|
+
return {
|
|
15915
|
+
stableRef: `3mf:build:${String(index2 + 1).padStart(3, "0")}:object:${item.objectId}`,
|
|
15916
|
+
objectId: item.objectId,
|
|
15917
|
+
autoName: buildNames[index2],
|
|
15918
|
+
sourceName: object == null ? void 0 : object.sourceName,
|
|
15919
|
+
type: object == null ? void 0 : object.type,
|
|
15920
|
+
transform: item.transform
|
|
15921
|
+
};
|
|
15922
|
+
});
|
|
15923
|
+
}
|
|
15924
|
+
function buildObjectEntries(model) {
|
|
15925
|
+
const objectNames = uniqueNames(model.objects.map((object) => cleanName(object.sourceName) ?? `object-${object.id}`));
|
|
15926
|
+
return model.objects.map(
|
|
15927
|
+
(object, index2) => ({
|
|
15928
|
+
stableRef: `3mf:object:${object.id}`,
|
|
15929
|
+
objectId: object.id,
|
|
15930
|
+
autoName: objectNames[index2],
|
|
15931
|
+
sourceName: object.sourceName,
|
|
15932
|
+
type: object.type
|
|
15933
|
+
})
|
|
15934
|
+
);
|
|
15935
|
+
}
|
|
15936
|
+
function buildDefaultSourceEntries(model) {
|
|
15937
|
+
return model.buildItems.length > 0 ? buildBuildEntries(model) : buildObjectEntries(model);
|
|
15938
|
+
}
|
|
15939
|
+
function buildSelectableEntries(model) {
|
|
15940
|
+
return model.buildItems.length > 0 ? [...buildBuildEntries(model), ...buildObjectEntries(model)] : buildObjectEntries(model);
|
|
15941
|
+
}
|
|
15942
|
+
function entryMatchesSelector(entry, selector) {
|
|
15943
|
+
const needle = normalizeSelector(selector);
|
|
15944
|
+
return [
|
|
15945
|
+
entry.stableRef,
|
|
15946
|
+
entry.autoName,
|
|
15947
|
+
entry.sourceName ?? "",
|
|
15948
|
+
entry.objectId,
|
|
15949
|
+
`object-${entry.objectId}`,
|
|
15950
|
+
`3mf:object:${entry.objectId}`
|
|
15951
|
+
].some((candidate) => normalizeSelector(candidate) === needle);
|
|
15952
|
+
}
|
|
15953
|
+
function availableEntryList(entries) {
|
|
15954
|
+
return entries.map((entry) => `${entry.autoName} [${entry.stableRef}]`).join(", ") || "none";
|
|
15955
|
+
}
|
|
15956
|
+
function selectSourceEntry(entries, selector) {
|
|
15957
|
+
const matches = entries.filter((entry) => entryMatchesSelector(entry, selector));
|
|
15958
|
+
if (matches.length === 1) return matches[0];
|
|
15959
|
+
if (matches.length > 1) {
|
|
15960
|
+
throw new Error(
|
|
15961
|
+
`3MF object selector "${selector}" is ambiguous. Use a stable ref: ${matches.map((entry) => entry.stableRef).join(", ")}`
|
|
15962
|
+
);
|
|
15963
|
+
}
|
|
15964
|
+
throw new Error(`3MF object selector "${selector}" matched no build item or resource object. Available: ${availableEntryList(entries)}`);
|
|
15965
|
+
}
|
|
15966
|
+
function selectorLooksLikeStableRef(selector) {
|
|
15967
|
+
return /^3mf:(build|object):/i.test(selector.trim());
|
|
15968
|
+
}
|
|
15969
|
+
function meshFromGeometry(geometry) {
|
|
15970
|
+
const vertices = [];
|
|
15971
|
+
const triangles = [];
|
|
15972
|
+
for (const vertex of geometry.vertices) vertices.push(vertex[0], vertex[1], vertex[2]);
|
|
15973
|
+
for (const triangle of geometry.triangles) triangles.push(triangle[0], triangle[1], triangle[2]);
|
|
15974
|
+
return {
|
|
15975
|
+
vertProperties: new Float32Array(vertices),
|
|
15976
|
+
triVerts: new Uint32Array(triangles),
|
|
15977
|
+
numProp: 3,
|
|
15978
|
+
mergeFromVert: new Uint32Array(0),
|
|
15979
|
+
mergeToVert: new Uint32Array(0)
|
|
15980
|
+
};
|
|
15981
|
+
}
|
|
15982
|
+
function partFromEntry(model, entry) {
|
|
15983
|
+
const geometry = collectObjectGeometry(model, entry.objectId, [entry.transform]);
|
|
15984
|
+
return {
|
|
15985
|
+
stableRef: entry.stableRef,
|
|
15986
|
+
objectId: entry.objectId,
|
|
15987
|
+
autoName: entry.autoName,
|
|
15988
|
+
sourceName: entry.sourceName,
|
|
15989
|
+
type: entry.type,
|
|
15990
|
+
mesh: meshFromGeometry(geometry),
|
|
15991
|
+
bbox: geometry.bbox,
|
|
15992
|
+
vertexCount: geometry.vertices.length,
|
|
15993
|
+
triangleCount: geometry.triangles.length
|
|
15994
|
+
};
|
|
15995
|
+
}
|
|
15665
15996
|
function parse3mfMesh(data) {
|
|
15666
15997
|
const model = parseModel(data);
|
|
15667
|
-
const
|
|
15668
|
-
const transforms = model.buildItems.length > 0 ? model.buildItems.map((item) => item.transform) : sourceIds.map(() => void 0);
|
|
15998
|
+
const entries = buildDefaultSourceEntries(model);
|
|
15669
15999
|
const vertices = [];
|
|
15670
16000
|
const triangles = [];
|
|
15671
|
-
|
|
15672
|
-
const geometry = collectObjectGeometry(model, objectId, [
|
|
16001
|
+
entries.forEach((entry) => {
|
|
16002
|
+
const geometry = collectObjectGeometry(model, entry.objectId, [entry.transform]);
|
|
15673
16003
|
const offset = vertices.length / 3;
|
|
15674
16004
|
for (const vertex of geometry.vertices) vertices.push(vertex[0], vertex[1], vertex[2]);
|
|
15675
16005
|
for (const triangle of geometry.triangles) triangles.push(triangle[0] + offset, triangle[1] + offset, triangle[2] + offset);
|
|
@@ -15682,6 +16012,11 @@ function parse3mfMesh(data) {
|
|
|
15682
16012
|
mergeToVert: new Uint32Array(0)
|
|
15683
16013
|
};
|
|
15684
16014
|
}
|
|
16015
|
+
function parse3mfMeshPart(data, selector) {
|
|
16016
|
+
const model = parseModel(data);
|
|
16017
|
+
const entries = selectorLooksLikeStableRef(selector) ? buildSelectableEntries(model) : buildDefaultSourceEntries(model);
|
|
16018
|
+
return partFromEntry(model, selectSourceEntry(entries, selector));
|
|
16019
|
+
}
|
|
15685
16020
|
function isStlBinary(data) {
|
|
15686
16021
|
if (data.byteLength < 84) return false;
|
|
15687
16022
|
const view = new DataView(data);
|
|
@@ -15826,17 +16161,17 @@ function parseObj(data) {
|
|
|
15826
16161
|
mergeToVert: new Uint32Array(0)
|
|
15827
16162
|
};
|
|
15828
16163
|
}
|
|
15829
|
-
function parse3mf(data) {
|
|
15830
|
-
return parse3mfMesh(data);
|
|
16164
|
+
function parse3mf(data, options = {}) {
|
|
16165
|
+
return options.object ? parse3mfMeshPart(data, options.object).mesh : parse3mfMesh(data);
|
|
15831
16166
|
}
|
|
15832
|
-
function parseMeshFile(data, format) {
|
|
16167
|
+
function parseMeshFile(data, format, options = {}) {
|
|
15833
16168
|
switch (format) {
|
|
15834
16169
|
case "stl":
|
|
15835
16170
|
return parseStl(data);
|
|
15836
16171
|
case "obj":
|
|
15837
16172
|
return parseObj(data);
|
|
15838
16173
|
case "3mf":
|
|
15839
|
-
return parse3mf(data);
|
|
16174
|
+
return parse3mf(data, options);
|
|
15840
16175
|
}
|
|
15841
16176
|
}
|
|
15842
16177
|
function cleanZero(value) {
|
|
@@ -15863,6 +16198,84 @@ function planeFrameToWorldToPlaneMatrix(frame) {
|
|
|
15863
16198
|
1
|
|
15864
16199
|
];
|
|
15865
16200
|
}
|
|
16201
|
+
const DEFAULT_TOLERANCE = 1;
|
|
16202
|
+
const DEFAULT_ANGLE_TOLERANCE = 10;
|
|
16203
|
+
function distSq$2(a2, b) {
|
|
16204
|
+
const dx = a2[0] - b[0];
|
|
16205
|
+
const dy = a2[1] - b[1];
|
|
16206
|
+
const dz = a2[2] - b[2];
|
|
16207
|
+
return dx * dx + dy * dy + dz * dz;
|
|
16208
|
+
}
|
|
16209
|
+
function vecLength$2(v) {
|
|
16210
|
+
return Math.sqrt(v[0] * v[0] + v[1] * v[1] + v[2] * v[2]);
|
|
16211
|
+
}
|
|
16212
|
+
function normalize$2(v) {
|
|
16213
|
+
const len = vecLength$2(v);
|
|
16214
|
+
if (len < 1e-12) return [0, 0, 0];
|
|
16215
|
+
return [v[0] / len, v[1] / len, v[2] / len];
|
|
16216
|
+
}
|
|
16217
|
+
function absDot$1(a2, b) {
|
|
16218
|
+
return Math.abs(a2[0] * b[0] + a2[1] * b[1] + a2[2] * b[2]);
|
|
16219
|
+
}
|
|
16220
|
+
function applyEdgeQueryFilters(edges, query) {
|
|
16221
|
+
const tol = query.tolerance ?? DEFAULT_TOLERANCE;
|
|
16222
|
+
const angleTol = query.angleTolerance ?? DEFAULT_ANGLE_TOLERANCE;
|
|
16223
|
+
const cosAngleTol = Math.cos(angleTol * Math.PI / 180);
|
|
16224
|
+
let result = edges;
|
|
16225
|
+
if (query.convex === true) {
|
|
16226
|
+
result = result.filter((e) => e.convex);
|
|
16227
|
+
}
|
|
16228
|
+
if (query.concave === true) {
|
|
16229
|
+
result = result.filter((e) => !e.convex);
|
|
16230
|
+
}
|
|
16231
|
+
if (query.minAngle != null) {
|
|
16232
|
+
const min2 = query.minAngle;
|
|
16233
|
+
result = result.filter((e) => e.dihedralAngle >= min2);
|
|
16234
|
+
}
|
|
16235
|
+
if (query.maxAngle != null) {
|
|
16236
|
+
const max2 = query.maxAngle;
|
|
16237
|
+
result = result.filter((e) => e.dihedralAngle <= max2);
|
|
16238
|
+
}
|
|
16239
|
+
if (query.minLength != null) {
|
|
16240
|
+
const min2 = query.minLength;
|
|
16241
|
+
result = result.filter((e) => e.length >= min2);
|
|
16242
|
+
}
|
|
16243
|
+
if (query.maxLength != null) {
|
|
16244
|
+
const max2 = query.maxLength;
|
|
16245
|
+
result = result.filter((e) => e.length <= max2);
|
|
16246
|
+
}
|
|
16247
|
+
if (query.parallel) {
|
|
16248
|
+
const dir = normalize$2(query.parallel);
|
|
16249
|
+
result = result.filter((e) => absDot$1(e.direction, dir) >= cosAngleTol);
|
|
16250
|
+
}
|
|
16251
|
+
if (query.perpendicular) {
|
|
16252
|
+
const dir = normalize$2(query.perpendicular);
|
|
16253
|
+
const sinAngleTol = Math.sin(angleTol * Math.PI / 180);
|
|
16254
|
+
result = result.filter((e) => absDot$1(e.direction, dir) <= sinAngleTol);
|
|
16255
|
+
}
|
|
16256
|
+
if (query.atZ != null) {
|
|
16257
|
+
const z2 = query.atZ;
|
|
16258
|
+
result = result.filter((e) => Math.abs(e.midpoint[2] - z2) <= tol);
|
|
16259
|
+
}
|
|
16260
|
+
if (query.within) {
|
|
16261
|
+
const b = query.within;
|
|
16262
|
+
result = result.filter((e) => {
|
|
16263
|
+
const [mx, my, mz] = e.midpoint;
|
|
16264
|
+
if (b.xMin != null && mx < b.xMin) return false;
|
|
16265
|
+
if (b.xMax != null && mx > b.xMax) return false;
|
|
16266
|
+
if (b.yMin != null && my < b.yMin) return false;
|
|
16267
|
+
if (b.yMax != null && my > b.yMax) return false;
|
|
16268
|
+
if (b.zMin != null && mz < b.zMin) return false;
|
|
16269
|
+
if (b.zMax != null && mz > b.zMax) return false;
|
|
16270
|
+
return true;
|
|
16271
|
+
});
|
|
16272
|
+
}
|
|
16273
|
+
if (query.near) {
|
|
16274
|
+
const pt = query.near;
|
|
16275
|
+
result = result.slice().sort((a2, b) => distSq$2(a2.midpoint, pt) - distSq$2(b.midpoint, pt));
|
|
16276
|
+
}
|
|
16277
|
+
return result;
|
|
16278
|
+
}
|
|
15866
16279
|
const SHELL_OPEN_FACE_CANONICAL = {
|
|
15867
16280
|
front: "side-bottom",
|
|
15868
16281
|
back: "side-top",
|
|
@@ -18170,6 +18583,8 @@ function getUnsupportedSdfProgramReason(node) {
|
|
|
18170
18583
|
return "noise depends on table-based simplex evaluation";
|
|
18171
18584
|
case "sdf:voronoi":
|
|
18172
18585
|
return "voronoi depends on table-based Worley evaluation";
|
|
18586
|
+
case "sdf:circularArray":
|
|
18587
|
+
return "circularArray folds polar coordinates and is not implemented in SdfProgram yet";
|
|
18173
18588
|
case "sdf:custom":
|
|
18174
18589
|
return "custom uses a dynamic JavaScript function body";
|
|
18175
18590
|
case "sdf:polylineSweep":
|
|
@@ -18850,6 +19265,7 @@ function requireOCCTShape(backend, apiName = "requireOCCTShape()") {
|
|
|
18850
19265
|
}
|
|
18851
19266
|
const BSPLINE_WIRE_THRESHOLD = 20;
|
|
18852
19267
|
const OFFSET_SOLID_EPS$1 = 1e-8;
|
|
19268
|
+
const MANIFOLD_BACKEND_REQUIRED_HINT = "Select the Manifold backend in the editor or run the CLI with --backend manifold.";
|
|
18853
19269
|
function transformProfileRadiusPoint$1(point, step) {
|
|
18854
19270
|
switch (step.kind) {
|
|
18855
19271
|
case "translate":
|
|
@@ -19555,6 +19971,31 @@ function findOCCTEdgeByMidpoint(oc, shape, midpoint2) {
|
|
|
19555
19971
|
}
|
|
19556
19972
|
return bestEdge;
|
|
19557
19973
|
}
|
|
19974
|
+
function edgeSegmentToTarget(segment) {
|
|
19975
|
+
return {
|
|
19976
|
+
midpoint: [segment.midpoint[0], segment.midpoint[1], segment.midpoint[2]],
|
|
19977
|
+
start: [segment.start[0], segment.start[1], segment.start[2]],
|
|
19978
|
+
end: [segment.end[0], segment.end[1], segment.end[2]],
|
|
19979
|
+
convex: segment.convex,
|
|
19980
|
+
...segment.nativeTopology ? { nativeTopology: segment.nativeTopology } : {}
|
|
19981
|
+
};
|
|
19982
|
+
}
|
|
19983
|
+
function selectOCCTEdgeFeatureTargets(base, plan) {
|
|
19984
|
+
if (!plan.edgeQuery) return plan.edgeTargets ?? [];
|
|
19985
|
+
const mesh = wrapOCCTShapeBackend(base).getMesh();
|
|
19986
|
+
const selected = applyEdgeQueryFilters(
|
|
19987
|
+
extractEdgeSegments({
|
|
19988
|
+
numProp: mesh.numProp,
|
|
19989
|
+
numTri: mesh.numTri,
|
|
19990
|
+
triVerts: mesh.triVerts,
|
|
19991
|
+
vertProperties: mesh.vertProperties,
|
|
19992
|
+
mergeFromVert: mesh.mergeFromVert,
|
|
19993
|
+
mergeToVert: mesh.mergeToVert
|
|
19994
|
+
}),
|
|
19995
|
+
plan.edgeQuery
|
|
19996
|
+
);
|
|
19997
|
+
return (plan.edgeSelection === "first" ? selected.slice(0, 1) : selected).map(edgeSegmentToTarget);
|
|
19998
|
+
}
|
|
19558
19999
|
function occtPointDistance(point, target) {
|
|
19559
20000
|
return Math.hypot(point.X() - target[0], point.Y() - target[1], point.Z() - target[2]);
|
|
19560
20001
|
}
|
|
@@ -19574,7 +20015,7 @@ function lowerFilletEdgesPlan$1(oc, plan) {
|
|
|
19574
20015
|
mkFillet.SetContinuity(mapSurfaceContinuityToOcct(oc, plan.continuity), 2 * Math.PI / 180);
|
|
19575
20016
|
}
|
|
19576
20017
|
let addedCount = 0;
|
|
19577
|
-
for (const target of plan
|
|
20018
|
+
for (const target of selectOCCTEdgeFeatureTargets(base, plan)) {
|
|
19578
20019
|
const matchedEdge = findOCCTEdgeByMidpoint(oc, base, target.midpoint);
|
|
19579
20020
|
if (matchedEdge) {
|
|
19580
20021
|
mkFillet.Add_2(plan.radius, matchedEdge);
|
|
@@ -19621,7 +20062,7 @@ function lowerChamferEdgesPlan$1(oc, plan) {
|
|
|
19621
20062
|
const base = lowerShapeCompilePlanToOCCT(plan.base, oc);
|
|
19622
20063
|
const mkChamfer = new oc.BRepFilletAPI_MakeChamfer(base);
|
|
19623
20064
|
let addedCount = 0;
|
|
19624
|
-
for (const target of plan
|
|
20065
|
+
for (const target of selectOCCTEdgeFeatureTargets(base, plan)) {
|
|
19625
20066
|
const matchedEdge = findOCCTEdgeByMidpoint(oc, base, target.midpoint);
|
|
19626
20067
|
if (matchedEdge) {
|
|
19627
20068
|
mkChamfer.Add_2(plan.size, matchedEdge);
|
|
@@ -19908,7 +20349,7 @@ function _lowerShapeCompilePlanToOCCTInner(plan, oc) {
|
|
|
19908
20349
|
`importMesh("${plan.filePath}") is not supported with the OCCT backend. Switch to the Manifold backend or use the default backend.`
|
|
19909
20350
|
);
|
|
19910
20351
|
case "sdf":
|
|
19911
|
-
throw new Error(
|
|
20352
|
+
throw new Error(`SDF shapes require the Manifold backend. ${MANIFOLD_BACKEND_REQUIRED_HINT}`);
|
|
19912
20353
|
case "fromSlices":
|
|
19913
20354
|
return lowerFromSlicesPlan$1(oc, plan);
|
|
19914
20355
|
case "nurbsSurface":
|
|
@@ -20080,6 +20521,7 @@ function buildBSplineCurveHandleFromSweepPathPlan(oc, path, context, allowApprox
|
|
|
20080
20521
|
case "catmull-rom":
|
|
20081
20522
|
case "hermite":
|
|
20082
20523
|
case "quintic-hermite":
|
|
20524
|
+
case "route3d":
|
|
20083
20525
|
if (allowApproximation) {
|
|
20084
20526
|
return buildApproximateBSplineCurveHandle(oc, sweepPathToPolyline(path, 96), context);
|
|
20085
20527
|
}
|
|
@@ -20460,27 +20902,166 @@ function lowerLoftPlan$1(oc, plan) {
|
|
|
20460
20902
|
}
|
|
20461
20903
|
return ts.Shape();
|
|
20462
20904
|
}
|
|
20463
|
-
function
|
|
20905
|
+
function fromSlicesPlaneFrameForOCCT(normalInput) {
|
|
20906
|
+
const normal = normalizeVec3$2(normalInput);
|
|
20907
|
+
if (!normal) throw new Error("Shape.fromSlices group normal must be non-zero");
|
|
20464
20908
|
const [nx, ny, nz] = normal;
|
|
20909
|
+
if (Math.abs(nz) > 1 - 1e-8) {
|
|
20910
|
+
return { u: [1, 0, 0], v: [0, nz > 0 ? 1 : -1, 0], normal };
|
|
20911
|
+
}
|
|
20912
|
+
if (Math.abs(ny) > 1 - 1e-8) {
|
|
20913
|
+
return { u: [1, 0, 0], v: [0, 0, ny > 0 ? 1 : -1], normal };
|
|
20914
|
+
}
|
|
20915
|
+
if (Math.abs(nx) > 1 - 1e-8) {
|
|
20916
|
+
return { u: [0, 1, 0], v: [0, 0, nx > 0 ? 1 : -1], normal };
|
|
20917
|
+
}
|
|
20918
|
+
const reference = Math.abs(nx) < 0.9 ? [1, 0, 0] : [0, 1, 0];
|
|
20919
|
+
const u2 = normalizeVec3$2(crossVec3$1(reference, normal));
|
|
20920
|
+
if (!u2) throw new Error("Shape.fromSlices profile u axis is invalid");
|
|
20921
|
+
return { u: u2, v: crossVec3$1(normal, u2), normal };
|
|
20922
|
+
}
|
|
20923
|
+
function buildFromSlicesLocalToWorldTransform(oc, normal) {
|
|
20924
|
+
const frame = fromSlicesPlaneFrameForOCCT(normal);
|
|
20465
20925
|
const trsf = new oc.gp_Trsf_1();
|
|
20466
|
-
|
|
20467
|
-
|
|
20468
|
-
|
|
20469
|
-
|
|
20470
|
-
|
|
20471
|
-
|
|
20472
|
-
|
|
20473
|
-
|
|
20474
|
-
|
|
20475
|
-
|
|
20476
|
-
|
|
20477
|
-
|
|
20926
|
+
trsf.SetValues(
|
|
20927
|
+
frame.u[0],
|
|
20928
|
+
frame.v[0],
|
|
20929
|
+
frame.normal[0],
|
|
20930
|
+
0,
|
|
20931
|
+
frame.u[1],
|
|
20932
|
+
frame.v[1],
|
|
20933
|
+
frame.normal[1],
|
|
20934
|
+
0,
|
|
20935
|
+
frame.u[2],
|
|
20936
|
+
frame.v[2],
|
|
20937
|
+
frame.normal[2],
|
|
20938
|
+
0
|
|
20939
|
+
);
|
|
20478
20940
|
return trsf;
|
|
20479
20941
|
}
|
|
20942
|
+
function axisAlignedDirectionForOCCT(vector) {
|
|
20943
|
+
let bestAxis = 0;
|
|
20944
|
+
let best = Math.abs(vector[0]);
|
|
20945
|
+
for (const axis of [1, 2]) {
|
|
20946
|
+
const value = Math.abs(vector[axis]);
|
|
20947
|
+
if (value > best) {
|
|
20948
|
+
best = value;
|
|
20949
|
+
bestAxis = axis;
|
|
20950
|
+
}
|
|
20951
|
+
}
|
|
20952
|
+
if (best < 1 - 1e-8) return null;
|
|
20953
|
+
return { axis: bestAxis, sign: vector[bestAxis] < 0 ? -1 : 1 };
|
|
20954
|
+
}
|
|
20955
|
+
function centeredEllipseProfileRadiiForOCCT(plan) {
|
|
20956
|
+
if (plan.kind !== "circle") return null;
|
|
20957
|
+
let rx = Math.abs(plan.radius);
|
|
20958
|
+
let ry = Math.abs(plan.radius);
|
|
20959
|
+
for (const transform of plan.transforms) {
|
|
20960
|
+
if (transform.kind !== "scale") return null;
|
|
20961
|
+
rx *= Math.abs(transform.x);
|
|
20962
|
+
ry *= Math.abs(transform.y);
|
|
20963
|
+
}
|
|
20964
|
+
return rx > 1e-10 && ry > 1e-10 ? [rx, ry] : null;
|
|
20965
|
+
}
|
|
20966
|
+
function setEllipsoidRadiusForOCCT(radii, axis, radius) {
|
|
20967
|
+
const existing = radii[axis];
|
|
20968
|
+
if (existing == null) {
|
|
20969
|
+
radii[axis] = radius;
|
|
20970
|
+
return true;
|
|
20971
|
+
}
|
|
20972
|
+
const tolerance = Math.max(1e-7, Math.max(Math.abs(existing), Math.abs(radius)) * 1e-7);
|
|
20973
|
+
return Math.abs(existing - radius) <= tolerance;
|
|
20974
|
+
}
|
|
20975
|
+
function buildRationalQuadraticEdgeForOCCT(oc, points, weights) {
|
|
20976
|
+
const poles = new oc.TColgp_Array1OfPnt_2(1, 3);
|
|
20977
|
+
const weightArr = new oc.TColStd_Array1OfReal_2(1, 3);
|
|
20978
|
+
for (let i = 0; i < 3; i++) {
|
|
20979
|
+
const [x2, y2, z2] = points[i];
|
|
20980
|
+
poles.SetValue(i + 1, new oc.gp_Pnt_3(x2, y2, z2));
|
|
20981
|
+
weightArr.SetValue(i + 1, weights[i]);
|
|
20982
|
+
}
|
|
20983
|
+
const knots = new oc.TColStd_Array1OfReal_2(1, 2);
|
|
20984
|
+
knots.SetValue(1, 0);
|
|
20985
|
+
knots.SetValue(2, 1);
|
|
20986
|
+
const mults = new oc.TColStd_Array1OfInteger_2(1, 2);
|
|
20987
|
+
mults.SetValue(1, 3);
|
|
20988
|
+
mults.SetValue(2, 3);
|
|
20989
|
+
const curve = new oc.Geom_BSplineCurve_2(poles, weightArr, knots, mults, 2, false, true);
|
|
20990
|
+
const handle = new oc.Handle_Geom_BSplineCurve_2(curve);
|
|
20991
|
+
return new oc.BRepBuilderAPI_MakeEdge_24(new oc.Handle_Geom_Curve_2(handle.get())).Edge();
|
|
20992
|
+
}
|
|
20993
|
+
function lowerAxisymmetricEllipsoidForOCCT(oc, radius, heightRadius) {
|
|
20994
|
+
const w2 = Math.SQRT1_2;
|
|
20995
|
+
const mkWire = new oc.BRepBuilderAPI_MakeWire_1();
|
|
20996
|
+
mkWire.Add_1(
|
|
20997
|
+
buildRationalQuadraticEdgeForOCCT(
|
|
20998
|
+
oc,
|
|
20999
|
+
[
|
|
21000
|
+
[0, 0, heightRadius],
|
|
21001
|
+
[radius, 0, heightRadius],
|
|
21002
|
+
[radius, 0, 0]
|
|
21003
|
+
],
|
|
21004
|
+
[1, w2, 1]
|
|
21005
|
+
)
|
|
21006
|
+
);
|
|
21007
|
+
mkWire.Add_1(
|
|
21008
|
+
buildRationalQuadraticEdgeForOCCT(
|
|
21009
|
+
oc,
|
|
21010
|
+
[
|
|
21011
|
+
[radius, 0, 0],
|
|
21012
|
+
[radius, 0, -heightRadius],
|
|
21013
|
+
[0, 0, -heightRadius]
|
|
21014
|
+
],
|
|
21015
|
+
[1, w2, 1]
|
|
21016
|
+
)
|
|
21017
|
+
);
|
|
21018
|
+
mkWire.Add_1(new oc.BRepBuilderAPI_MakeEdge_3(new oc.gp_Pnt_3(0, 0, -heightRadius), new oc.gp_Pnt_3(0, 0, heightRadius)).Edge());
|
|
21019
|
+
const face = buildFaceFromWire(oc, mkWire.Wire());
|
|
21020
|
+
const axis = new oc.gp_Ax1_2(new oc.gp_Pnt_3(0, 0, 0), new oc.gp_Dir_4(0, 0, 1));
|
|
21021
|
+
const revol = new oc.BRepPrimAPI_MakeRevol_1(face, axis, Math.PI * 2, true);
|
|
21022
|
+
revol.Build(new oc.Message_ProgressRange_1());
|
|
21023
|
+
if (!revol.IsDone()) {
|
|
21024
|
+
throw new Error("Shape.fromSlices exact ellipsoid revolve failed");
|
|
21025
|
+
}
|
|
21026
|
+
return revol.Shape();
|
|
21027
|
+
}
|
|
21028
|
+
function lowerOrthogonalEllipseFromSlicesPlan(oc, plan) {
|
|
21029
|
+
if (plan.groups.length !== 2) return null;
|
|
21030
|
+
const center = [0, 0, 0];
|
|
21031
|
+
const radii = [null, null, null];
|
|
21032
|
+
for (const group of plan.groups) {
|
|
21033
|
+
if (group.slices.length !== 1) return null;
|
|
21034
|
+
const slice = group.slices[0];
|
|
21035
|
+
const profileRadii = centeredEllipseProfileRadiiForOCCT(slice.profile);
|
|
21036
|
+
if (!profileRadii) return null;
|
|
21037
|
+
const frame = fromSlicesPlaneFrameForOCCT(group.normal);
|
|
21038
|
+
const normalAxis = axisAlignedDirectionForOCCT(frame.normal);
|
|
21039
|
+
const uAxis = axisAlignedDirectionForOCCT(frame.u);
|
|
21040
|
+
const vAxis = axisAlignedDirectionForOCCT(frame.v);
|
|
21041
|
+
if (!normalAxis || !uAxis || !vAxis) return null;
|
|
21042
|
+
center[normalAxis.axis] = normalAxis.sign * slice.offset;
|
|
21043
|
+
if (!setEllipsoidRadiusForOCCT(radii, uAxis.axis, profileRadii[0])) return null;
|
|
21044
|
+
if (!setEllipsoidRadiusForOCCT(radii, vAxis.axis, profileRadii[1])) return null;
|
|
21045
|
+
}
|
|
21046
|
+
if (radii.some((radius) => radius == null)) return null;
|
|
21047
|
+
const rx = radii[0];
|
|
21048
|
+
const ry = radii[1];
|
|
21049
|
+
const rz = radii[2];
|
|
21050
|
+
const axisymmetricTolerance = Math.max(1e-7, Math.max(Math.abs(rx), Math.abs(ry)) * 1e-7);
|
|
21051
|
+
if (Math.abs(rx - ry) > axisymmetricTolerance) return null;
|
|
21052
|
+
let shape = lowerAxisymmetricEllipsoidForOCCT(oc, (rx + ry) / 2, rz);
|
|
21053
|
+
if (Math.hypot(center[0], center[1], center[2]) > 1e-10) {
|
|
21054
|
+
const trsf = new oc.gp_Trsf_1();
|
|
21055
|
+
trsf.SetTranslation_1(new oc.gp_Vec_4(center[0], center[1], center[2]));
|
|
21056
|
+
const moved = new oc.BRepBuilderAPI_Transform_2(shape, trsf, true);
|
|
21057
|
+
shape = moved.Shape();
|
|
21058
|
+
}
|
|
21059
|
+
return shape;
|
|
21060
|
+
}
|
|
20480
21061
|
function lowerFromSlicesGroup(oc, group, singleSliceHalfExtent) {
|
|
20481
21062
|
const { normal, slices } = group;
|
|
20482
21063
|
const sorted = [...slices].sort((a2, b) => a2.offset - b.offset);
|
|
20483
|
-
const
|
|
21064
|
+
const localToWorldTrsf = buildFromSlicesLocalToWorldTransform(oc, normal);
|
|
20484
21065
|
if (sorted.length === 1) {
|
|
20485
21066
|
const s = sorted[0];
|
|
20486
21067
|
const rawFace = lowerProfileToFace(oc, s.profile);
|
|
@@ -20494,7 +21075,7 @@ function lowerFromSlicesGroup(oc, group, singleSliceHalfExtent) {
|
|
|
20494
21075
|
centerTrsf.SetTranslation_1(new oc.gp_Vec_4(0, 0, s.offset - extrudeHalf));
|
|
20495
21076
|
const centered = new oc.BRepBuilderAPI_Transform_2(shape, centerTrsf, true);
|
|
20496
21077
|
shape = centered.Shape();
|
|
20497
|
-
const rotated = new oc.BRepBuilderAPI_Transform_2(shape,
|
|
21078
|
+
const rotated = new oc.BRepBuilderAPI_Transform_2(shape, localToWorldTrsf, true);
|
|
20498
21079
|
return rotated.Shape();
|
|
20499
21080
|
}
|
|
20500
21081
|
const ts = new oc.BRepOffsetAPI_ThruSections(true, false, 1e-6);
|
|
@@ -20505,10 +21086,8 @@ function lowerFromSlicesGroup(oc, group, singleSliceHalfExtent) {
|
|
|
20505
21086
|
wire = toBSplineWireIfNeeded(oc, wire);
|
|
20506
21087
|
const placeTrsf = new oc.gp_Trsf_1();
|
|
20507
21088
|
placeTrsf.SetTranslation_1(new oc.gp_Vec_4(0, 0, s.offset));
|
|
20508
|
-
const
|
|
20509
|
-
|
|
20510
|
-
compound.Multiply(placeTrsf);
|
|
20511
|
-
const transformed = new oc.BRepBuilderAPI_Transform_2(wire, compound, true);
|
|
21089
|
+
const placed = new oc.BRepBuilderAPI_Transform_2(wire, placeTrsf, true);
|
|
21090
|
+
const transformed = new oc.BRepBuilderAPI_Transform_2(placed.Shape(), localToWorldTrsf, true);
|
|
20512
21091
|
ts.AddWire(oc.TopoDS.Wire_1(transformed.Shape()));
|
|
20513
21092
|
}
|
|
20514
21093
|
ts.CheckCompatibility(true);
|
|
@@ -20520,6 +21099,8 @@ function lowerFromSlicesGroup(oc, group, singleSliceHalfExtent) {
|
|
|
20520
21099
|
}
|
|
20521
21100
|
function lowerFromSlicesPlan$1(oc, plan) {
|
|
20522
21101
|
if (plan.groups.length === 0) throw new Error("Shape.fromSlices requires at least one slice");
|
|
21102
|
+
const exactEllipsoid = lowerOrthogonalEllipseFromSlicesPlan(oc, plan);
|
|
21103
|
+
if (exactEllipsoid) return exactEllipsoid;
|
|
20523
21104
|
const singleSliceHalfExtent = fromSlicesSingleSliceHalfExtentForOCCT(plan);
|
|
20524
21105
|
const groupSolids = plan.groups.map((g2) => lowerFromSlicesGroup(oc, g2, singleSliceHalfExtent));
|
|
20525
21106
|
if (groupSolids.length === 1) return groupSolids[0];
|
|
@@ -20546,14 +21127,40 @@ function buildPolylineSpineWire(oc, points) {
|
|
|
20546
21127
|
}
|
|
20547
21128
|
return mkWire.Wire();
|
|
20548
21129
|
}
|
|
21130
|
+
function buildRoute3DSpineWire(oc, path) {
|
|
21131
|
+
if (path.segments.length === 0) throw new Error("Route3D sweep path needs at least one segment");
|
|
21132
|
+
const mkWire = new oc.BRepBuilderAPI_MakeWire_1();
|
|
21133
|
+
for (const segment of path.segments) {
|
|
21134
|
+
if (segment.kind === "line") {
|
|
21135
|
+
const [x1, y1, z1] = segment.from;
|
|
21136
|
+
const [x2, y2, z2] = segment.to;
|
|
21137
|
+
if (x1 === x2 && y1 === y2 && z1 === z2) continue;
|
|
21138
|
+
mkWire.Add_1(new oc.BRepBuilderAPI_MakeEdge_3(new oc.gp_Pnt_3(x1, y1, z1), new oc.gp_Pnt_3(x2, y2, z2)).Edge());
|
|
21139
|
+
continue;
|
|
21140
|
+
}
|
|
21141
|
+
const radial = normalizeVec3$2(subtractVec3(segment.start, segment.center));
|
|
21142
|
+
if (!radial) throw new Error("Route3D sweep arc has a collapsed start radius");
|
|
21143
|
+
const axis = new oc.gp_Ax2_2(
|
|
21144
|
+
new oc.gp_Pnt_3(segment.center[0], segment.center[1], segment.center[2]),
|
|
21145
|
+
new oc.gp_Dir_4(segment.axis[0], segment.axis[1], segment.axis[2]),
|
|
21146
|
+
new oc.gp_Dir_4(radial[0], radial[1], radial[2])
|
|
21147
|
+
);
|
|
21148
|
+
const circle = new oc.gp_Circ_2(axis, segment.radius);
|
|
21149
|
+
mkWire.Add_1(new oc.BRepBuilderAPI_MakeEdge_9(circle, 0, segment.sweepDeg * Math.PI / 180).Edge());
|
|
21150
|
+
}
|
|
21151
|
+
return mkWire.Wire();
|
|
21152
|
+
}
|
|
20549
21153
|
function buildSpineWireFromPlan(oc, path, pathSamples) {
|
|
20550
21154
|
switch (path.kind) {
|
|
20551
21155
|
case "polyline":
|
|
20552
21156
|
return buildPolylineSpineWire(oc, path.points);
|
|
21157
|
+
case "route3d":
|
|
21158
|
+
return buildRoute3DSpineWire(oc, path);
|
|
21159
|
+
case "nurbs":
|
|
21160
|
+
return new oc.BRepBuilderAPI_MakeWire_2(buildCurveEdgeFromSweepPathPlan(oc, path, "OCCT sweep path")).Wire();
|
|
20553
21161
|
case "catmull-rom":
|
|
20554
21162
|
case "hermite":
|
|
20555
21163
|
case "quintic-hermite":
|
|
20556
|
-
case "nurbs":
|
|
20557
21164
|
return buildPolylineSpineWire(oc, sweepPathToPolyline(path, pathSamples ?? 48));
|
|
20558
21165
|
}
|
|
20559
21166
|
}
|
|
@@ -29418,18 +30025,18 @@ function faceAxes(face) {
|
|
|
29418
30025
|
}
|
|
29419
30026
|
return {};
|
|
29420
30027
|
}
|
|
29421
|
-
function edgeKey$
|
|
30028
|
+
function edgeKey$2(start, end) {
|
|
29422
30029
|
const encode = (p2) => p2.map((value) => value.toFixed(9)).join(",");
|
|
29423
30030
|
const a2 = encode(start);
|
|
29424
30031
|
const b = encode(end);
|
|
29425
30032
|
return a2 < b ? `${a2}|${b}` : `${b}|${a2}`;
|
|
29426
30033
|
}
|
|
29427
30034
|
function faceEdgeIndex(face, start, end) {
|
|
29428
|
-
const target = edgeKey$
|
|
30035
|
+
const target = edgeKey$2(start, end);
|
|
29429
30036
|
for (let i = 0; i < face.vertices.length; i++) {
|
|
29430
30037
|
const faceStart = face.vertices[i];
|
|
29431
30038
|
const faceEnd = face.vertices[(i + 1) % face.vertices.length];
|
|
29432
|
-
if (faceStart && faceEnd && edgeKey$
|
|
30039
|
+
if (faceStart && faceEnd && edgeKey$2(faceStart, faceEnd) === target) return i;
|
|
29433
30040
|
}
|
|
29434
30041
|
return null;
|
|
29435
30042
|
}
|
|
@@ -29630,7 +30237,7 @@ function topologyPayloadToTopology(payload) {
|
|
|
29630
30237
|
const start = explicitVertices[explicitEdge.vertices[0]];
|
|
29631
30238
|
const end = explicitVertices[explicitEdge.vertices[1]];
|
|
29632
30239
|
if (!isVec3(start) || !isVec3(end)) continue;
|
|
29633
|
-
const key = edgeKey$
|
|
30240
|
+
const key = edgeKey$2(start, end);
|
|
29634
30241
|
if (seenEdges.has(key)) continue;
|
|
29635
30242
|
seenEdges.set(key, edges.size);
|
|
29636
30243
|
const display = explicitEdgeDisplayName(payload, explicitEdge, explicitEdgeIndex, start, end);
|
|
@@ -29650,7 +30257,7 @@ function topologyPayloadToTopology(payload) {
|
|
|
29650
30257
|
const start = face.vertices[i];
|
|
29651
30258
|
const end = face.vertices[(i + 1) % face.vertices.length];
|
|
29652
30259
|
if (!start || !end) continue;
|
|
29653
|
-
const key = edgeKey$
|
|
30260
|
+
const key = edgeKey$2(start, end);
|
|
29654
30261
|
if (seenEdges.has(key)) continue;
|
|
29655
30262
|
seenEdges.set(key, edges.size);
|
|
29656
30263
|
edges.set(`${face.id}:edge-${i}`, {
|
|
@@ -31521,7 +32128,7 @@ function nurbsSurfaceForPlan(plan) {
|
|
|
31521
32128
|
return null;
|
|
31522
32129
|
}
|
|
31523
32130
|
function lowerImportedMeshPlan(plan) {
|
|
31524
|
-
const parsed = parseMeshFile(plan.fileData, plan.format);
|
|
32131
|
+
const parsed = parseMeshFile(plan.fileData, plan.format, { object: plan.object });
|
|
31525
32132
|
if (parsed.numProp !== 3) {
|
|
31526
32133
|
throw new Error(`importMesh("${plan.filePath}"): expected xyz vertex data`);
|
|
31527
32134
|
}
|
|
@@ -31824,12 +32431,18 @@ function applyNativeTruckFilletTargets(initialShape, targets, radius, segments,
|
|
|
31824
32431
|
}
|
|
31825
32432
|
}
|
|
31826
32433
|
function lowerFilletEdgesPlan(plan) {
|
|
32434
|
+
if (plan.edgeQuery) {
|
|
32435
|
+
throw new Error("filletEdges(): deferred edge queries are not supported by the Truck lowerer yet.");
|
|
32436
|
+
}
|
|
31827
32437
|
const shape = lowerShapeCompilePlanToTruckBackend(plan.base);
|
|
31828
|
-
return applyNativeTruckFilletTargets(shape, plan.edgeTargets, plan.radius, plan.segments, "filletEdges()");
|
|
32438
|
+
return applyNativeTruckFilletTargets(shape, plan.edgeTargets ?? [], plan.radius, plan.segments, "filletEdges()");
|
|
31829
32439
|
}
|
|
31830
32440
|
function lowerChamferEdgesPlan(plan) {
|
|
32441
|
+
if (plan.edgeQuery) {
|
|
32442
|
+
throw new Error("chamferEdges(): deferred edge queries are not supported by the Truck lowerer yet.");
|
|
32443
|
+
}
|
|
31831
32444
|
const shape = lowerShapeCompilePlanToTruckBackend(plan.base);
|
|
31832
|
-
return applyNativeTruckChamferTargets(shape, plan.edgeTargets, plan.size, "chamferEdges()");
|
|
32445
|
+
return applyNativeTruckChamferTargets(shape, plan.edgeTargets ?? [], plan.size, "chamferEdges()");
|
|
31833
32446
|
}
|
|
31834
32447
|
function resolvedEdgeFeatureSelectionToTarget(selection) {
|
|
31835
32448
|
return {
|
|
@@ -37846,8 +38459,8 @@ function resolveShapeFace(plan, name) {
|
|
|
37846
38459
|
const DEPRECATED_SIDE_NAMES = {
|
|
37847
38460
|
"side-left": "left",
|
|
37848
38461
|
"side-right": "right",
|
|
37849
|
-
"side-top": "
|
|
37850
|
-
"side-bottom": "
|
|
38462
|
+
"side-top": "back",
|
|
38463
|
+
"side-bottom": "front"
|
|
37851
38464
|
};
|
|
37852
38465
|
function explainMissingShapeFace(plan, name) {
|
|
37853
38466
|
const table = resolveShapeFaceTable(plan);
|
|
@@ -38926,11 +39539,14 @@ class ShapeGroup {
|
|
|
38926
39539
|
}
|
|
38927
39540
|
/** Move the entire group by (x, y, z). All children move together as a unit. */
|
|
38928
39541
|
translate(x2, y2, z2) {
|
|
38929
|
-
const
|
|
39542
|
+
const dx = requireFiniteNumber(x2, "ShapeGroup.translate() x");
|
|
39543
|
+
const dy = requireFiniteNumber(y2, "ShapeGroup.translate() y");
|
|
39544
|
+
const dz = requireFiniteNumber(z2, "ShapeGroup.translate() z");
|
|
39545
|
+
const matrix = Transform.translation(dx, dy, dz).toArray();
|
|
38930
39546
|
return this.mapChildrenTransform((c2) => {
|
|
38931
|
-
if (c2 instanceof ShapeGroup) return c2.translate(
|
|
38932
|
-
if (c2 instanceof Shape) return c2.translate(
|
|
38933
|
-
return c2.translate(
|
|
39547
|
+
if (c2 instanceof ShapeGroup) return c2.translate(dx, dy, dz);
|
|
39548
|
+
if (c2 instanceof Shape) return c2.translate(dx, dy, dz);
|
|
39549
|
+
return c2.translate(dx, dy);
|
|
38934
39550
|
}, matrix);
|
|
38935
39551
|
}
|
|
38936
39552
|
/** Compute combined bounding box of all 3D children */
|
|
@@ -38966,17 +39582,23 @@ class ShapeGroup {
|
|
|
38966
39582
|
return { min: bb.min, max: bb.max };
|
|
38967
39583
|
}
|
|
38968
39584
|
resolveRotatePoint(point) {
|
|
38969
|
-
if (Array.isArray(point)) return
|
|
39585
|
+
if (Array.isArray(point)) return requireFiniteVec3$1(point, "ShapeGroup.rotateAroundTo() point");
|
|
38970
39586
|
const bb = this._bbox();
|
|
38971
39587
|
return resolveAnchor3D(bb.min, bb.max, point);
|
|
38972
39588
|
}
|
|
38973
39589
|
/** Move the group so its bounding-box min corner lands at the given coordinate. */
|
|
38974
39590
|
moveTo(x2, y2, z2) {
|
|
39591
|
+
const targetX = requireFiniteNumber(x2, "ShapeGroup.moveTo() x");
|
|
39592
|
+
const targetY = requireFiniteNumber(y2, "ShapeGroup.moveTo() y");
|
|
39593
|
+
const targetZ = requireFiniteNumber(z2, "ShapeGroup.moveTo() z");
|
|
38975
39594
|
const bb = this._bbox();
|
|
38976
|
-
return this.translate(
|
|
39595
|
+
return this.translate(targetX - bb.min[0], targetY - bb.min[1], targetZ - bb.min[2]);
|
|
38977
39596
|
}
|
|
38978
39597
|
/** Move the group relative to another part's bounding-box min corner. */
|
|
38979
39598
|
moveToLocal(target, x2, y2, z2) {
|
|
39599
|
+
const localX = requireFiniteNumber(x2, "ShapeGroup.moveToLocal() x");
|
|
39600
|
+
const localY = requireFiniteNumber(y2, "ShapeGroup.moveToLocal() y");
|
|
39601
|
+
const localZ = requireFiniteNumber(z2, "ShapeGroup.moveToLocal() z");
|
|
38980
39602
|
let tbb;
|
|
38981
39603
|
if (target instanceof ShapeGroup) {
|
|
38982
39604
|
tbb = target._bbox();
|
|
@@ -38984,7 +39606,7 @@ class ShapeGroup {
|
|
|
38984
39606
|
const bb = target.boundingBox();
|
|
38985
39607
|
tbb = { min: bb.min };
|
|
38986
39608
|
}
|
|
38987
|
-
return this.moveTo(tbb.min[0] +
|
|
39609
|
+
return this.moveTo(tbb.min[0] + localX, tbb.min[1] + localY, tbb.min[2] + localZ);
|
|
38988
39610
|
}
|
|
38989
39611
|
/**
|
|
38990
39612
|
* Attach this group to a face or anchor on another part.
|
|
@@ -39013,9 +39635,10 @@ class ShapeGroup {
|
|
|
39013
39635
|
const sp = resolveAnchor3D(sbb.min, sbb.max, selfAnchor);
|
|
39014
39636
|
let dx = tp[0] - sp[0], dy = tp[1] - sp[1], dz = tp[2] - sp[2];
|
|
39015
39637
|
if (offset) {
|
|
39016
|
-
|
|
39017
|
-
|
|
39018
|
-
|
|
39638
|
+
const offsetPoint = requireFiniteVec3$1(offset, "ShapeGroup.attachTo() offset");
|
|
39639
|
+
dx += offsetPoint[0];
|
|
39640
|
+
dy += offsetPoint[1];
|
|
39641
|
+
dz += offsetPoint[2];
|
|
39019
39642
|
}
|
|
39020
39643
|
return this.translate(dx, dy, dz);
|
|
39021
39644
|
}
|
|
@@ -39024,7 +39647,9 @@ class ShapeGroup {
|
|
|
39024
39647
|
* See Shape.onFace() for full documentation.
|
|
39025
39648
|
*/
|
|
39026
39649
|
onFace(parent, face, opts = {}) {
|
|
39027
|
-
const u2 = opts.u ?? 0,
|
|
39650
|
+
const u2 = requireFiniteNumber(opts.u ?? 0, "ShapeGroup.onFace() u");
|
|
39651
|
+
const v = requireFiniteNumber(opts.v ?? 0, "ShapeGroup.onFace() v");
|
|
39652
|
+
const p2 = requireFiniteNumber(opts.protrude ?? 0, "ShapeGroup.onFace() protrude");
|
|
39028
39653
|
const opp = { front: "back", back: "front", left: "right", right: "left", top: "bottom", bottom: "top" };
|
|
39029
39654
|
const uvMap = {
|
|
39030
39655
|
front: (u22, v2, p22) => [u22, -p22, v2],
|
|
@@ -39063,20 +39688,31 @@ class ShapeGroup {
|
|
|
39063
39688
|
}
|
|
39064
39689
|
/** Rotate around an arbitrary axis, optionally through a pivot point. */
|
|
39065
39690
|
rotateAroundAxis(axis, angleDeg, pivot = [0, 0, 0]) {
|
|
39066
|
-
|
|
39691
|
+
const rotateAxis = requireNonZeroFiniteVec3(axis, "ShapeGroup.rotateAroundAxis() axis");
|
|
39692
|
+
const degrees = requireFiniteNumber(angleDeg, "ShapeGroup.rotateAroundAxis() angleDeg");
|
|
39693
|
+
const rotatePivot = requireFiniteVec3$1(pivot, "ShapeGroup.rotateAroundAxis() pivot");
|
|
39694
|
+
return this.transform(Transform.rotationAxis(rotateAxis, degrees, rotatePivot));
|
|
39067
39695
|
}
|
|
39068
39696
|
/**
|
|
39069
39697
|
* Rotate around an axis until a moving point reaches the target line/plane defined by the axis and target point.
|
|
39070
39698
|
* ShapeGroup string points use built-in anchors only.
|
|
39071
39699
|
*/
|
|
39072
39700
|
rotateAroundTo(axis, pivot, movingPoint, targetPoint, options = {}) {
|
|
39701
|
+
const rotateAxis = requireNonZeroFiniteVec3(axis, "ShapeGroup.rotateAroundTo() axis");
|
|
39702
|
+
const rotatePivot = requireFiniteVec3$1(pivot, "ShapeGroup.rotateAroundTo() pivot");
|
|
39073
39703
|
return this.transform(
|
|
39074
|
-
Transform.rotateAroundTo(
|
|
39704
|
+
Transform.rotateAroundTo(
|
|
39705
|
+
rotateAxis,
|
|
39706
|
+
rotatePivot,
|
|
39707
|
+
this.resolveRotatePoint(movingPoint),
|
|
39708
|
+
this.resolveRotatePoint(targetPoint),
|
|
39709
|
+
options
|
|
39710
|
+
)
|
|
39075
39711
|
);
|
|
39076
39712
|
}
|
|
39077
39713
|
/** Reorient the group so its local Z axis points along `direction`. */
|
|
39078
39714
|
pointAlong(direction) {
|
|
39079
|
-
const [dx, dy, dz] = direction;
|
|
39715
|
+
const [dx, dy, dz] = requireNonZeroFiniteVec3(direction, "ShapeGroup.pointAlong() direction");
|
|
39080
39716
|
const len = Math.sqrt(dx * dx + dy * dy + dz * dz) || 1;
|
|
39081
39717
|
const nx = dx / len, ny = dy / len, nz = dz / len;
|
|
39082
39718
|
const cx = -ny, cy = nx, cz = 0;
|
|
@@ -39091,11 +39727,11 @@ class ShapeGroup {
|
|
|
39091
39727
|
}
|
|
39092
39728
|
/** Apply a 4x4 transform matrix or `Transform` to all 3D children. */
|
|
39093
39729
|
transform(m2) {
|
|
39094
|
-
const matrix = m2 instanceof Transform ? m2.toArray() : m2;
|
|
39730
|
+
const matrix = m2 instanceof Transform ? m2.toArray() : requireFiniteMat4(m2, "ShapeGroup.transform() matrix");
|
|
39095
39731
|
const next = new ShapeGroup(
|
|
39096
39732
|
this.children.map((c2) => {
|
|
39097
|
-
if (c2 instanceof ShapeGroup) return c2.transform(
|
|
39098
|
-
if (c2 instanceof Shape) return c2.transform(
|
|
39733
|
+
if (c2 instanceof ShapeGroup) return c2.transform(matrix);
|
|
39734
|
+
if (c2 instanceof Shape) return c2.transform(matrix);
|
|
39099
39735
|
throw new Error(
|
|
39100
39736
|
"ShapeGroup.transform only supports 3D children (Shape/ShapeGroup). For Sketch children, use 2D transforms (translate/rotate/scale/mirror)."
|
|
39101
39737
|
);
|
|
@@ -39108,25 +39744,28 @@ class ShapeGroup {
|
|
|
39108
39744
|
}
|
|
39109
39745
|
/** Scale uniformly or per-axis from the group's bounding-box center. */
|
|
39110
39746
|
scale(v) {
|
|
39111
|
-
|
|
39747
|
+
const scale2 = requireNonZeroFiniteScale3(v, "ShapeGroup.scale() scale");
|
|
39748
|
+
return this.scaleAround(this._bboxCenter(), scale2);
|
|
39112
39749
|
}
|
|
39113
39750
|
/** Scale uniformly or per-axis from an explicit pivot point. */
|
|
39114
39751
|
scaleAround(pivot, v) {
|
|
39115
|
-
const
|
|
39116
|
-
|
|
39752
|
+
const scale2 = requireNonZeroFiniteScale3(v, "ShapeGroup.scaleAround() scale");
|
|
39753
|
+
const scalePivot = requireFiniteVec3$1(pivot, "ShapeGroup.scaleAround() pivot");
|
|
39754
|
+
const matrix = Transform.scale(scale2).toArray();
|
|
39755
|
+
if (scalePivot[0] === 0 && scalePivot[1] === 0 && scalePivot[2] === 0) {
|
|
39117
39756
|
return this.mapChildrenTransform((c2) => {
|
|
39118
|
-
if (c2 instanceof ShapeGroup) return c2.scaleAround([0, 0, 0],
|
|
39119
|
-
if (c2 instanceof Shape) return c2.scaleAround([0, 0, 0],
|
|
39120
|
-
return c2.scale(
|
|
39757
|
+
if (c2 instanceof ShapeGroup) return c2.scaleAround([0, 0, 0], scale2);
|
|
39758
|
+
if (c2 instanceof Shape) return c2.scaleAround([0, 0, 0], scale2);
|
|
39759
|
+
return c2.scale([scale2[0], scale2[1]]);
|
|
39121
39760
|
}, matrix);
|
|
39122
39761
|
}
|
|
39123
|
-
const moved = this.translate(-
|
|
39762
|
+
const moved = this.translate(-scalePivot[0], -scalePivot[1], -scalePivot[2]);
|
|
39124
39763
|
const scaled = moved.mapChildrenTransform((c2) => {
|
|
39125
|
-
if (c2 instanceof ShapeGroup) return c2.scaleAround([0, 0, 0],
|
|
39126
|
-
if (c2 instanceof Shape) return c2.scaleAround([0, 0, 0],
|
|
39127
|
-
return c2.scale(
|
|
39764
|
+
if (c2 instanceof ShapeGroup) return c2.scaleAround([0, 0, 0], scale2);
|
|
39765
|
+
if (c2 instanceof Shape) return c2.scaleAround([0, 0, 0], scale2);
|
|
39766
|
+
return c2.scale([scale2[0], scale2[1]]);
|
|
39128
39767
|
}, matrix);
|
|
39129
|
-
return scaled.translate(
|
|
39768
|
+
return scaled.translate(scalePivot[0], scalePivot[1], scalePivot[2]);
|
|
39130
39769
|
}
|
|
39131
39770
|
/** Mirror across a plane through the group's bounding-box center. */
|
|
39132
39771
|
mirror(normal) {
|
|
@@ -39134,21 +39773,23 @@ class ShapeGroup {
|
|
|
39134
39773
|
}
|
|
39135
39774
|
/** Mirror across a plane through an explicit point. */
|
|
39136
39775
|
mirrorThrough(point, normal) {
|
|
39137
|
-
const
|
|
39138
|
-
|
|
39776
|
+
const mirrorPoint = requireFiniteVec3$1(point, "ShapeGroup.mirrorThrough() point");
|
|
39777
|
+
const mirrorNormal = requireNonZeroFiniteVec3(normal, "ShapeGroup.mirrorThrough() normal");
|
|
39778
|
+
const matrix = mirrorPlaneMatrix(mirrorNormal);
|
|
39779
|
+
if (mirrorPoint[0] === 0 && mirrorPoint[1] === 0 && mirrorPoint[2] === 0) {
|
|
39139
39780
|
return this.mapChildrenTransform((c2) => {
|
|
39140
|
-
if (c2 instanceof ShapeGroup) return c2.mirrorThrough([0, 0, 0],
|
|
39141
|
-
if (c2 instanceof Shape) return c2.mirrorThrough([0, 0, 0],
|
|
39142
|
-
return c2.mirror([
|
|
39781
|
+
if (c2 instanceof ShapeGroup) return c2.mirrorThrough([0, 0, 0], mirrorNormal);
|
|
39782
|
+
if (c2 instanceof Shape) return c2.mirrorThrough([0, 0, 0], mirrorNormal);
|
|
39783
|
+
return c2.mirror([mirrorNormal[0], mirrorNormal[1]]);
|
|
39143
39784
|
}, matrix);
|
|
39144
39785
|
}
|
|
39145
|
-
const moved = this.translate(-
|
|
39786
|
+
const moved = this.translate(-mirrorPoint[0], -mirrorPoint[1], -mirrorPoint[2]);
|
|
39146
39787
|
const mirrored = moved.mapChildrenTransform((c2) => {
|
|
39147
|
-
if (c2 instanceof ShapeGroup) return c2.mirrorThrough([0, 0, 0],
|
|
39148
|
-
if (c2 instanceof Shape) return c2.mirrorThrough([0, 0, 0],
|
|
39149
|
-
return c2.mirror([
|
|
39788
|
+
if (c2 instanceof ShapeGroup) return c2.mirrorThrough([0, 0, 0], mirrorNormal);
|
|
39789
|
+
if (c2 instanceof Shape) return c2.mirrorThrough([0, 0, 0], mirrorNormal);
|
|
39790
|
+
return c2.mirror([mirrorNormal[0], mirrorNormal[1]]);
|
|
39150
39791
|
}, matrix);
|
|
39151
|
-
return mirrored.translate(
|
|
39792
|
+
return mirrored.translate(mirrorPoint[0], mirrorPoint[1], mirrorPoint[2]);
|
|
39152
39793
|
}
|
|
39153
39794
|
/** Return a copy of the group with the given display color applied to each child. */
|
|
39154
39795
|
color(hex) {
|
|
@@ -39220,14 +39861,16 @@ class ShapeGroup {
|
|
|
39220
39861
|
* ```
|
|
39221
39862
|
*/
|
|
39222
39863
|
placeReference(ref, target, offset) {
|
|
39864
|
+
const targetPoint = requireFiniteVec3$1(target, "ShapeGroup.placeReference() target");
|
|
39865
|
+
const offsetPoint = offset === void 0 ? void 0 : requireFiniteVec3$1(offset, "ShapeGroup.placeReference() offset");
|
|
39223
39866
|
const sourcePoint = this.referencePoint(ref);
|
|
39224
|
-
let dx =
|
|
39225
|
-
let dy =
|
|
39226
|
-
let dz =
|
|
39227
|
-
if (
|
|
39228
|
-
dx +=
|
|
39229
|
-
dy +=
|
|
39230
|
-
dz +=
|
|
39867
|
+
let dx = targetPoint[0] - sourcePoint[0];
|
|
39868
|
+
let dy = targetPoint[1] - sourcePoint[1];
|
|
39869
|
+
let dz = targetPoint[2] - sourcePoint[2];
|
|
39870
|
+
if (offsetPoint) {
|
|
39871
|
+
dx += offsetPoint[0];
|
|
39872
|
+
dy += offsetPoint[1];
|
|
39873
|
+
dz += offsetPoint[2];
|
|
39231
39874
|
}
|
|
39232
39875
|
return this.translate(dx, dy, dz);
|
|
39233
39876
|
}
|
|
@@ -40159,14 +40802,21 @@ function attachTopologyRewritePropagation(plan, propagation) {
|
|
|
40159
40802
|
}
|
|
40160
40803
|
return cloneNodeWithPropagation(plan, propagation);
|
|
40161
40804
|
}
|
|
40805
|
+
const DEFERRED_EDGE_SELECTION_MARKER = Symbol.for("forgecad.deferredEdgeSelection");
|
|
40806
|
+
function isDeferredEdgeSelection(value) {
|
|
40807
|
+
return Boolean(value && typeof value === "object" && value[DEFERRED_EDGE_SELECTION_MARKER] === true);
|
|
40808
|
+
}
|
|
40162
40809
|
function distSq$1(a2, b) {
|
|
40163
|
-
const dx = a2[0] - b[0]
|
|
40810
|
+
const dx = a2[0] - b[0];
|
|
40811
|
+
const dy = a2[1] - b[1];
|
|
40812
|
+
const dz = a2[2] - b[2];
|
|
40164
40813
|
return dx * dx + dy * dy + dz * dz;
|
|
40165
40814
|
}
|
|
40166
40815
|
function absDot(a2, b) {
|
|
40167
40816
|
return Math.abs(a2[0] * b[0] + a2[1] * b[1] + a2[2] * b[2]);
|
|
40168
40817
|
}
|
|
40169
40818
|
function coalesceEdges(segments, tolerance = 0.01) {
|
|
40819
|
+
if (segments.some(isDeferredEdgeSelection)) return segments;
|
|
40170
40820
|
if (segments.length <= 1) return segments;
|
|
40171
40821
|
const used = new Uint8Array(segments.length);
|
|
40172
40822
|
const result = [];
|
|
@@ -40889,16 +41539,6 @@ function mirrorMatrix(normal) {
|
|
|
40889
41539
|
const m22 = 1 - 2 * nz * nz;
|
|
40890
41540
|
return [m00, m10, m20, 0, m01, m11, m21, 0, m02, m12, m22, 0, 0, 0, 0, 1];
|
|
40891
41541
|
}
|
|
40892
|
-
function normalizeShapeScale(v) {
|
|
40893
|
-
const scale2 = typeof v === "number" ? [v, v, v] : v;
|
|
40894
|
-
if (!Number.isFinite(scale2[0]) || !Number.isFinite(scale2[1]) || !Number.isFinite(scale2[2])) {
|
|
40895
|
-
return null;
|
|
40896
|
-
}
|
|
40897
|
-
if (Math.abs(scale2[0]) < 1e-12 || Math.abs(scale2[1]) < 1e-12 || Math.abs(scale2[2]) < 1e-12) {
|
|
40898
|
-
return null;
|
|
40899
|
-
}
|
|
40900
|
-
return [scale2[0], scale2[1], scale2[2]];
|
|
40901
|
-
}
|
|
40902
41542
|
function dotVec3$1(a2, b) {
|
|
40903
41543
|
return a2[0] * b[0] + a2[1] * b[1] + a2[2] * b[2];
|
|
40904
41544
|
}
|
|
@@ -42051,7 +42691,7 @@ function withBaseDimensionsAndMergedSourceSpans(base, sources, out, preserveOutp
|
|
|
42051
42691
|
return result;
|
|
42052
42692
|
}
|
|
42053
42693
|
function resolveRotationPoint(shape, point) {
|
|
42054
|
-
if (Array.isArray(point)) return
|
|
42694
|
+
if (Array.isArray(point)) return requireFiniteVec3$1(point, "rotateAroundTo(): point");
|
|
42055
42695
|
return shape.referencePoint(point);
|
|
42056
42696
|
}
|
|
42057
42697
|
function setShapePlacementReferences(shape, refs, options = {}) {
|
|
@@ -42779,7 +43419,9 @@ class Shape {
|
|
|
42779
43419
|
edgesOf(faceLabel, options) {
|
|
42780
43420
|
const faceRefs = this._resolveFaceLabels(faceLabel);
|
|
42781
43421
|
const result = uniqueEdgeSegments(
|
|
42782
|
-
faceRefs.flatMap((faceRef) =>
|
|
43422
|
+
faceRefs.flatMap((faceRef) => {
|
|
43423
|
+
return edgesOfFace(this, faceRef, options, (name) => this._resolveFaceLabel(name));
|
|
43424
|
+
})
|
|
42783
43425
|
);
|
|
42784
43426
|
if (result.length === 0) {
|
|
42785
43427
|
throw new Error(
|
|
@@ -42827,7 +43469,11 @@ class Shape {
|
|
|
42827
43469
|
const refsA = this._resolveFaceLabels(faceA);
|
|
42828
43470
|
const bNames = Array.isArray(faceB) ? faceB : [faceB];
|
|
42829
43471
|
const refBs = bNames.flatMap((name) => this._resolveFaceLabels(name));
|
|
42830
|
-
const result = uniqueEdgeSegments(
|
|
43472
|
+
const result = uniqueEdgeSegments(
|
|
43473
|
+
refsA.flatMap((refA) => {
|
|
43474
|
+
return edgesBetweenFaces(this, refA, refBs);
|
|
43475
|
+
})
|
|
43476
|
+
);
|
|
42831
43477
|
if (result.length === 0) {
|
|
42832
43478
|
const bStr = bNames.length === 1 ? `'${bNames[0]}'` : `[${bNames.map((n) => `'${n}'`).join(", ")}]`;
|
|
42833
43479
|
throw new Error(
|
|
@@ -42891,14 +43537,16 @@ class Shape {
|
|
|
42891
43537
|
* ```
|
|
42892
43538
|
*/
|
|
42893
43539
|
placeReference(ref, target, offset) {
|
|
43540
|
+
const targetPoint = requireFiniteVec3$1(target, "Shape.placeReference() target");
|
|
43541
|
+
const offsetPoint = offset === void 0 ? void 0 : requireFiniteVec3$1(offset, "Shape.placeReference() offset");
|
|
42894
43542
|
const sourcePoint = this.referencePoint(ref);
|
|
42895
|
-
let dx =
|
|
42896
|
-
let dy =
|
|
42897
|
-
let dz =
|
|
42898
|
-
if (
|
|
42899
|
-
dx +=
|
|
42900
|
-
dy +=
|
|
42901
|
-
dz +=
|
|
43543
|
+
let dx = targetPoint[0] - sourcePoint[0];
|
|
43544
|
+
let dy = targetPoint[1] - sourcePoint[1];
|
|
43545
|
+
let dz = targetPoint[2] - sourcePoint[2];
|
|
43546
|
+
if (offsetPoint) {
|
|
43547
|
+
dx += offsetPoint[0];
|
|
43548
|
+
dy += offsetPoint[1];
|
|
43549
|
+
dz += offsetPoint[2];
|
|
42902
43550
|
}
|
|
42903
43551
|
return this.translate(dx, dy, dz);
|
|
42904
43552
|
}
|
|
@@ -42910,27 +43558,39 @@ class Shape {
|
|
|
42910
43558
|
* Example: `shape.translatePolar(50, 30)` moves 50mm at 30 degrees from +X.
|
|
42911
43559
|
*/
|
|
42912
43560
|
translatePolar(radius, angleDeg, z2 = 0) {
|
|
42913
|
-
const
|
|
42914
|
-
|
|
43561
|
+
const r = requireFiniteNumber(radius, "Shape.translatePolar() radius");
|
|
43562
|
+
const angle = requireFiniteNumber(angleDeg, "Shape.translatePolar() angleDeg");
|
|
43563
|
+
const zOffset = requireFiniteNumber(z2, "Shape.translatePolar() z");
|
|
43564
|
+
const rad = angle * (Math.PI / 180);
|
|
43565
|
+
return this.translate(r * Math.cos(rad), r * Math.sin(rad), zOffset);
|
|
42915
43566
|
}
|
|
42916
43567
|
/** Move the shape relative to its current position. All transforms are immutable and return new shapes. */
|
|
42917
43568
|
translate(x2, y2, z2) {
|
|
42918
|
-
const
|
|
43569
|
+
const dx = requireFiniteNumber(x2, "Shape.translate() x");
|
|
43570
|
+
const dy = requireFiniteNumber(y2, "Shape.translate() y");
|
|
43571
|
+
const dz = requireFiniteNumber(z2, "Shape.translate() z");
|
|
43572
|
+
const nextPlan = appendShapeCompileTransform(getShapeCompilePlanInternal(this), { kind: "translate", x: dx, y: dy, z: dz });
|
|
42919
43573
|
return setShapeCompilePlanInternal(
|
|
42920
|
-
withTransformedDimensions(this, buildShapeFromCompilePlan(nextPlan, this.colorHex), Transform.translation(
|
|
43574
|
+
withTransformedDimensions(this, buildShapeFromCompilePlan(nextPlan, this.colorHex), Transform.translation(dx, dy, dz).toArray()),
|
|
42921
43575
|
nextPlan
|
|
42922
43576
|
);
|
|
42923
43577
|
}
|
|
42924
43578
|
/** Position the shape so its bounding box min corner is at the given global coordinate. */
|
|
42925
43579
|
moveTo(x2, y2, z2) {
|
|
43580
|
+
const targetX = requireFiniteNumber(x2, "Shape.moveTo() x");
|
|
43581
|
+
const targetY = requireFiniteNumber(y2, "Shape.moveTo() y");
|
|
43582
|
+
const targetZ = requireFiniteNumber(z2, "Shape.moveTo() z");
|
|
42926
43583
|
const bb = this.boundingBox();
|
|
42927
|
-
return this.translate(
|
|
43584
|
+
return this.translate(targetX - bb.min[0], targetY - bb.min[1], targetZ - bb.min[2]);
|
|
42928
43585
|
}
|
|
42929
43586
|
/** Position the shape relative to another shape's local coordinate system (bounding box min corner). */
|
|
42930
43587
|
moveToLocal(target, x2, y2, z2) {
|
|
43588
|
+
const localX = requireFiniteNumber(x2, "Shape.moveToLocal() x");
|
|
43589
|
+
const localY = requireFiniteNumber(y2, "Shape.moveToLocal() y");
|
|
43590
|
+
const localZ = requireFiniteNumber(z2, "Shape.moveToLocal() z");
|
|
42931
43591
|
const s = "toShape" in target ? target.toShape() : target;
|
|
42932
43592
|
const tbb = s.boundingBox();
|
|
42933
|
-
return this.moveTo(tbb.min[0] +
|
|
43593
|
+
return this.moveTo(tbb.min[0] + localX, tbb.min[1] + localY, tbb.min[2] + localZ);
|
|
42934
43594
|
}
|
|
42935
43595
|
/** Rotate around an arbitrary axis through the origin. */
|
|
42936
43596
|
rotate(axis, angleDeg, options) {
|
|
@@ -42959,7 +43619,7 @@ class Shape {
|
|
|
42959
43619
|
}
|
|
42960
43620
|
/** Apply a 4x4 affine transform matrix (column-major) or a Transform object. */
|
|
42961
43621
|
transform(m2) {
|
|
42962
|
-
const mat = m2 instanceof Transform ? m2.toArray() : m2;
|
|
43622
|
+
const mat = m2 instanceof Transform ? m2.toArray() : requireFiniteMat4(m2, "Shape.transform() matrix");
|
|
42963
43623
|
const steps = rigidTransformStepsFromMatrix(mat);
|
|
42964
43624
|
if (steps == null) {
|
|
42965
43625
|
throw new Error(
|
|
@@ -42971,23 +43631,20 @@ class Shape {
|
|
|
42971
43631
|
}
|
|
42972
43632
|
/** Scale the shape uniformly or per-axis from the shape's bounding box center. Accepts a single number or [x, y, z] array. */
|
|
42973
43633
|
scale(v) {
|
|
43634
|
+
const scale2 = requireNonZeroFiniteScale3(v, "Shape.scale() scale");
|
|
42974
43635
|
const bb = this.boundingBox();
|
|
42975
43636
|
const center = [
|
|
42976
43637
|
(bb.min[0] + bb.max[0]) / 2,
|
|
42977
43638
|
(bb.min[1] + bb.max[1]) / 2,
|
|
42978
43639
|
(bb.min[2] + bb.max[2]) / 2
|
|
42979
43640
|
];
|
|
42980
|
-
return this.scaleAround(center,
|
|
43641
|
+
return this.scaleAround(center, scale2);
|
|
42981
43642
|
}
|
|
42982
43643
|
/** Scale the shape uniformly or per-axis from an explicit pivot point. */
|
|
42983
43644
|
scaleAround(pivot, v) {
|
|
42984
|
-
const scale2 =
|
|
42985
|
-
|
|
42986
|
-
|
|
42987
|
-
`Shape.scaleAround() received a degenerate scale value (${JSON.stringify(v)}). All scale components must be finite and non-zero.`
|
|
42988
|
-
);
|
|
42989
|
-
}
|
|
42990
|
-
if (pivot[0] === 0 && pivot[1] === 0 && pivot[2] === 0) {
|
|
43645
|
+
const scale2 = requireNonZeroFiniteScale3(v, "Shape.scaleAround() scale");
|
|
43646
|
+
const scalePivot = requireFiniteVec3$1(pivot, "Shape.scaleAround() pivot");
|
|
43647
|
+
if (scalePivot[0] === 0 && scalePivot[1] === 0 && scalePivot[2] === 0) {
|
|
42991
43648
|
const nextPlan2 = appendShapeCompileTransform(getShapeCompilePlanInternal(this), {
|
|
42992
43649
|
kind: "scale",
|
|
42993
43650
|
x: scale2[0],
|
|
@@ -42995,11 +43652,11 @@ class Shape {
|
|
|
42995
43652
|
z: scale2[2]
|
|
42996
43653
|
});
|
|
42997
43654
|
return setShapeCompilePlanInternal(
|
|
42998
|
-
withTransformedDimensions(this, buildShapeFromCompilePlan(nextPlan2, this.colorHex), Transform.scale(
|
|
43655
|
+
withTransformedDimensions(this, buildShapeFromCompilePlan(nextPlan2, this.colorHex), Transform.scale(scale2).toArray()),
|
|
42999
43656
|
nextPlan2
|
|
43000
43657
|
);
|
|
43001
43658
|
}
|
|
43002
|
-
const translated = this.translate(-
|
|
43659
|
+
const translated = this.translate(-scalePivot[0], -scalePivot[1], -scalePivot[2]);
|
|
43003
43660
|
const nextPlan = appendShapeCompileTransform(getShapeCompilePlanInternal(translated), {
|
|
43004
43661
|
kind: "scale",
|
|
43005
43662
|
x: scale2[0],
|
|
@@ -43007,10 +43664,10 @@ class Shape {
|
|
|
43007
43664
|
z: scale2[2]
|
|
43008
43665
|
});
|
|
43009
43666
|
const scaled = setShapeCompilePlanInternal(
|
|
43010
|
-
withTransformedDimensions(translated, buildShapeFromCompilePlan(nextPlan, translated.colorHex), Transform.scale(
|
|
43667
|
+
withTransformedDimensions(translated, buildShapeFromCompilePlan(nextPlan, translated.colorHex), Transform.scale(scale2).toArray()),
|
|
43011
43668
|
nextPlan
|
|
43012
43669
|
);
|
|
43013
|
-
return scaled.translate(
|
|
43670
|
+
return scaled.translate(scalePivot[0], scalePivot[1], scalePivot[2]);
|
|
43014
43671
|
}
|
|
43015
43672
|
/** Mirror across a plane through the shape's bounding box center, defined by its normal vector. */
|
|
43016
43673
|
mirror(normal) {
|
|
@@ -43024,32 +43681,34 @@ class Shape {
|
|
|
43024
43681
|
}
|
|
43025
43682
|
/** Mirror across a plane through an explicit point, defined by its normal vector. */
|
|
43026
43683
|
mirrorThrough(point, normal) {
|
|
43027
|
-
|
|
43684
|
+
const mirrorPoint = requireFiniteVec3$1(point, "Shape.mirrorThrough() point");
|
|
43685
|
+
const mirrorNormal = requireNonZeroFiniteVec3(normal, "Shape.mirrorThrough() normal");
|
|
43686
|
+
if (mirrorPoint[0] === 0 && mirrorPoint[1] === 0 && mirrorPoint[2] === 0) {
|
|
43028
43687
|
const transformedPlan2 = appendShapeCompileTransform(getShapeCompilePlanInternal(this), {
|
|
43029
43688
|
kind: "mirror",
|
|
43030
|
-
normalX:
|
|
43031
|
-
normalY:
|
|
43032
|
-
normalZ:
|
|
43689
|
+
normalX: mirrorNormal[0],
|
|
43690
|
+
normalY: mirrorNormal[1],
|
|
43691
|
+
normalZ: mirrorNormal[2]
|
|
43033
43692
|
});
|
|
43034
43693
|
const nextPlan2 = wrapRepeatedShapeCompilePlan(transformedPlan2, "mirror");
|
|
43035
43694
|
return setShapeCompilePlanInternal(
|
|
43036
|
-
withTransformedDimensions(this, buildShapeFromCompilePlan(nextPlan2, this.colorHex), mirrorMatrix(
|
|
43695
|
+
withTransformedDimensions(this, buildShapeFromCompilePlan(nextPlan2, this.colorHex), mirrorMatrix(mirrorNormal)),
|
|
43037
43696
|
nextPlan2
|
|
43038
43697
|
);
|
|
43039
43698
|
}
|
|
43040
|
-
const translated = this.translate(-
|
|
43699
|
+
const translated = this.translate(-mirrorPoint[0], -mirrorPoint[1], -mirrorPoint[2]);
|
|
43041
43700
|
const transformedPlan = appendShapeCompileTransform(getShapeCompilePlanInternal(translated), {
|
|
43042
43701
|
kind: "mirror",
|
|
43043
|
-
normalX:
|
|
43044
|
-
normalY:
|
|
43045
|
-
normalZ:
|
|
43702
|
+
normalX: mirrorNormal[0],
|
|
43703
|
+
normalY: mirrorNormal[1],
|
|
43704
|
+
normalZ: mirrorNormal[2]
|
|
43046
43705
|
});
|
|
43047
43706
|
const nextPlan = wrapRepeatedShapeCompilePlan(transformedPlan, "mirror");
|
|
43048
43707
|
const mirrored = setShapeCompilePlanInternal(
|
|
43049
|
-
withTransformedDimensions(translated, buildShapeFromCompilePlan(nextPlan, translated.colorHex), mirrorMatrix(
|
|
43708
|
+
withTransformedDimensions(translated, buildShapeFromCompilePlan(nextPlan, translated.colorHex), mirrorMatrix(mirrorNormal)),
|
|
43050
43709
|
nextPlan
|
|
43051
43710
|
);
|
|
43052
|
-
return mirrored.translate(
|
|
43711
|
+
return mirrored.translate(mirrorPoint[0], mirrorPoint[1], mirrorPoint[2]);
|
|
43053
43712
|
}
|
|
43054
43713
|
/**
|
|
43055
43714
|
* Reorient a shape so its primary axis (Z) points along the given direction.
|
|
@@ -43059,7 +43718,7 @@ class Shape {
|
|
|
43059
43718
|
* Example: cylinder(40, 5).pointAlong([1, 0, 0]) — lays cylinder along X, starting at origin
|
|
43060
43719
|
*/
|
|
43061
43720
|
pointAlong(direction) {
|
|
43062
|
-
const [dx, dy, dz] = direction;
|
|
43721
|
+
const [dx, dy, dz] = requireNonZeroFiniteVec3(direction, "Shape.pointAlong() direction");
|
|
43063
43722
|
const len = Math.sqrt(dx * dx + dy * dy + dz * dz) || 1;
|
|
43064
43723
|
const nx = dx / len, ny = dy / len, nz = dz / len;
|
|
43065
43724
|
const cx = -ny, cy = nx, cz = 0;
|
|
@@ -43078,18 +43737,21 @@ class Shape {
|
|
|
43078
43737
|
* @internal Prefer rotate(), rotateX(), rotateY(), rotateZ() for public use.
|
|
43079
43738
|
*/
|
|
43080
43739
|
rotateAroundAxis(axis, angleDeg, pivot = [0, 0, 0]) {
|
|
43081
|
-
const
|
|
43082
|
-
const
|
|
43083
|
-
const
|
|
43740
|
+
const rotateAxis = requireNonZeroFiniteVec3(axis, "Shape.rotateAroundAxis() axis");
|
|
43741
|
+
const degrees = requireFiniteNumber(angleDeg, "Shape.rotateAroundAxis() angleDeg");
|
|
43742
|
+
const rotatePivot = requireFiniteVec3$1(pivot, "Shape.rotateAroundAxis() pivot");
|
|
43743
|
+
const len = Math.sqrt(rotateAxis[0] ** 2 + rotateAxis[1] ** 2 + rotateAxis[2] ** 2) || 1;
|
|
43744
|
+
const normalizedAxis = [rotateAxis[0] / len, rotateAxis[1] / len, rotateAxis[2] / len];
|
|
43745
|
+
const matrix = rotationAroundAxisMatrix(normalizedAxis, degrees, rotatePivot);
|
|
43084
43746
|
const nextPlan = appendShapeCompileTransform(getShapeCompilePlanInternal(this), {
|
|
43085
43747
|
kind: "rotateAround",
|
|
43086
43748
|
axisX: normalizedAxis[0],
|
|
43087
43749
|
axisY: normalizedAxis[1],
|
|
43088
43750
|
axisZ: normalizedAxis[2],
|
|
43089
|
-
degrees
|
|
43090
|
-
pivotX:
|
|
43091
|
-
pivotY:
|
|
43092
|
-
pivotZ:
|
|
43751
|
+
degrees,
|
|
43752
|
+
pivotX: rotatePivot[0],
|
|
43753
|
+
pivotY: rotatePivot[1],
|
|
43754
|
+
pivotZ: rotatePivot[2]
|
|
43093
43755
|
});
|
|
43094
43756
|
return setShapeCompilePlanInternal(
|
|
43095
43757
|
withTransformedDimensions(this, buildShapeFromCompilePlan(nextPlan, this.colorHex), matrix),
|
|
@@ -43101,10 +43763,12 @@ class Shape {
|
|
|
43101
43763
|
* `movingPoint` / `targetPoint` may be raw world points or this shape's anchors/references.
|
|
43102
43764
|
*/
|
|
43103
43765
|
rotateAroundTo(axis, pivot, movingPoint, targetPoint, options = {}) {
|
|
43766
|
+
const rotateAxis = requireNonZeroFiniteVec3(axis, "Shape.rotateAroundTo() axis");
|
|
43767
|
+
const rotatePivot = requireFiniteVec3$1(pivot, "Shape.rotateAroundTo() pivot");
|
|
43104
43768
|
const moving = resolveRotationPoint(this, movingPoint);
|
|
43105
43769
|
const target = resolveRotationPoint(this, targetPoint);
|
|
43106
|
-
const angleDeg = solveRotateAroundAngle(
|
|
43107
|
-
return this.rotateAroundAxis(
|
|
43770
|
+
const angleDeg = solveRotateAroundAngle(rotateAxis, rotatePivot, moving, target, options);
|
|
43771
|
+
return this.rotateAroundAxis(rotateAxis, angleDeg, rotatePivot);
|
|
43108
43772
|
}
|
|
43109
43773
|
// --- Booleans ---
|
|
43110
43774
|
/** Unwrap any object with toShape() without circular import. */
|
|
@@ -43268,17 +43932,19 @@ class Shape {
|
|
|
43268
43932
|
}
|
|
43269
43933
|
/** Split by infinite plane. Returns [positive-side, negative-side]. */
|
|
43270
43934
|
splitByPlane(normal, originOffset = 0) {
|
|
43935
|
+
const planeNormal = requireNonZeroFiniteVec3(normal, "Shape.splitByPlane() normal");
|
|
43936
|
+
const planeOffset = requireFiniteNumber(originOffset, "Shape.splitByPlane() originOffset");
|
|
43271
43937
|
const info = deriveGeometryInfo(getShapeGeometryInfoInternal(this), "boolean", {
|
|
43272
43938
|
topology: _activeBackend === "truck" ? "kernel" : "none"
|
|
43273
43939
|
});
|
|
43274
43940
|
const basePlan = getShapeCompilePlanInternal(this);
|
|
43275
43941
|
const firstPlan = createOwnedTopologyRewritePlan(
|
|
43276
|
-
buildTrimByPlaneShapeCompilePlan(basePlan,
|
|
43942
|
+
buildTrimByPlaneShapeCompilePlan(basePlan, planeNormal, planeOffset),
|
|
43277
43943
|
"splitByPlane:positive",
|
|
43278
43944
|
(owner) => buildTrimByPlaneTopologyRewritePropagation(owner, basePlan)
|
|
43279
43945
|
);
|
|
43280
43946
|
const secondPlan = createOwnedTopologyRewritePlan(
|
|
43281
|
-
buildTrimByPlaneShapeCompilePlan(basePlan, [-
|
|
43947
|
+
buildTrimByPlaneShapeCompilePlan(basePlan, [-planeNormal[0], -planeNormal[1], -planeNormal[2]], -planeOffset),
|
|
43282
43948
|
"splitByPlane:opposite",
|
|
43283
43949
|
(owner) => buildTrimByPlaneTopologyRewritePropagation(owner, basePlan)
|
|
43284
43950
|
);
|
|
@@ -43296,9 +43962,11 @@ class Shape {
|
|
|
43296
43962
|
}
|
|
43297
43963
|
/** Keep the positive side of the plane and discard the opposite side. */
|
|
43298
43964
|
trimByPlane(normal, originOffset = 0) {
|
|
43965
|
+
const planeNormal = requireNonZeroFiniteVec3(normal, "Shape.trimByPlane() normal");
|
|
43966
|
+
const planeOffset = requireFiniteNumber(originOffset, "Shape.trimByPlane() originOffset");
|
|
43299
43967
|
const basePlan = getShapeCompilePlanInternal(this);
|
|
43300
43968
|
const nextPlan = createOwnedTopologyRewritePlan(
|
|
43301
|
-
buildTrimByPlaneShapeCompilePlan(basePlan,
|
|
43969
|
+
buildTrimByPlaneShapeCompilePlan(basePlan, planeNormal, planeOffset),
|
|
43302
43970
|
"trimByPlane",
|
|
43303
43971
|
(owner) => buildTrimByPlaneTopologyRewritePropagation(owner, basePlan)
|
|
43304
43972
|
);
|
|
@@ -43318,8 +43986,9 @@ class Shape {
|
|
|
43318
43986
|
* `openFaces` names any subset of the base shape's labeled faces to leave open (no wall).
|
|
43319
43987
|
*/
|
|
43320
43988
|
shell(thickness, opts = {}) {
|
|
43989
|
+
const wallThickness = requirePositiveFiniteNumber(thickness, "Shape.shell() thickness");
|
|
43321
43990
|
const basePlan = getShapeCompilePlanInternal(this);
|
|
43322
|
-
const shellPlan = buildShellShapeCompilePlan(basePlan,
|
|
43991
|
+
const shellPlan = buildShellShapeCompilePlan(basePlan, wallThickness, opts.openFaces);
|
|
43323
43992
|
if (!shellPlan) {
|
|
43324
43993
|
throw new Error(
|
|
43325
43994
|
"Shape.shell() supports box(), cylinder(), straight extrude(), loft(), sweep(), and variableSweep() solids with optional face openings and rigid transforms."
|
|
@@ -43340,7 +44009,8 @@ class Shape {
|
|
|
43340
44009
|
}
|
|
43341
44010
|
/** Offset-thicken an exact open surface or shell into a solid. */
|
|
43342
44011
|
thicken(thickness) {
|
|
43343
|
-
|
|
44012
|
+
const wallThickness = requireFiniteNumber(thickness, "Shape.thicken() thickness");
|
|
44013
|
+
if (wallThickness === 0) {
|
|
43344
44014
|
throw new Error("Shape.thicken() requires a non-zero finite thickness.");
|
|
43345
44015
|
}
|
|
43346
44016
|
const info = getShapeGeometryInfoInternal(this);
|
|
@@ -43348,7 +44018,7 @@ class Shape {
|
|
|
43348
44018
|
throw new Error("Shape.thicken() is only available on surface-representation shapes.");
|
|
43349
44019
|
}
|
|
43350
44020
|
const basePlan = getShapeCompilePlanInternal(this);
|
|
43351
|
-
const nextPlan = buildSurfaceThickenShapeCompilePlan(basePlan,
|
|
44021
|
+
const nextPlan = buildSurfaceThickenShapeCompilePlan(basePlan, wallThickness);
|
|
43352
44022
|
const representation = info.backend === "occt" || info.backend === "truck" ? "brep-solid" : "mesh-solid";
|
|
43353
44023
|
return setShapeCompilePlanInternal(
|
|
43354
44024
|
setShapeGeometryInfoInternal(
|
|
@@ -43389,11 +44059,12 @@ class Shape {
|
|
|
43389
44059
|
}
|
|
43390
44060
|
/** Slice the runtime solid by a plane normal to local Z at the given offset. */
|
|
43391
44061
|
slice(offset = 0) {
|
|
44062
|
+
const planeOffset = requireFiniteNumber(offset, "Shape.slice() offset");
|
|
43392
44063
|
if (getShapeGeometryInfoInternal(this).backend === "truck") {
|
|
43393
|
-
const slicedProfile = lowerExactSlicedShapeCompilePlanToTruckProfileBackend(getShapeCompilePlanInternal(this),
|
|
44064
|
+
const slicedProfile = lowerExactSlicedShapeCompilePlanToTruckProfileBackend(getShapeCompilePlanInternal(this), planeOffset);
|
|
43394
44065
|
if (slicedProfile) return slicedProfile;
|
|
43395
44066
|
}
|
|
43396
|
-
return getShapeRuntimeBackendInternal(this).slice(
|
|
44067
|
+
return getShapeRuntimeBackendInternal(this).slice(planeOffset);
|
|
43397
44068
|
}
|
|
43398
44069
|
/** Orthographically project the runtime solid onto the local XY plane. */
|
|
43399
44070
|
project() {
|
|
@@ -43416,9 +44087,10 @@ class Shape {
|
|
|
43416
44087
|
const sp = this.referencePoint(selfAnchor);
|
|
43417
44088
|
let dx = tp[0] - sp[0], dy = tp[1] - sp[1], dz = tp[2] - sp[2];
|
|
43418
44089
|
if (offset) {
|
|
43419
|
-
|
|
43420
|
-
|
|
43421
|
-
|
|
44090
|
+
const offsetPoint = requireFiniteVec3$1(offset, "Shape.attachTo() offset");
|
|
44091
|
+
dx += offsetPoint[0];
|
|
44092
|
+
dy += offsetPoint[1];
|
|
44093
|
+
dz += offsetPoint[2];
|
|
43422
44094
|
}
|
|
43423
44095
|
return this.translate(dx, dy, dz);
|
|
43424
44096
|
}
|
|
@@ -43434,9 +44106,9 @@ class Shape {
|
|
|
43434
44106
|
* - `protrude` = how far the child sticks out (positive = outward from face)
|
|
43435
44107
|
*/
|
|
43436
44108
|
onFace(parent, face, opts = {}) {
|
|
43437
|
-
const u2 = opts.u ?? 0;
|
|
43438
|
-
const v = opts.v ?? 0;
|
|
43439
|
-
const p2 = opts.protrude ?? 0;
|
|
44109
|
+
const u2 = requireFiniteNumber(opts.u ?? 0, "Shape.onFace() u");
|
|
44110
|
+
const v = requireFiniteNumber(opts.v ?? 0, "Shape.onFace() v");
|
|
44111
|
+
const p2 = requireFiniteNumber(opts.protrude ?? 0, "Shape.onFace() protrude");
|
|
43440
44112
|
const opposite = {
|
|
43441
44113
|
front: "back",
|
|
43442
44114
|
back: "front",
|
|
@@ -44015,6 +44687,8 @@ function sampleSweepPath(path, edgeLengthHint) {
|
|
|
44015
44687
|
path,
|
|
44016
44688
|
edgeLengthHint != null ? Math.max(16, Math.round(path.controlPoints.length * 12 / Math.max(0.1, edgeLengthHint))) : 48
|
|
44017
44689
|
);
|
|
44690
|
+
case "route3d":
|
|
44691
|
+
return sweepPathToPolyline(path, resolveCurveSampleCount(edgeLengthHint, path.length));
|
|
44018
44692
|
}
|
|
44019
44693
|
}
|
|
44020
44694
|
function clamp(v, lo, hi) {
|
|
@@ -45144,6 +45818,7 @@ function rotateVector(v, axis, c2, s) {
|
|
|
45144
45818
|
];
|
|
45145
45819
|
}
|
|
45146
45820
|
const OFFSET_SOLID_EPS = 1e-9;
|
|
45821
|
+
const OCCT_BACKEND_REQUIRED_HINT = "Select the OCCT backend in the editor or run the CLI with --backend occt.";
|
|
45147
45822
|
function disposeWasmObject(value) {
|
|
45148
45823
|
if (value != null && typeof value.delete === "function") value.delete();
|
|
45149
45824
|
}
|
|
@@ -45628,7 +46303,7 @@ function profilePolygonLoopTopologyMatches(left, right) {
|
|
|
45628
46303
|
}
|
|
45629
46304
|
function lowerOffsetLoftCompilePlan(plan, thickness, wasm) {
|
|
45630
46305
|
if (plan.profiles.length !== plan.heights.length || plan.profiles.length < 2) {
|
|
45631
|
-
throw new Error(
|
|
46306
|
+
throw new Error(`Offset solid requires the OCCT backend. ${OCCT_BACKEND_REQUIRED_HINT}`);
|
|
45632
46307
|
}
|
|
45633
46308
|
const heights = [...plan.heights];
|
|
45634
46309
|
heights[0] -= thickness;
|
|
@@ -45639,7 +46314,7 @@ function lowerOffsetLoftCompilePlan(plan, thickness, wasm) {
|
|
|
45639
46314
|
const offsetPolygons = plan.profiles.map((profile) => offsetProfilePolygonsForManifold(profile, thickness, wasm));
|
|
45640
46315
|
const stitched = loftStitched(offsetPolygons, heights, wasm);
|
|
45641
46316
|
if (!stitched) {
|
|
45642
|
-
throw new Error(
|
|
46317
|
+
throw new Error(`Offset solid requires the OCCT backend. ${OCCT_BACKEND_REQUIRED_HINT}`);
|
|
45643
46318
|
}
|
|
45644
46319
|
return stitched;
|
|
45645
46320
|
}
|
|
@@ -45679,16 +46354,16 @@ function lowerOffsetSweepCompilePlan(plan, thickness, wasm) {
|
|
|
45679
46354
|
const basePolygons = profilePolygonsForManifold(plan.profile, wasm);
|
|
45680
46355
|
const offsetPolygons = offsetProfilePolygonsForManifold(plan.profile, thickness, wasm);
|
|
45681
46356
|
if (!profilePolygonLoopTopologyMatches(basePolygons, offsetPolygons)) {
|
|
45682
|
-
throw new Error(
|
|
46357
|
+
throw new Error(`Offset solid requires the OCCT backend. ${OCCT_BACKEND_REQUIRED_HINT}`);
|
|
45683
46358
|
}
|
|
45684
46359
|
const pathPoints = sweepPathToPolylineAdaptive(plan.path, plan.pathSamples ?? 48);
|
|
45685
46360
|
const extendedPath = extendedStraightSweepPathForManifold(pathPoints, thickness);
|
|
45686
46361
|
if (!extendedPath) {
|
|
45687
|
-
throw new Error(
|
|
46362
|
+
throw new Error(`Offset solid requires the OCCT backend. ${OCCT_BACKEND_REQUIRED_HINT}`);
|
|
45688
46363
|
}
|
|
45689
46364
|
const stitched = sweepStitched(offsetPolygons, extendedPath, [plan.up[0], plan.up[1], plan.up[2]], wasm);
|
|
45690
46365
|
if (!stitched) {
|
|
45691
|
-
throw new Error(
|
|
46366
|
+
throw new Error(`Offset solid requires the OCCT backend. ${OCCT_BACKEND_REQUIRED_HINT}`);
|
|
45692
46367
|
}
|
|
45693
46368
|
return stitched;
|
|
45694
46369
|
}
|
|
@@ -45697,7 +46372,7 @@ function lowerTransformedOffsetSolidCompilePlan(plan, thickness, wasm) {
|
|
|
45697
46372
|
for (const step of plan.steps) {
|
|
45698
46373
|
const stepScale = offsetSolidTransformDistanceScaleForManifold(step);
|
|
45699
46374
|
if (stepScale == null) {
|
|
45700
|
-
throw new Error(
|
|
46375
|
+
throw new Error(`Offset solid requires the OCCT backend. ${OCCT_BACKEND_REQUIRED_HINT}`);
|
|
45701
46376
|
}
|
|
45702
46377
|
distanceScale *= stepScale;
|
|
45703
46378
|
}
|
|
@@ -45738,7 +46413,7 @@ function lowerOffsetSolidCompilePlan(plan, wasm) {
|
|
|
45738
46413
|
}
|
|
45739
46414
|
const base = verticalPrismOffsetBaseForManifold(basePlan);
|
|
45740
46415
|
if (!base) {
|
|
45741
|
-
throw new Error(
|
|
46416
|
+
throw new Error(`Offset solid requires the OCCT backend. ${OCCT_BACKEND_REQUIRED_HINT}`);
|
|
45742
46417
|
}
|
|
45743
46418
|
const zMin = base.zMin - plan.thickness;
|
|
45744
46419
|
const zMax = base.zMax + plan.thickness;
|
|
@@ -46263,6 +46938,18 @@ function matchEdgeSegmentByMidpoint(segments, target) {
|
|
|
46263
46938
|
}
|
|
46264
46939
|
return best;
|
|
46265
46940
|
}
|
|
46941
|
+
function selectEdgeSegmentsForFeature(segments, plan) {
|
|
46942
|
+
if (plan.edgeQuery) {
|
|
46943
|
+
const selected = applyEdgeQueryFilters(segments, plan.edgeQuery);
|
|
46944
|
+
return plan.edgeSelection === "first" ? selected.slice(0, 1) : selected;
|
|
46945
|
+
}
|
|
46946
|
+
const matched = [];
|
|
46947
|
+
for (const target of plan.edgeTargets ?? []) {
|
|
46948
|
+
const seg = matchEdgeSegmentByMidpoint(segments, target);
|
|
46949
|
+
if (seg && seg.length >= 1e-6) matched.push(seg);
|
|
46950
|
+
}
|
|
46951
|
+
return matched;
|
|
46952
|
+
}
|
|
46266
46953
|
function lowerFilletEdgesCompilePlan(plan, wasm) {
|
|
46267
46954
|
let manifold = lowerShapeCompilePlanToManifold(plan.base, wasm);
|
|
46268
46955
|
const mesh = manifold.getMesh();
|
|
@@ -46272,11 +46959,8 @@ function lowerFilletEdgesCompilePlan(plan, wasm) {
|
|
|
46272
46959
|
triVerts: mesh.triVerts,
|
|
46273
46960
|
vertProperties: mesh.vertProperties
|
|
46274
46961
|
});
|
|
46275
|
-
const matched =
|
|
46276
|
-
|
|
46277
|
-
const seg = matchEdgeSegmentByMidpoint(segments, target);
|
|
46278
|
-
if (seg && seg.length >= 1e-6) matched.push(seg);
|
|
46279
|
-
}
|
|
46962
|
+
const matched = selectEdgeSegmentsForFeature(segments, plan);
|
|
46963
|
+
if (plan.edgeQuery && matched.length === 0) throw new Error("filletEdges(): no edges match the deferred edge query.");
|
|
46280
46964
|
matched.sort((a2, b) => b.length - a2.length);
|
|
46281
46965
|
for (const seg of matched) {
|
|
46282
46966
|
try {
|
|
@@ -46299,11 +46983,8 @@ function lowerChamferEdgesCompilePlan(plan, wasm) {
|
|
|
46299
46983
|
triVerts: mesh.triVerts,
|
|
46300
46984
|
vertProperties: mesh.vertProperties
|
|
46301
46985
|
});
|
|
46302
|
-
const matched =
|
|
46303
|
-
|
|
46304
|
-
const seg = matchEdgeSegmentByMidpoint(segments, target);
|
|
46305
|
-
if (seg && seg.length >= 1e-6) matched.push(seg);
|
|
46306
|
-
}
|
|
46986
|
+
const matched = selectEdgeSegmentsForFeature(segments, plan);
|
|
46987
|
+
if (plan.edgeQuery && matched.length === 0) throw new Error("chamferEdges(): no edges match the deferred edge query.");
|
|
46307
46988
|
matched.sort((a2, b) => b.length - a2.length);
|
|
46308
46989
|
for (const seg of matched) {
|
|
46309
46990
|
try {
|
|
@@ -46405,20 +47086,20 @@ function lowerShapeCompilePlanToManifold(plan, wasm) {
|
|
|
46405
47086
|
case "filletEdges":
|
|
46406
47087
|
return lowerFilletEdgesCompilePlan(plan, wasm);
|
|
46407
47088
|
case "cornerYBlend":
|
|
46408
|
-
throw new Error(
|
|
47089
|
+
throw new Error(`Blend.CornerY() requires the OCCT backend. ${OCCT_BACKEND_REQUIRED_HINT}`);
|
|
46409
47090
|
case "chamferEdges":
|
|
46410
47091
|
return lowerChamferEdgesCompilePlan(plan, wasm);
|
|
46411
47092
|
case "draft": {
|
|
46412
47093
|
const lowered = lowerDraftShapeCompilePlanToLoftPlan(plan);
|
|
46413
47094
|
if (lowered) return lowerShapeCompilePlanToManifold(lowered, wasm);
|
|
46414
|
-
throw new Error(
|
|
47095
|
+
throw new Error(`Draft angle requires the OCCT backend. ${OCCT_BACKEND_REQUIRED_HINT}`);
|
|
46415
47096
|
}
|
|
46416
47097
|
case "offsetSolid":
|
|
46417
47098
|
return lowerOffsetSolidCompilePlan(plan, wasm);
|
|
46418
47099
|
case "trimByPlane":
|
|
46419
47100
|
return lowerShapeTrimByPlaneCompilePlan(plan, wasm);
|
|
46420
47101
|
case "importedMesh":
|
|
46421
|
-
return lowerImportedMeshToManifold(plan.fileData, plan.format, plan.filePath, wasm);
|
|
47102
|
+
return lowerImportedMeshToManifold(plan.fileData, plan.format, plan.filePath, wasm, plan.object);
|
|
46422
47103
|
case "sdf": {
|
|
46423
47104
|
const evaluator = compileSdfMaterializationEvaluator3(plan.tree);
|
|
46424
47105
|
return lowerSdfToManifold(
|
|
@@ -46442,9 +47123,9 @@ function lowerShapeCompilePlanToManifold(plan, wasm) {
|
|
|
46442
47123
|
case "surfaceExtend":
|
|
46443
47124
|
case "surfaceThicken":
|
|
46444
47125
|
case "surfaceSolid":
|
|
46445
|
-
throw new Error(
|
|
47126
|
+
throw new Error(`Exact surfacing operations require the OCCT backend. ${OCCT_BACKEND_REQUIRED_HINT}`);
|
|
46446
47127
|
case "importedStep":
|
|
46447
|
-
throw new Error(`importStep("${plan.filePath}") requires the OCCT backend.
|
|
47128
|
+
throw new Error(`importStep("${plan.filePath}") requires the OCCT backend. ${OCCT_BACKEND_REQUIRED_HINT}`);
|
|
46448
47129
|
default:
|
|
46449
47130
|
assertExhaustive(plan);
|
|
46450
47131
|
}
|
|
@@ -46585,11 +47266,11 @@ function projectVerticesToSurfaceWithNormals(vertProperties, sdfFn, out6) {
|
|
|
46585
47266
|
function lowerNurbsSurfaceToManifold(plan, wasm) {
|
|
46586
47267
|
if (!plan.allowApproximation && plan.thickness === 0) {
|
|
46587
47268
|
throw new Error(
|
|
46588
|
-
|
|
47269
|
+
`nurbsSurface() now defaults to an exact open sheet. The Manifold backend cannot represent exact open surfaces. ${OCCT_BACKEND_REQUIRED_HINT} Pass { approximate: true } with a non-zero thickness if you explicitly want a sampled fallback.`
|
|
46589
47270
|
);
|
|
46590
47271
|
}
|
|
46591
47272
|
if (plan.thickness === 0) {
|
|
46592
|
-
throw new Error(
|
|
47273
|
+
throw new Error(`The Manifold backend cannot represent open sheet surfaces. ${OCCT_BACKEND_REQUIRED_HINT}`);
|
|
46593
47274
|
}
|
|
46594
47275
|
const surface = new NurbsSurface(plan.controlGrid, {
|
|
46595
47276
|
degreeU: plan.degreeU,
|
|
@@ -46739,8 +47420,8 @@ function lowerTrimmedNurbsSurfaceToManifold(surface, plan, wasm) {
|
|
|
46739
47420
|
disposeWasmObject(mesh);
|
|
46740
47421
|
}
|
|
46741
47422
|
}
|
|
46742
|
-
function lowerImportedMeshToManifold(fileData, format, filePath, wasm) {
|
|
46743
|
-
const parsed = parseMeshFile(fileData, format);
|
|
47423
|
+
function lowerImportedMeshToManifold(fileData, format, filePath, wasm, object) {
|
|
47424
|
+
const parsed = parseMeshFile(fileData, format, { object });
|
|
46744
47425
|
if (parsed.triVerts.length === 0) {
|
|
46745
47426
|
throw new Error(`importMesh("${filePath}"): file contains no triangles`);
|
|
46746
47427
|
}
|
|
@@ -46762,7 +47443,11 @@ function lowerImportedMeshToManifold(fileData, format, filePath, wasm) {
|
|
|
46762
47443
|
}
|
|
46763
47444
|
}
|
|
46764
47445
|
function lowerShapeCompilePlanToShapeBackend(plan, wasm) {
|
|
46765
|
-
return lowerShapeBackendWithCache(
|
|
47446
|
+
return lowerShapeBackendWithCache(
|
|
47447
|
+
"manifold",
|
|
47448
|
+
plan,
|
|
47449
|
+
(basePlan) => wrapManifoldShapeBackend(lowerShapeCompilePlanToManifold(basePlan, wasm))
|
|
47450
|
+
);
|
|
46766
47451
|
}
|
|
46767
47452
|
const DEFAULT_LEAF_SIZE = 8;
|
|
46768
47453
|
function cloneVec3$3(value) {
|
|
@@ -48104,6 +48789,92 @@ function percentile(sorted, q) {
|
|
|
48104
48789
|
const index2 = MathUtils.clamp(Math.floor(sorted.length * q), 0, sorted.length - 1);
|
|
48105
48790
|
return Number(sorted[index2].toFixed(2));
|
|
48106
48791
|
}
|
|
48792
|
+
class DisjointSet {
|
|
48793
|
+
constructor(size) {
|
|
48794
|
+
__publicField(this, "parent");
|
|
48795
|
+
__publicField(this, "rank");
|
|
48796
|
+
this.parent = Array.from({ length: size }, (_2, index2) => index2);
|
|
48797
|
+
this.rank = Array.from({ length: size }, () => 0);
|
|
48798
|
+
}
|
|
48799
|
+
find(index2) {
|
|
48800
|
+
const parent = this.parent[index2];
|
|
48801
|
+
if (parent === index2) return index2;
|
|
48802
|
+
const root = this.find(parent);
|
|
48803
|
+
this.parent[index2] = root;
|
|
48804
|
+
return root;
|
|
48805
|
+
}
|
|
48806
|
+
union(a2, b) {
|
|
48807
|
+
const rootA = this.find(a2);
|
|
48808
|
+
const rootB = this.find(b);
|
|
48809
|
+
if (rootA === rootB) return;
|
|
48810
|
+
if (this.rank[rootA] < this.rank[rootB]) {
|
|
48811
|
+
this.parent[rootA] = rootB;
|
|
48812
|
+
} else if (this.rank[rootA] > this.rank[rootB]) {
|
|
48813
|
+
this.parent[rootB] = rootA;
|
|
48814
|
+
} else {
|
|
48815
|
+
this.parent[rootB] = rootA;
|
|
48816
|
+
this.rank[rootA] += 1;
|
|
48817
|
+
}
|
|
48818
|
+
}
|
|
48819
|
+
}
|
|
48820
|
+
function connectedCoplanarSurfacePatches(triangles) {
|
|
48821
|
+
const snap = surfacePatchSnap(triangles);
|
|
48822
|
+
const planeKeys = triangles.map((triangle) => planeKey(triangle, snap));
|
|
48823
|
+
const edgeOwners = /* @__PURE__ */ new Map();
|
|
48824
|
+
const sets = new DisjointSet(triangles.length);
|
|
48825
|
+
triangles.forEach((triangle, index2) => {
|
|
48826
|
+
for (const key of triangleEdgeKeys(triangle, snap)) {
|
|
48827
|
+
const owners = edgeOwners.get(key);
|
|
48828
|
+
if (owners) {
|
|
48829
|
+
for (const owner of owners) {
|
|
48830
|
+
if (planeKeys[owner] === planeKeys[index2]) sets.union(owner, index2);
|
|
48831
|
+
}
|
|
48832
|
+
owners.push(index2);
|
|
48833
|
+
} else {
|
|
48834
|
+
edgeOwners.set(key, [index2]);
|
|
48835
|
+
}
|
|
48836
|
+
}
|
|
48837
|
+
});
|
|
48838
|
+
const patchByRoot = /* @__PURE__ */ new Map();
|
|
48839
|
+
triangles.forEach((triangle, index2) => {
|
|
48840
|
+
const root = sets.find(index2);
|
|
48841
|
+
const patch = patchByRoot.get(root) ?? { triangleIndexes: [], area: 0 };
|
|
48842
|
+
patch.triangleIndexes.push(index2);
|
|
48843
|
+
patch.area += triangle.area;
|
|
48844
|
+
patchByRoot.set(root, patch);
|
|
48845
|
+
});
|
|
48846
|
+
return [...patchByRoot.values()];
|
|
48847
|
+
}
|
|
48848
|
+
function surfacePatchSnap(triangles) {
|
|
48849
|
+
const bounds = new Box3();
|
|
48850
|
+
for (const triangle of triangles) {
|
|
48851
|
+
bounds.expandByPoint(triangle.a);
|
|
48852
|
+
bounds.expandByPoint(triangle.b);
|
|
48853
|
+
bounds.expandByPoint(triangle.c);
|
|
48854
|
+
}
|
|
48855
|
+
const size = bounds.getSize(new Vector3());
|
|
48856
|
+
return Math.max(1e-6, size.length() * 1e-8);
|
|
48857
|
+
}
|
|
48858
|
+
function planeKey(triangle, snap) {
|
|
48859
|
+
const normalSnap = 1e-6;
|
|
48860
|
+
const distance = triangle.normal.dot(triangle.a);
|
|
48861
|
+
return [
|
|
48862
|
+
Math.round(triangle.normal.x / normalSnap),
|
|
48863
|
+
Math.round(triangle.normal.y / normalSnap),
|
|
48864
|
+
Math.round(triangle.normal.z / normalSnap),
|
|
48865
|
+
Math.round(distance / snap)
|
|
48866
|
+
].join(",");
|
|
48867
|
+
}
|
|
48868
|
+
function triangleEdgeKeys(triangle, snap) {
|
|
48869
|
+
const vertices = [vertexKey$2(triangle.a, snap), vertexKey$2(triangle.b, snap), vertexKey$2(triangle.c, snap)];
|
|
48870
|
+
return [edgeKey$1(vertices[0], vertices[1]), edgeKey$1(vertices[1], vertices[2]), edgeKey$1(vertices[2], vertices[0])];
|
|
48871
|
+
}
|
|
48872
|
+
function vertexKey$2(point, snap) {
|
|
48873
|
+
return `${Math.round(point.x / snap)},${Math.round(point.y / snap)},${Math.round(point.z / snap)}`;
|
|
48874
|
+
}
|
|
48875
|
+
function edgeKey$1(a2, b) {
|
|
48876
|
+
return a2 < b ? `${a2}|${b}` : `${b}|${a2}`;
|
|
48877
|
+
}
|
|
48107
48878
|
const MIN_TRIANGLE_AREA = 1e-12;
|
|
48108
48879
|
const R2_ALPHA = 0.7548776662466927;
|
|
48109
48880
|
const R2_BETA = 0.5698402909980532;
|
|
@@ -48156,7 +48927,7 @@ function allocateAreaSampleCounts(triangles, maxSamples) {
|
|
|
48156
48927
|
return counts;
|
|
48157
48928
|
}
|
|
48158
48929
|
function sampleSurfaceTriangles(triangles, maxSamples) {
|
|
48159
|
-
const counts =
|
|
48930
|
+
const counts = allocateSurfacePatchSampleCounts(triangles, maxSamples);
|
|
48160
48931
|
const samples = [];
|
|
48161
48932
|
const position = new Vector3();
|
|
48162
48933
|
let sampleIndex = 0;
|
|
@@ -48181,6 +48952,35 @@ function sampleSurfaceTriangles(triangles, maxSamples) {
|
|
|
48181
48952
|
});
|
|
48182
48953
|
return samples;
|
|
48183
48954
|
}
|
|
48955
|
+
function allocateSurfacePatchSampleCounts(triangles, maxSamples) {
|
|
48956
|
+
const counts = new Array(triangles.length).fill(0);
|
|
48957
|
+
if (triangles.length === 0) return counts;
|
|
48958
|
+
const patches = connectedCoplanarSurfacePatches(triangles);
|
|
48959
|
+
const patchCounts = allocateAreaSampleCounts(
|
|
48960
|
+
patches.map((patch, index2) => {
|
|
48961
|
+
var _a3, _b3, _c2, _d2;
|
|
48962
|
+
return {
|
|
48963
|
+
index: index2,
|
|
48964
|
+
a: ((_a3 = triangles[patch.triangleIndexes[0]]) == null ? void 0 : _a3.a) ?? new Vector3(),
|
|
48965
|
+
b: ((_b3 = triangles[patch.triangleIndexes[0]]) == null ? void 0 : _b3.b) ?? new Vector3(),
|
|
48966
|
+
c: ((_c2 = triangles[patch.triangleIndexes[0]]) == null ? void 0 : _c2.c) ?? new Vector3(),
|
|
48967
|
+
normal: ((_d2 = triangles[patch.triangleIndexes[0]]) == null ? void 0 : _d2.normal) ?? new Vector3(0, 0, 1),
|
|
48968
|
+
area: patch.area
|
|
48969
|
+
};
|
|
48970
|
+
}),
|
|
48971
|
+
maxSamples
|
|
48972
|
+
);
|
|
48973
|
+
patches.forEach((patch, patchIndex) => {
|
|
48974
|
+
const patchBudget = patchCounts[patchIndex] ?? 0;
|
|
48975
|
+
if (patchBudget <= 0) return;
|
|
48976
|
+
const patchTriangles = patch.triangleIndexes.map((index2) => triangles[index2]);
|
|
48977
|
+
const localCounts = allocateAreaSampleCounts(patchTriangles, patchBudget);
|
|
48978
|
+
patch.triangleIndexes.forEach((triangleIndex, localIndex) => {
|
|
48979
|
+
counts[triangleIndex] += localCounts[localIndex] ?? 0;
|
|
48980
|
+
});
|
|
48981
|
+
});
|
|
48982
|
+
return counts;
|
|
48983
|
+
}
|
|
48184
48984
|
function totalSurfaceArea(triangles) {
|
|
48185
48985
|
return triangles.reduce((sum2, triangle) => sum2 + triangle.area, 0);
|
|
48186
48986
|
}
|
|
@@ -48361,16 +49161,23 @@ const DEFAULT_THICKNESS_INSPECTION_OPTIONS = {
|
|
|
48361
49161
|
minThickness: 1.2,
|
|
48362
49162
|
warnThickness: 2,
|
|
48363
49163
|
maxThickness: 6,
|
|
49164
|
+
colorMinThickness: 0,
|
|
49165
|
+
colorMaxThickness: 6,
|
|
48364
49166
|
maxSamplesPerObject: 5e3,
|
|
48365
49167
|
contactTolerance: DEFAULT_PHYSICAL_CONNECTIVITY_OPTIONS.contactTolerance
|
|
48366
49168
|
};
|
|
48367
49169
|
const THICKNESS_COLORS = {
|
|
48368
49170
|
critical: [255, 28, 28],
|
|
48369
|
-
warning: [255, 150, 0],
|
|
48370
49171
|
ok: [60, 220, 90],
|
|
48371
49172
|
thick: [70, 145, 255],
|
|
48372
49173
|
unknown: [90, 90, 90]
|
|
48373
49174
|
};
|
|
49175
|
+
const THICKNESS_GRADIENT_COLORS = [
|
|
49176
|
+
THICKNESS_COLORS.critical,
|
|
49177
|
+
[255, 222, 0],
|
|
49178
|
+
THICKNESS_COLORS.ok,
|
|
49179
|
+
THICKNESS_COLORS.thick
|
|
49180
|
+
];
|
|
48374
49181
|
function finitePositive(value, fallback, label) {
|
|
48375
49182
|
if (value === void 0) return fallback;
|
|
48376
49183
|
if (!Number.isFinite(value) || value <= 0) {
|
|
@@ -48389,6 +49196,16 @@ function resolveThicknessInspectionOptions(raw = {}) {
|
|
|
48389
49196
|
const minThickness = finitePositive(raw.minThickness, DEFAULT_THICKNESS_INSPECTION_OPTIONS.minThickness, "minThickness");
|
|
48390
49197
|
const warnThickness = finitePositive(raw.warnThickness, DEFAULT_THICKNESS_INSPECTION_OPTIONS.warnThickness, "warnThickness");
|
|
48391
49198
|
const maxThickness = finitePositive(raw.maxThickness, DEFAULT_THICKNESS_INSPECTION_OPTIONS.maxThickness, "maxThickness");
|
|
49199
|
+
const colorMinThickness = finiteNonNegative(
|
|
49200
|
+
raw.colorMinThickness,
|
|
49201
|
+
DEFAULT_THICKNESS_INSPECTION_OPTIONS.colorMinThickness,
|
|
49202
|
+
"colorMinThickness"
|
|
49203
|
+
);
|
|
49204
|
+
const colorMaxThickness = finitePositive(
|
|
49205
|
+
raw.colorMaxThickness,
|
|
49206
|
+
DEFAULT_THICKNESS_INSPECTION_OPTIONS.colorMaxThickness,
|
|
49207
|
+
"colorMaxThickness"
|
|
49208
|
+
);
|
|
48392
49209
|
const maxSamplesPerObject = finitePositive(
|
|
48393
49210
|
raw.maxSamplesPerObject,
|
|
48394
49211
|
DEFAULT_THICKNESS_INSPECTION_OPTIONS.maxSamplesPerObject,
|
|
@@ -48405,10 +49222,15 @@ function resolveThicknessInspectionOptions(raw = {}) {
|
|
|
48405
49222
|
if (warnThickness > maxThickness) {
|
|
48406
49223
|
throw new Error("warnThickness must be less than or equal to maxThickness.");
|
|
48407
49224
|
}
|
|
49225
|
+
if (colorMinThickness >= colorMaxThickness) {
|
|
49226
|
+
throw new Error("colorMinThickness must be less than colorMaxThickness.");
|
|
49227
|
+
}
|
|
48408
49228
|
return {
|
|
48409
49229
|
minThickness,
|
|
48410
49230
|
warnThickness,
|
|
48411
49231
|
maxThickness,
|
|
49232
|
+
colorMinThickness,
|
|
49233
|
+
colorMaxThickness,
|
|
48412
49234
|
maxSamplesPerObject: Math.max(1, Math.floor(maxSamplesPerObject)),
|
|
48413
49235
|
contactTolerance
|
|
48414
49236
|
};
|
|
@@ -48419,6 +49241,16 @@ function lerp$1(a2, b, t) {
|
|
|
48419
49241
|
function lerpColor(a2, b, t) {
|
|
48420
49242
|
return [Math.round(lerp$1(a2[0], b[0], t)), Math.round(lerp$1(a2[1], b[1], t)), Math.round(lerp$1(a2[2], b[2], t))];
|
|
48421
49243
|
}
|
|
49244
|
+
function gradientColor(stops, t) {
|
|
49245
|
+
if (stops.length === 0) return THICKNESS_COLORS.unknown;
|
|
49246
|
+
if (stops.length === 1) return stops[0] ?? THICKNESS_COLORS.unknown;
|
|
49247
|
+
const clamped = Math.max(0, Math.min(1, t));
|
|
49248
|
+
const scaled = clamped * (stops.length - 1);
|
|
49249
|
+
const leftIndex = Math.min(stops.length - 2, Math.floor(scaled));
|
|
49250
|
+
const left = stops[leftIndex] ?? THICKNESS_COLORS.unknown;
|
|
49251
|
+
const right = stops[leftIndex + 1] ?? left;
|
|
49252
|
+
return lerpColor(left, right, scaled - leftIndex);
|
|
49253
|
+
}
|
|
48422
49254
|
function thicknessClass(thickness, options) {
|
|
48423
49255
|
if (thickness == null || !Number.isFinite(thickness) || thickness <= 0) return "unknown";
|
|
48424
49256
|
if (thickness <= options.minThickness) return "critical";
|
|
@@ -48427,18 +49259,9 @@ function thicknessClass(thickness, options) {
|
|
|
48427
49259
|
return "thick";
|
|
48428
49260
|
}
|
|
48429
49261
|
function thicknessColor(thickness, options) {
|
|
48430
|
-
|
|
48431
|
-
|
|
48432
|
-
|
|
48433
|
-
if (cls === "warning") {
|
|
48434
|
-
const span = Math.max(1e-9, options.warnThickness - options.minThickness);
|
|
48435
|
-
return lerpColor(THICKNESS_COLORS.critical, THICKNESS_COLORS.warning, ((thickness ?? 0) - options.minThickness) / span);
|
|
48436
|
-
}
|
|
48437
|
-
if (cls === "ok") {
|
|
48438
|
-
const span = Math.max(1e-9, options.maxThickness - options.warnThickness);
|
|
48439
|
-
return lerpColor(THICKNESS_COLORS.ok, THICKNESS_COLORS.thick, ((thickness ?? 0) - options.warnThickness) / span);
|
|
48440
|
-
}
|
|
48441
|
-
return THICKNESS_COLORS.thick;
|
|
49262
|
+
if (thickness == null || !Number.isFinite(thickness) || thickness <= 0) return THICKNESS_COLORS.unknown;
|
|
49263
|
+
const span = Math.max(1e-9, options.colorMaxThickness - options.colorMinThickness);
|
|
49264
|
+
return gradientColor(THICKNESS_GRADIENT_COLORS, (thickness - options.colorMinThickness) / span);
|
|
48442
49265
|
}
|
|
48443
49266
|
function cloneGeometryForFaceColors(geometry) {
|
|
48444
49267
|
return geometry.index ? geometry.toNonIndexed() : geometry.clone();
|
|
@@ -49302,7 +50125,7 @@ for (let radius = 0; radius <= MAX_SEARCH_RADIUS; radius += 1) {
|
|
|
49302
50125
|
function gridKey(x2, y2, z2) {
|
|
49303
50126
|
return `${x2},${y2},${z2}`;
|
|
49304
50127
|
}
|
|
49305
|
-
function
|
|
50128
|
+
function buildInspectHeatmapFieldBounds(geometry) {
|
|
49306
50129
|
const position = geometry.getAttribute("position");
|
|
49307
50130
|
if (!position || position.count === 0) return null;
|
|
49308
50131
|
const bounds = new Box3().setFromBufferAttribute(position);
|
|
@@ -49310,7 +50133,11 @@ function buildGeometryBounds(geometry) {
|
|
|
49310
50133
|
const size = bounds.getSize(new Vector3());
|
|
49311
50134
|
const pad = Math.max(size.x, size.y, size.z, 1) * 1e-5;
|
|
49312
50135
|
bounds.expandByScalar(pad);
|
|
49313
|
-
|
|
50136
|
+
const boundsSize = bounds.getSize(new Vector3());
|
|
50137
|
+
return {
|
|
50138
|
+
boundsMin: [bounds.min.x, bounds.min.y, bounds.min.z],
|
|
50139
|
+
boundsSize: [boundsSize.x, boundsSize.y, boundsSize.z]
|
|
50140
|
+
};
|
|
49314
50141
|
}
|
|
49315
50142
|
function buildSampleGrid(pointCloud) {
|
|
49316
50143
|
const sampleCount = Math.floor(pointCloud.positions.length / 3);
|
|
@@ -49394,11 +50221,15 @@ function blendedColorAt(point, pointCloud, sampleGrid) {
|
|
|
49394
50221
|
return [r / weightSum, g2 / weightSum, b / weightSum];
|
|
49395
50222
|
}
|
|
49396
50223
|
function buildInspectHeatmapFieldData(geometry, pointCloud) {
|
|
49397
|
-
const bounds =
|
|
50224
|
+
const bounds = buildInspectHeatmapFieldBounds(geometry);
|
|
50225
|
+
return bounds ? buildInspectHeatmapFieldDataFromBounds(bounds, pointCloud) : null;
|
|
50226
|
+
}
|
|
50227
|
+
function buildInspectHeatmapFieldDataFromBounds(bounds, pointCloud) {
|
|
49398
50228
|
const sampleGrid = buildSampleGrid(pointCloud);
|
|
49399
50229
|
if (!bounds || !sampleGrid) return null;
|
|
49400
50230
|
const gridSize = fieldGridSizeForSampleCount(Math.floor(pointCloud.positions.length / 3));
|
|
49401
|
-
const
|
|
50231
|
+
const boundsMin = new Vector3(...bounds.boundsMin);
|
|
50232
|
+
const boundsSize = new Vector3(...bounds.boundsSize);
|
|
49402
50233
|
const data = new Uint8Array(gridSize * gridSize * gridSize * 4);
|
|
49403
50234
|
const point = new Vector3();
|
|
49404
50235
|
let dataOffset = 0;
|
|
@@ -49406,9 +50237,9 @@ function buildInspectHeatmapFieldData(geometry, pointCloud) {
|
|
|
49406
50237
|
for (let z2 = 0; z2 < gridSize; z2 += 1) {
|
|
49407
50238
|
for (let x2 = 0; x2 < gridSize; x2 += 1) {
|
|
49408
50239
|
point.set(
|
|
49409
|
-
|
|
49410
|
-
|
|
49411
|
-
|
|
50240
|
+
boundsMin.x + boundsSize.x * x2 / (gridSize - 1),
|
|
50241
|
+
boundsMin.y + boundsSize.y * y2 / (gridSize - 1),
|
|
50242
|
+
boundsMin.z + boundsSize.z * z2 / (gridSize - 1)
|
|
49412
50243
|
);
|
|
49413
50244
|
const [r, g2, b] = blendedColorAt(point, pointCloud, sampleGrid);
|
|
49414
50245
|
data[dataOffset] = Math.max(0, Math.min(255, Math.round(r)));
|
|
@@ -49421,13 +50252,14 @@ function buildInspectHeatmapFieldData(geometry, pointCloud) {
|
|
|
49421
50252
|
}
|
|
49422
50253
|
return {
|
|
49423
50254
|
data,
|
|
49424
|
-
boundsMin:
|
|
50255
|
+
boundsMin: bounds.boundsMin,
|
|
49425
50256
|
boundsSize: [boundsSize.x, boundsSize.y, boundsSize.z],
|
|
49426
50257
|
gridSize
|
|
49427
50258
|
};
|
|
49428
50259
|
}
|
|
49429
50260
|
const workerScope = self;
|
|
49430
50261
|
let manifoldReadyPromise = null;
|
|
50262
|
+
let cachedThicknessColorizeAnalysis = null;
|
|
49431
50263
|
function ensureManifoldReady() {
|
|
49432
50264
|
if (!manifoldReadyPromise) manifoldReadyPromise = initKernelManifoldOnly();
|
|
49433
50265
|
return manifoldReadyPromise;
|
|
@@ -49473,6 +50305,7 @@ function geometryFromPositions(positions) {
|
|
|
49473
50305
|
function pointBuffers(samples) {
|
|
49474
50306
|
const positions = new Float32Array(samples.length * 3);
|
|
49475
50307
|
const colors = new Float32Array(samples.length * 3);
|
|
50308
|
+
const values = new Float32Array(samples.length);
|
|
49476
50309
|
samples.forEach((sample, index2) => {
|
|
49477
50310
|
const base = index2 * 3;
|
|
49478
50311
|
positions[base] = sample.position[0] + sample.normal[0] * 0.025;
|
|
@@ -49481,8 +50314,9 @@ function pointBuffers(samples) {
|
|
|
49481
50314
|
colors[base] = sample.color[0] / 255;
|
|
49482
50315
|
colors[base + 1] = sample.color[1] / 255;
|
|
49483
50316
|
colors[base + 2] = sample.color[2] / 255;
|
|
50317
|
+
values[index2] = sample.value ?? Number.NaN;
|
|
49484
50318
|
});
|
|
49485
|
-
return { positions, colors };
|
|
50319
|
+
return { positions, colors, values };
|
|
49486
50320
|
}
|
|
49487
50321
|
function rgbFloatsForHex(hex) {
|
|
49488
50322
|
const color = new Color(hex);
|
|
@@ -49507,6 +50341,7 @@ function analyzeScalarChannel(request) {
|
|
|
49507
50341
|
const pointObjects = [];
|
|
49508
50342
|
const heatmapFieldObjects = [];
|
|
49509
50343
|
const warnings = [];
|
|
50344
|
+
const thicknessCacheObjects = [];
|
|
49510
50345
|
for (const object of request.objects) {
|
|
49511
50346
|
if (!object.positions || object.positions.length < 9) continue;
|
|
49512
50347
|
const geometry = geometryFromPositions(object.positions);
|
|
@@ -49514,13 +50349,22 @@ function analyzeScalarChannel(request) {
|
|
|
49514
50349
|
const analysis = request.channel === "thickness" ? analyzeThicknessGeometry(geometry, request.thickness) : analyzeRoughnessGeometry(geometry, request.roughness);
|
|
49515
50350
|
analysis.warnings.forEach((warning) => warnings.push(`${object.name}: ${warning}`));
|
|
49516
50351
|
const buffers = pointBuffers(analysis.pointSamples);
|
|
49517
|
-
const
|
|
50352
|
+
const heatmapBounds = buildInspectHeatmapFieldBounds(analysis.geometry);
|
|
50353
|
+
const field = heatmapBounds ? buildInspectHeatmapFieldDataFromBounds(heatmapBounds, buffers) : buildInspectHeatmapFieldData(analysis.geometry, buffers);
|
|
49518
50354
|
if (field) {
|
|
49519
50355
|
heatmapFieldObjects.push({
|
|
49520
50356
|
objectId: object.id,
|
|
49521
50357
|
...field
|
|
49522
50358
|
});
|
|
49523
50359
|
}
|
|
50360
|
+
if (request.channel === "thickness" && buffers.values) {
|
|
50361
|
+
thicknessCacheObjects.push({
|
|
50362
|
+
objectId: object.id,
|
|
50363
|
+
positions: new Float32Array(buffers.positions),
|
|
50364
|
+
values: new Float32Array(buffers.values),
|
|
50365
|
+
heatmapBounds
|
|
50366
|
+
});
|
|
50367
|
+
}
|
|
49524
50368
|
pointObjects.push({
|
|
49525
50369
|
objectId: object.id,
|
|
49526
50370
|
sampleCount: analysis.pointSamples.length,
|
|
@@ -49531,7 +50375,9 @@ function analyzeScalarChannel(request) {
|
|
|
49531
50375
|
geometry.dispose();
|
|
49532
50376
|
}
|
|
49533
50377
|
}
|
|
50378
|
+
cachedThicknessColorizeAnalysis = request.channel === "thickness" ? { analysisId: request.reqId, objects: thicknessCacheObjects } : null;
|
|
49534
50379
|
return {
|
|
50380
|
+
analysisId: request.reqId,
|
|
49535
50381
|
channel: request.channel,
|
|
49536
50382
|
objectColors: {},
|
|
49537
50383
|
pointObjects,
|
|
@@ -49541,6 +50387,47 @@ function analyzeScalarChannel(request) {
|
|
|
49541
50387
|
warnings
|
|
49542
50388
|
};
|
|
49543
50389
|
}
|
|
50390
|
+
function thicknessColorsForValues(values, colorMinThickness, colorMaxThickness) {
|
|
50391
|
+
const options = resolveThicknessInspectionOptions({ colorMinThickness, colorMaxThickness });
|
|
50392
|
+
const colors = new Float32Array(values.length * 3);
|
|
50393
|
+
for (let index2 = 0; index2 < values.length; index2 += 1) {
|
|
50394
|
+
const color = thicknessColor(values[index2], options);
|
|
50395
|
+
const offset = index2 * 3;
|
|
50396
|
+
colors[offset] = color[0] / 255;
|
|
50397
|
+
colors[offset + 1] = color[1] / 255;
|
|
50398
|
+
colors[offset + 2] = color[2] / 255;
|
|
50399
|
+
}
|
|
50400
|
+
return colors;
|
|
50401
|
+
}
|
|
50402
|
+
function colorizeThicknessAnalysis(request) {
|
|
50403
|
+
const cached = cachedThicknessColorizeAnalysis;
|
|
50404
|
+
if (!cached || cached.analysisId !== request.analysisId) {
|
|
50405
|
+
throw new Error("Thickness colorize cache is no longer available.");
|
|
50406
|
+
}
|
|
50407
|
+
const pointObjects = [];
|
|
50408
|
+
const heatmapFieldObjects = [];
|
|
50409
|
+
for (const object of cached.objects) {
|
|
50410
|
+
const colors = thicknessColorsForValues(object.values, request.colorMinThickness, request.colorMaxThickness);
|
|
50411
|
+
pointObjects.push({ objectId: object.objectId, colors });
|
|
50412
|
+
if (object.heatmapBounds) {
|
|
50413
|
+
const field = buildInspectHeatmapFieldDataFromBounds(object.heatmapBounds, {
|
|
50414
|
+
positions: object.positions,
|
|
50415
|
+
colors
|
|
50416
|
+
});
|
|
50417
|
+
if (field) {
|
|
50418
|
+
heatmapFieldObjects.push({
|
|
50419
|
+
objectId: object.objectId,
|
|
50420
|
+
...field
|
|
50421
|
+
});
|
|
50422
|
+
}
|
|
50423
|
+
}
|
|
50424
|
+
}
|
|
50425
|
+
return {
|
|
50426
|
+
analysisId: cached.analysisId,
|
|
50427
|
+
pointObjects,
|
|
50428
|
+
heatmapFieldObjects
|
|
50429
|
+
};
|
|
50430
|
+
}
|
|
49544
50431
|
function analyzeConnectivityChannel(request) {
|
|
49545
50432
|
const bodyInput = buildMeshBodyConnectivityInput(
|
|
49546
50433
|
request.objects.map((object) => ({
|
|
@@ -49707,7 +50594,11 @@ function analyzeCollisionChannel(request) {
|
|
|
49707
50594
|
}
|
|
49708
50595
|
function transferFor(result) {
|
|
49709
50596
|
return [
|
|
49710
|
-
...result.pointObjects.flatMap((object) => [
|
|
50597
|
+
...result.pointObjects.flatMap((object) => [
|
|
50598
|
+
object.positions.buffer,
|
|
50599
|
+
object.colors.buffer,
|
|
50600
|
+
...object.values ? [object.values.buffer] : []
|
|
50601
|
+
]),
|
|
49711
50602
|
...result.meshColorObjects.map((object) => object.colors.buffer),
|
|
49712
50603
|
...result.heatmapFieldObjects.map((object) => object.data.buffer),
|
|
49713
50604
|
...result.collisionGeometryObjects.flatMap((object) => [object.positions.buffer, object.normals.buffer, object.edgePositions.buffer])
|
|
@@ -49715,6 +50606,21 @@ function transferFor(result) {
|
|
|
49715
50606
|
}
|
|
49716
50607
|
async function handleRequest(request) {
|
|
49717
50608
|
try {
|
|
50609
|
+
if (request.type === "colorize-thickness") {
|
|
50610
|
+
const result2 = colorizeThicknessAnalysis(request.payload);
|
|
50611
|
+
const response2 = {
|
|
50612
|
+
type: "inspect-colorize-success",
|
|
50613
|
+
payload: {
|
|
50614
|
+
reqId: request.payload.reqId,
|
|
50615
|
+
result: result2
|
|
50616
|
+
}
|
|
50617
|
+
};
|
|
50618
|
+
workerScope.postMessage(response2, [
|
|
50619
|
+
...result2.pointObjects.map((object) => object.colors.buffer),
|
|
50620
|
+
...result2.heatmapFieldObjects.map((object) => object.data.buffer)
|
|
50621
|
+
]);
|
|
50622
|
+
return;
|
|
50623
|
+
}
|
|
49718
50624
|
if (request.payload.channel === "collisions") await ensureManifoldReady();
|
|
49719
50625
|
const result = request.payload.channel === "thickness" || request.payload.channel === "roughness" ? analyzeScalarChannel(request.payload) : request.payload.channel === "collisions" ? analyzeCollisionChannel(request.payload) : analyzeConnectivityChannel(request.payload);
|
|
49720
50626
|
const response = {
|