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
|
@@ -235,7 +235,7 @@ function denormalize(value, array) {
|
|
|
235
235
|
throw new Error("Invalid component type.");
|
|
236
236
|
}
|
|
237
237
|
}
|
|
238
|
-
function normalize$
|
|
238
|
+
function normalize$4(value, array) {
|
|
239
239
|
switch (array.constructor) {
|
|
240
240
|
case Float32Array:
|
|
241
241
|
return value;
|
|
@@ -487,7 +487,7 @@ const MathUtils = {
|
|
|
487
487
|
* @param {TypedArray} array - The typed array that defines the data type of the value.
|
|
488
488
|
* @return {number} The normalize value.
|
|
489
489
|
*/
|
|
490
|
-
normalize: normalize$
|
|
490
|
+
normalize: normalize$4,
|
|
491
491
|
/**
|
|
492
492
|
* Denormalizes the given value according to the given typed array.
|
|
493
493
|
*
|
|
@@ -9728,7 +9728,7 @@ class BufferAttribute {
|
|
|
9728
9728
|
* @return {BufferAttribute} A reference to this instance.
|
|
9729
9729
|
*/
|
|
9730
9730
|
setComponent(index2, component, value) {
|
|
9731
|
-
if (this.normalized) value = normalize$
|
|
9731
|
+
if (this.normalized) value = normalize$4(value, this.array);
|
|
9732
9732
|
this.array[index2 * this.itemSize + component] = value;
|
|
9733
9733
|
return this;
|
|
9734
9734
|
}
|
|
@@ -9751,7 +9751,7 @@ class BufferAttribute {
|
|
|
9751
9751
|
* @return {BufferAttribute} A reference to this instance.
|
|
9752
9752
|
*/
|
|
9753
9753
|
setX(index2, x2) {
|
|
9754
|
-
if (this.normalized) x2 = normalize$
|
|
9754
|
+
if (this.normalized) x2 = normalize$4(x2, this.array);
|
|
9755
9755
|
this.array[index2 * this.itemSize] = x2;
|
|
9756
9756
|
return this;
|
|
9757
9757
|
}
|
|
@@ -9774,7 +9774,7 @@ class BufferAttribute {
|
|
|
9774
9774
|
* @return {BufferAttribute} A reference to this instance.
|
|
9775
9775
|
*/
|
|
9776
9776
|
setY(index2, y2) {
|
|
9777
|
-
if (this.normalized) y2 = normalize$
|
|
9777
|
+
if (this.normalized) y2 = normalize$4(y2, this.array);
|
|
9778
9778
|
this.array[index2 * this.itemSize + 1] = y2;
|
|
9779
9779
|
return this;
|
|
9780
9780
|
}
|
|
@@ -9797,7 +9797,7 @@ class BufferAttribute {
|
|
|
9797
9797
|
* @return {BufferAttribute} A reference to this instance.
|
|
9798
9798
|
*/
|
|
9799
9799
|
setZ(index2, z2) {
|
|
9800
|
-
if (this.normalized) z2 = normalize$
|
|
9800
|
+
if (this.normalized) z2 = normalize$4(z2, this.array);
|
|
9801
9801
|
this.array[index2 * this.itemSize + 2] = z2;
|
|
9802
9802
|
return this;
|
|
9803
9803
|
}
|
|
@@ -9820,7 +9820,7 @@ class BufferAttribute {
|
|
|
9820
9820
|
* @return {BufferAttribute} A reference to this instance.
|
|
9821
9821
|
*/
|
|
9822
9822
|
setW(index2, w2) {
|
|
9823
|
-
if (this.normalized) w2 = normalize$
|
|
9823
|
+
if (this.normalized) w2 = normalize$4(w2, this.array);
|
|
9824
9824
|
this.array[index2 * this.itemSize + 3] = w2;
|
|
9825
9825
|
return this;
|
|
9826
9826
|
}
|
|
@@ -9835,8 +9835,8 @@ class BufferAttribute {
|
|
|
9835
9835
|
setXY(index2, x2, y2) {
|
|
9836
9836
|
index2 *= this.itemSize;
|
|
9837
9837
|
if (this.normalized) {
|
|
9838
|
-
x2 = normalize$
|
|
9839
|
-
y2 = normalize$
|
|
9838
|
+
x2 = normalize$4(x2, this.array);
|
|
9839
|
+
y2 = normalize$4(y2, this.array);
|
|
9840
9840
|
}
|
|
9841
9841
|
this.array[index2 + 0] = x2;
|
|
9842
9842
|
this.array[index2 + 1] = y2;
|
|
@@ -9854,9 +9854,9 @@ class BufferAttribute {
|
|
|
9854
9854
|
setXYZ(index2, x2, y2, z2) {
|
|
9855
9855
|
index2 *= this.itemSize;
|
|
9856
9856
|
if (this.normalized) {
|
|
9857
|
-
x2 = normalize$
|
|
9858
|
-
y2 = normalize$
|
|
9859
|
-
z2 = normalize$
|
|
9857
|
+
x2 = normalize$4(x2, this.array);
|
|
9858
|
+
y2 = normalize$4(y2, this.array);
|
|
9859
|
+
z2 = normalize$4(z2, this.array);
|
|
9860
9860
|
}
|
|
9861
9861
|
this.array[index2 + 0] = x2;
|
|
9862
9862
|
this.array[index2 + 1] = y2;
|
|
@@ -9876,10 +9876,10 @@ class BufferAttribute {
|
|
|
9876
9876
|
setXYZW(index2, x2, y2, z2, w2) {
|
|
9877
9877
|
index2 *= this.itemSize;
|
|
9878
9878
|
if (this.normalized) {
|
|
9879
|
-
x2 = normalize$
|
|
9880
|
-
y2 = normalize$
|
|
9881
|
-
z2 = normalize$
|
|
9882
|
-
w2 = normalize$
|
|
9879
|
+
x2 = normalize$4(x2, this.array);
|
|
9880
|
+
y2 = normalize$4(y2, this.array);
|
|
9881
|
+
z2 = normalize$4(z2, this.array);
|
|
9882
|
+
w2 = normalize$4(w2, this.array);
|
|
9883
9883
|
}
|
|
9884
9884
|
this.array[index2 + 0] = x2;
|
|
9885
9885
|
this.array[index2 + 1] = y2;
|
|
@@ -12298,6 +12298,55 @@ function cloneShapeWorkplanePlacement(placement) {
|
|
|
12298
12298
|
placement: cloneSketchPlacementModel(placement.placement)
|
|
12299
12299
|
};
|
|
12300
12300
|
}
|
|
12301
|
+
function formatValidationValue(value) {
|
|
12302
|
+
if (typeof value === "number") return Number.isNaN(value) ? "NaN" : String(value);
|
|
12303
|
+
if (value === void 0) return "undefined";
|
|
12304
|
+
if (typeof value === "string") return JSON.stringify(value);
|
|
12305
|
+
try {
|
|
12306
|
+
return JSON.stringify(value) ?? String(value);
|
|
12307
|
+
} catch {
|
|
12308
|
+
return String(value);
|
|
12309
|
+
}
|
|
12310
|
+
}
|
|
12311
|
+
function requireFiniteNumber(value, label) {
|
|
12312
|
+
if (typeof value !== "number" || !Number.isFinite(value)) {
|
|
12313
|
+
throw new Error(`${label} must be a finite number, got ${formatValidationValue(value)}`);
|
|
12314
|
+
}
|
|
12315
|
+
return value;
|
|
12316
|
+
}
|
|
12317
|
+
function requirePositiveFiniteNumber(value, label) {
|
|
12318
|
+
const n = requireFiniteNumber(value, label);
|
|
12319
|
+
if (n <= 0) throw new Error(`${label} must be a positive finite number, got ${formatValidationValue(value)}`);
|
|
12320
|
+
return n;
|
|
12321
|
+
}
|
|
12322
|
+
function requireFiniteVec3$1(value, label) {
|
|
12323
|
+
if (!Array.isArray(value) || value.length !== 3) {
|
|
12324
|
+
throw new Error(`${label} must be [x, y, z] with finite numbers, got ${formatValidationValue(value)}`);
|
|
12325
|
+
}
|
|
12326
|
+
return [
|
|
12327
|
+
requireFiniteNumber(value[0], `${label}[0]`),
|
|
12328
|
+
requireFiniteNumber(value[1], `${label}[1]`),
|
|
12329
|
+
requireFiniteNumber(value[2], `${label}[2]`)
|
|
12330
|
+
];
|
|
12331
|
+
}
|
|
12332
|
+
function requireNonZeroFiniteVec3(value, label) {
|
|
12333
|
+
const v = requireFiniteVec3$1(value, label);
|
|
12334
|
+
if (v[0] === 0 && v[1] === 0 && v[2] === 0) throw new Error(`${label} must not be [0, 0, 0]`);
|
|
12335
|
+
return v;
|
|
12336
|
+
}
|
|
12337
|
+
function requireFiniteMat4(value, label) {
|
|
12338
|
+
if (!Array.isArray(value) || value.length !== 16) {
|
|
12339
|
+
throw new Error(`${label} must be a 4x4 matrix array with 16 finite numbers, got ${formatValidationValue(value)}`);
|
|
12340
|
+
}
|
|
12341
|
+
return value.map((entry, index2) => requireFiniteNumber(entry, `${label}[${index2}]`));
|
|
12342
|
+
}
|
|
12343
|
+
function requireNonZeroFiniteScale3(value, label) {
|
|
12344
|
+
const scale2 = typeof value === "number" ? [requireFiniteNumber(value, label), requireFiniteNumber(value, label), requireFiniteNumber(value, label)] : requireFiniteVec3$1(value, label);
|
|
12345
|
+
if (Math.abs(scale2[0]) < 1e-12 || Math.abs(scale2[1]) < 1e-12 || Math.abs(scale2[2]) < 1e-12) {
|
|
12346
|
+
throw new Error(`${label} must have finite non-zero components, got ${formatValidationValue(value)}`);
|
|
12347
|
+
}
|
|
12348
|
+
return scale2;
|
|
12349
|
+
}
|
|
12301
12350
|
const EPS$3 = 1e-10;
|
|
12302
12351
|
function subVec3(a2, b) {
|
|
12303
12352
|
return [a2[0] - b[0], a2[1] - b[1], a2[2] - b[2]];
|
|
@@ -12379,9 +12428,6 @@ function solveRotateAroundAngle(axis, pivot, movingPoint, targetPoint, options =
|
|
|
12379
12428
|
function identityMatrix() {
|
|
12380
12429
|
return [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1];
|
|
12381
12430
|
}
|
|
12382
|
-
function toMat4(input) {
|
|
12383
|
-
return input instanceof Transform ? input.toArray() : input;
|
|
12384
|
-
}
|
|
12385
12431
|
function multiplyMat4(a2, b) {
|
|
12386
12432
|
const out = new Array(16).fill(0);
|
|
12387
12433
|
for (let col = 0; col < 4; col++) {
|
|
@@ -12458,23 +12504,40 @@ class Transform {
|
|
|
12458
12504
|
}
|
|
12459
12505
|
/** Wrap an existing `Transform` or raw 4x4 matrix as a `Transform`. */
|
|
12460
12506
|
static from(input) {
|
|
12461
|
-
return input instanceof Transform ? input : new Transform(input);
|
|
12507
|
+
return input instanceof Transform ? input : new Transform(requireFiniteMat4(input, "Transform.from() matrix"));
|
|
12462
12508
|
}
|
|
12463
12509
|
/** Create a translation transform. */
|
|
12464
12510
|
static translation(x2, y2, z2) {
|
|
12465
|
-
return new Transform([
|
|
12511
|
+
return new Transform([
|
|
12512
|
+
1,
|
|
12513
|
+
0,
|
|
12514
|
+
0,
|
|
12515
|
+
0,
|
|
12516
|
+
0,
|
|
12517
|
+
1,
|
|
12518
|
+
0,
|
|
12519
|
+
0,
|
|
12520
|
+
0,
|
|
12521
|
+
0,
|
|
12522
|
+
1,
|
|
12523
|
+
0,
|
|
12524
|
+
requireFiniteNumber(x2, "Transform.translation() x"),
|
|
12525
|
+
requireFiniteNumber(y2, "Transform.translation() y"),
|
|
12526
|
+
requireFiniteNumber(z2, "Transform.translation() z"),
|
|
12527
|
+
1
|
|
12528
|
+
]);
|
|
12466
12529
|
}
|
|
12467
12530
|
/** Create a uniform or per-axis scale transform. */
|
|
12468
12531
|
static scale(v) {
|
|
12469
|
-
const sx =
|
|
12470
|
-
const sy = typeof v === "number" ? v : v[1];
|
|
12471
|
-
const sz = typeof v === "number" ? v : v[2];
|
|
12532
|
+
const [sx, sy, sz] = requireNonZeroFiniteScale3(v, "Transform.scale() scale");
|
|
12472
12533
|
return new Transform([sx, 0, 0, 0, 0, sy, 0, 0, 0, 0, sz, 0, 0, 0, 0, 1]);
|
|
12473
12534
|
}
|
|
12474
12535
|
/** Create a rotation around an arbitrary axis, optionally about a pivot. */
|
|
12475
12536
|
static rotationAxis(axis, angleDeg, pivot = [0, 0, 0]) {
|
|
12476
|
-
const [ux, uy, uz] = normalizeVec3$3(axis);
|
|
12477
|
-
const
|
|
12537
|
+
const [ux, uy, uz] = normalizeVec3$3(requireNonZeroFiniteVec3(axis, "Transform.rotationAxis() axis"));
|
|
12538
|
+
const degrees = requireFiniteNumber(angleDeg, "Transform.rotationAxis() angleDeg");
|
|
12539
|
+
const [px, py, pz] = requireFiniteVec3$1(pivot, "Transform.rotationAxis() pivot");
|
|
12540
|
+
const rad = degrees * Math.PI / 180;
|
|
12478
12541
|
const cos2 = Math.cos(rad);
|
|
12479
12542
|
const sin2 = Math.sin(rad);
|
|
12480
12543
|
const m00 = cos2 + ux * ux * (1 - cos2);
|
|
@@ -12486,7 +12549,6 @@ class Transform {
|
|
|
12486
12549
|
const m20 = uz * ux * (1 - cos2) - uy * sin2;
|
|
12487
12550
|
const m21 = uz * uy * (1 - cos2) + ux * sin2;
|
|
12488
12551
|
const m22 = cos2 + uz * uz * (1 - cos2);
|
|
12489
|
-
const [px, py, pz] = pivot;
|
|
12490
12552
|
const tx = px - (m00 * px + m01 * py + m02 * pz);
|
|
12491
12553
|
const ty = py - (m10 * px + m11 * py + m12 * pz);
|
|
12492
12554
|
const tz = pz - (m20 * px + m21 * py + m22 * pz);
|
|
@@ -12494,12 +12556,16 @@ class Transform {
|
|
|
12494
12556
|
}
|
|
12495
12557
|
/** Solve the rotation needed to move one point onto a target line or plane. */
|
|
12496
12558
|
static rotateAroundTo(axis, pivot, movingPoint, targetPoint, options = {}) {
|
|
12497
|
-
const
|
|
12498
|
-
|
|
12559
|
+
const rotateAxis = requireNonZeroFiniteVec3(axis, "Transform.rotateAroundTo() axis");
|
|
12560
|
+
const rotatePivot = requireFiniteVec3$1(pivot, "Transform.rotateAroundTo() pivot");
|
|
12561
|
+
const moving = requireFiniteVec3$1(movingPoint, "Transform.rotateAroundTo() movingPoint");
|
|
12562
|
+
const target = requireFiniteVec3$1(targetPoint, "Transform.rotateAroundTo() targetPoint");
|
|
12563
|
+
const angleDeg = solveRotateAroundAngle(rotateAxis, rotatePivot, moving, target, options);
|
|
12564
|
+
return Transform.rotationAxis(rotateAxis, angleDeg, rotatePivot);
|
|
12499
12565
|
}
|
|
12500
12566
|
/** Compose transforms in chain order: `a.mul(b)` applies `a`, then `b`. */
|
|
12501
12567
|
mul(other) {
|
|
12502
|
-
const rhs =
|
|
12568
|
+
const rhs = other instanceof Transform ? other.toArray() : requireFiniteMat4(other, "Transform.mul() matrix");
|
|
12503
12569
|
return new Transform(multiplyMat4(rhs, this.m));
|
|
12504
12570
|
}
|
|
12505
12571
|
/** Translate after the current transform. */
|
|
@@ -12510,6 +12576,18 @@ class Transform {
|
|
|
12510
12576
|
rotateAxis(axis, angleDeg, pivot = [0, 0, 0]) {
|
|
12511
12577
|
return this.mul(Transform.rotationAxis(axis, angleDeg, pivot));
|
|
12512
12578
|
}
|
|
12579
|
+
/** Rotate about the X axis after the current transform (parity with `Shape.rotateX`). */
|
|
12580
|
+
rotateX(angleDeg, pivot = [0, 0, 0]) {
|
|
12581
|
+
return this.rotateAxis([1, 0, 0], angleDeg, pivot);
|
|
12582
|
+
}
|
|
12583
|
+
/** Rotate about the Y axis after the current transform (parity with `Shape.rotateY`). */
|
|
12584
|
+
rotateY(angleDeg, pivot = [0, 0, 0]) {
|
|
12585
|
+
return this.rotateAxis([0, 1, 0], angleDeg, pivot);
|
|
12586
|
+
}
|
|
12587
|
+
/** Rotate about the Z axis after the current transform (parity with `Shape.rotateZ`). */
|
|
12588
|
+
rotateZ(angleDeg, pivot = [0, 0, 0]) {
|
|
12589
|
+
return this.rotateAxis([0, 0, 1], angleDeg, pivot);
|
|
12590
|
+
}
|
|
12513
12591
|
/** Scale after the current transform. */
|
|
12514
12592
|
scale(v) {
|
|
12515
12593
|
return this.mul(Transform.scale(v));
|
|
@@ -12520,11 +12598,11 @@ class Transform {
|
|
|
12520
12598
|
}
|
|
12521
12599
|
/** Transform a point using homogeneous coordinates. */
|
|
12522
12600
|
point(p2) {
|
|
12523
|
-
return transformPoint$1(this.m, p2, 1);
|
|
12601
|
+
return transformPoint$1(this.m, requireFiniteVec3$1(p2, "Transform.point() point"), 1);
|
|
12524
12602
|
}
|
|
12525
12603
|
/** Transform a direction vector without translation. */
|
|
12526
12604
|
vector(v) {
|
|
12527
|
-
return transformPoint$1(this.m, v, 0);
|
|
12605
|
+
return transformPoint$1(this.m, requireFiniteVec3$1(v, "Transform.vector() vector"), 0);
|
|
12528
12606
|
}
|
|
12529
12607
|
/** Return the transform as a raw 4x4 matrix array. */
|
|
12530
12608
|
toArray() {
|
|
@@ -12913,6 +12991,42 @@ function cloneCutTaperCompilePlan(plan) {
|
|
|
12913
12991
|
scale: [canonicalNumber(plan.scale[0]), canonicalNumber(plan.scale[1])]
|
|
12914
12992
|
};
|
|
12915
12993
|
}
|
|
12994
|
+
function cloneEdgeFeatureTarget(target) {
|
|
12995
|
+
return {
|
|
12996
|
+
midpoint: [target.midpoint[0], target.midpoint[1], target.midpoint[2]],
|
|
12997
|
+
start: [target.start[0], target.start[1], target.start[2]],
|
|
12998
|
+
end: [target.end[0], target.end[1], target.end[2]],
|
|
12999
|
+
convex: target.convex,
|
|
13000
|
+
...target.nativeTopology ? { nativeTopology: { backend: target.nativeTopology.backend, edge: target.nativeTopology.edge } } : {}
|
|
13001
|
+
};
|
|
13002
|
+
}
|
|
13003
|
+
function cloneEdgeFeatureQuery(query) {
|
|
13004
|
+
if (!query) return void 0;
|
|
13005
|
+
return {
|
|
13006
|
+
...query.near ? { near: [query.near[0], query.near[1], query.near[2]] } : {},
|
|
13007
|
+
...query.parallel ? { parallel: [query.parallel[0], query.parallel[1], query.parallel[2]] } : {},
|
|
13008
|
+
...query.perpendicular ? { perpendicular: [query.perpendicular[0], query.perpendicular[1], query.perpendicular[2]] } : {},
|
|
13009
|
+
...query.convex !== void 0 ? { convex: query.convex } : {},
|
|
13010
|
+
...query.concave !== void 0 ? { concave: query.concave } : {},
|
|
13011
|
+
...query.minAngle !== void 0 ? { minAngle: canonicalNumber(query.minAngle) } : {},
|
|
13012
|
+
...query.maxAngle !== void 0 ? { maxAngle: canonicalNumber(query.maxAngle) } : {},
|
|
13013
|
+
...query.minLength !== void 0 ? { minLength: canonicalNumber(query.minLength) } : {},
|
|
13014
|
+
...query.maxLength !== void 0 ? { maxLength: canonicalNumber(query.maxLength) } : {},
|
|
13015
|
+
...query.within ? {
|
|
13016
|
+
within: {
|
|
13017
|
+
...query.within.xMin !== void 0 ? { xMin: canonicalNumber(query.within.xMin) } : {},
|
|
13018
|
+
...query.within.xMax !== void 0 ? { xMax: canonicalNumber(query.within.xMax) } : {},
|
|
13019
|
+
...query.within.yMin !== void 0 ? { yMin: canonicalNumber(query.within.yMin) } : {},
|
|
13020
|
+
...query.within.yMax !== void 0 ? { yMax: canonicalNumber(query.within.yMax) } : {},
|
|
13021
|
+
...query.within.zMin !== void 0 ? { zMin: canonicalNumber(query.within.zMin) } : {},
|
|
13022
|
+
...query.within.zMax !== void 0 ? { zMax: canonicalNumber(query.within.zMax) } : {}
|
|
13023
|
+
}
|
|
13024
|
+
} : {},
|
|
13025
|
+
...query.atZ !== void 0 ? { atZ: canonicalNumber(query.atZ) } : {},
|
|
13026
|
+
...query.tolerance !== void 0 ? { tolerance: canonicalNumber(query.tolerance) } : {},
|
|
13027
|
+
...query.angleTolerance !== void 0 ? { angleTolerance: canonicalNumber(query.angleTolerance) } : {}
|
|
13028
|
+
};
|
|
13029
|
+
}
|
|
12916
13030
|
function featureCutExtentForwardSide(extent) {
|
|
12917
13031
|
return extent.kind === "two-sided" ? extent.forward : extent;
|
|
12918
13032
|
}
|
|
@@ -13009,6 +13123,41 @@ function cloneSweepPathCompilePlan(path) {
|
|
|
13009
13123
|
degree: path.degree,
|
|
13010
13124
|
closed: path.closed
|
|
13011
13125
|
};
|
|
13126
|
+
case "route3d":
|
|
13127
|
+
return {
|
|
13128
|
+
kind: "route3d",
|
|
13129
|
+
segments: path.segments.map(
|
|
13130
|
+
(segment) => segment.kind === "line" ? {
|
|
13131
|
+
kind: "line",
|
|
13132
|
+
from: canonicalVec3(segment.from),
|
|
13133
|
+
to: canonicalVec3(segment.to),
|
|
13134
|
+
length: canonicalNumber(segment.length)
|
|
13135
|
+
} : {
|
|
13136
|
+
kind: "arc",
|
|
13137
|
+
center: canonicalVec3(segment.center),
|
|
13138
|
+
radius: canonicalNumber(segment.radius),
|
|
13139
|
+
axis: canonicalVec3(segment.axis),
|
|
13140
|
+
start: canonicalVec3(segment.start),
|
|
13141
|
+
end: canonicalVec3(segment.end),
|
|
13142
|
+
sweepDeg: canonicalNumber(segment.sweepDeg),
|
|
13143
|
+
length: canonicalNumber(segment.length)
|
|
13144
|
+
}
|
|
13145
|
+
),
|
|
13146
|
+
ports: Object.fromEntries(
|
|
13147
|
+
Object.entries(path.ports).map(([name, port]) => [
|
|
13148
|
+
name,
|
|
13149
|
+
{
|
|
13150
|
+
name: port.name,
|
|
13151
|
+
origin: canonicalVec3(port.origin),
|
|
13152
|
+
axis: canonicalVec3(port.axis),
|
|
13153
|
+
xAxis: canonicalVec3(port.xAxis),
|
|
13154
|
+
yAxis: canonicalVec3(port.yAxis),
|
|
13155
|
+
station: canonicalNumber(port.station)
|
|
13156
|
+
}
|
|
13157
|
+
])
|
|
13158
|
+
),
|
|
13159
|
+
length: canonicalNumber(path.length)
|
|
13160
|
+
};
|
|
13012
13161
|
default:
|
|
13013
13162
|
assertExhaustive(path);
|
|
13014
13163
|
}
|
|
@@ -13103,6 +13252,7 @@ function cloneProfileEdge(edge) {
|
|
|
13103
13252
|
}
|
|
13104
13253
|
}
|
|
13105
13254
|
function cloneShapeCompilePlan(plan) {
|
|
13255
|
+
var _a3, _b3, _c2;
|
|
13106
13256
|
if (!plan) return null;
|
|
13107
13257
|
let result;
|
|
13108
13258
|
switch (plan.kind) {
|
|
@@ -13281,13 +13431,9 @@ function cloneShapeCompilePlan(plan) {
|
|
|
13281
13431
|
radius: plan.radius,
|
|
13282
13432
|
segments: plan.segments,
|
|
13283
13433
|
continuity: plan.continuity,
|
|
13284
|
-
edgeTargets: plan.edgeTargets.map(
|
|
13285
|
-
|
|
13286
|
-
|
|
13287
|
-
end: [t.end[0], t.end[1], t.end[2]],
|
|
13288
|
-
convex: t.convex,
|
|
13289
|
-
...t.nativeTopology ? { nativeTopology: { backend: t.nativeTopology.backend, edge: t.nativeTopology.edge } } : {}
|
|
13290
|
-
}))
|
|
13434
|
+
edgeTargets: (_a3 = plan.edgeTargets) == null ? void 0 : _a3.map(cloneEdgeFeatureTarget),
|
|
13435
|
+
edgeQuery: cloneEdgeFeatureQuery(plan.edgeQuery),
|
|
13436
|
+
edgeSelection: plan.edgeSelection
|
|
13291
13437
|
};
|
|
13292
13438
|
break;
|
|
13293
13439
|
case "cornerYBlend":
|
|
@@ -13297,13 +13443,7 @@ function cloneShapeCompilePlan(plan) {
|
|
|
13297
13443
|
radius: plan.radius,
|
|
13298
13444
|
segments: plan.segments,
|
|
13299
13445
|
continuity: plan.continuity,
|
|
13300
|
-
edgeTargets: plan.edgeTargets.map(
|
|
13301
|
-
midpoint: [t.midpoint[0], t.midpoint[1], t.midpoint[2]],
|
|
13302
|
-
start: [t.start[0], t.start[1], t.start[2]],
|
|
13303
|
-
end: [t.end[0], t.end[1], t.end[2]],
|
|
13304
|
-
convex: t.convex,
|
|
13305
|
-
...t.nativeTopology ? { nativeTopology: { backend: t.nativeTopology.backend, edge: t.nativeTopology.edge } } : {}
|
|
13306
|
-
})),
|
|
13446
|
+
edgeTargets: ((_b3 = plan.edgeTargets) == null ? void 0 : _b3.map(cloneEdgeFeatureTarget)) ?? [],
|
|
13307
13447
|
cornerPoint: [plan.cornerPoint[0], plan.cornerPoint[1], plan.cornerPoint[2]],
|
|
13308
13448
|
cornerTolerance: canonicalNumber(plan.cornerTolerance),
|
|
13309
13449
|
minBranchAngleDeg: canonicalNumber(plan.minBranchAngleDeg)
|
|
@@ -13314,13 +13454,9 @@ function cloneShapeCompilePlan(plan) {
|
|
|
13314
13454
|
kind: "chamferEdges",
|
|
13315
13455
|
base: cloneShapeCompilePlan(plan.base),
|
|
13316
13456
|
size: plan.size,
|
|
13317
|
-
edgeTargets: plan.edgeTargets.map(
|
|
13318
|
-
|
|
13319
|
-
|
|
13320
|
-
end: [t.end[0], t.end[1], t.end[2]],
|
|
13321
|
-
convex: t.convex,
|
|
13322
|
-
...t.nativeTopology ? { nativeTopology: { backend: t.nativeTopology.backend, edge: t.nativeTopology.edge } } : {}
|
|
13323
|
-
}))
|
|
13457
|
+
edgeTargets: (_c2 = plan.edgeTargets) == null ? void 0 : _c2.map(cloneEdgeFeatureTarget),
|
|
13458
|
+
edgeQuery: cloneEdgeFeatureQuery(plan.edgeQuery),
|
|
13459
|
+
edgeSelection: plan.edgeSelection
|
|
13324
13460
|
};
|
|
13325
13461
|
break;
|
|
13326
13462
|
case "draft":
|
|
@@ -13340,7 +13476,13 @@ function cloneShapeCompilePlan(plan) {
|
|
|
13340
13476
|
};
|
|
13341
13477
|
break;
|
|
13342
13478
|
case "importedMesh":
|
|
13343
|
-
result = {
|
|
13479
|
+
result = {
|
|
13480
|
+
kind: "importedMesh",
|
|
13481
|
+
filePath: plan.filePath,
|
|
13482
|
+
format: plan.format,
|
|
13483
|
+
...plan.object ? { object: plan.object } : {},
|
|
13484
|
+
fileData: plan.fileData
|
|
13485
|
+
};
|
|
13344
13486
|
break;
|
|
13345
13487
|
case "sdf":
|
|
13346
13488
|
result = {
|
|
@@ -13655,6 +13797,83 @@ function remapToKnotDomain(t, n, degree, knots) {
|
|
|
13655
13797
|
const uMax = knots[n];
|
|
13656
13798
|
return uMin + Math.max(0, Math.min(1, t)) * (uMax - uMin);
|
|
13657
13799
|
}
|
|
13800
|
+
const EPSILON$2 = 1e-9;
|
|
13801
|
+
function add$2(a2, b) {
|
|
13802
|
+
return [a2[0] + b[0], a2[1] + b[1], a2[2] + b[2]];
|
|
13803
|
+
}
|
|
13804
|
+
function scale$2(v, factor) {
|
|
13805
|
+
return [v[0] * factor, v[1] * factor, v[2] * factor];
|
|
13806
|
+
}
|
|
13807
|
+
function sub$2(a2, b) {
|
|
13808
|
+
return [a2[0] - b[0], a2[1] - b[1], a2[2] - b[2]];
|
|
13809
|
+
}
|
|
13810
|
+
function dot$3(a2, b) {
|
|
13811
|
+
return a2[0] * b[0] + a2[1] * b[1] + a2[2] * b[2];
|
|
13812
|
+
}
|
|
13813
|
+
function cross$4(a2, b) {
|
|
13814
|
+
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]];
|
|
13815
|
+
}
|
|
13816
|
+
function rotateAroundAxis(v, axis, angleRad) {
|
|
13817
|
+
const c2 = Math.cos(angleRad);
|
|
13818
|
+
const s = Math.sin(angleRad);
|
|
13819
|
+
const term1 = scale$2(v, c2);
|
|
13820
|
+
const term2 = scale$2(cross$4(axis, v), s);
|
|
13821
|
+
const term3 = scale$2(axis, dot$3(axis, v) * (1 - c2));
|
|
13822
|
+
return add$2(add$2(term1, term2), term3);
|
|
13823
|
+
}
|
|
13824
|
+
function arcPointAt(segment, t) {
|
|
13825
|
+
const sweepRad = segment.sweepDeg * Math.PI / 180 * t;
|
|
13826
|
+
return add$2(segment.center, rotateAroundAxis(sub$2(segment.start, segment.center), segment.axis, sweepRad));
|
|
13827
|
+
}
|
|
13828
|
+
function pushUnique(points, point) {
|
|
13829
|
+
const prev = points[points.length - 1];
|
|
13830
|
+
if (!prev || Math.hypot(prev[0] - point[0], prev[1] - point[1], prev[2] - point[2]) > EPSILON$2) {
|
|
13831
|
+
points.push([point[0], point[1], point[2]]);
|
|
13832
|
+
}
|
|
13833
|
+
}
|
|
13834
|
+
function resolveOptions(options) {
|
|
13835
|
+
if (typeof options === "number") return { samples: Math.max(2, Math.floor(options)), maxAngleDeg: 6 };
|
|
13836
|
+
return {
|
|
13837
|
+
samples: Math.max(2, Math.floor((options == null ? void 0 : options.samples) ?? 48)),
|
|
13838
|
+
maxAngleDeg: Math.max(0.25, (options == null ? void 0 : options.maxAngleDeg) ?? 6)
|
|
13839
|
+
};
|
|
13840
|
+
}
|
|
13841
|
+
function routePointAt(plan, t) {
|
|
13842
|
+
if (plan.segments.length === 0) return [0, 0, 0];
|
|
13843
|
+
const target = Math.max(0, Math.min(1, t)) * plan.length;
|
|
13844
|
+
let station = 0;
|
|
13845
|
+
for (const segment of plan.segments) {
|
|
13846
|
+
const next = station + segment.length;
|
|
13847
|
+
if (target <= next || segment === plan.segments[plan.segments.length - 1]) {
|
|
13848
|
+
const localT = segment.length <= EPSILON$2 ? 1 : Math.max(0, Math.min(1, (target - station) / segment.length));
|
|
13849
|
+
if (segment.kind === "line") return add$2(segment.from, scale$2(sub$2(segment.to, segment.from), localT));
|
|
13850
|
+
return arcPointAt(segment, localT);
|
|
13851
|
+
}
|
|
13852
|
+
station = next;
|
|
13853
|
+
}
|
|
13854
|
+
const last = plan.segments[plan.segments.length - 1];
|
|
13855
|
+
return last.kind === "line" ? last.to : last.end;
|
|
13856
|
+
}
|
|
13857
|
+
function sampleRoute3DCompilePlan(plan, options) {
|
|
13858
|
+
const resolved = resolveOptions(options);
|
|
13859
|
+
const points = [];
|
|
13860
|
+
const totalIntervals = Math.max(1, resolved.samples - 1);
|
|
13861
|
+
for (const segment of plan.segments) {
|
|
13862
|
+
const proportional = plan.length > EPSILON$2 ? Math.ceil(segment.length / plan.length * totalIntervals) : 1;
|
|
13863
|
+
const arcIntervals = segment.kind === "arc" ? Math.ceil(Math.abs(segment.sweepDeg) / resolved.maxAngleDeg) : 1;
|
|
13864
|
+
const intervals = Math.max(1, proportional, arcIntervals);
|
|
13865
|
+
const start = segment.kind === "line" ? segment.from : segment.start;
|
|
13866
|
+
pushUnique(points, start);
|
|
13867
|
+
for (let i = 1; i <= intervals; i += 1) {
|
|
13868
|
+
if (segment.kind === "line") {
|
|
13869
|
+
pushUnique(points, add$2(segment.from, scale$2(sub$2(segment.to, segment.from), i / intervals)));
|
|
13870
|
+
} else {
|
|
13871
|
+
pushUnique(points, arcPointAt(segment, i / intervals));
|
|
13872
|
+
}
|
|
13873
|
+
}
|
|
13874
|
+
}
|
|
13875
|
+
return points;
|
|
13876
|
+
}
|
|
13658
13877
|
function catmullRom3D$1(p0, p1, p2, p3, t, tension) {
|
|
13659
13878
|
const tt = t * t;
|
|
13660
13879
|
const ttt = tt * t;
|
|
@@ -13793,6 +14012,8 @@ function evalPathAt(path, t) {
|
|
|
13793
14012
|
const u2 = remapToKnotDomain(Math.max(0, Math.min(1, t)), path.controlPoints.length, path.degree, path.knots);
|
|
13794
14013
|
return deBoor3D(path.controlPoints, path.weights, path.knots, path.degree, u2);
|
|
13795
14014
|
}
|
|
14015
|
+
case "route3d":
|
|
14016
|
+
return routePointAt(path, t);
|
|
13796
14017
|
}
|
|
13797
14018
|
}
|
|
13798
14019
|
function estimateCurvatureAt(path, t) {
|
|
@@ -13839,10 +14060,13 @@ function sweepPathToPolyline(path, samples = 48) {
|
|
|
13839
14060
|
}
|
|
13840
14061
|
return result;
|
|
13841
14062
|
}
|
|
14063
|
+
case "route3d":
|
|
14064
|
+
return sampleRoute3DCompilePlan(path, samples);
|
|
13842
14065
|
}
|
|
13843
14066
|
}
|
|
13844
14067
|
function sweepPathToPolylineAdaptive(path, baseSamples = 48) {
|
|
13845
14068
|
if (path.kind === "polyline") return path.points;
|
|
14069
|
+
if (path.kind === "route3d") return sampleRoute3DCompilePlan(path, baseSamples);
|
|
13846
14070
|
const probeCount = 64;
|
|
13847
14071
|
const curvatures = [];
|
|
13848
14072
|
for (let i = 0; i <= probeCount; i++) {
|
|
@@ -13873,7 +14097,7 @@ const EPS$2 = 1e-8;
|
|
|
13873
14097
|
function midpoint$1(start, end) {
|
|
13874
14098
|
return [(start[0] + end[0]) * 0.5, (start[1] + end[1]) * 0.5, (start[2] + end[2]) * 0.5];
|
|
13875
14099
|
}
|
|
13876
|
-
function normalize$
|
|
14100
|
+
function normalize$3(v) {
|
|
13877
14101
|
const len = Math.hypot(v[0], v[1], v[2]);
|
|
13878
14102
|
if (len <= EPS$2) throw new Error("Edge feature selection requires a non-zero direction vector");
|
|
13879
14103
|
return [v[0] / len, v[1] / len, v[2] / len];
|
|
@@ -14292,8 +14516,8 @@ function extrudeEdgeSelection(plan, edgeName) {
|
|
|
14292
14516
|
}
|
|
14293
14517
|
const points = plan.profile.points;
|
|
14294
14518
|
const [bl, br, _tr, tl] = points;
|
|
14295
|
-
const u2 = normalize$
|
|
14296
|
-
const v = normalize$
|
|
14519
|
+
const u2 = normalize$3([br[0] - bl[0], br[1] - bl[1], 0]);
|
|
14520
|
+
const v = normalize$3([tl[0] - bl[0], tl[1] - bl[1], 0]);
|
|
14297
14521
|
const vertex = points[index2];
|
|
14298
14522
|
const quadrant = index2 === 0 ? [1, -1] : index2 === 1 ? [-1, -1] : index2 === 2 ? [-1, 1] : [1, 1];
|
|
14299
14523
|
return {
|
|
@@ -14314,9 +14538,9 @@ function extrudeEdgeSelection(plan, edgeName) {
|
|
|
14314
14538
|
function applySelectionTransform(selection, transform) {
|
|
14315
14539
|
const start = transform.point(selection.start);
|
|
14316
14540
|
const end = transform.point(selection.end);
|
|
14317
|
-
const basisX = normalize$
|
|
14318
|
-
const basisY = normalize$
|
|
14319
|
-
const axis = normalize$
|
|
14541
|
+
const basisX = normalize$3(transform.vector(selection.basisX));
|
|
14542
|
+
const basisY = normalize$3(transform.vector(selection.basisY));
|
|
14543
|
+
const axis = normalize$3(subtract(end, start));
|
|
14320
14544
|
return {
|
|
14321
14545
|
kind: "line-segment",
|
|
14322
14546
|
edgeName: selection.edgeName,
|
|
@@ -15591,6 +15815,20 @@ function cleanName(value) {
|
|
|
15591
15815
|
const trimmed = value == null ? void 0 : value.replace(/\s+/g, " ").trim();
|
|
15592
15816
|
return trimmed && trimmed.length > 0 ? trimmed : null;
|
|
15593
15817
|
}
|
|
15818
|
+
function uniqueNames(baseNames) {
|
|
15819
|
+
const totals = /* @__PURE__ */ new Map();
|
|
15820
|
+
const seen = /* @__PURE__ */ new Map();
|
|
15821
|
+
for (const baseName of baseNames) totals.set(baseName, (totals.get(baseName) ?? 0) + 1);
|
|
15822
|
+
return baseNames.map((baseName) => {
|
|
15823
|
+
if ((totals.get(baseName) ?? 0) <= 1) return baseName;
|
|
15824
|
+
const ordinal = (seen.get(baseName) ?? 0) + 1;
|
|
15825
|
+
seen.set(baseName, ordinal);
|
|
15826
|
+
return `${baseName} #${String(ordinal).padStart(3, "0")}`;
|
|
15827
|
+
});
|
|
15828
|
+
}
|
|
15829
|
+
function normalizeSelector(value) {
|
|
15830
|
+
return value.trim().replace(/\s+/g, " ").toLowerCase();
|
|
15831
|
+
}
|
|
15594
15832
|
function extractModelXml(data) {
|
|
15595
15833
|
const zip = unzipSync(new Uint8Array(data));
|
|
15596
15834
|
const path = Object.keys(zip).find((entry) => entry.toLowerCase() === "3d/3dmodel.model");
|
|
@@ -15662,14 +15900,105 @@ function collectObjectGeometry(model, objectId, transforms = [], visiting = /* @
|
|
|
15662
15900
|
}
|
|
15663
15901
|
return { vertices, triangles, bbox };
|
|
15664
15902
|
}
|
|
15903
|
+
function buildBuildEntries(model) {
|
|
15904
|
+
const buildBaseNames = model.buildItems.map(
|
|
15905
|
+
(item) => {
|
|
15906
|
+
var _a3;
|
|
15907
|
+
return cleanName((_a3 = model.objectsById.get(item.objectId)) == null ? void 0 : _a3.sourceName) ?? `object-${item.objectId}`;
|
|
15908
|
+
}
|
|
15909
|
+
);
|
|
15910
|
+
const buildNames = uniqueNames(buildBaseNames);
|
|
15911
|
+
return model.buildItems.map((item, index2) => {
|
|
15912
|
+
const object = model.objectsById.get(item.objectId);
|
|
15913
|
+
return {
|
|
15914
|
+
stableRef: `3mf:build:${String(index2 + 1).padStart(3, "0")}:object:${item.objectId}`,
|
|
15915
|
+
objectId: item.objectId,
|
|
15916
|
+
autoName: buildNames[index2],
|
|
15917
|
+
sourceName: object == null ? void 0 : object.sourceName,
|
|
15918
|
+
type: object == null ? void 0 : object.type,
|
|
15919
|
+
transform: item.transform
|
|
15920
|
+
};
|
|
15921
|
+
});
|
|
15922
|
+
}
|
|
15923
|
+
function buildObjectEntries(model) {
|
|
15924
|
+
const objectNames = uniqueNames(model.objects.map((object) => cleanName(object.sourceName) ?? `object-${object.id}`));
|
|
15925
|
+
return model.objects.map(
|
|
15926
|
+
(object, index2) => ({
|
|
15927
|
+
stableRef: `3mf:object:${object.id}`,
|
|
15928
|
+
objectId: object.id,
|
|
15929
|
+
autoName: objectNames[index2],
|
|
15930
|
+
sourceName: object.sourceName,
|
|
15931
|
+
type: object.type
|
|
15932
|
+
})
|
|
15933
|
+
);
|
|
15934
|
+
}
|
|
15935
|
+
function buildDefaultSourceEntries(model) {
|
|
15936
|
+
return model.buildItems.length > 0 ? buildBuildEntries(model) : buildObjectEntries(model);
|
|
15937
|
+
}
|
|
15938
|
+
function buildSelectableEntries(model) {
|
|
15939
|
+
return model.buildItems.length > 0 ? [...buildBuildEntries(model), ...buildObjectEntries(model)] : buildObjectEntries(model);
|
|
15940
|
+
}
|
|
15941
|
+
function entryMatchesSelector(entry, selector) {
|
|
15942
|
+
const needle = normalizeSelector(selector);
|
|
15943
|
+
return [
|
|
15944
|
+
entry.stableRef,
|
|
15945
|
+
entry.autoName,
|
|
15946
|
+
entry.sourceName ?? "",
|
|
15947
|
+
entry.objectId,
|
|
15948
|
+
`object-${entry.objectId}`,
|
|
15949
|
+
`3mf:object:${entry.objectId}`
|
|
15950
|
+
].some((candidate) => normalizeSelector(candidate) === needle);
|
|
15951
|
+
}
|
|
15952
|
+
function availableEntryList(entries) {
|
|
15953
|
+
return entries.map((entry) => `${entry.autoName} [${entry.stableRef}]`).join(", ") || "none";
|
|
15954
|
+
}
|
|
15955
|
+
function selectSourceEntry(entries, selector) {
|
|
15956
|
+
const matches = entries.filter((entry) => entryMatchesSelector(entry, selector));
|
|
15957
|
+
if (matches.length === 1) return matches[0];
|
|
15958
|
+
if (matches.length > 1) {
|
|
15959
|
+
throw new Error(
|
|
15960
|
+
`3MF object selector "${selector}" is ambiguous. Use a stable ref: ${matches.map((entry) => entry.stableRef).join(", ")}`
|
|
15961
|
+
);
|
|
15962
|
+
}
|
|
15963
|
+
throw new Error(`3MF object selector "${selector}" matched no build item or resource object. Available: ${availableEntryList(entries)}`);
|
|
15964
|
+
}
|
|
15965
|
+
function selectorLooksLikeStableRef(selector) {
|
|
15966
|
+
return /^3mf:(build|object):/i.test(selector.trim());
|
|
15967
|
+
}
|
|
15968
|
+
function meshFromGeometry(geometry) {
|
|
15969
|
+
const vertices = [];
|
|
15970
|
+
const triangles = [];
|
|
15971
|
+
for (const vertex of geometry.vertices) vertices.push(vertex[0], vertex[1], vertex[2]);
|
|
15972
|
+
for (const triangle of geometry.triangles) triangles.push(triangle[0], triangle[1], triangle[2]);
|
|
15973
|
+
return {
|
|
15974
|
+
vertProperties: new Float32Array(vertices),
|
|
15975
|
+
triVerts: new Uint32Array(triangles),
|
|
15976
|
+
numProp: 3,
|
|
15977
|
+
mergeFromVert: new Uint32Array(0),
|
|
15978
|
+
mergeToVert: new Uint32Array(0)
|
|
15979
|
+
};
|
|
15980
|
+
}
|
|
15981
|
+
function partFromEntry(model, entry) {
|
|
15982
|
+
const geometry = collectObjectGeometry(model, entry.objectId, [entry.transform]);
|
|
15983
|
+
return {
|
|
15984
|
+
stableRef: entry.stableRef,
|
|
15985
|
+
objectId: entry.objectId,
|
|
15986
|
+
autoName: entry.autoName,
|
|
15987
|
+
sourceName: entry.sourceName,
|
|
15988
|
+
type: entry.type,
|
|
15989
|
+
mesh: meshFromGeometry(geometry),
|
|
15990
|
+
bbox: geometry.bbox,
|
|
15991
|
+
vertexCount: geometry.vertices.length,
|
|
15992
|
+
triangleCount: geometry.triangles.length
|
|
15993
|
+
};
|
|
15994
|
+
}
|
|
15665
15995
|
function parse3mfMesh(data) {
|
|
15666
15996
|
const model = parseModel(data);
|
|
15667
|
-
const
|
|
15668
|
-
const transforms = model.buildItems.length > 0 ? model.buildItems.map((item) => item.transform) : sourceIds.map(() => void 0);
|
|
15997
|
+
const entries = buildDefaultSourceEntries(model);
|
|
15669
15998
|
const vertices = [];
|
|
15670
15999
|
const triangles = [];
|
|
15671
|
-
|
|
15672
|
-
const geometry = collectObjectGeometry(model, objectId, [
|
|
16000
|
+
entries.forEach((entry) => {
|
|
16001
|
+
const geometry = collectObjectGeometry(model, entry.objectId, [entry.transform]);
|
|
15673
16002
|
const offset = vertices.length / 3;
|
|
15674
16003
|
for (const vertex of geometry.vertices) vertices.push(vertex[0], vertex[1], vertex[2]);
|
|
15675
16004
|
for (const triangle of geometry.triangles) triangles.push(triangle[0] + offset, triangle[1] + offset, triangle[2] + offset);
|
|
@@ -15682,6 +16011,11 @@ function parse3mfMesh(data) {
|
|
|
15682
16011
|
mergeToVert: new Uint32Array(0)
|
|
15683
16012
|
};
|
|
15684
16013
|
}
|
|
16014
|
+
function parse3mfMeshPart(data, selector) {
|
|
16015
|
+
const model = parseModel(data);
|
|
16016
|
+
const entries = selectorLooksLikeStableRef(selector) ? buildSelectableEntries(model) : buildDefaultSourceEntries(model);
|
|
16017
|
+
return partFromEntry(model, selectSourceEntry(entries, selector));
|
|
16018
|
+
}
|
|
15685
16019
|
function isStlBinary(data) {
|
|
15686
16020
|
if (data.byteLength < 84) return false;
|
|
15687
16021
|
const view = new DataView(data);
|
|
@@ -15826,17 +16160,17 @@ function parseObj(data) {
|
|
|
15826
16160
|
mergeToVert: new Uint32Array(0)
|
|
15827
16161
|
};
|
|
15828
16162
|
}
|
|
15829
|
-
function parse3mf(data) {
|
|
15830
|
-
return parse3mfMesh(data);
|
|
16163
|
+
function parse3mf(data, options = {}) {
|
|
16164
|
+
return options.object ? parse3mfMeshPart(data, options.object).mesh : parse3mfMesh(data);
|
|
15831
16165
|
}
|
|
15832
|
-
function parseMeshFile(data, format) {
|
|
16166
|
+
function parseMeshFile(data, format, options = {}) {
|
|
15833
16167
|
switch (format) {
|
|
15834
16168
|
case "stl":
|
|
15835
16169
|
return parseStl(data);
|
|
15836
16170
|
case "obj":
|
|
15837
16171
|
return parseObj(data);
|
|
15838
16172
|
case "3mf":
|
|
15839
|
-
return parse3mf(data);
|
|
16173
|
+
return parse3mf(data, options);
|
|
15840
16174
|
}
|
|
15841
16175
|
}
|
|
15842
16176
|
function cleanZero(value) {
|
|
@@ -15863,6 +16197,84 @@ function planeFrameToWorldToPlaneMatrix(frame) {
|
|
|
15863
16197
|
1
|
|
15864
16198
|
];
|
|
15865
16199
|
}
|
|
16200
|
+
const DEFAULT_TOLERANCE = 1;
|
|
16201
|
+
const DEFAULT_ANGLE_TOLERANCE = 10;
|
|
16202
|
+
function distSq$2(a2, b) {
|
|
16203
|
+
const dx = a2[0] - b[0];
|
|
16204
|
+
const dy = a2[1] - b[1];
|
|
16205
|
+
const dz = a2[2] - b[2];
|
|
16206
|
+
return dx * dx + dy * dy + dz * dz;
|
|
16207
|
+
}
|
|
16208
|
+
function vecLength$2(v) {
|
|
16209
|
+
return Math.sqrt(v[0] * v[0] + v[1] * v[1] + v[2] * v[2]);
|
|
16210
|
+
}
|
|
16211
|
+
function normalize$2(v) {
|
|
16212
|
+
const len = vecLength$2(v);
|
|
16213
|
+
if (len < 1e-12) return [0, 0, 0];
|
|
16214
|
+
return [v[0] / len, v[1] / len, v[2] / len];
|
|
16215
|
+
}
|
|
16216
|
+
function absDot$1(a2, b) {
|
|
16217
|
+
return Math.abs(a2[0] * b[0] + a2[1] * b[1] + a2[2] * b[2]);
|
|
16218
|
+
}
|
|
16219
|
+
function applyEdgeQueryFilters(edges, query) {
|
|
16220
|
+
const tol = query.tolerance ?? DEFAULT_TOLERANCE;
|
|
16221
|
+
const angleTol = query.angleTolerance ?? DEFAULT_ANGLE_TOLERANCE;
|
|
16222
|
+
const cosAngleTol = Math.cos(angleTol * Math.PI / 180);
|
|
16223
|
+
let result = edges;
|
|
16224
|
+
if (query.convex === true) {
|
|
16225
|
+
result = result.filter((e) => e.convex);
|
|
16226
|
+
}
|
|
16227
|
+
if (query.concave === true) {
|
|
16228
|
+
result = result.filter((e) => !e.convex);
|
|
16229
|
+
}
|
|
16230
|
+
if (query.minAngle != null) {
|
|
16231
|
+
const min2 = query.minAngle;
|
|
16232
|
+
result = result.filter((e) => e.dihedralAngle >= min2);
|
|
16233
|
+
}
|
|
16234
|
+
if (query.maxAngle != null) {
|
|
16235
|
+
const max2 = query.maxAngle;
|
|
16236
|
+
result = result.filter((e) => e.dihedralAngle <= max2);
|
|
16237
|
+
}
|
|
16238
|
+
if (query.minLength != null) {
|
|
16239
|
+
const min2 = query.minLength;
|
|
16240
|
+
result = result.filter((e) => e.length >= min2);
|
|
16241
|
+
}
|
|
16242
|
+
if (query.maxLength != null) {
|
|
16243
|
+
const max2 = query.maxLength;
|
|
16244
|
+
result = result.filter((e) => e.length <= max2);
|
|
16245
|
+
}
|
|
16246
|
+
if (query.parallel) {
|
|
16247
|
+
const dir = normalize$2(query.parallel);
|
|
16248
|
+
result = result.filter((e) => absDot$1(e.direction, dir) >= cosAngleTol);
|
|
16249
|
+
}
|
|
16250
|
+
if (query.perpendicular) {
|
|
16251
|
+
const dir = normalize$2(query.perpendicular);
|
|
16252
|
+
const sinAngleTol = Math.sin(angleTol * Math.PI / 180);
|
|
16253
|
+
result = result.filter((e) => absDot$1(e.direction, dir) <= sinAngleTol);
|
|
16254
|
+
}
|
|
16255
|
+
if (query.atZ != null) {
|
|
16256
|
+
const z2 = query.atZ;
|
|
16257
|
+
result = result.filter((e) => Math.abs(e.midpoint[2] - z2) <= tol);
|
|
16258
|
+
}
|
|
16259
|
+
if (query.within) {
|
|
16260
|
+
const b = query.within;
|
|
16261
|
+
result = result.filter((e) => {
|
|
16262
|
+
const [mx, my, mz] = e.midpoint;
|
|
16263
|
+
if (b.xMin != null && mx < b.xMin) return false;
|
|
16264
|
+
if (b.xMax != null && mx > b.xMax) return false;
|
|
16265
|
+
if (b.yMin != null && my < b.yMin) return false;
|
|
16266
|
+
if (b.yMax != null && my > b.yMax) return false;
|
|
16267
|
+
if (b.zMin != null && mz < b.zMin) return false;
|
|
16268
|
+
if (b.zMax != null && mz > b.zMax) return false;
|
|
16269
|
+
return true;
|
|
16270
|
+
});
|
|
16271
|
+
}
|
|
16272
|
+
if (query.near) {
|
|
16273
|
+
const pt = query.near;
|
|
16274
|
+
result = result.slice().sort((a2, b) => distSq$2(a2.midpoint, pt) - distSq$2(b.midpoint, pt));
|
|
16275
|
+
}
|
|
16276
|
+
return result;
|
|
16277
|
+
}
|
|
15866
16278
|
const SHELL_OPEN_FACE_CANONICAL = {
|
|
15867
16279
|
front: "side-bottom",
|
|
15868
16280
|
back: "side-top",
|
|
@@ -18170,6 +18582,8 @@ function getUnsupportedSdfProgramReason(node) {
|
|
|
18170
18582
|
return "noise depends on table-based simplex evaluation";
|
|
18171
18583
|
case "sdf:voronoi":
|
|
18172
18584
|
return "voronoi depends on table-based Worley evaluation";
|
|
18585
|
+
case "sdf:circularArray":
|
|
18586
|
+
return "circularArray folds polar coordinates and is not implemented in SdfProgram yet";
|
|
18173
18587
|
case "sdf:custom":
|
|
18174
18588
|
return "custom uses a dynamic JavaScript function body";
|
|
18175
18589
|
case "sdf:polylineSweep":
|
|
@@ -18850,6 +19264,7 @@ function requireOCCTShape(backend, apiName = "requireOCCTShape()") {
|
|
|
18850
19264
|
}
|
|
18851
19265
|
const BSPLINE_WIRE_THRESHOLD = 20;
|
|
18852
19266
|
const OFFSET_SOLID_EPS$1 = 1e-8;
|
|
19267
|
+
const MANIFOLD_BACKEND_REQUIRED_HINT = "Select the Manifold backend in the editor or run the CLI with --backend manifold.";
|
|
18853
19268
|
function transformProfileRadiusPoint$1(point, step) {
|
|
18854
19269
|
switch (step.kind) {
|
|
18855
19270
|
case "translate":
|
|
@@ -19555,6 +19970,31 @@ function findOCCTEdgeByMidpoint(oc, shape, midpoint2) {
|
|
|
19555
19970
|
}
|
|
19556
19971
|
return bestEdge;
|
|
19557
19972
|
}
|
|
19973
|
+
function edgeSegmentToTarget(segment) {
|
|
19974
|
+
return {
|
|
19975
|
+
midpoint: [segment.midpoint[0], segment.midpoint[1], segment.midpoint[2]],
|
|
19976
|
+
start: [segment.start[0], segment.start[1], segment.start[2]],
|
|
19977
|
+
end: [segment.end[0], segment.end[1], segment.end[2]],
|
|
19978
|
+
convex: segment.convex,
|
|
19979
|
+
...segment.nativeTopology ? { nativeTopology: segment.nativeTopology } : {}
|
|
19980
|
+
};
|
|
19981
|
+
}
|
|
19982
|
+
function selectOCCTEdgeFeatureTargets(base, plan) {
|
|
19983
|
+
if (!plan.edgeQuery) return plan.edgeTargets ?? [];
|
|
19984
|
+
const mesh = wrapOCCTShapeBackend(base).getMesh();
|
|
19985
|
+
const selected = applyEdgeQueryFilters(
|
|
19986
|
+
extractEdgeSegments({
|
|
19987
|
+
numProp: mesh.numProp,
|
|
19988
|
+
numTri: mesh.numTri,
|
|
19989
|
+
triVerts: mesh.triVerts,
|
|
19990
|
+
vertProperties: mesh.vertProperties,
|
|
19991
|
+
mergeFromVert: mesh.mergeFromVert,
|
|
19992
|
+
mergeToVert: mesh.mergeToVert
|
|
19993
|
+
}),
|
|
19994
|
+
plan.edgeQuery
|
|
19995
|
+
);
|
|
19996
|
+
return (plan.edgeSelection === "first" ? selected.slice(0, 1) : selected).map(edgeSegmentToTarget);
|
|
19997
|
+
}
|
|
19558
19998
|
function occtPointDistance(point, target) {
|
|
19559
19999
|
return Math.hypot(point.X() - target[0], point.Y() - target[1], point.Z() - target[2]);
|
|
19560
20000
|
}
|
|
@@ -19574,7 +20014,7 @@ function lowerFilletEdgesPlan$1(oc, plan) {
|
|
|
19574
20014
|
mkFillet.SetContinuity(mapSurfaceContinuityToOcct(oc, plan.continuity), 2 * Math.PI / 180);
|
|
19575
20015
|
}
|
|
19576
20016
|
let addedCount = 0;
|
|
19577
|
-
for (const target of plan
|
|
20017
|
+
for (const target of selectOCCTEdgeFeatureTargets(base, plan)) {
|
|
19578
20018
|
const matchedEdge = findOCCTEdgeByMidpoint(oc, base, target.midpoint);
|
|
19579
20019
|
if (matchedEdge) {
|
|
19580
20020
|
mkFillet.Add_2(plan.radius, matchedEdge);
|
|
@@ -19621,7 +20061,7 @@ function lowerChamferEdgesPlan$1(oc, plan) {
|
|
|
19621
20061
|
const base = lowerShapeCompilePlanToOCCT(plan.base, oc);
|
|
19622
20062
|
const mkChamfer = new oc.BRepFilletAPI_MakeChamfer(base);
|
|
19623
20063
|
let addedCount = 0;
|
|
19624
|
-
for (const target of plan
|
|
20064
|
+
for (const target of selectOCCTEdgeFeatureTargets(base, plan)) {
|
|
19625
20065
|
const matchedEdge = findOCCTEdgeByMidpoint(oc, base, target.midpoint);
|
|
19626
20066
|
if (matchedEdge) {
|
|
19627
20067
|
mkChamfer.Add_2(plan.size, matchedEdge);
|
|
@@ -19908,7 +20348,7 @@ function _lowerShapeCompilePlanToOCCTInner(plan, oc) {
|
|
|
19908
20348
|
`importMesh("${plan.filePath}") is not supported with the OCCT backend. Switch to the Manifold backend or use the default backend.`
|
|
19909
20349
|
);
|
|
19910
20350
|
case "sdf":
|
|
19911
|
-
throw new Error(
|
|
20351
|
+
throw new Error(`SDF shapes require the Manifold backend. ${MANIFOLD_BACKEND_REQUIRED_HINT}`);
|
|
19912
20352
|
case "fromSlices":
|
|
19913
20353
|
return lowerFromSlicesPlan$1(oc, plan);
|
|
19914
20354
|
case "nurbsSurface":
|
|
@@ -20080,6 +20520,7 @@ function buildBSplineCurveHandleFromSweepPathPlan(oc, path, context, allowApprox
|
|
|
20080
20520
|
case "catmull-rom":
|
|
20081
20521
|
case "hermite":
|
|
20082
20522
|
case "quintic-hermite":
|
|
20523
|
+
case "route3d":
|
|
20083
20524
|
if (allowApproximation) {
|
|
20084
20525
|
return buildApproximateBSplineCurveHandle(oc, sweepPathToPolyline(path, 96), context);
|
|
20085
20526
|
}
|
|
@@ -20460,27 +20901,166 @@ function lowerLoftPlan$1(oc, plan) {
|
|
|
20460
20901
|
}
|
|
20461
20902
|
return ts.Shape();
|
|
20462
20903
|
}
|
|
20463
|
-
function
|
|
20904
|
+
function fromSlicesPlaneFrameForOCCT(normalInput) {
|
|
20905
|
+
const normal = normalizeVec3$2(normalInput);
|
|
20906
|
+
if (!normal) throw new Error("Shape.fromSlices group normal must be non-zero");
|
|
20464
20907
|
const [nx, ny, nz] = normal;
|
|
20908
|
+
if (Math.abs(nz) > 1 - 1e-8) {
|
|
20909
|
+
return { u: [1, 0, 0], v: [0, nz > 0 ? 1 : -1, 0], normal };
|
|
20910
|
+
}
|
|
20911
|
+
if (Math.abs(ny) > 1 - 1e-8) {
|
|
20912
|
+
return { u: [1, 0, 0], v: [0, 0, ny > 0 ? 1 : -1], normal };
|
|
20913
|
+
}
|
|
20914
|
+
if (Math.abs(nx) > 1 - 1e-8) {
|
|
20915
|
+
return { u: [0, 1, 0], v: [0, 0, nx > 0 ? 1 : -1], normal };
|
|
20916
|
+
}
|
|
20917
|
+
const reference = Math.abs(nx) < 0.9 ? [1, 0, 0] : [0, 1, 0];
|
|
20918
|
+
const u2 = normalizeVec3$2(crossVec3$1(reference, normal));
|
|
20919
|
+
if (!u2) throw new Error("Shape.fromSlices profile u axis is invalid");
|
|
20920
|
+
return { u: u2, v: crossVec3$1(normal, u2), normal };
|
|
20921
|
+
}
|
|
20922
|
+
function buildFromSlicesLocalToWorldTransform(oc, normal) {
|
|
20923
|
+
const frame = fromSlicesPlaneFrameForOCCT(normal);
|
|
20465
20924
|
const trsf = new oc.gp_Trsf_1();
|
|
20466
|
-
|
|
20467
|
-
|
|
20468
|
-
|
|
20469
|
-
|
|
20470
|
-
|
|
20471
|
-
|
|
20472
|
-
|
|
20473
|
-
|
|
20474
|
-
|
|
20475
|
-
|
|
20476
|
-
|
|
20477
|
-
|
|
20925
|
+
trsf.SetValues(
|
|
20926
|
+
frame.u[0],
|
|
20927
|
+
frame.v[0],
|
|
20928
|
+
frame.normal[0],
|
|
20929
|
+
0,
|
|
20930
|
+
frame.u[1],
|
|
20931
|
+
frame.v[1],
|
|
20932
|
+
frame.normal[1],
|
|
20933
|
+
0,
|
|
20934
|
+
frame.u[2],
|
|
20935
|
+
frame.v[2],
|
|
20936
|
+
frame.normal[2],
|
|
20937
|
+
0
|
|
20938
|
+
);
|
|
20478
20939
|
return trsf;
|
|
20479
20940
|
}
|
|
20941
|
+
function axisAlignedDirectionForOCCT(vector) {
|
|
20942
|
+
let bestAxis = 0;
|
|
20943
|
+
let best = Math.abs(vector[0]);
|
|
20944
|
+
for (const axis of [1, 2]) {
|
|
20945
|
+
const value = Math.abs(vector[axis]);
|
|
20946
|
+
if (value > best) {
|
|
20947
|
+
best = value;
|
|
20948
|
+
bestAxis = axis;
|
|
20949
|
+
}
|
|
20950
|
+
}
|
|
20951
|
+
if (best < 1 - 1e-8) return null;
|
|
20952
|
+
return { axis: bestAxis, sign: vector[bestAxis] < 0 ? -1 : 1 };
|
|
20953
|
+
}
|
|
20954
|
+
function centeredEllipseProfileRadiiForOCCT(plan) {
|
|
20955
|
+
if (plan.kind !== "circle") return null;
|
|
20956
|
+
let rx = Math.abs(plan.radius);
|
|
20957
|
+
let ry = Math.abs(plan.radius);
|
|
20958
|
+
for (const transform of plan.transforms) {
|
|
20959
|
+
if (transform.kind !== "scale") return null;
|
|
20960
|
+
rx *= Math.abs(transform.x);
|
|
20961
|
+
ry *= Math.abs(transform.y);
|
|
20962
|
+
}
|
|
20963
|
+
return rx > 1e-10 && ry > 1e-10 ? [rx, ry] : null;
|
|
20964
|
+
}
|
|
20965
|
+
function setEllipsoidRadiusForOCCT(radii, axis, radius) {
|
|
20966
|
+
const existing = radii[axis];
|
|
20967
|
+
if (existing == null) {
|
|
20968
|
+
radii[axis] = radius;
|
|
20969
|
+
return true;
|
|
20970
|
+
}
|
|
20971
|
+
const tolerance = Math.max(1e-7, Math.max(Math.abs(existing), Math.abs(radius)) * 1e-7);
|
|
20972
|
+
return Math.abs(existing - radius) <= tolerance;
|
|
20973
|
+
}
|
|
20974
|
+
function buildRationalQuadraticEdgeForOCCT(oc, points, weights) {
|
|
20975
|
+
const poles = new oc.TColgp_Array1OfPnt_2(1, 3);
|
|
20976
|
+
const weightArr = new oc.TColStd_Array1OfReal_2(1, 3);
|
|
20977
|
+
for (let i = 0; i < 3; i++) {
|
|
20978
|
+
const [x2, y2, z2] = points[i];
|
|
20979
|
+
poles.SetValue(i + 1, new oc.gp_Pnt_3(x2, y2, z2));
|
|
20980
|
+
weightArr.SetValue(i + 1, weights[i]);
|
|
20981
|
+
}
|
|
20982
|
+
const knots = new oc.TColStd_Array1OfReal_2(1, 2);
|
|
20983
|
+
knots.SetValue(1, 0);
|
|
20984
|
+
knots.SetValue(2, 1);
|
|
20985
|
+
const mults = new oc.TColStd_Array1OfInteger_2(1, 2);
|
|
20986
|
+
mults.SetValue(1, 3);
|
|
20987
|
+
mults.SetValue(2, 3);
|
|
20988
|
+
const curve = new oc.Geom_BSplineCurve_2(poles, weightArr, knots, mults, 2, false, true);
|
|
20989
|
+
const handle = new oc.Handle_Geom_BSplineCurve_2(curve);
|
|
20990
|
+
return new oc.BRepBuilderAPI_MakeEdge_24(new oc.Handle_Geom_Curve_2(handle.get())).Edge();
|
|
20991
|
+
}
|
|
20992
|
+
function lowerAxisymmetricEllipsoidForOCCT(oc, radius, heightRadius) {
|
|
20993
|
+
const w2 = Math.SQRT1_2;
|
|
20994
|
+
const mkWire = new oc.BRepBuilderAPI_MakeWire_1();
|
|
20995
|
+
mkWire.Add_1(
|
|
20996
|
+
buildRationalQuadraticEdgeForOCCT(
|
|
20997
|
+
oc,
|
|
20998
|
+
[
|
|
20999
|
+
[0, 0, heightRadius],
|
|
21000
|
+
[radius, 0, heightRadius],
|
|
21001
|
+
[radius, 0, 0]
|
|
21002
|
+
],
|
|
21003
|
+
[1, w2, 1]
|
|
21004
|
+
)
|
|
21005
|
+
);
|
|
21006
|
+
mkWire.Add_1(
|
|
21007
|
+
buildRationalQuadraticEdgeForOCCT(
|
|
21008
|
+
oc,
|
|
21009
|
+
[
|
|
21010
|
+
[radius, 0, 0],
|
|
21011
|
+
[radius, 0, -heightRadius],
|
|
21012
|
+
[0, 0, -heightRadius]
|
|
21013
|
+
],
|
|
21014
|
+
[1, w2, 1]
|
|
21015
|
+
)
|
|
21016
|
+
);
|
|
21017
|
+
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());
|
|
21018
|
+
const face = buildFaceFromWire(oc, mkWire.Wire());
|
|
21019
|
+
const axis = new oc.gp_Ax1_2(new oc.gp_Pnt_3(0, 0, 0), new oc.gp_Dir_4(0, 0, 1));
|
|
21020
|
+
const revol = new oc.BRepPrimAPI_MakeRevol_1(face, axis, Math.PI * 2, true);
|
|
21021
|
+
revol.Build(new oc.Message_ProgressRange_1());
|
|
21022
|
+
if (!revol.IsDone()) {
|
|
21023
|
+
throw new Error("Shape.fromSlices exact ellipsoid revolve failed");
|
|
21024
|
+
}
|
|
21025
|
+
return revol.Shape();
|
|
21026
|
+
}
|
|
21027
|
+
function lowerOrthogonalEllipseFromSlicesPlan(oc, plan) {
|
|
21028
|
+
if (plan.groups.length !== 2) return null;
|
|
21029
|
+
const center = [0, 0, 0];
|
|
21030
|
+
const radii = [null, null, null];
|
|
21031
|
+
for (const group of plan.groups) {
|
|
21032
|
+
if (group.slices.length !== 1) return null;
|
|
21033
|
+
const slice = group.slices[0];
|
|
21034
|
+
const profileRadii = centeredEllipseProfileRadiiForOCCT(slice.profile);
|
|
21035
|
+
if (!profileRadii) return null;
|
|
21036
|
+
const frame = fromSlicesPlaneFrameForOCCT(group.normal);
|
|
21037
|
+
const normalAxis = axisAlignedDirectionForOCCT(frame.normal);
|
|
21038
|
+
const uAxis = axisAlignedDirectionForOCCT(frame.u);
|
|
21039
|
+
const vAxis = axisAlignedDirectionForOCCT(frame.v);
|
|
21040
|
+
if (!normalAxis || !uAxis || !vAxis) return null;
|
|
21041
|
+
center[normalAxis.axis] = normalAxis.sign * slice.offset;
|
|
21042
|
+
if (!setEllipsoidRadiusForOCCT(radii, uAxis.axis, profileRadii[0])) return null;
|
|
21043
|
+
if (!setEllipsoidRadiusForOCCT(radii, vAxis.axis, profileRadii[1])) return null;
|
|
21044
|
+
}
|
|
21045
|
+
if (radii.some((radius) => radius == null)) return null;
|
|
21046
|
+
const rx = radii[0];
|
|
21047
|
+
const ry = radii[1];
|
|
21048
|
+
const rz = radii[2];
|
|
21049
|
+
const axisymmetricTolerance = Math.max(1e-7, Math.max(Math.abs(rx), Math.abs(ry)) * 1e-7);
|
|
21050
|
+
if (Math.abs(rx - ry) > axisymmetricTolerance) return null;
|
|
21051
|
+
let shape = lowerAxisymmetricEllipsoidForOCCT(oc, (rx + ry) / 2, rz);
|
|
21052
|
+
if (Math.hypot(center[0], center[1], center[2]) > 1e-10) {
|
|
21053
|
+
const trsf = new oc.gp_Trsf_1();
|
|
21054
|
+
trsf.SetTranslation_1(new oc.gp_Vec_4(center[0], center[1], center[2]));
|
|
21055
|
+
const moved = new oc.BRepBuilderAPI_Transform_2(shape, trsf, true);
|
|
21056
|
+
shape = moved.Shape();
|
|
21057
|
+
}
|
|
21058
|
+
return shape;
|
|
21059
|
+
}
|
|
20480
21060
|
function lowerFromSlicesGroup(oc, group, singleSliceHalfExtent) {
|
|
20481
21061
|
const { normal, slices } = group;
|
|
20482
21062
|
const sorted = [...slices].sort((a2, b) => a2.offset - b.offset);
|
|
20483
|
-
const
|
|
21063
|
+
const localToWorldTrsf = buildFromSlicesLocalToWorldTransform(oc, normal);
|
|
20484
21064
|
if (sorted.length === 1) {
|
|
20485
21065
|
const s = sorted[0];
|
|
20486
21066
|
const rawFace = lowerProfileToFace(oc, s.profile);
|
|
@@ -20494,7 +21074,7 @@ function lowerFromSlicesGroup(oc, group, singleSliceHalfExtent) {
|
|
|
20494
21074
|
centerTrsf.SetTranslation_1(new oc.gp_Vec_4(0, 0, s.offset - extrudeHalf));
|
|
20495
21075
|
const centered = new oc.BRepBuilderAPI_Transform_2(shape, centerTrsf, true);
|
|
20496
21076
|
shape = centered.Shape();
|
|
20497
|
-
const rotated = new oc.BRepBuilderAPI_Transform_2(shape,
|
|
21077
|
+
const rotated = new oc.BRepBuilderAPI_Transform_2(shape, localToWorldTrsf, true);
|
|
20498
21078
|
return rotated.Shape();
|
|
20499
21079
|
}
|
|
20500
21080
|
const ts = new oc.BRepOffsetAPI_ThruSections(true, false, 1e-6);
|
|
@@ -20505,10 +21085,8 @@ function lowerFromSlicesGroup(oc, group, singleSliceHalfExtent) {
|
|
|
20505
21085
|
wire = toBSplineWireIfNeeded(oc, wire);
|
|
20506
21086
|
const placeTrsf = new oc.gp_Trsf_1();
|
|
20507
21087
|
placeTrsf.SetTranslation_1(new oc.gp_Vec_4(0, 0, s.offset));
|
|
20508
|
-
const
|
|
20509
|
-
|
|
20510
|
-
compound.Multiply(placeTrsf);
|
|
20511
|
-
const transformed = new oc.BRepBuilderAPI_Transform_2(wire, compound, true);
|
|
21088
|
+
const placed = new oc.BRepBuilderAPI_Transform_2(wire, placeTrsf, true);
|
|
21089
|
+
const transformed = new oc.BRepBuilderAPI_Transform_2(placed.Shape(), localToWorldTrsf, true);
|
|
20512
21090
|
ts.AddWire(oc.TopoDS.Wire_1(transformed.Shape()));
|
|
20513
21091
|
}
|
|
20514
21092
|
ts.CheckCompatibility(true);
|
|
@@ -20520,6 +21098,8 @@ function lowerFromSlicesGroup(oc, group, singleSliceHalfExtent) {
|
|
|
20520
21098
|
}
|
|
20521
21099
|
function lowerFromSlicesPlan$1(oc, plan) {
|
|
20522
21100
|
if (plan.groups.length === 0) throw new Error("Shape.fromSlices requires at least one slice");
|
|
21101
|
+
const exactEllipsoid = lowerOrthogonalEllipseFromSlicesPlan(oc, plan);
|
|
21102
|
+
if (exactEllipsoid) return exactEllipsoid;
|
|
20523
21103
|
const singleSliceHalfExtent = fromSlicesSingleSliceHalfExtentForOCCT(plan);
|
|
20524
21104
|
const groupSolids = plan.groups.map((g2) => lowerFromSlicesGroup(oc, g2, singleSliceHalfExtent));
|
|
20525
21105
|
if (groupSolids.length === 1) return groupSolids[0];
|
|
@@ -20546,14 +21126,40 @@ function buildPolylineSpineWire(oc, points) {
|
|
|
20546
21126
|
}
|
|
20547
21127
|
return mkWire.Wire();
|
|
20548
21128
|
}
|
|
21129
|
+
function buildRoute3DSpineWire(oc, path) {
|
|
21130
|
+
if (path.segments.length === 0) throw new Error("Route3D sweep path needs at least one segment");
|
|
21131
|
+
const mkWire = new oc.BRepBuilderAPI_MakeWire_1();
|
|
21132
|
+
for (const segment of path.segments) {
|
|
21133
|
+
if (segment.kind === "line") {
|
|
21134
|
+
const [x1, y1, z1] = segment.from;
|
|
21135
|
+
const [x2, y2, z2] = segment.to;
|
|
21136
|
+
if (x1 === x2 && y1 === y2 && z1 === z2) continue;
|
|
21137
|
+
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());
|
|
21138
|
+
continue;
|
|
21139
|
+
}
|
|
21140
|
+
const radial = normalizeVec3$2(subtractVec3(segment.start, segment.center));
|
|
21141
|
+
if (!radial) throw new Error("Route3D sweep arc has a collapsed start radius");
|
|
21142
|
+
const axis = new oc.gp_Ax2_2(
|
|
21143
|
+
new oc.gp_Pnt_3(segment.center[0], segment.center[1], segment.center[2]),
|
|
21144
|
+
new oc.gp_Dir_4(segment.axis[0], segment.axis[1], segment.axis[2]),
|
|
21145
|
+
new oc.gp_Dir_4(radial[0], radial[1], radial[2])
|
|
21146
|
+
);
|
|
21147
|
+
const circle = new oc.gp_Circ_2(axis, segment.radius);
|
|
21148
|
+
mkWire.Add_1(new oc.BRepBuilderAPI_MakeEdge_9(circle, 0, segment.sweepDeg * Math.PI / 180).Edge());
|
|
21149
|
+
}
|
|
21150
|
+
return mkWire.Wire();
|
|
21151
|
+
}
|
|
20549
21152
|
function buildSpineWireFromPlan(oc, path, pathSamples) {
|
|
20550
21153
|
switch (path.kind) {
|
|
20551
21154
|
case "polyline":
|
|
20552
21155
|
return buildPolylineSpineWire(oc, path.points);
|
|
21156
|
+
case "route3d":
|
|
21157
|
+
return buildRoute3DSpineWire(oc, path);
|
|
21158
|
+
case "nurbs":
|
|
21159
|
+
return new oc.BRepBuilderAPI_MakeWire_2(buildCurveEdgeFromSweepPathPlan(oc, path, "OCCT sweep path")).Wire();
|
|
20553
21160
|
case "catmull-rom":
|
|
20554
21161
|
case "hermite":
|
|
20555
21162
|
case "quintic-hermite":
|
|
20556
|
-
case "nurbs":
|
|
20557
21163
|
return buildPolylineSpineWire(oc, sweepPathToPolyline(path, pathSamples ?? 48));
|
|
20558
21164
|
}
|
|
20559
21165
|
}
|
|
@@ -31521,7 +32127,7 @@ function nurbsSurfaceForPlan(plan) {
|
|
|
31521
32127
|
return null;
|
|
31522
32128
|
}
|
|
31523
32129
|
function lowerImportedMeshPlan(plan) {
|
|
31524
|
-
const parsed = parseMeshFile(plan.fileData, plan.format);
|
|
32130
|
+
const parsed = parseMeshFile(plan.fileData, plan.format, { object: plan.object });
|
|
31525
32131
|
if (parsed.numProp !== 3) {
|
|
31526
32132
|
throw new Error(`importMesh("${plan.filePath}"): expected xyz vertex data`);
|
|
31527
32133
|
}
|
|
@@ -31824,12 +32430,18 @@ function applyNativeTruckFilletTargets(initialShape, targets, radius, segments,
|
|
|
31824
32430
|
}
|
|
31825
32431
|
}
|
|
31826
32432
|
function lowerFilletEdgesPlan(plan) {
|
|
32433
|
+
if (plan.edgeQuery) {
|
|
32434
|
+
throw new Error("filletEdges(): deferred edge queries are not supported by the Truck lowerer yet.");
|
|
32435
|
+
}
|
|
31827
32436
|
const shape = lowerShapeCompilePlanToTruckBackend(plan.base);
|
|
31828
|
-
return applyNativeTruckFilletTargets(shape, plan.edgeTargets, plan.radius, plan.segments, "filletEdges()");
|
|
32437
|
+
return applyNativeTruckFilletTargets(shape, plan.edgeTargets ?? [], plan.radius, plan.segments, "filletEdges()");
|
|
31829
32438
|
}
|
|
31830
32439
|
function lowerChamferEdgesPlan(plan) {
|
|
32440
|
+
if (plan.edgeQuery) {
|
|
32441
|
+
throw new Error("chamferEdges(): deferred edge queries are not supported by the Truck lowerer yet.");
|
|
32442
|
+
}
|
|
31831
32443
|
const shape = lowerShapeCompilePlanToTruckBackend(plan.base);
|
|
31832
|
-
return applyNativeTruckChamferTargets(shape, plan.edgeTargets, plan.size, "chamferEdges()");
|
|
32444
|
+
return applyNativeTruckChamferTargets(shape, plan.edgeTargets ?? [], plan.size, "chamferEdges()");
|
|
31833
32445
|
}
|
|
31834
32446
|
function resolvedEdgeFeatureSelectionToTarget(selection) {
|
|
31835
32447
|
return {
|
|
@@ -37846,8 +38458,8 @@ function resolveShapeFace(plan, name) {
|
|
|
37846
38458
|
const DEPRECATED_SIDE_NAMES = {
|
|
37847
38459
|
"side-left": "left",
|
|
37848
38460
|
"side-right": "right",
|
|
37849
|
-
"side-top": "
|
|
37850
|
-
"side-bottom": "
|
|
38461
|
+
"side-top": "back",
|
|
38462
|
+
"side-bottom": "front"
|
|
37851
38463
|
};
|
|
37852
38464
|
function explainMissingShapeFace(plan, name) {
|
|
37853
38465
|
const table = resolveShapeFaceTable(plan);
|
|
@@ -38926,11 +39538,14 @@ class ShapeGroup {
|
|
|
38926
39538
|
}
|
|
38927
39539
|
/** Move the entire group by (x, y, z). All children move together as a unit. */
|
|
38928
39540
|
translate(x2, y2, z2) {
|
|
38929
|
-
const
|
|
39541
|
+
const dx = requireFiniteNumber(x2, "ShapeGroup.translate() x");
|
|
39542
|
+
const dy = requireFiniteNumber(y2, "ShapeGroup.translate() y");
|
|
39543
|
+
const dz = requireFiniteNumber(z2, "ShapeGroup.translate() z");
|
|
39544
|
+
const matrix = Transform.translation(dx, dy, dz).toArray();
|
|
38930
39545
|
return this.mapChildrenTransform((c2) => {
|
|
38931
|
-
if (c2 instanceof ShapeGroup) return c2.translate(
|
|
38932
|
-
if (c2 instanceof Shape) return c2.translate(
|
|
38933
|
-
return c2.translate(
|
|
39546
|
+
if (c2 instanceof ShapeGroup) return c2.translate(dx, dy, dz);
|
|
39547
|
+
if (c2 instanceof Shape) return c2.translate(dx, dy, dz);
|
|
39548
|
+
return c2.translate(dx, dy);
|
|
38934
39549
|
}, matrix);
|
|
38935
39550
|
}
|
|
38936
39551
|
/** Compute combined bounding box of all 3D children */
|
|
@@ -38966,17 +39581,23 @@ class ShapeGroup {
|
|
|
38966
39581
|
return { min: bb.min, max: bb.max };
|
|
38967
39582
|
}
|
|
38968
39583
|
resolveRotatePoint(point) {
|
|
38969
|
-
if (Array.isArray(point)) return
|
|
39584
|
+
if (Array.isArray(point)) return requireFiniteVec3$1(point, "ShapeGroup.rotateAroundTo() point");
|
|
38970
39585
|
const bb = this._bbox();
|
|
38971
39586
|
return resolveAnchor3D(bb.min, bb.max, point);
|
|
38972
39587
|
}
|
|
38973
39588
|
/** Move the group so its bounding-box min corner lands at the given coordinate. */
|
|
38974
39589
|
moveTo(x2, y2, z2) {
|
|
39590
|
+
const targetX = requireFiniteNumber(x2, "ShapeGroup.moveTo() x");
|
|
39591
|
+
const targetY = requireFiniteNumber(y2, "ShapeGroup.moveTo() y");
|
|
39592
|
+
const targetZ = requireFiniteNumber(z2, "ShapeGroup.moveTo() z");
|
|
38975
39593
|
const bb = this._bbox();
|
|
38976
|
-
return this.translate(
|
|
39594
|
+
return this.translate(targetX - bb.min[0], targetY - bb.min[1], targetZ - bb.min[2]);
|
|
38977
39595
|
}
|
|
38978
39596
|
/** Move the group relative to another part's bounding-box min corner. */
|
|
38979
39597
|
moveToLocal(target, x2, y2, z2) {
|
|
39598
|
+
const localX = requireFiniteNumber(x2, "ShapeGroup.moveToLocal() x");
|
|
39599
|
+
const localY = requireFiniteNumber(y2, "ShapeGroup.moveToLocal() y");
|
|
39600
|
+
const localZ = requireFiniteNumber(z2, "ShapeGroup.moveToLocal() z");
|
|
38980
39601
|
let tbb;
|
|
38981
39602
|
if (target instanceof ShapeGroup) {
|
|
38982
39603
|
tbb = target._bbox();
|
|
@@ -38984,7 +39605,7 @@ class ShapeGroup {
|
|
|
38984
39605
|
const bb = target.boundingBox();
|
|
38985
39606
|
tbb = { min: bb.min };
|
|
38986
39607
|
}
|
|
38987
|
-
return this.moveTo(tbb.min[0] +
|
|
39608
|
+
return this.moveTo(tbb.min[0] + localX, tbb.min[1] + localY, tbb.min[2] + localZ);
|
|
38988
39609
|
}
|
|
38989
39610
|
/**
|
|
38990
39611
|
* Attach this group to a face or anchor on another part.
|
|
@@ -39013,9 +39634,10 @@ class ShapeGroup {
|
|
|
39013
39634
|
const sp = resolveAnchor3D(sbb.min, sbb.max, selfAnchor);
|
|
39014
39635
|
let dx = tp[0] - sp[0], dy = tp[1] - sp[1], dz = tp[2] - sp[2];
|
|
39015
39636
|
if (offset) {
|
|
39016
|
-
|
|
39017
|
-
|
|
39018
|
-
|
|
39637
|
+
const offsetPoint = requireFiniteVec3$1(offset, "ShapeGroup.attachTo() offset");
|
|
39638
|
+
dx += offsetPoint[0];
|
|
39639
|
+
dy += offsetPoint[1];
|
|
39640
|
+
dz += offsetPoint[2];
|
|
39019
39641
|
}
|
|
39020
39642
|
return this.translate(dx, dy, dz);
|
|
39021
39643
|
}
|
|
@@ -39024,7 +39646,9 @@ class ShapeGroup {
|
|
|
39024
39646
|
* See Shape.onFace() for full documentation.
|
|
39025
39647
|
*/
|
|
39026
39648
|
onFace(parent, face, opts = {}) {
|
|
39027
|
-
const u2 = opts.u ?? 0,
|
|
39649
|
+
const u2 = requireFiniteNumber(opts.u ?? 0, "ShapeGroup.onFace() u");
|
|
39650
|
+
const v = requireFiniteNumber(opts.v ?? 0, "ShapeGroup.onFace() v");
|
|
39651
|
+
const p2 = requireFiniteNumber(opts.protrude ?? 0, "ShapeGroup.onFace() protrude");
|
|
39028
39652
|
const opp = { front: "back", back: "front", left: "right", right: "left", top: "bottom", bottom: "top" };
|
|
39029
39653
|
const uvMap = {
|
|
39030
39654
|
front: (u22, v2, p22) => [u22, -p22, v2],
|
|
@@ -39063,20 +39687,31 @@ class ShapeGroup {
|
|
|
39063
39687
|
}
|
|
39064
39688
|
/** Rotate around an arbitrary axis, optionally through a pivot point. */
|
|
39065
39689
|
rotateAroundAxis(axis, angleDeg, pivot = [0, 0, 0]) {
|
|
39066
|
-
|
|
39690
|
+
const rotateAxis = requireNonZeroFiniteVec3(axis, "ShapeGroup.rotateAroundAxis() axis");
|
|
39691
|
+
const degrees = requireFiniteNumber(angleDeg, "ShapeGroup.rotateAroundAxis() angleDeg");
|
|
39692
|
+
const rotatePivot = requireFiniteVec3$1(pivot, "ShapeGroup.rotateAroundAxis() pivot");
|
|
39693
|
+
return this.transform(Transform.rotationAxis(rotateAxis, degrees, rotatePivot));
|
|
39067
39694
|
}
|
|
39068
39695
|
/**
|
|
39069
39696
|
* Rotate around an axis until a moving point reaches the target line/plane defined by the axis and target point.
|
|
39070
39697
|
* ShapeGroup string points use built-in anchors only.
|
|
39071
39698
|
*/
|
|
39072
39699
|
rotateAroundTo(axis, pivot, movingPoint, targetPoint, options = {}) {
|
|
39700
|
+
const rotateAxis = requireNonZeroFiniteVec3(axis, "ShapeGroup.rotateAroundTo() axis");
|
|
39701
|
+
const rotatePivot = requireFiniteVec3$1(pivot, "ShapeGroup.rotateAroundTo() pivot");
|
|
39073
39702
|
return this.transform(
|
|
39074
|
-
Transform.rotateAroundTo(
|
|
39703
|
+
Transform.rotateAroundTo(
|
|
39704
|
+
rotateAxis,
|
|
39705
|
+
rotatePivot,
|
|
39706
|
+
this.resolveRotatePoint(movingPoint),
|
|
39707
|
+
this.resolveRotatePoint(targetPoint),
|
|
39708
|
+
options
|
|
39709
|
+
)
|
|
39075
39710
|
);
|
|
39076
39711
|
}
|
|
39077
39712
|
/** Reorient the group so its local Z axis points along `direction`. */
|
|
39078
39713
|
pointAlong(direction) {
|
|
39079
|
-
const [dx, dy, dz] = direction;
|
|
39714
|
+
const [dx, dy, dz] = requireNonZeroFiniteVec3(direction, "ShapeGroup.pointAlong() direction");
|
|
39080
39715
|
const len = Math.sqrt(dx * dx + dy * dy + dz * dz) || 1;
|
|
39081
39716
|
const nx = dx / len, ny = dy / len, nz = dz / len;
|
|
39082
39717
|
const cx = -ny, cy = nx, cz = 0;
|
|
@@ -39091,11 +39726,11 @@ class ShapeGroup {
|
|
|
39091
39726
|
}
|
|
39092
39727
|
/** Apply a 4x4 transform matrix or `Transform` to all 3D children. */
|
|
39093
39728
|
transform(m2) {
|
|
39094
|
-
const matrix = m2 instanceof Transform ? m2.toArray() : m2;
|
|
39729
|
+
const matrix = m2 instanceof Transform ? m2.toArray() : requireFiniteMat4(m2, "ShapeGroup.transform() matrix");
|
|
39095
39730
|
const next = new ShapeGroup(
|
|
39096
39731
|
this.children.map((c2) => {
|
|
39097
|
-
if (c2 instanceof ShapeGroup) return c2.transform(
|
|
39098
|
-
if (c2 instanceof Shape) return c2.transform(
|
|
39732
|
+
if (c2 instanceof ShapeGroup) return c2.transform(matrix);
|
|
39733
|
+
if (c2 instanceof Shape) return c2.transform(matrix);
|
|
39099
39734
|
throw new Error(
|
|
39100
39735
|
"ShapeGroup.transform only supports 3D children (Shape/ShapeGroup). For Sketch children, use 2D transforms (translate/rotate/scale/mirror)."
|
|
39101
39736
|
);
|
|
@@ -39108,25 +39743,28 @@ class ShapeGroup {
|
|
|
39108
39743
|
}
|
|
39109
39744
|
/** Scale uniformly or per-axis from the group's bounding-box center. */
|
|
39110
39745
|
scale(v) {
|
|
39111
|
-
|
|
39746
|
+
const scale2 = requireNonZeroFiniteScale3(v, "ShapeGroup.scale() scale");
|
|
39747
|
+
return this.scaleAround(this._bboxCenter(), scale2);
|
|
39112
39748
|
}
|
|
39113
39749
|
/** Scale uniformly or per-axis from an explicit pivot point. */
|
|
39114
39750
|
scaleAround(pivot, v) {
|
|
39115
|
-
const
|
|
39116
|
-
|
|
39751
|
+
const scale2 = requireNonZeroFiniteScale3(v, "ShapeGroup.scaleAround() scale");
|
|
39752
|
+
const scalePivot = requireFiniteVec3$1(pivot, "ShapeGroup.scaleAround() pivot");
|
|
39753
|
+
const matrix = Transform.scale(scale2).toArray();
|
|
39754
|
+
if (scalePivot[0] === 0 && scalePivot[1] === 0 && scalePivot[2] === 0) {
|
|
39117
39755
|
return this.mapChildrenTransform((c2) => {
|
|
39118
|
-
if (c2 instanceof ShapeGroup) return c2.scaleAround([0, 0, 0],
|
|
39119
|
-
if (c2 instanceof Shape) return c2.scaleAround([0, 0, 0],
|
|
39120
|
-
return c2.scale(
|
|
39756
|
+
if (c2 instanceof ShapeGroup) return c2.scaleAround([0, 0, 0], scale2);
|
|
39757
|
+
if (c2 instanceof Shape) return c2.scaleAround([0, 0, 0], scale2);
|
|
39758
|
+
return c2.scale([scale2[0], scale2[1]]);
|
|
39121
39759
|
}, matrix);
|
|
39122
39760
|
}
|
|
39123
|
-
const moved = this.translate(-
|
|
39761
|
+
const moved = this.translate(-scalePivot[0], -scalePivot[1], -scalePivot[2]);
|
|
39124
39762
|
const scaled = moved.mapChildrenTransform((c2) => {
|
|
39125
|
-
if (c2 instanceof ShapeGroup) return c2.scaleAround([0, 0, 0],
|
|
39126
|
-
if (c2 instanceof Shape) return c2.scaleAround([0, 0, 0],
|
|
39127
|
-
return c2.scale(
|
|
39763
|
+
if (c2 instanceof ShapeGroup) return c2.scaleAround([0, 0, 0], scale2);
|
|
39764
|
+
if (c2 instanceof Shape) return c2.scaleAround([0, 0, 0], scale2);
|
|
39765
|
+
return c2.scale([scale2[0], scale2[1]]);
|
|
39128
39766
|
}, matrix);
|
|
39129
|
-
return scaled.translate(
|
|
39767
|
+
return scaled.translate(scalePivot[0], scalePivot[1], scalePivot[2]);
|
|
39130
39768
|
}
|
|
39131
39769
|
/** Mirror across a plane through the group's bounding-box center. */
|
|
39132
39770
|
mirror(normal) {
|
|
@@ -39134,21 +39772,23 @@ class ShapeGroup {
|
|
|
39134
39772
|
}
|
|
39135
39773
|
/** Mirror across a plane through an explicit point. */
|
|
39136
39774
|
mirrorThrough(point, normal) {
|
|
39137
|
-
const
|
|
39138
|
-
|
|
39775
|
+
const mirrorPoint = requireFiniteVec3$1(point, "ShapeGroup.mirrorThrough() point");
|
|
39776
|
+
const mirrorNormal = requireNonZeroFiniteVec3(normal, "ShapeGroup.mirrorThrough() normal");
|
|
39777
|
+
const matrix = mirrorPlaneMatrix(mirrorNormal);
|
|
39778
|
+
if (mirrorPoint[0] === 0 && mirrorPoint[1] === 0 && mirrorPoint[2] === 0) {
|
|
39139
39779
|
return this.mapChildrenTransform((c2) => {
|
|
39140
|
-
if (c2 instanceof ShapeGroup) return c2.mirrorThrough([0, 0, 0],
|
|
39141
|
-
if (c2 instanceof Shape) return c2.mirrorThrough([0, 0, 0],
|
|
39142
|
-
return c2.mirror([
|
|
39780
|
+
if (c2 instanceof ShapeGroup) return c2.mirrorThrough([0, 0, 0], mirrorNormal);
|
|
39781
|
+
if (c2 instanceof Shape) return c2.mirrorThrough([0, 0, 0], mirrorNormal);
|
|
39782
|
+
return c2.mirror([mirrorNormal[0], mirrorNormal[1]]);
|
|
39143
39783
|
}, matrix);
|
|
39144
39784
|
}
|
|
39145
|
-
const moved = this.translate(-
|
|
39785
|
+
const moved = this.translate(-mirrorPoint[0], -mirrorPoint[1], -mirrorPoint[2]);
|
|
39146
39786
|
const mirrored = moved.mapChildrenTransform((c2) => {
|
|
39147
|
-
if (c2 instanceof ShapeGroup) return c2.mirrorThrough([0, 0, 0],
|
|
39148
|
-
if (c2 instanceof Shape) return c2.mirrorThrough([0, 0, 0],
|
|
39149
|
-
return c2.mirror([
|
|
39787
|
+
if (c2 instanceof ShapeGroup) return c2.mirrorThrough([0, 0, 0], mirrorNormal);
|
|
39788
|
+
if (c2 instanceof Shape) return c2.mirrorThrough([0, 0, 0], mirrorNormal);
|
|
39789
|
+
return c2.mirror([mirrorNormal[0], mirrorNormal[1]]);
|
|
39150
39790
|
}, matrix);
|
|
39151
|
-
return mirrored.translate(
|
|
39791
|
+
return mirrored.translate(mirrorPoint[0], mirrorPoint[1], mirrorPoint[2]);
|
|
39152
39792
|
}
|
|
39153
39793
|
/** Return a copy of the group with the given display color applied to each child. */
|
|
39154
39794
|
color(hex) {
|
|
@@ -39220,14 +39860,16 @@ class ShapeGroup {
|
|
|
39220
39860
|
* ```
|
|
39221
39861
|
*/
|
|
39222
39862
|
placeReference(ref, target, offset) {
|
|
39863
|
+
const targetPoint = requireFiniteVec3$1(target, "ShapeGroup.placeReference() target");
|
|
39864
|
+
const offsetPoint = offset === void 0 ? void 0 : requireFiniteVec3$1(offset, "ShapeGroup.placeReference() offset");
|
|
39223
39865
|
const sourcePoint = this.referencePoint(ref);
|
|
39224
|
-
let dx =
|
|
39225
|
-
let dy =
|
|
39226
|
-
let dz =
|
|
39227
|
-
if (
|
|
39228
|
-
dx +=
|
|
39229
|
-
dy +=
|
|
39230
|
-
dz +=
|
|
39866
|
+
let dx = targetPoint[0] - sourcePoint[0];
|
|
39867
|
+
let dy = targetPoint[1] - sourcePoint[1];
|
|
39868
|
+
let dz = targetPoint[2] - sourcePoint[2];
|
|
39869
|
+
if (offsetPoint) {
|
|
39870
|
+
dx += offsetPoint[0];
|
|
39871
|
+
dy += offsetPoint[1];
|
|
39872
|
+
dz += offsetPoint[2];
|
|
39231
39873
|
}
|
|
39232
39874
|
return this.translate(dx, dy, dz);
|
|
39233
39875
|
}
|
|
@@ -40159,14 +40801,21 @@ function attachTopologyRewritePropagation(plan, propagation) {
|
|
|
40159
40801
|
}
|
|
40160
40802
|
return cloneNodeWithPropagation(plan, propagation);
|
|
40161
40803
|
}
|
|
40804
|
+
const DEFERRED_EDGE_SELECTION_MARKER = Symbol.for("forgecad.deferredEdgeSelection");
|
|
40805
|
+
function isDeferredEdgeSelection(value) {
|
|
40806
|
+
return Boolean(value && typeof value === "object" && value[DEFERRED_EDGE_SELECTION_MARKER] === true);
|
|
40807
|
+
}
|
|
40162
40808
|
function distSq$1(a2, b) {
|
|
40163
|
-
const dx = a2[0] - b[0]
|
|
40809
|
+
const dx = a2[0] - b[0];
|
|
40810
|
+
const dy = a2[1] - b[1];
|
|
40811
|
+
const dz = a2[2] - b[2];
|
|
40164
40812
|
return dx * dx + dy * dy + dz * dz;
|
|
40165
40813
|
}
|
|
40166
40814
|
function absDot(a2, b) {
|
|
40167
40815
|
return Math.abs(a2[0] * b[0] + a2[1] * b[1] + a2[2] * b[2]);
|
|
40168
40816
|
}
|
|
40169
40817
|
function coalesceEdges(segments, tolerance = 0.01) {
|
|
40818
|
+
if (segments.some(isDeferredEdgeSelection)) return segments;
|
|
40170
40819
|
if (segments.length <= 1) return segments;
|
|
40171
40820
|
const used = new Uint8Array(segments.length);
|
|
40172
40821
|
const result = [];
|
|
@@ -40889,16 +41538,6 @@ function mirrorMatrix(normal) {
|
|
|
40889
41538
|
const m22 = 1 - 2 * nz * nz;
|
|
40890
41539
|
return [m00, m10, m20, 0, m01, m11, m21, 0, m02, m12, m22, 0, 0, 0, 0, 1];
|
|
40891
41540
|
}
|
|
40892
|
-
function normalizeShapeScale(v) {
|
|
40893
|
-
const scale2 = typeof v === "number" ? [v, v, v] : v;
|
|
40894
|
-
if (!Number.isFinite(scale2[0]) || !Number.isFinite(scale2[1]) || !Number.isFinite(scale2[2])) {
|
|
40895
|
-
return null;
|
|
40896
|
-
}
|
|
40897
|
-
if (Math.abs(scale2[0]) < 1e-12 || Math.abs(scale2[1]) < 1e-12 || Math.abs(scale2[2]) < 1e-12) {
|
|
40898
|
-
return null;
|
|
40899
|
-
}
|
|
40900
|
-
return [scale2[0], scale2[1], scale2[2]];
|
|
40901
|
-
}
|
|
40902
41541
|
function dotVec3$1(a2, b) {
|
|
40903
41542
|
return a2[0] * b[0] + a2[1] * b[1] + a2[2] * b[2];
|
|
40904
41543
|
}
|
|
@@ -42051,7 +42690,7 @@ function withBaseDimensionsAndMergedSourceSpans(base, sources, out, preserveOutp
|
|
|
42051
42690
|
return result;
|
|
42052
42691
|
}
|
|
42053
42692
|
function resolveRotationPoint(shape, point) {
|
|
42054
|
-
if (Array.isArray(point)) return
|
|
42693
|
+
if (Array.isArray(point)) return requireFiniteVec3$1(point, "rotateAroundTo(): point");
|
|
42055
42694
|
return shape.referencePoint(point);
|
|
42056
42695
|
}
|
|
42057
42696
|
function setShapePlacementReferences(shape, refs, options = {}) {
|
|
@@ -42779,7 +43418,9 @@ class Shape {
|
|
|
42779
43418
|
edgesOf(faceLabel, options) {
|
|
42780
43419
|
const faceRefs = this._resolveFaceLabels(faceLabel);
|
|
42781
43420
|
const result = uniqueEdgeSegments(
|
|
42782
|
-
faceRefs.flatMap((faceRef) =>
|
|
43421
|
+
faceRefs.flatMap((faceRef) => {
|
|
43422
|
+
return edgesOfFace(this, faceRef, options, (name) => this._resolveFaceLabel(name));
|
|
43423
|
+
})
|
|
42783
43424
|
);
|
|
42784
43425
|
if (result.length === 0) {
|
|
42785
43426
|
throw new Error(
|
|
@@ -42827,7 +43468,11 @@ class Shape {
|
|
|
42827
43468
|
const refsA = this._resolveFaceLabels(faceA);
|
|
42828
43469
|
const bNames = Array.isArray(faceB) ? faceB : [faceB];
|
|
42829
43470
|
const refBs = bNames.flatMap((name) => this._resolveFaceLabels(name));
|
|
42830
|
-
const result = uniqueEdgeSegments(
|
|
43471
|
+
const result = uniqueEdgeSegments(
|
|
43472
|
+
refsA.flatMap((refA) => {
|
|
43473
|
+
return edgesBetweenFaces(this, refA, refBs);
|
|
43474
|
+
})
|
|
43475
|
+
);
|
|
42831
43476
|
if (result.length === 0) {
|
|
42832
43477
|
const bStr = bNames.length === 1 ? `'${bNames[0]}'` : `[${bNames.map((n) => `'${n}'`).join(", ")}]`;
|
|
42833
43478
|
throw new Error(
|
|
@@ -42891,14 +43536,16 @@ class Shape {
|
|
|
42891
43536
|
* ```
|
|
42892
43537
|
*/
|
|
42893
43538
|
placeReference(ref, target, offset) {
|
|
43539
|
+
const targetPoint = requireFiniteVec3$1(target, "Shape.placeReference() target");
|
|
43540
|
+
const offsetPoint = offset === void 0 ? void 0 : requireFiniteVec3$1(offset, "Shape.placeReference() offset");
|
|
42894
43541
|
const sourcePoint = this.referencePoint(ref);
|
|
42895
|
-
let dx =
|
|
42896
|
-
let dy =
|
|
42897
|
-
let dz =
|
|
42898
|
-
if (
|
|
42899
|
-
dx +=
|
|
42900
|
-
dy +=
|
|
42901
|
-
dz +=
|
|
43542
|
+
let dx = targetPoint[0] - sourcePoint[0];
|
|
43543
|
+
let dy = targetPoint[1] - sourcePoint[1];
|
|
43544
|
+
let dz = targetPoint[2] - sourcePoint[2];
|
|
43545
|
+
if (offsetPoint) {
|
|
43546
|
+
dx += offsetPoint[0];
|
|
43547
|
+
dy += offsetPoint[1];
|
|
43548
|
+
dz += offsetPoint[2];
|
|
42902
43549
|
}
|
|
42903
43550
|
return this.translate(dx, dy, dz);
|
|
42904
43551
|
}
|
|
@@ -42910,27 +43557,39 @@ class Shape {
|
|
|
42910
43557
|
* Example: `shape.translatePolar(50, 30)` moves 50mm at 30 degrees from +X.
|
|
42911
43558
|
*/
|
|
42912
43559
|
translatePolar(radius, angleDeg, z2 = 0) {
|
|
42913
|
-
const
|
|
42914
|
-
|
|
43560
|
+
const r = requireFiniteNumber(radius, "Shape.translatePolar() radius");
|
|
43561
|
+
const angle = requireFiniteNumber(angleDeg, "Shape.translatePolar() angleDeg");
|
|
43562
|
+
const zOffset = requireFiniteNumber(z2, "Shape.translatePolar() z");
|
|
43563
|
+
const rad = angle * (Math.PI / 180);
|
|
43564
|
+
return this.translate(r * Math.cos(rad), r * Math.sin(rad), zOffset);
|
|
42915
43565
|
}
|
|
42916
43566
|
/** Move the shape relative to its current position. All transforms are immutable and return new shapes. */
|
|
42917
43567
|
translate(x2, y2, z2) {
|
|
42918
|
-
const
|
|
43568
|
+
const dx = requireFiniteNumber(x2, "Shape.translate() x");
|
|
43569
|
+
const dy = requireFiniteNumber(y2, "Shape.translate() y");
|
|
43570
|
+
const dz = requireFiniteNumber(z2, "Shape.translate() z");
|
|
43571
|
+
const nextPlan = appendShapeCompileTransform(getShapeCompilePlanInternal(this), { kind: "translate", x: dx, y: dy, z: dz });
|
|
42919
43572
|
return setShapeCompilePlanInternal(
|
|
42920
|
-
withTransformedDimensions(this, buildShapeFromCompilePlan(nextPlan, this.colorHex), Transform.translation(
|
|
43573
|
+
withTransformedDimensions(this, buildShapeFromCompilePlan(nextPlan, this.colorHex), Transform.translation(dx, dy, dz).toArray()),
|
|
42921
43574
|
nextPlan
|
|
42922
43575
|
);
|
|
42923
43576
|
}
|
|
42924
43577
|
/** Position the shape so its bounding box min corner is at the given global coordinate. */
|
|
42925
43578
|
moveTo(x2, y2, z2) {
|
|
43579
|
+
const targetX = requireFiniteNumber(x2, "Shape.moveTo() x");
|
|
43580
|
+
const targetY = requireFiniteNumber(y2, "Shape.moveTo() y");
|
|
43581
|
+
const targetZ = requireFiniteNumber(z2, "Shape.moveTo() z");
|
|
42926
43582
|
const bb = this.boundingBox();
|
|
42927
|
-
return this.translate(
|
|
43583
|
+
return this.translate(targetX - bb.min[0], targetY - bb.min[1], targetZ - bb.min[2]);
|
|
42928
43584
|
}
|
|
42929
43585
|
/** Position the shape relative to another shape's local coordinate system (bounding box min corner). */
|
|
42930
43586
|
moveToLocal(target, x2, y2, z2) {
|
|
43587
|
+
const localX = requireFiniteNumber(x2, "Shape.moveToLocal() x");
|
|
43588
|
+
const localY = requireFiniteNumber(y2, "Shape.moveToLocal() y");
|
|
43589
|
+
const localZ = requireFiniteNumber(z2, "Shape.moveToLocal() z");
|
|
42931
43590
|
const s = "toShape" in target ? target.toShape() : target;
|
|
42932
43591
|
const tbb = s.boundingBox();
|
|
42933
|
-
return this.moveTo(tbb.min[0] +
|
|
43592
|
+
return this.moveTo(tbb.min[0] + localX, tbb.min[1] + localY, tbb.min[2] + localZ);
|
|
42934
43593
|
}
|
|
42935
43594
|
/** Rotate around an arbitrary axis through the origin. */
|
|
42936
43595
|
rotate(axis, angleDeg, options) {
|
|
@@ -42959,7 +43618,7 @@ class Shape {
|
|
|
42959
43618
|
}
|
|
42960
43619
|
/** Apply a 4x4 affine transform matrix (column-major) or a Transform object. */
|
|
42961
43620
|
transform(m2) {
|
|
42962
|
-
const mat = m2 instanceof Transform ? m2.toArray() : m2;
|
|
43621
|
+
const mat = m2 instanceof Transform ? m2.toArray() : requireFiniteMat4(m2, "Shape.transform() matrix");
|
|
42963
43622
|
const steps = rigidTransformStepsFromMatrix(mat);
|
|
42964
43623
|
if (steps == null) {
|
|
42965
43624
|
throw new Error(
|
|
@@ -42971,23 +43630,20 @@ class Shape {
|
|
|
42971
43630
|
}
|
|
42972
43631
|
/** Scale the shape uniformly or per-axis from the shape's bounding box center. Accepts a single number or [x, y, z] array. */
|
|
42973
43632
|
scale(v) {
|
|
43633
|
+
const scale2 = requireNonZeroFiniteScale3(v, "Shape.scale() scale");
|
|
42974
43634
|
const bb = this.boundingBox();
|
|
42975
43635
|
const center = [
|
|
42976
43636
|
(bb.min[0] + bb.max[0]) / 2,
|
|
42977
43637
|
(bb.min[1] + bb.max[1]) / 2,
|
|
42978
43638
|
(bb.min[2] + bb.max[2]) / 2
|
|
42979
43639
|
];
|
|
42980
|
-
return this.scaleAround(center,
|
|
43640
|
+
return this.scaleAround(center, scale2);
|
|
42981
43641
|
}
|
|
42982
43642
|
/** Scale the shape uniformly or per-axis from an explicit pivot point. */
|
|
42983
43643
|
scaleAround(pivot, v) {
|
|
42984
|
-
const scale2 =
|
|
42985
|
-
|
|
42986
|
-
|
|
42987
|
-
`Shape.scaleAround() received a degenerate scale value (${JSON.stringify(v)}). All scale components must be finite and non-zero.`
|
|
42988
|
-
);
|
|
42989
|
-
}
|
|
42990
|
-
if (pivot[0] === 0 && pivot[1] === 0 && pivot[2] === 0) {
|
|
43644
|
+
const scale2 = requireNonZeroFiniteScale3(v, "Shape.scaleAround() scale");
|
|
43645
|
+
const scalePivot = requireFiniteVec3$1(pivot, "Shape.scaleAround() pivot");
|
|
43646
|
+
if (scalePivot[0] === 0 && scalePivot[1] === 0 && scalePivot[2] === 0) {
|
|
42991
43647
|
const nextPlan2 = appendShapeCompileTransform(getShapeCompilePlanInternal(this), {
|
|
42992
43648
|
kind: "scale",
|
|
42993
43649
|
x: scale2[0],
|
|
@@ -42995,11 +43651,11 @@ class Shape {
|
|
|
42995
43651
|
z: scale2[2]
|
|
42996
43652
|
});
|
|
42997
43653
|
return setShapeCompilePlanInternal(
|
|
42998
|
-
withTransformedDimensions(this, buildShapeFromCompilePlan(nextPlan2, this.colorHex), Transform.scale(
|
|
43654
|
+
withTransformedDimensions(this, buildShapeFromCompilePlan(nextPlan2, this.colorHex), Transform.scale(scale2).toArray()),
|
|
42999
43655
|
nextPlan2
|
|
43000
43656
|
);
|
|
43001
43657
|
}
|
|
43002
|
-
const translated = this.translate(-
|
|
43658
|
+
const translated = this.translate(-scalePivot[0], -scalePivot[1], -scalePivot[2]);
|
|
43003
43659
|
const nextPlan = appendShapeCompileTransform(getShapeCompilePlanInternal(translated), {
|
|
43004
43660
|
kind: "scale",
|
|
43005
43661
|
x: scale2[0],
|
|
@@ -43007,10 +43663,10 @@ class Shape {
|
|
|
43007
43663
|
z: scale2[2]
|
|
43008
43664
|
});
|
|
43009
43665
|
const scaled = setShapeCompilePlanInternal(
|
|
43010
|
-
withTransformedDimensions(translated, buildShapeFromCompilePlan(nextPlan, translated.colorHex), Transform.scale(
|
|
43666
|
+
withTransformedDimensions(translated, buildShapeFromCompilePlan(nextPlan, translated.colorHex), Transform.scale(scale2).toArray()),
|
|
43011
43667
|
nextPlan
|
|
43012
43668
|
);
|
|
43013
|
-
return scaled.translate(
|
|
43669
|
+
return scaled.translate(scalePivot[0], scalePivot[1], scalePivot[2]);
|
|
43014
43670
|
}
|
|
43015
43671
|
/** Mirror across a plane through the shape's bounding box center, defined by its normal vector. */
|
|
43016
43672
|
mirror(normal) {
|
|
@@ -43024,32 +43680,34 @@ class Shape {
|
|
|
43024
43680
|
}
|
|
43025
43681
|
/** Mirror across a plane through an explicit point, defined by its normal vector. */
|
|
43026
43682
|
mirrorThrough(point, normal) {
|
|
43027
|
-
|
|
43683
|
+
const mirrorPoint = requireFiniteVec3$1(point, "Shape.mirrorThrough() point");
|
|
43684
|
+
const mirrorNormal = requireNonZeroFiniteVec3(normal, "Shape.mirrorThrough() normal");
|
|
43685
|
+
if (mirrorPoint[0] === 0 && mirrorPoint[1] === 0 && mirrorPoint[2] === 0) {
|
|
43028
43686
|
const transformedPlan2 = appendShapeCompileTransform(getShapeCompilePlanInternal(this), {
|
|
43029
43687
|
kind: "mirror",
|
|
43030
|
-
normalX:
|
|
43031
|
-
normalY:
|
|
43032
|
-
normalZ:
|
|
43688
|
+
normalX: mirrorNormal[0],
|
|
43689
|
+
normalY: mirrorNormal[1],
|
|
43690
|
+
normalZ: mirrorNormal[2]
|
|
43033
43691
|
});
|
|
43034
43692
|
const nextPlan2 = wrapRepeatedShapeCompilePlan(transformedPlan2, "mirror");
|
|
43035
43693
|
return setShapeCompilePlanInternal(
|
|
43036
|
-
withTransformedDimensions(this, buildShapeFromCompilePlan(nextPlan2, this.colorHex), mirrorMatrix(
|
|
43694
|
+
withTransformedDimensions(this, buildShapeFromCompilePlan(nextPlan2, this.colorHex), mirrorMatrix(mirrorNormal)),
|
|
43037
43695
|
nextPlan2
|
|
43038
43696
|
);
|
|
43039
43697
|
}
|
|
43040
|
-
const translated = this.translate(-
|
|
43698
|
+
const translated = this.translate(-mirrorPoint[0], -mirrorPoint[1], -mirrorPoint[2]);
|
|
43041
43699
|
const transformedPlan = appendShapeCompileTransform(getShapeCompilePlanInternal(translated), {
|
|
43042
43700
|
kind: "mirror",
|
|
43043
|
-
normalX:
|
|
43044
|
-
normalY:
|
|
43045
|
-
normalZ:
|
|
43701
|
+
normalX: mirrorNormal[0],
|
|
43702
|
+
normalY: mirrorNormal[1],
|
|
43703
|
+
normalZ: mirrorNormal[2]
|
|
43046
43704
|
});
|
|
43047
43705
|
const nextPlan = wrapRepeatedShapeCompilePlan(transformedPlan, "mirror");
|
|
43048
43706
|
const mirrored = setShapeCompilePlanInternal(
|
|
43049
|
-
withTransformedDimensions(translated, buildShapeFromCompilePlan(nextPlan, translated.colorHex), mirrorMatrix(
|
|
43707
|
+
withTransformedDimensions(translated, buildShapeFromCompilePlan(nextPlan, translated.colorHex), mirrorMatrix(mirrorNormal)),
|
|
43050
43708
|
nextPlan
|
|
43051
43709
|
);
|
|
43052
|
-
return mirrored.translate(
|
|
43710
|
+
return mirrored.translate(mirrorPoint[0], mirrorPoint[1], mirrorPoint[2]);
|
|
43053
43711
|
}
|
|
43054
43712
|
/**
|
|
43055
43713
|
* Reorient a shape so its primary axis (Z) points along the given direction.
|
|
@@ -43059,7 +43717,7 @@ class Shape {
|
|
|
43059
43717
|
* Example: cylinder(40, 5).pointAlong([1, 0, 0]) — lays cylinder along X, starting at origin
|
|
43060
43718
|
*/
|
|
43061
43719
|
pointAlong(direction) {
|
|
43062
|
-
const [dx, dy, dz] = direction;
|
|
43720
|
+
const [dx, dy, dz] = requireNonZeroFiniteVec3(direction, "Shape.pointAlong() direction");
|
|
43063
43721
|
const len = Math.sqrt(dx * dx + dy * dy + dz * dz) || 1;
|
|
43064
43722
|
const nx = dx / len, ny = dy / len, nz = dz / len;
|
|
43065
43723
|
const cx = -ny, cy = nx, cz = 0;
|
|
@@ -43078,18 +43736,21 @@ class Shape {
|
|
|
43078
43736
|
* @internal Prefer rotate(), rotateX(), rotateY(), rotateZ() for public use.
|
|
43079
43737
|
*/
|
|
43080
43738
|
rotateAroundAxis(axis, angleDeg, pivot = [0, 0, 0]) {
|
|
43081
|
-
const
|
|
43082
|
-
const
|
|
43083
|
-
const
|
|
43739
|
+
const rotateAxis = requireNonZeroFiniteVec3(axis, "Shape.rotateAroundAxis() axis");
|
|
43740
|
+
const degrees = requireFiniteNumber(angleDeg, "Shape.rotateAroundAxis() angleDeg");
|
|
43741
|
+
const rotatePivot = requireFiniteVec3$1(pivot, "Shape.rotateAroundAxis() pivot");
|
|
43742
|
+
const len = Math.sqrt(rotateAxis[0] ** 2 + rotateAxis[1] ** 2 + rotateAxis[2] ** 2) || 1;
|
|
43743
|
+
const normalizedAxis = [rotateAxis[0] / len, rotateAxis[1] / len, rotateAxis[2] / len];
|
|
43744
|
+
const matrix = rotationAroundAxisMatrix(normalizedAxis, degrees, rotatePivot);
|
|
43084
43745
|
const nextPlan = appendShapeCompileTransform(getShapeCompilePlanInternal(this), {
|
|
43085
43746
|
kind: "rotateAround",
|
|
43086
43747
|
axisX: normalizedAxis[0],
|
|
43087
43748
|
axisY: normalizedAxis[1],
|
|
43088
43749
|
axisZ: normalizedAxis[2],
|
|
43089
|
-
degrees
|
|
43090
|
-
pivotX:
|
|
43091
|
-
pivotY:
|
|
43092
|
-
pivotZ:
|
|
43750
|
+
degrees,
|
|
43751
|
+
pivotX: rotatePivot[0],
|
|
43752
|
+
pivotY: rotatePivot[1],
|
|
43753
|
+
pivotZ: rotatePivot[2]
|
|
43093
43754
|
});
|
|
43094
43755
|
return setShapeCompilePlanInternal(
|
|
43095
43756
|
withTransformedDimensions(this, buildShapeFromCompilePlan(nextPlan, this.colorHex), matrix),
|
|
@@ -43101,10 +43762,12 @@ class Shape {
|
|
|
43101
43762
|
* `movingPoint` / `targetPoint` may be raw world points or this shape's anchors/references.
|
|
43102
43763
|
*/
|
|
43103
43764
|
rotateAroundTo(axis, pivot, movingPoint, targetPoint, options = {}) {
|
|
43765
|
+
const rotateAxis = requireNonZeroFiniteVec3(axis, "Shape.rotateAroundTo() axis");
|
|
43766
|
+
const rotatePivot = requireFiniteVec3$1(pivot, "Shape.rotateAroundTo() pivot");
|
|
43104
43767
|
const moving = resolveRotationPoint(this, movingPoint);
|
|
43105
43768
|
const target = resolveRotationPoint(this, targetPoint);
|
|
43106
|
-
const angleDeg = solveRotateAroundAngle(
|
|
43107
|
-
return this.rotateAroundAxis(
|
|
43769
|
+
const angleDeg = solveRotateAroundAngle(rotateAxis, rotatePivot, moving, target, options);
|
|
43770
|
+
return this.rotateAroundAxis(rotateAxis, angleDeg, rotatePivot);
|
|
43108
43771
|
}
|
|
43109
43772
|
// --- Booleans ---
|
|
43110
43773
|
/** Unwrap any object with toShape() without circular import. */
|
|
@@ -43268,17 +43931,19 @@ class Shape {
|
|
|
43268
43931
|
}
|
|
43269
43932
|
/** Split by infinite plane. Returns [positive-side, negative-side]. */
|
|
43270
43933
|
splitByPlane(normal, originOffset = 0) {
|
|
43934
|
+
const planeNormal = requireNonZeroFiniteVec3(normal, "Shape.splitByPlane() normal");
|
|
43935
|
+
const planeOffset = requireFiniteNumber(originOffset, "Shape.splitByPlane() originOffset");
|
|
43271
43936
|
const info = deriveGeometryInfo(getShapeGeometryInfoInternal(this), "boolean", {
|
|
43272
43937
|
topology: _activeBackend === "truck" ? "kernel" : "none"
|
|
43273
43938
|
});
|
|
43274
43939
|
const basePlan = getShapeCompilePlanInternal(this);
|
|
43275
43940
|
const firstPlan = createOwnedTopologyRewritePlan(
|
|
43276
|
-
buildTrimByPlaneShapeCompilePlan(basePlan,
|
|
43941
|
+
buildTrimByPlaneShapeCompilePlan(basePlan, planeNormal, planeOffset),
|
|
43277
43942
|
"splitByPlane:positive",
|
|
43278
43943
|
(owner) => buildTrimByPlaneTopologyRewritePropagation(owner, basePlan)
|
|
43279
43944
|
);
|
|
43280
43945
|
const secondPlan = createOwnedTopologyRewritePlan(
|
|
43281
|
-
buildTrimByPlaneShapeCompilePlan(basePlan, [-
|
|
43946
|
+
buildTrimByPlaneShapeCompilePlan(basePlan, [-planeNormal[0], -planeNormal[1], -planeNormal[2]], -planeOffset),
|
|
43282
43947
|
"splitByPlane:opposite",
|
|
43283
43948
|
(owner) => buildTrimByPlaneTopologyRewritePropagation(owner, basePlan)
|
|
43284
43949
|
);
|
|
@@ -43296,9 +43961,11 @@ class Shape {
|
|
|
43296
43961
|
}
|
|
43297
43962
|
/** Keep the positive side of the plane and discard the opposite side. */
|
|
43298
43963
|
trimByPlane(normal, originOffset = 0) {
|
|
43964
|
+
const planeNormal = requireNonZeroFiniteVec3(normal, "Shape.trimByPlane() normal");
|
|
43965
|
+
const planeOffset = requireFiniteNumber(originOffset, "Shape.trimByPlane() originOffset");
|
|
43299
43966
|
const basePlan = getShapeCompilePlanInternal(this);
|
|
43300
43967
|
const nextPlan = createOwnedTopologyRewritePlan(
|
|
43301
|
-
buildTrimByPlaneShapeCompilePlan(basePlan,
|
|
43968
|
+
buildTrimByPlaneShapeCompilePlan(basePlan, planeNormal, planeOffset),
|
|
43302
43969
|
"trimByPlane",
|
|
43303
43970
|
(owner) => buildTrimByPlaneTopologyRewritePropagation(owner, basePlan)
|
|
43304
43971
|
);
|
|
@@ -43318,8 +43985,9 @@ class Shape {
|
|
|
43318
43985
|
* `openFaces` names any subset of the base shape's labeled faces to leave open (no wall).
|
|
43319
43986
|
*/
|
|
43320
43987
|
shell(thickness, opts = {}) {
|
|
43988
|
+
const wallThickness = requirePositiveFiniteNumber(thickness, "Shape.shell() thickness");
|
|
43321
43989
|
const basePlan = getShapeCompilePlanInternal(this);
|
|
43322
|
-
const shellPlan = buildShellShapeCompilePlan(basePlan,
|
|
43990
|
+
const shellPlan = buildShellShapeCompilePlan(basePlan, wallThickness, opts.openFaces);
|
|
43323
43991
|
if (!shellPlan) {
|
|
43324
43992
|
throw new Error(
|
|
43325
43993
|
"Shape.shell() supports box(), cylinder(), straight extrude(), loft(), sweep(), and variableSweep() solids with optional face openings and rigid transforms."
|
|
@@ -43340,7 +44008,8 @@ class Shape {
|
|
|
43340
44008
|
}
|
|
43341
44009
|
/** Offset-thicken an exact open surface or shell into a solid. */
|
|
43342
44010
|
thicken(thickness) {
|
|
43343
|
-
|
|
44011
|
+
const wallThickness = requireFiniteNumber(thickness, "Shape.thicken() thickness");
|
|
44012
|
+
if (wallThickness === 0) {
|
|
43344
44013
|
throw new Error("Shape.thicken() requires a non-zero finite thickness.");
|
|
43345
44014
|
}
|
|
43346
44015
|
const info = getShapeGeometryInfoInternal(this);
|
|
@@ -43348,7 +44017,7 @@ class Shape {
|
|
|
43348
44017
|
throw new Error("Shape.thicken() is only available on surface-representation shapes.");
|
|
43349
44018
|
}
|
|
43350
44019
|
const basePlan = getShapeCompilePlanInternal(this);
|
|
43351
|
-
const nextPlan = buildSurfaceThickenShapeCompilePlan(basePlan,
|
|
44020
|
+
const nextPlan = buildSurfaceThickenShapeCompilePlan(basePlan, wallThickness);
|
|
43352
44021
|
const representation = info.backend === "occt" || info.backend === "truck" ? "brep-solid" : "mesh-solid";
|
|
43353
44022
|
return setShapeCompilePlanInternal(
|
|
43354
44023
|
setShapeGeometryInfoInternal(
|
|
@@ -43389,11 +44058,12 @@ class Shape {
|
|
|
43389
44058
|
}
|
|
43390
44059
|
/** Slice the runtime solid by a plane normal to local Z at the given offset. */
|
|
43391
44060
|
slice(offset = 0) {
|
|
44061
|
+
const planeOffset = requireFiniteNumber(offset, "Shape.slice() offset");
|
|
43392
44062
|
if (getShapeGeometryInfoInternal(this).backend === "truck") {
|
|
43393
|
-
const slicedProfile = lowerExactSlicedShapeCompilePlanToTruckProfileBackend(getShapeCompilePlanInternal(this),
|
|
44063
|
+
const slicedProfile = lowerExactSlicedShapeCompilePlanToTruckProfileBackend(getShapeCompilePlanInternal(this), planeOffset);
|
|
43394
44064
|
if (slicedProfile) return slicedProfile;
|
|
43395
44065
|
}
|
|
43396
|
-
return getShapeRuntimeBackendInternal(this).slice(
|
|
44066
|
+
return getShapeRuntimeBackendInternal(this).slice(planeOffset);
|
|
43397
44067
|
}
|
|
43398
44068
|
/** Orthographically project the runtime solid onto the local XY plane. */
|
|
43399
44069
|
project() {
|
|
@@ -43416,9 +44086,10 @@ class Shape {
|
|
|
43416
44086
|
const sp = this.referencePoint(selfAnchor);
|
|
43417
44087
|
let dx = tp[0] - sp[0], dy = tp[1] - sp[1], dz = tp[2] - sp[2];
|
|
43418
44088
|
if (offset) {
|
|
43419
|
-
|
|
43420
|
-
|
|
43421
|
-
|
|
44089
|
+
const offsetPoint = requireFiniteVec3$1(offset, "Shape.attachTo() offset");
|
|
44090
|
+
dx += offsetPoint[0];
|
|
44091
|
+
dy += offsetPoint[1];
|
|
44092
|
+
dz += offsetPoint[2];
|
|
43422
44093
|
}
|
|
43423
44094
|
return this.translate(dx, dy, dz);
|
|
43424
44095
|
}
|
|
@@ -43434,9 +44105,9 @@ class Shape {
|
|
|
43434
44105
|
* - `protrude` = how far the child sticks out (positive = outward from face)
|
|
43435
44106
|
*/
|
|
43436
44107
|
onFace(parent, face, opts = {}) {
|
|
43437
|
-
const u2 = opts.u ?? 0;
|
|
43438
|
-
const v = opts.v ?? 0;
|
|
43439
|
-
const p2 = opts.protrude ?? 0;
|
|
44108
|
+
const u2 = requireFiniteNumber(opts.u ?? 0, "Shape.onFace() u");
|
|
44109
|
+
const v = requireFiniteNumber(opts.v ?? 0, "Shape.onFace() v");
|
|
44110
|
+
const p2 = requireFiniteNumber(opts.protrude ?? 0, "Shape.onFace() protrude");
|
|
43440
44111
|
const opposite = {
|
|
43441
44112
|
front: "back",
|
|
43442
44113
|
back: "front",
|
|
@@ -44015,6 +44686,8 @@ function sampleSweepPath(path, edgeLengthHint) {
|
|
|
44015
44686
|
path,
|
|
44016
44687
|
edgeLengthHint != null ? Math.max(16, Math.round(path.controlPoints.length * 12 / Math.max(0.1, edgeLengthHint))) : 48
|
|
44017
44688
|
);
|
|
44689
|
+
case "route3d":
|
|
44690
|
+
return sweepPathToPolyline(path, resolveCurveSampleCount(edgeLengthHint, path.length));
|
|
44018
44691
|
}
|
|
44019
44692
|
}
|
|
44020
44693
|
function clamp(v, lo, hi) {
|
|
@@ -45144,6 +45817,7 @@ function rotateVector(v, axis, c2, s) {
|
|
|
45144
45817
|
];
|
|
45145
45818
|
}
|
|
45146
45819
|
const OFFSET_SOLID_EPS = 1e-9;
|
|
45820
|
+
const OCCT_BACKEND_REQUIRED_HINT = "Select the OCCT backend in the editor or run the CLI with --backend occt.";
|
|
45147
45821
|
function disposeWasmObject(value) {
|
|
45148
45822
|
if (value != null && typeof value.delete === "function") value.delete();
|
|
45149
45823
|
}
|
|
@@ -45628,7 +46302,7 @@ function profilePolygonLoopTopologyMatches(left, right) {
|
|
|
45628
46302
|
}
|
|
45629
46303
|
function lowerOffsetLoftCompilePlan(plan, thickness, wasm) {
|
|
45630
46304
|
if (plan.profiles.length !== plan.heights.length || plan.profiles.length < 2) {
|
|
45631
|
-
throw new Error(
|
|
46305
|
+
throw new Error(`Offset solid requires the OCCT backend. ${OCCT_BACKEND_REQUIRED_HINT}`);
|
|
45632
46306
|
}
|
|
45633
46307
|
const heights = [...plan.heights];
|
|
45634
46308
|
heights[0] -= thickness;
|
|
@@ -45639,7 +46313,7 @@ function lowerOffsetLoftCompilePlan(plan, thickness, wasm) {
|
|
|
45639
46313
|
const offsetPolygons = plan.profiles.map((profile) => offsetProfilePolygonsForManifold(profile, thickness, wasm));
|
|
45640
46314
|
const stitched = loftStitched(offsetPolygons, heights, wasm);
|
|
45641
46315
|
if (!stitched) {
|
|
45642
|
-
throw new Error(
|
|
46316
|
+
throw new Error(`Offset solid requires the OCCT backend. ${OCCT_BACKEND_REQUIRED_HINT}`);
|
|
45643
46317
|
}
|
|
45644
46318
|
return stitched;
|
|
45645
46319
|
}
|
|
@@ -45679,16 +46353,16 @@ function lowerOffsetSweepCompilePlan(plan, thickness, wasm) {
|
|
|
45679
46353
|
const basePolygons = profilePolygonsForManifold(plan.profile, wasm);
|
|
45680
46354
|
const offsetPolygons = offsetProfilePolygonsForManifold(plan.profile, thickness, wasm);
|
|
45681
46355
|
if (!profilePolygonLoopTopologyMatches(basePolygons, offsetPolygons)) {
|
|
45682
|
-
throw new Error(
|
|
46356
|
+
throw new Error(`Offset solid requires the OCCT backend. ${OCCT_BACKEND_REQUIRED_HINT}`);
|
|
45683
46357
|
}
|
|
45684
46358
|
const pathPoints = sweepPathToPolylineAdaptive(plan.path, plan.pathSamples ?? 48);
|
|
45685
46359
|
const extendedPath = extendedStraightSweepPathForManifold(pathPoints, thickness);
|
|
45686
46360
|
if (!extendedPath) {
|
|
45687
|
-
throw new Error(
|
|
46361
|
+
throw new Error(`Offset solid requires the OCCT backend. ${OCCT_BACKEND_REQUIRED_HINT}`);
|
|
45688
46362
|
}
|
|
45689
46363
|
const stitched = sweepStitched(offsetPolygons, extendedPath, [plan.up[0], plan.up[1], plan.up[2]], wasm);
|
|
45690
46364
|
if (!stitched) {
|
|
45691
|
-
throw new Error(
|
|
46365
|
+
throw new Error(`Offset solid requires the OCCT backend. ${OCCT_BACKEND_REQUIRED_HINT}`);
|
|
45692
46366
|
}
|
|
45693
46367
|
return stitched;
|
|
45694
46368
|
}
|
|
@@ -45697,7 +46371,7 @@ function lowerTransformedOffsetSolidCompilePlan(plan, thickness, wasm) {
|
|
|
45697
46371
|
for (const step of plan.steps) {
|
|
45698
46372
|
const stepScale = offsetSolidTransformDistanceScaleForManifold(step);
|
|
45699
46373
|
if (stepScale == null) {
|
|
45700
|
-
throw new Error(
|
|
46374
|
+
throw new Error(`Offset solid requires the OCCT backend. ${OCCT_BACKEND_REQUIRED_HINT}`);
|
|
45701
46375
|
}
|
|
45702
46376
|
distanceScale *= stepScale;
|
|
45703
46377
|
}
|
|
@@ -45738,7 +46412,7 @@ function lowerOffsetSolidCompilePlan(plan, wasm) {
|
|
|
45738
46412
|
}
|
|
45739
46413
|
const base = verticalPrismOffsetBaseForManifold(basePlan);
|
|
45740
46414
|
if (!base) {
|
|
45741
|
-
throw new Error(
|
|
46415
|
+
throw new Error(`Offset solid requires the OCCT backend. ${OCCT_BACKEND_REQUIRED_HINT}`);
|
|
45742
46416
|
}
|
|
45743
46417
|
const zMin = base.zMin - plan.thickness;
|
|
45744
46418
|
const zMax = base.zMax + plan.thickness;
|
|
@@ -46263,6 +46937,18 @@ function matchEdgeSegmentByMidpoint(segments, target) {
|
|
|
46263
46937
|
}
|
|
46264
46938
|
return best;
|
|
46265
46939
|
}
|
|
46940
|
+
function selectEdgeSegmentsForFeature(segments, plan) {
|
|
46941
|
+
if (plan.edgeQuery) {
|
|
46942
|
+
const selected = applyEdgeQueryFilters(segments, plan.edgeQuery);
|
|
46943
|
+
return plan.edgeSelection === "first" ? selected.slice(0, 1) : selected;
|
|
46944
|
+
}
|
|
46945
|
+
const matched = [];
|
|
46946
|
+
for (const target of plan.edgeTargets ?? []) {
|
|
46947
|
+
const seg = matchEdgeSegmentByMidpoint(segments, target);
|
|
46948
|
+
if (seg && seg.length >= 1e-6) matched.push(seg);
|
|
46949
|
+
}
|
|
46950
|
+
return matched;
|
|
46951
|
+
}
|
|
46266
46952
|
function lowerFilletEdgesCompilePlan(plan, wasm) {
|
|
46267
46953
|
let manifold = lowerShapeCompilePlanToManifold(plan.base, wasm);
|
|
46268
46954
|
const mesh = manifold.getMesh();
|
|
@@ -46272,11 +46958,8 @@ function lowerFilletEdgesCompilePlan(plan, wasm) {
|
|
|
46272
46958
|
triVerts: mesh.triVerts,
|
|
46273
46959
|
vertProperties: mesh.vertProperties
|
|
46274
46960
|
});
|
|
46275
|
-
const matched =
|
|
46276
|
-
|
|
46277
|
-
const seg = matchEdgeSegmentByMidpoint(segments, target);
|
|
46278
|
-
if (seg && seg.length >= 1e-6) matched.push(seg);
|
|
46279
|
-
}
|
|
46961
|
+
const matched = selectEdgeSegmentsForFeature(segments, plan);
|
|
46962
|
+
if (plan.edgeQuery && matched.length === 0) throw new Error("filletEdges(): no edges match the deferred edge query.");
|
|
46280
46963
|
matched.sort((a2, b) => b.length - a2.length);
|
|
46281
46964
|
for (const seg of matched) {
|
|
46282
46965
|
try {
|
|
@@ -46299,11 +46982,8 @@ function lowerChamferEdgesCompilePlan(plan, wasm) {
|
|
|
46299
46982
|
triVerts: mesh.triVerts,
|
|
46300
46983
|
vertProperties: mesh.vertProperties
|
|
46301
46984
|
});
|
|
46302
|
-
const matched =
|
|
46303
|
-
|
|
46304
|
-
const seg = matchEdgeSegmentByMidpoint(segments, target);
|
|
46305
|
-
if (seg && seg.length >= 1e-6) matched.push(seg);
|
|
46306
|
-
}
|
|
46985
|
+
const matched = selectEdgeSegmentsForFeature(segments, plan);
|
|
46986
|
+
if (plan.edgeQuery && matched.length === 0) throw new Error("chamferEdges(): no edges match the deferred edge query.");
|
|
46307
46987
|
matched.sort((a2, b) => b.length - a2.length);
|
|
46308
46988
|
for (const seg of matched) {
|
|
46309
46989
|
try {
|
|
@@ -46405,20 +47085,20 @@ function lowerShapeCompilePlanToManifold(plan, wasm) {
|
|
|
46405
47085
|
case "filletEdges":
|
|
46406
47086
|
return lowerFilletEdgesCompilePlan(plan, wasm);
|
|
46407
47087
|
case "cornerYBlend":
|
|
46408
|
-
throw new Error(
|
|
47088
|
+
throw new Error(`Blend.CornerY() requires the OCCT backend. ${OCCT_BACKEND_REQUIRED_HINT}`);
|
|
46409
47089
|
case "chamferEdges":
|
|
46410
47090
|
return lowerChamferEdgesCompilePlan(plan, wasm);
|
|
46411
47091
|
case "draft": {
|
|
46412
47092
|
const lowered = lowerDraftShapeCompilePlanToLoftPlan(plan);
|
|
46413
47093
|
if (lowered) return lowerShapeCompilePlanToManifold(lowered, wasm);
|
|
46414
|
-
throw new Error(
|
|
47094
|
+
throw new Error(`Draft angle requires the OCCT backend. ${OCCT_BACKEND_REQUIRED_HINT}`);
|
|
46415
47095
|
}
|
|
46416
47096
|
case "offsetSolid":
|
|
46417
47097
|
return lowerOffsetSolidCompilePlan(plan, wasm);
|
|
46418
47098
|
case "trimByPlane":
|
|
46419
47099
|
return lowerShapeTrimByPlaneCompilePlan(plan, wasm);
|
|
46420
47100
|
case "importedMesh":
|
|
46421
|
-
return lowerImportedMeshToManifold(plan.fileData, plan.format, plan.filePath, wasm);
|
|
47101
|
+
return lowerImportedMeshToManifold(plan.fileData, plan.format, plan.filePath, wasm, plan.object);
|
|
46422
47102
|
case "sdf": {
|
|
46423
47103
|
const evaluator = compileSdfMaterializationEvaluator3(plan.tree);
|
|
46424
47104
|
return lowerSdfToManifold(
|
|
@@ -46442,9 +47122,9 @@ function lowerShapeCompilePlanToManifold(plan, wasm) {
|
|
|
46442
47122
|
case "surfaceExtend":
|
|
46443
47123
|
case "surfaceThicken":
|
|
46444
47124
|
case "surfaceSolid":
|
|
46445
|
-
throw new Error(
|
|
47125
|
+
throw new Error(`Exact surfacing operations require the OCCT backend. ${OCCT_BACKEND_REQUIRED_HINT}`);
|
|
46446
47126
|
case "importedStep":
|
|
46447
|
-
throw new Error(`importStep("${plan.filePath}") requires the OCCT backend.
|
|
47127
|
+
throw new Error(`importStep("${plan.filePath}") requires the OCCT backend. ${OCCT_BACKEND_REQUIRED_HINT}`);
|
|
46448
47128
|
default:
|
|
46449
47129
|
assertExhaustive(plan);
|
|
46450
47130
|
}
|
|
@@ -46585,11 +47265,11 @@ function projectVerticesToSurfaceWithNormals(vertProperties, sdfFn, out6) {
|
|
|
46585
47265
|
function lowerNurbsSurfaceToManifold(plan, wasm) {
|
|
46586
47266
|
if (!plan.allowApproximation && plan.thickness === 0) {
|
|
46587
47267
|
throw new Error(
|
|
46588
|
-
|
|
47268
|
+
`nurbsSurface() now defaults to an exact open sheet. The Manifold backend cannot represent exact open surfaces. ${OCCT_BACKEND_REQUIRED_HINT} Pass { approximate: true } with a non-zero thickness if you explicitly want a sampled fallback.`
|
|
46589
47269
|
);
|
|
46590
47270
|
}
|
|
46591
47271
|
if (plan.thickness === 0) {
|
|
46592
|
-
throw new Error(
|
|
47272
|
+
throw new Error(`The Manifold backend cannot represent open sheet surfaces. ${OCCT_BACKEND_REQUIRED_HINT}`);
|
|
46593
47273
|
}
|
|
46594
47274
|
const surface = new NurbsSurface(plan.controlGrid, {
|
|
46595
47275
|
degreeU: plan.degreeU,
|
|
@@ -46739,8 +47419,8 @@ function lowerTrimmedNurbsSurfaceToManifold(surface, plan, wasm) {
|
|
|
46739
47419
|
disposeWasmObject(mesh);
|
|
46740
47420
|
}
|
|
46741
47421
|
}
|
|
46742
|
-
function lowerImportedMeshToManifold(fileData, format, filePath, wasm) {
|
|
46743
|
-
const parsed = parseMeshFile(fileData, format);
|
|
47422
|
+
function lowerImportedMeshToManifold(fileData, format, filePath, wasm, object) {
|
|
47423
|
+
const parsed = parseMeshFile(fileData, format, { object });
|
|
46744
47424
|
if (parsed.triVerts.length === 0) {
|
|
46745
47425
|
throw new Error(`importMesh("${filePath}"): file contains no triangles`);
|
|
46746
47426
|
}
|
|
@@ -46762,7 +47442,11 @@ function lowerImportedMeshToManifold(fileData, format, filePath, wasm) {
|
|
|
46762
47442
|
}
|
|
46763
47443
|
}
|
|
46764
47444
|
function lowerShapeCompilePlanToShapeBackend(plan, wasm) {
|
|
46765
|
-
return lowerShapeBackendWithCache(
|
|
47445
|
+
return lowerShapeBackendWithCache(
|
|
47446
|
+
"manifold",
|
|
47447
|
+
plan,
|
|
47448
|
+
(basePlan) => wrapManifoldShapeBackend(lowerShapeCompilePlanToManifold(basePlan, wasm))
|
|
47449
|
+
);
|
|
46766
47450
|
}
|
|
46767
47451
|
const DEFAULT_LEAF_SIZE = 8;
|
|
46768
47452
|
function cloneVec3$3(value) {
|