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