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
package/dist/assets/{constructionHistoryWorker-HYwzJY4m.js → constructionHistoryWorker-Ba2Hm58b.js}
RENAMED
|
@@ -118,7 +118,7 @@ function denormalize(value, array) {
|
|
|
118
118
|
throw new Error("Invalid component type.");
|
|
119
119
|
}
|
|
120
120
|
}
|
|
121
|
-
function normalize$
|
|
121
|
+
function normalize$4(value, array) {
|
|
122
122
|
switch (array.constructor) {
|
|
123
123
|
case Float32Array:
|
|
124
124
|
return value;
|
|
@@ -6531,7 +6531,7 @@ class BufferAttribute {
|
|
|
6531
6531
|
* @return {BufferAttribute} A reference to this instance.
|
|
6532
6532
|
*/
|
|
6533
6533
|
setComponent(index2, component, value) {
|
|
6534
|
-
if (this.normalized) value = normalize$
|
|
6534
|
+
if (this.normalized) value = normalize$4(value, this.array);
|
|
6535
6535
|
this.array[index2 * this.itemSize + component] = value;
|
|
6536
6536
|
return this;
|
|
6537
6537
|
}
|
|
@@ -6554,7 +6554,7 @@ class BufferAttribute {
|
|
|
6554
6554
|
* @return {BufferAttribute} A reference to this instance.
|
|
6555
6555
|
*/
|
|
6556
6556
|
setX(index2, x2) {
|
|
6557
|
-
if (this.normalized) x2 = normalize$
|
|
6557
|
+
if (this.normalized) x2 = normalize$4(x2, this.array);
|
|
6558
6558
|
this.array[index2 * this.itemSize] = x2;
|
|
6559
6559
|
return this;
|
|
6560
6560
|
}
|
|
@@ -6577,7 +6577,7 @@ class BufferAttribute {
|
|
|
6577
6577
|
* @return {BufferAttribute} A reference to this instance.
|
|
6578
6578
|
*/
|
|
6579
6579
|
setY(index2, y2) {
|
|
6580
|
-
if (this.normalized) y2 = normalize$
|
|
6580
|
+
if (this.normalized) y2 = normalize$4(y2, this.array);
|
|
6581
6581
|
this.array[index2 * this.itemSize + 1] = y2;
|
|
6582
6582
|
return this;
|
|
6583
6583
|
}
|
|
@@ -6600,7 +6600,7 @@ class BufferAttribute {
|
|
|
6600
6600
|
* @return {BufferAttribute} A reference to this instance.
|
|
6601
6601
|
*/
|
|
6602
6602
|
setZ(index2, z2) {
|
|
6603
|
-
if (this.normalized) z2 = normalize$
|
|
6603
|
+
if (this.normalized) z2 = normalize$4(z2, this.array);
|
|
6604
6604
|
this.array[index2 * this.itemSize + 2] = z2;
|
|
6605
6605
|
return this;
|
|
6606
6606
|
}
|
|
@@ -6623,7 +6623,7 @@ class BufferAttribute {
|
|
|
6623
6623
|
* @return {BufferAttribute} A reference to this instance.
|
|
6624
6624
|
*/
|
|
6625
6625
|
setW(index2, w2) {
|
|
6626
|
-
if (this.normalized) w2 = normalize$
|
|
6626
|
+
if (this.normalized) w2 = normalize$4(w2, this.array);
|
|
6627
6627
|
this.array[index2 * this.itemSize + 3] = w2;
|
|
6628
6628
|
return this;
|
|
6629
6629
|
}
|
|
@@ -6638,8 +6638,8 @@ class BufferAttribute {
|
|
|
6638
6638
|
setXY(index2, x2, y2) {
|
|
6639
6639
|
index2 *= this.itemSize;
|
|
6640
6640
|
if (this.normalized) {
|
|
6641
|
-
x2 = normalize$
|
|
6642
|
-
y2 = normalize$
|
|
6641
|
+
x2 = normalize$4(x2, this.array);
|
|
6642
|
+
y2 = normalize$4(y2, this.array);
|
|
6643
6643
|
}
|
|
6644
6644
|
this.array[index2 + 0] = x2;
|
|
6645
6645
|
this.array[index2 + 1] = y2;
|
|
@@ -6657,9 +6657,9 @@ class BufferAttribute {
|
|
|
6657
6657
|
setXYZ(index2, x2, y2, z2) {
|
|
6658
6658
|
index2 *= this.itemSize;
|
|
6659
6659
|
if (this.normalized) {
|
|
6660
|
-
x2 = normalize$
|
|
6661
|
-
y2 = normalize$
|
|
6662
|
-
z2 = normalize$
|
|
6660
|
+
x2 = normalize$4(x2, this.array);
|
|
6661
|
+
y2 = normalize$4(y2, this.array);
|
|
6662
|
+
z2 = normalize$4(z2, this.array);
|
|
6663
6663
|
}
|
|
6664
6664
|
this.array[index2 + 0] = x2;
|
|
6665
6665
|
this.array[index2 + 1] = y2;
|
|
@@ -6679,10 +6679,10 @@ class BufferAttribute {
|
|
|
6679
6679
|
setXYZW(index2, x2, y2, z2, w2) {
|
|
6680
6680
|
index2 *= this.itemSize;
|
|
6681
6681
|
if (this.normalized) {
|
|
6682
|
-
x2 = normalize$
|
|
6683
|
-
y2 = normalize$
|
|
6684
|
-
z2 = normalize$
|
|
6685
|
-
w2 = normalize$
|
|
6682
|
+
x2 = normalize$4(x2, this.array);
|
|
6683
|
+
y2 = normalize$4(y2, this.array);
|
|
6684
|
+
z2 = normalize$4(z2, this.array);
|
|
6685
|
+
w2 = normalize$4(w2, this.array);
|
|
6686
6686
|
}
|
|
6687
6687
|
this.array[index2 + 0] = x2;
|
|
6688
6688
|
this.array[index2 + 1] = y2;
|
|
@@ -7554,6 +7554,55 @@ function disposeShapeBackend(backend) {
|
|
|
7554
7554
|
const dispose = backend.dispose;
|
|
7555
7555
|
dispose == null ? void 0 : dispose.call(backend);
|
|
7556
7556
|
}
|
|
7557
|
+
function formatValidationValue(value) {
|
|
7558
|
+
if (typeof value === "number") return Number.isNaN(value) ? "NaN" : String(value);
|
|
7559
|
+
if (value === void 0) return "undefined";
|
|
7560
|
+
if (typeof value === "string") return JSON.stringify(value);
|
|
7561
|
+
try {
|
|
7562
|
+
return JSON.stringify(value) ?? String(value);
|
|
7563
|
+
} catch {
|
|
7564
|
+
return String(value);
|
|
7565
|
+
}
|
|
7566
|
+
}
|
|
7567
|
+
function requireFiniteNumber(value, label) {
|
|
7568
|
+
if (typeof value !== "number" || !Number.isFinite(value)) {
|
|
7569
|
+
throw new Error(`${label} must be a finite number, got ${formatValidationValue(value)}`);
|
|
7570
|
+
}
|
|
7571
|
+
return value;
|
|
7572
|
+
}
|
|
7573
|
+
function requirePositiveFiniteNumber(value, label) {
|
|
7574
|
+
const n = requireFiniteNumber(value, label);
|
|
7575
|
+
if (n <= 0) throw new Error(`${label} must be a positive finite number, got ${formatValidationValue(value)}`);
|
|
7576
|
+
return n;
|
|
7577
|
+
}
|
|
7578
|
+
function requireFiniteVec3$1(value, label) {
|
|
7579
|
+
if (!Array.isArray(value) || value.length !== 3) {
|
|
7580
|
+
throw new Error(`${label} must be [x, y, z] with finite numbers, got ${formatValidationValue(value)}`);
|
|
7581
|
+
}
|
|
7582
|
+
return [
|
|
7583
|
+
requireFiniteNumber(value[0], `${label}[0]`),
|
|
7584
|
+
requireFiniteNumber(value[1], `${label}[1]`),
|
|
7585
|
+
requireFiniteNumber(value[2], `${label}[2]`)
|
|
7586
|
+
];
|
|
7587
|
+
}
|
|
7588
|
+
function requireNonZeroFiniteVec3(value, label) {
|
|
7589
|
+
const v = requireFiniteVec3$1(value, label);
|
|
7590
|
+
if (v[0] === 0 && v[1] === 0 && v[2] === 0) throw new Error(`${label} must not be [0, 0, 0]`);
|
|
7591
|
+
return v;
|
|
7592
|
+
}
|
|
7593
|
+
function requireFiniteMat4(value, label) {
|
|
7594
|
+
if (!Array.isArray(value) || value.length !== 16) {
|
|
7595
|
+
throw new Error(`${label} must be a 4x4 matrix array with 16 finite numbers, got ${formatValidationValue(value)}`);
|
|
7596
|
+
}
|
|
7597
|
+
return value.map((entry, index2) => requireFiniteNumber(entry, `${label}[${index2}]`));
|
|
7598
|
+
}
|
|
7599
|
+
function requireNonZeroFiniteScale3(value, label) {
|
|
7600
|
+
const scale2 = typeof value === "number" ? [requireFiniteNumber(value, label), requireFiniteNumber(value, label), requireFiniteNumber(value, label)] : requireFiniteVec3$1(value, label);
|
|
7601
|
+
if (Math.abs(scale2[0]) < 1e-12 || Math.abs(scale2[1]) < 1e-12 || Math.abs(scale2[2]) < 1e-12) {
|
|
7602
|
+
throw new Error(`${label} must have finite non-zero components, got ${formatValidationValue(value)}`);
|
|
7603
|
+
}
|
|
7604
|
+
return scale2;
|
|
7605
|
+
}
|
|
7557
7606
|
const EPS$4 = 1e-10;
|
|
7558
7607
|
function subVec3(a2, b) {
|
|
7559
7608
|
return [a2[0] - b[0], a2[1] - b[1], a2[2] - b[2]];
|
|
@@ -7635,9 +7684,6 @@ function solveRotateAroundAngle(axis, pivot, movingPoint, targetPoint, options =
|
|
|
7635
7684
|
function identityMatrix() {
|
|
7636
7685
|
return [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1];
|
|
7637
7686
|
}
|
|
7638
|
-
function toMat4(input) {
|
|
7639
|
-
return input instanceof Transform ? input.toArray() : input;
|
|
7640
|
-
}
|
|
7641
7687
|
function multiplyMat4(a2, b) {
|
|
7642
7688
|
const out = new Array(16).fill(0);
|
|
7643
7689
|
for (let col = 0; col < 4; col++) {
|
|
@@ -7714,23 +7760,40 @@ class Transform {
|
|
|
7714
7760
|
}
|
|
7715
7761
|
/** Wrap an existing `Transform` or raw 4x4 matrix as a `Transform`. */
|
|
7716
7762
|
static from(input) {
|
|
7717
|
-
return input instanceof Transform ? input : new Transform(input);
|
|
7763
|
+
return input instanceof Transform ? input : new Transform(requireFiniteMat4(input, "Transform.from() matrix"));
|
|
7718
7764
|
}
|
|
7719
7765
|
/** Create a translation transform. */
|
|
7720
7766
|
static translation(x2, y2, z2) {
|
|
7721
|
-
return new Transform([
|
|
7767
|
+
return new Transform([
|
|
7768
|
+
1,
|
|
7769
|
+
0,
|
|
7770
|
+
0,
|
|
7771
|
+
0,
|
|
7772
|
+
0,
|
|
7773
|
+
1,
|
|
7774
|
+
0,
|
|
7775
|
+
0,
|
|
7776
|
+
0,
|
|
7777
|
+
0,
|
|
7778
|
+
1,
|
|
7779
|
+
0,
|
|
7780
|
+
requireFiniteNumber(x2, "Transform.translation() x"),
|
|
7781
|
+
requireFiniteNumber(y2, "Transform.translation() y"),
|
|
7782
|
+
requireFiniteNumber(z2, "Transform.translation() z"),
|
|
7783
|
+
1
|
|
7784
|
+
]);
|
|
7722
7785
|
}
|
|
7723
7786
|
/** Create a uniform or per-axis scale transform. */
|
|
7724
7787
|
static scale(v) {
|
|
7725
|
-
const sx =
|
|
7726
|
-
const sy = typeof v === "number" ? v : v[1];
|
|
7727
|
-
const sz = typeof v === "number" ? v : v[2];
|
|
7788
|
+
const [sx, sy, sz] = requireNonZeroFiniteScale3(v, "Transform.scale() scale");
|
|
7728
7789
|
return new Transform([sx, 0, 0, 0, 0, sy, 0, 0, 0, 0, sz, 0, 0, 0, 0, 1]);
|
|
7729
7790
|
}
|
|
7730
7791
|
/** Create a rotation around an arbitrary axis, optionally about a pivot. */
|
|
7731
7792
|
static rotationAxis(axis, angleDeg, pivot = [0, 0, 0]) {
|
|
7732
|
-
const [ux, uy, uz] = normalizeVec3$3(axis);
|
|
7733
|
-
const
|
|
7793
|
+
const [ux, uy, uz] = normalizeVec3$3(requireNonZeroFiniteVec3(axis, "Transform.rotationAxis() axis"));
|
|
7794
|
+
const degrees = requireFiniteNumber(angleDeg, "Transform.rotationAxis() angleDeg");
|
|
7795
|
+
const [px, py, pz] = requireFiniteVec3$1(pivot, "Transform.rotationAxis() pivot");
|
|
7796
|
+
const rad = degrees * Math.PI / 180;
|
|
7734
7797
|
const cos2 = Math.cos(rad);
|
|
7735
7798
|
const sin2 = Math.sin(rad);
|
|
7736
7799
|
const m00 = cos2 + ux * ux * (1 - cos2);
|
|
@@ -7742,7 +7805,6 @@ class Transform {
|
|
|
7742
7805
|
const m20 = uz * ux * (1 - cos2) - uy * sin2;
|
|
7743
7806
|
const m21 = uz * uy * (1 - cos2) + ux * sin2;
|
|
7744
7807
|
const m22 = cos2 + uz * uz * (1 - cos2);
|
|
7745
|
-
const [px, py, pz] = pivot;
|
|
7746
7808
|
const tx = px - (m00 * px + m01 * py + m02 * pz);
|
|
7747
7809
|
const ty = py - (m10 * px + m11 * py + m12 * pz);
|
|
7748
7810
|
const tz = pz - (m20 * px + m21 * py + m22 * pz);
|
|
@@ -7750,12 +7812,16 @@ class Transform {
|
|
|
7750
7812
|
}
|
|
7751
7813
|
/** Solve the rotation needed to move one point onto a target line or plane. */
|
|
7752
7814
|
static rotateAroundTo(axis, pivot, movingPoint, targetPoint, options = {}) {
|
|
7753
|
-
const
|
|
7754
|
-
|
|
7815
|
+
const rotateAxis = requireNonZeroFiniteVec3(axis, "Transform.rotateAroundTo() axis");
|
|
7816
|
+
const rotatePivot = requireFiniteVec3$1(pivot, "Transform.rotateAroundTo() pivot");
|
|
7817
|
+
const moving = requireFiniteVec3$1(movingPoint, "Transform.rotateAroundTo() movingPoint");
|
|
7818
|
+
const target = requireFiniteVec3$1(targetPoint, "Transform.rotateAroundTo() targetPoint");
|
|
7819
|
+
const angleDeg = solveRotateAroundAngle(rotateAxis, rotatePivot, moving, target, options);
|
|
7820
|
+
return Transform.rotationAxis(rotateAxis, angleDeg, rotatePivot);
|
|
7755
7821
|
}
|
|
7756
7822
|
/** Compose transforms in chain order: `a.mul(b)` applies `a`, then `b`. */
|
|
7757
7823
|
mul(other) {
|
|
7758
|
-
const rhs =
|
|
7824
|
+
const rhs = other instanceof Transform ? other.toArray() : requireFiniteMat4(other, "Transform.mul() matrix");
|
|
7759
7825
|
return new Transform(multiplyMat4(rhs, this.m));
|
|
7760
7826
|
}
|
|
7761
7827
|
/** Translate after the current transform. */
|
|
@@ -7766,7 +7832,20 @@ class Transform {
|
|
|
7766
7832
|
rotateAxis(axis, angleDeg, pivot = [0, 0, 0]) {
|
|
7767
7833
|
return this.mul(Transform.rotationAxis(axis, angleDeg, pivot));
|
|
7768
7834
|
}
|
|
7835
|
+
/** Rotate about the X axis after the current transform (parity with `Shape.rotateX`). */
|
|
7836
|
+
rotateX(angleDeg, pivot = [0, 0, 0]) {
|
|
7837
|
+
return this.rotateAxis([1, 0, 0], angleDeg, pivot);
|
|
7838
|
+
}
|
|
7839
|
+
/** Rotate about the Y axis after the current transform (parity with `Shape.rotateY`). */
|
|
7840
|
+
rotateY(angleDeg, pivot = [0, 0, 0]) {
|
|
7841
|
+
return this.rotateAxis([0, 1, 0], angleDeg, pivot);
|
|
7842
|
+
}
|
|
7843
|
+
/** Rotate about the Z axis after the current transform (parity with `Shape.rotateZ`). */
|
|
7844
|
+
rotateZ(angleDeg, pivot = [0, 0, 0]) {
|
|
7845
|
+
return this.rotateAxis([0, 0, 1], angleDeg, pivot);
|
|
7846
|
+
}
|
|
7769
7847
|
/** Scale after the current transform. */
|
|
7848
|
+
// biome-ignore lint/suspicious/useAdjacentOverloadSignatures: Static Transform.scale() and chainable instance scale() intentionally share the CAD API name.
|
|
7770
7849
|
scale(v) {
|
|
7771
7850
|
return this.mul(Transform.scale(v));
|
|
7772
7851
|
}
|
|
@@ -7776,11 +7855,11 @@ class Transform {
|
|
|
7776
7855
|
}
|
|
7777
7856
|
/** Transform a point using homogeneous coordinates. */
|
|
7778
7857
|
point(p2) {
|
|
7779
|
-
return transformPoint(this.m, p2, 1);
|
|
7858
|
+
return transformPoint(this.m, requireFiniteVec3$1(p2, "Transform.point() point"), 1);
|
|
7780
7859
|
}
|
|
7781
7860
|
/** Transform a direction vector without translation. */
|
|
7782
7861
|
vector(v) {
|
|
7783
|
-
return transformPoint(this.m, v, 0);
|
|
7862
|
+
return transformPoint(this.m, requireFiniteVec3$1(v, "Transform.vector() vector"), 0);
|
|
7784
7863
|
}
|
|
7785
7864
|
/** Return the transform as a raw 4x4 matrix array. */
|
|
7786
7865
|
toArray() {
|
|
@@ -10010,6 +10089,42 @@ function cloneCutTaperCompilePlan(plan) {
|
|
|
10010
10089
|
scale: [canonicalNumber(plan.scale[0]), canonicalNumber(plan.scale[1])]
|
|
10011
10090
|
};
|
|
10012
10091
|
}
|
|
10092
|
+
function cloneEdgeFeatureTarget(target) {
|
|
10093
|
+
return {
|
|
10094
|
+
midpoint: [target.midpoint[0], target.midpoint[1], target.midpoint[2]],
|
|
10095
|
+
start: [target.start[0], target.start[1], target.start[2]],
|
|
10096
|
+
end: [target.end[0], target.end[1], target.end[2]],
|
|
10097
|
+
convex: target.convex,
|
|
10098
|
+
...target.nativeTopology ? { nativeTopology: { backend: target.nativeTopology.backend, edge: target.nativeTopology.edge } } : {}
|
|
10099
|
+
};
|
|
10100
|
+
}
|
|
10101
|
+
function cloneEdgeFeatureQuery(query) {
|
|
10102
|
+
if (!query) return void 0;
|
|
10103
|
+
return {
|
|
10104
|
+
...query.near ? { near: [query.near[0], query.near[1], query.near[2]] } : {},
|
|
10105
|
+
...query.parallel ? { parallel: [query.parallel[0], query.parallel[1], query.parallel[2]] } : {},
|
|
10106
|
+
...query.perpendicular ? { perpendicular: [query.perpendicular[0], query.perpendicular[1], query.perpendicular[2]] } : {},
|
|
10107
|
+
...query.convex !== void 0 ? { convex: query.convex } : {},
|
|
10108
|
+
...query.concave !== void 0 ? { concave: query.concave } : {},
|
|
10109
|
+
...query.minAngle !== void 0 ? { minAngle: canonicalNumber(query.minAngle) } : {},
|
|
10110
|
+
...query.maxAngle !== void 0 ? { maxAngle: canonicalNumber(query.maxAngle) } : {},
|
|
10111
|
+
...query.minLength !== void 0 ? { minLength: canonicalNumber(query.minLength) } : {},
|
|
10112
|
+
...query.maxLength !== void 0 ? { maxLength: canonicalNumber(query.maxLength) } : {},
|
|
10113
|
+
...query.within ? {
|
|
10114
|
+
within: {
|
|
10115
|
+
...query.within.xMin !== void 0 ? { xMin: canonicalNumber(query.within.xMin) } : {},
|
|
10116
|
+
...query.within.xMax !== void 0 ? { xMax: canonicalNumber(query.within.xMax) } : {},
|
|
10117
|
+
...query.within.yMin !== void 0 ? { yMin: canonicalNumber(query.within.yMin) } : {},
|
|
10118
|
+
...query.within.yMax !== void 0 ? { yMax: canonicalNumber(query.within.yMax) } : {},
|
|
10119
|
+
...query.within.zMin !== void 0 ? { zMin: canonicalNumber(query.within.zMin) } : {},
|
|
10120
|
+
...query.within.zMax !== void 0 ? { zMax: canonicalNumber(query.within.zMax) } : {}
|
|
10121
|
+
}
|
|
10122
|
+
} : {},
|
|
10123
|
+
...query.atZ !== void 0 ? { atZ: canonicalNumber(query.atZ) } : {},
|
|
10124
|
+
...query.tolerance !== void 0 ? { tolerance: canonicalNumber(query.tolerance) } : {},
|
|
10125
|
+
...query.angleTolerance !== void 0 ? { angleTolerance: canonicalNumber(query.angleTolerance) } : {}
|
|
10126
|
+
};
|
|
10127
|
+
}
|
|
10013
10128
|
function featureCutExtentForwardSide(extent) {
|
|
10014
10129
|
return extent.kind === "two-sided" ? extent.forward : extent;
|
|
10015
10130
|
}
|
|
@@ -10106,6 +10221,41 @@ function cloneSweepPathCompilePlan(path) {
|
|
|
10106
10221
|
degree: path.degree,
|
|
10107
10222
|
closed: path.closed
|
|
10108
10223
|
};
|
|
10224
|
+
case "route3d":
|
|
10225
|
+
return {
|
|
10226
|
+
kind: "route3d",
|
|
10227
|
+
segments: path.segments.map(
|
|
10228
|
+
(segment) => segment.kind === "line" ? {
|
|
10229
|
+
kind: "line",
|
|
10230
|
+
from: canonicalVec3(segment.from),
|
|
10231
|
+
to: canonicalVec3(segment.to),
|
|
10232
|
+
length: canonicalNumber(segment.length)
|
|
10233
|
+
} : {
|
|
10234
|
+
kind: "arc",
|
|
10235
|
+
center: canonicalVec3(segment.center),
|
|
10236
|
+
radius: canonicalNumber(segment.radius),
|
|
10237
|
+
axis: canonicalVec3(segment.axis),
|
|
10238
|
+
start: canonicalVec3(segment.start),
|
|
10239
|
+
end: canonicalVec3(segment.end),
|
|
10240
|
+
sweepDeg: canonicalNumber(segment.sweepDeg),
|
|
10241
|
+
length: canonicalNumber(segment.length)
|
|
10242
|
+
}
|
|
10243
|
+
),
|
|
10244
|
+
ports: Object.fromEntries(
|
|
10245
|
+
Object.entries(path.ports).map(([name, port]) => [
|
|
10246
|
+
name,
|
|
10247
|
+
{
|
|
10248
|
+
name: port.name,
|
|
10249
|
+
origin: canonicalVec3(port.origin),
|
|
10250
|
+
axis: canonicalVec3(port.axis),
|
|
10251
|
+
xAxis: canonicalVec3(port.xAxis),
|
|
10252
|
+
yAxis: canonicalVec3(port.yAxis),
|
|
10253
|
+
station: canonicalNumber(port.station)
|
|
10254
|
+
}
|
|
10255
|
+
])
|
|
10256
|
+
),
|
|
10257
|
+
length: canonicalNumber(path.length)
|
|
10258
|
+
};
|
|
10109
10259
|
default:
|
|
10110
10260
|
assertExhaustive(path);
|
|
10111
10261
|
}
|
|
@@ -10200,6 +10350,7 @@ function cloneProfileEdge(edge) {
|
|
|
10200
10350
|
}
|
|
10201
10351
|
}
|
|
10202
10352
|
function cloneShapeCompilePlan(plan) {
|
|
10353
|
+
var _a3, _b3, _c2;
|
|
10203
10354
|
if (!plan) return null;
|
|
10204
10355
|
let result;
|
|
10205
10356
|
switch (plan.kind) {
|
|
@@ -10378,13 +10529,9 @@ function cloneShapeCompilePlan(plan) {
|
|
|
10378
10529
|
radius: plan.radius,
|
|
10379
10530
|
segments: plan.segments,
|
|
10380
10531
|
continuity: plan.continuity,
|
|
10381
|
-
edgeTargets: plan.edgeTargets.map(
|
|
10382
|
-
|
|
10383
|
-
|
|
10384
|
-
end: [t.end[0], t.end[1], t.end[2]],
|
|
10385
|
-
convex: t.convex,
|
|
10386
|
-
...t.nativeTopology ? { nativeTopology: { backend: t.nativeTopology.backend, edge: t.nativeTopology.edge } } : {}
|
|
10387
|
-
}))
|
|
10532
|
+
edgeTargets: (_a3 = plan.edgeTargets) == null ? void 0 : _a3.map(cloneEdgeFeatureTarget),
|
|
10533
|
+
edgeQuery: cloneEdgeFeatureQuery(plan.edgeQuery),
|
|
10534
|
+
edgeSelection: plan.edgeSelection
|
|
10388
10535
|
};
|
|
10389
10536
|
break;
|
|
10390
10537
|
case "cornerYBlend":
|
|
@@ -10394,13 +10541,7 @@ function cloneShapeCompilePlan(plan) {
|
|
|
10394
10541
|
radius: plan.radius,
|
|
10395
10542
|
segments: plan.segments,
|
|
10396
10543
|
continuity: plan.continuity,
|
|
10397
|
-
edgeTargets: plan.edgeTargets.map(
|
|
10398
|
-
midpoint: [t.midpoint[0], t.midpoint[1], t.midpoint[2]],
|
|
10399
|
-
start: [t.start[0], t.start[1], t.start[2]],
|
|
10400
|
-
end: [t.end[0], t.end[1], t.end[2]],
|
|
10401
|
-
convex: t.convex,
|
|
10402
|
-
...t.nativeTopology ? { nativeTopology: { backend: t.nativeTopology.backend, edge: t.nativeTopology.edge } } : {}
|
|
10403
|
-
})),
|
|
10544
|
+
edgeTargets: ((_b3 = plan.edgeTargets) == null ? void 0 : _b3.map(cloneEdgeFeatureTarget)) ?? [],
|
|
10404
10545
|
cornerPoint: [plan.cornerPoint[0], plan.cornerPoint[1], plan.cornerPoint[2]],
|
|
10405
10546
|
cornerTolerance: canonicalNumber(plan.cornerTolerance),
|
|
10406
10547
|
minBranchAngleDeg: canonicalNumber(plan.minBranchAngleDeg)
|
|
@@ -10411,13 +10552,9 @@ function cloneShapeCompilePlan(plan) {
|
|
|
10411
10552
|
kind: "chamferEdges",
|
|
10412
10553
|
base: cloneShapeCompilePlan(plan.base),
|
|
10413
10554
|
size: plan.size,
|
|
10414
|
-
edgeTargets: plan.edgeTargets.map(
|
|
10415
|
-
|
|
10416
|
-
|
|
10417
|
-
end: [t.end[0], t.end[1], t.end[2]],
|
|
10418
|
-
convex: t.convex,
|
|
10419
|
-
...t.nativeTopology ? { nativeTopology: { backend: t.nativeTopology.backend, edge: t.nativeTopology.edge } } : {}
|
|
10420
|
-
}))
|
|
10555
|
+
edgeTargets: (_c2 = plan.edgeTargets) == null ? void 0 : _c2.map(cloneEdgeFeatureTarget),
|
|
10556
|
+
edgeQuery: cloneEdgeFeatureQuery(plan.edgeQuery),
|
|
10557
|
+
edgeSelection: plan.edgeSelection
|
|
10421
10558
|
};
|
|
10422
10559
|
break;
|
|
10423
10560
|
case "draft":
|
|
@@ -10437,7 +10574,13 @@ function cloneShapeCompilePlan(plan) {
|
|
|
10437
10574
|
};
|
|
10438
10575
|
break;
|
|
10439
10576
|
case "importedMesh":
|
|
10440
|
-
result = {
|
|
10577
|
+
result = {
|
|
10578
|
+
kind: "importedMesh",
|
|
10579
|
+
filePath: plan.filePath,
|
|
10580
|
+
format: plan.format,
|
|
10581
|
+
...plan.object ? { object: plan.object } : {},
|
|
10582
|
+
fileData: plan.fileData
|
|
10583
|
+
};
|
|
10441
10584
|
break;
|
|
10442
10585
|
case "sdf":
|
|
10443
10586
|
result = {
|
|
@@ -10752,6 +10895,83 @@ function remapToKnotDomain(t, n, degree, knots) {
|
|
|
10752
10895
|
const uMax = knots[n];
|
|
10753
10896
|
return uMin + Math.max(0, Math.min(1, t)) * (uMax - uMin);
|
|
10754
10897
|
}
|
|
10898
|
+
const EPSILON$1 = 1e-9;
|
|
10899
|
+
function add$2(a2, b) {
|
|
10900
|
+
return [a2[0] + b[0], a2[1] + b[1], a2[2] + b[2]];
|
|
10901
|
+
}
|
|
10902
|
+
function scale$2(v, factor) {
|
|
10903
|
+
return [v[0] * factor, v[1] * factor, v[2] * factor];
|
|
10904
|
+
}
|
|
10905
|
+
function sub$2(a2, b) {
|
|
10906
|
+
return [a2[0] - b[0], a2[1] - b[1], a2[2] - b[2]];
|
|
10907
|
+
}
|
|
10908
|
+
function dot$3(a2, b) {
|
|
10909
|
+
return a2[0] * b[0] + a2[1] * b[1] + a2[2] * b[2];
|
|
10910
|
+
}
|
|
10911
|
+
function cross$4(a2, b) {
|
|
10912
|
+
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]];
|
|
10913
|
+
}
|
|
10914
|
+
function rotateAroundAxis(v, axis, angleRad) {
|
|
10915
|
+
const c2 = Math.cos(angleRad);
|
|
10916
|
+
const s = Math.sin(angleRad);
|
|
10917
|
+
const term1 = scale$2(v, c2);
|
|
10918
|
+
const term2 = scale$2(cross$4(axis, v), s);
|
|
10919
|
+
const term3 = scale$2(axis, dot$3(axis, v) * (1 - c2));
|
|
10920
|
+
return add$2(add$2(term1, term2), term3);
|
|
10921
|
+
}
|
|
10922
|
+
function arcPointAt(segment, t) {
|
|
10923
|
+
const sweepRad = segment.sweepDeg * Math.PI / 180 * t;
|
|
10924
|
+
return add$2(segment.center, rotateAroundAxis(sub$2(segment.start, segment.center), segment.axis, sweepRad));
|
|
10925
|
+
}
|
|
10926
|
+
function pushUnique(points, point) {
|
|
10927
|
+
const prev = points[points.length - 1];
|
|
10928
|
+
if (!prev || Math.hypot(prev[0] - point[0], prev[1] - point[1], prev[2] - point[2]) > EPSILON$1) {
|
|
10929
|
+
points.push([point[0], point[1], point[2]]);
|
|
10930
|
+
}
|
|
10931
|
+
}
|
|
10932
|
+
function resolveOptions(options) {
|
|
10933
|
+
if (typeof options === "number") return { samples: Math.max(2, Math.floor(options)), maxAngleDeg: 6 };
|
|
10934
|
+
return {
|
|
10935
|
+
samples: Math.max(2, Math.floor((options == null ? void 0 : options.samples) ?? 48)),
|
|
10936
|
+
maxAngleDeg: Math.max(0.25, (options == null ? void 0 : options.maxAngleDeg) ?? 6)
|
|
10937
|
+
};
|
|
10938
|
+
}
|
|
10939
|
+
function routePointAt(plan, t) {
|
|
10940
|
+
if (plan.segments.length === 0) return [0, 0, 0];
|
|
10941
|
+
const target = Math.max(0, Math.min(1, t)) * plan.length;
|
|
10942
|
+
let station = 0;
|
|
10943
|
+
for (const segment of plan.segments) {
|
|
10944
|
+
const next = station + segment.length;
|
|
10945
|
+
if (target <= next || segment === plan.segments[plan.segments.length - 1]) {
|
|
10946
|
+
const localT = segment.length <= EPSILON$1 ? 1 : Math.max(0, Math.min(1, (target - station) / segment.length));
|
|
10947
|
+
if (segment.kind === "line") return add$2(segment.from, scale$2(sub$2(segment.to, segment.from), localT));
|
|
10948
|
+
return arcPointAt(segment, localT);
|
|
10949
|
+
}
|
|
10950
|
+
station = next;
|
|
10951
|
+
}
|
|
10952
|
+
const last = plan.segments[plan.segments.length - 1];
|
|
10953
|
+
return last.kind === "line" ? last.to : last.end;
|
|
10954
|
+
}
|
|
10955
|
+
function sampleRoute3DCompilePlan(plan, options) {
|
|
10956
|
+
const resolved = resolveOptions(options);
|
|
10957
|
+
const points = [];
|
|
10958
|
+
const totalIntervals = Math.max(1, resolved.samples - 1);
|
|
10959
|
+
for (const segment of plan.segments) {
|
|
10960
|
+
const proportional = plan.length > EPSILON$1 ? Math.ceil(segment.length / plan.length * totalIntervals) : 1;
|
|
10961
|
+
const arcIntervals = segment.kind === "arc" ? Math.ceil(Math.abs(segment.sweepDeg) / resolved.maxAngleDeg) : 1;
|
|
10962
|
+
const intervals = Math.max(1, proportional, arcIntervals);
|
|
10963
|
+
const start = segment.kind === "line" ? segment.from : segment.start;
|
|
10964
|
+
pushUnique(points, start);
|
|
10965
|
+
for (let i = 1; i <= intervals; i += 1) {
|
|
10966
|
+
if (segment.kind === "line") {
|
|
10967
|
+
pushUnique(points, add$2(segment.from, scale$2(sub$2(segment.to, segment.from), i / intervals)));
|
|
10968
|
+
} else {
|
|
10969
|
+
pushUnique(points, arcPointAt(segment, i / intervals));
|
|
10970
|
+
}
|
|
10971
|
+
}
|
|
10972
|
+
}
|
|
10973
|
+
return points;
|
|
10974
|
+
}
|
|
10755
10975
|
function catmullRom3D$1(p0, p1, p2, p3, t, tension) {
|
|
10756
10976
|
const tt = t * t;
|
|
10757
10977
|
const ttt = tt * t;
|
|
@@ -10890,6 +11110,8 @@ function evalPathAt(path, t) {
|
|
|
10890
11110
|
const u2 = remapToKnotDomain(Math.max(0, Math.min(1, t)), path.controlPoints.length, path.degree, path.knots);
|
|
10891
11111
|
return deBoor3D(path.controlPoints, path.weights, path.knots, path.degree, u2);
|
|
10892
11112
|
}
|
|
11113
|
+
case "route3d":
|
|
11114
|
+
return routePointAt(path, t);
|
|
10893
11115
|
}
|
|
10894
11116
|
}
|
|
10895
11117
|
function estimateCurvatureAt(path, t) {
|
|
@@ -10936,10 +11158,13 @@ function sweepPathToPolyline(path, samples = 48) {
|
|
|
10936
11158
|
}
|
|
10937
11159
|
return result;
|
|
10938
11160
|
}
|
|
11161
|
+
case "route3d":
|
|
11162
|
+
return sampleRoute3DCompilePlan(path, samples);
|
|
10939
11163
|
}
|
|
10940
11164
|
}
|
|
10941
11165
|
function sweepPathToPolylineAdaptive(path, baseSamples = 48) {
|
|
10942
11166
|
if (path.kind === "polyline") return path.points;
|
|
11167
|
+
if (path.kind === "route3d") return sampleRoute3DCompilePlan(path, baseSamples);
|
|
10943
11168
|
const probeCount = 64;
|
|
10944
11169
|
const curvatures = [];
|
|
10945
11170
|
for (let i = 0; i <= probeCount; i++) {
|
|
@@ -10970,7 +11195,7 @@ const EPS$2 = 1e-8;
|
|
|
10970
11195
|
function midpoint$1(start, end) {
|
|
10971
11196
|
return [(start[0] + end[0]) * 0.5, (start[1] + end[1]) * 0.5, (start[2] + end[2]) * 0.5];
|
|
10972
11197
|
}
|
|
10973
|
-
function normalize$
|
|
11198
|
+
function normalize$3(v) {
|
|
10974
11199
|
const len = Math.hypot(v[0], v[1], v[2]);
|
|
10975
11200
|
if (len <= EPS$2) throw new Error("Edge feature selection requires a non-zero direction vector");
|
|
10976
11201
|
return [v[0] / len, v[1] / len, v[2] / len];
|
|
@@ -11389,8 +11614,8 @@ function extrudeEdgeSelection(plan, edgeName) {
|
|
|
11389
11614
|
}
|
|
11390
11615
|
const points = plan.profile.points;
|
|
11391
11616
|
const [bl, br, _tr, tl] = points;
|
|
11392
|
-
const u2 = normalize$
|
|
11393
|
-
const v = normalize$
|
|
11617
|
+
const u2 = normalize$3([br[0] - bl[0], br[1] - bl[1], 0]);
|
|
11618
|
+
const v = normalize$3([tl[0] - bl[0], tl[1] - bl[1], 0]);
|
|
11394
11619
|
const vertex = points[index2];
|
|
11395
11620
|
const quadrant = index2 === 0 ? [1, -1] : index2 === 1 ? [-1, -1] : index2 === 2 ? [-1, 1] : [1, 1];
|
|
11396
11621
|
return {
|
|
@@ -11411,9 +11636,9 @@ function extrudeEdgeSelection(plan, edgeName) {
|
|
|
11411
11636
|
function applySelectionTransform(selection, transform) {
|
|
11412
11637
|
const start = transform.point(selection.start);
|
|
11413
11638
|
const end = transform.point(selection.end);
|
|
11414
|
-
const basisX = normalize$
|
|
11415
|
-
const basisY = normalize$
|
|
11416
|
-
const axis = normalize$
|
|
11639
|
+
const basisX = normalize$3(transform.vector(selection.basisX));
|
|
11640
|
+
const basisY = normalize$3(transform.vector(selection.basisY));
|
|
11641
|
+
const axis = normalize$3(subtract(end, start));
|
|
11417
11642
|
return {
|
|
11418
11643
|
kind: "line-segment",
|
|
11419
11644
|
edgeName: selection.edgeName,
|
|
@@ -12688,6 +12913,20 @@ function cleanName(value) {
|
|
|
12688
12913
|
const trimmed = value == null ? void 0 : value.replace(/\s+/g, " ").trim();
|
|
12689
12914
|
return trimmed && trimmed.length > 0 ? trimmed : null;
|
|
12690
12915
|
}
|
|
12916
|
+
function uniqueNames(baseNames) {
|
|
12917
|
+
const totals = /* @__PURE__ */ new Map();
|
|
12918
|
+
const seen = /* @__PURE__ */ new Map();
|
|
12919
|
+
for (const baseName of baseNames) totals.set(baseName, (totals.get(baseName) ?? 0) + 1);
|
|
12920
|
+
return baseNames.map((baseName) => {
|
|
12921
|
+
if ((totals.get(baseName) ?? 0) <= 1) return baseName;
|
|
12922
|
+
const ordinal = (seen.get(baseName) ?? 0) + 1;
|
|
12923
|
+
seen.set(baseName, ordinal);
|
|
12924
|
+
return `${baseName} #${String(ordinal).padStart(3, "0")}`;
|
|
12925
|
+
});
|
|
12926
|
+
}
|
|
12927
|
+
function normalizeSelector(value) {
|
|
12928
|
+
return value.trim().replace(/\s+/g, " ").toLowerCase();
|
|
12929
|
+
}
|
|
12691
12930
|
function extractModelXml(data) {
|
|
12692
12931
|
const zip = unzipSync(new Uint8Array(data));
|
|
12693
12932
|
const path = Object.keys(zip).find((entry) => entry.toLowerCase() === "3d/3dmodel.model");
|
|
@@ -12759,14 +12998,105 @@ function collectObjectGeometry(model, objectId, transforms = [], visiting = /* @
|
|
|
12759
12998
|
}
|
|
12760
12999
|
return { vertices, triangles, bbox };
|
|
12761
13000
|
}
|
|
13001
|
+
function buildBuildEntries(model) {
|
|
13002
|
+
const buildBaseNames = model.buildItems.map(
|
|
13003
|
+
(item) => {
|
|
13004
|
+
var _a3;
|
|
13005
|
+
return cleanName((_a3 = model.objectsById.get(item.objectId)) == null ? void 0 : _a3.sourceName) ?? `object-${item.objectId}`;
|
|
13006
|
+
}
|
|
13007
|
+
);
|
|
13008
|
+
const buildNames = uniqueNames(buildBaseNames);
|
|
13009
|
+
return model.buildItems.map((item, index2) => {
|
|
13010
|
+
const object = model.objectsById.get(item.objectId);
|
|
13011
|
+
return {
|
|
13012
|
+
stableRef: `3mf:build:${String(index2 + 1).padStart(3, "0")}:object:${item.objectId}`,
|
|
13013
|
+
objectId: item.objectId,
|
|
13014
|
+
autoName: buildNames[index2],
|
|
13015
|
+
sourceName: object == null ? void 0 : object.sourceName,
|
|
13016
|
+
type: object == null ? void 0 : object.type,
|
|
13017
|
+
transform: item.transform
|
|
13018
|
+
};
|
|
13019
|
+
});
|
|
13020
|
+
}
|
|
13021
|
+
function buildObjectEntries(model) {
|
|
13022
|
+
const objectNames = uniqueNames(model.objects.map((object) => cleanName(object.sourceName) ?? `object-${object.id}`));
|
|
13023
|
+
return model.objects.map(
|
|
13024
|
+
(object, index2) => ({
|
|
13025
|
+
stableRef: `3mf:object:${object.id}`,
|
|
13026
|
+
objectId: object.id,
|
|
13027
|
+
autoName: objectNames[index2],
|
|
13028
|
+
sourceName: object.sourceName,
|
|
13029
|
+
type: object.type
|
|
13030
|
+
})
|
|
13031
|
+
);
|
|
13032
|
+
}
|
|
13033
|
+
function buildDefaultSourceEntries(model) {
|
|
13034
|
+
return model.buildItems.length > 0 ? buildBuildEntries(model) : buildObjectEntries(model);
|
|
13035
|
+
}
|
|
13036
|
+
function buildSelectableEntries(model) {
|
|
13037
|
+
return model.buildItems.length > 0 ? [...buildBuildEntries(model), ...buildObjectEntries(model)] : buildObjectEntries(model);
|
|
13038
|
+
}
|
|
13039
|
+
function entryMatchesSelector(entry, selector) {
|
|
13040
|
+
const needle = normalizeSelector(selector);
|
|
13041
|
+
return [
|
|
13042
|
+
entry.stableRef,
|
|
13043
|
+
entry.autoName,
|
|
13044
|
+
entry.sourceName ?? "",
|
|
13045
|
+
entry.objectId,
|
|
13046
|
+
`object-${entry.objectId}`,
|
|
13047
|
+
`3mf:object:${entry.objectId}`
|
|
13048
|
+
].some((candidate) => normalizeSelector(candidate) === needle);
|
|
13049
|
+
}
|
|
13050
|
+
function availableEntryList(entries) {
|
|
13051
|
+
return entries.map((entry) => `${entry.autoName} [${entry.stableRef}]`).join(", ") || "none";
|
|
13052
|
+
}
|
|
13053
|
+
function selectSourceEntry(entries, selector) {
|
|
13054
|
+
const matches = entries.filter((entry) => entryMatchesSelector(entry, selector));
|
|
13055
|
+
if (matches.length === 1) return matches[0];
|
|
13056
|
+
if (matches.length > 1) {
|
|
13057
|
+
throw new Error(
|
|
13058
|
+
`3MF object selector "${selector}" is ambiguous. Use a stable ref: ${matches.map((entry) => entry.stableRef).join(", ")}`
|
|
13059
|
+
);
|
|
13060
|
+
}
|
|
13061
|
+
throw new Error(`3MF object selector "${selector}" matched no build item or resource object. Available: ${availableEntryList(entries)}`);
|
|
13062
|
+
}
|
|
13063
|
+
function selectorLooksLikeStableRef(selector) {
|
|
13064
|
+
return /^3mf:(build|object):/i.test(selector.trim());
|
|
13065
|
+
}
|
|
13066
|
+
function meshFromGeometry(geometry) {
|
|
13067
|
+
const vertices = [];
|
|
13068
|
+
const triangles = [];
|
|
13069
|
+
for (const vertex of geometry.vertices) vertices.push(vertex[0], vertex[1], vertex[2]);
|
|
13070
|
+
for (const triangle of geometry.triangles) triangles.push(triangle[0], triangle[1], triangle[2]);
|
|
13071
|
+
return {
|
|
13072
|
+
vertProperties: new Float32Array(vertices),
|
|
13073
|
+
triVerts: new Uint32Array(triangles),
|
|
13074
|
+
numProp: 3,
|
|
13075
|
+
mergeFromVert: new Uint32Array(0),
|
|
13076
|
+
mergeToVert: new Uint32Array(0)
|
|
13077
|
+
};
|
|
13078
|
+
}
|
|
13079
|
+
function partFromEntry(model, entry) {
|
|
13080
|
+
const geometry = collectObjectGeometry(model, entry.objectId, [entry.transform]);
|
|
13081
|
+
return {
|
|
13082
|
+
stableRef: entry.stableRef,
|
|
13083
|
+
objectId: entry.objectId,
|
|
13084
|
+
autoName: entry.autoName,
|
|
13085
|
+
sourceName: entry.sourceName,
|
|
13086
|
+
type: entry.type,
|
|
13087
|
+
mesh: meshFromGeometry(geometry),
|
|
13088
|
+
bbox: geometry.bbox,
|
|
13089
|
+
vertexCount: geometry.vertices.length,
|
|
13090
|
+
triangleCount: geometry.triangles.length
|
|
13091
|
+
};
|
|
13092
|
+
}
|
|
12762
13093
|
function parse3mfMesh(data) {
|
|
12763
13094
|
const model = parseModel(data);
|
|
12764
|
-
const
|
|
12765
|
-
const transforms = model.buildItems.length > 0 ? model.buildItems.map((item) => item.transform) : sourceIds.map(() => void 0);
|
|
13095
|
+
const entries = buildDefaultSourceEntries(model);
|
|
12766
13096
|
const vertices = [];
|
|
12767
13097
|
const triangles = [];
|
|
12768
|
-
|
|
12769
|
-
const geometry = collectObjectGeometry(model, objectId, [
|
|
13098
|
+
entries.forEach((entry) => {
|
|
13099
|
+
const geometry = collectObjectGeometry(model, entry.objectId, [entry.transform]);
|
|
12770
13100
|
const offset = vertices.length / 3;
|
|
12771
13101
|
for (const vertex of geometry.vertices) vertices.push(vertex[0], vertex[1], vertex[2]);
|
|
12772
13102
|
for (const triangle of geometry.triangles) triangles.push(triangle[0] + offset, triangle[1] + offset, triangle[2] + offset);
|
|
@@ -12779,6 +13109,11 @@ function parse3mfMesh(data) {
|
|
|
12779
13109
|
mergeToVert: new Uint32Array(0)
|
|
12780
13110
|
};
|
|
12781
13111
|
}
|
|
13112
|
+
function parse3mfMeshPart(data, selector) {
|
|
13113
|
+
const model = parseModel(data);
|
|
13114
|
+
const entries = selectorLooksLikeStableRef(selector) ? buildSelectableEntries(model) : buildDefaultSourceEntries(model);
|
|
13115
|
+
return partFromEntry(model, selectSourceEntry(entries, selector));
|
|
13116
|
+
}
|
|
12782
13117
|
function isStlBinary(data) {
|
|
12783
13118
|
if (data.byteLength < 84) return false;
|
|
12784
13119
|
const view = new DataView(data);
|
|
@@ -12923,17 +13258,17 @@ function parseObj(data) {
|
|
|
12923
13258
|
mergeToVert: new Uint32Array(0)
|
|
12924
13259
|
};
|
|
12925
13260
|
}
|
|
12926
|
-
function parse3mf(data) {
|
|
12927
|
-
return parse3mfMesh(data);
|
|
13261
|
+
function parse3mf(data, options = {}) {
|
|
13262
|
+
return options.object ? parse3mfMeshPart(data, options.object).mesh : parse3mfMesh(data);
|
|
12928
13263
|
}
|
|
12929
|
-
function parseMeshFile(data, format) {
|
|
13264
|
+
function parseMeshFile(data, format, options = {}) {
|
|
12930
13265
|
switch (format) {
|
|
12931
13266
|
case "stl":
|
|
12932
13267
|
return parseStl(data);
|
|
12933
13268
|
case "obj":
|
|
12934
13269
|
return parseObj(data);
|
|
12935
13270
|
case "3mf":
|
|
12936
|
-
return parse3mf(data);
|
|
13271
|
+
return parse3mf(data, options);
|
|
12937
13272
|
}
|
|
12938
13273
|
}
|
|
12939
13274
|
function cleanZero(value) {
|
|
@@ -12960,6 +13295,84 @@ function planeFrameToWorldToPlaneMatrix(frame) {
|
|
|
12960
13295
|
1
|
|
12961
13296
|
];
|
|
12962
13297
|
}
|
|
13298
|
+
const DEFAULT_TOLERANCE = 1;
|
|
13299
|
+
const DEFAULT_ANGLE_TOLERANCE = 10;
|
|
13300
|
+
function distSq$1(a2, b) {
|
|
13301
|
+
const dx = a2[0] - b[0];
|
|
13302
|
+
const dy = a2[1] - b[1];
|
|
13303
|
+
const dz = a2[2] - b[2];
|
|
13304
|
+
return dx * dx + dy * dy + dz * dz;
|
|
13305
|
+
}
|
|
13306
|
+
function vecLength$2(v) {
|
|
13307
|
+
return Math.sqrt(v[0] * v[0] + v[1] * v[1] + v[2] * v[2]);
|
|
13308
|
+
}
|
|
13309
|
+
function normalize$2(v) {
|
|
13310
|
+
const len = vecLength$2(v);
|
|
13311
|
+
if (len < 1e-12) return [0, 0, 0];
|
|
13312
|
+
return [v[0] / len, v[1] / len, v[2] / len];
|
|
13313
|
+
}
|
|
13314
|
+
function absDot$1(a2, b) {
|
|
13315
|
+
return Math.abs(a2[0] * b[0] + a2[1] * b[1] + a2[2] * b[2]);
|
|
13316
|
+
}
|
|
13317
|
+
function applyEdgeQueryFilters(edges, query) {
|
|
13318
|
+
const tol = query.tolerance ?? DEFAULT_TOLERANCE;
|
|
13319
|
+
const angleTol = query.angleTolerance ?? DEFAULT_ANGLE_TOLERANCE;
|
|
13320
|
+
const cosAngleTol = Math.cos(angleTol * Math.PI / 180);
|
|
13321
|
+
let result = edges;
|
|
13322
|
+
if (query.convex === true) {
|
|
13323
|
+
result = result.filter((e) => e.convex);
|
|
13324
|
+
}
|
|
13325
|
+
if (query.concave === true) {
|
|
13326
|
+
result = result.filter((e) => !e.convex);
|
|
13327
|
+
}
|
|
13328
|
+
if (query.minAngle != null) {
|
|
13329
|
+
const min2 = query.minAngle;
|
|
13330
|
+
result = result.filter((e) => e.dihedralAngle >= min2);
|
|
13331
|
+
}
|
|
13332
|
+
if (query.maxAngle != null) {
|
|
13333
|
+
const max2 = query.maxAngle;
|
|
13334
|
+
result = result.filter((e) => e.dihedralAngle <= max2);
|
|
13335
|
+
}
|
|
13336
|
+
if (query.minLength != null) {
|
|
13337
|
+
const min2 = query.minLength;
|
|
13338
|
+
result = result.filter((e) => e.length >= min2);
|
|
13339
|
+
}
|
|
13340
|
+
if (query.maxLength != null) {
|
|
13341
|
+
const max2 = query.maxLength;
|
|
13342
|
+
result = result.filter((e) => e.length <= max2);
|
|
13343
|
+
}
|
|
13344
|
+
if (query.parallel) {
|
|
13345
|
+
const dir = normalize$2(query.parallel);
|
|
13346
|
+
result = result.filter((e) => absDot$1(e.direction, dir) >= cosAngleTol);
|
|
13347
|
+
}
|
|
13348
|
+
if (query.perpendicular) {
|
|
13349
|
+
const dir = normalize$2(query.perpendicular);
|
|
13350
|
+
const sinAngleTol = Math.sin(angleTol * Math.PI / 180);
|
|
13351
|
+
result = result.filter((e) => absDot$1(e.direction, dir) <= sinAngleTol);
|
|
13352
|
+
}
|
|
13353
|
+
if (query.atZ != null) {
|
|
13354
|
+
const z2 = query.atZ;
|
|
13355
|
+
result = result.filter((e) => Math.abs(e.midpoint[2] - z2) <= tol);
|
|
13356
|
+
}
|
|
13357
|
+
if (query.within) {
|
|
13358
|
+
const b = query.within;
|
|
13359
|
+
result = result.filter((e) => {
|
|
13360
|
+
const [mx, my, mz] = e.midpoint;
|
|
13361
|
+
if (b.xMin != null && mx < b.xMin) return false;
|
|
13362
|
+
if (b.xMax != null && mx > b.xMax) return false;
|
|
13363
|
+
if (b.yMin != null && my < b.yMin) return false;
|
|
13364
|
+
if (b.yMax != null && my > b.yMax) return false;
|
|
13365
|
+
if (b.zMin != null && mz < b.zMin) return false;
|
|
13366
|
+
if (b.zMax != null && mz > b.zMax) return false;
|
|
13367
|
+
return true;
|
|
13368
|
+
});
|
|
13369
|
+
}
|
|
13370
|
+
if (query.near) {
|
|
13371
|
+
const pt = query.near;
|
|
13372
|
+
result = result.slice().sort((a2, b) => distSq$1(a2.midpoint, pt) - distSq$1(b.midpoint, pt));
|
|
13373
|
+
}
|
|
13374
|
+
return result;
|
|
13375
|
+
}
|
|
12963
13376
|
const SHELL_OPEN_FACE_CANONICAL = {
|
|
12964
13377
|
front: "side-bottom",
|
|
12965
13378
|
back: "side-top",
|
|
@@ -15259,6 +15672,8 @@ function getUnsupportedSdfProgramReason(node) {
|
|
|
15259
15672
|
return "noise depends on table-based simplex evaluation";
|
|
15260
15673
|
case "sdf:voronoi":
|
|
15261
15674
|
return "voronoi depends on table-based Worley evaluation";
|
|
15675
|
+
case "sdf:circularArray":
|
|
15676
|
+
return "circularArray folds polar coordinates and is not implemented in SdfProgram yet";
|
|
15262
15677
|
case "sdf:custom":
|
|
15263
15678
|
return "custom uses a dynamic JavaScript function body";
|
|
15264
15679
|
case "sdf:polylineSweep":
|
|
@@ -16065,6 +16480,8 @@ function sampleSweepPath(path, edgeLengthHint) {
|
|
|
16065
16480
|
path,
|
|
16066
16481
|
edgeLengthHint != null ? Math.max(16, Math.round(path.controlPoints.length * 12 / Math.max(0.1, edgeLengthHint))) : 48
|
|
16067
16482
|
);
|
|
16483
|
+
case "route3d":
|
|
16484
|
+
return sweepPathToPolyline(path, resolveCurveSampleCount(edgeLengthHint, path.length));
|
|
16068
16485
|
}
|
|
16069
16486
|
}
|
|
16070
16487
|
function clamp(v, lo, hi) {
|
|
@@ -17348,6 +17765,7 @@ function rotateVector(v, axis, c2, s) {
|
|
|
17348
17765
|
];
|
|
17349
17766
|
}
|
|
17350
17767
|
const OFFSET_SOLID_EPS$1 = 1e-9;
|
|
17768
|
+
const OCCT_BACKEND_REQUIRED_HINT = "Select the OCCT backend in the editor or run the CLI with --backend occt.";
|
|
17351
17769
|
function disposeWasmObject(value) {
|
|
17352
17770
|
if (value != null && typeof value.delete === "function") value.delete();
|
|
17353
17771
|
}
|
|
@@ -17832,7 +18250,7 @@ function profilePolygonLoopTopologyMatches(left, right) {
|
|
|
17832
18250
|
}
|
|
17833
18251
|
function lowerOffsetLoftCompilePlan(plan, thickness, wasm) {
|
|
17834
18252
|
if (plan.profiles.length !== plan.heights.length || plan.profiles.length < 2) {
|
|
17835
|
-
throw new Error(
|
|
18253
|
+
throw new Error(`Offset solid requires the OCCT backend. ${OCCT_BACKEND_REQUIRED_HINT}`);
|
|
17836
18254
|
}
|
|
17837
18255
|
const heights = [...plan.heights];
|
|
17838
18256
|
heights[0] -= thickness;
|
|
@@ -17843,7 +18261,7 @@ function lowerOffsetLoftCompilePlan(plan, thickness, wasm) {
|
|
|
17843
18261
|
const offsetPolygons = plan.profiles.map((profile) => offsetProfilePolygonsForManifold(profile, thickness, wasm));
|
|
17844
18262
|
const stitched = loftStitched(offsetPolygons, heights, wasm);
|
|
17845
18263
|
if (!stitched) {
|
|
17846
|
-
throw new Error(
|
|
18264
|
+
throw new Error(`Offset solid requires the OCCT backend. ${OCCT_BACKEND_REQUIRED_HINT}`);
|
|
17847
18265
|
}
|
|
17848
18266
|
return stitched;
|
|
17849
18267
|
}
|
|
@@ -17883,16 +18301,16 @@ function lowerOffsetSweepCompilePlan(plan, thickness, wasm) {
|
|
|
17883
18301
|
const basePolygons = profilePolygonsForManifold(plan.profile, wasm);
|
|
17884
18302
|
const offsetPolygons = offsetProfilePolygonsForManifold(plan.profile, thickness, wasm);
|
|
17885
18303
|
if (!profilePolygonLoopTopologyMatches(basePolygons, offsetPolygons)) {
|
|
17886
|
-
throw new Error(
|
|
18304
|
+
throw new Error(`Offset solid requires the OCCT backend. ${OCCT_BACKEND_REQUIRED_HINT}`);
|
|
17887
18305
|
}
|
|
17888
18306
|
const pathPoints = sweepPathToPolylineAdaptive(plan.path, plan.pathSamples ?? 48);
|
|
17889
18307
|
const extendedPath = extendedStraightSweepPathForManifold(pathPoints, thickness);
|
|
17890
18308
|
if (!extendedPath) {
|
|
17891
|
-
throw new Error(
|
|
18309
|
+
throw new Error(`Offset solid requires the OCCT backend. ${OCCT_BACKEND_REQUIRED_HINT}`);
|
|
17892
18310
|
}
|
|
17893
18311
|
const stitched = sweepStitched(offsetPolygons, extendedPath, [plan.up[0], plan.up[1], plan.up[2]], wasm);
|
|
17894
18312
|
if (!stitched) {
|
|
17895
|
-
throw new Error(
|
|
18313
|
+
throw new Error(`Offset solid requires the OCCT backend. ${OCCT_BACKEND_REQUIRED_HINT}`);
|
|
17896
18314
|
}
|
|
17897
18315
|
return stitched;
|
|
17898
18316
|
}
|
|
@@ -17901,7 +18319,7 @@ function lowerTransformedOffsetSolidCompilePlan(plan, thickness, wasm) {
|
|
|
17901
18319
|
for (const step of plan.steps) {
|
|
17902
18320
|
const stepScale = offsetSolidTransformDistanceScaleForManifold(step);
|
|
17903
18321
|
if (stepScale == null) {
|
|
17904
|
-
throw new Error(
|
|
18322
|
+
throw new Error(`Offset solid requires the OCCT backend. ${OCCT_BACKEND_REQUIRED_HINT}`);
|
|
17905
18323
|
}
|
|
17906
18324
|
distanceScale *= stepScale;
|
|
17907
18325
|
}
|
|
@@ -17942,7 +18360,7 @@ function lowerOffsetSolidCompilePlan(plan, wasm) {
|
|
|
17942
18360
|
}
|
|
17943
18361
|
const base = verticalPrismOffsetBaseForManifold(basePlan);
|
|
17944
18362
|
if (!base) {
|
|
17945
|
-
throw new Error(
|
|
18363
|
+
throw new Error(`Offset solid requires the OCCT backend. ${OCCT_BACKEND_REQUIRED_HINT}`);
|
|
17946
18364
|
}
|
|
17947
18365
|
const zMin = base.zMin - plan.thickness;
|
|
17948
18366
|
const zMax = base.zMax + plan.thickness;
|
|
@@ -18467,6 +18885,18 @@ function matchEdgeSegmentByMidpoint(segments, target) {
|
|
|
18467
18885
|
}
|
|
18468
18886
|
return best;
|
|
18469
18887
|
}
|
|
18888
|
+
function selectEdgeSegmentsForFeature(segments, plan) {
|
|
18889
|
+
if (plan.edgeQuery) {
|
|
18890
|
+
const selected = applyEdgeQueryFilters(segments, plan.edgeQuery);
|
|
18891
|
+
return plan.edgeSelection === "first" ? selected.slice(0, 1) : selected;
|
|
18892
|
+
}
|
|
18893
|
+
const matched = [];
|
|
18894
|
+
for (const target of plan.edgeTargets ?? []) {
|
|
18895
|
+
const seg = matchEdgeSegmentByMidpoint(segments, target);
|
|
18896
|
+
if (seg && seg.length >= 1e-6) matched.push(seg);
|
|
18897
|
+
}
|
|
18898
|
+
return matched;
|
|
18899
|
+
}
|
|
18470
18900
|
function lowerFilletEdgesCompilePlan(plan, wasm) {
|
|
18471
18901
|
let manifold = lowerShapeCompilePlanToManifold(plan.base, wasm);
|
|
18472
18902
|
const mesh = manifold.getMesh();
|
|
@@ -18476,11 +18906,8 @@ function lowerFilletEdgesCompilePlan(plan, wasm) {
|
|
|
18476
18906
|
triVerts: mesh.triVerts,
|
|
18477
18907
|
vertProperties: mesh.vertProperties
|
|
18478
18908
|
});
|
|
18479
|
-
const matched =
|
|
18480
|
-
|
|
18481
|
-
const seg = matchEdgeSegmentByMidpoint(segments, target);
|
|
18482
|
-
if (seg && seg.length >= 1e-6) matched.push(seg);
|
|
18483
|
-
}
|
|
18909
|
+
const matched = selectEdgeSegmentsForFeature(segments, plan);
|
|
18910
|
+
if (plan.edgeQuery && matched.length === 0) throw new Error("filletEdges(): no edges match the deferred edge query.");
|
|
18484
18911
|
matched.sort((a2, b) => b.length - a2.length);
|
|
18485
18912
|
for (const seg of matched) {
|
|
18486
18913
|
try {
|
|
@@ -18503,11 +18930,8 @@ function lowerChamferEdgesCompilePlan(plan, wasm) {
|
|
|
18503
18930
|
triVerts: mesh.triVerts,
|
|
18504
18931
|
vertProperties: mesh.vertProperties
|
|
18505
18932
|
});
|
|
18506
|
-
const matched =
|
|
18507
|
-
|
|
18508
|
-
const seg = matchEdgeSegmentByMidpoint(segments, target);
|
|
18509
|
-
if (seg && seg.length >= 1e-6) matched.push(seg);
|
|
18510
|
-
}
|
|
18933
|
+
const matched = selectEdgeSegmentsForFeature(segments, plan);
|
|
18934
|
+
if (plan.edgeQuery && matched.length === 0) throw new Error("chamferEdges(): no edges match the deferred edge query.");
|
|
18511
18935
|
matched.sort((a2, b) => b.length - a2.length);
|
|
18512
18936
|
for (const seg of matched) {
|
|
18513
18937
|
try {
|
|
@@ -18609,20 +19033,20 @@ function lowerShapeCompilePlanToManifold(plan, wasm) {
|
|
|
18609
19033
|
case "filletEdges":
|
|
18610
19034
|
return lowerFilletEdgesCompilePlan(plan, wasm);
|
|
18611
19035
|
case "cornerYBlend":
|
|
18612
|
-
throw new Error(
|
|
19036
|
+
throw new Error(`Blend.CornerY() requires the OCCT backend. ${OCCT_BACKEND_REQUIRED_HINT}`);
|
|
18613
19037
|
case "chamferEdges":
|
|
18614
19038
|
return lowerChamferEdgesCompilePlan(plan, wasm);
|
|
18615
19039
|
case "draft": {
|
|
18616
19040
|
const lowered = lowerDraftShapeCompilePlanToLoftPlan(plan);
|
|
18617
19041
|
if (lowered) return lowerShapeCompilePlanToManifold(lowered, wasm);
|
|
18618
|
-
throw new Error(
|
|
19042
|
+
throw new Error(`Draft angle requires the OCCT backend. ${OCCT_BACKEND_REQUIRED_HINT}`);
|
|
18619
19043
|
}
|
|
18620
19044
|
case "offsetSolid":
|
|
18621
19045
|
return lowerOffsetSolidCompilePlan(plan, wasm);
|
|
18622
19046
|
case "trimByPlane":
|
|
18623
19047
|
return lowerShapeTrimByPlaneCompilePlan(plan, wasm);
|
|
18624
19048
|
case "importedMesh":
|
|
18625
|
-
return lowerImportedMeshToManifold(plan.fileData, plan.format, plan.filePath, wasm);
|
|
19049
|
+
return lowerImportedMeshToManifold(plan.fileData, plan.format, plan.filePath, wasm, plan.object);
|
|
18626
19050
|
case "sdf": {
|
|
18627
19051
|
const evaluator = compileSdfMaterializationEvaluator3(plan.tree);
|
|
18628
19052
|
return lowerSdfToManifold(
|
|
@@ -18646,9 +19070,9 @@ function lowerShapeCompilePlanToManifold(plan, wasm) {
|
|
|
18646
19070
|
case "surfaceExtend":
|
|
18647
19071
|
case "surfaceThicken":
|
|
18648
19072
|
case "surfaceSolid":
|
|
18649
|
-
throw new Error(
|
|
19073
|
+
throw new Error(`Exact surfacing operations require the OCCT backend. ${OCCT_BACKEND_REQUIRED_HINT}`);
|
|
18650
19074
|
case "importedStep":
|
|
18651
|
-
throw new Error(`importStep("${plan.filePath}") requires the OCCT backend.
|
|
19075
|
+
throw new Error(`importStep("${plan.filePath}") requires the OCCT backend. ${OCCT_BACKEND_REQUIRED_HINT}`);
|
|
18652
19076
|
default:
|
|
18653
19077
|
assertExhaustive(plan);
|
|
18654
19078
|
}
|
|
@@ -18789,11 +19213,11 @@ function projectVerticesToSurfaceWithNormals(vertProperties, sdfFn, out6) {
|
|
|
18789
19213
|
function lowerNurbsSurfaceToManifold(plan, wasm) {
|
|
18790
19214
|
if (!plan.allowApproximation && plan.thickness === 0) {
|
|
18791
19215
|
throw new Error(
|
|
18792
|
-
|
|
19216
|
+
`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.`
|
|
18793
19217
|
);
|
|
18794
19218
|
}
|
|
18795
19219
|
if (plan.thickness === 0) {
|
|
18796
|
-
throw new Error(
|
|
19220
|
+
throw new Error(`The Manifold backend cannot represent open sheet surfaces. ${OCCT_BACKEND_REQUIRED_HINT}`);
|
|
18797
19221
|
}
|
|
18798
19222
|
const surface = new NurbsSurface(plan.controlGrid, {
|
|
18799
19223
|
degreeU: plan.degreeU,
|
|
@@ -18943,8 +19367,8 @@ function lowerTrimmedNurbsSurfaceToManifold(surface, plan, wasm) {
|
|
|
18943
19367
|
disposeWasmObject(mesh);
|
|
18944
19368
|
}
|
|
18945
19369
|
}
|
|
18946
|
-
function lowerImportedMeshToManifold(fileData, format, filePath, wasm) {
|
|
18947
|
-
const parsed = parseMeshFile(fileData, format);
|
|
19370
|
+
function lowerImportedMeshToManifold(fileData, format, filePath, wasm, object) {
|
|
19371
|
+
const parsed = parseMeshFile(fileData, format, { object });
|
|
18948
19372
|
if (parsed.triVerts.length === 0) {
|
|
18949
19373
|
throw new Error(`importMesh("${filePath}"): file contains no triangles`);
|
|
18950
19374
|
}
|
|
@@ -18966,7 +19390,11 @@ function lowerImportedMeshToManifold(fileData, format, filePath, wasm) {
|
|
|
18966
19390
|
}
|
|
18967
19391
|
}
|
|
18968
19392
|
function lowerShapeCompilePlanToShapeBackend(plan, wasm) {
|
|
18969
|
-
return lowerShapeBackendWithCache(
|
|
19393
|
+
return lowerShapeBackendWithCache(
|
|
19394
|
+
"manifold",
|
|
19395
|
+
plan,
|
|
19396
|
+
(basePlan) => wrapManifoldShapeBackend(lowerShapeCompilePlanToManifold(basePlan, wasm))
|
|
19397
|
+
);
|
|
18970
19398
|
}
|
|
18971
19399
|
const PROFILE_BACKEND_MARKER = Symbol.for("forgecad.profileBackend");
|
|
18972
19400
|
function occtProfileOffsetJoinType(oc, join) {
|
|
@@ -18981,6 +19409,7 @@ function occtProfileOffsetJoinType(oc, join) {
|
|
|
18981
19409
|
}
|
|
18982
19410
|
const BSPLINE_WIRE_THRESHOLD = 20;
|
|
18983
19411
|
const OFFSET_SOLID_EPS = 1e-8;
|
|
19412
|
+
const MANIFOLD_BACKEND_REQUIRED_HINT = "Select the Manifold backend in the editor or run the CLI with --backend manifold.";
|
|
18984
19413
|
function transformProfileRadiusPoint(point, step) {
|
|
18985
19414
|
switch (step.kind) {
|
|
18986
19415
|
case "translate":
|
|
@@ -19686,6 +20115,31 @@ function findOCCTEdgeByMidpoint(oc, shape, midpoint2) {
|
|
|
19686
20115
|
}
|
|
19687
20116
|
return bestEdge;
|
|
19688
20117
|
}
|
|
20118
|
+
function edgeSegmentToTarget(segment) {
|
|
20119
|
+
return {
|
|
20120
|
+
midpoint: [segment.midpoint[0], segment.midpoint[1], segment.midpoint[2]],
|
|
20121
|
+
start: [segment.start[0], segment.start[1], segment.start[2]],
|
|
20122
|
+
end: [segment.end[0], segment.end[1], segment.end[2]],
|
|
20123
|
+
convex: segment.convex,
|
|
20124
|
+
...segment.nativeTopology ? { nativeTopology: segment.nativeTopology } : {}
|
|
20125
|
+
};
|
|
20126
|
+
}
|
|
20127
|
+
function selectOCCTEdgeFeatureTargets(base, plan) {
|
|
20128
|
+
if (!plan.edgeQuery) return plan.edgeTargets ?? [];
|
|
20129
|
+
const mesh = wrapOCCTShapeBackend(base).getMesh();
|
|
20130
|
+
const selected = applyEdgeQueryFilters(
|
|
20131
|
+
extractEdgeSegments({
|
|
20132
|
+
numProp: mesh.numProp,
|
|
20133
|
+
numTri: mesh.numTri,
|
|
20134
|
+
triVerts: mesh.triVerts,
|
|
20135
|
+
vertProperties: mesh.vertProperties,
|
|
20136
|
+
mergeFromVert: mesh.mergeFromVert,
|
|
20137
|
+
mergeToVert: mesh.mergeToVert
|
|
20138
|
+
}),
|
|
20139
|
+
plan.edgeQuery
|
|
20140
|
+
);
|
|
20141
|
+
return (plan.edgeSelection === "first" ? selected.slice(0, 1) : selected).map(edgeSegmentToTarget);
|
|
20142
|
+
}
|
|
19689
20143
|
function occtPointDistance(point, target) {
|
|
19690
20144
|
return Math.hypot(point.X() - target[0], point.Y() - target[1], point.Z() - target[2]);
|
|
19691
20145
|
}
|
|
@@ -19705,7 +20159,7 @@ function lowerFilletEdgesPlan$1(oc, plan) {
|
|
|
19705
20159
|
mkFillet.SetContinuity(mapSurfaceContinuityToOcct(oc, plan.continuity), 2 * Math.PI / 180);
|
|
19706
20160
|
}
|
|
19707
20161
|
let addedCount = 0;
|
|
19708
|
-
for (const target of plan
|
|
20162
|
+
for (const target of selectOCCTEdgeFeatureTargets(base, plan)) {
|
|
19709
20163
|
const matchedEdge = findOCCTEdgeByMidpoint(oc, base, target.midpoint);
|
|
19710
20164
|
if (matchedEdge) {
|
|
19711
20165
|
mkFillet.Add_2(plan.radius, matchedEdge);
|
|
@@ -19752,7 +20206,7 @@ function lowerChamferEdgesPlan$1(oc, plan) {
|
|
|
19752
20206
|
const base = lowerShapeCompilePlanToOCCT(plan.base, oc);
|
|
19753
20207
|
const mkChamfer = new oc.BRepFilletAPI_MakeChamfer(base);
|
|
19754
20208
|
let addedCount = 0;
|
|
19755
|
-
for (const target of plan
|
|
20209
|
+
for (const target of selectOCCTEdgeFeatureTargets(base, plan)) {
|
|
19756
20210
|
const matchedEdge = findOCCTEdgeByMidpoint(oc, base, target.midpoint);
|
|
19757
20211
|
if (matchedEdge) {
|
|
19758
20212
|
mkChamfer.Add_2(plan.size, matchedEdge);
|
|
@@ -20039,7 +20493,7 @@ function _lowerShapeCompilePlanToOCCTInner(plan, oc) {
|
|
|
20039
20493
|
`importMesh("${plan.filePath}") is not supported with the OCCT backend. Switch to the Manifold backend or use the default backend.`
|
|
20040
20494
|
);
|
|
20041
20495
|
case "sdf":
|
|
20042
|
-
throw new Error(
|
|
20496
|
+
throw new Error(`SDF shapes require the Manifold backend. ${MANIFOLD_BACKEND_REQUIRED_HINT}`);
|
|
20043
20497
|
case "fromSlices":
|
|
20044
20498
|
return lowerFromSlicesPlan$1(oc, plan);
|
|
20045
20499
|
case "nurbsSurface":
|
|
@@ -20211,6 +20665,7 @@ function buildBSplineCurveHandleFromSweepPathPlan(oc, path, context, allowApprox
|
|
|
20211
20665
|
case "catmull-rom":
|
|
20212
20666
|
case "hermite":
|
|
20213
20667
|
case "quintic-hermite":
|
|
20668
|
+
case "route3d":
|
|
20214
20669
|
if (allowApproximation) {
|
|
20215
20670
|
return buildApproximateBSplineCurveHandle(oc, sweepPathToPolyline(path, 96), context);
|
|
20216
20671
|
}
|
|
@@ -20591,27 +21046,166 @@ function lowerLoftPlan$1(oc, plan) {
|
|
|
20591
21046
|
}
|
|
20592
21047
|
return ts.Shape();
|
|
20593
21048
|
}
|
|
20594
|
-
function
|
|
21049
|
+
function fromSlicesPlaneFrameForOCCT(normalInput) {
|
|
21050
|
+
const normal = normalizeVec3$1(normalInput);
|
|
21051
|
+
if (!normal) throw new Error("Shape.fromSlices group normal must be non-zero");
|
|
20595
21052
|
const [nx, ny, nz] = normal;
|
|
21053
|
+
if (Math.abs(nz) > 1 - 1e-8) {
|
|
21054
|
+
return { u: [1, 0, 0], v: [0, nz > 0 ? 1 : -1, 0], normal };
|
|
21055
|
+
}
|
|
21056
|
+
if (Math.abs(ny) > 1 - 1e-8) {
|
|
21057
|
+
return { u: [1, 0, 0], v: [0, 0, ny > 0 ? 1 : -1], normal };
|
|
21058
|
+
}
|
|
21059
|
+
if (Math.abs(nx) > 1 - 1e-8) {
|
|
21060
|
+
return { u: [0, 1, 0], v: [0, 0, nx > 0 ? 1 : -1], normal };
|
|
21061
|
+
}
|
|
21062
|
+
const reference = Math.abs(nx) < 0.9 ? [1, 0, 0] : [0, 1, 0];
|
|
21063
|
+
const u2 = normalizeVec3$1(crossVec3$1(reference, normal));
|
|
21064
|
+
if (!u2) throw new Error("Shape.fromSlices profile u axis is invalid");
|
|
21065
|
+
return { u: u2, v: crossVec3$1(normal, u2), normal };
|
|
21066
|
+
}
|
|
21067
|
+
function buildFromSlicesLocalToWorldTransform(oc, normal) {
|
|
21068
|
+
const frame = fromSlicesPlaneFrameForOCCT(normal);
|
|
20596
21069
|
const trsf = new oc.gp_Trsf_1();
|
|
20597
|
-
|
|
20598
|
-
|
|
20599
|
-
|
|
20600
|
-
|
|
20601
|
-
|
|
20602
|
-
|
|
20603
|
-
|
|
20604
|
-
|
|
20605
|
-
|
|
20606
|
-
|
|
20607
|
-
|
|
20608
|
-
|
|
21070
|
+
trsf.SetValues(
|
|
21071
|
+
frame.u[0],
|
|
21072
|
+
frame.v[0],
|
|
21073
|
+
frame.normal[0],
|
|
21074
|
+
0,
|
|
21075
|
+
frame.u[1],
|
|
21076
|
+
frame.v[1],
|
|
21077
|
+
frame.normal[1],
|
|
21078
|
+
0,
|
|
21079
|
+
frame.u[2],
|
|
21080
|
+
frame.v[2],
|
|
21081
|
+
frame.normal[2],
|
|
21082
|
+
0
|
|
21083
|
+
);
|
|
20609
21084
|
return trsf;
|
|
20610
21085
|
}
|
|
21086
|
+
function axisAlignedDirectionForOCCT(vector) {
|
|
21087
|
+
let bestAxis = 0;
|
|
21088
|
+
let best = Math.abs(vector[0]);
|
|
21089
|
+
for (const axis of [1, 2]) {
|
|
21090
|
+
const value = Math.abs(vector[axis]);
|
|
21091
|
+
if (value > best) {
|
|
21092
|
+
best = value;
|
|
21093
|
+
bestAxis = axis;
|
|
21094
|
+
}
|
|
21095
|
+
}
|
|
21096
|
+
if (best < 1 - 1e-8) return null;
|
|
21097
|
+
return { axis: bestAxis, sign: vector[bestAxis] < 0 ? -1 : 1 };
|
|
21098
|
+
}
|
|
21099
|
+
function centeredEllipseProfileRadiiForOCCT(plan) {
|
|
21100
|
+
if (plan.kind !== "circle") return null;
|
|
21101
|
+
let rx = Math.abs(plan.radius);
|
|
21102
|
+
let ry = Math.abs(plan.radius);
|
|
21103
|
+
for (const transform of plan.transforms) {
|
|
21104
|
+
if (transform.kind !== "scale") return null;
|
|
21105
|
+
rx *= Math.abs(transform.x);
|
|
21106
|
+
ry *= Math.abs(transform.y);
|
|
21107
|
+
}
|
|
21108
|
+
return rx > 1e-10 && ry > 1e-10 ? [rx, ry] : null;
|
|
21109
|
+
}
|
|
21110
|
+
function setEllipsoidRadiusForOCCT(radii, axis, radius) {
|
|
21111
|
+
const existing = radii[axis];
|
|
21112
|
+
if (existing == null) {
|
|
21113
|
+
radii[axis] = radius;
|
|
21114
|
+
return true;
|
|
21115
|
+
}
|
|
21116
|
+
const tolerance = Math.max(1e-7, Math.max(Math.abs(existing), Math.abs(radius)) * 1e-7);
|
|
21117
|
+
return Math.abs(existing - radius) <= tolerance;
|
|
21118
|
+
}
|
|
21119
|
+
function buildRationalQuadraticEdgeForOCCT(oc, points, weights) {
|
|
21120
|
+
const poles = new oc.TColgp_Array1OfPnt_2(1, 3);
|
|
21121
|
+
const weightArr = new oc.TColStd_Array1OfReal_2(1, 3);
|
|
21122
|
+
for (let i = 0; i < 3; i++) {
|
|
21123
|
+
const [x2, y2, z2] = points[i];
|
|
21124
|
+
poles.SetValue(i + 1, new oc.gp_Pnt_3(x2, y2, z2));
|
|
21125
|
+
weightArr.SetValue(i + 1, weights[i]);
|
|
21126
|
+
}
|
|
21127
|
+
const knots = new oc.TColStd_Array1OfReal_2(1, 2);
|
|
21128
|
+
knots.SetValue(1, 0);
|
|
21129
|
+
knots.SetValue(2, 1);
|
|
21130
|
+
const mults = new oc.TColStd_Array1OfInteger_2(1, 2);
|
|
21131
|
+
mults.SetValue(1, 3);
|
|
21132
|
+
mults.SetValue(2, 3);
|
|
21133
|
+
const curve = new oc.Geom_BSplineCurve_2(poles, weightArr, knots, mults, 2, false, true);
|
|
21134
|
+
const handle = new oc.Handle_Geom_BSplineCurve_2(curve);
|
|
21135
|
+
return new oc.BRepBuilderAPI_MakeEdge_24(new oc.Handle_Geom_Curve_2(handle.get())).Edge();
|
|
21136
|
+
}
|
|
21137
|
+
function lowerAxisymmetricEllipsoidForOCCT(oc, radius, heightRadius) {
|
|
21138
|
+
const w2 = Math.SQRT1_2;
|
|
21139
|
+
const mkWire = new oc.BRepBuilderAPI_MakeWire_1();
|
|
21140
|
+
mkWire.Add_1(
|
|
21141
|
+
buildRationalQuadraticEdgeForOCCT(
|
|
21142
|
+
oc,
|
|
21143
|
+
[
|
|
21144
|
+
[0, 0, heightRadius],
|
|
21145
|
+
[radius, 0, heightRadius],
|
|
21146
|
+
[radius, 0, 0]
|
|
21147
|
+
],
|
|
21148
|
+
[1, w2, 1]
|
|
21149
|
+
)
|
|
21150
|
+
);
|
|
21151
|
+
mkWire.Add_1(
|
|
21152
|
+
buildRationalQuadraticEdgeForOCCT(
|
|
21153
|
+
oc,
|
|
21154
|
+
[
|
|
21155
|
+
[radius, 0, 0],
|
|
21156
|
+
[radius, 0, -heightRadius],
|
|
21157
|
+
[0, 0, -heightRadius]
|
|
21158
|
+
],
|
|
21159
|
+
[1, w2, 1]
|
|
21160
|
+
)
|
|
21161
|
+
);
|
|
21162
|
+
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());
|
|
21163
|
+
const face = buildFaceFromWire(oc, mkWire.Wire());
|
|
21164
|
+
const axis = new oc.gp_Ax1_2(new oc.gp_Pnt_3(0, 0, 0), new oc.gp_Dir_4(0, 0, 1));
|
|
21165
|
+
const revol = new oc.BRepPrimAPI_MakeRevol_1(face, axis, Math.PI * 2, true);
|
|
21166
|
+
revol.Build(new oc.Message_ProgressRange_1());
|
|
21167
|
+
if (!revol.IsDone()) {
|
|
21168
|
+
throw new Error("Shape.fromSlices exact ellipsoid revolve failed");
|
|
21169
|
+
}
|
|
21170
|
+
return revol.Shape();
|
|
21171
|
+
}
|
|
21172
|
+
function lowerOrthogonalEllipseFromSlicesPlan(oc, plan) {
|
|
21173
|
+
if (plan.groups.length !== 2) return null;
|
|
21174
|
+
const center = [0, 0, 0];
|
|
21175
|
+
const radii = [null, null, null];
|
|
21176
|
+
for (const group of plan.groups) {
|
|
21177
|
+
if (group.slices.length !== 1) return null;
|
|
21178
|
+
const slice = group.slices[0];
|
|
21179
|
+
const profileRadii = centeredEllipseProfileRadiiForOCCT(slice.profile);
|
|
21180
|
+
if (!profileRadii) return null;
|
|
21181
|
+
const frame = fromSlicesPlaneFrameForOCCT(group.normal);
|
|
21182
|
+
const normalAxis = axisAlignedDirectionForOCCT(frame.normal);
|
|
21183
|
+
const uAxis = axisAlignedDirectionForOCCT(frame.u);
|
|
21184
|
+
const vAxis = axisAlignedDirectionForOCCT(frame.v);
|
|
21185
|
+
if (!normalAxis || !uAxis || !vAxis) return null;
|
|
21186
|
+
center[normalAxis.axis] = normalAxis.sign * slice.offset;
|
|
21187
|
+
if (!setEllipsoidRadiusForOCCT(radii, uAxis.axis, profileRadii[0])) return null;
|
|
21188
|
+
if (!setEllipsoidRadiusForOCCT(radii, vAxis.axis, profileRadii[1])) return null;
|
|
21189
|
+
}
|
|
21190
|
+
if (radii.some((radius) => radius == null)) return null;
|
|
21191
|
+
const rx = radii[0];
|
|
21192
|
+
const ry = radii[1];
|
|
21193
|
+
const rz = radii[2];
|
|
21194
|
+
const axisymmetricTolerance = Math.max(1e-7, Math.max(Math.abs(rx), Math.abs(ry)) * 1e-7);
|
|
21195
|
+
if (Math.abs(rx - ry) > axisymmetricTolerance) return null;
|
|
21196
|
+
let shape = lowerAxisymmetricEllipsoidForOCCT(oc, (rx + ry) / 2, rz);
|
|
21197
|
+
if (Math.hypot(center[0], center[1], center[2]) > 1e-10) {
|
|
21198
|
+
const trsf = new oc.gp_Trsf_1();
|
|
21199
|
+
trsf.SetTranslation_1(new oc.gp_Vec_4(center[0], center[1], center[2]));
|
|
21200
|
+
const moved = new oc.BRepBuilderAPI_Transform_2(shape, trsf, true);
|
|
21201
|
+
shape = moved.Shape();
|
|
21202
|
+
}
|
|
21203
|
+
return shape;
|
|
21204
|
+
}
|
|
20611
21205
|
function lowerFromSlicesGroup(oc, group, singleSliceHalfExtent) {
|
|
20612
21206
|
const { normal, slices } = group;
|
|
20613
21207
|
const sorted = [...slices].sort((a2, b) => a2.offset - b.offset);
|
|
20614
|
-
const
|
|
21208
|
+
const localToWorldTrsf = buildFromSlicesLocalToWorldTransform(oc, normal);
|
|
20615
21209
|
if (sorted.length === 1) {
|
|
20616
21210
|
const s = sorted[0];
|
|
20617
21211
|
const rawFace = lowerProfileToFace(oc, s.profile);
|
|
@@ -20625,7 +21219,7 @@ function lowerFromSlicesGroup(oc, group, singleSliceHalfExtent) {
|
|
|
20625
21219
|
centerTrsf.SetTranslation_1(new oc.gp_Vec_4(0, 0, s.offset - extrudeHalf));
|
|
20626
21220
|
const centered = new oc.BRepBuilderAPI_Transform_2(shape, centerTrsf, true);
|
|
20627
21221
|
shape = centered.Shape();
|
|
20628
|
-
const rotated = new oc.BRepBuilderAPI_Transform_2(shape,
|
|
21222
|
+
const rotated = new oc.BRepBuilderAPI_Transform_2(shape, localToWorldTrsf, true);
|
|
20629
21223
|
return rotated.Shape();
|
|
20630
21224
|
}
|
|
20631
21225
|
const ts = new oc.BRepOffsetAPI_ThruSections(true, false, 1e-6);
|
|
@@ -20636,10 +21230,8 @@ function lowerFromSlicesGroup(oc, group, singleSliceHalfExtent) {
|
|
|
20636
21230
|
wire = toBSplineWireIfNeeded(oc, wire);
|
|
20637
21231
|
const placeTrsf = new oc.gp_Trsf_1();
|
|
20638
21232
|
placeTrsf.SetTranslation_1(new oc.gp_Vec_4(0, 0, s.offset));
|
|
20639
|
-
const
|
|
20640
|
-
|
|
20641
|
-
compound.Multiply(placeTrsf);
|
|
20642
|
-
const transformed = new oc.BRepBuilderAPI_Transform_2(wire, compound, true);
|
|
21233
|
+
const placed = new oc.BRepBuilderAPI_Transform_2(wire, placeTrsf, true);
|
|
21234
|
+
const transformed = new oc.BRepBuilderAPI_Transform_2(placed.Shape(), localToWorldTrsf, true);
|
|
20643
21235
|
ts.AddWire(oc.TopoDS.Wire_1(transformed.Shape()));
|
|
20644
21236
|
}
|
|
20645
21237
|
ts.CheckCompatibility(true);
|
|
@@ -20651,6 +21243,8 @@ function lowerFromSlicesGroup(oc, group, singleSliceHalfExtent) {
|
|
|
20651
21243
|
}
|
|
20652
21244
|
function lowerFromSlicesPlan$1(oc, plan) {
|
|
20653
21245
|
if (plan.groups.length === 0) throw new Error("Shape.fromSlices requires at least one slice");
|
|
21246
|
+
const exactEllipsoid = lowerOrthogonalEllipseFromSlicesPlan(oc, plan);
|
|
21247
|
+
if (exactEllipsoid) return exactEllipsoid;
|
|
20654
21248
|
const singleSliceHalfExtent = fromSlicesSingleSliceHalfExtentForOCCT(plan);
|
|
20655
21249
|
const groupSolids = plan.groups.map((g2) => lowerFromSlicesGroup(oc, g2, singleSliceHalfExtent));
|
|
20656
21250
|
if (groupSolids.length === 1) return groupSolids[0];
|
|
@@ -20677,14 +21271,40 @@ function buildPolylineSpineWire(oc, points) {
|
|
|
20677
21271
|
}
|
|
20678
21272
|
return mkWire.Wire();
|
|
20679
21273
|
}
|
|
21274
|
+
function buildRoute3DSpineWire(oc, path) {
|
|
21275
|
+
if (path.segments.length === 0) throw new Error("Route3D sweep path needs at least one segment");
|
|
21276
|
+
const mkWire = new oc.BRepBuilderAPI_MakeWire_1();
|
|
21277
|
+
for (const segment of path.segments) {
|
|
21278
|
+
if (segment.kind === "line") {
|
|
21279
|
+
const [x1, y1, z1] = segment.from;
|
|
21280
|
+
const [x2, y2, z2] = segment.to;
|
|
21281
|
+
if (x1 === x2 && y1 === y2 && z1 === z2) continue;
|
|
21282
|
+
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());
|
|
21283
|
+
continue;
|
|
21284
|
+
}
|
|
21285
|
+
const radial = normalizeVec3$1(subtractVec3(segment.start, segment.center));
|
|
21286
|
+
if (!radial) throw new Error("Route3D sweep arc has a collapsed start radius");
|
|
21287
|
+
const axis = new oc.gp_Ax2_2(
|
|
21288
|
+
new oc.gp_Pnt_3(segment.center[0], segment.center[1], segment.center[2]),
|
|
21289
|
+
new oc.gp_Dir_4(segment.axis[0], segment.axis[1], segment.axis[2]),
|
|
21290
|
+
new oc.gp_Dir_4(radial[0], radial[1], radial[2])
|
|
21291
|
+
);
|
|
21292
|
+
const circle = new oc.gp_Circ_2(axis, segment.radius);
|
|
21293
|
+
mkWire.Add_1(new oc.BRepBuilderAPI_MakeEdge_9(circle, 0, segment.sweepDeg * Math.PI / 180).Edge());
|
|
21294
|
+
}
|
|
21295
|
+
return mkWire.Wire();
|
|
21296
|
+
}
|
|
20680
21297
|
function buildSpineWireFromPlan(oc, path, pathSamples) {
|
|
20681
21298
|
switch (path.kind) {
|
|
20682
21299
|
case "polyline":
|
|
20683
21300
|
return buildPolylineSpineWire(oc, path.points);
|
|
21301
|
+
case "route3d":
|
|
21302
|
+
return buildRoute3DSpineWire(oc, path);
|
|
21303
|
+
case "nurbs":
|
|
21304
|
+
return new oc.BRepBuilderAPI_MakeWire_2(buildCurveEdgeFromSweepPathPlan(oc, path, "OCCT sweep path")).Wire();
|
|
20684
21305
|
case "catmull-rom":
|
|
20685
21306
|
case "hermite":
|
|
20686
21307
|
case "quintic-hermite":
|
|
20687
|
-
case "nurbs":
|
|
20688
21308
|
return buildPolylineSpineWire(oc, sweepPathToPolyline(path, pathSamples ?? 48));
|
|
20689
21309
|
}
|
|
20690
21310
|
}
|
|
@@ -28541,7 +29161,7 @@ async function initTruckGeometryWasm() {
|
|
|
28541
29161
|
if (_initPromise) return _initPromise;
|
|
28542
29162
|
_initPromise = (async () => {
|
|
28543
29163
|
try {
|
|
28544
|
-
const geometryModule = await import("./forgecad_geometry-
|
|
29164
|
+
const geometryModule = await import("./forgecad_geometry-Dgceylq9.js");
|
|
28545
29165
|
const isNode = isNodeRuntime();
|
|
28546
29166
|
if (isNode) {
|
|
28547
29167
|
const { readFileSync, existsSync } = await import("./__vite-browser-external-Dhvy_jtL.js");
|
|
@@ -31348,7 +31968,7 @@ function nurbsSurfaceForPlan(plan) {
|
|
|
31348
31968
|
return null;
|
|
31349
31969
|
}
|
|
31350
31970
|
function lowerImportedMeshPlan(plan) {
|
|
31351
|
-
const parsed = parseMeshFile(plan.fileData, plan.format);
|
|
31971
|
+
const parsed = parseMeshFile(plan.fileData, plan.format, { object: plan.object });
|
|
31352
31972
|
if (parsed.numProp !== 3) {
|
|
31353
31973
|
throw new Error(`importMesh("${plan.filePath}"): expected xyz vertex data`);
|
|
31354
31974
|
}
|
|
@@ -31651,12 +32271,18 @@ function applyNativeTruckFilletTargets(initialShape, targets, radius, segments,
|
|
|
31651
32271
|
}
|
|
31652
32272
|
}
|
|
31653
32273
|
function lowerFilletEdgesPlan(plan) {
|
|
32274
|
+
if (plan.edgeQuery) {
|
|
32275
|
+
throw new Error("filletEdges(): deferred edge queries are not supported by the Truck lowerer yet.");
|
|
32276
|
+
}
|
|
31654
32277
|
const shape = lowerShapeCompilePlanToTruckBackend(plan.base);
|
|
31655
|
-
return applyNativeTruckFilletTargets(shape, plan.edgeTargets, plan.radius, plan.segments, "filletEdges()");
|
|
32278
|
+
return applyNativeTruckFilletTargets(shape, plan.edgeTargets ?? [], plan.radius, plan.segments, "filletEdges()");
|
|
31656
32279
|
}
|
|
31657
32280
|
function lowerChamferEdgesPlan(plan) {
|
|
32281
|
+
if (plan.edgeQuery) {
|
|
32282
|
+
throw new Error("chamferEdges(): deferred edge queries are not supported by the Truck lowerer yet.");
|
|
32283
|
+
}
|
|
31658
32284
|
const shape = lowerShapeCompilePlanToTruckBackend(plan.base);
|
|
31659
|
-
return applyNativeTruckChamferTargets(shape, plan.edgeTargets, plan.size, "chamferEdges()");
|
|
32285
|
+
return applyNativeTruckChamferTargets(shape, plan.edgeTargets ?? [], plan.size, "chamferEdges()");
|
|
31660
32286
|
}
|
|
31661
32287
|
function resolvedEdgeFeatureSelectionToTarget(selection) {
|
|
31662
32288
|
return {
|
|
@@ -37673,8 +38299,8 @@ function resolveShapeFace(plan, name) {
|
|
|
37673
38299
|
const DEPRECATED_SIDE_NAMES = {
|
|
37674
38300
|
"side-left": "left",
|
|
37675
38301
|
"side-right": "right",
|
|
37676
|
-
"side-top": "
|
|
37677
|
-
"side-bottom": "
|
|
38302
|
+
"side-top": "back",
|
|
38303
|
+
"side-bottom": "front"
|
|
37678
38304
|
};
|
|
37679
38305
|
function explainMissingShapeFace(plan, name) {
|
|
37680
38306
|
const table = resolveShapeFaceTable(plan);
|
|
@@ -38599,11 +39225,14 @@ class ShapeGroup {
|
|
|
38599
39225
|
}
|
|
38600
39226
|
/** Move the entire group by (x, y, z). All children move together as a unit. */
|
|
38601
39227
|
translate(x2, y2, z2) {
|
|
38602
|
-
const
|
|
39228
|
+
const dx = requireFiniteNumber(x2, "ShapeGroup.translate() x");
|
|
39229
|
+
const dy = requireFiniteNumber(y2, "ShapeGroup.translate() y");
|
|
39230
|
+
const dz = requireFiniteNumber(z2, "ShapeGroup.translate() z");
|
|
39231
|
+
const matrix = Transform.translation(dx, dy, dz).toArray();
|
|
38603
39232
|
return this.mapChildrenTransform((c2) => {
|
|
38604
|
-
if (c2 instanceof ShapeGroup) return c2.translate(
|
|
38605
|
-
if (c2 instanceof Shape) return c2.translate(
|
|
38606
|
-
return c2.translate(
|
|
39233
|
+
if (c2 instanceof ShapeGroup) return c2.translate(dx, dy, dz);
|
|
39234
|
+
if (c2 instanceof Shape) return c2.translate(dx, dy, dz);
|
|
39235
|
+
return c2.translate(dx, dy);
|
|
38607
39236
|
}, matrix);
|
|
38608
39237
|
}
|
|
38609
39238
|
/** Compute combined bounding box of all 3D children */
|
|
@@ -38639,17 +39268,23 @@ class ShapeGroup {
|
|
|
38639
39268
|
return { min: bb.min, max: bb.max };
|
|
38640
39269
|
}
|
|
38641
39270
|
resolveRotatePoint(point) {
|
|
38642
|
-
if (Array.isArray(point)) return
|
|
39271
|
+
if (Array.isArray(point)) return requireFiniteVec3$1(point, "ShapeGroup.rotateAroundTo() point");
|
|
38643
39272
|
const bb = this._bbox();
|
|
38644
39273
|
return resolveAnchor3D(bb.min, bb.max, point);
|
|
38645
39274
|
}
|
|
38646
39275
|
/** Move the group so its bounding-box min corner lands at the given coordinate. */
|
|
38647
39276
|
moveTo(x2, y2, z2) {
|
|
39277
|
+
const targetX = requireFiniteNumber(x2, "ShapeGroup.moveTo() x");
|
|
39278
|
+
const targetY = requireFiniteNumber(y2, "ShapeGroup.moveTo() y");
|
|
39279
|
+
const targetZ = requireFiniteNumber(z2, "ShapeGroup.moveTo() z");
|
|
38648
39280
|
const bb = this._bbox();
|
|
38649
|
-
return this.translate(
|
|
39281
|
+
return this.translate(targetX - bb.min[0], targetY - bb.min[1], targetZ - bb.min[2]);
|
|
38650
39282
|
}
|
|
38651
39283
|
/** Move the group relative to another part's bounding-box min corner. */
|
|
38652
39284
|
moveToLocal(target, x2, y2, z2) {
|
|
39285
|
+
const localX = requireFiniteNumber(x2, "ShapeGroup.moveToLocal() x");
|
|
39286
|
+
const localY = requireFiniteNumber(y2, "ShapeGroup.moveToLocal() y");
|
|
39287
|
+
const localZ = requireFiniteNumber(z2, "ShapeGroup.moveToLocal() z");
|
|
38653
39288
|
let tbb;
|
|
38654
39289
|
if (target instanceof ShapeGroup) {
|
|
38655
39290
|
tbb = target._bbox();
|
|
@@ -38657,7 +39292,7 @@ class ShapeGroup {
|
|
|
38657
39292
|
const bb = target.boundingBox();
|
|
38658
39293
|
tbb = { min: bb.min };
|
|
38659
39294
|
}
|
|
38660
|
-
return this.moveTo(tbb.min[0] +
|
|
39295
|
+
return this.moveTo(tbb.min[0] + localX, tbb.min[1] + localY, tbb.min[2] + localZ);
|
|
38661
39296
|
}
|
|
38662
39297
|
/**
|
|
38663
39298
|
* Attach this group to a face or anchor on another part.
|
|
@@ -38686,9 +39321,10 @@ class ShapeGroup {
|
|
|
38686
39321
|
const sp = resolveAnchor3D(sbb.min, sbb.max, selfAnchor);
|
|
38687
39322
|
let dx = tp[0] - sp[0], dy = tp[1] - sp[1], dz = tp[2] - sp[2];
|
|
38688
39323
|
if (offset) {
|
|
38689
|
-
|
|
38690
|
-
|
|
38691
|
-
|
|
39324
|
+
const offsetPoint = requireFiniteVec3$1(offset, "ShapeGroup.attachTo() offset");
|
|
39325
|
+
dx += offsetPoint[0];
|
|
39326
|
+
dy += offsetPoint[1];
|
|
39327
|
+
dz += offsetPoint[2];
|
|
38692
39328
|
}
|
|
38693
39329
|
return this.translate(dx, dy, dz);
|
|
38694
39330
|
}
|
|
@@ -38697,7 +39333,9 @@ class ShapeGroup {
|
|
|
38697
39333
|
* See Shape.onFace() for full documentation.
|
|
38698
39334
|
*/
|
|
38699
39335
|
onFace(parent, face, opts = {}) {
|
|
38700
|
-
const u2 = opts.u ?? 0,
|
|
39336
|
+
const u2 = requireFiniteNumber(opts.u ?? 0, "ShapeGroup.onFace() u");
|
|
39337
|
+
const v = requireFiniteNumber(opts.v ?? 0, "ShapeGroup.onFace() v");
|
|
39338
|
+
const p2 = requireFiniteNumber(opts.protrude ?? 0, "ShapeGroup.onFace() protrude");
|
|
38701
39339
|
const opp = { front: "back", back: "front", left: "right", right: "left", top: "bottom", bottom: "top" };
|
|
38702
39340
|
const uvMap = {
|
|
38703
39341
|
front: (u22, v2, p22) => [u22, -p22, v2],
|
|
@@ -38736,20 +39374,31 @@ class ShapeGroup {
|
|
|
38736
39374
|
}
|
|
38737
39375
|
/** Rotate around an arbitrary axis, optionally through a pivot point. */
|
|
38738
39376
|
rotateAroundAxis(axis, angleDeg, pivot = [0, 0, 0]) {
|
|
38739
|
-
|
|
39377
|
+
const rotateAxis = requireNonZeroFiniteVec3(axis, "ShapeGroup.rotateAroundAxis() axis");
|
|
39378
|
+
const degrees = requireFiniteNumber(angleDeg, "ShapeGroup.rotateAroundAxis() angleDeg");
|
|
39379
|
+
const rotatePivot = requireFiniteVec3$1(pivot, "ShapeGroup.rotateAroundAxis() pivot");
|
|
39380
|
+
return this.transform(Transform.rotationAxis(rotateAxis, degrees, rotatePivot));
|
|
38740
39381
|
}
|
|
38741
39382
|
/**
|
|
38742
39383
|
* Rotate around an axis until a moving point reaches the target line/plane defined by the axis and target point.
|
|
38743
39384
|
* ShapeGroup string points use built-in anchors only.
|
|
38744
39385
|
*/
|
|
38745
39386
|
rotateAroundTo(axis, pivot, movingPoint, targetPoint, options = {}) {
|
|
39387
|
+
const rotateAxis = requireNonZeroFiniteVec3(axis, "ShapeGroup.rotateAroundTo() axis");
|
|
39388
|
+
const rotatePivot = requireFiniteVec3$1(pivot, "ShapeGroup.rotateAroundTo() pivot");
|
|
38746
39389
|
return this.transform(
|
|
38747
|
-
Transform.rotateAroundTo(
|
|
39390
|
+
Transform.rotateAroundTo(
|
|
39391
|
+
rotateAxis,
|
|
39392
|
+
rotatePivot,
|
|
39393
|
+
this.resolveRotatePoint(movingPoint),
|
|
39394
|
+
this.resolveRotatePoint(targetPoint),
|
|
39395
|
+
options
|
|
39396
|
+
)
|
|
38748
39397
|
);
|
|
38749
39398
|
}
|
|
38750
39399
|
/** Reorient the group so its local Z axis points along `direction`. */
|
|
38751
39400
|
pointAlong(direction) {
|
|
38752
|
-
const [dx, dy, dz] = direction;
|
|
39401
|
+
const [dx, dy, dz] = requireNonZeroFiniteVec3(direction, "ShapeGroup.pointAlong() direction");
|
|
38753
39402
|
const len = Math.sqrt(dx * dx + dy * dy + dz * dz) || 1;
|
|
38754
39403
|
const nx = dx / len, ny = dy / len, nz = dz / len;
|
|
38755
39404
|
const cx = -ny, cy = nx, cz = 0;
|
|
@@ -38764,11 +39413,11 @@ class ShapeGroup {
|
|
|
38764
39413
|
}
|
|
38765
39414
|
/** Apply a 4x4 transform matrix or `Transform` to all 3D children. */
|
|
38766
39415
|
transform(m2) {
|
|
38767
|
-
const matrix = m2 instanceof Transform ? m2.toArray() : m2;
|
|
39416
|
+
const matrix = m2 instanceof Transform ? m2.toArray() : requireFiniteMat4(m2, "ShapeGroup.transform() matrix");
|
|
38768
39417
|
const next = new ShapeGroup(
|
|
38769
39418
|
this.children.map((c2) => {
|
|
38770
|
-
if (c2 instanceof ShapeGroup) return c2.transform(
|
|
38771
|
-
if (c2 instanceof Shape) return c2.transform(
|
|
39419
|
+
if (c2 instanceof ShapeGroup) return c2.transform(matrix);
|
|
39420
|
+
if (c2 instanceof Shape) return c2.transform(matrix);
|
|
38772
39421
|
throw new Error(
|
|
38773
39422
|
"ShapeGroup.transform only supports 3D children (Shape/ShapeGroup). For Sketch children, use 2D transforms (translate/rotate/scale/mirror)."
|
|
38774
39423
|
);
|
|
@@ -38781,25 +39430,28 @@ class ShapeGroup {
|
|
|
38781
39430
|
}
|
|
38782
39431
|
/** Scale uniformly or per-axis from the group's bounding-box center. */
|
|
38783
39432
|
scale(v) {
|
|
38784
|
-
|
|
39433
|
+
const scale2 = requireNonZeroFiniteScale3(v, "ShapeGroup.scale() scale");
|
|
39434
|
+
return this.scaleAround(this._bboxCenter(), scale2);
|
|
38785
39435
|
}
|
|
38786
39436
|
/** Scale uniformly or per-axis from an explicit pivot point. */
|
|
38787
39437
|
scaleAround(pivot, v) {
|
|
38788
|
-
const
|
|
38789
|
-
|
|
39438
|
+
const scale2 = requireNonZeroFiniteScale3(v, "ShapeGroup.scaleAround() scale");
|
|
39439
|
+
const scalePivot = requireFiniteVec3$1(pivot, "ShapeGroup.scaleAround() pivot");
|
|
39440
|
+
const matrix = Transform.scale(scale2).toArray();
|
|
39441
|
+
if (scalePivot[0] === 0 && scalePivot[1] === 0 && scalePivot[2] === 0) {
|
|
38790
39442
|
return this.mapChildrenTransform((c2) => {
|
|
38791
|
-
if (c2 instanceof ShapeGroup) return c2.scaleAround([0, 0, 0],
|
|
38792
|
-
if (c2 instanceof Shape) return c2.scaleAround([0, 0, 0],
|
|
38793
|
-
return c2.scale(
|
|
39443
|
+
if (c2 instanceof ShapeGroup) return c2.scaleAround([0, 0, 0], scale2);
|
|
39444
|
+
if (c2 instanceof Shape) return c2.scaleAround([0, 0, 0], scale2);
|
|
39445
|
+
return c2.scale([scale2[0], scale2[1]]);
|
|
38794
39446
|
}, matrix);
|
|
38795
39447
|
}
|
|
38796
|
-
const moved = this.translate(-
|
|
39448
|
+
const moved = this.translate(-scalePivot[0], -scalePivot[1], -scalePivot[2]);
|
|
38797
39449
|
const scaled = moved.mapChildrenTransform((c2) => {
|
|
38798
|
-
if (c2 instanceof ShapeGroup) return c2.scaleAround([0, 0, 0],
|
|
38799
|
-
if (c2 instanceof Shape) return c2.scaleAround([0, 0, 0],
|
|
38800
|
-
return c2.scale(
|
|
39450
|
+
if (c2 instanceof ShapeGroup) return c2.scaleAround([0, 0, 0], scale2);
|
|
39451
|
+
if (c2 instanceof Shape) return c2.scaleAround([0, 0, 0], scale2);
|
|
39452
|
+
return c2.scale([scale2[0], scale2[1]]);
|
|
38801
39453
|
}, matrix);
|
|
38802
|
-
return scaled.translate(
|
|
39454
|
+
return scaled.translate(scalePivot[0], scalePivot[1], scalePivot[2]);
|
|
38803
39455
|
}
|
|
38804
39456
|
/** Mirror across a plane through the group's bounding-box center. */
|
|
38805
39457
|
mirror(normal) {
|
|
@@ -38807,21 +39459,23 @@ class ShapeGroup {
|
|
|
38807
39459
|
}
|
|
38808
39460
|
/** Mirror across a plane through an explicit point. */
|
|
38809
39461
|
mirrorThrough(point, normal) {
|
|
38810
|
-
const
|
|
38811
|
-
|
|
39462
|
+
const mirrorPoint = requireFiniteVec3$1(point, "ShapeGroup.mirrorThrough() point");
|
|
39463
|
+
const mirrorNormal = requireNonZeroFiniteVec3(normal, "ShapeGroup.mirrorThrough() normal");
|
|
39464
|
+
const matrix = mirrorPlaneMatrix(mirrorNormal);
|
|
39465
|
+
if (mirrorPoint[0] === 0 && mirrorPoint[1] === 0 && mirrorPoint[2] === 0) {
|
|
38812
39466
|
return this.mapChildrenTransform((c2) => {
|
|
38813
|
-
if (c2 instanceof ShapeGroup) return c2.mirrorThrough([0, 0, 0],
|
|
38814
|
-
if (c2 instanceof Shape) return c2.mirrorThrough([0, 0, 0],
|
|
38815
|
-
return c2.mirror([
|
|
39467
|
+
if (c2 instanceof ShapeGroup) return c2.mirrorThrough([0, 0, 0], mirrorNormal);
|
|
39468
|
+
if (c2 instanceof Shape) return c2.mirrorThrough([0, 0, 0], mirrorNormal);
|
|
39469
|
+
return c2.mirror([mirrorNormal[0], mirrorNormal[1]]);
|
|
38816
39470
|
}, matrix);
|
|
38817
39471
|
}
|
|
38818
|
-
const moved = this.translate(-
|
|
39472
|
+
const moved = this.translate(-mirrorPoint[0], -mirrorPoint[1], -mirrorPoint[2]);
|
|
38819
39473
|
const mirrored = moved.mapChildrenTransform((c2) => {
|
|
38820
|
-
if (c2 instanceof ShapeGroup) return c2.mirrorThrough([0, 0, 0],
|
|
38821
|
-
if (c2 instanceof Shape) return c2.mirrorThrough([0, 0, 0],
|
|
38822
|
-
return c2.mirror([
|
|
39474
|
+
if (c2 instanceof ShapeGroup) return c2.mirrorThrough([0, 0, 0], mirrorNormal);
|
|
39475
|
+
if (c2 instanceof Shape) return c2.mirrorThrough([0, 0, 0], mirrorNormal);
|
|
39476
|
+
return c2.mirror([mirrorNormal[0], mirrorNormal[1]]);
|
|
38823
39477
|
}, matrix);
|
|
38824
|
-
return mirrored.translate(
|
|
39478
|
+
return mirrored.translate(mirrorPoint[0], mirrorPoint[1], mirrorPoint[2]);
|
|
38825
39479
|
}
|
|
38826
39480
|
/** Return a copy of the group with the given display color applied to each child. */
|
|
38827
39481
|
color(hex) {
|
|
@@ -38893,14 +39547,16 @@ class ShapeGroup {
|
|
|
38893
39547
|
* ```
|
|
38894
39548
|
*/
|
|
38895
39549
|
placeReference(ref, target, offset) {
|
|
39550
|
+
const targetPoint = requireFiniteVec3$1(target, "ShapeGroup.placeReference() target");
|
|
39551
|
+
const offsetPoint = offset === void 0 ? void 0 : requireFiniteVec3$1(offset, "ShapeGroup.placeReference() offset");
|
|
38896
39552
|
const sourcePoint = this.referencePoint(ref);
|
|
38897
|
-
let dx =
|
|
38898
|
-
let dy =
|
|
38899
|
-
let dz =
|
|
38900
|
-
if (
|
|
38901
|
-
dx +=
|
|
38902
|
-
dy +=
|
|
38903
|
-
dz +=
|
|
39553
|
+
let dx = targetPoint[0] - sourcePoint[0];
|
|
39554
|
+
let dy = targetPoint[1] - sourcePoint[1];
|
|
39555
|
+
let dz = targetPoint[2] - sourcePoint[2];
|
|
39556
|
+
if (offsetPoint) {
|
|
39557
|
+
dx += offsetPoint[0];
|
|
39558
|
+
dy += offsetPoint[1];
|
|
39559
|
+
dz += offsetPoint[2];
|
|
38904
39560
|
}
|
|
38905
39561
|
return this.translate(dx, dy, dz);
|
|
38906
39562
|
}
|
|
@@ -39832,14 +40488,21 @@ function attachTopologyRewritePropagation(plan, propagation) {
|
|
|
39832
40488
|
}
|
|
39833
40489
|
return cloneNodeWithPropagation(plan, propagation);
|
|
39834
40490
|
}
|
|
40491
|
+
const DEFERRED_EDGE_SELECTION_MARKER = Symbol.for("forgecad.deferredEdgeSelection");
|
|
40492
|
+
function isDeferredEdgeSelection(value) {
|
|
40493
|
+
return Boolean(value && typeof value === "object" && value[DEFERRED_EDGE_SELECTION_MARKER] === true);
|
|
40494
|
+
}
|
|
39835
40495
|
function distSq(a2, b) {
|
|
39836
|
-
const dx = a2[0] - b[0]
|
|
40496
|
+
const dx = a2[0] - b[0];
|
|
40497
|
+
const dy = a2[1] - b[1];
|
|
40498
|
+
const dz = a2[2] - b[2];
|
|
39837
40499
|
return dx * dx + dy * dy + dz * dz;
|
|
39838
40500
|
}
|
|
39839
40501
|
function absDot(a2, b) {
|
|
39840
40502
|
return Math.abs(a2[0] * b[0] + a2[1] * b[1] + a2[2] * b[2]);
|
|
39841
40503
|
}
|
|
39842
40504
|
function coalesceEdges(segments, tolerance = 0.01) {
|
|
40505
|
+
if (segments.some(isDeferredEdgeSelection)) return segments;
|
|
39843
40506
|
if (segments.length <= 1) return segments;
|
|
39844
40507
|
const used = new Uint8Array(segments.length);
|
|
39845
40508
|
const result = [];
|
|
@@ -40562,16 +41225,6 @@ function mirrorMatrix(normal) {
|
|
|
40562
41225
|
const m22 = 1 - 2 * nz * nz;
|
|
40563
41226
|
return [m00, m10, m20, 0, m01, m11, m21, 0, m02, m12, m22, 0, 0, 0, 0, 1];
|
|
40564
41227
|
}
|
|
40565
|
-
function normalizeShapeScale(v) {
|
|
40566
|
-
const scale2 = typeof v === "number" ? [v, v, v] : v;
|
|
40567
|
-
if (!Number.isFinite(scale2[0]) || !Number.isFinite(scale2[1]) || !Number.isFinite(scale2[2])) {
|
|
40568
|
-
return null;
|
|
40569
|
-
}
|
|
40570
|
-
if (Math.abs(scale2[0]) < 1e-12 || Math.abs(scale2[1]) < 1e-12 || Math.abs(scale2[2]) < 1e-12) {
|
|
40571
|
-
return null;
|
|
40572
|
-
}
|
|
40573
|
-
return [scale2[0], scale2[1], scale2[2]];
|
|
40574
|
-
}
|
|
40575
41228
|
function dotVec3$1(a2, b) {
|
|
40576
41229
|
return a2[0] * b[0] + a2[1] * b[1] + a2[2] * b[2];
|
|
40577
41230
|
}
|
|
@@ -41660,7 +42313,7 @@ function withBaseDimensionsAndMergedSourceSpans(base, sources, out, preserveOutp
|
|
|
41660
42313
|
return result;
|
|
41661
42314
|
}
|
|
41662
42315
|
function resolveRotationPoint(shape, point) {
|
|
41663
|
-
if (Array.isArray(point)) return
|
|
42316
|
+
if (Array.isArray(point)) return requireFiniteVec3$1(point, "rotateAroundTo(): point");
|
|
41664
42317
|
return shape.referencePoint(point);
|
|
41665
42318
|
}
|
|
41666
42319
|
function setShapePlacementReferences(shape, refs, options = {}) {
|
|
@@ -42388,7 +43041,9 @@ class Shape {
|
|
|
42388
43041
|
edgesOf(faceLabel, options) {
|
|
42389
43042
|
const faceRefs = this._resolveFaceLabels(faceLabel);
|
|
42390
43043
|
const result = uniqueEdgeSegments(
|
|
42391
|
-
faceRefs.flatMap((faceRef) =>
|
|
43044
|
+
faceRefs.flatMap((faceRef) => {
|
|
43045
|
+
return edgesOfFace(this, faceRef, options, (name) => this._resolveFaceLabel(name));
|
|
43046
|
+
})
|
|
42392
43047
|
);
|
|
42393
43048
|
if (result.length === 0) {
|
|
42394
43049
|
throw new Error(
|
|
@@ -42436,7 +43091,11 @@ class Shape {
|
|
|
42436
43091
|
const refsA = this._resolveFaceLabels(faceA);
|
|
42437
43092
|
const bNames = Array.isArray(faceB) ? faceB : [faceB];
|
|
42438
43093
|
const refBs = bNames.flatMap((name) => this._resolveFaceLabels(name));
|
|
42439
|
-
const result = uniqueEdgeSegments(
|
|
43094
|
+
const result = uniqueEdgeSegments(
|
|
43095
|
+
refsA.flatMap((refA) => {
|
|
43096
|
+
return edgesBetweenFaces(this, refA, refBs);
|
|
43097
|
+
})
|
|
43098
|
+
);
|
|
42440
43099
|
if (result.length === 0) {
|
|
42441
43100
|
const bStr = bNames.length === 1 ? `'${bNames[0]}'` : `[${bNames.map((n) => `'${n}'`).join(", ")}]`;
|
|
42442
43101
|
throw new Error(
|
|
@@ -42500,14 +43159,16 @@ class Shape {
|
|
|
42500
43159
|
* ```
|
|
42501
43160
|
*/
|
|
42502
43161
|
placeReference(ref, target, offset) {
|
|
43162
|
+
const targetPoint = requireFiniteVec3$1(target, "Shape.placeReference() target");
|
|
43163
|
+
const offsetPoint = offset === void 0 ? void 0 : requireFiniteVec3$1(offset, "Shape.placeReference() offset");
|
|
42503
43164
|
const sourcePoint = this.referencePoint(ref);
|
|
42504
|
-
let dx =
|
|
42505
|
-
let dy =
|
|
42506
|
-
let dz =
|
|
42507
|
-
if (
|
|
42508
|
-
dx +=
|
|
42509
|
-
dy +=
|
|
42510
|
-
dz +=
|
|
43165
|
+
let dx = targetPoint[0] - sourcePoint[0];
|
|
43166
|
+
let dy = targetPoint[1] - sourcePoint[1];
|
|
43167
|
+
let dz = targetPoint[2] - sourcePoint[2];
|
|
43168
|
+
if (offsetPoint) {
|
|
43169
|
+
dx += offsetPoint[0];
|
|
43170
|
+
dy += offsetPoint[1];
|
|
43171
|
+
dz += offsetPoint[2];
|
|
42511
43172
|
}
|
|
42512
43173
|
return this.translate(dx, dy, dz);
|
|
42513
43174
|
}
|
|
@@ -42519,27 +43180,39 @@ class Shape {
|
|
|
42519
43180
|
* Example: `shape.translatePolar(50, 30)` moves 50mm at 30 degrees from +X.
|
|
42520
43181
|
*/
|
|
42521
43182
|
translatePolar(radius, angleDeg, z2 = 0) {
|
|
42522
|
-
const
|
|
42523
|
-
|
|
43183
|
+
const r = requireFiniteNumber(radius, "Shape.translatePolar() radius");
|
|
43184
|
+
const angle = requireFiniteNumber(angleDeg, "Shape.translatePolar() angleDeg");
|
|
43185
|
+
const zOffset = requireFiniteNumber(z2, "Shape.translatePolar() z");
|
|
43186
|
+
const rad = angle * (Math.PI / 180);
|
|
43187
|
+
return this.translate(r * Math.cos(rad), r * Math.sin(rad), zOffset);
|
|
42524
43188
|
}
|
|
42525
43189
|
/** Move the shape relative to its current position. All transforms are immutable and return new shapes. */
|
|
42526
43190
|
translate(x2, y2, z2) {
|
|
42527
|
-
const
|
|
43191
|
+
const dx = requireFiniteNumber(x2, "Shape.translate() x");
|
|
43192
|
+
const dy = requireFiniteNumber(y2, "Shape.translate() y");
|
|
43193
|
+
const dz = requireFiniteNumber(z2, "Shape.translate() z");
|
|
43194
|
+
const nextPlan = appendShapeCompileTransform(getShapeCompilePlanInternal(this), { kind: "translate", x: dx, y: dy, z: dz });
|
|
42528
43195
|
return setShapeCompilePlanInternal(
|
|
42529
|
-
withTransformedDimensions(this, buildShapeFromCompilePlan(nextPlan, this.colorHex), Transform.translation(
|
|
43196
|
+
withTransformedDimensions(this, buildShapeFromCompilePlan(nextPlan, this.colorHex), Transform.translation(dx, dy, dz).toArray()),
|
|
42530
43197
|
nextPlan
|
|
42531
43198
|
);
|
|
42532
43199
|
}
|
|
42533
43200
|
/** Position the shape so its bounding box min corner is at the given global coordinate. */
|
|
42534
43201
|
moveTo(x2, y2, z2) {
|
|
43202
|
+
const targetX = requireFiniteNumber(x2, "Shape.moveTo() x");
|
|
43203
|
+
const targetY = requireFiniteNumber(y2, "Shape.moveTo() y");
|
|
43204
|
+
const targetZ = requireFiniteNumber(z2, "Shape.moveTo() z");
|
|
42535
43205
|
const bb = this.boundingBox();
|
|
42536
|
-
return this.translate(
|
|
43206
|
+
return this.translate(targetX - bb.min[0], targetY - bb.min[1], targetZ - bb.min[2]);
|
|
42537
43207
|
}
|
|
42538
43208
|
/** Position the shape relative to another shape's local coordinate system (bounding box min corner). */
|
|
42539
43209
|
moveToLocal(target, x2, y2, z2) {
|
|
43210
|
+
const localX = requireFiniteNumber(x2, "Shape.moveToLocal() x");
|
|
43211
|
+
const localY = requireFiniteNumber(y2, "Shape.moveToLocal() y");
|
|
43212
|
+
const localZ = requireFiniteNumber(z2, "Shape.moveToLocal() z");
|
|
42540
43213
|
const s = "toShape" in target ? target.toShape() : target;
|
|
42541
43214
|
const tbb = s.boundingBox();
|
|
42542
|
-
return this.moveTo(tbb.min[0] +
|
|
43215
|
+
return this.moveTo(tbb.min[0] + localX, tbb.min[1] + localY, tbb.min[2] + localZ);
|
|
42543
43216
|
}
|
|
42544
43217
|
/** Rotate around an arbitrary axis through the origin. */
|
|
42545
43218
|
rotate(axis, angleDeg, options) {
|
|
@@ -42568,7 +43241,7 @@ class Shape {
|
|
|
42568
43241
|
}
|
|
42569
43242
|
/** Apply a 4x4 affine transform matrix (column-major) or a Transform object. */
|
|
42570
43243
|
transform(m2) {
|
|
42571
|
-
const mat = m2 instanceof Transform ? m2.toArray() : m2;
|
|
43244
|
+
const mat = m2 instanceof Transform ? m2.toArray() : requireFiniteMat4(m2, "Shape.transform() matrix");
|
|
42572
43245
|
const steps = rigidTransformStepsFromMatrix(mat);
|
|
42573
43246
|
if (steps == null) {
|
|
42574
43247
|
throw new Error(
|
|
@@ -42580,23 +43253,20 @@ class Shape {
|
|
|
42580
43253
|
}
|
|
42581
43254
|
/** Scale the shape uniformly or per-axis from the shape's bounding box center. Accepts a single number or [x, y, z] array. */
|
|
42582
43255
|
scale(v) {
|
|
43256
|
+
const scale2 = requireNonZeroFiniteScale3(v, "Shape.scale() scale");
|
|
42583
43257
|
const bb = this.boundingBox();
|
|
42584
43258
|
const center = [
|
|
42585
43259
|
(bb.min[0] + bb.max[0]) / 2,
|
|
42586
43260
|
(bb.min[1] + bb.max[1]) / 2,
|
|
42587
43261
|
(bb.min[2] + bb.max[2]) / 2
|
|
42588
43262
|
];
|
|
42589
|
-
return this.scaleAround(center,
|
|
43263
|
+
return this.scaleAround(center, scale2);
|
|
42590
43264
|
}
|
|
42591
43265
|
/** Scale the shape uniformly or per-axis from an explicit pivot point. */
|
|
42592
43266
|
scaleAround(pivot, v) {
|
|
42593
|
-
const scale2 =
|
|
42594
|
-
|
|
42595
|
-
|
|
42596
|
-
`Shape.scaleAround() received a degenerate scale value (${JSON.stringify(v)}). All scale components must be finite and non-zero.`
|
|
42597
|
-
);
|
|
42598
|
-
}
|
|
42599
|
-
if (pivot[0] === 0 && pivot[1] === 0 && pivot[2] === 0) {
|
|
43267
|
+
const scale2 = requireNonZeroFiniteScale3(v, "Shape.scaleAround() scale");
|
|
43268
|
+
const scalePivot = requireFiniteVec3$1(pivot, "Shape.scaleAround() pivot");
|
|
43269
|
+
if (scalePivot[0] === 0 && scalePivot[1] === 0 && scalePivot[2] === 0) {
|
|
42600
43270
|
const nextPlan2 = appendShapeCompileTransform(getShapeCompilePlanInternal(this), {
|
|
42601
43271
|
kind: "scale",
|
|
42602
43272
|
x: scale2[0],
|
|
@@ -42604,11 +43274,11 @@ class Shape {
|
|
|
42604
43274
|
z: scale2[2]
|
|
42605
43275
|
});
|
|
42606
43276
|
return setShapeCompilePlanInternal(
|
|
42607
|
-
withTransformedDimensions(this, buildShapeFromCompilePlan(nextPlan2, this.colorHex), Transform.scale(
|
|
43277
|
+
withTransformedDimensions(this, buildShapeFromCompilePlan(nextPlan2, this.colorHex), Transform.scale(scale2).toArray()),
|
|
42608
43278
|
nextPlan2
|
|
42609
43279
|
);
|
|
42610
43280
|
}
|
|
42611
|
-
const translated = this.translate(-
|
|
43281
|
+
const translated = this.translate(-scalePivot[0], -scalePivot[1], -scalePivot[2]);
|
|
42612
43282
|
const nextPlan = appendShapeCompileTransform(getShapeCompilePlanInternal(translated), {
|
|
42613
43283
|
kind: "scale",
|
|
42614
43284
|
x: scale2[0],
|
|
@@ -42616,10 +43286,10 @@ class Shape {
|
|
|
42616
43286
|
z: scale2[2]
|
|
42617
43287
|
});
|
|
42618
43288
|
const scaled = setShapeCompilePlanInternal(
|
|
42619
|
-
withTransformedDimensions(translated, buildShapeFromCompilePlan(nextPlan, translated.colorHex), Transform.scale(
|
|
43289
|
+
withTransformedDimensions(translated, buildShapeFromCompilePlan(nextPlan, translated.colorHex), Transform.scale(scale2).toArray()),
|
|
42620
43290
|
nextPlan
|
|
42621
43291
|
);
|
|
42622
|
-
return scaled.translate(
|
|
43292
|
+
return scaled.translate(scalePivot[0], scalePivot[1], scalePivot[2]);
|
|
42623
43293
|
}
|
|
42624
43294
|
/** Mirror across a plane through the shape's bounding box center, defined by its normal vector. */
|
|
42625
43295
|
mirror(normal) {
|
|
@@ -42633,32 +43303,34 @@ class Shape {
|
|
|
42633
43303
|
}
|
|
42634
43304
|
/** Mirror across a plane through an explicit point, defined by its normal vector. */
|
|
42635
43305
|
mirrorThrough(point, normal) {
|
|
42636
|
-
|
|
43306
|
+
const mirrorPoint = requireFiniteVec3$1(point, "Shape.mirrorThrough() point");
|
|
43307
|
+
const mirrorNormal = requireNonZeroFiniteVec3(normal, "Shape.mirrorThrough() normal");
|
|
43308
|
+
if (mirrorPoint[0] === 0 && mirrorPoint[1] === 0 && mirrorPoint[2] === 0) {
|
|
42637
43309
|
const transformedPlan2 = appendShapeCompileTransform(getShapeCompilePlanInternal(this), {
|
|
42638
43310
|
kind: "mirror",
|
|
42639
|
-
normalX:
|
|
42640
|
-
normalY:
|
|
42641
|
-
normalZ:
|
|
43311
|
+
normalX: mirrorNormal[0],
|
|
43312
|
+
normalY: mirrorNormal[1],
|
|
43313
|
+
normalZ: mirrorNormal[2]
|
|
42642
43314
|
});
|
|
42643
43315
|
const nextPlan2 = wrapRepeatedShapeCompilePlan(transformedPlan2, "mirror");
|
|
42644
43316
|
return setShapeCompilePlanInternal(
|
|
42645
|
-
withTransformedDimensions(this, buildShapeFromCompilePlan(nextPlan2, this.colorHex), mirrorMatrix(
|
|
43317
|
+
withTransformedDimensions(this, buildShapeFromCompilePlan(nextPlan2, this.colorHex), mirrorMatrix(mirrorNormal)),
|
|
42646
43318
|
nextPlan2
|
|
42647
43319
|
);
|
|
42648
43320
|
}
|
|
42649
|
-
const translated = this.translate(-
|
|
43321
|
+
const translated = this.translate(-mirrorPoint[0], -mirrorPoint[1], -mirrorPoint[2]);
|
|
42650
43322
|
const transformedPlan = appendShapeCompileTransform(getShapeCompilePlanInternal(translated), {
|
|
42651
43323
|
kind: "mirror",
|
|
42652
|
-
normalX:
|
|
42653
|
-
normalY:
|
|
42654
|
-
normalZ:
|
|
43324
|
+
normalX: mirrorNormal[0],
|
|
43325
|
+
normalY: mirrorNormal[1],
|
|
43326
|
+
normalZ: mirrorNormal[2]
|
|
42655
43327
|
});
|
|
42656
43328
|
const nextPlan = wrapRepeatedShapeCompilePlan(transformedPlan, "mirror");
|
|
42657
43329
|
const mirrored = setShapeCompilePlanInternal(
|
|
42658
|
-
withTransformedDimensions(translated, buildShapeFromCompilePlan(nextPlan, translated.colorHex), mirrorMatrix(
|
|
43330
|
+
withTransformedDimensions(translated, buildShapeFromCompilePlan(nextPlan, translated.colorHex), mirrorMatrix(mirrorNormal)),
|
|
42659
43331
|
nextPlan
|
|
42660
43332
|
);
|
|
42661
|
-
return mirrored.translate(
|
|
43333
|
+
return mirrored.translate(mirrorPoint[0], mirrorPoint[1], mirrorPoint[2]);
|
|
42662
43334
|
}
|
|
42663
43335
|
/**
|
|
42664
43336
|
* Reorient a shape so its primary axis (Z) points along the given direction.
|
|
@@ -42668,7 +43340,7 @@ class Shape {
|
|
|
42668
43340
|
* Example: cylinder(40, 5).pointAlong([1, 0, 0]) — lays cylinder along X, starting at origin
|
|
42669
43341
|
*/
|
|
42670
43342
|
pointAlong(direction) {
|
|
42671
|
-
const [dx, dy, dz] = direction;
|
|
43343
|
+
const [dx, dy, dz] = requireNonZeroFiniteVec3(direction, "Shape.pointAlong() direction");
|
|
42672
43344
|
const len = Math.sqrt(dx * dx + dy * dy + dz * dz) || 1;
|
|
42673
43345
|
const nx = dx / len, ny = dy / len, nz = dz / len;
|
|
42674
43346
|
const cx = -ny, cy = nx, cz = 0;
|
|
@@ -42687,18 +43359,21 @@ class Shape {
|
|
|
42687
43359
|
* @internal Prefer rotate(), rotateX(), rotateY(), rotateZ() for public use.
|
|
42688
43360
|
*/
|
|
42689
43361
|
rotateAroundAxis(axis, angleDeg, pivot = [0, 0, 0]) {
|
|
42690
|
-
const
|
|
42691
|
-
const
|
|
42692
|
-
const
|
|
43362
|
+
const rotateAxis = requireNonZeroFiniteVec3(axis, "Shape.rotateAroundAxis() axis");
|
|
43363
|
+
const degrees = requireFiniteNumber(angleDeg, "Shape.rotateAroundAxis() angleDeg");
|
|
43364
|
+
const rotatePivot = requireFiniteVec3$1(pivot, "Shape.rotateAroundAxis() pivot");
|
|
43365
|
+
const len = Math.sqrt(rotateAxis[0] ** 2 + rotateAxis[1] ** 2 + rotateAxis[2] ** 2) || 1;
|
|
43366
|
+
const normalizedAxis = [rotateAxis[0] / len, rotateAxis[1] / len, rotateAxis[2] / len];
|
|
43367
|
+
const matrix = rotationAroundAxisMatrix(normalizedAxis, degrees, rotatePivot);
|
|
42693
43368
|
const nextPlan = appendShapeCompileTransform(getShapeCompilePlanInternal(this), {
|
|
42694
43369
|
kind: "rotateAround",
|
|
42695
43370
|
axisX: normalizedAxis[0],
|
|
42696
43371
|
axisY: normalizedAxis[1],
|
|
42697
43372
|
axisZ: normalizedAxis[2],
|
|
42698
|
-
degrees
|
|
42699
|
-
pivotX:
|
|
42700
|
-
pivotY:
|
|
42701
|
-
pivotZ:
|
|
43373
|
+
degrees,
|
|
43374
|
+
pivotX: rotatePivot[0],
|
|
43375
|
+
pivotY: rotatePivot[1],
|
|
43376
|
+
pivotZ: rotatePivot[2]
|
|
42702
43377
|
});
|
|
42703
43378
|
return setShapeCompilePlanInternal(
|
|
42704
43379
|
withTransformedDimensions(this, buildShapeFromCompilePlan(nextPlan, this.colorHex), matrix),
|
|
@@ -42710,10 +43385,12 @@ class Shape {
|
|
|
42710
43385
|
* `movingPoint` / `targetPoint` may be raw world points or this shape's anchors/references.
|
|
42711
43386
|
*/
|
|
42712
43387
|
rotateAroundTo(axis, pivot, movingPoint, targetPoint, options = {}) {
|
|
43388
|
+
const rotateAxis = requireNonZeroFiniteVec3(axis, "Shape.rotateAroundTo() axis");
|
|
43389
|
+
const rotatePivot = requireFiniteVec3$1(pivot, "Shape.rotateAroundTo() pivot");
|
|
42713
43390
|
const moving = resolveRotationPoint(this, movingPoint);
|
|
42714
43391
|
const target = resolveRotationPoint(this, targetPoint);
|
|
42715
|
-
const angleDeg = solveRotateAroundAngle(
|
|
42716
|
-
return this.rotateAroundAxis(
|
|
43392
|
+
const angleDeg = solveRotateAroundAngle(rotateAxis, rotatePivot, moving, target, options);
|
|
43393
|
+
return this.rotateAroundAxis(rotateAxis, angleDeg, rotatePivot);
|
|
42717
43394
|
}
|
|
42718
43395
|
// --- Booleans ---
|
|
42719
43396
|
/** Unwrap any object with toShape() without circular import. */
|
|
@@ -42877,17 +43554,19 @@ class Shape {
|
|
|
42877
43554
|
}
|
|
42878
43555
|
/** Split by infinite plane. Returns [positive-side, negative-side]. */
|
|
42879
43556
|
splitByPlane(normal, originOffset = 0) {
|
|
43557
|
+
const planeNormal = requireNonZeroFiniteVec3(normal, "Shape.splitByPlane() normal");
|
|
43558
|
+
const planeOffset = requireFiniteNumber(originOffset, "Shape.splitByPlane() originOffset");
|
|
42880
43559
|
const info = deriveGeometryInfo(getShapeGeometryInfoInternal(this), "boolean", {
|
|
42881
43560
|
topology: _activeBackend === "truck" ? "kernel" : "none"
|
|
42882
43561
|
});
|
|
42883
43562
|
const basePlan = getShapeCompilePlanInternal(this);
|
|
42884
43563
|
const firstPlan = createOwnedTopologyRewritePlan(
|
|
42885
|
-
buildTrimByPlaneShapeCompilePlan(basePlan,
|
|
43564
|
+
buildTrimByPlaneShapeCompilePlan(basePlan, planeNormal, planeOffset),
|
|
42886
43565
|
"splitByPlane:positive",
|
|
42887
43566
|
(owner) => buildTrimByPlaneTopologyRewritePropagation(owner, basePlan)
|
|
42888
43567
|
);
|
|
42889
43568
|
const secondPlan = createOwnedTopologyRewritePlan(
|
|
42890
|
-
buildTrimByPlaneShapeCompilePlan(basePlan, [-
|
|
43569
|
+
buildTrimByPlaneShapeCompilePlan(basePlan, [-planeNormal[0], -planeNormal[1], -planeNormal[2]], -planeOffset),
|
|
42891
43570
|
"splitByPlane:opposite",
|
|
42892
43571
|
(owner) => buildTrimByPlaneTopologyRewritePropagation(owner, basePlan)
|
|
42893
43572
|
);
|
|
@@ -42905,9 +43584,11 @@ class Shape {
|
|
|
42905
43584
|
}
|
|
42906
43585
|
/** Keep the positive side of the plane and discard the opposite side. */
|
|
42907
43586
|
trimByPlane(normal, originOffset = 0) {
|
|
43587
|
+
const planeNormal = requireNonZeroFiniteVec3(normal, "Shape.trimByPlane() normal");
|
|
43588
|
+
const planeOffset = requireFiniteNumber(originOffset, "Shape.trimByPlane() originOffset");
|
|
42908
43589
|
const basePlan = getShapeCompilePlanInternal(this);
|
|
42909
43590
|
const nextPlan = createOwnedTopologyRewritePlan(
|
|
42910
|
-
buildTrimByPlaneShapeCompilePlan(basePlan,
|
|
43591
|
+
buildTrimByPlaneShapeCompilePlan(basePlan, planeNormal, planeOffset),
|
|
42911
43592
|
"trimByPlane",
|
|
42912
43593
|
(owner) => buildTrimByPlaneTopologyRewritePropagation(owner, basePlan)
|
|
42913
43594
|
);
|
|
@@ -42927,8 +43608,9 @@ class Shape {
|
|
|
42927
43608
|
* `openFaces` names any subset of the base shape's labeled faces to leave open (no wall).
|
|
42928
43609
|
*/
|
|
42929
43610
|
shell(thickness, opts = {}) {
|
|
43611
|
+
const wallThickness = requirePositiveFiniteNumber(thickness, "Shape.shell() thickness");
|
|
42930
43612
|
const basePlan = getShapeCompilePlanInternal(this);
|
|
42931
|
-
const shellPlan = buildShellShapeCompilePlan(basePlan,
|
|
43613
|
+
const shellPlan = buildShellShapeCompilePlan(basePlan, wallThickness, opts.openFaces);
|
|
42932
43614
|
if (!shellPlan) {
|
|
42933
43615
|
throw new Error(
|
|
42934
43616
|
"Shape.shell() supports box(), cylinder(), straight extrude(), loft(), sweep(), and variableSweep() solids with optional face openings and rigid transforms."
|
|
@@ -42949,7 +43631,8 @@ class Shape {
|
|
|
42949
43631
|
}
|
|
42950
43632
|
/** Offset-thicken an exact open surface or shell into a solid. */
|
|
42951
43633
|
thicken(thickness) {
|
|
42952
|
-
|
|
43634
|
+
const wallThickness = requireFiniteNumber(thickness, "Shape.thicken() thickness");
|
|
43635
|
+
if (wallThickness === 0) {
|
|
42953
43636
|
throw new Error("Shape.thicken() requires a non-zero finite thickness.");
|
|
42954
43637
|
}
|
|
42955
43638
|
const info = getShapeGeometryInfoInternal(this);
|
|
@@ -42957,7 +43640,7 @@ class Shape {
|
|
|
42957
43640
|
throw new Error("Shape.thicken() is only available on surface-representation shapes.");
|
|
42958
43641
|
}
|
|
42959
43642
|
const basePlan = getShapeCompilePlanInternal(this);
|
|
42960
|
-
const nextPlan = buildSurfaceThickenShapeCompilePlan(basePlan,
|
|
43643
|
+
const nextPlan = buildSurfaceThickenShapeCompilePlan(basePlan, wallThickness);
|
|
42961
43644
|
const representation = info.backend === "occt" || info.backend === "truck" ? "brep-solid" : "mesh-solid";
|
|
42962
43645
|
return setShapeCompilePlanInternal(
|
|
42963
43646
|
setShapeGeometryInfoInternal(
|
|
@@ -42998,11 +43681,12 @@ class Shape {
|
|
|
42998
43681
|
}
|
|
42999
43682
|
/** Slice the runtime solid by a plane normal to local Z at the given offset. */
|
|
43000
43683
|
slice(offset = 0) {
|
|
43684
|
+
const planeOffset = requireFiniteNumber(offset, "Shape.slice() offset");
|
|
43001
43685
|
if (getShapeGeometryInfoInternal(this).backend === "truck") {
|
|
43002
|
-
const slicedProfile = lowerExactSlicedShapeCompilePlanToTruckProfileBackend(getShapeCompilePlanInternal(this),
|
|
43686
|
+
const slicedProfile = lowerExactSlicedShapeCompilePlanToTruckProfileBackend(getShapeCompilePlanInternal(this), planeOffset);
|
|
43003
43687
|
if (slicedProfile) return slicedProfile;
|
|
43004
43688
|
}
|
|
43005
|
-
return getShapeRuntimeBackendInternal(this).slice(
|
|
43689
|
+
return getShapeRuntimeBackendInternal(this).slice(planeOffset);
|
|
43006
43690
|
}
|
|
43007
43691
|
/** Orthographically project the runtime solid onto the local XY plane. */
|
|
43008
43692
|
project() {
|
|
@@ -43025,9 +43709,10 @@ class Shape {
|
|
|
43025
43709
|
const sp = this.referencePoint(selfAnchor);
|
|
43026
43710
|
let dx = tp[0] - sp[0], dy = tp[1] - sp[1], dz = tp[2] - sp[2];
|
|
43027
43711
|
if (offset) {
|
|
43028
|
-
|
|
43029
|
-
|
|
43030
|
-
|
|
43712
|
+
const offsetPoint = requireFiniteVec3$1(offset, "Shape.attachTo() offset");
|
|
43713
|
+
dx += offsetPoint[0];
|
|
43714
|
+
dy += offsetPoint[1];
|
|
43715
|
+
dz += offsetPoint[2];
|
|
43031
43716
|
}
|
|
43032
43717
|
return this.translate(dx, dy, dz);
|
|
43033
43718
|
}
|
|
@@ -43043,9 +43728,9 @@ class Shape {
|
|
|
43043
43728
|
* - `protrude` = how far the child sticks out (positive = outward from face)
|
|
43044
43729
|
*/
|
|
43045
43730
|
onFace(parent, face, opts = {}) {
|
|
43046
|
-
const u2 = opts.u ?? 0;
|
|
43047
|
-
const v = opts.v ?? 0;
|
|
43048
|
-
const p2 = opts.protrude ?? 0;
|
|
43731
|
+
const u2 = requireFiniteNumber(opts.u ?? 0, "Shape.onFace() u");
|
|
43732
|
+
const v = requireFiniteNumber(opts.v ?? 0, "Shape.onFace() v");
|
|
43733
|
+
const p2 = requireFiniteNumber(opts.protrude ?? 0, "Shape.onFace() protrude");
|
|
43049
43734
|
const opposite = {
|
|
43050
43735
|
front: "back",
|
|
43051
43736
|
back: "front",
|