forgecad 0.10.5 → 0.11.0
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/dist/assets/{AdminPage-raksfnNA.js → AdminPage-B1nIvqLS.js} +1 -1
- package/dist/assets/{BenchmarkPage-DP3RxhPs.js → BenchmarkPage-YZJbw5nd.js} +1 -1
- package/dist/assets/{BlogPage-D7Dos-vl.js → BlogPage-DIWRApKS.js} +1 -1
- package/dist/assets/{DocsPage-DO1kvBns.js → DocsPage-ClL6X1hR.js} +2 -22
- package/dist/assets/{EditorApp-DQJmcmRT.js → EditorApp-CYBDvSyT.js} +575 -119
- package/dist/assets/{EmbedViewer-DFDUhOma.js → EmbedViewer-Dmfu_LIw.js} +2 -2
- package/dist/assets/{LandingPageProofDriven-DbE_tp8-.js → LandingPageProofDriven-XYTiYxfM.js} +1 -1
- package/dist/assets/{LegalPage-CominSso.js → LegalPage-D5Z3CscF.js} +1 -1
- package/dist/assets/{PricingPage-CcVIN9yj.js → PricingPage-BP4lIGio.js} +1 -1
- package/dist/assets/{SettingsPage-DLWcP289.js → SettingsPage-D3bcPBsC.js} +1 -1
- package/dist/assets/{app-xW3hOdq9.js → app-BKjogwIZ.js} +2192 -231
- package/dist/assets/{backendInit-mDHk97u7.js → backendInit-6a9-ilom.js} +76448 -75066
- package/dist/assets/cli/{render--SIU27W_.js → render-CMNudGb0.js} +3 -3
- package/dist/assets/{constructionHistoryWorker-uEe_Q7Kg.js → constructionHistoryWorker-BuZgc606.js} +6985 -6706
- package/dist/assets/{evalWorker-BqyDHDcI.js → evalWorker-DQ82ueGu.js} +40862 -39497
- package/dist/assets/{inspectWorker-UXMxlcR8.js → inspectWorker-Cuby2qfT.js} +2078 -478
- package/dist/assets/{jointPose-bYMlwU3v.js → jointPose-CFql5I-u.js} +1 -1
- package/dist/assets/{manifold-CyOV5B9S.js → manifold-02pmr7O7.js} +2 -2
- package/dist/assets/{manifold-BR7UYI4P.js → manifold-C6KU0oII.js} +1 -1
- package/dist/assets/{manifold-D4d5NQst.js → manifold-P1yF3GKn.js} +1 -1
- package/dist/assets/{reportWorker-DsaICZsn.js → reportWorker-kg065BVL.js} +85183 -78309
- package/dist/cli/render.html +1 -1
- package/dist/docs/index.html +2 -2
- package/dist/docs-raw/AI/usage.md +6 -8
- package/dist/docs-raw/CLI.md +10 -10
- package/dist/docs-raw/component-model.md +28 -9
- package/dist/docs-raw/generated/concepts.md +13 -4
- package/dist/docs-raw/generated/core.md +244 -56
- package/dist/docs-raw/generated/curves.md +13 -0
- package/dist/docs-raw/generated/runtime-names.md +2 -2
- package/dist/docs-raw/guides/inspection-bundles.md +1 -1
- package/dist/docs-raw/guides/structural-fea.md +11 -0
- package/dist/docs-raw/skills/forgecad-build-model.md +70 -147
- package/dist/docs-raw/skills/forgecad-image-prompt.md +1 -1
- package/dist/docs-raw/skills/forgecad-project-sync.md +3 -3
- package/dist/docs-raw/skills/forgecad-reconstruct-cad-file.md +2 -2
- package/dist/docs-raw/skills/forgecad-reconstruct-from-images.md +4 -5
- package/dist/docs-raw/skills/forgecad.md +3 -1
- package/dist/docs-raw/skills/index.md +1 -5
- package/dist/docs-raw/welcome.md +3 -4
- package/dist/index.html +1 -1
- package/dist/llms.txt +1 -2
- package/dist/sitemap.xml +15 -15
- package/dist-cli/{check-compiler-7YAHVXYM.js → check-compiler-UJWUEIDC.js} +1 -1
- package/dist-cli/{check-query-propagation-ZRR6IOJW.js → check-query-propagation-O2EPDJSY.js} +1 -1
- package/dist-cli/{chunk-VNM67DIV.js → chunk-MNDROM7T.js} +77145 -75767
- package/dist-cli/forgecad.js +1145 -441
- package/dist-skill/CONTEXT.md +429 -64
- package/dist-skill/SKILL.md +3 -1
- package/dist-skill/docs/API/core/concepts.md +31 -4
- package/dist-skill/docs/CLI.md +10 -10
- package/dist-skill/docs/generated/core.md +240 -57
- package/dist-skill/docs/generated/curves.md +13 -0
- package/dist-skill/docs/generated/runtime-names.md +2 -2
- package/dist-skill/docs/guides/inspection-bundles.md +1 -1
- package/dist-skill/docs/guides/manual-parameters.md +130 -0
- package/dist-skill/docs/guides/structural-fea.md +11 -0
- package/dist-skill/library/README.md +0 -4
- package/dist-skill/library/forgecad-build-model/SKILL.md +57 -150
- package/dist-skill/library/forgecad-build-model/references/inspection-feedback.md +58 -0
- package/dist-skill/library/forgecad-build-model/references/module-contracts.md +53 -0
- package/dist-skill/library/forgecad-build-model/references/parameter-controls.md +22 -0
- package/dist-skill/library/forgecad-build-model/references/readiness-review.md +43 -0
- package/dist-skill/library/forgecad-build-model/references/simulation-feedback.md +49 -0
- package/dist-skill/library/forgecad-build-model/references/stage-1-design-intent.md +21 -0
- package/dist-skill/library/forgecad-build-model/references/stage-2-architecture-plan.md +23 -0
- package/dist-skill/library/forgecad-build-model/references/stage-3-build-slices.md +39 -0
- package/dist-skill/library/forgecad-build-model/references/stage-4-feedback-iteration.md +24 -0
- package/dist-skill/library/forgecad-build-model/references/stage-5-readiness-package.md +34 -0
- package/dist-skill/library/forgecad-image-prompt/SKILL.md +1 -1
- package/dist-skill/library/forgecad-project-sync/SKILL.md +3 -3
- package/dist-skill/library/forgecad-reconstruct-cad-file/SKILL.md +2 -2
- package/dist-skill/library/forgecad-reconstruct-from-images/SKILL.md +4 -5
- package/dist-skill/website/skills/forgecad-build-model.md +70 -147
- package/dist-skill/website/skills/forgecad-image-prompt.md +1 -1
- package/dist-skill/website/skills/forgecad-project-sync.md +3 -3
- package/dist-skill/website/skills/forgecad-reconstruct-cad-file.md +2 -2
- package/dist-skill/website/skills/forgecad-reconstruct-from-images.md +4 -5
- package/dist-skill/website/skills/forgecad.md +3 -1
- package/dist-skill/website/skills/index.md +1 -5
- package/examples/api/param-path2d.forge.js +65 -0
- package/examples/api/param-placement2d.forge.js +80 -0
- package/examples/api/param-spline2d-g-continuity.forge.js +57 -0
- package/examples/api/spoon-full-tang-handle.forge.js +57 -17
- package/examples/api/surface-variable-thickness-panel.forge.js +62 -0
- package/examples/mechanical/airplane-propeller.forge.js +81 -28
- package/package.json +2 -2
- package/dist/docs-raw/skills/forgecad-design-spec.md +0 -145
- package/dist/docs-raw/skills/forgecad-grade-model.md +0 -84
- package/dist/docs-raw/skills/forgecad-inspect-model.md +0 -80
- package/dist/docs-raw/skills/forgecad-verify-mujoco.md +0 -78
- package/dist-skill/library/forgecad-design-spec/SKILL.md +0 -132
- package/dist-skill/library/forgecad-design-spec/references/default-profiles.md +0 -99
- package/dist-skill/library/forgecad-design-spec/references/master-prompt.md +0 -73
- package/dist-skill/library/forgecad-grade-model/SKILL.md +0 -72
- package/dist-skill/library/forgecad-grade-model/agents/openai.yaml +0 -4
- package/dist-skill/library/forgecad-inspect-model/SKILL.md +0 -68
- package/dist-skill/library/forgecad-verify-mujoco/SKILL.md +0 -66
- package/dist-skill/website/skills/forgecad-design-spec.md +0 -145
- package/dist-skill/website/skills/forgecad-grade-model.md +0 -84
- package/dist-skill/website/skills/forgecad-inspect-model.md +0 -80
- package/dist-skill/website/skills/forgecad-verify-mujoco.md +0 -78
- /package/dist-skill/library/{forgecad-verify-mujoco → forgecad-build-model}/scripts/mujoco_verify.py +0 -0
- /package/dist-skill/library/{forgecad-inspect-model → forgecad-build-model/scripts}/summarize_manifest.py +0 -0
|
@@ -4149,8 +4149,8 @@ class Vector3 {
|
|
|
4149
4149
|
* @param {Vector3} normal - The (normalized) normal vector.
|
|
4150
4150
|
* @return {Vector3} A reference to this vector.
|
|
4151
4151
|
*/
|
|
4152
|
-
reflect(
|
|
4153
|
-
return this.sub(_vector$c.copy(
|
|
4152
|
+
reflect(normal2) {
|
|
4153
|
+
return this.sub(_vector$c.copy(normal2).multiplyScalar(2 * this.dot(normal2)));
|
|
4154
4154
|
}
|
|
4155
4155
|
/**
|
|
4156
4156
|
* Returns the angle between the given vector and this instance in radians.
|
|
@@ -5492,29 +5492,29 @@ class Ray {
|
|
|
5492
5492
|
_edge2.subVectors(c2, a2);
|
|
5493
5493
|
_normal$1.crossVectors(_edge1, _edge2);
|
|
5494
5494
|
let DdN = this.direction.dot(_normal$1);
|
|
5495
|
-
let
|
|
5495
|
+
let sign2;
|
|
5496
5496
|
if (DdN > 0) {
|
|
5497
5497
|
if (backfaceCulling) return null;
|
|
5498
|
-
|
|
5498
|
+
sign2 = 1;
|
|
5499
5499
|
} else if (DdN < 0) {
|
|
5500
|
-
|
|
5500
|
+
sign2 = -1;
|
|
5501
5501
|
DdN = -DdN;
|
|
5502
5502
|
} else {
|
|
5503
5503
|
return null;
|
|
5504
5504
|
}
|
|
5505
5505
|
_diff.subVectors(this.origin, a2);
|
|
5506
|
-
const DdQxE2 =
|
|
5506
|
+
const DdQxE2 = sign2 * this.direction.dot(_edge2.crossVectors(_diff, _edge2));
|
|
5507
5507
|
if (DdQxE2 < 0) {
|
|
5508
5508
|
return null;
|
|
5509
5509
|
}
|
|
5510
|
-
const DdE1xQ =
|
|
5510
|
+
const DdE1xQ = sign2 * this.direction.dot(_edge1.cross(_diff));
|
|
5511
5511
|
if (DdE1xQ < 0) {
|
|
5512
5512
|
return null;
|
|
5513
5513
|
}
|
|
5514
5514
|
if (DdQxE2 + DdE1xQ > DdN) {
|
|
5515
5515
|
return null;
|
|
5516
5516
|
}
|
|
5517
|
-
const QdN = -
|
|
5517
|
+
const QdN = -sign2 * _diff.dot(_normal$1);
|
|
5518
5518
|
if (QdN < 0) {
|
|
5519
5519
|
return null;
|
|
5520
5520
|
}
|
|
@@ -10116,11 +10116,11 @@ class BufferGeometry extends EventDispatcher {
|
|
|
10116
10116
|
position.applyMatrix4(matrix);
|
|
10117
10117
|
position.needsUpdate = true;
|
|
10118
10118
|
}
|
|
10119
|
-
const
|
|
10120
|
-
if (
|
|
10119
|
+
const normal2 = this.attributes.normal;
|
|
10120
|
+
if (normal2 !== void 0) {
|
|
10121
10121
|
const normalMatrix = new Matrix3().getNormalMatrix(matrix);
|
|
10122
|
-
|
|
10123
|
-
|
|
10122
|
+
normal2.applyNormalMatrix(normalMatrix);
|
|
10123
|
+
normal2.needsUpdate = true;
|
|
10124
10124
|
}
|
|
10125
10125
|
const tangent = this.attributes.tangent;
|
|
10126
10126
|
if (tangent !== void 0) {
|
|
@@ -10833,7 +10833,7 @@ class Mesh extends Object3D {
|
|
|
10833
10833
|
* @param {Raycaster} raycaster - The raycaster.
|
|
10834
10834
|
* @param {Array<Object>} intersects - The target array that holds the intersection points.
|
|
10835
10835
|
*/
|
|
10836
|
-
raycast(raycaster,
|
|
10836
|
+
raycast(raycaster, intersects2) {
|
|
10837
10837
|
const geometry = this.geometry;
|
|
10838
10838
|
const material = this.material;
|
|
10839
10839
|
const matrixWorld = this.matrixWorld;
|
|
@@ -10851,9 +10851,9 @@ class Mesh extends Object3D {
|
|
|
10851
10851
|
if (geometry.boundingBox !== null) {
|
|
10852
10852
|
if (_ray$3.intersectsBox(geometry.boundingBox) === false) return;
|
|
10853
10853
|
}
|
|
10854
|
-
this._computeIntersections(raycaster,
|
|
10854
|
+
this._computeIntersections(raycaster, intersects2, _ray$3);
|
|
10855
10855
|
}
|
|
10856
|
-
_computeIntersections(raycaster,
|
|
10856
|
+
_computeIntersections(raycaster, intersects2, rayLocalSpace) {
|
|
10857
10857
|
let intersection2;
|
|
10858
10858
|
const geometry = this.geometry;
|
|
10859
10859
|
const material = this.material;
|
|
@@ -10861,7 +10861,7 @@ class Mesh extends Object3D {
|
|
|
10861
10861
|
const position = geometry.attributes.position;
|
|
10862
10862
|
const uv = geometry.attributes.uv;
|
|
10863
10863
|
const uv1 = geometry.attributes.uv1;
|
|
10864
|
-
const
|
|
10864
|
+
const normal2 = geometry.attributes.normal;
|
|
10865
10865
|
const groups = geometry.groups;
|
|
10866
10866
|
const drawRange = geometry.drawRange;
|
|
10867
10867
|
if (index2 !== null) {
|
|
@@ -10875,11 +10875,11 @@ class Mesh extends Object3D {
|
|
|
10875
10875
|
const a2 = index2.getX(j);
|
|
10876
10876
|
const b = index2.getX(j + 1);
|
|
10877
10877
|
const c2 = index2.getX(j + 2);
|
|
10878
|
-
intersection2 = checkGeometryIntersection(this, groupMaterial, raycaster, rayLocalSpace, uv, uv1,
|
|
10878
|
+
intersection2 = checkGeometryIntersection(this, groupMaterial, raycaster, rayLocalSpace, uv, uv1, normal2, a2, b, c2);
|
|
10879
10879
|
if (intersection2) {
|
|
10880
10880
|
intersection2.faceIndex = Math.floor(j / 3);
|
|
10881
10881
|
intersection2.face.materialIndex = group.materialIndex;
|
|
10882
|
-
|
|
10882
|
+
intersects2.push(intersection2);
|
|
10883
10883
|
}
|
|
10884
10884
|
}
|
|
10885
10885
|
}
|
|
@@ -10890,10 +10890,10 @@ class Mesh extends Object3D {
|
|
|
10890
10890
|
const a2 = index2.getX(i);
|
|
10891
10891
|
const b = index2.getX(i + 1);
|
|
10892
10892
|
const c2 = index2.getX(i + 2);
|
|
10893
|
-
intersection2 = checkGeometryIntersection(this, material, raycaster, rayLocalSpace, uv, uv1,
|
|
10893
|
+
intersection2 = checkGeometryIntersection(this, material, raycaster, rayLocalSpace, uv, uv1, normal2, a2, b, c2);
|
|
10894
10894
|
if (intersection2) {
|
|
10895
10895
|
intersection2.faceIndex = Math.floor(i / 3);
|
|
10896
|
-
|
|
10896
|
+
intersects2.push(intersection2);
|
|
10897
10897
|
}
|
|
10898
10898
|
}
|
|
10899
10899
|
}
|
|
@@ -10908,11 +10908,11 @@ class Mesh extends Object3D {
|
|
|
10908
10908
|
const a2 = j;
|
|
10909
10909
|
const b = j + 1;
|
|
10910
10910
|
const c2 = j + 2;
|
|
10911
|
-
intersection2 = checkGeometryIntersection(this, groupMaterial, raycaster, rayLocalSpace, uv, uv1,
|
|
10911
|
+
intersection2 = checkGeometryIntersection(this, groupMaterial, raycaster, rayLocalSpace, uv, uv1, normal2, a2, b, c2);
|
|
10912
10912
|
if (intersection2) {
|
|
10913
10913
|
intersection2.faceIndex = Math.floor(j / 3);
|
|
10914
10914
|
intersection2.face.materialIndex = group.materialIndex;
|
|
10915
|
-
|
|
10915
|
+
intersects2.push(intersection2);
|
|
10916
10916
|
}
|
|
10917
10917
|
}
|
|
10918
10918
|
}
|
|
@@ -10923,10 +10923,10 @@ class Mesh extends Object3D {
|
|
|
10923
10923
|
const a2 = i;
|
|
10924
10924
|
const b = i + 1;
|
|
10925
10925
|
const c2 = i + 2;
|
|
10926
|
-
intersection2 = checkGeometryIntersection(this, material, raycaster, rayLocalSpace, uv, uv1,
|
|
10926
|
+
intersection2 = checkGeometryIntersection(this, material, raycaster, rayLocalSpace, uv, uv1, normal2, a2, b, c2);
|
|
10927
10927
|
if (intersection2) {
|
|
10928
10928
|
intersection2.faceIndex = Math.floor(i / 3);
|
|
10929
|
-
|
|
10929
|
+
intersects2.push(intersection2);
|
|
10930
10930
|
}
|
|
10931
10931
|
}
|
|
10932
10932
|
}
|
|
@@ -10951,7 +10951,7 @@ function checkIntersection$1(object, material, raycaster, ray2, pA, pB, pC, poin
|
|
|
10951
10951
|
object
|
|
10952
10952
|
};
|
|
10953
10953
|
}
|
|
10954
|
-
function checkGeometryIntersection(object, material, raycaster, ray2, uv, uv1,
|
|
10954
|
+
function checkGeometryIntersection(object, material, raycaster, ray2, uv, uv1, normal2, a2, b, c2) {
|
|
10955
10955
|
object.getVertexPosition(a2, _vA$1);
|
|
10956
10956
|
object.getVertexPosition(b, _vB$1);
|
|
10957
10957
|
object.getVertexPosition(c2, _vC$1);
|
|
@@ -10965,8 +10965,8 @@ function checkGeometryIntersection(object, material, raycaster, ray2, uv, uv1, n
|
|
|
10965
10965
|
if (uv1) {
|
|
10966
10966
|
intersection2.uv1 = Triangle.getInterpolatedAttribute(uv1, a2, b, c2, barycoord, new Vector2());
|
|
10967
10967
|
}
|
|
10968
|
-
if (
|
|
10969
|
-
intersection2.normal = Triangle.getInterpolatedAttribute(
|
|
10968
|
+
if (normal2) {
|
|
10969
|
+
intersection2.normal = Triangle.getInterpolatedAttribute(normal2, a2, b, c2, barycoord, new Vector3());
|
|
10970
10970
|
if (intersection2.normal.dot(ray2.direction) > 0) {
|
|
10971
10971
|
intersection2.normal.multiplyScalar(-1);
|
|
10972
10972
|
}
|
|
@@ -11020,9 +11020,9 @@ class Plane {
|
|
|
11020
11020
|
* @param {Vector3} [normal=(1,0,0)] - A unit length vector defining the normal of the plane.
|
|
11021
11021
|
* @param {number} [constant=0] - The signed distance from the origin to the plane.
|
|
11022
11022
|
*/
|
|
11023
|
-
constructor(
|
|
11023
|
+
constructor(normal2 = new Vector3(1, 0, 0), constant = 0) {
|
|
11024
11024
|
this.isPlane = true;
|
|
11025
|
-
this.normal =
|
|
11025
|
+
this.normal = normal2;
|
|
11026
11026
|
this.constant = constant;
|
|
11027
11027
|
}
|
|
11028
11028
|
/**
|
|
@@ -11032,8 +11032,8 @@ class Plane {
|
|
|
11032
11032
|
* @param {number} constant - The constant.
|
|
11033
11033
|
* @return {Plane} A reference to this plane.
|
|
11034
11034
|
*/
|
|
11035
|
-
set(
|
|
11036
|
-
this.normal.copy(
|
|
11035
|
+
set(normal2, constant) {
|
|
11036
|
+
this.normal.copy(normal2);
|
|
11037
11037
|
this.constant = constant;
|
|
11038
11038
|
return this;
|
|
11039
11039
|
}
|
|
@@ -11060,8 +11060,8 @@ class Plane {
|
|
|
11060
11060
|
* @param {Vector3} point - A coplanar point.
|
|
11061
11061
|
* @return {Plane} A reference to this plane.
|
|
11062
11062
|
*/
|
|
11063
|
-
setFromNormalAndCoplanarPoint(
|
|
11064
|
-
this.normal.copy(
|
|
11063
|
+
setFromNormalAndCoplanarPoint(normal2, point2) {
|
|
11064
|
+
this.normal.copy(normal2);
|
|
11065
11065
|
this.constant = -point2.dot(this.normal);
|
|
11066
11066
|
return this;
|
|
11067
11067
|
}
|
|
@@ -11076,8 +11076,8 @@ class Plane {
|
|
|
11076
11076
|
* @return {Plane} A reference to this plane.
|
|
11077
11077
|
*/
|
|
11078
11078
|
setFromCoplanarPoints(a2, b, c2) {
|
|
11079
|
-
const
|
|
11080
|
-
this.setFromNormalAndCoplanarPoint(
|
|
11079
|
+
const normal2 = _vector1.subVectors(c2, b).cross(_vector2.subVectors(a2, b)).normalize();
|
|
11080
|
+
this.setFromNormalAndCoplanarPoint(normal2, a2);
|
|
11081
11081
|
return this;
|
|
11082
11082
|
}
|
|
11083
11083
|
/**
|
|
@@ -11218,8 +11218,8 @@ class Plane {
|
|
|
11218
11218
|
applyMatrix4(matrix, optionalNormalMatrix) {
|
|
11219
11219
|
const normalMatrix = optionalNormalMatrix || _normalMatrix.getNormalMatrix(matrix);
|
|
11220
11220
|
const referencePoint = this.coplanarPoint(_vector1).applyMatrix4(matrix);
|
|
11221
|
-
const
|
|
11222
|
-
this.constant = -referencePoint.dot(
|
|
11221
|
+
const normal2 = this.normal.applyMatrix3(normalMatrix).normalize();
|
|
11222
|
+
this.constant = -referencePoint.dot(normal2);
|
|
11223
11223
|
return this;
|
|
11224
11224
|
}
|
|
11225
11225
|
/**
|
|
@@ -12224,7 +12224,7 @@ class BatchedMesh extends Mesh {
|
|
|
12224
12224
|
copyArrayContents(oldGeometry.attributes[key2].array, geometry.attributes[key2].array);
|
|
12225
12225
|
}
|
|
12226
12226
|
}
|
|
12227
|
-
raycast(raycaster,
|
|
12227
|
+
raycast(raycaster, intersects2) {
|
|
12228
12228
|
const instanceInfo = this._instanceInfo;
|
|
12229
12229
|
const geometryInfoList = this._geometryInfo;
|
|
12230
12230
|
const matrixWorld = this.matrixWorld;
|
|
@@ -12253,7 +12253,7 @@ class BatchedMesh extends Mesh {
|
|
|
12253
12253
|
const intersect2 = _batchIntersects$1[j];
|
|
12254
12254
|
intersect2.object = this;
|
|
12255
12255
|
intersect2.batchId = i;
|
|
12256
|
-
|
|
12256
|
+
intersects2.push(intersect2);
|
|
12257
12257
|
}
|
|
12258
12258
|
_batchIntersects$1.length = 0;
|
|
12259
12259
|
}
|
|
@@ -12389,6 +12389,502 @@ class BatchedMesh extends Mesh {
|
|
|
12389
12389
|
this.onBeforeRender(renderer, null, shadowCamera, geometry, depthMaterial);
|
|
12390
12390
|
}
|
|
12391
12391
|
}
|
|
12392
|
+
function earcut(data, holeIndices, dim = 2) {
|
|
12393
|
+
const hasHoles = holeIndices && holeIndices.length;
|
|
12394
|
+
const outerLen = hasHoles ? holeIndices[0] * dim : data.length;
|
|
12395
|
+
let outerNode = linkedList(data, 0, outerLen, dim, true);
|
|
12396
|
+
const triangles = [];
|
|
12397
|
+
if (!outerNode || outerNode.next === outerNode.prev) return triangles;
|
|
12398
|
+
let minX, minY, invSize;
|
|
12399
|
+
if (hasHoles) outerNode = eliminateHoles(data, holeIndices, outerNode, dim);
|
|
12400
|
+
if (data.length > 80 * dim) {
|
|
12401
|
+
minX = Infinity;
|
|
12402
|
+
minY = Infinity;
|
|
12403
|
+
let maxX = -Infinity;
|
|
12404
|
+
let maxY = -Infinity;
|
|
12405
|
+
for (let i = dim; i < outerLen; i += dim) {
|
|
12406
|
+
const x2 = data[i];
|
|
12407
|
+
const y2 = data[i + 1];
|
|
12408
|
+
if (x2 < minX) minX = x2;
|
|
12409
|
+
if (y2 < minY) minY = y2;
|
|
12410
|
+
if (x2 > maxX) maxX = x2;
|
|
12411
|
+
if (y2 > maxY) maxY = y2;
|
|
12412
|
+
}
|
|
12413
|
+
invSize = Math.max(maxX - minX, maxY - minY);
|
|
12414
|
+
invSize = invSize !== 0 ? 32767 / invSize : 0;
|
|
12415
|
+
}
|
|
12416
|
+
earcutLinked(outerNode, triangles, dim, minX, minY, invSize, 0);
|
|
12417
|
+
return triangles;
|
|
12418
|
+
}
|
|
12419
|
+
function linkedList(data, start, end, dim, clockwise) {
|
|
12420
|
+
let last;
|
|
12421
|
+
if (clockwise === signedArea$4(data, start, end, dim) > 0) {
|
|
12422
|
+
for (let i = start; i < end; i += dim) last = insertNode(i / dim | 0, data[i], data[i + 1], last);
|
|
12423
|
+
} else {
|
|
12424
|
+
for (let i = end - dim; i >= start; i -= dim) last = insertNode(i / dim | 0, data[i], data[i + 1], last);
|
|
12425
|
+
}
|
|
12426
|
+
if (last && equals(last, last.next)) {
|
|
12427
|
+
removeNode(last);
|
|
12428
|
+
last = last.next;
|
|
12429
|
+
}
|
|
12430
|
+
return last;
|
|
12431
|
+
}
|
|
12432
|
+
function filterPoints(start, end) {
|
|
12433
|
+
if (!start) return start;
|
|
12434
|
+
if (!end) end = start;
|
|
12435
|
+
let p2 = start, again;
|
|
12436
|
+
do {
|
|
12437
|
+
again = false;
|
|
12438
|
+
if (!p2.steiner && (equals(p2, p2.next) || area(p2.prev, p2, p2.next) === 0)) {
|
|
12439
|
+
removeNode(p2);
|
|
12440
|
+
p2 = end = p2.prev;
|
|
12441
|
+
if (p2 === p2.next) break;
|
|
12442
|
+
again = true;
|
|
12443
|
+
} else {
|
|
12444
|
+
p2 = p2.next;
|
|
12445
|
+
}
|
|
12446
|
+
} while (again || p2 !== end);
|
|
12447
|
+
return end;
|
|
12448
|
+
}
|
|
12449
|
+
function earcutLinked(ear, triangles, dim, minX, minY, invSize, pass) {
|
|
12450
|
+
if (!ear) return;
|
|
12451
|
+
if (!pass && invSize) indexCurve(ear, minX, minY, invSize);
|
|
12452
|
+
let stop = ear;
|
|
12453
|
+
while (ear.prev !== ear.next) {
|
|
12454
|
+
const prev = ear.prev;
|
|
12455
|
+
const next = ear.next;
|
|
12456
|
+
if (invSize ? isEarHashed(ear, minX, minY, invSize) : isEar(ear)) {
|
|
12457
|
+
triangles.push(prev.i, ear.i, next.i);
|
|
12458
|
+
removeNode(ear);
|
|
12459
|
+
ear = next.next;
|
|
12460
|
+
stop = next.next;
|
|
12461
|
+
continue;
|
|
12462
|
+
}
|
|
12463
|
+
ear = next;
|
|
12464
|
+
if (ear === stop) {
|
|
12465
|
+
if (!pass) {
|
|
12466
|
+
earcutLinked(filterPoints(ear), triangles, dim, minX, minY, invSize, 1);
|
|
12467
|
+
} else if (pass === 1) {
|
|
12468
|
+
ear = cureLocalIntersections(filterPoints(ear), triangles);
|
|
12469
|
+
earcutLinked(ear, triangles, dim, minX, minY, invSize, 2);
|
|
12470
|
+
} else if (pass === 2) {
|
|
12471
|
+
splitEarcut(ear, triangles, dim, minX, minY, invSize);
|
|
12472
|
+
}
|
|
12473
|
+
break;
|
|
12474
|
+
}
|
|
12475
|
+
}
|
|
12476
|
+
}
|
|
12477
|
+
function isEar(ear) {
|
|
12478
|
+
const a2 = ear.prev, b = ear, c2 = ear.next;
|
|
12479
|
+
if (area(a2, b, c2) >= 0) return false;
|
|
12480
|
+
const ax = a2.x, bx = b.x, cx = c2.x, ay = a2.y, by = b.y, cy = c2.y;
|
|
12481
|
+
const x0 = Math.min(ax, bx, cx), y0 = Math.min(ay, by, cy), x1 = Math.max(ax, bx, cx), y1 = Math.max(ay, by, cy);
|
|
12482
|
+
let p2 = c2.next;
|
|
12483
|
+
while (p2 !== a2) {
|
|
12484
|
+
if (p2.x >= x0 && p2.x <= x1 && p2.y >= y0 && p2.y <= y1 && pointInTriangleExceptFirst(ax, ay, bx, by, cx, cy, p2.x, p2.y) && area(p2.prev, p2, p2.next) >= 0) return false;
|
|
12485
|
+
p2 = p2.next;
|
|
12486
|
+
}
|
|
12487
|
+
return true;
|
|
12488
|
+
}
|
|
12489
|
+
function isEarHashed(ear, minX, minY, invSize) {
|
|
12490
|
+
const a2 = ear.prev, b = ear, c2 = ear.next;
|
|
12491
|
+
if (area(a2, b, c2) >= 0) return false;
|
|
12492
|
+
const ax = a2.x, bx = b.x, cx = c2.x, ay = a2.y, by = b.y, cy = c2.y;
|
|
12493
|
+
const x0 = Math.min(ax, bx, cx), y0 = Math.min(ay, by, cy), x1 = Math.max(ax, bx, cx), y1 = Math.max(ay, by, cy);
|
|
12494
|
+
const minZ = zOrder(x0, y0, minX, minY, invSize), maxZ = zOrder(x1, y1, minX, minY, invSize);
|
|
12495
|
+
let p2 = ear.prevZ, n = ear.nextZ;
|
|
12496
|
+
while (p2 && p2.z >= minZ && n && n.z <= maxZ) {
|
|
12497
|
+
if (p2.x >= x0 && p2.x <= x1 && p2.y >= y0 && p2.y <= y1 && p2 !== a2 && p2 !== c2 && pointInTriangleExceptFirst(ax, ay, bx, by, cx, cy, p2.x, p2.y) && area(p2.prev, p2, p2.next) >= 0) return false;
|
|
12498
|
+
p2 = p2.prevZ;
|
|
12499
|
+
if (n.x >= x0 && n.x <= x1 && n.y >= y0 && n.y <= y1 && n !== a2 && n !== c2 && pointInTriangleExceptFirst(ax, ay, bx, by, cx, cy, n.x, n.y) && area(n.prev, n, n.next) >= 0) return false;
|
|
12500
|
+
n = n.nextZ;
|
|
12501
|
+
}
|
|
12502
|
+
while (p2 && p2.z >= minZ) {
|
|
12503
|
+
if (p2.x >= x0 && p2.x <= x1 && p2.y >= y0 && p2.y <= y1 && p2 !== a2 && p2 !== c2 && pointInTriangleExceptFirst(ax, ay, bx, by, cx, cy, p2.x, p2.y) && area(p2.prev, p2, p2.next) >= 0) return false;
|
|
12504
|
+
p2 = p2.prevZ;
|
|
12505
|
+
}
|
|
12506
|
+
while (n && n.z <= maxZ) {
|
|
12507
|
+
if (n.x >= x0 && n.x <= x1 && n.y >= y0 && n.y <= y1 && n !== a2 && n !== c2 && pointInTriangleExceptFirst(ax, ay, bx, by, cx, cy, n.x, n.y) && area(n.prev, n, n.next) >= 0) return false;
|
|
12508
|
+
n = n.nextZ;
|
|
12509
|
+
}
|
|
12510
|
+
return true;
|
|
12511
|
+
}
|
|
12512
|
+
function cureLocalIntersections(start, triangles) {
|
|
12513
|
+
let p2 = start;
|
|
12514
|
+
do {
|
|
12515
|
+
const a2 = p2.prev, b = p2.next.next;
|
|
12516
|
+
if (!equals(a2, b) && intersects(a2, p2, p2.next, b) && locallyInside(a2, b) && locallyInside(b, a2)) {
|
|
12517
|
+
triangles.push(a2.i, p2.i, b.i);
|
|
12518
|
+
removeNode(p2);
|
|
12519
|
+
removeNode(p2.next);
|
|
12520
|
+
p2 = start = b;
|
|
12521
|
+
}
|
|
12522
|
+
p2 = p2.next;
|
|
12523
|
+
} while (p2 !== start);
|
|
12524
|
+
return filterPoints(p2);
|
|
12525
|
+
}
|
|
12526
|
+
function splitEarcut(start, triangles, dim, minX, minY, invSize) {
|
|
12527
|
+
let a2 = start;
|
|
12528
|
+
do {
|
|
12529
|
+
let b = a2.next.next;
|
|
12530
|
+
while (b !== a2.prev) {
|
|
12531
|
+
if (a2.i !== b.i && isValidDiagonal(a2, b)) {
|
|
12532
|
+
let c2 = splitPolygon(a2, b);
|
|
12533
|
+
a2 = filterPoints(a2, a2.next);
|
|
12534
|
+
c2 = filterPoints(c2, c2.next);
|
|
12535
|
+
earcutLinked(a2, triangles, dim, minX, minY, invSize, 0);
|
|
12536
|
+
earcutLinked(c2, triangles, dim, minX, minY, invSize, 0);
|
|
12537
|
+
return;
|
|
12538
|
+
}
|
|
12539
|
+
b = b.next;
|
|
12540
|
+
}
|
|
12541
|
+
a2 = a2.next;
|
|
12542
|
+
} while (a2 !== start);
|
|
12543
|
+
}
|
|
12544
|
+
function eliminateHoles(data, holeIndices, outerNode, dim) {
|
|
12545
|
+
const queue = [];
|
|
12546
|
+
for (let i = 0, len2 = holeIndices.length; i < len2; i++) {
|
|
12547
|
+
const start = holeIndices[i] * dim;
|
|
12548
|
+
const end = i < len2 - 1 ? holeIndices[i + 1] * dim : data.length;
|
|
12549
|
+
const list = linkedList(data, start, end, dim, false);
|
|
12550
|
+
if (list === list.next) list.steiner = true;
|
|
12551
|
+
queue.push(getLeftmost(list));
|
|
12552
|
+
}
|
|
12553
|
+
queue.sort(compareXYSlope);
|
|
12554
|
+
for (let i = 0; i < queue.length; i++) {
|
|
12555
|
+
outerNode = eliminateHole(queue[i], outerNode);
|
|
12556
|
+
}
|
|
12557
|
+
return outerNode;
|
|
12558
|
+
}
|
|
12559
|
+
function compareXYSlope(a2, b) {
|
|
12560
|
+
let result = a2.x - b.x;
|
|
12561
|
+
if (result === 0) {
|
|
12562
|
+
result = a2.y - b.y;
|
|
12563
|
+
if (result === 0) {
|
|
12564
|
+
const aSlope = (a2.next.y - a2.y) / (a2.next.x - a2.x);
|
|
12565
|
+
const bSlope = (b.next.y - b.y) / (b.next.x - b.x);
|
|
12566
|
+
result = aSlope - bSlope;
|
|
12567
|
+
}
|
|
12568
|
+
}
|
|
12569
|
+
return result;
|
|
12570
|
+
}
|
|
12571
|
+
function eliminateHole(hole, outerNode) {
|
|
12572
|
+
const bridge = findHoleBridge(hole, outerNode);
|
|
12573
|
+
if (!bridge) {
|
|
12574
|
+
return outerNode;
|
|
12575
|
+
}
|
|
12576
|
+
const bridgeReverse = splitPolygon(bridge, hole);
|
|
12577
|
+
filterPoints(bridgeReverse, bridgeReverse.next);
|
|
12578
|
+
return filterPoints(bridge, bridge.next);
|
|
12579
|
+
}
|
|
12580
|
+
function findHoleBridge(hole, outerNode) {
|
|
12581
|
+
let p2 = outerNode;
|
|
12582
|
+
const hx = hole.x;
|
|
12583
|
+
const hy = hole.y;
|
|
12584
|
+
let qx = -Infinity;
|
|
12585
|
+
let m2;
|
|
12586
|
+
if (equals(hole, p2)) return p2;
|
|
12587
|
+
do {
|
|
12588
|
+
if (equals(hole, p2.next)) return p2.next;
|
|
12589
|
+
else if (hy <= p2.y && hy >= p2.next.y && p2.next.y !== p2.y) {
|
|
12590
|
+
const x2 = p2.x + (hy - p2.y) * (p2.next.x - p2.x) / (p2.next.y - p2.y);
|
|
12591
|
+
if (x2 <= hx && x2 > qx) {
|
|
12592
|
+
qx = x2;
|
|
12593
|
+
m2 = p2.x < p2.next.x ? p2 : p2.next;
|
|
12594
|
+
if (x2 === hx) return m2;
|
|
12595
|
+
}
|
|
12596
|
+
}
|
|
12597
|
+
p2 = p2.next;
|
|
12598
|
+
} while (p2 !== outerNode);
|
|
12599
|
+
if (!m2) return null;
|
|
12600
|
+
const stop = m2;
|
|
12601
|
+
const mx = m2.x;
|
|
12602
|
+
const my = m2.y;
|
|
12603
|
+
let tanMin = Infinity;
|
|
12604
|
+
p2 = m2;
|
|
12605
|
+
do {
|
|
12606
|
+
if (hx >= p2.x && p2.x >= mx && hx !== p2.x && pointInTriangle(hy < my ? hx : qx, hy, mx, my, hy < my ? qx : hx, hy, p2.x, p2.y)) {
|
|
12607
|
+
const tan = Math.abs(hy - p2.y) / (hx - p2.x);
|
|
12608
|
+
if (locallyInside(p2, hole) && (tan < tanMin || tan === tanMin && (p2.x > m2.x || p2.x === m2.x && sectorContainsSector(m2, p2)))) {
|
|
12609
|
+
m2 = p2;
|
|
12610
|
+
tanMin = tan;
|
|
12611
|
+
}
|
|
12612
|
+
}
|
|
12613
|
+
p2 = p2.next;
|
|
12614
|
+
} while (p2 !== stop);
|
|
12615
|
+
return m2;
|
|
12616
|
+
}
|
|
12617
|
+
function sectorContainsSector(m2, p2) {
|
|
12618
|
+
return area(m2.prev, m2, p2.prev) < 0 && area(p2.next, m2, m2.next) < 0;
|
|
12619
|
+
}
|
|
12620
|
+
function indexCurve(start, minX, minY, invSize) {
|
|
12621
|
+
let p2 = start;
|
|
12622
|
+
do {
|
|
12623
|
+
if (p2.z === 0) p2.z = zOrder(p2.x, p2.y, minX, minY, invSize);
|
|
12624
|
+
p2.prevZ = p2.prev;
|
|
12625
|
+
p2.nextZ = p2.next;
|
|
12626
|
+
p2 = p2.next;
|
|
12627
|
+
} while (p2 !== start);
|
|
12628
|
+
p2.prevZ.nextZ = null;
|
|
12629
|
+
p2.prevZ = null;
|
|
12630
|
+
sortLinked(p2);
|
|
12631
|
+
}
|
|
12632
|
+
function sortLinked(list) {
|
|
12633
|
+
let numMerges;
|
|
12634
|
+
let inSize = 1;
|
|
12635
|
+
do {
|
|
12636
|
+
let p2 = list;
|
|
12637
|
+
let e;
|
|
12638
|
+
list = null;
|
|
12639
|
+
let tail = null;
|
|
12640
|
+
numMerges = 0;
|
|
12641
|
+
while (p2) {
|
|
12642
|
+
numMerges++;
|
|
12643
|
+
let q = p2;
|
|
12644
|
+
let pSize = 0;
|
|
12645
|
+
for (let i = 0; i < inSize; i++) {
|
|
12646
|
+
pSize++;
|
|
12647
|
+
q = q.nextZ;
|
|
12648
|
+
if (!q) break;
|
|
12649
|
+
}
|
|
12650
|
+
let qSize = inSize;
|
|
12651
|
+
while (pSize > 0 || qSize > 0 && q) {
|
|
12652
|
+
if (pSize !== 0 && (qSize === 0 || !q || p2.z <= q.z)) {
|
|
12653
|
+
e = p2;
|
|
12654
|
+
p2 = p2.nextZ;
|
|
12655
|
+
pSize--;
|
|
12656
|
+
} else {
|
|
12657
|
+
e = q;
|
|
12658
|
+
q = q.nextZ;
|
|
12659
|
+
qSize--;
|
|
12660
|
+
}
|
|
12661
|
+
if (tail) tail.nextZ = e;
|
|
12662
|
+
else list = e;
|
|
12663
|
+
e.prevZ = tail;
|
|
12664
|
+
tail = e;
|
|
12665
|
+
}
|
|
12666
|
+
p2 = q;
|
|
12667
|
+
}
|
|
12668
|
+
tail.nextZ = null;
|
|
12669
|
+
inSize *= 2;
|
|
12670
|
+
} while (numMerges > 1);
|
|
12671
|
+
return list;
|
|
12672
|
+
}
|
|
12673
|
+
function zOrder(x2, y2, minX, minY, invSize) {
|
|
12674
|
+
x2 = (x2 - minX) * invSize | 0;
|
|
12675
|
+
y2 = (y2 - minY) * invSize | 0;
|
|
12676
|
+
x2 = (x2 | x2 << 8) & 16711935;
|
|
12677
|
+
x2 = (x2 | x2 << 4) & 252645135;
|
|
12678
|
+
x2 = (x2 | x2 << 2) & 858993459;
|
|
12679
|
+
x2 = (x2 | x2 << 1) & 1431655765;
|
|
12680
|
+
y2 = (y2 | y2 << 8) & 16711935;
|
|
12681
|
+
y2 = (y2 | y2 << 4) & 252645135;
|
|
12682
|
+
y2 = (y2 | y2 << 2) & 858993459;
|
|
12683
|
+
y2 = (y2 | y2 << 1) & 1431655765;
|
|
12684
|
+
return x2 | y2 << 1;
|
|
12685
|
+
}
|
|
12686
|
+
function getLeftmost(start) {
|
|
12687
|
+
let p2 = start, leftmost = start;
|
|
12688
|
+
do {
|
|
12689
|
+
if (p2.x < leftmost.x || p2.x === leftmost.x && p2.y < leftmost.y) leftmost = p2;
|
|
12690
|
+
p2 = p2.next;
|
|
12691
|
+
} while (p2 !== start);
|
|
12692
|
+
return leftmost;
|
|
12693
|
+
}
|
|
12694
|
+
function pointInTriangle(ax, ay, bx, by, cx, cy, px, py) {
|
|
12695
|
+
return (cx - px) * (ay - py) >= (ax - px) * (cy - py) && (ax - px) * (by - py) >= (bx - px) * (ay - py) && (bx - px) * (cy - py) >= (cx - px) * (by - py);
|
|
12696
|
+
}
|
|
12697
|
+
function pointInTriangleExceptFirst(ax, ay, bx, by, cx, cy, px, py) {
|
|
12698
|
+
return !(ax === px && ay === py) && pointInTriangle(ax, ay, bx, by, cx, cy, px, py);
|
|
12699
|
+
}
|
|
12700
|
+
function isValidDiagonal(a2, b) {
|
|
12701
|
+
return a2.next.i !== b.i && a2.prev.i !== b.i && !intersectsPolygon(a2, b) && // dones't intersect other edges
|
|
12702
|
+
(locallyInside(a2, b) && locallyInside(b, a2) && middleInside(a2, b) && // locally visible
|
|
12703
|
+
(area(a2.prev, a2, b.prev) || area(a2, b.prev, b)) || // does not create opposite-facing sectors
|
|
12704
|
+
equals(a2, b) && area(a2.prev, a2, a2.next) > 0 && area(b.prev, b, b.next) > 0);
|
|
12705
|
+
}
|
|
12706
|
+
function area(p2, q, r) {
|
|
12707
|
+
return (q.y - p2.y) * (r.x - q.x) - (q.x - p2.x) * (r.y - q.y);
|
|
12708
|
+
}
|
|
12709
|
+
function equals(p1, p2) {
|
|
12710
|
+
return p1.x === p2.x && p1.y === p2.y;
|
|
12711
|
+
}
|
|
12712
|
+
function intersects(p1, q1, p2, q2) {
|
|
12713
|
+
const o1 = sign(area(p1, q1, p2));
|
|
12714
|
+
const o2 = sign(area(p1, q1, q2));
|
|
12715
|
+
const o3 = sign(area(p2, q2, p1));
|
|
12716
|
+
const o4 = sign(area(p2, q2, q1));
|
|
12717
|
+
if (o1 !== o2 && o3 !== o4) return true;
|
|
12718
|
+
if (o1 === 0 && onSegment(p1, p2, q1)) return true;
|
|
12719
|
+
if (o2 === 0 && onSegment(p1, q2, q1)) return true;
|
|
12720
|
+
if (o3 === 0 && onSegment(p2, p1, q2)) return true;
|
|
12721
|
+
if (o4 === 0 && onSegment(p2, q1, q2)) return true;
|
|
12722
|
+
return false;
|
|
12723
|
+
}
|
|
12724
|
+
function onSegment(p2, q, r) {
|
|
12725
|
+
return q.x <= Math.max(p2.x, r.x) && q.x >= Math.min(p2.x, r.x) && q.y <= Math.max(p2.y, r.y) && q.y >= Math.min(p2.y, r.y);
|
|
12726
|
+
}
|
|
12727
|
+
function sign(num) {
|
|
12728
|
+
return num > 0 ? 1 : num < 0 ? -1 : 0;
|
|
12729
|
+
}
|
|
12730
|
+
function intersectsPolygon(a2, b) {
|
|
12731
|
+
let p2 = a2;
|
|
12732
|
+
do {
|
|
12733
|
+
if (p2.i !== a2.i && p2.next.i !== a2.i && p2.i !== b.i && p2.next.i !== b.i && intersects(p2, p2.next, a2, b)) return true;
|
|
12734
|
+
p2 = p2.next;
|
|
12735
|
+
} while (p2 !== a2);
|
|
12736
|
+
return false;
|
|
12737
|
+
}
|
|
12738
|
+
function locallyInside(a2, b) {
|
|
12739
|
+
return area(a2.prev, a2, a2.next) < 0 ? area(a2, b, a2.next) >= 0 && area(a2, a2.prev, b) >= 0 : area(a2, b, a2.prev) < 0 || area(a2, a2.next, b) < 0;
|
|
12740
|
+
}
|
|
12741
|
+
function middleInside(a2, b) {
|
|
12742
|
+
let p2 = a2;
|
|
12743
|
+
let inside = false;
|
|
12744
|
+
const px = (a2.x + b.x) / 2;
|
|
12745
|
+
const py = (a2.y + b.y) / 2;
|
|
12746
|
+
do {
|
|
12747
|
+
if (p2.y > py !== p2.next.y > py && p2.next.y !== p2.y && px < (p2.next.x - p2.x) * (py - p2.y) / (p2.next.y - p2.y) + p2.x)
|
|
12748
|
+
inside = !inside;
|
|
12749
|
+
p2 = p2.next;
|
|
12750
|
+
} while (p2 !== a2);
|
|
12751
|
+
return inside;
|
|
12752
|
+
}
|
|
12753
|
+
function splitPolygon(a2, b) {
|
|
12754
|
+
const a22 = createNode(a2.i, a2.x, a2.y), b22 = createNode(b.i, b.x, b.y), an = a2.next, bp = b.prev;
|
|
12755
|
+
a2.next = b;
|
|
12756
|
+
b.prev = a2;
|
|
12757
|
+
a22.next = an;
|
|
12758
|
+
an.prev = a22;
|
|
12759
|
+
b22.next = a22;
|
|
12760
|
+
a22.prev = b22;
|
|
12761
|
+
bp.next = b22;
|
|
12762
|
+
b22.prev = bp;
|
|
12763
|
+
return b22;
|
|
12764
|
+
}
|
|
12765
|
+
function insertNode(i, x2, y2, last) {
|
|
12766
|
+
const p2 = createNode(i, x2, y2);
|
|
12767
|
+
if (!last) {
|
|
12768
|
+
p2.prev = p2;
|
|
12769
|
+
p2.next = p2;
|
|
12770
|
+
} else {
|
|
12771
|
+
p2.next = last.next;
|
|
12772
|
+
p2.prev = last;
|
|
12773
|
+
last.next.prev = p2;
|
|
12774
|
+
last.next = p2;
|
|
12775
|
+
}
|
|
12776
|
+
return p2;
|
|
12777
|
+
}
|
|
12778
|
+
function removeNode(p2) {
|
|
12779
|
+
p2.next.prev = p2.prev;
|
|
12780
|
+
p2.prev.next = p2.next;
|
|
12781
|
+
if (p2.prevZ) p2.prevZ.nextZ = p2.nextZ;
|
|
12782
|
+
if (p2.nextZ) p2.nextZ.prevZ = p2.prevZ;
|
|
12783
|
+
}
|
|
12784
|
+
function createNode(i, x2, y2) {
|
|
12785
|
+
return {
|
|
12786
|
+
i,
|
|
12787
|
+
// vertex index in coordinates array
|
|
12788
|
+
x: x2,
|
|
12789
|
+
y: y2,
|
|
12790
|
+
// vertex coordinates
|
|
12791
|
+
prev: null,
|
|
12792
|
+
// previous and next vertex nodes in a polygon ring
|
|
12793
|
+
next: null,
|
|
12794
|
+
z: 0,
|
|
12795
|
+
// z-order curve value
|
|
12796
|
+
prevZ: null,
|
|
12797
|
+
// previous and next nodes in z-order
|
|
12798
|
+
nextZ: null,
|
|
12799
|
+
steiner: false
|
|
12800
|
+
// indicates whether this is a steiner point
|
|
12801
|
+
};
|
|
12802
|
+
}
|
|
12803
|
+
function signedArea$4(data, start, end, dim) {
|
|
12804
|
+
let sum2 = 0;
|
|
12805
|
+
for (let i = start, j = end - dim; i < end; i += dim) {
|
|
12806
|
+
sum2 += (data[j] - data[i]) * (data[i + 1] + data[j + 1]);
|
|
12807
|
+
j = i;
|
|
12808
|
+
}
|
|
12809
|
+
return sum2;
|
|
12810
|
+
}
|
|
12811
|
+
class Earcut {
|
|
12812
|
+
/**
|
|
12813
|
+
* Triangulates the given shape definition by returning an array of triangles.
|
|
12814
|
+
*
|
|
12815
|
+
* @param {Array<number>} data - An array with 2D points.
|
|
12816
|
+
* @param {Array<number>} holeIndices - An array with indices defining holes.
|
|
12817
|
+
* @param {number} [dim=2] - The number of coordinates per vertex in the input array.
|
|
12818
|
+
* @return {Array<number>} An array representing the triangulated faces. Each face is defined by three consecutive numbers
|
|
12819
|
+
* representing vertex indices.
|
|
12820
|
+
*/
|
|
12821
|
+
static triangulate(data, holeIndices, dim = 2) {
|
|
12822
|
+
return earcut(data, holeIndices, dim);
|
|
12823
|
+
}
|
|
12824
|
+
}
|
|
12825
|
+
class ShapeUtils {
|
|
12826
|
+
/**
|
|
12827
|
+
* Calculate area of a ( 2D ) contour polygon.
|
|
12828
|
+
*
|
|
12829
|
+
* @param {Array<Vector2>} contour - An array of 2D points.
|
|
12830
|
+
* @return {number} The area.
|
|
12831
|
+
*/
|
|
12832
|
+
static area(contour) {
|
|
12833
|
+
const n = contour.length;
|
|
12834
|
+
let a2 = 0;
|
|
12835
|
+
for (let p2 = n - 1, q = 0; q < n; p2 = q++) {
|
|
12836
|
+
a2 += contour[p2].x * contour[q].y - contour[q].x * contour[p2].y;
|
|
12837
|
+
}
|
|
12838
|
+
return a2 * 0.5;
|
|
12839
|
+
}
|
|
12840
|
+
/**
|
|
12841
|
+
* Returns `true` if the given contour uses a clockwise winding order.
|
|
12842
|
+
*
|
|
12843
|
+
* @param {Array<Vector2>} pts - An array of 2D points defining a polygon.
|
|
12844
|
+
* @return {boolean} Whether the given contour uses a clockwise winding order or not.
|
|
12845
|
+
*/
|
|
12846
|
+
static isClockWise(pts) {
|
|
12847
|
+
return ShapeUtils.area(pts) < 0;
|
|
12848
|
+
}
|
|
12849
|
+
/**
|
|
12850
|
+
* Triangulates the given shape definition.
|
|
12851
|
+
*
|
|
12852
|
+
* @param {Array<Vector2>} contour - An array of 2D points defining the contour.
|
|
12853
|
+
* @param {Array<Array<Vector2>>} holes - An array that holds arrays of 2D points defining the holes.
|
|
12854
|
+
* @return {Array<Array<number>>} An array that holds for each face definition an array with three indices.
|
|
12855
|
+
*/
|
|
12856
|
+
static triangulateShape(contour, holes) {
|
|
12857
|
+
const vertices = [];
|
|
12858
|
+
const holeIndices = [];
|
|
12859
|
+
const faces = [];
|
|
12860
|
+
removeDupEndPts(contour);
|
|
12861
|
+
addContour(vertices, contour);
|
|
12862
|
+
let holeIndex = contour.length;
|
|
12863
|
+
holes.forEach(removeDupEndPts);
|
|
12864
|
+
for (let i = 0; i < holes.length; i++) {
|
|
12865
|
+
holeIndices.push(holeIndex);
|
|
12866
|
+
holeIndex += holes[i].length;
|
|
12867
|
+
addContour(vertices, holes[i]);
|
|
12868
|
+
}
|
|
12869
|
+
const triangles = Earcut.triangulate(vertices, holeIndices);
|
|
12870
|
+
for (let i = 0; i < triangles.length; i += 3) {
|
|
12871
|
+
faces.push(triangles.slice(i, i + 3));
|
|
12872
|
+
}
|
|
12873
|
+
return faces;
|
|
12874
|
+
}
|
|
12875
|
+
}
|
|
12876
|
+
function removeDupEndPts(points) {
|
|
12877
|
+
const l = points.length;
|
|
12878
|
+
if (l > 2 && points[l - 1].equals(points[0])) {
|
|
12879
|
+
points.pop();
|
|
12880
|
+
}
|
|
12881
|
+
}
|
|
12882
|
+
function addContour(vertices, contour) {
|
|
12883
|
+
for (let i = 0; i < contour.length; i++) {
|
|
12884
|
+
vertices.push(contour[i].x);
|
|
12885
|
+
vertices.push(contour[i].y);
|
|
12886
|
+
}
|
|
12887
|
+
}
|
|
12392
12888
|
const _matrix = /* @__PURE__ */ new Matrix4();
|
|
12393
12889
|
class Raycaster {
|
|
12394
12890
|
/**
|
|
@@ -12489,10 +12985,10 @@ class Raycaster {
|
|
|
12489
12985
|
* @param {Array<Raycaster~Intersection>} [intersects=[]] The target array that holds the result of the method.
|
|
12490
12986
|
* @return {Array<Raycaster~Intersection>} An array holding the intersection points.
|
|
12491
12987
|
*/
|
|
12492
|
-
intersectObject(object, recursive = true,
|
|
12493
|
-
intersect(object, this,
|
|
12494
|
-
|
|
12495
|
-
return
|
|
12988
|
+
intersectObject(object, recursive = true, intersects2 = []) {
|
|
12989
|
+
intersect(object, this, intersects2, recursive);
|
|
12990
|
+
intersects2.sort(ascSort);
|
|
12991
|
+
return intersects2;
|
|
12496
12992
|
}
|
|
12497
12993
|
/**
|
|
12498
12994
|
* Checks all intersection between the ray and the objects with or without
|
|
@@ -12504,27 +13000,27 @@ class Raycaster {
|
|
|
12504
13000
|
* @param {Array<Raycaster~Intersection>} [intersects=[]] The target array that holds the result of the method.
|
|
12505
13001
|
* @return {Array<Raycaster~Intersection>} An array holding the intersection points.
|
|
12506
13002
|
*/
|
|
12507
|
-
intersectObjects(objects, recursive = true,
|
|
13003
|
+
intersectObjects(objects, recursive = true, intersects2 = []) {
|
|
12508
13004
|
for (let i = 0, l = objects.length; i < l; i++) {
|
|
12509
|
-
intersect(objects[i], this,
|
|
13005
|
+
intersect(objects[i], this, intersects2, recursive);
|
|
12510
13006
|
}
|
|
12511
|
-
|
|
12512
|
-
return
|
|
13007
|
+
intersects2.sort(ascSort);
|
|
13008
|
+
return intersects2;
|
|
12513
13009
|
}
|
|
12514
13010
|
}
|
|
12515
13011
|
function ascSort(a2, b) {
|
|
12516
13012
|
return a2.distance - b.distance;
|
|
12517
13013
|
}
|
|
12518
|
-
function intersect(object, raycaster,
|
|
13014
|
+
function intersect(object, raycaster, intersects2, recursive) {
|
|
12519
13015
|
let propagate = true;
|
|
12520
13016
|
if (object.layers.test(raycaster.layers)) {
|
|
12521
|
-
const result = object.raycast(raycaster,
|
|
13017
|
+
const result = object.raycast(raycaster, intersects2);
|
|
12522
13018
|
if (result === false) propagate = false;
|
|
12523
13019
|
}
|
|
12524
13020
|
if (propagate === true && recursive === true) {
|
|
12525
13021
|
const children = object.children;
|
|
12526
13022
|
for (let i = 0, l = children.length; i < l; i++) {
|
|
12527
|
-
intersect(children[i], raycaster,
|
|
13023
|
+
intersect(children[i], raycaster, intersects2, true);
|
|
12528
13024
|
}
|
|
12529
13025
|
}
|
|
12530
13026
|
}
|
|
@@ -13100,7 +13596,7 @@ function cloneSdfNode(node) {
|
|
|
13100
13596
|
}
|
|
13101
13597
|
}
|
|
13102
13598
|
const SHEET_METAL_EDGES = ["top", "right", "bottom", "left"];
|
|
13103
|
-
const EPS$
|
|
13599
|
+
const EPS$4 = 1e-9;
|
|
13104
13600
|
function isFinitePositive$1(value) {
|
|
13105
13601
|
return Number.isFinite(value) && value > 0;
|
|
13106
13602
|
}
|
|
@@ -13141,7 +13637,7 @@ function edgeDisplayName(edge) {
|
|
|
13141
13637
|
return `sheetMetal().flange("${edge}", ...)`;
|
|
13142
13638
|
}
|
|
13143
13639
|
function normalizeAngle(angleDeg) {
|
|
13144
|
-
return Math.abs(angleDeg) <= EPS$
|
|
13640
|
+
return Math.abs(angleDeg) <= EPS$4 ? 0 : angleDeg;
|
|
13145
13641
|
}
|
|
13146
13642
|
function validateSheetMetalModel(model) {
|
|
13147
13643
|
if (!isFinitePositive$1(model.panel.width) || !isFinitePositive$1(model.panel.height)) {
|
|
@@ -13153,7 +13649,7 @@ function validateSheetMetalModel(model) {
|
|
|
13153
13649
|
if (!isFiniteNonNegative(model.bendRadius)) {
|
|
13154
13650
|
return "sheetMetal() requires a finite non-negative bendRadius.";
|
|
13155
13651
|
}
|
|
13156
|
-
if (model.bendRadius <= EPS$
|
|
13652
|
+
if (model.bendRadius <= EPS$4) {
|
|
13157
13653
|
return "sheetMetal() v1 requires a positive bendRadius so the bend region stays explicit instead of collapsing into a sharp fold.";
|
|
13158
13654
|
}
|
|
13159
13655
|
if (model.bendAllowance.kind !== "k-factor") {
|
|
@@ -13215,7 +13711,7 @@ function deriveSheetMetalModel(model) {
|
|
|
13215
13711
|
const trimEnd = flanges.has(adjacent.end) ? model.cornerRelief.size : 0;
|
|
13216
13712
|
const fullLength = edge === "top" || edge === "bottom" ? model.panel.width : model.panel.height;
|
|
13217
13713
|
const span2 = fullLength - trimStart - trimEnd;
|
|
13218
|
-
if (!(span2 > EPS$
|
|
13714
|
+
if (!(span2 > EPS$4)) {
|
|
13219
13715
|
throw new Error(
|
|
13220
13716
|
`${edgeDisplayName(edge)} loses all usable span after applying the defended rectangular corner relief size ${model.cornerRelief.size}.`
|
|
13221
13717
|
);
|
|
@@ -13245,13 +13741,13 @@ function deriveSheetMetalModel(model) {
|
|
|
13245
13741
|
function isSheetMetalPlanarRegionName(name) {
|
|
13246
13742
|
return name === "panel" || name === "flange-top" || name === "flange-right" || name === "flange-bottom" || name === "flange-left";
|
|
13247
13743
|
}
|
|
13248
|
-
function transformPlacement(origin, u2, v,
|
|
13744
|
+
function transformPlacement(origin, u2, v, normal2) {
|
|
13249
13745
|
return {
|
|
13250
13746
|
workplane: {
|
|
13251
13747
|
origin: [origin[0], origin[1], origin[2]],
|
|
13252
13748
|
u: [u2[0], u2[1], u2[2]],
|
|
13253
13749
|
v: [v[0], v[1], v[2]],
|
|
13254
|
-
normal: [
|
|
13750
|
+
normal: [normal2[0], normal2[1], normal2[2]],
|
|
13255
13751
|
source: { kind: "face-ref", faceName: "sheet-metal-placement" }
|
|
13256
13752
|
},
|
|
13257
13753
|
u: 0,
|
|
@@ -13261,7 +13757,7 @@ function transformPlacement(origin, u2, v, normal) {
|
|
|
13261
13757
|
};
|
|
13262
13758
|
}
|
|
13263
13759
|
function translatePlan(plan, x2, y2, z2) {
|
|
13264
|
-
if (Math.abs(x2) <= EPS$
|
|
13760
|
+
if (Math.abs(x2) <= EPS$4 && Math.abs(y2) <= EPS$4 && Math.abs(z2) <= EPS$4) return cloneShapeCompilePlan(plan);
|
|
13265
13761
|
return appendShapeCompileTransform(cloneShapeCompilePlan(plan), {
|
|
13266
13762
|
kind: "translate",
|
|
13267
13763
|
x: x2,
|
|
@@ -13269,9 +13765,9 @@ function translatePlan(plan, x2, y2, z2) {
|
|
|
13269
13765
|
z: z2
|
|
13270
13766
|
});
|
|
13271
13767
|
}
|
|
13272
|
-
function workplanePlacedPlan(plan, origin, u2, v,
|
|
13273
|
-
const placement = transformPlacement(origin, u2, v,
|
|
13274
|
-
const matrix = [u2[0], u2[1], u2[2], 0, v[0], v[1], v[2], 0,
|
|
13768
|
+
function workplanePlacedPlan(plan, origin, u2, v, normal2) {
|
|
13769
|
+
const placement = transformPlacement(origin, u2, v, normal2);
|
|
13770
|
+
const matrix = [u2[0], u2[1], u2[2], 0, v[0], v[1], v[2], 0, normal2[0], normal2[1], normal2[2], 0, origin[0], origin[1], origin[2], 1];
|
|
13275
13771
|
return appendShapeCompileTransform(cloneShapeCompilePlan(plan), {
|
|
13276
13772
|
kind: "workplanePlacement",
|
|
13277
13773
|
matrix,
|
|
@@ -13406,11 +13902,11 @@ function lowerSheetMetalBasePlan(model, output) {
|
|
|
13406
13902
|
const pieces = lowerSheetMetalBasePiecePlans(model, output).map((piece) => piece.plan);
|
|
13407
13903
|
return pieces.length === 1 ? pieces[0] : buildBooleanShapeCompilePlan("union", pieces);
|
|
13408
13904
|
}
|
|
13409
|
-
function descriptor(name, center2,
|
|
13905
|
+
function descriptor(name, center2, normal2, planar, uAxis, vAxis, semantic = "face", memberNames = [name], coplanar = planar) {
|
|
13410
13906
|
return {
|
|
13411
13907
|
name,
|
|
13412
13908
|
center: cloneVec3$7(center2),
|
|
13413
|
-
normal: cloneVec3$7(
|
|
13909
|
+
normal: cloneVec3$7(normal2),
|
|
13414
13910
|
planar,
|
|
13415
13911
|
uAxis: cloneFaceAxis(uAxis),
|
|
13416
13912
|
vAxis: cloneFaceAxis(vAxis),
|
|
@@ -13761,7 +14257,7 @@ function requireNonZeroFiniteScale3(value, label) {
|
|
|
13761
14257
|
}
|
|
13762
14258
|
return scale2;
|
|
13763
14259
|
}
|
|
13764
|
-
const EPS$
|
|
14260
|
+
const EPS$3 = 1e-10;
|
|
13765
14261
|
function subVec3(a2, b) {
|
|
13766
14262
|
return [a2[0] - b[0], a2[1] - b[1], a2[2] - b[2]];
|
|
13767
14263
|
}
|
|
@@ -13787,7 +14283,7 @@ function projectRadial(v, axis) {
|
|
|
13787
14283
|
function signedAngleAroundAxis(from, to, axis) {
|
|
13788
14284
|
const fromLen = lengthVec3$1(from);
|
|
13789
14285
|
const toLen = lengthVec3$1(to);
|
|
13790
|
-
if (fromLen < EPS$
|
|
14286
|
+
if (fromLen < EPS$3 || toLen < EPS$3) return 0;
|
|
13791
14287
|
const fn = scaleVec3(from, 1 / fromLen);
|
|
13792
14288
|
const tn = scaleVec3(to, 1 / toLen);
|
|
13793
14289
|
const sin2 = dotVec3$2(axis, crossVec3$1(fn, tn));
|
|
@@ -13808,19 +14304,19 @@ function solveRotateAroundAngle(axis, pivot, movingPoint, targetPoint, options =
|
|
|
13808
14304
|
const targetDecomp = projectRadial(target, unitAxis);
|
|
13809
14305
|
const movingRadialLen = lengthVec3$1(movingDecomp.radial);
|
|
13810
14306
|
const targetRadialLen = lengthVec3$1(targetDecomp.radial);
|
|
13811
|
-
if (movingRadialLen < EPS$
|
|
13812
|
-
if (mode === "line" && targetRadialLen >= EPS$
|
|
14307
|
+
if (movingRadialLen < EPS$3) {
|
|
14308
|
+
if (mode === "line" && targetRadialLen >= EPS$3) {
|
|
13813
14309
|
throw new Error("rotateAroundTo(...): moving point lies on the rotation axis, so line alignment is impossible");
|
|
13814
14310
|
}
|
|
13815
14311
|
return 0;
|
|
13816
14312
|
}
|
|
13817
14313
|
if (mode === "plane") {
|
|
13818
|
-
if (targetRadialLen < EPS$
|
|
14314
|
+
if (targetRadialLen < EPS$3) {
|
|
13819
14315
|
throw new Error("rotateAroundTo(...): target point lies on the rotation axis, so the target plane is undefined");
|
|
13820
14316
|
}
|
|
13821
14317
|
return signedAngleAroundAxis(movingDecomp.radial, targetDecomp.radial, unitAxis);
|
|
13822
14318
|
}
|
|
13823
|
-
if (targetRadialLen < EPS$
|
|
14319
|
+
if (targetRadialLen < EPS$3) {
|
|
13824
14320
|
throw new Error("rotateAroundTo(...): target line lies on the rotation axis, but the moving point does not");
|
|
13825
14321
|
}
|
|
13826
14322
|
const axialTol = 1e-8 * Math.max(1, Math.abs(movingDecomp.axial), Math.abs(targetDecomp.axial));
|
|
@@ -13857,7 +14353,7 @@ function multiplyMat4(a2, b) {
|
|
|
13857
14353
|
}
|
|
13858
14354
|
function normalizeVec3$2(v) {
|
|
13859
14355
|
const len2 = Math.sqrt(v[0] * v[0] + v[1] * v[1] + v[2] * v[2]);
|
|
13860
|
-
if (len2 < EPS$
|
|
14356
|
+
if (len2 < EPS$3) throw new Error("Axis must be non-zero");
|
|
13861
14357
|
return [v[0] / len2, v[1] / len2, v[2] / len2];
|
|
13862
14358
|
}
|
|
13863
14359
|
function transformPoint$2(m2, p2, w2) {
|
|
@@ -13887,7 +14383,7 @@ function invertMat4(m2) {
|
|
|
13887
14383
|
const b10 = a21 * a33 - a23 * a31;
|
|
13888
14384
|
const b11 = a22 * a33 - a23 * a32;
|
|
13889
14385
|
const det = b00 * b11 - b01 * b10 + b02 * b09 + b03 * b08 - b04 * b07 + b05 * b06;
|
|
13890
|
-
if (Math.abs(det) < EPS$
|
|
14386
|
+
if (Math.abs(det) < EPS$3) throw new Error("Transform matrix is not invertible");
|
|
13891
14387
|
const invDet = 1 / det;
|
|
13892
14388
|
out[0] = (a11 * b11 - a12 * b10 + a13 * b09) * invDet;
|
|
13893
14389
|
out[1] = (a02 * b10 - a01 * b11 - a03 * b09) * invDet;
|
|
@@ -14242,6 +14738,33 @@ function cloneSurfaceTrimLoopCompilePlan(loop) {
|
|
|
14242
14738
|
samples: loop.samples
|
|
14243
14739
|
};
|
|
14244
14740
|
}
|
|
14741
|
+
function cloneThicknessFieldCompilePlan$1(plan) {
|
|
14742
|
+
switch (plan.kind) {
|
|
14743
|
+
case "constant":
|
|
14744
|
+
return { kind: "constant", thickness: canonicalNumber(plan.thickness) };
|
|
14745
|
+
case "alongU":
|
|
14746
|
+
case "alongV":
|
|
14747
|
+
return {
|
|
14748
|
+
kind: plan.kind,
|
|
14749
|
+
stations: plan.stations.map((station) => ({
|
|
14750
|
+
t: canonicalNumber(station.t),
|
|
14751
|
+
thickness: canonicalNumber(station.thickness)
|
|
14752
|
+
})),
|
|
14753
|
+
easing: plan.easing
|
|
14754
|
+
};
|
|
14755
|
+
case "grid":
|
|
14756
|
+
return { kind: "grid", values: plan.values.map((row) => row.map(canonicalNumber)), easing: plan.easing };
|
|
14757
|
+
case "nurbs":
|
|
14758
|
+
return {
|
|
14759
|
+
kind: "nurbs",
|
|
14760
|
+
values: plan.values.map((row) => row.map(canonicalNumber)),
|
|
14761
|
+
degreeU: plan.degreeU,
|
|
14762
|
+
degreeV: plan.degreeV,
|
|
14763
|
+
knotsU: plan.knotsU.map(canonicalNumber),
|
|
14764
|
+
knotsV: plan.knotsV.map(canonicalNumber)
|
|
14765
|
+
};
|
|
14766
|
+
}
|
|
14767
|
+
}
|
|
14245
14768
|
function cloneAnalyticSurfaceCompilePlan(surface) {
|
|
14246
14769
|
switch (surface.kind) {
|
|
14247
14770
|
case "plane":
|
|
@@ -15098,7 +15621,8 @@ function cloneShapeCompilePlan(plan) {
|
|
|
15098
15621
|
result = {
|
|
15099
15622
|
kind: "surfaceThicken",
|
|
15100
15623
|
base: cloneShapeCompilePlan(plan.base),
|
|
15101
|
-
thickness: canonicalNumber(plan.thickness)
|
|
15624
|
+
thickness: canonicalNumber(plan.thickness),
|
|
15625
|
+
thicknessField: plan.thicknessField ? cloneThicknessFieldCompilePlan$1(plan.thicknessField) : void 0
|
|
15102
15626
|
};
|
|
15103
15627
|
break;
|
|
15104
15628
|
case "surfaceSolid":
|
|
@@ -15199,12 +15723,12 @@ function profilePlanFromCrossSection(cross2) {
|
|
|
15199
15723
|
if (plans.length === 1) return plans[0];
|
|
15200
15724
|
return { kind: "boolean", op: "union", profiles: plans, transforms: [] };
|
|
15201
15725
|
}
|
|
15202
|
-
function buildTrimByPlaneShapeCompilePlan(base,
|
|
15203
|
-
const len2 = Math.sqrt(
|
|
15726
|
+
function buildTrimByPlaneShapeCompilePlan(base, normal2, originOffset) {
|
|
15727
|
+
const len2 = Math.sqrt(normal2[0] * normal2[0] + normal2[1] * normal2[1] + normal2[2] * normal2[2]);
|
|
15204
15728
|
if (len2 === 0) throw new Error("trimByPlane: normal vector must not be zero");
|
|
15205
|
-
const nx =
|
|
15206
|
-
const ny =
|
|
15207
|
-
const nz =
|
|
15729
|
+
const nx = normal2[0] / len2;
|
|
15730
|
+
const ny = normal2[1] / len2;
|
|
15731
|
+
const nz = normal2[2] / len2;
|
|
15208
15732
|
const adjustedOffset = originOffset / len2;
|
|
15209
15733
|
return {
|
|
15210
15734
|
kind: "trimByPlane",
|
|
@@ -15227,11 +15751,12 @@ function buildLoftShapeCompilePlan(profiles, heights, options) {
|
|
|
15227
15751
|
edgeLabels: options.edgeLabels ? { ...options.edgeLabels } : void 0
|
|
15228
15752
|
};
|
|
15229
15753
|
}
|
|
15230
|
-
function buildSurfaceThickenShapeCompilePlan(base, thickness) {
|
|
15754
|
+
function buildSurfaceThickenShapeCompilePlan(base, thickness, thicknessField) {
|
|
15231
15755
|
return {
|
|
15232
15756
|
kind: "surfaceThicken",
|
|
15233
15757
|
base: cloneShapeCompilePlan(base),
|
|
15234
|
-
thickness: canonicalNumber(thickness)
|
|
15758
|
+
thickness: canonicalNumber(thickness),
|
|
15759
|
+
thicknessField: thicknessField ? cloneThicknessFieldCompilePlan$1(thicknessField) : void 0
|
|
15235
15760
|
};
|
|
15236
15761
|
}
|
|
15237
15762
|
const DRAFT_TO_LOFT_EPSILON = 1e-9;
|
|
@@ -17599,13 +18124,13 @@ function sdPolylineSweep3(node, x2, y2, z2) {
|
|
|
17599
18124
|
return d2;
|
|
17600
18125
|
}
|
|
17601
18126
|
function signedArea2D$2(loop) {
|
|
17602
|
-
let
|
|
18127
|
+
let area2 = 0;
|
|
17603
18128
|
for (let index2 = 0; index2 < loop.length; index2 += 1) {
|
|
17604
18129
|
const [x1, y1] = loop[index2];
|
|
17605
18130
|
const [x2, y2] = loop[(index2 + 1) % loop.length];
|
|
17606
|
-
|
|
18131
|
+
area2 += x1 * y2 - x2 * y1;
|
|
17607
18132
|
}
|
|
17608
|
-
return
|
|
18133
|
+
return area2 * 0.5;
|
|
17609
18134
|
}
|
|
17610
18135
|
function pointInLoop2D(point2, loop) {
|
|
17611
18136
|
let inside = false;
|
|
@@ -17613,8 +18138,8 @@ function pointInLoop2D(point2, loop) {
|
|
|
17613
18138
|
for (let index2 = 0, prev = loop.length - 1; index2 < loop.length; prev = index2, index2 += 1) {
|
|
17614
18139
|
const [xi, yi] = loop[index2];
|
|
17615
18140
|
const [xj, yj] = loop[prev];
|
|
17616
|
-
const
|
|
17617
|
-
if (
|
|
18141
|
+
const intersects2 = yi > py !== yj > py && px < (xj - xi) * (py - yi) / (yj - yi + 1e-20) + xi;
|
|
18142
|
+
if (intersects2) inside = !inside;
|
|
17618
18143
|
}
|
|
17619
18144
|
return inside;
|
|
17620
18145
|
}
|
|
@@ -18586,13 +19111,13 @@ function sdTaperedSegment(b, x2, y2, z2, a2, end, ra, rb) {
|
|
|
18586
19111
|
return b.sub(length3(b, sx, sy, sz), radius);
|
|
18587
19112
|
}
|
|
18588
19113
|
function signedArea2D$1(loop) {
|
|
18589
|
-
let
|
|
19114
|
+
let area2 = 0;
|
|
18590
19115
|
for (let index2 = 0; index2 < loop.length; index2 += 1) {
|
|
18591
19116
|
const [x1, y1] = loop[index2];
|
|
18592
19117
|
const [x2, y2] = loop[(index2 + 1) % loop.length];
|
|
18593
|
-
|
|
19118
|
+
area2 += x1 * y2 - x2 * y1;
|
|
18594
19119
|
}
|
|
18595
|
-
return
|
|
19120
|
+
return area2 * 0.5;
|
|
18596
19121
|
}
|
|
18597
19122
|
function sdProfileExtrude(b, node, x2, y2, z2) {
|
|
18598
19123
|
const zMin = Math.min(0, node.height);
|
|
@@ -18962,6 +19487,7 @@ function deepFreezePlanData(value) {
|
|
|
18962
19487
|
return value;
|
|
18963
19488
|
}
|
|
18964
19489
|
const SHAPE_BACKEND_MARKER = Symbol.for("forgecad.shapeBackend");
|
|
19490
|
+
const POSITION_OFFSET = 0;
|
|
18965
19491
|
const NORMAL_OFFSET = 3;
|
|
18966
19492
|
const UV_OFFSET = 6;
|
|
18967
19493
|
const NUM_PROP_POSITION_ONLY = 3;
|
|
@@ -19596,6 +20122,21 @@ function deBoor3D(controlPoints, weights, knots, degree, u2) {
|
|
|
19596
20122
|
if (wSum === 0) return [0, 0, 0];
|
|
19597
20123
|
return [wx / wSum, wy / wSum, wz / wSum];
|
|
19598
20124
|
}
|
|
20125
|
+
function deBoor2D(controlPoints, weights, knots, degree, u2) {
|
|
20126
|
+
const n = controlPoints.length;
|
|
20127
|
+
const span2 = findSpan(n, degree, u2, knots);
|
|
20128
|
+
const N = basisFuns(span2, u2, degree, knots);
|
|
20129
|
+
let wx = 0, wy = 0, wSum = 0;
|
|
20130
|
+
for (let j = 0; j <= degree; j++) {
|
|
20131
|
+
const idx = span2 - degree + j;
|
|
20132
|
+
const w2 = weights[idx] * N[j];
|
|
20133
|
+
wx += w2 * controlPoints[idx][0];
|
|
20134
|
+
wy += w2 * controlPoints[idx][1];
|
|
20135
|
+
wSum += w2;
|
|
20136
|
+
}
|
|
20137
|
+
if (wSum === 0) return [0, 0];
|
|
20138
|
+
return [wx / wSum, wy / wSum];
|
|
20139
|
+
}
|
|
19599
20140
|
function remapToKnotDomain(t, n, degree, knots) {
|
|
19600
20141
|
const uMin = knots[degree];
|
|
19601
20142
|
const uMax = knots[n];
|
|
@@ -19974,13 +20515,13 @@ function vec3Norm(v) {
|
|
|
19974
20515
|
return [v[0] / len2, v[1] / len2, v[2] / len2];
|
|
19975
20516
|
}
|
|
19976
20517
|
function signedArea2D(loop) {
|
|
19977
|
-
let
|
|
20518
|
+
let area2 = 0;
|
|
19978
20519
|
for (let index2 = 0; index2 < loop.length; index2 += 1) {
|
|
19979
20520
|
const [x1, y1] = loop[index2];
|
|
19980
20521
|
const [x2, y2] = loop[(index2 + 1) % loop.length];
|
|
19981
|
-
|
|
20522
|
+
area2 += x1 * y2 - x2 * y1;
|
|
19982
20523
|
}
|
|
19983
|
-
return
|
|
20524
|
+
return area2 * 0.5;
|
|
19984
20525
|
}
|
|
19985
20526
|
function buildSdfLoopEdges(pts) {
|
|
19986
20527
|
const n = pts.length;
|
|
@@ -20606,6 +21147,9 @@ function clamp$1(value, min2, max2) {
|
|
|
20606
21147
|
function dot3$4(a2, b) {
|
|
20607
21148
|
return a2[0] * b[0] + a2[1] * b[1] + a2[2] * b[2];
|
|
20608
21149
|
}
|
|
21150
|
+
function cross3$6(a2, b) {
|
|
21151
|
+
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]];
|
|
21152
|
+
}
|
|
20609
21153
|
function normalize3$2(v, context) {
|
|
20610
21154
|
const length4 = Math.hypot(v[0], v[1], v[2]);
|
|
20611
21155
|
if (length4 <= 1e-12) throw new Error(`${context} requires a non-zero vector`);
|
|
@@ -20659,24 +21203,59 @@ function inverseMat4(m2) {
|
|
|
20659
21203
|
return out;
|
|
20660
21204
|
}
|
|
20661
21205
|
function signedArea2$1(loop) {
|
|
20662
|
-
let
|
|
21206
|
+
let area2 = 0;
|
|
20663
21207
|
for (let idx = 0; idx < loop.length; idx += 1) {
|
|
20664
21208
|
const current = loop[idx];
|
|
20665
21209
|
const next = loop[(idx + 1) % loop.length];
|
|
20666
|
-
|
|
21210
|
+
area2 += current[0] * next[1] - next[0] * current[1];
|
|
21211
|
+
}
|
|
21212
|
+
return area2 * 0.5;
|
|
21213
|
+
}
|
|
21214
|
+
function mirrorMatrixFromNormal(normal2) {
|
|
21215
|
+
const n = normalize3$2(normal2, "SDF mirror transform");
|
|
21216
|
+
return [
|
|
21217
|
+
1 - 2 * n[0] * n[0],
|
|
21218
|
+
-2 * n[1] * n[0],
|
|
21219
|
+
-2 * n[2] * n[0],
|
|
21220
|
+
0,
|
|
21221
|
+
-2 * n[0] * n[1],
|
|
21222
|
+
1 - 2 * n[1] * n[1],
|
|
21223
|
+
-2 * n[2] * n[1],
|
|
21224
|
+
0,
|
|
21225
|
+
-2 * n[0] * n[2],
|
|
21226
|
+
-2 * n[1] * n[2],
|
|
21227
|
+
1 - 2 * n[2] * n[2],
|
|
21228
|
+
0,
|
|
21229
|
+
0,
|
|
21230
|
+
0,
|
|
21231
|
+
0,
|
|
21232
|
+
1
|
|
21233
|
+
];
|
|
21234
|
+
}
|
|
21235
|
+
function matrixFromShapeCompileTransformStep(step) {
|
|
21236
|
+
switch (step.kind) {
|
|
21237
|
+
case "translate":
|
|
21238
|
+
return Transform.translation(step.x, step.y, step.z).toArray();
|
|
21239
|
+
case "scale":
|
|
21240
|
+
return Transform.scale([step.x, step.y, step.z]).toArray();
|
|
21241
|
+
case "rotateAround":
|
|
21242
|
+
return Transform.rotationAxis([step.axisX, step.axisY, step.axisZ], step.degrees, [step.pivotX, step.pivotY, step.pivotZ]).toArray();
|
|
21243
|
+
case "workplanePlacement":
|
|
21244
|
+
return step.matrix;
|
|
21245
|
+
case "mirror":
|
|
21246
|
+
return mirrorMatrixFromNormal([step.normalX, step.normalY, step.normalZ]);
|
|
20667
21247
|
}
|
|
20668
|
-
return area * 0.5;
|
|
20669
21248
|
}
|
|
20670
21249
|
function linearDeterminant(matrix) {
|
|
20671
21250
|
return matrix[0] * (matrix[5] * matrix[10] - matrix[9] * matrix[6]) - matrix[4] * (matrix[1] * matrix[10] - matrix[9] * matrix[2]) + matrix[8] * (matrix[1] * matrix[6] - matrix[5] * matrix[2]);
|
|
20672
21251
|
}
|
|
20673
|
-
function transformNormal(matrix,
|
|
21252
|
+
function transformNormal(matrix, normal2) {
|
|
20674
21253
|
const inverse = inverseMat4(matrix);
|
|
20675
21254
|
return normalize3$2(
|
|
20676
21255
|
[
|
|
20677
|
-
inverse[0] *
|
|
20678
|
-
inverse[4] *
|
|
20679
|
-
inverse[8] *
|
|
21256
|
+
inverse[0] * normal2[0] + inverse[1] * normal2[1] + inverse[2] * normal2[2],
|
|
21257
|
+
inverse[4] * normal2[0] + inverse[5] * normal2[1] + inverse[6] * normal2[2],
|
|
21258
|
+
inverse[8] * normal2[0] + inverse[9] * normal2[1] + inverse[10] * normal2[2]
|
|
20680
21259
|
],
|
|
20681
21260
|
"SDF mesh normal transform"
|
|
20682
21261
|
);
|
|
@@ -20691,10 +21270,10 @@ function transformRuntimeMesh(mesh, matrix) {
|
|
|
20691
21270
|
vertProperties[offset + 1] = point2[1];
|
|
20692
21271
|
vertProperties[offset + 2] = point2[2];
|
|
20693
21272
|
if (mesh.numProp >= 6) {
|
|
20694
|
-
const
|
|
20695
|
-
vertProperties[offset + 3] =
|
|
20696
|
-
vertProperties[offset + 4] =
|
|
20697
|
-
vertProperties[offset + 5] =
|
|
21273
|
+
const normal2 = transformNormal(matrix, [vertProperties[offset + 3], vertProperties[offset + 4], vertProperties[offset + 5]]);
|
|
21274
|
+
vertProperties[offset + 3] = normal2[0];
|
|
21275
|
+
vertProperties[offset + 4] = normal2[1];
|
|
21276
|
+
vertProperties[offset + 5] = normal2[2];
|
|
20698
21277
|
}
|
|
20699
21278
|
}
|
|
20700
21279
|
const triVerts = new Uint32Array(mesh.triVerts);
|
|
@@ -20707,6 +21286,9 @@ function transformRuntimeMesh(mesh, matrix) {
|
|
|
20707
21286
|
}
|
|
20708
21287
|
return { ...mesh, vertProperties, triVerts };
|
|
20709
21288
|
}
|
|
21289
|
+
function transformRuntimeMeshSteps(mesh, steps) {
|
|
21290
|
+
return steps.reduce((current, step) => transformRuntimeMesh(current, matrixFromShapeCompileTransformStep(step)), mesh);
|
|
21291
|
+
}
|
|
20710
21292
|
function cloneBounds3(bounds) {
|
|
20711
21293
|
return {
|
|
20712
21294
|
min: [bounds.min[0], bounds.min[1], bounds.min[2]],
|
|
@@ -20809,9 +21391,9 @@ function distanceSqToTriangle(p2, tri) {
|
|
|
20809
21391
|
if (vb <= 0 && d2 >= 0 && d6 <= 0) return distanceSqToSegment(p2, tri.a, tri.c);
|
|
20810
21392
|
const va = d3 * d6 - d5 * d4;
|
|
20811
21393
|
if (va <= 0 && d4 - d3 >= 0 && d5 - d6 >= 0) return distanceSqToSegment(p2, tri.b, tri.c);
|
|
20812
|
-
const
|
|
20813
|
-
const normalLenSq = Math.max(dot3$4(
|
|
20814
|
-
const signed = dot3$4(ap,
|
|
21394
|
+
const normal2 = [ab[1] * ac[2] - ab[2] * ac[1], ab[2] * ac[0] - ab[0] * ac[2], ab[0] * ac[1] - ab[1] * ac[0]];
|
|
21395
|
+
const normalLenSq = Math.max(dot3$4(normal2, normal2), 1e-20);
|
|
21396
|
+
const signed = dot3$4(ap, normal2);
|
|
20815
21397
|
return signed * signed / normalLenSq;
|
|
20816
21398
|
}
|
|
20817
21399
|
function rayHitsTriangleX(p2, tri) {
|
|
@@ -21258,13 +21840,13 @@ function applyConcaveChamferSelectionToManifold(base, selection, size, wasm) {
|
|
|
21258
21840
|
const chamfer = triangle3.extrude(span2, 0, 0, void 0, false).transform(frame);
|
|
21259
21841
|
return wasm.Manifold.union([base, chamfer]);
|
|
21260
21842
|
}
|
|
21261
|
-
const EPS$
|
|
21843
|
+
const EPS$2 = 1e-8;
|
|
21262
21844
|
function midpoint$1(start, end) {
|
|
21263
21845
|
return [(start[0] + end[0]) * 0.5, (start[1] + end[1]) * 0.5, (start[2] + end[2]) * 0.5];
|
|
21264
21846
|
}
|
|
21265
21847
|
function normalize$4(v) {
|
|
21266
21848
|
const len2 = Math.hypot(v[0], v[1], v[2]);
|
|
21267
|
-
if (len2 <= EPS$
|
|
21849
|
+
if (len2 <= EPS$2) throw new Error("Edge feature selection requires a non-zero direction vector");
|
|
21268
21850
|
return [v[0] / len2, v[1] / len2, v[2] / len2];
|
|
21269
21851
|
}
|
|
21270
21852
|
function subtract(a2, b) {
|
|
@@ -21343,7 +21925,7 @@ function rigidTransformForEdgeStep(step) {
|
|
|
21343
21925
|
case "mirror": {
|
|
21344
21926
|
const [nx0, ny0, nz0] = [step.normalX, step.normalY, step.normalZ];
|
|
21345
21927
|
const len2 = Math.hypot(nx0, ny0, nz0);
|
|
21346
|
-
if (len2 <= EPS$
|
|
21928
|
+
if (len2 <= EPS$2) return Transform.identity();
|
|
21347
21929
|
const nx = nx0 / len2;
|
|
21348
21930
|
const ny = ny0 / len2;
|
|
21349
21931
|
const nz = nz0 / len2;
|
|
@@ -21643,7 +22225,7 @@ function isRectangleProfile(points) {
|
|
|
21643
22225
|
return [next[0] - point2[0], next[1] - point2[1]];
|
|
21644
22226
|
});
|
|
21645
22227
|
const lengths = vectors.map(([x2, y2]) => Math.hypot(x2, y2));
|
|
21646
|
-
if (lengths.some((length4) => length4 <= EPS$
|
|
22228
|
+
if (lengths.some((length4) => length4 <= EPS$2)) return false;
|
|
21647
22229
|
const dot01 = vectors[0][0] * vectors[1][0] + vectors[0][1] * vectors[1][1];
|
|
21648
22230
|
const dot12 = vectors[1][0] * vectors[2][0] + vectors[1][1] * vectors[2][1];
|
|
21649
22231
|
const dot23 = vectors[2][0] * vectors[3][0] + vectors[2][1] * vectors[3][1];
|
|
@@ -22171,6 +22753,16 @@ function signedTriangleMeshVolume(triangles, vertexAt2) {
|
|
|
22171
22753
|
}
|
|
22172
22754
|
return volume6 / 6;
|
|
22173
22755
|
}
|
|
22756
|
+
function trianglesToTriVerts(triangles) {
|
|
22757
|
+
const triVerts = new Uint32Array(triangles.length * 3);
|
|
22758
|
+
for (let triIndex = 0; triIndex < triangles.length; triIndex++) {
|
|
22759
|
+
const triangle3 = triangles[triIndex];
|
|
22760
|
+
triVerts[triIndex * 3] = triangle3[0];
|
|
22761
|
+
triVerts[triIndex * 3 + 1] = triangle3[1];
|
|
22762
|
+
triVerts[triIndex * 3 + 2] = triangle3[2];
|
|
22763
|
+
}
|
|
22764
|
+
return triVerts;
|
|
22765
|
+
}
|
|
22174
22766
|
function triVertsToTriangles(triVerts) {
|
|
22175
22767
|
const triangles = [];
|
|
22176
22768
|
for (let idx = 0; idx < triVerts.length; idx += 3) {
|
|
@@ -22197,23 +22789,23 @@ function cleanZero(value) {
|
|
|
22197
22789
|
return Object.is(value, -0) ? 0 : value;
|
|
22198
22790
|
}
|
|
22199
22791
|
function planeFrameToWorldToPlaneMatrix(frame) {
|
|
22200
|
-
const { origin, u: u2, v, normal } = frame;
|
|
22792
|
+
const { origin, u: u2, v, normal: normal2 } = frame;
|
|
22201
22793
|
return [
|
|
22202
22794
|
u2[0],
|
|
22203
22795
|
v[0],
|
|
22204
|
-
|
|
22796
|
+
normal2[0],
|
|
22205
22797
|
0,
|
|
22206
22798
|
u2[1],
|
|
22207
22799
|
v[1],
|
|
22208
|
-
|
|
22800
|
+
normal2[1],
|
|
22209
22801
|
0,
|
|
22210
22802
|
u2[2],
|
|
22211
22803
|
v[2],
|
|
22212
|
-
|
|
22804
|
+
normal2[2],
|
|
22213
22805
|
0,
|
|
22214
22806
|
cleanZero(-(u2[0] * origin[0] + u2[1] * origin[1] + u2[2] * origin[2])),
|
|
22215
22807
|
cleanZero(-(v[0] * origin[0] + v[1] * origin[1] + v[2] * origin[2])),
|
|
22216
|
-
cleanZero(-(
|
|
22808
|
+
cleanZero(-(normal2[0] * origin[0] + normal2[1] * origin[1] + normal2[2] * origin[2])),
|
|
22217
22809
|
1
|
|
22218
22810
|
];
|
|
22219
22811
|
}
|
|
@@ -22614,8 +23206,8 @@ function classifyLoops(loops) {
|
|
|
22614
23206
|
const holes = [];
|
|
22615
23207
|
for (const loop of loops) {
|
|
22616
23208
|
if (loop.length < 3) continue;
|
|
22617
|
-
const
|
|
22618
|
-
if (
|
|
23209
|
+
const area2 = signedArea$3(loop);
|
|
23210
|
+
if (area2 >= 0) {
|
|
22619
23211
|
outers.push(loop);
|
|
22620
23212
|
} else {
|
|
22621
23213
|
holes.push(loop);
|
|
@@ -22665,13 +23257,13 @@ function matchLoopsAcrossProfiles(profileLoops) {
|
|
|
22665
23257
|
return groups;
|
|
22666
23258
|
}
|
|
22667
23259
|
function signedArea$3(loop) {
|
|
22668
|
-
let
|
|
23260
|
+
let area2 = 0;
|
|
22669
23261
|
for (let i = 0; i < loop.length; i++) {
|
|
22670
23262
|
const p1 = loop[i];
|
|
22671
23263
|
const p2 = loop[(i + 1) % loop.length];
|
|
22672
|
-
|
|
23264
|
+
area2 += p1[0] * p2[1] - p2[0] * p1[1];
|
|
22673
23265
|
}
|
|
22674
|
-
return
|
|
23266
|
+
return area2 * 0.5;
|
|
22675
23267
|
}
|
|
22676
23268
|
function detectCorners(loop) {
|
|
22677
23269
|
const corners = [];
|
|
@@ -22766,7 +23358,7 @@ function maxQuadDeviation(rings, heights, colA, colB) {
|
|
|
22766
23358
|
const b = [rings[i][colB][0], rings[i][colB][1], heights[i]];
|
|
22767
23359
|
const c2 = [rings[i + 1][colB][0], rings[i + 1][colB][1], heights[i + 1]];
|
|
22768
23360
|
const d2 = [rings[i + 1][colA][0], rings[i + 1][colA][1], heights[i + 1]];
|
|
22769
|
-
const n = cross3$5(sub3$
|
|
23361
|
+
const n = cross3$5(sub3$2(b, a2), sub3$2(d2, a2));
|
|
22770
23362
|
const len2 = Math.hypot(n[0], n[1], n[2]);
|
|
22771
23363
|
if (len2 < 1e-12) continue;
|
|
22772
23364
|
const deviation = Math.abs((n[0] * (c2[0] - a2[0]) + n[1] * (c2[1] - a2[1]) + n[2] * (c2[2] - a2[2])) / len2);
|
|
@@ -23044,16 +23636,16 @@ function buildSpanRowsFromStations(stations) {
|
|
|
23044
23636
|
function stationTangent(stations, t, i, j) {
|
|
23045
23637
|
const R = stations.length;
|
|
23046
23638
|
if (i === 0) {
|
|
23047
|
-
return scale3$
|
|
23639
|
+
return scale3$2(sub3$2(stations[1][j], stations[0][j]), 1 / (t[1] - t[0]));
|
|
23048
23640
|
}
|
|
23049
23641
|
if (i === R - 1) {
|
|
23050
|
-
return scale3$
|
|
23642
|
+
return scale3$2(sub3$2(stations[R - 1][j], stations[R - 2][j]), 1 / (t[R - 1] - t[R - 2]));
|
|
23051
23643
|
}
|
|
23052
23644
|
const hPrev = t[i] - t[i - 1];
|
|
23053
23645
|
const hNext = t[i + 1] - t[i];
|
|
23054
|
-
const dPrev = scale3$
|
|
23055
|
-
const dNext = scale3$
|
|
23056
|
-
return scale3$
|
|
23646
|
+
const dPrev = scale3$2(sub3$2(stations[i][j], stations[i - 1][j]), 1 / hPrev);
|
|
23647
|
+
const dNext = scale3$2(sub3$2(stations[i + 1][j], stations[i][j]), 1 / hNext);
|
|
23648
|
+
return scale3$2(add3$2(scale3$2(dPrev, hNext), scale3$2(dNext, hPrev)), 1 / (hPrev + hNext));
|
|
23057
23649
|
}
|
|
23058
23650
|
function hermite(p0, m0, p1, m1, h, u2) {
|
|
23059
23651
|
const u22 = u2 * u2;
|
|
@@ -23080,8 +23672,8 @@ function hermite(p0, m0, p1, m1, h, u2) {
|
|
|
23080
23672
|
}
|
|
23081
23673
|
function stitchSingleLoopLoft(loops, heights, wasm, options) {
|
|
23082
23674
|
const normalizedLoops = loops.map((loop) => {
|
|
23083
|
-
const
|
|
23084
|
-
return
|
|
23675
|
+
const area2 = signedArea$3(loop);
|
|
23676
|
+
return area2 < 0 ? [...loop].reverse() : loop;
|
|
23085
23677
|
});
|
|
23086
23678
|
const compatible = buildCompatibleRings(normalizedLoops, heights, options.edgeLength);
|
|
23087
23679
|
if (!compatible) return null;
|
|
@@ -23108,12 +23700,12 @@ function stitchSingleLoopLoft(loops, heights, wasm, options) {
|
|
|
23108
23700
|
const curr = points[j];
|
|
23109
23701
|
const next = points[(j + 1) % N];
|
|
23110
23702
|
if (cornerSet.has(j)) {
|
|
23111
|
-
const nFwd = surfaceNormal(sub3$
|
|
23112
|
-
const nBwd = surfaceNormal(sub3$
|
|
23703
|
+
const nFwd = surfaceNormal(sub3$2(next, curr), tangents[j]);
|
|
23704
|
+
const nBwd = surfaceNormal(sub3$2(curr, prev), tangents[j]);
|
|
23113
23705
|
fwd[j] = pushVert(curr, nFwd);
|
|
23114
23706
|
bwd[j] = pushVert(curr, nBwd);
|
|
23115
23707
|
} else {
|
|
23116
|
-
const idx = pushVert(curr, surfaceNormal(sub3$
|
|
23708
|
+
const idx = pushVert(curr, surfaceNormal(sub3$2(next, prev), tangents[j]));
|
|
23117
23709
|
fwd[j] = idx;
|
|
23118
23710
|
bwd[j] = idx;
|
|
23119
23711
|
}
|
|
@@ -23166,8 +23758,8 @@ function stitchSingleLoopLoft(loops, heights, wasm, options) {
|
|
|
23166
23758
|
}
|
|
23167
23759
|
function stitchSingleLoopLoftOnFrames(loops, frames, wasm, options) {
|
|
23168
23760
|
const normalizedLoops = loops.map((loop) => {
|
|
23169
|
-
const
|
|
23170
|
-
return
|
|
23761
|
+
const area2 = signedArea$3(loop);
|
|
23762
|
+
return area2 < 0 ? [...loop].reverse() : loop;
|
|
23171
23763
|
});
|
|
23172
23764
|
const stationDistances = cumulativeFrameDistances(frames);
|
|
23173
23765
|
const compatible = buildCompatibleRings(normalizedLoops, stationDistances, options.edgeLength);
|
|
@@ -23196,12 +23788,12 @@ function stitchSingleLoopLoftOnFrames(loops, frames, wasm, options) {
|
|
|
23196
23788
|
const curr = points[j];
|
|
23197
23789
|
const next = points[(j + 1) % N];
|
|
23198
23790
|
if (cornerSet.has(j)) {
|
|
23199
|
-
const nFwd = surfaceNormal(sub3$
|
|
23200
|
-
const nBwd = surfaceNormal(sub3$
|
|
23791
|
+
const nFwd = surfaceNormal(sub3$2(next, curr), tangents[j]);
|
|
23792
|
+
const nBwd = surfaceNormal(sub3$2(curr, prev), tangents[j]);
|
|
23201
23793
|
fwd[j] = pushVert(curr, nFwd);
|
|
23202
23794
|
bwd[j] = pushVert(curr, nBwd);
|
|
23203
23795
|
} else {
|
|
23204
|
-
const idx = pushVert(curr, surfaceNormal(sub3$
|
|
23796
|
+
const idx = pushVert(curr, surfaceNormal(sub3$2(next, prev), tangents[j]));
|
|
23205
23797
|
fwd[j] = idx;
|
|
23206
23798
|
bwd[j] = idx;
|
|
23207
23799
|
}
|
|
@@ -23223,7 +23815,7 @@ function stitchSingleLoopLoftOnFrames(loops, frames, wasm, options) {
|
|
|
23223
23815
|
}
|
|
23224
23816
|
const bottomTris = wasm.triangulate([rings[0]]);
|
|
23225
23817
|
const bottomBase = vertCount;
|
|
23226
|
-
const bottomNormal = scale3$
|
|
23818
|
+
const bottomNormal = scale3$2(frames[0].normal, -1);
|
|
23227
23819
|
for (const p2 of rows[0].points) pushVert(p2, bottomNormal);
|
|
23228
23820
|
for (const tri of bottomTris) {
|
|
23229
23821
|
const [v0, v1, v2] = Array.isArray(tri) ? tri : [tri[0], tri[1], tri[2]];
|
|
@@ -23276,13 +23868,13 @@ function surfaceNormal(chord, span2) {
|
|
|
23276
23868
|
}
|
|
23277
23869
|
return [n[0] / len2, n[1] / len2, n[2] / len2];
|
|
23278
23870
|
}
|
|
23279
|
-
function sub3$
|
|
23871
|
+
function sub3$2(a2, b) {
|
|
23280
23872
|
return [a2[0] - b[0], a2[1] - b[1], a2[2] - b[2]];
|
|
23281
23873
|
}
|
|
23282
|
-
function add3$
|
|
23874
|
+
function add3$2(a2, b) {
|
|
23283
23875
|
return [a2[0] + b[0], a2[1] + b[1], a2[2] + b[2]];
|
|
23284
23876
|
}
|
|
23285
|
-
function scale3$
|
|
23877
|
+
function scale3$2(a2, s) {
|
|
23286
23878
|
return [a2[0] * s, a2[1] * s, a2[2] * s];
|
|
23287
23879
|
}
|
|
23288
23880
|
function cross3$5(a2, b) {
|
|
@@ -23338,19 +23930,19 @@ const _ManifoldShapeBackend = class _ManifoldShapeBackend {
|
|
|
23338
23930
|
scale(v) {
|
|
23339
23931
|
return new _ManifoldShapeBackend(this.getLiveManifold("scale()").scale(v));
|
|
23340
23932
|
}
|
|
23341
|
-
mirror(
|
|
23342
|
-
return new _ManifoldShapeBackend(this.getLiveManifold("mirror()").mirror(
|
|
23933
|
+
mirror(normal2) {
|
|
23934
|
+
return new _ManifoldShapeBackend(this.getLiveManifold("mirror()").mirror(normal2));
|
|
23343
23935
|
}
|
|
23344
23936
|
split(other) {
|
|
23345
23937
|
const [inside, outside] = this.getLiveManifold("split()").split(requireManifoldShapeBackend(other, "ShapeBackend.split()"));
|
|
23346
23938
|
return [new _ManifoldShapeBackend(inside), new _ManifoldShapeBackend(outside)];
|
|
23347
23939
|
}
|
|
23348
|
-
splitByPlane(
|
|
23349
|
-
const [inside, outside] = this.getLiveManifold("splitByPlane()").splitByPlane(
|
|
23940
|
+
splitByPlane(normal2, originOffset) {
|
|
23941
|
+
const [inside, outside] = this.getLiveManifold("splitByPlane()").splitByPlane(normal2, originOffset);
|
|
23350
23942
|
return [new _ManifoldShapeBackend(inside), new _ManifoldShapeBackend(outside)];
|
|
23351
23943
|
}
|
|
23352
|
-
trimByPlane(
|
|
23353
|
-
return new _ManifoldShapeBackend(this.getLiveManifold("trimByPlane()").trimByPlane(
|
|
23944
|
+
trimByPlane(normal2, originOffset) {
|
|
23945
|
+
return new _ManifoldShapeBackend(this.getLiveManifold("trimByPlane()").trimByPlane(normal2, originOffset));
|
|
23354
23946
|
}
|
|
23355
23947
|
simplify(tolerance) {
|
|
23356
23948
|
return new _ManifoldShapeBackend(this.getLiveManifold("simplify()").simplify(tolerance));
|
|
@@ -23635,13 +24227,13 @@ function stitchLoopAlongPath(loop, _path, frames, wasm) {
|
|
|
23635
24227
|
}
|
|
23636
24228
|
}
|
|
23637
24229
|
function signedArea$2(loop) {
|
|
23638
|
-
let
|
|
24230
|
+
let area2 = 0;
|
|
23639
24231
|
for (let i = 0; i < loop.length; i++) {
|
|
23640
24232
|
const p1 = loop[i];
|
|
23641
24233
|
const p2 = loop[(i + 1) % loop.length];
|
|
23642
|
-
|
|
24234
|
+
area2 += p1[0] * p2[1] - p2[0] * p1[1];
|
|
23643
24235
|
}
|
|
23644
|
-
return
|
|
24236
|
+
return area2 * 0.5;
|
|
23645
24237
|
}
|
|
23646
24238
|
function sub$2(a2, b) {
|
|
23647
24239
|
return [a2[0] - b[0], a2[1] - b[1], a2[2] - b[2]];
|
|
@@ -23683,6 +24275,27 @@ function disposeWasmObject(value) {
|
|
|
23683
24275
|
function disposeWasmObjects(values) {
|
|
23684
24276
|
for (const value of values) disposeWasmObject(value);
|
|
23685
24277
|
}
|
|
24278
|
+
function lowerRuntimeMeshToManifold(mesh, wasm, context) {
|
|
24279
|
+
const vertexCount = mesh.numVert ?? mesh.vertProperties.length / mesh.numProp;
|
|
24280
|
+
let triVerts = mesh.triVerts;
|
|
24281
|
+
if (!isClosedConsistentlyWoundTriangleMesh(triVerts, vertexCount)) {
|
|
24282
|
+
triVerts = trianglesToTriVerts(orientClosedTriangleMesh(triVertsToTriangles(triVerts), context));
|
|
24283
|
+
}
|
|
24284
|
+
if (!isClosedConsistentlyWoundTriangleMesh(triVerts, vertexCount)) {
|
|
24285
|
+
throw new Error(`${context} produced an open, non-manifold, or inconsistently wound triangle mesh.`);
|
|
24286
|
+
}
|
|
24287
|
+
const wasmMesh = new wasm.Mesh({
|
|
24288
|
+
numProp: mesh.numProp,
|
|
24289
|
+
vertProperties: new Float32Array(mesh.vertProperties),
|
|
24290
|
+
triVerts: new Uint32Array(triVerts)
|
|
24291
|
+
});
|
|
24292
|
+
try {
|
|
24293
|
+
wasmMesh.merge();
|
|
24294
|
+
return new wasm.Manifold(wasmMesh);
|
|
24295
|
+
} finally {
|
|
24296
|
+
disposeWasmObject(wasmMesh);
|
|
24297
|
+
}
|
|
24298
|
+
}
|
|
23686
24299
|
function nowMs$1() {
|
|
23687
24300
|
return typeof performance !== "undefined" ? performance.now() : Date.now();
|
|
23688
24301
|
}
|
|
@@ -23995,27 +24608,27 @@ function cross3$4(a2, b) {
|
|
|
23995
24608
|
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]];
|
|
23996
24609
|
}
|
|
23997
24610
|
function fromSlicesPlaneFrameForManifold(normalInput) {
|
|
23998
|
-
const
|
|
23999
|
-
const [nx, ny, nz] =
|
|
24611
|
+
const normal2 = normalizeVec3$1(normalInput, "Shape.fromSlices group normal");
|
|
24612
|
+
const [nx, ny, nz] = normal2;
|
|
24000
24613
|
if (Math.abs(nz) > 1 - 1e-8) {
|
|
24001
|
-
return { u: [1, 0, 0], v: [0, nz > 0 ? 1 : -1, 0], normal };
|
|
24614
|
+
return { u: [1, 0, 0], v: [0, nz > 0 ? 1 : -1, 0], normal: normal2 };
|
|
24002
24615
|
}
|
|
24003
24616
|
if (Math.abs(ny) > 1 - 1e-8) {
|
|
24004
|
-
return { u: [1, 0, 0], v: [0, 0, ny > 0 ? 1 : -1], normal };
|
|
24617
|
+
return { u: [1, 0, 0], v: [0, 0, ny > 0 ? 1 : -1], normal: normal2 };
|
|
24005
24618
|
}
|
|
24006
24619
|
if (Math.abs(nx) > 1 - 1e-8) {
|
|
24007
|
-
return { u: [0, 1, 0], v: [0, 0, nx > 0 ? 1 : -1], normal };
|
|
24620
|
+
return { u: [0, 1, 0], v: [0, 0, nx > 0 ? 1 : -1], normal: normal2 };
|
|
24008
24621
|
}
|
|
24009
24622
|
const reference = Math.abs(nx) < 0.9 ? [1, 0, 0] : [0, 1, 0];
|
|
24010
|
-
const u2 = normalizeVec3$1(cross3$4(reference,
|
|
24011
|
-
return { u: u2, v: cross3$4(
|
|
24623
|
+
const u2 = normalizeVec3$1(cross3$4(reference, normal2), "Shape.fromSlices profile u axis");
|
|
24624
|
+
return { u: u2, v: cross3$4(normal2, u2), normal: normal2 };
|
|
24012
24625
|
}
|
|
24013
|
-
function fromSlicesLocalToWorldMatrixForManifold(
|
|
24014
|
-
const frame = fromSlicesPlaneFrameForManifold(
|
|
24626
|
+
function fromSlicesLocalToWorldMatrixForManifold(normal2) {
|
|
24627
|
+
const frame = fromSlicesPlaneFrameForManifold(normal2);
|
|
24015
24628
|
return Transform.from(planeFrameToWorldToPlaneMatrix({ origin: [0, 0, 0], u: frame.u, v: frame.v, normal: frame.normal })).inverse().toArray();
|
|
24016
24629
|
}
|
|
24017
|
-
function transformZAlignedFromSlicesPlanForManifold(base,
|
|
24018
|
-
const matrix = fromSlicesLocalToWorldMatrixForManifold(
|
|
24630
|
+
function transformZAlignedFromSlicesPlanForManifold(base, normal2) {
|
|
24631
|
+
const matrix = fromSlicesLocalToWorldMatrixForManifold(normal2);
|
|
24019
24632
|
const isIdentity = Math.abs(matrix[0] - 1) <= OFFSET_SOLID_EPS && Math.abs(matrix[5] - 1) <= OFFSET_SOLID_EPS && Math.abs(matrix[10] - 1) <= OFFSET_SOLID_EPS && Math.abs(matrix[15] - 1) <= OFFSET_SOLID_EPS && matrix.every((value, idx) => idx === 0 || idx === 5 || idx === 10 || idx === 15 ? true : Math.abs(value) <= OFFSET_SOLID_EPS);
|
|
24020
24633
|
if (isIdentity) return base;
|
|
24021
24634
|
return {
|
|
@@ -24149,13 +24762,13 @@ function profilePolygonsForManifold(profile, wasm) {
|
|
|
24149
24762
|
}
|
|
24150
24763
|
}
|
|
24151
24764
|
function signedArea2(loop) {
|
|
24152
|
-
let
|
|
24765
|
+
let area2 = 0;
|
|
24153
24766
|
for (let idx = 0; idx < loop.length; idx++) {
|
|
24154
24767
|
const current = loop[idx];
|
|
24155
24768
|
const next = loop[(idx + 1) % loop.length];
|
|
24156
|
-
|
|
24769
|
+
area2 += current[0] * next[1] - next[0] * current[1];
|
|
24157
24770
|
}
|
|
24158
|
-
return
|
|
24771
|
+
return area2 * 0.5;
|
|
24159
24772
|
}
|
|
24160
24773
|
function profilePolygonLoopTopologyMatches(left, right) {
|
|
24161
24774
|
let leftOuterCount = 0;
|
|
@@ -24347,8 +24960,8 @@ function lowerShapeSweepCompilePlan(plan, wasm) {
|
|
|
24347
24960
|
});
|
|
24348
24961
|
return lowerSdfToManifold(levelSetFieldToStandardSdf3(input.sdf), input.bounds, input.edgeLength, wasm);
|
|
24349
24962
|
}
|
|
24350
|
-
function buildPlaneFrame(
|
|
24351
|
-
const [nx, ny, nz] =
|
|
24963
|
+
function buildPlaneFrame(normal2) {
|
|
24964
|
+
const [nx, ny, nz] = normal2;
|
|
24352
24965
|
if (Math.abs(nz) > 1 - 1e-8) {
|
|
24353
24966
|
const s = nz > 0 ? 1 : -1;
|
|
24354
24967
|
return { u: [1, 0, 0], v: [0, s, 0] };
|
|
@@ -24784,8 +25397,8 @@ function edgeSegmentToSelection(segment) {
|
|
|
24784
25397
|
const surfaceDirB = pickSurfaceDir(nBx, nBy);
|
|
24785
25398
|
const projX = avgX;
|
|
24786
25399
|
const projY = avgY;
|
|
24787
|
-
const
|
|
24788
|
-
const quadrant = [projX >= 0 ?
|
|
25400
|
+
const sign2 = convex ? -1 : 1;
|
|
25401
|
+
const quadrant = [projX >= 0 ? sign2 : -sign2, projY >= 0 ? sign2 : -sign2];
|
|
24789
25402
|
return {
|
|
24790
25403
|
kind: "line-segment",
|
|
24791
25404
|
edgeName: `mesh-edge-${segment.index}`,
|
|
@@ -25003,9 +25616,15 @@ function lowerShapeCompilePlanToManifold(plan, wasm) {
|
|
|
25003
25616
|
case "surfaceFill":
|
|
25004
25617
|
case "surfaceSew":
|
|
25005
25618
|
case "surfaceExtend":
|
|
25006
|
-
case "surfaceThicken":
|
|
25007
25619
|
case "surfaceSolid":
|
|
25008
25620
|
throw new Error(`Exact surfacing operations require the OCCT backend. ${OCCT_BACKEND_REQUIRED_HINT}`);
|
|
25621
|
+
case "surfaceThicken":
|
|
25622
|
+
if (!plan.thicknessField) throw new Error(`Exact surfacing operations require the OCCT backend. ${OCCT_BACKEND_REQUIRED_HINT}`);
|
|
25623
|
+
return lowerRuntimeMeshToManifold(
|
|
25624
|
+
meshFromThickenedSurfaceSheetPlan(plan.base, plan.thickness, plan.thicknessField),
|
|
25625
|
+
wasm,
|
|
25626
|
+
"Surface.thicken() variable thickness"
|
|
25627
|
+
);
|
|
25009
25628
|
case "importedStep":
|
|
25010
25629
|
throw new Error(`importStep("${plan.filePath}") requires the OCCT backend. ${OCCT_BACKEND_REQUIRED_HINT}`);
|
|
25011
25630
|
default:
|
|
@@ -25304,14 +25923,14 @@ function normalizeTrimPolygonForManifold(points, context) {
|
|
|
25304
25923
|
}
|
|
25305
25924
|
}
|
|
25306
25925
|
if (deduped.length < 3) throw new Error(`${context}: trim loop requires at least 3 distinct points`);
|
|
25307
|
-
let
|
|
25926
|
+
let area2 = 0;
|
|
25308
25927
|
for (let i = 0; i < deduped.length; i++) {
|
|
25309
25928
|
const a2 = deduped[i];
|
|
25310
25929
|
const b = deduped[(i + 1) % deduped.length];
|
|
25311
|
-
|
|
25930
|
+
area2 += a2[0] * b[1] - b[0] * a2[1];
|
|
25312
25931
|
}
|
|
25313
|
-
if (Math.abs(
|
|
25314
|
-
if (
|
|
25932
|
+
if (Math.abs(area2) <= 1e-12) throw new Error(`${context}: trim loop area is too small`);
|
|
25933
|
+
if (area2 < 0) deduped.reverse();
|
|
25315
25934
|
return deduped;
|
|
25316
25935
|
}
|
|
25317
25936
|
function sampleNurbsUvTrimLoop(loop) {
|
|
@@ -25453,10 +26072,10 @@ function extractMeshFromShape(oc, shape, linearDeflection = DEFAULT_LINEAR_DEFLE
|
|
|
25453
26072
|
const pt = tri.Node(i).Transformed(trsf);
|
|
25454
26073
|
allPositions.push(pt.X(), pt.Y(), pt.Z());
|
|
25455
26074
|
if (faceHasNormals) {
|
|
25456
|
-
const
|
|
25457
|
-
const transformedNormal =
|
|
25458
|
-
const
|
|
25459
|
-
allNormals.push(transformedNormal.X() *
|
|
26075
|
+
const normal2 = tri.Normal_1(i);
|
|
26076
|
+
const transformedNormal = normal2.Transformed(trsf);
|
|
26077
|
+
const sign2 = reversed ? -1 : 1;
|
|
26078
|
+
allNormals.push(transformedNormal.X() * sign2, transformedNormal.Y() * sign2, transformedNormal.Z() * sign2);
|
|
25460
26079
|
} else {
|
|
25461
26080
|
allNormals.push(0, 0, 0);
|
|
25462
26081
|
}
|
|
@@ -25683,9 +26302,9 @@ const _OCCTShapeBackend = class _OCCTShapeBackend {
|
|
|
25683
26302
|
const transformed = new oc.BRepBuilderAPI_GTransform_2(this.getLiveShape("scale()"), gtrsf, true);
|
|
25684
26303
|
return new _OCCTShapeBackend(transformed.Shape());
|
|
25685
26304
|
}
|
|
25686
|
-
mirror(
|
|
26305
|
+
mirror(normal2) {
|
|
25687
26306
|
const oc = getOCCT();
|
|
25688
|
-
const ax2 = new oc.gp_Ax2_3(new oc.gp_Pnt_3(0, 0, 0), new oc.gp_Dir_4(
|
|
26307
|
+
const ax2 = new oc.gp_Ax2_3(new oc.gp_Pnt_3(0, 0, 0), new oc.gp_Dir_4(normal2[0], normal2[1], normal2[2]));
|
|
25689
26308
|
const trsf = new oc.gp_Trsf_1();
|
|
25690
26309
|
trsf.SetMirror_3(ax2);
|
|
25691
26310
|
const transformed = new oc.BRepBuilderAPI_Transform_2(this.getLiveShape("mirror()"), trsf, true);
|
|
@@ -25700,13 +26319,13 @@ const _OCCTShapeBackend = class _OCCTShapeBackend {
|
|
|
25700
26319
|
outside.Build(new oc.Message_ProgressRange_1());
|
|
25701
26320
|
return [new _OCCTShapeBackend(inside.Shape()), new _OCCTShapeBackend(outside.Shape())];
|
|
25702
26321
|
}
|
|
25703
|
-
splitByPlane(
|
|
26322
|
+
splitByPlane(normal2, originOffset) {
|
|
25704
26323
|
const oc = getOCCT();
|
|
25705
|
-
const dir = new oc.gp_Dir_4(
|
|
25706
|
-
const pln = new oc.gp_Pln_3(new oc.gp_Pnt_3(
|
|
26324
|
+
const dir = new oc.gp_Dir_4(normal2[0], normal2[1], normal2[2]);
|
|
26325
|
+
const pln = new oc.gp_Pln_3(new oc.gp_Pnt_3(normal2[0] * originOffset, normal2[1] * originOffset, normal2[2] * originOffset), dir);
|
|
25707
26326
|
const halfSpace = new oc.BRepPrimAPI_MakeHalfSpace_1(
|
|
25708
26327
|
new oc.BRepBuilderAPI_MakeFace_9(pln, -1e6, 1e6, -1e6, 1e6).Face(),
|
|
25709
|
-
new oc.gp_Pnt_3(
|
|
26328
|
+
new oc.gp_Pnt_3(normal2[0] * (originOffset + 1), normal2[1] * (originOffset + 1), normal2[2] * (originOffset + 1))
|
|
25710
26329
|
);
|
|
25711
26330
|
const inside = new oc.BRepAlgoAPI_Common_3(this.getLiveShape("splitByPlane()"), halfSpace.Solid(), new oc.Message_ProgressRange_1());
|
|
25712
26331
|
inside.Build(new oc.Message_ProgressRange_1());
|
|
@@ -25714,8 +26333,8 @@ const _OCCTShapeBackend = class _OCCTShapeBackend {
|
|
|
25714
26333
|
outside.Build(new oc.Message_ProgressRange_1());
|
|
25715
26334
|
return [new _OCCTShapeBackend(inside.Shape()), new _OCCTShapeBackend(outside.Shape())];
|
|
25716
26335
|
}
|
|
25717
|
-
trimByPlane(
|
|
25718
|
-
const [inside] = this.splitByPlane(
|
|
26336
|
+
trimByPlane(normal2, originOffset) {
|
|
26337
|
+
const [inside] = this.splitByPlane(normal2, originOffset);
|
|
25719
26338
|
return inside;
|
|
25720
26339
|
}
|
|
25721
26340
|
boundingBox() {
|
|
@@ -25837,7 +26456,7 @@ function requireOCCTShape(backend, apiName = "requireOCCTShape()") {
|
|
|
25837
26456
|
}
|
|
25838
26457
|
throw new Error(`${apiName} requires an OCCT-backed shape.`);
|
|
25839
26458
|
}
|
|
25840
|
-
function vertex(mesh, index2) {
|
|
26459
|
+
function vertex$2(mesh, index2) {
|
|
25841
26460
|
const offset = index2 * mesh.numProp;
|
|
25842
26461
|
return [mesh.vertProperties[offset], mesh.vertProperties[offset + 1], mesh.vertProperties[offset + 2]];
|
|
25843
26462
|
}
|
|
@@ -25847,7 +26466,7 @@ function meshBounds(mesh) {
|
|
|
25847
26466
|
const max2 = [-Infinity, -Infinity, -Infinity];
|
|
25848
26467
|
const count = mesh.numVert ?? mesh.vertProperties.length / mesh.numProp;
|
|
25849
26468
|
for (let idx = 0; idx < count; idx += 1) {
|
|
25850
|
-
const point2 = vertex(mesh, idx);
|
|
26469
|
+
const point2 = vertex$2(mesh, idx);
|
|
25851
26470
|
for (let axis = 0; axis < 3; axis += 1) {
|
|
25852
26471
|
min2[axis] = Math.min(min2[axis], point2[axis]);
|
|
25853
26472
|
max2[axis] = Math.max(max2[axis], point2[axis]);
|
|
@@ -25858,24 +26477,24 @@ function meshBounds(mesh) {
|
|
|
25858
26477
|
function meshVolume(mesh) {
|
|
25859
26478
|
let volume = 0;
|
|
25860
26479
|
for (let tri = 0; tri < mesh.numTri; tri += 1) {
|
|
25861
|
-
const a2 = vertex(mesh, mesh.triVerts[tri * 3]);
|
|
25862
|
-
const b = vertex(mesh, mesh.triVerts[tri * 3 + 1]);
|
|
25863
|
-
const c2 = vertex(mesh, mesh.triVerts[tri * 3 + 2]);
|
|
26480
|
+
const a2 = vertex$2(mesh, mesh.triVerts[tri * 3]);
|
|
26481
|
+
const b = vertex$2(mesh, mesh.triVerts[tri * 3 + 1]);
|
|
26482
|
+
const c2 = vertex$2(mesh, mesh.triVerts[tri * 3 + 2]);
|
|
25864
26483
|
volume += (a2[0] * (b[1] * c2[2] - b[2] * c2[1]) + a2[1] * (b[2] * c2[0] - b[0] * c2[2]) + a2[2] * (b[0] * c2[1] - b[1] * c2[0])) / 6;
|
|
25865
26484
|
}
|
|
25866
26485
|
return Math.abs(volume);
|
|
25867
26486
|
}
|
|
25868
26487
|
function meshSurfaceArea(mesh) {
|
|
25869
|
-
let
|
|
26488
|
+
let area2 = 0;
|
|
25870
26489
|
for (let tri = 0; tri < mesh.numTri; tri += 1) {
|
|
25871
|
-
const a2 = vertex(mesh, mesh.triVerts[tri * 3]);
|
|
25872
|
-
const b = vertex(mesh, mesh.triVerts[tri * 3 + 1]);
|
|
25873
|
-
const c2 = vertex(mesh, mesh.triVerts[tri * 3 + 2]);
|
|
26490
|
+
const a2 = vertex$2(mesh, mesh.triVerts[tri * 3]);
|
|
26491
|
+
const b = vertex$2(mesh, mesh.triVerts[tri * 3 + 1]);
|
|
26492
|
+
const c2 = vertex$2(mesh, mesh.triVerts[tri * 3 + 2]);
|
|
25874
26493
|
const ab = [b[0] - a2[0], b[1] - a2[1], b[2] - a2[2]];
|
|
25875
26494
|
const ac = [c2[0] - a2[0], c2[1] - a2[1], c2[2] - a2[2]];
|
|
25876
|
-
|
|
26495
|
+
area2 += Math.hypot(ab[1] * ac[2] - ab[2] * ac[1], ab[2] * ac[0] - ab[0] * ac[2], ab[0] * ac[1] - ab[1] * ac[0]) * 0.5;
|
|
25877
26496
|
}
|
|
25878
|
-
return
|
|
26497
|
+
return area2;
|
|
25879
26498
|
}
|
|
25880
26499
|
function meshBodyCount(mesh) {
|
|
25881
26500
|
if (mesh.numTri === 0) return 0;
|
|
@@ -30990,11 +31609,11 @@ function requireClipper() {
|
|
|
30990
31609
|
};
|
|
30991
31610
|
ClipperLib2.JS.AreaOfPolygons = function(poly, scale2) {
|
|
30992
31611
|
if (!scale2) scale2 = 1;
|
|
30993
|
-
var
|
|
31612
|
+
var area2 = 0;
|
|
30994
31613
|
for (var i = 0; i < poly.length; i++) {
|
|
30995
|
-
|
|
31614
|
+
area2 += ClipperLib2.Clipper.Area(poly[i]);
|
|
30996
31615
|
}
|
|
30997
|
-
return
|
|
31616
|
+
return area2 / (scale2 * scale2);
|
|
30998
31617
|
};
|
|
30999
31618
|
ClipperLib2.JS.BoundsOfPath = function(path, scale2) {
|
|
31000
31619
|
return ClipperLib2.JS.BoundsOfPaths([path], scale2);
|
|
@@ -33082,8 +33701,8 @@ function cleanLoop$2(points) {
|
|
|
33082
33701
|
return out.length >= 3 && Math.abs(signedArea2$1(out)) > 1e-12 ? out : [];
|
|
33083
33702
|
}
|
|
33084
33703
|
function orient(loop, ccw) {
|
|
33085
|
-
const
|
|
33086
|
-
return ccw &&
|
|
33704
|
+
const area2 = signedArea2$1(loop);
|
|
33705
|
+
return ccw && area2 < 0 || !ccw && area2 > 0 ? [...loop].reverse() : loop.map(([x2, y2]) => [x2, y2]);
|
|
33087
33706
|
}
|
|
33088
33707
|
function closeRing$2(points) {
|
|
33089
33708
|
const ring = points.map(([x2, y2]) => [snap(x2), snap(y2)]);
|
|
@@ -33514,8 +34133,8 @@ function runtimeMeshFromReconstructionData(mesh) {
|
|
|
33514
34133
|
mergeToVert: mesh.mergeToVert
|
|
33515
34134
|
};
|
|
33516
34135
|
}
|
|
33517
|
-
function mirrorMatrix$2(
|
|
33518
|
-
const n = normalize3$2(
|
|
34136
|
+
function mirrorMatrix$2(normal2) {
|
|
34137
|
+
const n = normalize3$2(normal2, "SDF mirror() normal");
|
|
33519
34138
|
return [
|
|
33520
34139
|
1 - 2 * n[0] * n[0],
|
|
33521
34140
|
-2 * n[1] * n[0],
|
|
@@ -33623,8 +34242,8 @@ const _SdfShapeBackend = class _SdfShapeBackend {
|
|
|
33623
34242
|
this.mesh ? transformRuntimeMesh(this.mesh, matrix) : null
|
|
33624
34243
|
);
|
|
33625
34244
|
}
|
|
33626
|
-
mirror(
|
|
33627
|
-
return this.transform(mirrorMatrix$2(
|
|
34245
|
+
mirror(normal2) {
|
|
34246
|
+
return this.transform(mirrorMatrix$2(normal2));
|
|
33628
34247
|
}
|
|
33629
34248
|
split(other) {
|
|
33630
34249
|
const cutter = otherAsSdf(other, this.field.edgeLength);
|
|
@@ -33646,12 +34265,12 @@ const _SdfShapeBackend = class _SdfShapeBackend {
|
|
|
33646
34265
|
};
|
|
33647
34266
|
return [new _SdfShapeBackend(inside), new _SdfShapeBackend(outside)];
|
|
33648
34267
|
}
|
|
33649
|
-
splitByPlane(
|
|
33650
|
-
return [this.trimByPlane(
|
|
34268
|
+
splitByPlane(normal2, originOffset) {
|
|
34269
|
+
return [this.trimByPlane(normal2, originOffset), this.trimByPlane([-normal2[0], -normal2[1], -normal2[2]], -originOffset)];
|
|
33651
34270
|
}
|
|
33652
|
-
trimByPlane(
|
|
33653
|
-
const n = normalize3$2(
|
|
33654
|
-
const offset = originOffset / Math.hypot(
|
|
34271
|
+
trimByPlane(normal2, originOffset) {
|
|
34272
|
+
const n = normalize3$2(normal2, "SDF trimByPlane() normal");
|
|
34273
|
+
const offset = originOffset / Math.hypot(normal2[0], normal2[1], normal2[2]);
|
|
33655
34274
|
const field2 = {
|
|
33656
34275
|
edgeLength: this.field.edgeLength,
|
|
33657
34276
|
bounds: this.field.bounds,
|
|
@@ -33791,6 +34410,92 @@ let SdfPolygonProfileBackend = _SdfPolygonProfileBackend;
|
|
|
33791
34410
|
function wrapSdfPolygonProfileBackend(polygons) {
|
|
33792
34411
|
return new SdfPolygonProfileBackend(cloneLoops$1(polygons));
|
|
33793
34412
|
}
|
|
34413
|
+
const EPS$1 = 1e-9;
|
|
34414
|
+
function vertex$1(mesh, index2, distance) {
|
|
34415
|
+
const start = index2 * mesh.numProp;
|
|
34416
|
+
const props = Array.from(mesh.vertProperties.slice(start, start + mesh.numProp));
|
|
34417
|
+
return {
|
|
34418
|
+
props,
|
|
34419
|
+
distance: distance(props[0], props[1], props[2])
|
|
34420
|
+
};
|
|
34421
|
+
}
|
|
34422
|
+
function interpolate(a2, b) {
|
|
34423
|
+
const t = a2.distance / (a2.distance - b.distance);
|
|
34424
|
+
const props = a2.props.map((value, index2) => value + (b.props[index2] - value) * t);
|
|
34425
|
+
return { props, distance: 0 };
|
|
34426
|
+
}
|
|
34427
|
+
function clipPolygon(vertices) {
|
|
34428
|
+
let output = vertices;
|
|
34429
|
+
const input = output;
|
|
34430
|
+
output = [];
|
|
34431
|
+
for (let index2 = 0; index2 < input.length; index2 += 1) {
|
|
34432
|
+
const current = input[index2];
|
|
34433
|
+
const previous = input[(index2 + input.length - 1) % input.length];
|
|
34434
|
+
const currentInside = current.distance >= -EPS$1;
|
|
34435
|
+
const previousInside = previous.distance >= -EPS$1;
|
|
34436
|
+
if (currentInside && previousInside) {
|
|
34437
|
+
output.push(current);
|
|
34438
|
+
} else if (currentInside && !previousInside) {
|
|
34439
|
+
output.push(interpolate(previous, current), current);
|
|
34440
|
+
} else if (!currentInside && previousInside) {
|
|
34441
|
+
output.push(interpolate(previous, current));
|
|
34442
|
+
}
|
|
34443
|
+
}
|
|
34444
|
+
return output;
|
|
34445
|
+
}
|
|
34446
|
+
function normalizeInterpolatedNormals(props, numProp) {
|
|
34447
|
+
if (numProp < 6) return props;
|
|
34448
|
+
const length4 = Math.hypot(props[3], props[4], props[5]);
|
|
34449
|
+
if (length4 <= EPS$1) return props;
|
|
34450
|
+
const next = [...props];
|
|
34451
|
+
next[3] /= length4;
|
|
34452
|
+
next[4] /= length4;
|
|
34453
|
+
next[5] /= length4;
|
|
34454
|
+
return next;
|
|
34455
|
+
}
|
|
34456
|
+
function keyFor(props) {
|
|
34457
|
+
return props.slice(0, 3).map((value) => value.toFixed(8)).join(",");
|
|
34458
|
+
}
|
|
34459
|
+
function clipSurfaceMeshBySignedDistance(mesh, distance) {
|
|
34460
|
+
const positions = [];
|
|
34461
|
+
const indices = [];
|
|
34462
|
+
const vertexByKey = /* @__PURE__ */ new Map();
|
|
34463
|
+
const addVertex = (clipVertex) => {
|
|
34464
|
+
const props = normalizeInterpolatedNormals(clipVertex.props, mesh.numProp);
|
|
34465
|
+
const key2 = keyFor(props);
|
|
34466
|
+
const existing = vertexByKey.get(key2);
|
|
34467
|
+
if (existing !== void 0) return existing;
|
|
34468
|
+
const index2 = positions.length / mesh.numProp;
|
|
34469
|
+
vertexByKey.set(key2, index2);
|
|
34470
|
+
positions.push(...props);
|
|
34471
|
+
return index2;
|
|
34472
|
+
};
|
|
34473
|
+
for (let tri = 0; tri < mesh.numTri; tri += 1) {
|
|
34474
|
+
const clipped = clipPolygon([
|
|
34475
|
+
vertex$1(mesh, mesh.triVerts[tri * 3], distance),
|
|
34476
|
+
vertex$1(mesh, mesh.triVerts[tri * 3 + 1], distance),
|
|
34477
|
+
vertex$1(mesh, mesh.triVerts[tri * 3 + 2], distance)
|
|
34478
|
+
]);
|
|
34479
|
+
if (clipped.length < 3) continue;
|
|
34480
|
+
const first = addVertex(clipped[0]);
|
|
34481
|
+
for (let index2 = 1; index2 < clipped.length - 1; index2 += 1) {
|
|
34482
|
+
const b = addVertex(clipped[index2]);
|
|
34483
|
+
const c2 = addVertex(clipped[index2 + 1]);
|
|
34484
|
+
if (first !== b && b !== c2 && c2 !== first) indices.push(first, b, c2);
|
|
34485
|
+
}
|
|
34486
|
+
}
|
|
34487
|
+
return {
|
|
34488
|
+
numProp: mesh.numProp,
|
|
34489
|
+
numVert: positions.length / mesh.numProp,
|
|
34490
|
+
numTri: indices.length / 3,
|
|
34491
|
+
vertProperties: new Float32Array(positions),
|
|
34492
|
+
triVerts: new Uint32Array(indices)
|
|
34493
|
+
};
|
|
34494
|
+
}
|
|
34495
|
+
function clipSurfaceMeshByPlane(mesh, normalInput, originOffset) {
|
|
34496
|
+
const normal2 = normalize3$2(normalInput, "SDF surface mesh clip normal");
|
|
34497
|
+
return clipSurfaceMeshBySignedDistance(mesh, (x2, y2, z2) => x2 * normal2[0] + y2 * normal2[1] + z2 * normal2[2] - originOffset);
|
|
34498
|
+
}
|
|
33794
34499
|
const CUBE_CORNER_OFFSETS = [
|
|
33795
34500
|
[0, 0, 0],
|
|
33796
34501
|
[1, 0, 0],
|
|
@@ -34417,8 +35122,8 @@ function transformFaceSurface(surface, tx) {
|
|
|
34417
35122
|
const scale2 = uniformDistanceScale(tx.toArray());
|
|
34418
35123
|
switch (surface.kind) {
|
|
34419
35124
|
case "plane": {
|
|
34420
|
-
const
|
|
34421
|
-
return
|
|
35125
|
+
const normal2 = transformSurfaceAxis(tx, surface.normal);
|
|
35126
|
+
return normal2 ? { kind: "plane", normal: normal2 } : void 0;
|
|
34422
35127
|
}
|
|
34423
35128
|
case "cylinder": {
|
|
34424
35129
|
if (scale2 === null) return void 0;
|
|
@@ -34548,13 +35253,13 @@ function cloneRegion$1(region) {
|
|
|
34548
35253
|
};
|
|
34549
35254
|
}
|
|
34550
35255
|
function signedArea$1(points) {
|
|
34551
|
-
let
|
|
35256
|
+
let area2 = 0;
|
|
34552
35257
|
for (let i = 0; i < points.length; i++) {
|
|
34553
35258
|
const [x0, y0] = points[i];
|
|
34554
35259
|
const [x1, y1] = points[(i + 1) % points.length];
|
|
34555
|
-
|
|
35260
|
+
area2 += x0 * y1 - x1 * y0;
|
|
34556
35261
|
}
|
|
34557
|
-
return
|
|
35262
|
+
return area2 / 2;
|
|
34558
35263
|
}
|
|
34559
35264
|
function cleanLoop(points) {
|
|
34560
35265
|
const cleaned = [];
|
|
@@ -34572,11 +35277,11 @@ function cleanLoop(points) {
|
|
|
34572
35277
|
return cleaned.length >= 3 && Math.abs(signedArea$1(cleaned)) > 1e-10 ? cleaned : [];
|
|
34573
35278
|
}
|
|
34574
35279
|
function orientLoop(points, ccw) {
|
|
34575
|
-
const
|
|
34576
|
-
if (ccw &&
|
|
35280
|
+
const area2 = signedArea$1(points);
|
|
35281
|
+
if (ccw && area2 < 0 || !ccw && area2 > 0) return [...points].reverse();
|
|
34577
35282
|
return points.map(([x2, y2]) => [x2, y2]);
|
|
34578
35283
|
}
|
|
34579
|
-
function pointInLoop(point2, loop) {
|
|
35284
|
+
function pointInLoop$1(point2, loop) {
|
|
34580
35285
|
let inside = false;
|
|
34581
35286
|
for (let i = 0, j = loop.length - 1; i < loop.length; j = i++) {
|
|
34582
35287
|
const [xi, yi] = loop[i];
|
|
@@ -34602,7 +35307,7 @@ function loopsToRegions(polygons) {
|
|
|
34602
35307
|
const loopRegion = /* @__PURE__ */ new Map();
|
|
34603
35308
|
for (const loop of loops) {
|
|
34604
35309
|
const containers = loops.filter(
|
|
34605
|
-
(candidate) => candidate !== loop && Math.abs(signedArea$1(candidate)) > Math.abs(signedArea$1(loop)) && pointInLoop(loop[0], candidate)
|
|
35310
|
+
(candidate) => candidate !== loop && Math.abs(signedArea$1(candidate)) > Math.abs(signedArea$1(loop)) && pointInLoop$1(loop[0], candidate)
|
|
34606
35311
|
);
|
|
34607
35312
|
if (containers.length % 2 === 0) {
|
|
34608
35313
|
const region2 = { outer: orientLoop(loop, true), holes: [] };
|
|
@@ -34611,7 +35316,7 @@ function loopsToRegions(polygons) {
|
|
|
34611
35316
|
continue;
|
|
34612
35317
|
}
|
|
34613
35318
|
const parent = containers.find(
|
|
34614
|
-
(candidate) => containers.filter((other) => other !== candidate && pointInLoop(candidate[0], other)).length % 2 === 0
|
|
35319
|
+
(candidate) => containers.filter((other) => other !== candidate && pointInLoop$1(candidate[0], other)).length % 2 === 0
|
|
34615
35320
|
);
|
|
34616
35321
|
const region = parent ? loopRegion.get(parent) : void 0;
|
|
34617
35322
|
if (region) region.holes.push(orientLoop(loop, false));
|
|
@@ -35115,16 +35820,16 @@ function boundsCorners(bounds) {
|
|
|
35115
35820
|
[maxX, maxY, maxZ]
|
|
35116
35821
|
];
|
|
35117
35822
|
}
|
|
35118
|
-
function perpendicularAxes(
|
|
35119
|
-
const seed = Math.abs(
|
|
35120
|
-
const uAxis = normalizeVec3(cross$2(seed,
|
|
35121
|
-
const vAxis = normalizeVec3(cross$2(
|
|
35823
|
+
function perpendicularAxes(normal2) {
|
|
35824
|
+
const seed = Math.abs(normal2[2]) < 0.9 ? [0, 0, 1] : [0, 1, 0];
|
|
35825
|
+
const uAxis = normalizeVec3(cross$2(seed, normal2));
|
|
35826
|
+
const vAxis = normalizeVec3(cross$2(normal2, uAxis));
|
|
35122
35827
|
return { uAxis, vAxis };
|
|
35123
35828
|
}
|
|
35124
|
-
function createBoundedHalfSpace(bounds,
|
|
35125
|
-
const normalLength = Math.hypot(
|
|
35829
|
+
function createBoundedHalfSpace(bounds, normal2, originOffset) {
|
|
35830
|
+
const normalLength = Math.hypot(normal2[0], normal2[1], normal2[2]);
|
|
35126
35831
|
if (normalLength <= 1e-12) throw new Error("Truck trimByPlane() normal vector must not be zero.");
|
|
35127
|
-
const n = [
|
|
35832
|
+
const n = [normal2[0] / normalLength, normal2[1] / normalLength, normal2[2] / normalLength];
|
|
35128
35833
|
const signedOffset = originOffset / normalLength;
|
|
35129
35834
|
const corners = boundsCorners(bounds);
|
|
35130
35835
|
const planeOrigin = scale(n, signedOffset);
|
|
@@ -35227,13 +35932,13 @@ function explicitEdgeDisplayName(payload, explicitEdge, explicitEdgeIndex, start
|
|
|
35227
35932
|
return { name: fallback, faceName: fallback };
|
|
35228
35933
|
}
|
|
35229
35934
|
function signedArea2d(points) {
|
|
35230
|
-
let
|
|
35935
|
+
let area2 = 0;
|
|
35231
35936
|
for (let i = 0; i < points.length; i++) {
|
|
35232
35937
|
const [x0, y0] = points[i];
|
|
35233
35938
|
const [x1, y1] = points[(i + 1) % points.length];
|
|
35234
|
-
|
|
35939
|
+
area2 += x0 * y1 - x1 * y0;
|
|
35235
35940
|
}
|
|
35236
|
-
return
|
|
35941
|
+
return area2 / 2;
|
|
35237
35942
|
}
|
|
35238
35943
|
function cleanLoop2d(points) {
|
|
35239
35944
|
const cleaned = [];
|
|
@@ -35474,8 +36179,8 @@ const _TruckShapeBackend = class _TruckShapeBackend {
|
|
|
35474
36179
|
const [sx, sy, sz] = typeof v === "number" ? [v, v, v] : v;
|
|
35475
36180
|
return this.transform(Transform.scale([sx, sy, sz]).toArray());
|
|
35476
36181
|
}
|
|
35477
|
-
mirror(
|
|
35478
|
-
const [nx0, ny0, nz0] =
|
|
36182
|
+
mirror(normal2) {
|
|
36183
|
+
const [nx0, ny0, nz0] = normal2;
|
|
35479
36184
|
const len2 = Math.hypot(nx0, ny0, nz0);
|
|
35480
36185
|
if (len2 < 1e-12) return this.clone();
|
|
35481
36186
|
const nx = nx0 / len2;
|
|
@@ -35512,20 +36217,20 @@ const _TruckShapeBackend = class _TruckShapeBackend {
|
|
|
35512
36217
|
new _TruckShapeBackend(wasm.geometry_boolean(handles, "difference"))
|
|
35513
36218
|
];
|
|
35514
36219
|
}
|
|
35515
|
-
splitByPlane(
|
|
35516
|
-
return [this.trimByPlane(
|
|
36220
|
+
splitByPlane(normal2, originOffset) {
|
|
36221
|
+
return [this.trimByPlane(normal2, originOffset), this.trimByPlane([-normal2[0], -normal2[1], -normal2[2]], -originOffset)];
|
|
35517
36222
|
}
|
|
35518
|
-
trimByPlane(
|
|
36223
|
+
trimByPlane(normal2, originOffset) {
|
|
35519
36224
|
const wasm = getTruckGeometryWasm();
|
|
35520
36225
|
const bounds = this.boundingBox();
|
|
35521
|
-
const normalLength = Math.hypot(
|
|
36226
|
+
const normalLength = Math.hypot(normal2[0], normal2[1], normal2[2]);
|
|
35522
36227
|
if (normalLength <= 1e-12) throw new Error("Truck trimByPlane() normal vector must not be zero.");
|
|
35523
|
-
const n = [
|
|
36228
|
+
const n = [normal2[0] / normalLength, normal2[1] / normalLength, normal2[2] / normalLength];
|
|
35524
36229
|
const signedOffset = originOffset / normalLength;
|
|
35525
36230
|
const distances = boundsCorners(bounds).map((corner) => dot$2(corner, n) - signedOffset);
|
|
35526
36231
|
if (distances.every((distance) => distance >= -1e-8)) return this.clone();
|
|
35527
36232
|
if (distances.every((distance) => distance <= 1e-8)) return new _TruckShapeBackend(wasm.geometry_create_empty());
|
|
35528
|
-
const halfSpace = createBoundedHalfSpace(bounds,
|
|
36233
|
+
const halfSpace = createBoundedHalfSpace(bounds, normal2, originOffset);
|
|
35529
36234
|
try {
|
|
35530
36235
|
return new _TruckShapeBackend(
|
|
35531
36236
|
wasm.geometry_boolean(
|
|
@@ -35738,8 +36443,8 @@ function applyProfileTransformsToRegion(region, transforms) {
|
|
|
35738
36443
|
};
|
|
35739
36444
|
}
|
|
35740
36445
|
function orientRingForClipper(points, ccw) {
|
|
35741
|
-
const
|
|
35742
|
-
if (ccw &&
|
|
36446
|
+
const area2 = signedArea(points);
|
|
36447
|
+
if (ccw && area2 < 0 || !ccw && area2 > 0) {
|
|
35743
36448
|
return [...points].reverse();
|
|
35744
36449
|
}
|
|
35745
36450
|
return points;
|
|
@@ -35881,12 +36586,12 @@ function openRing(ring) {
|
|
|
35881
36586
|
return deduped;
|
|
35882
36587
|
}
|
|
35883
36588
|
function signedArea(points) {
|
|
35884
|
-
let
|
|
36589
|
+
let area2 = 0;
|
|
35885
36590
|
for (let i = 0; i < points.length; i++) {
|
|
35886
36591
|
const next = (i + 1) % points.length;
|
|
35887
|
-
|
|
36592
|
+
area2 += points[i][0] * points[next][1] - points[next][0] * points[i][1];
|
|
35888
36593
|
}
|
|
35889
|
-
return
|
|
36594
|
+
return area2 / 2;
|
|
35890
36595
|
}
|
|
35891
36596
|
function regionBounds(region) {
|
|
35892
36597
|
var _a3, _b3;
|
|
@@ -36086,7 +36791,7 @@ function dot3$2(a2, b) {
|
|
|
36086
36791
|
function subtract3(a2, b) {
|
|
36087
36792
|
return [a2[0] - b[0], a2[1] - b[1], a2[2] - b[2]];
|
|
36088
36793
|
}
|
|
36089
|
-
function localToWorldMatrix(origin, uAxis, vAxis,
|
|
36794
|
+
function localToWorldMatrix(origin, uAxis, vAxis, normal2) {
|
|
36090
36795
|
return [
|
|
36091
36796
|
uAxis[0],
|
|
36092
36797
|
uAxis[1],
|
|
@@ -36096,9 +36801,9 @@ function localToWorldMatrix(origin, uAxis, vAxis, normal) {
|
|
|
36096
36801
|
vAxis[1],
|
|
36097
36802
|
vAxis[2],
|
|
36098
36803
|
0,
|
|
36099
|
-
|
|
36100
|
-
|
|
36101
|
-
|
|
36804
|
+
normal2[0],
|
|
36805
|
+
normal2[1],
|
|
36806
|
+
normal2[2],
|
|
36102
36807
|
0,
|
|
36103
36808
|
origin[0],
|
|
36104
36809
|
origin[1],
|
|
@@ -36227,15 +36932,15 @@ function rotateRegion(region, degrees, pivot) {
|
|
|
36227
36932
|
holes: region.holes.map((hole) => hole.map((point2) => rotatePointAround(point2, degrees, pivot)))
|
|
36228
36933
|
};
|
|
36229
36934
|
}
|
|
36230
|
-
function mirrorPointAcrossLineNormal(point2,
|
|
36231
|
-
const normalLengthSq =
|
|
36935
|
+
function mirrorPointAcrossLineNormal(point2, normal2) {
|
|
36936
|
+
const normalLengthSq = normal2[0] * normal2[0] + normal2[1] * normal2[1];
|
|
36232
36937
|
if (normalLengthSq <= 1e-18) return null;
|
|
36233
|
-
const signedDistanceScale = 2 * (point2[0] *
|
|
36234
|
-
return [point2[0] - signedDistanceScale *
|
|
36938
|
+
const signedDistanceScale = 2 * (point2[0] * normal2[0] + point2[1] * normal2[1]) / normalLengthSq;
|
|
36939
|
+
return [point2[0] - signedDistanceScale * normal2[0], point2[1] - signedDistanceScale * normal2[1]];
|
|
36235
36940
|
}
|
|
36236
|
-
function mirrorRegionAcrossVerticalPlane(region,
|
|
36941
|
+
function mirrorRegionAcrossVerticalPlane(region, normal2) {
|
|
36237
36942
|
const mirrorLoop = (loop) => {
|
|
36238
|
-
const mirrored = loop.map((point2) => mirrorPointAcrossLineNormal(point2,
|
|
36943
|
+
const mirrored = loop.map((point2) => mirrorPointAcrossLineNormal(point2, normal2));
|
|
36239
36944
|
if (mirrored.some((point2) => point2 == null)) return null;
|
|
36240
36945
|
return mirrored.reverse();
|
|
36241
36946
|
};
|
|
@@ -36309,9 +37014,9 @@ function applyShapeTransformToVerticalPrism(prism, step) {
|
|
|
36309
37014
|
case "mirror": {
|
|
36310
37015
|
const xyNormalLength = Math.hypot(step.normalX, step.normalY);
|
|
36311
37016
|
if (xyNormalLength > 1e-9 && Math.abs(step.normalZ) <= 1e-9) {
|
|
36312
|
-
const
|
|
36313
|
-
const regions = prism.regions.map((region) => mirrorRegionAcrossVerticalPlane(region,
|
|
36314
|
-
const topRegions = (_d2 = prism.topRegions) == null ? void 0 : _d2.map((region) => mirrorRegionAcrossVerticalPlane(region,
|
|
37017
|
+
const normal2 = [step.normalX, step.normalY];
|
|
37018
|
+
const regions = prism.regions.map((region) => mirrorRegionAcrossVerticalPlane(region, normal2));
|
|
37019
|
+
const topRegions = (_d2 = prism.topRegions) == null ? void 0 : _d2.map((region) => mirrorRegionAcrossVerticalPlane(region, normal2));
|
|
36315
37020
|
if (regions.some((region) => region == null) || (topRegions == null ? void 0 : topRegions.some((region) => region == null))) return null;
|
|
36316
37021
|
return {
|
|
36317
37022
|
regions,
|
|
@@ -37984,7 +38689,7 @@ function lowerVariableSweepPlan(plan) {
|
|
|
37984
38689
|
)
|
|
37985
38690
|
);
|
|
37986
38691
|
}
|
|
37987
|
-
function resamplePolyline(points, count) {
|
|
38692
|
+
function resamplePolyline$1(points, count) {
|
|
37988
38693
|
if (points.length === 0) return [];
|
|
37989
38694
|
if (points.length === 1 || count <= 1) return [points[0]];
|
|
37990
38695
|
const cumulative = [0];
|
|
@@ -38008,35 +38713,35 @@ function resamplePolyline(points, count) {
|
|
|
38008
38713
|
}
|
|
38009
38714
|
return out;
|
|
38010
38715
|
}
|
|
38011
|
-
function sampleSurfaceCurve(path, resolution) {
|
|
38716
|
+
function sampleSurfaceCurve$1(path, resolution) {
|
|
38012
38717
|
const count = Math.max(2, resolution + 1);
|
|
38013
|
-
return resamplePolyline(sampleTruckSweepPath(path, count, false), count);
|
|
38718
|
+
return resamplePolyline$1(sampleTruckSweepPath(path, count, false), count);
|
|
38014
38719
|
}
|
|
38015
|
-
function reversePoints(points) {
|
|
38720
|
+
function reversePoints$1(points) {
|
|
38016
38721
|
return [...points].reverse();
|
|
38017
38722
|
}
|
|
38018
|
-
function surfaceGridForRuledPlan(plan) {
|
|
38723
|
+
function surfaceGridForRuledPlan$1(plan) {
|
|
38019
38724
|
const count = Math.max(2, plan.resolution + 1);
|
|
38020
38725
|
return [
|
|
38021
|
-
resamplePolyline(sampleSurfaceCurve(plan.curveA, plan.resolution), count),
|
|
38022
|
-
resamplePolyline(sampleSurfaceCurve(plan.curveB, plan.resolution), count)
|
|
38726
|
+
resamplePolyline$1(sampleSurfaceCurve$1(plan.curveA, plan.resolution), count),
|
|
38727
|
+
resamplePolyline$1(sampleSurfaceCurve$1(plan.curveB, plan.resolution), count)
|
|
38023
38728
|
];
|
|
38024
38729
|
}
|
|
38025
|
-
function namedBoundaryCurve(plan, name) {
|
|
38730
|
+
function namedBoundaryCurve$1(plan, name) {
|
|
38026
38731
|
var _a3;
|
|
38027
38732
|
return ((_a3 = plan.boundaries.find((boundary) => boundary.name === name)) == null ? void 0 : _a3.curve) ?? null;
|
|
38028
38733
|
}
|
|
38029
|
-
function surfaceGridForFillPlan(plan) {
|
|
38030
|
-
const bottomCurve = namedBoundaryCurve(plan, "v0");
|
|
38031
|
-
const rightCurve = namedBoundaryCurve(plan, "u1");
|
|
38032
|
-
const topCurve = namedBoundaryCurve(plan, "v1");
|
|
38033
|
-
const leftCurve = namedBoundaryCurve(plan, "u0");
|
|
38734
|
+
function surfaceGridForFillPlan$1(plan) {
|
|
38735
|
+
const bottomCurve = namedBoundaryCurve$1(plan, "v0");
|
|
38736
|
+
const rightCurve = namedBoundaryCurve$1(plan, "u1");
|
|
38737
|
+
const topCurve = namedBoundaryCurve$1(plan, "v1");
|
|
38738
|
+
const leftCurve = namedBoundaryCurve$1(plan, "u0");
|
|
38034
38739
|
if (!bottomCurve || !rightCurve || !topCurve || !leftCurve || plan.boundaries.some((boundary) => boundary.support)) return null;
|
|
38035
38740
|
const count = Math.max(2, plan.resolution + 1);
|
|
38036
|
-
const bottom = sampleSurfaceCurve(bottomCurve, plan.resolution);
|
|
38037
|
-
const right = sampleSurfaceCurve(rightCurve, plan.resolution);
|
|
38038
|
-
const top = reversePoints(sampleSurfaceCurve(topCurve, plan.resolution));
|
|
38039
|
-
const left = reversePoints(sampleSurfaceCurve(leftCurve, plan.resolution));
|
|
38741
|
+
const bottom = sampleSurfaceCurve$1(bottomCurve, plan.resolution);
|
|
38742
|
+
const right = sampleSurfaceCurve$1(rightCurve, plan.resolution);
|
|
38743
|
+
const top = reversePoints$1(sampleSurfaceCurve$1(topCurve, plan.resolution));
|
|
38744
|
+
const left = reversePoints$1(sampleSurfaceCurve$1(leftCurve, plan.resolution));
|
|
38040
38745
|
const p00 = bottom[0];
|
|
38041
38746
|
const p10 = bottom[bottom.length - 1];
|
|
38042
38747
|
const p01 = top[0];
|
|
@@ -38051,62 +38756,62 @@ function surfaceGridForFillPlan(plan) {
|
|
|
38051
38756
|
const topPoint = top[uIdx];
|
|
38052
38757
|
const leftPoint = left[vIdx];
|
|
38053
38758
|
const rightPoint = right[vIdx];
|
|
38054
|
-
const
|
|
38759
|
+
const bilinear2 = [
|
|
38055
38760
|
(1 - u2) * (1 - v) * p00[0] + u2 * (1 - v) * p10[0] + (1 - u2) * v * p01[0] + u2 * v * p11[0],
|
|
38056
38761
|
(1 - u2) * (1 - v) * p00[1] + u2 * (1 - v) * p10[1] + (1 - u2) * v * p01[1] + u2 * v * p11[1],
|
|
38057
38762
|
(1 - u2) * (1 - v) * p00[2] + u2 * (1 - v) * p10[2] + (1 - u2) * v * p01[2] + u2 * v * p11[2]
|
|
38058
38763
|
];
|
|
38059
38764
|
row.push([
|
|
38060
|
-
(1 - v) * bottomPoint[0] + v * topPoint[0] + (1 - u2) * leftPoint[0] + u2 * rightPoint[0] -
|
|
38061
|
-
(1 - v) * bottomPoint[1] + v * topPoint[1] + (1 - u2) * leftPoint[1] + u2 * rightPoint[1] -
|
|
38062
|
-
(1 - v) * bottomPoint[2] + v * topPoint[2] + (1 - u2) * leftPoint[2] + u2 * rightPoint[2] -
|
|
38765
|
+
(1 - v) * bottomPoint[0] + v * topPoint[0] + (1 - u2) * leftPoint[0] + u2 * rightPoint[0] - bilinear2[0],
|
|
38766
|
+
(1 - v) * bottomPoint[1] + v * topPoint[1] + (1 - u2) * leftPoint[1] + u2 * rightPoint[1] - bilinear2[1],
|
|
38767
|
+
(1 - v) * bottomPoint[2] + v * topPoint[2] + (1 - u2) * leftPoint[2] + u2 * rightPoint[2] - bilinear2[2]
|
|
38063
38768
|
]);
|
|
38064
38769
|
}
|
|
38065
38770
|
grid.push(row);
|
|
38066
38771
|
}
|
|
38067
38772
|
return grid;
|
|
38068
38773
|
}
|
|
38069
|
-
function add3(a2, b) {
|
|
38774
|
+
function add3$1(a2, b) {
|
|
38070
38775
|
return [a2[0] + b[0], a2[1] + b[1], a2[2] + b[2]];
|
|
38071
38776
|
}
|
|
38072
|
-
function scale3(v, s) {
|
|
38777
|
+
function scale3$1(v, s) {
|
|
38073
38778
|
return [v[0] * s, v[1] * s, v[2] * s];
|
|
38074
38779
|
}
|
|
38075
|
-
function analyticYForFrame(axis, xAxis) {
|
|
38780
|
+
function analyticYForFrame$1(axis, xAxis) {
|
|
38076
38781
|
return normalizedVector3(cross3$3(axis, xAxis), "analytic surface yAxis");
|
|
38077
38782
|
}
|
|
38078
|
-
function radialPoint(xAxis, yAxis, u2, radius) {
|
|
38079
|
-
return add3(scale3(xAxis, Math.cos(u2) * radius), scale3(yAxis, Math.sin(u2) * radius));
|
|
38783
|
+
function radialPoint$1(xAxis, yAxis, u2, radius) {
|
|
38784
|
+
return add3$1(scale3$1(xAxis, Math.cos(u2) * radius), scale3$1(yAxis, Math.sin(u2) * radius));
|
|
38080
38785
|
}
|
|
38081
|
-
function analyticSurfacePoint(plan, u2, v) {
|
|
38786
|
+
function analyticSurfacePoint$1(plan, u2, v) {
|
|
38082
38787
|
switch (plan.kind) {
|
|
38083
38788
|
case "plane":
|
|
38084
|
-
return add3(add3(plan.origin, scale3(plan.uAxis, u2)), scale3(plan.vAxis, v));
|
|
38789
|
+
return add3$1(add3$1(plan.origin, scale3$1(plan.uAxis, u2)), scale3$1(plan.vAxis, v));
|
|
38085
38790
|
case "cylinder": {
|
|
38086
|
-
const yAxis = analyticYForFrame(plan.axis, plan.xAxis);
|
|
38087
|
-
return add3(add3(plan.origin, scale3(plan.axis, v)), radialPoint(plan.xAxis, yAxis, u2, plan.radius));
|
|
38791
|
+
const yAxis = analyticYForFrame$1(plan.axis, plan.xAxis);
|
|
38792
|
+
return add3$1(add3$1(plan.origin, scale3$1(plan.axis, v)), radialPoint$1(plan.xAxis, yAxis, u2, plan.radius));
|
|
38088
38793
|
}
|
|
38089
38794
|
case "cone": {
|
|
38090
|
-
const yAxis = analyticYForFrame(plan.axis, plan.xAxis);
|
|
38795
|
+
const yAxis = analyticYForFrame$1(plan.axis, plan.xAxis);
|
|
38091
38796
|
const t = (v - plan.vMin) / (plan.vMax - plan.vMin);
|
|
38092
38797
|
const radius = plan.radiusBottom + (plan.radiusTop - plan.radiusBottom) * t;
|
|
38093
|
-
return add3(add3(plan.origin, scale3(plan.axis, v)), radialPoint(plan.xAxis, yAxis, u2, radius));
|
|
38798
|
+
return add3$1(add3$1(plan.origin, scale3$1(plan.axis, v)), radialPoint$1(plan.xAxis, yAxis, u2, radius));
|
|
38094
38799
|
}
|
|
38095
38800
|
case "sphere": {
|
|
38096
|
-
const yAxis = analyticYForFrame(plan.axis, plan.xAxis);
|
|
38097
|
-
const radial = radialPoint(plan.xAxis, yAxis, u2, plan.radius * Math.cos(v));
|
|
38098
|
-
return add3(add3(plan.center, radial), scale3(plan.axis, plan.radius * Math.sin(v)));
|
|
38801
|
+
const yAxis = analyticYForFrame$1(plan.axis, plan.xAxis);
|
|
38802
|
+
const radial = radialPoint$1(plan.xAxis, yAxis, u2, plan.radius * Math.cos(v));
|
|
38803
|
+
return add3$1(add3$1(plan.center, radial), scale3$1(plan.axis, plan.radius * Math.sin(v)));
|
|
38099
38804
|
}
|
|
38100
38805
|
case "torus": {
|
|
38101
|
-
const yAxis = analyticYForFrame(plan.axis, plan.xAxis);
|
|
38102
|
-
const radial = radialPoint(plan.xAxis, yAxis, u2, plan.majorRadius + plan.minorRadius * Math.cos(v));
|
|
38103
|
-
return add3(add3(plan.center, radial), scale3(plan.axis, plan.minorRadius * Math.sin(v)));
|
|
38806
|
+
const yAxis = analyticYForFrame$1(plan.axis, plan.xAxis);
|
|
38807
|
+
const radial = radialPoint$1(plan.xAxis, yAxis, u2, plan.majorRadius + plan.minorRadius * Math.cos(v));
|
|
38808
|
+
return add3$1(add3$1(plan.center, radial), scale3$1(plan.axis, plan.minorRadius * Math.sin(v)));
|
|
38104
38809
|
}
|
|
38105
38810
|
default:
|
|
38106
38811
|
return assertExhaustive(plan);
|
|
38107
38812
|
}
|
|
38108
38813
|
}
|
|
38109
|
-
function surfaceGridForAnalyticPlan(plan) {
|
|
38814
|
+
function surfaceGridForAnalyticPlan$1(plan) {
|
|
38110
38815
|
if (plan.trim) return null;
|
|
38111
38816
|
const rows = Math.max(2, plan.resolution + 1);
|
|
38112
38817
|
const cols = Math.max(2, plan.resolution + 1);
|
|
@@ -38117,7 +38822,7 @@ function surfaceGridForAnalyticPlan(plan) {
|
|
|
38117
38822
|
const row = [];
|
|
38118
38823
|
for (let uIdx = 0; uIdx < cols; uIdx++) {
|
|
38119
38824
|
const u2 = uMin + (uMax - uMin) * uIdx / (cols - 1);
|
|
38120
|
-
row.push(analyticSurfacePoint(plan.surface, u2, v));
|
|
38825
|
+
row.push(analyticSurfacePoint$1(plan.surface, u2, v));
|
|
38121
38826
|
}
|
|
38122
38827
|
grid.push(row);
|
|
38123
38828
|
}
|
|
@@ -38162,11 +38867,11 @@ function surfaceGridForPlan(plan) {
|
|
|
38162
38867
|
return grid;
|
|
38163
38868
|
}
|
|
38164
38869
|
case "analyticSurface":
|
|
38165
|
-
return surfaceGridForAnalyticPlan(plan);
|
|
38870
|
+
return surfaceGridForAnalyticPlan$1(plan);
|
|
38166
38871
|
case "surfaceRuled":
|
|
38167
|
-
return surfaceGridForRuledPlan(plan);
|
|
38872
|
+
return surfaceGridForRuledPlan$1(plan);
|
|
38168
38873
|
case "surfaceFill":
|
|
38169
|
-
return surfaceGridForFillPlan(plan);
|
|
38874
|
+
return surfaceGridForFillPlan$1(plan);
|
|
38170
38875
|
default:
|
|
38171
38876
|
return null;
|
|
38172
38877
|
}
|
|
@@ -38218,10 +38923,10 @@ function triangleNormal(vertices, triangle3) {
|
|
|
38218
38923
|
const c2 = vertices[triangle3[2]];
|
|
38219
38924
|
const ab = [b[0] - a2[0], b[1] - a2[1], b[2] - a2[2]];
|
|
38220
38925
|
const ac = [c2[0] - a2[0], c2[1] - a2[1], c2[2] - a2[2]];
|
|
38221
|
-
const
|
|
38222
|
-
const len2 = Math.hypot(
|
|
38926
|
+
const normal2 = cross3$3(ab, ac);
|
|
38927
|
+
const len2 = Math.hypot(normal2[0], normal2[1], normal2[2]);
|
|
38223
38928
|
if (len2 <= 1e-12) return null;
|
|
38224
|
-
return [
|
|
38929
|
+
return [normal2[0] / len2, normal2[1] / len2, normal2[2] / len2];
|
|
38225
38930
|
}
|
|
38226
38931
|
function offsetClosedSurfaceMesh(mesh, thickness) {
|
|
38227
38932
|
let triangles;
|
|
@@ -38235,22 +38940,22 @@ function offsetClosedSurfaceMesh(mesh, thickness) {
|
|
|
38235
38940
|
}
|
|
38236
38941
|
const normals = Array.from({ length: mesh.vertices.length }, () => [0, 0, 0]);
|
|
38237
38942
|
for (const triangle3 of triangles) {
|
|
38238
|
-
const
|
|
38239
|
-
if (!
|
|
38943
|
+
const normal2 = triangleNormal(mesh.vertices, triangle3);
|
|
38944
|
+
if (!normal2) return null;
|
|
38240
38945
|
for (const vertexIndex of triangle3) {
|
|
38241
|
-
normals[vertexIndex][0] +=
|
|
38242
|
-
normals[vertexIndex][1] +=
|
|
38243
|
-
normals[vertexIndex][2] +=
|
|
38946
|
+
normals[vertexIndex][0] += normal2[0];
|
|
38947
|
+
normals[vertexIndex][1] += normal2[1];
|
|
38948
|
+
normals[vertexIndex][2] += normal2[2];
|
|
38244
38949
|
}
|
|
38245
38950
|
}
|
|
38246
38951
|
const offsetVertices = mesh.vertices.map((vertex2, index2) => {
|
|
38247
|
-
const
|
|
38248
|
-
const len2 = Math.hypot(
|
|
38952
|
+
const normal2 = normals[index2];
|
|
38953
|
+
const len2 = Math.hypot(normal2[0], normal2[1], normal2[2]);
|
|
38249
38954
|
if (len2 <= 1e-12) return [vertex2[0], vertex2[1], vertex2[2]];
|
|
38250
38955
|
return [
|
|
38251
|
-
vertex2[0] -
|
|
38252
|
-
vertex2[1] -
|
|
38253
|
-
vertex2[2] -
|
|
38956
|
+
vertex2[0] - normal2[0] / len2 * thickness,
|
|
38957
|
+
vertex2[1] - normal2[1] / len2 * thickness,
|
|
38958
|
+
vertex2[2] - normal2[2] / len2 * thickness
|
|
38254
38959
|
];
|
|
38255
38960
|
});
|
|
38256
38961
|
const innerOffset = mesh.vertices.length;
|
|
@@ -38306,19 +39011,19 @@ function lowerThickenedSurfaceGrid(points, thickness) {
|
|
|
38306
39011
|
return wrapTruckShapeBackend(getTruckGeometryWasm().geometry_create_thickened_surface_grid(JSON.stringify({ points }), thickness));
|
|
38307
39012
|
}
|
|
38308
39013
|
function lowerSurfaceRuledPlan(plan) {
|
|
38309
|
-
return lowerSurfaceGrid(surfaceGridForRuledPlan(plan));
|
|
39014
|
+
return lowerSurfaceGrid(surfaceGridForRuledPlan$1(plan));
|
|
38310
39015
|
}
|
|
38311
39016
|
function lowerSurfaceFillPlan(plan) {
|
|
38312
39017
|
var _a3, _b3;
|
|
38313
39018
|
if ((((_a3 = plan.interiorCurves) == null ? void 0 : _a3.length) ?? 0) > 0 || (((_b3 = plan.interiorPoints) == null ? void 0 : _b3.length) ?? 0) > 0) {
|
|
38314
39019
|
truckUnsupported("surface fill with interior constraint curves/points");
|
|
38315
39020
|
}
|
|
38316
|
-
const grid = surfaceGridForFillPlan(plan);
|
|
39021
|
+
const grid = surfaceGridForFillPlan$1(plan);
|
|
38317
39022
|
if (!grid) truckUnsupported("surface fill constraints beyond four-boundary Coons patches");
|
|
38318
39023
|
return lowerSurfaceGrid(grid);
|
|
38319
39024
|
}
|
|
38320
39025
|
function lowerAnalyticSurfacePlan(plan) {
|
|
38321
|
-
const grid = surfaceGridForAnalyticPlan(plan);
|
|
39026
|
+
const grid = surfaceGridForAnalyticPlan$1(plan);
|
|
38322
39027
|
if (!grid) truckUnsupported("trimmed analytic surfaces in the Truck backend");
|
|
38323
39028
|
return lowerSurfaceGrid(grid);
|
|
38324
39029
|
}
|
|
@@ -38333,6 +39038,12 @@ function lowerSurfaceSewPlan(plan) {
|
|
|
38333
39038
|
}
|
|
38334
39039
|
}
|
|
38335
39040
|
function lowerSurfaceThickenPlan(plan) {
|
|
39041
|
+
if (plan.thicknessField) {
|
|
39042
|
+
const mesh = meshFromThickenedSurfaceSheetPlan(plan.base, plan.thickness, plan.thicknessField);
|
|
39043
|
+
return wrapTruckShapeBackend(
|
|
39044
|
+
getTruckGeometryWasm().geometry_create_imported_triangle_mesh(JSON.stringify(triangleMeshSpecFromShapeMesh(mesh)))
|
|
39045
|
+
);
|
|
39046
|
+
}
|
|
38336
39047
|
const sewShapes = surfaceSewShapesForPlan(plan.base);
|
|
38337
39048
|
if (sewShapes) {
|
|
38338
39049
|
const closedSew = lowerThickenedClosedSewMesh(sewShapes, plan.thickness);
|
|
@@ -38372,23 +39083,23 @@ function cross3$3(a2, b) {
|
|
|
38372
39083
|
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]];
|
|
38373
39084
|
}
|
|
38374
39085
|
function fromSlicesPlaneFrame(normalInput) {
|
|
38375
|
-
const
|
|
38376
|
-
const [nx, ny, nz] =
|
|
39086
|
+
const normal2 = normalizedVector3(normalInput, "Shape.fromSlices group normal");
|
|
39087
|
+
const [nx, ny, nz] = normal2;
|
|
38377
39088
|
if (Math.abs(nz) > 1 - 1e-8) {
|
|
38378
|
-
return { u: [1, 0, 0], v: [0, nz > 0 ? 1 : -1, 0], normal };
|
|
39089
|
+
return { u: [1, 0, 0], v: [0, nz > 0 ? 1 : -1, 0], normal: normal2 };
|
|
38379
39090
|
}
|
|
38380
39091
|
if (Math.abs(ny) > 1 - 1e-8) {
|
|
38381
|
-
return { u: [1, 0, 0], v: [0, 0, ny > 0 ? 1 : -1], normal };
|
|
39092
|
+
return { u: [1, 0, 0], v: [0, 0, ny > 0 ? 1 : -1], normal: normal2 };
|
|
38382
39093
|
}
|
|
38383
39094
|
if (Math.abs(nx) > 1 - 1e-8) {
|
|
38384
|
-
return { u: [0, 1, 0], v: [0, 0, nx > 0 ? 1 : -1], normal };
|
|
39095
|
+
return { u: [0, 1, 0], v: [0, 0, nx > 0 ? 1 : -1], normal: normal2 };
|
|
38385
39096
|
}
|
|
38386
39097
|
const reference = Math.abs(nx) < 0.9 ? [1, 0, 0] : [0, 1, 0];
|
|
38387
|
-
const u2 = normalizedVector3(cross3$3(reference,
|
|
38388
|
-
return { u: u2, v: cross3$3(
|
|
39098
|
+
const u2 = normalizedVector3(cross3$3(reference, normal2), "Shape.fromSlices profile u axis");
|
|
39099
|
+
return { u: u2, v: cross3$3(normal2, u2), normal: normal2 };
|
|
38389
39100
|
}
|
|
38390
|
-
function fromSlicesLocalToWorldMatrix(
|
|
38391
|
-
const frame = fromSlicesPlaneFrame(
|
|
39101
|
+
function fromSlicesLocalToWorldMatrix(normal2) {
|
|
39102
|
+
const frame = fromSlicesPlaneFrame(normal2);
|
|
38392
39103
|
return [
|
|
38393
39104
|
frame.u[0],
|
|
38394
39105
|
frame.u[1],
|
|
@@ -38430,8 +39141,8 @@ function fromSlicesSingleSliceHalfExtent$1(plan) {
|
|
|
38430
39141
|
}
|
|
38431
39142
|
return Math.max(1, radius + maxOffsetMagnitude + plan.boundsPadding + plan.edgeLength * 3);
|
|
38432
39143
|
}
|
|
38433
|
-
function transformZAlignedFromSlicesGroupPlan(base,
|
|
38434
|
-
const matrix = fromSlicesLocalToWorldMatrix(
|
|
39144
|
+
function transformZAlignedFromSlicesGroupPlan(base, normal2) {
|
|
39145
|
+
const matrix = fromSlicesLocalToWorldMatrix(normal2);
|
|
38435
39146
|
const isIdentity = Math.abs(matrix[0] - 1) <= 1e-12 && Math.abs(matrix[5] - 1) <= 1e-12 && Math.abs(matrix[10] - 1) <= 1e-12 && Math.abs(matrix[15] - 1) <= 1e-12 && matrix.every((value, idx) => idx === 0 || idx === 5 || idx === 10 || idx === 15 ? true : Math.abs(value) <= 1e-12);
|
|
38436
39147
|
if (isIdentity) return base;
|
|
38437
39148
|
return {
|
|
@@ -38622,8 +39333,8 @@ function lowerShapeCompilePlanToTruckBackend(plan) {
|
|
|
38622
39333
|
return lowerShapeBackendWithCache("truck", plan, lowerShapeCompilePlanToTruckBackendUncached);
|
|
38623
39334
|
}
|
|
38624
39335
|
function orientProfileLoop(points, ccw) {
|
|
38625
|
-
const
|
|
38626
|
-
if (ccw &&
|
|
39336
|
+
const area2 = signedArea(points);
|
|
39337
|
+
if (ccw && area2 < 0 || !ccw && area2 > 0) return [...points].reverse();
|
|
38627
39338
|
return points.map(([x2, y2]) => [x2, y2]);
|
|
38628
39339
|
}
|
|
38629
39340
|
function lowerProfileCompilePlanToTruckProfileBackend(plan) {
|
|
@@ -38673,8 +39384,8 @@ function normalizeVec3OrNull(v) {
|
|
|
38673
39384
|
const length4 = Math.hypot(v[0], v[1], v[2]);
|
|
38674
39385
|
return length4 > EXACT_PROFILE_EPS ? [v[0] / length4, v[1] / length4, v[2] / length4] : null;
|
|
38675
39386
|
}
|
|
38676
|
-
function mirrorTransformMatrix(
|
|
38677
|
-
const unit = normalizeVec3OrNull(
|
|
39387
|
+
function mirrorTransformMatrix(normal2) {
|
|
39388
|
+
const unit = normalizeVec3OrNull(normal2);
|
|
38678
39389
|
if (!unit) return Transform.identity().toArray();
|
|
38679
39390
|
const [nx, ny, nz] = unit;
|
|
38680
39391
|
return [
|
|
@@ -42182,10 +42893,10 @@ function normVec3(v) {
|
|
|
42182
42893
|
if (len2 < 1e-10) return null;
|
|
42183
42894
|
return [v[0] / len2, v[1] / len2, v[2] / len2];
|
|
42184
42895
|
}
|
|
42185
|
-
function tangentFrame(
|
|
42186
|
-
const ref = Math.abs(
|
|
42187
|
-
const v = normVec3(cross$1(
|
|
42188
|
-
const u2 = normVec3(cross$1(v,
|
|
42896
|
+
function tangentFrame(normal2) {
|
|
42897
|
+
const ref = Math.abs(normal2[0]) < 0.9 ? [1, 0, 0] : [0, 1, 0];
|
|
42898
|
+
const v = normVec3(cross$1(normal2, ref));
|
|
42899
|
+
const u2 = normVec3(cross$1(v, normal2));
|
|
42189
42900
|
return { u: u2, v };
|
|
42190
42901
|
}
|
|
42191
42902
|
const NORMAL_COS_EPS$1 = 0.9998;
|
|
@@ -42205,15 +42916,15 @@ function clusterMeshFaces(shape) {
|
|
|
42205
42916
|
const e1 = [v1[0] - v0[0], v1[1] - v0[1], v1[2] - v0[2]];
|
|
42206
42917
|
const e2 = [v2[0] - v0[0], v2[1] - v0[1], v2[2] - v0[2]];
|
|
42207
42918
|
const rawCross = cross$1(e1, e2);
|
|
42208
|
-
const
|
|
42209
|
-
if (!
|
|
42919
|
+
const normal2 = normVec3(rawCross);
|
|
42920
|
+
if (!normal2) continue;
|
|
42210
42921
|
const crossLen = Math.sqrt(rawCross[0] * rawCross[0] + rawCross[1] * rawCross[1] + rawCross[2] * rawCross[2]);
|
|
42211
42922
|
const triArea2 = crossLen / 2;
|
|
42212
|
-
const planeOffset = dot$1(
|
|
42923
|
+
const planeOffset = dot$1(normal2, v0);
|
|
42213
42924
|
const triCentroid2 = [(v0[0] + v1[0] + v2[0]) / 3, (v0[1] + v1[1] + v2[1]) / 3, (v0[2] + v1[2] + v2[2]) / 3];
|
|
42214
42925
|
let merged = false;
|
|
42215
42926
|
for (const c2 of clusters) {
|
|
42216
|
-
if (dot$1(c2.normal,
|
|
42927
|
+
if (dot$1(c2.normal, normal2) > NORMAL_COS_EPS$1 && Math.abs(c2.planeOffset - planeOffset) < PLANE_OFFSET_EPS$1) {
|
|
42217
42928
|
c2.centroidSum[0] += triCentroid2[0];
|
|
42218
42929
|
c2.centroidSum[1] += triCentroid2[1];
|
|
42219
42930
|
c2.centroidSum[2] += triCentroid2[2];
|
|
@@ -42225,7 +42936,7 @@ function clusterMeshFaces(shape) {
|
|
|
42225
42936
|
}
|
|
42226
42937
|
if (!merged) {
|
|
42227
42938
|
clusters.push({
|
|
42228
|
-
normal,
|
|
42939
|
+
normal: normal2,
|
|
42229
42940
|
planeOffset,
|
|
42230
42941
|
centroidSum: [triCentroid2[0], triCentroid2[1], triCentroid2[2]],
|
|
42231
42942
|
count: 1,
|
|
@@ -42399,8 +43110,8 @@ function facesAreCoplanar(faces) {
|
|
|
42399
43110
|
const planeOffset = firstNormal[0] * first.center[0] + firstNormal[1] * first.center[1] + firstNormal[2] * first.center[2];
|
|
42400
43111
|
for (const face of faces.slice(1)) {
|
|
42401
43112
|
if (face.planar === false || !face.uAxis || !face.vAxis) return false;
|
|
42402
|
-
const
|
|
42403
|
-
const alignment = Math.abs(firstNormal[0] *
|
|
43113
|
+
const normal2 = normalizeAxis(face.normal);
|
|
43114
|
+
const alignment = Math.abs(firstNormal[0] * normal2[0] + firstNormal[1] * normal2[1] + firstNormal[2] * normal2[2]);
|
|
42404
43115
|
if (Math.abs(alignment - 1) > 1e-6) return false;
|
|
42405
43116
|
const offset = firstNormal[0] * face.center[0] + firstNormal[1] * face.center[1] + firstNormal[2] * face.center[2];
|
|
42406
43117
|
if (Math.abs(offset - planeOffset) > 1e-6) return false;
|
|
@@ -42543,12 +43254,12 @@ function canonicalShapeStepMatrix(step) {
|
|
|
42543
43254
|
return [...step.matrix];
|
|
42544
43255
|
}
|
|
42545
43256
|
}
|
|
42546
|
-
function mirrorMatrix$1(
|
|
42547
|
-
const len2 = Math.hypot(
|
|
43257
|
+
function mirrorMatrix$1(normal2) {
|
|
43258
|
+
const len2 = Math.hypot(normal2[0], normal2[1], normal2[2]);
|
|
42548
43259
|
if (len2 < 1e-12) return Transform.identity().toArray();
|
|
42549
|
-
const nx =
|
|
42550
|
-
const ny =
|
|
42551
|
-
const nz =
|
|
43260
|
+
const nx = normal2[0] / len2;
|
|
43261
|
+
const ny = normal2[1] / len2;
|
|
43262
|
+
const nz = normal2[2] / len2;
|
|
42552
43263
|
return [
|
|
42553
43264
|
1 - 2 * nx * nx,
|
|
42554
43265
|
-2 * nx * ny,
|
|
@@ -42618,8 +43329,8 @@ function normalize2d(vec2) {
|
|
|
42618
43329
|
function cross3$2(a2, b) {
|
|
42619
43330
|
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]];
|
|
42620
43331
|
}
|
|
42621
|
-
function orthonormalBasisFromNormal(
|
|
42622
|
-
const n = normalizeAxis(
|
|
43332
|
+
function orthonormalBasisFromNormal(normal2) {
|
|
43333
|
+
const n = normalizeAxis(normal2);
|
|
42623
43334
|
const seed = Math.abs(n[2]) < 0.9 ? [0, 0, 1] : [0, 1, 0];
|
|
42624
43335
|
const u2 = normalizeAxis(cross3$2(seed, n));
|
|
42625
43336
|
const v = normalizeAxis(cross3$2(n, u2));
|
|
@@ -43556,10 +44267,10 @@ function resolveShapeFaceTableInternal(plan, owner) {
|
|
|
43556
44267
|
forwardStart3[1] - reverseStart3[1],
|
|
43557
44268
|
forwardStart3[2] - reverseStart3[2]
|
|
43558
44269
|
]);
|
|
43559
|
-
const
|
|
44270
|
+
const normal2 = normalizeAxis(cross3$2(edgeVec, depthVec));
|
|
43560
44271
|
registerFace(table, {
|
|
43561
44272
|
name: wall.name,
|
|
43562
|
-
normal,
|
|
44273
|
+
normal: normal2,
|
|
43563
44274
|
center: averageVec3([reverseStart3, reverseEnd3, forwardStart3, forwardEnd3]),
|
|
43564
44275
|
planar: true,
|
|
43565
44276
|
uAxis: edgeVec,
|
|
@@ -43651,22 +44362,22 @@ function resolveShapeFaceTableInternal(plan, owner) {
|
|
|
43651
44362
|
const baseTable = resolveShapeFaceTable(plan.base);
|
|
43652
44363
|
const centers = Array.from(baseTable.faces.values()).map((face) => face.center);
|
|
43653
44364
|
const averageCenter = centers.length > 0 ? centers.reduce((acc, center22) => [acc[0] + center22[0], acc[1] + center22[1], acc[2] + center22[2]], [0, 0, 0]).map((value) => value / centers.length) : [0, 0, plan.originOffset];
|
|
43654
|
-
const
|
|
43655
|
-
const planeDistance = averageCenter[0] *
|
|
44365
|
+
const normal2 = normalizeAxis([plan.normalX, plan.normalY, plan.normalZ]);
|
|
44366
|
+
const planeDistance = averageCenter[0] * normal2[0] + averageCenter[1] * normal2[1] + averageCenter[2] * normal2[2] - plan.originOffset;
|
|
43656
44367
|
const center2 = [
|
|
43657
|
-
averageCenter[0] -
|
|
43658
|
-
averageCenter[1] -
|
|
43659
|
-
averageCenter[2] -
|
|
44368
|
+
averageCenter[0] - normal2[0] * planeDistance,
|
|
44369
|
+
averageCenter[1] - normal2[1] * planeDistance,
|
|
44370
|
+
averageCenter[2] - normal2[2] * planeDistance
|
|
43660
44371
|
];
|
|
43661
|
-
const basis = orthonormalBasisFromNormal(
|
|
44372
|
+
const basis = orthonormalBasisFromNormal(normal2);
|
|
43662
44373
|
registerFace(table, {
|
|
43663
44374
|
name: "plane-cap",
|
|
43664
|
-
normal,
|
|
44375
|
+
normal: normal2,
|
|
43665
44376
|
center: center2,
|
|
43666
44377
|
planar: true,
|
|
43667
44378
|
uAxis: basis.u,
|
|
43668
44379
|
vAxis: basis.v,
|
|
43669
|
-
surface: { kind: "plane", normal },
|
|
44380
|
+
surface: { kind: "plane", normal: normal2 },
|
|
43670
44381
|
query: planeCapQuery
|
|
43671
44382
|
});
|
|
43672
44383
|
return table;
|
|
@@ -44422,16 +45133,16 @@ function buildCarrierFaceRefs(mesh, carriers) {
|
|
|
44422
45133
|
const ny = (bz - az) * (cx - ax) - (bx - ax) * (cz - az);
|
|
44423
45134
|
const nz = (bx - ax) * (cy - ay) - (by - ay) * (cx - ax);
|
|
44424
45135
|
const twoArea = Math.hypot(nx, ny, nz);
|
|
44425
|
-
const
|
|
45136
|
+
const area2 = twoArea * 0.5;
|
|
44426
45137
|
let a2 = acc.get(name);
|
|
44427
45138
|
if (!a2) {
|
|
44428
45139
|
a2 = { area: 0, cx: 0, cy: 0, cz: 0, nx: 0, ny: 0, nz: 0, facetNormal: null };
|
|
44429
45140
|
acc.set(name, a2);
|
|
44430
45141
|
}
|
|
44431
|
-
a2.area +=
|
|
44432
|
-
a2.cx += (ax + bx + cx) / 3 *
|
|
44433
|
-
a2.cy += (ay + by + cy) / 3 *
|
|
44434
|
-
a2.cz += (az + bz + cz) / 3 *
|
|
45142
|
+
a2.area += area2;
|
|
45143
|
+
a2.cx += (ax + bx + cx) / 3 * area2;
|
|
45144
|
+
a2.cy += (ay + by + cy) / 3 * area2;
|
|
45145
|
+
a2.cz += (az + bz + cz) / 3 * area2;
|
|
44435
45146
|
a2.nx += nx * 0.5;
|
|
44436
45147
|
a2.ny += ny * 0.5;
|
|
44437
45148
|
a2.nz += nz * 0.5;
|
|
@@ -44441,9 +45152,9 @@ function buildCarrierFaceRefs(mesh, carriers) {
|
|
|
44441
45152
|
if (a2.area <= 0) continue;
|
|
44442
45153
|
const center2 = [a2.cx / a2.area, a2.cy / a2.area, a2.cz / a2.area];
|
|
44443
45154
|
const nlen = Math.hypot(a2.nx, a2.ny, a2.nz);
|
|
44444
|
-
const
|
|
45155
|
+
const normal2 = nlen > 1e-9 ? [a2.nx / nlen, a2.ny / nlen, a2.nz / nlen] : a2.facetNormal ?? [0, 0, 1];
|
|
44445
45156
|
const surface = surfaceByName.get(name);
|
|
44446
|
-
out.set(name, { name, center: center2, normal, surface, planar: surface ? surface.kind === "plane" : void 0 });
|
|
45157
|
+
out.set(name, { name, center: center2, normal: normal2, surface, planar: surface ? surface.kind === "plane" : void 0 });
|
|
44447
45158
|
}
|
|
44448
45159
|
return out;
|
|
44449
45160
|
}
|
|
@@ -44915,7 +45626,7 @@ function normalize3(v) {
|
|
|
44915
45626
|
function cross3(a2, b) {
|
|
44916
45627
|
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]];
|
|
44917
45628
|
}
|
|
44918
|
-
function sub3(a2, b) {
|
|
45629
|
+
function sub3$1(a2, b) {
|
|
44919
45630
|
return [a2[0] - b[0], a2[1] - b[1], a2[2] - b[2]];
|
|
44920
45631
|
}
|
|
44921
45632
|
function negate3(v) {
|
|
@@ -44938,7 +45649,7 @@ function alignmentMatrix(childOrigin, childAxis, childUp, parentOrigin, parentAx
|
|
|
44938
45649
|
r10 * childOrigin[0] + r11 * childOrigin[1] + r12 * childOrigin[2],
|
|
44939
45650
|
r20 * childOrigin[0] + r21 * childOrigin[1] + r22 * childOrigin[2]
|
|
44940
45651
|
];
|
|
44941
|
-
const t = sub3(parentOrigin, rc);
|
|
45652
|
+
const t = sub3$1(parentOrigin, rc);
|
|
44942
45653
|
return Transform.from([r00, r10, r20, 0, r01, r11, r21, 0, r02, r12, r22, 0, t[0], t[1], t[2], 1]);
|
|
44943
45654
|
}
|
|
44944
45655
|
function computeSinglePairAlignment(childPort, targetPort) {
|
|
@@ -44977,8 +45688,8 @@ function computeMultiPairAlignment(pairs, childPorts, targetPorts, tolerance = 0
|
|
|
44977
45688
|
[0, 0, 0]
|
|
44978
45689
|
];
|
|
44979
45690
|
for (const p2 of pairs) {
|
|
44980
|
-
const s = sub3(p2.childOrigin, srcCentroid);
|
|
44981
|
-
const t2 = sub3(p2.targetOrigin, tgtCentroid);
|
|
45691
|
+
const s = sub3$1(p2.childOrigin, srcCentroid);
|
|
45692
|
+
const t2 = sub3$1(p2.targetOrigin, tgtCentroid);
|
|
44982
45693
|
for (let i = 0; i < 3; i++) {
|
|
44983
45694
|
for (let j = 0; j < 3; j++) {
|
|
44984
45695
|
h[i][j] += s[i] * t2[j];
|
|
@@ -44991,7 +45702,7 @@ function computeMultiPairAlignment(pairs, childPorts, targetPorts, tolerance = 0
|
|
|
44991
45702
|
R[1][0] * srcCentroid[0] + R[1][1] * srcCentroid[1] + R[1][2] * srcCentroid[2],
|
|
44992
45703
|
R[2][0] * srcCentroid[0] + R[2][1] * srcCentroid[1] + R[2][2] * srcCentroid[2]
|
|
44993
45704
|
];
|
|
44994
|
-
const t = sub3(tgtCentroid, rSrc);
|
|
45705
|
+
const t = sub3$1(tgtCentroid, rSrc);
|
|
44995
45706
|
const transform = Transform.from([
|
|
44996
45707
|
R[0][0],
|
|
44997
45708
|
R[1][0],
|
|
@@ -45013,7 +45724,7 @@ function computeMultiPairAlignment(pairs, childPorts, targetPorts, tolerance = 0
|
|
|
45013
45724
|
const residuals = [];
|
|
45014
45725
|
for (const p2 of pairs) {
|
|
45015
45726
|
const transformed = transform.point(p2.childOrigin);
|
|
45016
|
-
const diff = sub3(transformed, p2.targetOrigin);
|
|
45727
|
+
const diff = sub3$1(transformed, p2.targetOrigin);
|
|
45017
45728
|
residuals.push(len3(diff));
|
|
45018
45729
|
}
|
|
45019
45730
|
const maxResidual = Math.max(...residuals);
|
|
@@ -45214,7 +45925,7 @@ function getConnectorDistance(ports, nameA, nameB) {
|
|
|
45214
45925
|
const b = ports[nameB];
|
|
45215
45926
|
if (!a2) throw new Error(`connectorDistance: unknown connector "${nameA}"`);
|
|
45216
45927
|
if (!b) throw new Error(`connectorDistance: unknown connector "${nameB}"`);
|
|
45217
|
-
const d2 = sub3(a2.origin, b.origin);
|
|
45928
|
+
const d2 = sub3$1(a2.origin, b.origin);
|
|
45218
45929
|
return len3(d2);
|
|
45219
45930
|
}
|
|
45220
45931
|
function getConnectorMeasurements(ports, name) {
|
|
@@ -45277,8 +45988,8 @@ function requireVec3Pivot(v, method) {
|
|
|
45277
45988
|
if (!Array.isArray(v) || v.length !== 3 || !v.every((n) => typeof n === "number" && Number.isFinite(n)))
|
|
45278
45989
|
throw new Error(`${method} pivot must be [x, y, z] with finite numbers, got ${JSON.stringify(v)}`);
|
|
45279
45990
|
}
|
|
45280
|
-
function mirrorPlaneMatrix(
|
|
45281
|
-
const [nx0, ny0, nz0] =
|
|
45991
|
+
function mirrorPlaneMatrix(normal2) {
|
|
45992
|
+
const [nx0, ny0, nz0] = normal2;
|
|
45282
45993
|
const len2 = Math.hypot(nx0, ny0, nz0);
|
|
45283
45994
|
if (len2 < 1e-12) return Transform.identity().toArray();
|
|
45284
45995
|
const nx = nx0 / len2, ny = ny0 / len2, nz = nz0 / len2;
|
|
@@ -45581,13 +46292,13 @@ class ShapeGroup {
|
|
|
45581
46292
|
return scaled.translate(scalePivot[0], scalePivot[1], scalePivot[2]);
|
|
45582
46293
|
}
|
|
45583
46294
|
/** Mirror across a plane through the group's bounding-box center. */
|
|
45584
|
-
mirror(
|
|
45585
|
-
return this.mirrorThrough(this._bboxCenter(),
|
|
46295
|
+
mirror(normal2) {
|
|
46296
|
+
return this.mirrorThrough(this._bboxCenter(), normal2);
|
|
45586
46297
|
}
|
|
45587
46298
|
/** Mirror across a plane through an explicit point. */
|
|
45588
|
-
mirrorThrough(point2,
|
|
46299
|
+
mirrorThrough(point2, normal2) {
|
|
45589
46300
|
const mirrorPoint = requireFiniteVec3$1(point2, "ShapeGroup.mirrorThrough() point");
|
|
45590
|
-
const mirrorNormal = requireNonZeroFiniteVec3(
|
|
46301
|
+
const mirrorNormal = requireNonZeroFiniteVec3(normal2, "ShapeGroup.mirrorThrough() normal");
|
|
45591
46302
|
const matrix = mirrorPlaneMatrix(mirrorNormal);
|
|
45592
46303
|
if (mirrorPoint[0] === 0 && mirrorPoint[1] === 0 && mirrorPoint[2] === 0) {
|
|
45593
46304
|
return this.mapChildrenTransform((c2) => {
|
|
@@ -46781,12 +47492,12 @@ function clusterTriangles(mesh) {
|
|
|
46781
47492
|
nx /= len2;
|
|
46782
47493
|
ny /= len2;
|
|
46783
47494
|
nz /= len2;
|
|
46784
|
-
const
|
|
47495
|
+
const normal2 = [nx, ny, nz];
|
|
46785
47496
|
const planeOffset = nx * v0x + ny * v0y + nz * v0z;
|
|
46786
47497
|
let matched = -1;
|
|
46787
47498
|
for (let c2 = 0; c2 < clusters.length; c2++) {
|
|
46788
47499
|
const cl = clusters[c2];
|
|
46789
|
-
if (dot3(cl.normal,
|
|
47500
|
+
if (dot3(cl.normal, normal2) > NORMAL_COS_EPS && Math.abs(cl.planeOffset - planeOffset) < PLANE_OFFSET_EPS) {
|
|
46790
47501
|
matched = c2;
|
|
46791
47502
|
break;
|
|
46792
47503
|
}
|
|
@@ -46796,7 +47507,7 @@ function clusterTriangles(mesh) {
|
|
|
46796
47507
|
triCluster[t] = matched;
|
|
46797
47508
|
} else {
|
|
46798
47509
|
triCluster[t] = clusters.length;
|
|
46799
|
-
clusters.push({ normal, planeOffset, triangleIndices: [t] });
|
|
47510
|
+
clusters.push({ normal: normal2, planeOffset, triangleIndices: [t] });
|
|
46800
47511
|
}
|
|
46801
47512
|
}
|
|
46802
47513
|
return { clusters, triCluster };
|
|
@@ -47336,6 +48047,112 @@ function autoFitProjection(spec, bbox) {
|
|
|
47336
48047
|
function isImageHandle(value) {
|
|
47337
48048
|
return typeof value === "object" && value !== null && value.__forgeImage === true;
|
|
47338
48049
|
}
|
|
48050
|
+
function ease(t, easing) {
|
|
48051
|
+
if (easing !== "easeInOut") return t;
|
|
48052
|
+
return t * t * (3 - 2 * t);
|
|
48053
|
+
}
|
|
48054
|
+
function interpolateStations(profile, t) {
|
|
48055
|
+
const stations = profile.stations;
|
|
48056
|
+
if (t <= stations[0].t) return stations[0].thickness;
|
|
48057
|
+
for (let index2 = 0; index2 < stations.length - 1; index2 += 1) {
|
|
48058
|
+
const a2 = stations[index2];
|
|
48059
|
+
const b = stations[index2 + 1];
|
|
48060
|
+
if (t > b.t) continue;
|
|
48061
|
+
const localT = ease((t - a2.t) / Math.max(1e-12, b.t - a2.t), profile.easing);
|
|
48062
|
+
return a2.thickness + (b.thickness - a2.thickness) * localT;
|
|
48063
|
+
}
|
|
48064
|
+
return stations[stations.length - 1].thickness;
|
|
48065
|
+
}
|
|
48066
|
+
function bilinear(values, u2, v, easing) {
|
|
48067
|
+
const uScaled = ease(Math.min(1, Math.max(0, u2)), easing) * (values.length - 1);
|
|
48068
|
+
const vScaled = ease(Math.min(1, Math.max(0, v)), easing) * (values[0].length - 1);
|
|
48069
|
+
const u0 = Math.min(values.length - 2, Math.floor(uScaled));
|
|
48070
|
+
const v0 = Math.min(values[0].length - 2, Math.floor(vScaled));
|
|
48071
|
+
const fu = uScaled - u0;
|
|
48072
|
+
const fv = vScaled - v0;
|
|
48073
|
+
const a2 = values[u0][v0] + (values[u0 + 1][v0] - values[u0][v0]) * fu;
|
|
48074
|
+
const b = values[u0][v0 + 1] + (values[u0 + 1][v0 + 1] - values[u0][v0 + 1]) * fu;
|
|
48075
|
+
return a2 + (b - a2) * fv;
|
|
48076
|
+
}
|
|
48077
|
+
function evaluateScalarNurbs(plan, u2, v) {
|
|
48078
|
+
const degreeU = plan.degreeU;
|
|
48079
|
+
const degreeV = plan.degreeV;
|
|
48080
|
+
const values = plan.values;
|
|
48081
|
+
const uMin = plan.knotsU[degreeU];
|
|
48082
|
+
const uMax = plan.knotsU[values.length];
|
|
48083
|
+
const vMin = plan.knotsV[degreeV];
|
|
48084
|
+
const vMax = plan.knotsV[values[0].length];
|
|
48085
|
+
const uu = uMin + Math.min(1, Math.max(0, u2)) * (uMax - uMin);
|
|
48086
|
+
const vv = vMin + Math.min(1, Math.max(0, v)) * (vMax - vMin);
|
|
48087
|
+
const spanU = findSpan(values.length - 1, degreeU, uu, plan.knotsU);
|
|
48088
|
+
const spanV = findSpan(values[0].length - 1, degreeV, vv, plan.knotsV);
|
|
48089
|
+
const basisU = basisFuns(spanU, uu, degreeU, plan.knotsU);
|
|
48090
|
+
const basisV = basisFuns(spanV, vv, degreeV, plan.knotsV);
|
|
48091
|
+
let out = 0;
|
|
48092
|
+
for (let i = 0; i <= degreeU; i += 1) {
|
|
48093
|
+
const row = spanU - degreeU + i;
|
|
48094
|
+
for (let j = 0; j <= degreeV; j += 1) {
|
|
48095
|
+
const col = spanV - degreeV + j;
|
|
48096
|
+
out += basisU[i] * basisV[j] * values[row][col];
|
|
48097
|
+
}
|
|
48098
|
+
}
|
|
48099
|
+
return out;
|
|
48100
|
+
}
|
|
48101
|
+
function cloneThicknessFieldCompilePlan(plan) {
|
|
48102
|
+
switch (plan.kind) {
|
|
48103
|
+
case "constant":
|
|
48104
|
+
return { kind: "constant", thickness: plan.thickness };
|
|
48105
|
+
case "alongU":
|
|
48106
|
+
case "alongV":
|
|
48107
|
+
return { kind: plan.kind, stations: plan.stations.map((station) => ({ ...station })), easing: plan.easing };
|
|
48108
|
+
case "grid":
|
|
48109
|
+
return { kind: "grid", values: plan.values.map((row) => [...row]), easing: plan.easing };
|
|
48110
|
+
case "nurbs":
|
|
48111
|
+
return {
|
|
48112
|
+
kind: "nurbs",
|
|
48113
|
+
values: plan.values.map((row) => [...row]),
|
|
48114
|
+
degreeU: plan.degreeU,
|
|
48115
|
+
degreeV: plan.degreeV,
|
|
48116
|
+
knotsU: [...plan.knotsU],
|
|
48117
|
+
knotsV: [...plan.knotsV]
|
|
48118
|
+
};
|
|
48119
|
+
}
|
|
48120
|
+
}
|
|
48121
|
+
function evaluateThicknessField(plan, u2, v) {
|
|
48122
|
+
switch (plan.kind) {
|
|
48123
|
+
case "constant":
|
|
48124
|
+
return plan.thickness;
|
|
48125
|
+
case "alongU":
|
|
48126
|
+
return interpolateStations(plan, u2);
|
|
48127
|
+
case "alongV":
|
|
48128
|
+
return interpolateStations(plan, v);
|
|
48129
|
+
case "grid":
|
|
48130
|
+
return bilinear(plan.values, u2, v, plan.easing);
|
|
48131
|
+
case "nurbs":
|
|
48132
|
+
return evaluateScalarNurbs(plan, u2, v);
|
|
48133
|
+
}
|
|
48134
|
+
}
|
|
48135
|
+
function maxThicknessFieldValue(plan, samples = 16) {
|
|
48136
|
+
if (plan.kind === "constant") return plan.thickness;
|
|
48137
|
+
if (plan.kind === "alongU" || plan.kind === "alongV") return Math.max(...plan.stations.map((station) => station.thickness));
|
|
48138
|
+
if (plan.kind === "grid" || plan.kind === "nurbs") return Math.max(...plan.values.flat());
|
|
48139
|
+
let max2 = 0;
|
|
48140
|
+
for (let i = 0; i <= samples; i += 1) {
|
|
48141
|
+
for (let j = 0; j <= samples; j += 1) max2 = Math.max(max2, evaluateThicknessField(plan, i / samples, j / samples));
|
|
48142
|
+
}
|
|
48143
|
+
return max2;
|
|
48144
|
+
}
|
|
48145
|
+
const FIELD_PLANS = /* @__PURE__ */ new WeakMap();
|
|
48146
|
+
function normalizeThicknessInput(input, label) {
|
|
48147
|
+
if (typeof input === "number") return { thickness: input };
|
|
48148
|
+
if (input && typeof input === "object") {
|
|
48149
|
+
const stored = FIELD_PLANS.get(input);
|
|
48150
|
+
if (!stored) throw new Error(`${label} must be created by Thickness.*.`);
|
|
48151
|
+
const plan = cloneThicknessFieldCompilePlan(stored);
|
|
48152
|
+
return plan.kind === "constant" ? { thickness: plan.thickness } : { thickness: maxThicknessFieldValue(plan), field: plan };
|
|
48153
|
+
}
|
|
48154
|
+
throw new Error(`${label} must be a number or Thickness.* field.`);
|
|
48155
|
+
}
|
|
47339
48156
|
const _shapeDimensions = /* @__PURE__ */ new WeakMap();
|
|
47340
48157
|
let _shapeDimensionCounter = 0;
|
|
47341
48158
|
function nextShapeDimensionId() {
|
|
@@ -47438,8 +48255,8 @@ function rotationAroundAxisMatrix(axis, angleDeg, pivot) {
|
|
|
47438
48255
|
const tz = pz - (m20 * px + m21 * py + m22 * pz);
|
|
47439
48256
|
return [m00, m10, m20, 0, m01, m11, m21, 0, m02, m12, m22, 0, tx, ty, tz, 1];
|
|
47440
48257
|
}
|
|
47441
|
-
function mirrorMatrix(
|
|
47442
|
-
const [nx0, ny0, nz0] =
|
|
48258
|
+
function mirrorMatrix(normal2) {
|
|
48259
|
+
const [nx0, ny0, nz0] = normal2;
|
|
47443
48260
|
const len2 = Math.hypot(nx0, ny0, nz0);
|
|
47444
48261
|
if (len2 < 1e-12) return Transform.identity().toArray();
|
|
47445
48262
|
const nx = nx0 / len2;
|
|
@@ -49052,19 +49869,19 @@ class Shape {
|
|
|
49052
49869
|
return scaled.translate(scalePivot[0], scalePivot[1], scalePivot[2]);
|
|
49053
49870
|
}
|
|
49054
49871
|
/** Mirror across a plane through the shape's bounding box center, defined by its normal vector. */
|
|
49055
|
-
mirror(
|
|
49872
|
+
mirror(normal2) {
|
|
49056
49873
|
const bb = this.boundingBox();
|
|
49057
49874
|
const center2 = [
|
|
49058
49875
|
(bb.min[0] + bb.max[0]) / 2,
|
|
49059
49876
|
(bb.min[1] + bb.max[1]) / 2,
|
|
49060
49877
|
(bb.min[2] + bb.max[2]) / 2
|
|
49061
49878
|
];
|
|
49062
|
-
return this.mirrorThrough(center2,
|
|
49879
|
+
return this.mirrorThrough(center2, normal2);
|
|
49063
49880
|
}
|
|
49064
49881
|
/** Mirror across a plane through an explicit point, defined by its normal vector. */
|
|
49065
|
-
mirrorThrough(point2,
|
|
49882
|
+
mirrorThrough(point2, normal2) {
|
|
49066
49883
|
const mirrorPoint = requireFiniteVec3$1(point2, "Shape.mirrorThrough() point");
|
|
49067
|
-
const mirrorNormal = requireNonZeroFiniteVec3(
|
|
49884
|
+
const mirrorNormal = requireNonZeroFiniteVec3(normal2, "Shape.mirrorThrough() normal");
|
|
49068
49885
|
if (mirrorPoint[0] === 0 && mirrorPoint[1] === 0 && mirrorPoint[2] === 0) {
|
|
49069
49886
|
const transformedPlan2 = appendShapeCompileTransform(getShapeCompilePlanInternal(this), {
|
|
49070
49887
|
kind: "mirror",
|
|
@@ -49320,8 +50137,8 @@ class Shape {
|
|
|
49320
50137
|
];
|
|
49321
50138
|
}
|
|
49322
50139
|
/** Split by infinite plane. Returns [positive-side, negative-side]. */
|
|
49323
|
-
splitByPlane(
|
|
49324
|
-
const planeNormal = requireNonZeroFiniteVec3(
|
|
50140
|
+
splitByPlane(normal2, originOffset = 0) {
|
|
50141
|
+
const planeNormal = requireNonZeroFiniteVec3(normal2, "Shape.splitByPlane() normal");
|
|
49325
50142
|
const planeOffset = requireFiniteNumber(originOffset, "Shape.splitByPlane() originOffset");
|
|
49326
50143
|
const info = deriveGeometryInfo(getShapeGeometryInfoInternal(this), "boolean", {
|
|
49327
50144
|
topology: "none"
|
|
@@ -49350,8 +50167,8 @@ class Shape {
|
|
|
49350
50167
|
];
|
|
49351
50168
|
}
|
|
49352
50169
|
/** Keep the positive side of the plane and discard the opposite side. */
|
|
49353
|
-
trimByPlane(
|
|
49354
|
-
const planeNormal = requireNonZeroFiniteVec3(
|
|
50170
|
+
trimByPlane(normal2, originOffset = 0) {
|
|
50171
|
+
const planeNormal = requireNonZeroFiniteVec3(normal2, "Shape.trimByPlane() normal");
|
|
49355
50172
|
const planeOffset = requireFiniteNumber(originOffset, "Shape.trimByPlane() originOffset");
|
|
49356
50173
|
const basePlan = getShapeCompilePlanInternal(this);
|
|
49357
50174
|
const nextPlan = createOwnedTopologyRewritePlan(
|
|
@@ -49398,7 +50215,8 @@ class Shape {
|
|
|
49398
50215
|
}
|
|
49399
50216
|
/** Offset-thicken an exact open surface or shell into a solid. */
|
|
49400
50217
|
thicken(thickness) {
|
|
49401
|
-
const
|
|
50218
|
+
const resolvedThickness = normalizeThicknessInput(thickness, "Shape.thicken() thickness");
|
|
50219
|
+
const wallThickness = requireFiniteNumber(resolvedThickness.thickness, "Shape.thicken() thickness");
|
|
49402
50220
|
if (wallThickness === 0) {
|
|
49403
50221
|
throw new Error("Shape.thicken() requires a non-zero finite thickness.");
|
|
49404
50222
|
}
|
|
@@ -49407,12 +50225,17 @@ class Shape {
|
|
|
49407
50225
|
throw new Error("Shape.thicken() is only available on surface-representation shapes.");
|
|
49408
50226
|
}
|
|
49409
50227
|
const basePlan = getShapeCompilePlanInternal(this);
|
|
49410
|
-
const nextPlan = buildSurfaceThickenShapeCompilePlan(basePlan, wallThickness);
|
|
49411
|
-
const
|
|
50228
|
+
const nextPlan = buildSurfaceThickenShapeCompilePlan(basePlan, wallThickness, resolvedThickness.field);
|
|
50229
|
+
const variableThickness = resolvedThickness.field !== void 0;
|
|
50230
|
+
const representation = variableThickness || info.backend !== "occt" && info.backend !== "truck" ? "mesh-solid" : "brep-solid";
|
|
49412
50231
|
return setShapeCompilePlanInternal(
|
|
49413
50232
|
setShapeGeometryInfoInternal(
|
|
49414
50233
|
withBaseDimensionsPreservingOutputTopology(this, buildShapeFromCompilePlan(nextPlan, this.colorHex)),
|
|
49415
|
-
deriveGeometryInfo(info, "shell", {
|
|
50234
|
+
deriveGeometryInfo(info, "shell", {
|
|
50235
|
+
representation,
|
|
50236
|
+
fidelity: variableThickness ? "sampled" : void 0,
|
|
50237
|
+
topology: variableThickness ? "none" : info.backend === "truck" ? "kernel" : "none"
|
|
50238
|
+
})
|
|
49416
50239
|
),
|
|
49417
50240
|
nextPlan
|
|
49418
50241
|
);
|
|
@@ -50004,6 +50827,783 @@ class NurbsSurface {
|
|
|
50004
50827
|
return this.knotsV[this.degreeV] + domainT * (this.knotsV[this.nV] - this.knotsV[this.degreeV]);
|
|
50005
50828
|
}
|
|
50006
50829
|
}
|
|
50830
|
+
function cleanTrimLoop(points, context) {
|
|
50831
|
+
const open = [...points];
|
|
50832
|
+
if (open.length > 1) {
|
|
50833
|
+
const first = open[0];
|
|
50834
|
+
const last = open[open.length - 1];
|
|
50835
|
+
if (Math.hypot(first[0] - last[0], first[1] - last[1]) <= 1e-12) open.pop();
|
|
50836
|
+
}
|
|
50837
|
+
const out = [];
|
|
50838
|
+
for (const point2 of open) {
|
|
50839
|
+
const previous = out[out.length - 1];
|
|
50840
|
+
if (!previous || Math.hypot(point2[0] - previous[0], point2[1] - previous[1]) > 1e-12) out.push(point2);
|
|
50841
|
+
}
|
|
50842
|
+
if (out.length < 3) throw new Error(`${context}: trim loop requires at least 3 distinct points`);
|
|
50843
|
+
if (Math.abs(signedArea2$1(out)) <= 1e-12) throw new Error(`${context}: trim loop area is too small`);
|
|
50844
|
+
return out;
|
|
50845
|
+
}
|
|
50846
|
+
function sampleTrimLoop(loop, context) {
|
|
50847
|
+
if (loop.kind === "polygon") return cleanTrimLoop(loop.points, context);
|
|
50848
|
+
const uMin = loop.knots[loop.degree];
|
|
50849
|
+
const uMax = loop.knots[loop.controlPoints.length];
|
|
50850
|
+
const count = Math.max(3, loop.samples);
|
|
50851
|
+
const samples = Array.from({ length: count }, (_unused, index2) => {
|
|
50852
|
+
const t = count === 1 ? 0 : index2 / (count - 1);
|
|
50853
|
+
return deBoor2D(loop.controlPoints, loop.weights, loop.knots, loop.degree, uMin + t * (uMax - uMin));
|
|
50854
|
+
});
|
|
50855
|
+
return cleanTrimLoop(samples, context);
|
|
50856
|
+
}
|
|
50857
|
+
function pointInLoop(point2, loop) {
|
|
50858
|
+
let inside = false;
|
|
50859
|
+
for (let i = 0, j = loop.length - 1; i < loop.length; j = i++) {
|
|
50860
|
+
const a2 = loop[i];
|
|
50861
|
+
const b = loop[j];
|
|
50862
|
+
const intersects2 = a2[1] > point2[1] !== b[1] > point2[1] && point2[0] < (b[0] - a2[0]) * (point2[1] - a2[1]) / (b[1] - a2[1]) + a2[0];
|
|
50863
|
+
if (intersects2) inside = !inside;
|
|
50864
|
+
}
|
|
50865
|
+
return inside;
|
|
50866
|
+
}
|
|
50867
|
+
function sampleTrim(trim) {
|
|
50868
|
+
if (!trim) return null;
|
|
50869
|
+
return {
|
|
50870
|
+
outer: sampleTrimLoop(trim.outer, "nurbsSurface(trim.outer)"),
|
|
50871
|
+
holes: trim.holes.map((hole, index2) => sampleTrimLoop(hole, `nurbsSurface(trim.holes[${index2}])`))
|
|
50872
|
+
};
|
|
50873
|
+
}
|
|
50874
|
+
function uvInsideTrim(uv, trim) {
|
|
50875
|
+
if (!trim) return true;
|
|
50876
|
+
if (!pointInLoop(uv, trim.outer)) return false;
|
|
50877
|
+
return !trim.holes.some((hole) => pointInLoop(uv, hole));
|
|
50878
|
+
}
|
|
50879
|
+
function add3(a2, b) {
|
|
50880
|
+
return [a2[0] + b[0], a2[1] + b[1], a2[2] + b[2]];
|
|
50881
|
+
}
|
|
50882
|
+
function sub3(a2, b) {
|
|
50883
|
+
return [a2[0] - b[0], a2[1] - b[1], a2[2] - b[2]];
|
|
50884
|
+
}
|
|
50885
|
+
function scale3(v, scale2) {
|
|
50886
|
+
return [v[0] * scale2, v[1] * scale2, v[2] * scale2];
|
|
50887
|
+
}
|
|
50888
|
+
function distance3(a2, b) {
|
|
50889
|
+
return Math.hypot(a2[0] - b[0], a2[1] - b[1], a2[2] - b[2]);
|
|
50890
|
+
}
|
|
50891
|
+
function radialPoint(xAxis, yAxis, u2, radius) {
|
|
50892
|
+
return add3(scale3(xAxis, Math.cos(u2) * radius), scale3(yAxis, Math.sin(u2) * radius));
|
|
50893
|
+
}
|
|
50894
|
+
function analyticYForFrame(axis, xAxis) {
|
|
50895
|
+
return normalize3$2(cross3$6(axis, xAxis), "SDF analytic surface yAxis");
|
|
50896
|
+
}
|
|
50897
|
+
function analyticSurfacePoint(surface, u2, v) {
|
|
50898
|
+
switch (surface.kind) {
|
|
50899
|
+
case "plane":
|
|
50900
|
+
return add3(add3(surface.origin, scale3(surface.uAxis, u2)), scale3(surface.vAxis, v));
|
|
50901
|
+
case "cylinder": {
|
|
50902
|
+
const yAxis = analyticYForFrame(surface.axis, surface.xAxis);
|
|
50903
|
+
return add3(add3(surface.origin, scale3(surface.axis, v)), radialPoint(surface.xAxis, yAxis, u2, surface.radius));
|
|
50904
|
+
}
|
|
50905
|
+
case "cone": {
|
|
50906
|
+
const yAxis = analyticYForFrame(surface.axis, surface.xAxis);
|
|
50907
|
+
const t = (v - surface.vMin) / (surface.vMax - surface.vMin);
|
|
50908
|
+
const radius = surface.radiusBottom + (surface.radiusTop - surface.radiusBottom) * t;
|
|
50909
|
+
return add3(add3(surface.origin, scale3(surface.axis, v)), radialPoint(surface.xAxis, yAxis, u2, radius));
|
|
50910
|
+
}
|
|
50911
|
+
case "sphere": {
|
|
50912
|
+
const yAxis = analyticYForFrame(surface.axis, surface.xAxis);
|
|
50913
|
+
const radial = radialPoint(surface.xAxis, yAxis, u2, surface.radius * Math.cos(v));
|
|
50914
|
+
return add3(add3(surface.center, radial), scale3(surface.axis, surface.radius * Math.sin(v)));
|
|
50915
|
+
}
|
|
50916
|
+
case "torus": {
|
|
50917
|
+
const yAxis = analyticYForFrame(surface.axis, surface.xAxis);
|
|
50918
|
+
const radial = radialPoint(surface.xAxis, yAxis, u2, surface.majorRadius + surface.minorRadius * Math.cos(v));
|
|
50919
|
+
return add3(add3(surface.center, radial), scale3(surface.axis, surface.minorRadius * Math.sin(v)));
|
|
50920
|
+
}
|
|
50921
|
+
}
|
|
50922
|
+
}
|
|
50923
|
+
function resamplePolyline(points, count) {
|
|
50924
|
+
if (points.length === 0) return [];
|
|
50925
|
+
if (points.length === 1 || count <= 1) return [points[0]];
|
|
50926
|
+
const cumulative = [0];
|
|
50927
|
+
for (let index2 = 1; index2 < points.length; index2 += 1) {
|
|
50928
|
+
cumulative.push(cumulative[index2 - 1] + Math.hypot(...sub3(points[index2], points[index2 - 1])));
|
|
50929
|
+
}
|
|
50930
|
+
const total = cumulative[cumulative.length - 1];
|
|
50931
|
+
if (total <= 1e-12) return Array.from({ length: count }, () => points[0]);
|
|
50932
|
+
const out = [];
|
|
50933
|
+
let segment = 0;
|
|
50934
|
+
for (let index2 = 0; index2 < count; index2 += 1) {
|
|
50935
|
+
const target = index2 / (count - 1) * total;
|
|
50936
|
+
while (segment < cumulative.length - 2 && cumulative[segment + 1] < target) segment += 1;
|
|
50937
|
+
const span2 = cumulative[segment + 1] - cumulative[segment];
|
|
50938
|
+
const t = span2 > 1e-12 ? (target - cumulative[segment]) / span2 : 0;
|
|
50939
|
+
const a2 = points[segment];
|
|
50940
|
+
const b = points[segment + 1];
|
|
50941
|
+
out.push([a2[0] + (b[0] - a2[0]) * t, a2[1] + (b[1] - a2[1]) * t, a2[2] + (b[2] - a2[2]) * t]);
|
|
50942
|
+
}
|
|
50943
|
+
return out;
|
|
50944
|
+
}
|
|
50945
|
+
function sampleSurfaceCurve(path, resolution) {
|
|
50946
|
+
const count = Math.max(2, resolution + 1);
|
|
50947
|
+
return resamplePolyline(sampleSweepPath(path), count);
|
|
50948
|
+
}
|
|
50949
|
+
function reversePoints(points) {
|
|
50950
|
+
return [...points].reverse();
|
|
50951
|
+
}
|
|
50952
|
+
function pointTolerance(points) {
|
|
50953
|
+
if (points.length === 0) return 1e-7;
|
|
50954
|
+
const min2 = [...points[0]];
|
|
50955
|
+
const max2 = [...points[0]];
|
|
50956
|
+
for (const point2 of points) {
|
|
50957
|
+
min2[0] = Math.min(min2[0], point2[0]);
|
|
50958
|
+
min2[1] = Math.min(min2[1], point2[1]);
|
|
50959
|
+
min2[2] = Math.min(min2[2], point2[2]);
|
|
50960
|
+
max2[0] = Math.max(max2[0], point2[0]);
|
|
50961
|
+
max2[1] = Math.max(max2[1], point2[1]);
|
|
50962
|
+
max2[2] = Math.max(max2[2], point2[2]);
|
|
50963
|
+
}
|
|
50964
|
+
return Math.max(1e-7, distance3(min2, max2) * 1e-7);
|
|
50965
|
+
}
|
|
50966
|
+
function samePoint(a2, b, tolerance) {
|
|
50967
|
+
return distance3(a2, b) <= tolerance;
|
|
50968
|
+
}
|
|
50969
|
+
function cleanSampledCurve(points, tolerance, context) {
|
|
50970
|
+
const cleaned = [];
|
|
50971
|
+
for (const point2 of points) {
|
|
50972
|
+
const previous = cleaned[cleaned.length - 1];
|
|
50973
|
+
if (!previous || !samePoint(point2, previous, tolerance)) cleaned.push(point2);
|
|
50974
|
+
}
|
|
50975
|
+
if (cleaned.length > 1 && samePoint(cleaned[0], cleaned[cleaned.length - 1], tolerance)) cleaned.pop();
|
|
50976
|
+
if (cleaned.length < 2) throw new Error(`${context} boundary curve must have at least two distinct sample points.`);
|
|
50977
|
+
return cleaned;
|
|
50978
|
+
}
|
|
50979
|
+
function stitchBoundaryLoop(boundaries, tolerance) {
|
|
50980
|
+
const tryStitch = (seed, remaining) => {
|
|
50981
|
+
const loop = [...seed];
|
|
50982
|
+
const unused = [...remaining];
|
|
50983
|
+
while (unused.length > 0) {
|
|
50984
|
+
const end = loop[loop.length - 1];
|
|
50985
|
+
const matchIndex = unused.findIndex(
|
|
50986
|
+
(curve) => samePoint(curve[0], end, tolerance) || samePoint(curve[curve.length - 1], end, tolerance)
|
|
50987
|
+
);
|
|
50988
|
+
if (matchIndex < 0) return null;
|
|
50989
|
+
const [match] = unused.splice(matchIndex, 1);
|
|
50990
|
+
const oriented = samePoint(match[0], end, tolerance) ? match : reversePoints(match);
|
|
50991
|
+
loop.push(...oriented.slice(1));
|
|
50992
|
+
}
|
|
50993
|
+
if (!samePoint(loop[0], loop[loop.length - 1], tolerance)) return null;
|
|
50994
|
+
loop.pop();
|
|
50995
|
+
return loop;
|
|
50996
|
+
};
|
|
50997
|
+
return tryStitch(boundaries[0], boundaries.slice(1)) ?? tryStitch(reversePoints(boundaries[0]), boundaries.slice(1));
|
|
50998
|
+
}
|
|
50999
|
+
function rejectSdfInteriorConstraints(plan) {
|
|
51000
|
+
var _a3, _b3;
|
|
51001
|
+
if ((((_a3 = plan.interiorCurves) == null ? void 0 : _a3.length) ?? 0) > 0 || (((_b3 = plan.interiorPoints) == null ? void 0 : _b3.length) ?? 0) > 0) {
|
|
51002
|
+
throw new Error(
|
|
51003
|
+
"SDF backend cannot build a Surface.Fill() with interior constraint curves/points. Use the OCCT backend for constrained fills."
|
|
51004
|
+
);
|
|
51005
|
+
}
|
|
51006
|
+
}
|
|
51007
|
+
function sampledFillBoundaryLoop(plan) {
|
|
51008
|
+
rejectSdfInteriorConstraints(plan);
|
|
51009
|
+
if (plan.boundaries.length < 3) throw new Error("SDF backend sampled Surface.Fill() requires at least three boundary curves.");
|
|
51010
|
+
const rawBoundaries = plan.boundaries.map((boundary) => sampleSurfaceCurve(boundary.curve, plan.resolution));
|
|
51011
|
+
const tolerance = pointTolerance(rawBoundaries.flat());
|
|
51012
|
+
const boundaries = rawBoundaries.map(
|
|
51013
|
+
(points, index2) => cleanSampledCurve(points, tolerance, `SDF sampled Surface.Fill() boundary '${plan.boundaries[index2].name}'`)
|
|
51014
|
+
);
|
|
51015
|
+
const loop = stitchBoundaryLoop(boundaries, tolerance);
|
|
51016
|
+
if (!loop) throw new Error("SDF backend sampled Surface.Fill() requires boundary curves to form one closed loop.");
|
|
51017
|
+
if (loop.length < 3) throw new Error("SDF backend sampled Surface.Fill() requires at least three distinct boundary points.");
|
|
51018
|
+
return loop;
|
|
51019
|
+
}
|
|
51020
|
+
function surfaceGridForRuledPlan(plan) {
|
|
51021
|
+
const count = Math.max(2, plan.resolution + 1);
|
|
51022
|
+
return [
|
|
51023
|
+
resamplePolyline(sampleSurfaceCurve(plan.curveA, plan.resolution), count),
|
|
51024
|
+
resamplePolyline(sampleSurfaceCurve(plan.curveB, plan.resolution), count)
|
|
51025
|
+
];
|
|
51026
|
+
}
|
|
51027
|
+
function namedBoundaryCurve(plan, name) {
|
|
51028
|
+
return plan.boundaries.find((boundary) => boundary.name === name) ?? null;
|
|
51029
|
+
}
|
|
51030
|
+
function hasUnconstrainedCoonsFillBoundaries(plan) {
|
|
51031
|
+
return !!namedBoundaryCurve(plan, "v0") && !!namedBoundaryCurve(plan, "u1") && !!namedBoundaryCurve(plan, "v1") && !!namedBoundaryCurve(plan, "u0") && !plan.boundaries.some((boundary) => boundary.support);
|
|
51032
|
+
}
|
|
51033
|
+
function surfaceGridForFillPlan(plan) {
|
|
51034
|
+
rejectSdfInteriorConstraints(plan);
|
|
51035
|
+
const bottomCurve = namedBoundaryCurve(plan, "v0");
|
|
51036
|
+
const rightCurve = namedBoundaryCurve(plan, "u1");
|
|
51037
|
+
const topCurve = namedBoundaryCurve(plan, "v1");
|
|
51038
|
+
const leftCurve = namedBoundaryCurve(plan, "u0");
|
|
51039
|
+
if (!bottomCurve || !rightCurve || !topCurve || !leftCurve || plan.boundaries.some((boundary) => boundary.support)) {
|
|
51040
|
+
throw new Error("SDF backend gridded Surface.Patch()/Surface.Fill() requires an unconstrained four-boundary Coons patch.");
|
|
51041
|
+
}
|
|
51042
|
+
const count = Math.max(2, plan.resolution + 1);
|
|
51043
|
+
const bottom = sampleSurfaceCurve(bottomCurve.curve, plan.resolution);
|
|
51044
|
+
const right = sampleSurfaceCurve(rightCurve.curve, plan.resolution);
|
|
51045
|
+
const top = reversePoints(sampleSurfaceCurve(topCurve.curve, plan.resolution));
|
|
51046
|
+
const left = reversePoints(sampleSurfaceCurve(leftCurve.curve, plan.resolution));
|
|
51047
|
+
const p00 = bottom[0];
|
|
51048
|
+
const p10 = bottom[bottom.length - 1];
|
|
51049
|
+
const p01 = top[0];
|
|
51050
|
+
const p11 = top[top.length - 1];
|
|
51051
|
+
const grid = [];
|
|
51052
|
+
for (let vIndex = 0; vIndex < count; vIndex += 1) {
|
|
51053
|
+
const v = vIndex / (count - 1);
|
|
51054
|
+
const row = [];
|
|
51055
|
+
for (let uIndex = 0; uIndex < count; uIndex += 1) {
|
|
51056
|
+
const u2 = uIndex / (count - 1);
|
|
51057
|
+
const bottomPoint = bottom[uIndex];
|
|
51058
|
+
const topPoint = top[uIndex];
|
|
51059
|
+
const leftPoint = left[vIndex];
|
|
51060
|
+
const rightPoint = right[vIndex];
|
|
51061
|
+
const bilinear2 = [
|
|
51062
|
+
(1 - u2) * (1 - v) * p00[0] + u2 * (1 - v) * p10[0] + (1 - u2) * v * p01[0] + u2 * v * p11[0],
|
|
51063
|
+
(1 - u2) * (1 - v) * p00[1] + u2 * (1 - v) * p10[1] + (1 - u2) * v * p01[1] + u2 * v * p11[1],
|
|
51064
|
+
(1 - u2) * (1 - v) * p00[2] + u2 * (1 - v) * p10[2] + (1 - u2) * v * p01[2] + u2 * v * p11[2]
|
|
51065
|
+
];
|
|
51066
|
+
row.push([
|
|
51067
|
+
(1 - v) * bottomPoint[0] + v * topPoint[0] + (1 - u2) * leftPoint[0] + u2 * rightPoint[0] - bilinear2[0],
|
|
51068
|
+
(1 - v) * bottomPoint[1] + v * topPoint[1] + (1 - u2) * leftPoint[1] + u2 * rightPoint[1] - bilinear2[1],
|
|
51069
|
+
(1 - v) * bottomPoint[2] + v * topPoint[2] + (1 - u2) * leftPoint[2] + u2 * rightPoint[2] - bilinear2[2]
|
|
51070
|
+
]);
|
|
51071
|
+
}
|
|
51072
|
+
grid.push(row);
|
|
51073
|
+
}
|
|
51074
|
+
return grid;
|
|
51075
|
+
}
|
|
51076
|
+
function surfaceGridForAnalyticPlan(plan) {
|
|
51077
|
+
const count = Math.max(2, plan.resolution + 1);
|
|
51078
|
+
const grid = [];
|
|
51079
|
+
const uvGrid = [];
|
|
51080
|
+
const { uMin, uMax, vMin, vMax } = plan.surface;
|
|
51081
|
+
for (let uIndex = 0; uIndex < count; uIndex += 1) {
|
|
51082
|
+
const uNorm = uIndex / (count - 1);
|
|
51083
|
+
const u2 = uMin + (uMax - uMin) * uNorm;
|
|
51084
|
+
const row = [];
|
|
51085
|
+
const uvRow = [];
|
|
51086
|
+
for (let vIndex = 0; vIndex < count; vIndex += 1) {
|
|
51087
|
+
const vNorm = vIndex / (count - 1);
|
|
51088
|
+
const v = vMin + (vMax - vMin) * vNorm;
|
|
51089
|
+
row.push(analyticSurfacePoint(plan.surface, u2, v));
|
|
51090
|
+
uvRow.push([uNorm, vNorm]);
|
|
51091
|
+
}
|
|
51092
|
+
grid.push(row);
|
|
51093
|
+
uvGrid.push(uvRow);
|
|
51094
|
+
}
|
|
51095
|
+
return { grid, trim: sampleTrim(plan.trim), uvGrid };
|
|
51096
|
+
}
|
|
51097
|
+
function computeGridNormals(positions, indices) {
|
|
51098
|
+
const normals = Array.from({ length: positions.length }, () => [0, 0, 0]);
|
|
51099
|
+
for (let index2 = 0; index2 < indices.length; index2 += 3) {
|
|
51100
|
+
const a2 = positions[indices[index2]];
|
|
51101
|
+
const b = positions[indices[index2 + 1]];
|
|
51102
|
+
const c2 = positions[indices[index2 + 2]];
|
|
51103
|
+
const normal2 = cross3$6(sub3(b, a2), sub3(c2, a2));
|
|
51104
|
+
for (const vertexIndex of [indices[index2], indices[index2 + 1], indices[index2 + 2]]) {
|
|
51105
|
+
normals[vertexIndex][0] += normal2[0];
|
|
51106
|
+
normals[vertexIndex][1] += normal2[1];
|
|
51107
|
+
normals[vertexIndex][2] += normal2[2];
|
|
51108
|
+
}
|
|
51109
|
+
}
|
|
51110
|
+
return normals.map((normal2) => {
|
|
51111
|
+
const length4 = Math.hypot(normal2[0], normal2[1], normal2[2]);
|
|
51112
|
+
return length4 <= 1e-12 ? [0, 0, 1] : [normal2[0] / length4, normal2[1] / length4, normal2[2] / length4];
|
|
51113
|
+
});
|
|
51114
|
+
}
|
|
51115
|
+
function meshFromSurfaceGrid(grid, trim = null, context = "SDF surface sheet", uvGrid) {
|
|
51116
|
+
var _a3;
|
|
51117
|
+
const rows = grid.length;
|
|
51118
|
+
const cols = ((_a3 = grid[0]) == null ? void 0 : _a3.length) ?? 0;
|
|
51119
|
+
if (rows < 2 || cols < 2) throw new Error(`${context} requires at least a 2x2 sampled grid.`);
|
|
51120
|
+
const positions = grid.flat();
|
|
51121
|
+
const hasParametricUv = uvGrid !== void 0;
|
|
51122
|
+
const uvs = [];
|
|
51123
|
+
if (uvGrid) {
|
|
51124
|
+
if (uvGrid.length !== rows || uvGrid.some((row) => row.length !== cols)) {
|
|
51125
|
+
throw new Error(`${context} UV grid must match the sampled surface grid.`);
|
|
51126
|
+
}
|
|
51127
|
+
for (const row of uvGrid) uvs.push(...row);
|
|
51128
|
+
} else {
|
|
51129
|
+
for (let row = 0; row < rows; row += 1) {
|
|
51130
|
+
for (let col = 0; col < cols; col += 1) uvs.push([row / (rows - 1), col / (cols - 1)]);
|
|
51131
|
+
}
|
|
51132
|
+
}
|
|
51133
|
+
const normalizeUv = (() => {
|
|
51134
|
+
if (!uvGrid) return (uv) => uv;
|
|
51135
|
+
const { uDomain, vDomain } = uvDomainFromGrid(uvGrid);
|
|
51136
|
+
const uSpan = uDomain[1] - uDomain[0];
|
|
51137
|
+
const vSpan = vDomain[1] - vDomain[0];
|
|
51138
|
+
return (uv) => [
|
|
51139
|
+
uSpan > 0 ? (uv[0] - uDomain[0]) / uSpan : 0,
|
|
51140
|
+
vSpan > 0 ? (uv[1] - vDomain[0]) / vSpan : 0
|
|
51141
|
+
];
|
|
51142
|
+
})();
|
|
51143
|
+
const sourceIndices = [];
|
|
51144
|
+
const includeTriangle = (a2, b, c2) => {
|
|
51145
|
+
const centroid = [(uvs[a2][0] + uvs[b][0] + uvs[c2][0]) / 3, (uvs[a2][1] + uvs[b][1] + uvs[c2][1]) / 3];
|
|
51146
|
+
return uvInsideTrim(centroid, trim);
|
|
51147
|
+
};
|
|
51148
|
+
for (let row = 0; row < rows - 1; row += 1) {
|
|
51149
|
+
for (let col = 0; col < cols - 1; col += 1) {
|
|
51150
|
+
const a2 = row * cols + col;
|
|
51151
|
+
const b = a2 + 1;
|
|
51152
|
+
const c2 = (row + 1) * cols + col;
|
|
51153
|
+
const d2 = c2 + 1;
|
|
51154
|
+
if (includeTriangle(a2, c2, b)) sourceIndices.push(a2, c2, b);
|
|
51155
|
+
if (includeTriangle(b, c2, d2)) sourceIndices.push(b, c2, d2);
|
|
51156
|
+
}
|
|
51157
|
+
}
|
|
51158
|
+
if (sourceIndices.length === 0) throw new Error(`${context} trim loops removed the whole sampled surface.`);
|
|
51159
|
+
const used = /* @__PURE__ */ new Map();
|
|
51160
|
+
const compactPositions = [];
|
|
51161
|
+
const compactUvs = [];
|
|
51162
|
+
const compactIndices = sourceIndices.map((sourceIndex) => {
|
|
51163
|
+
const existing = used.get(sourceIndex);
|
|
51164
|
+
if (existing !== void 0) return existing;
|
|
51165
|
+
const next = compactPositions.length;
|
|
51166
|
+
used.set(sourceIndex, next);
|
|
51167
|
+
compactPositions.push(positions[sourceIndex]);
|
|
51168
|
+
if (hasParametricUv) compactUvs.push(normalizeUv(uvs[sourceIndex]));
|
|
51169
|
+
return next;
|
|
51170
|
+
});
|
|
51171
|
+
const compactNormals = computeGridNormals(compactPositions, compactIndices);
|
|
51172
|
+
const numProp = hasParametricUv ? NUM_PROP_WITH_UV : NUM_PROP_WITH_NORMAL;
|
|
51173
|
+
const vertProperties = new Float32Array(compactPositions.length * numProp);
|
|
51174
|
+
for (let index2 = 0; index2 < compactPositions.length; index2 += 1) {
|
|
51175
|
+
const [x2, y2, z2] = compactPositions[index2];
|
|
51176
|
+
const [nx, ny, nz] = compactNormals[index2];
|
|
51177
|
+
const offset = index2 * numProp;
|
|
51178
|
+
vertProperties[offset + POSITION_OFFSET] = x2;
|
|
51179
|
+
vertProperties[offset + POSITION_OFFSET + 1] = y2;
|
|
51180
|
+
vertProperties[offset + POSITION_OFFSET + 2] = z2;
|
|
51181
|
+
vertProperties[offset + NORMAL_OFFSET] = nx;
|
|
51182
|
+
vertProperties[offset + NORMAL_OFFSET + 1] = ny;
|
|
51183
|
+
vertProperties[offset + NORMAL_OFFSET + 2] = nz;
|
|
51184
|
+
if (hasParametricUv) {
|
|
51185
|
+
const [u2, v] = compactUvs[index2];
|
|
51186
|
+
vertProperties[offset + UV_OFFSET] = u2;
|
|
51187
|
+
vertProperties[offset + UV_OFFSET + 1] = v;
|
|
51188
|
+
}
|
|
51189
|
+
}
|
|
51190
|
+
return {
|
|
51191
|
+
numProp,
|
|
51192
|
+
numVert: compactPositions.length,
|
|
51193
|
+
numTri: compactIndices.length / 3,
|
|
51194
|
+
vertProperties,
|
|
51195
|
+
triVerts: new Uint32Array(compactIndices)
|
|
51196
|
+
};
|
|
51197
|
+
}
|
|
51198
|
+
function polygonNormal3(points, context) {
|
|
51199
|
+
const normal2 = [0, 0, 0];
|
|
51200
|
+
for (let index2 = 0; index2 < points.length; index2 += 1) {
|
|
51201
|
+
const a2 = points[index2];
|
|
51202
|
+
const b = points[(index2 + 1) % points.length];
|
|
51203
|
+
normal2[0] += (a2[1] - b[1]) * (a2[2] + b[2]);
|
|
51204
|
+
normal2[1] += (a2[2] - b[2]) * (a2[0] + b[0]);
|
|
51205
|
+
normal2[2] += (a2[0] - b[0]) * (a2[1] + b[1]);
|
|
51206
|
+
}
|
|
51207
|
+
return normalize3$2(normal2, `${context} boundary normal`);
|
|
51208
|
+
}
|
|
51209
|
+
function planarProjectionFrame(points, context) {
|
|
51210
|
+
const origin = points[0];
|
|
51211
|
+
const normal2 = polygonNormal3(points, context);
|
|
51212
|
+
const tolerance = pointTolerance(points) * 100;
|
|
51213
|
+
const uSource = points.find((point2) => distance3(point2, origin) > tolerance);
|
|
51214
|
+
if (!uSource) throw new Error(`${context} boundary loop collapsed to one point.`);
|
|
51215
|
+
const u2 = normalize3$2(sub3(uSource, origin), `${context} u axis`);
|
|
51216
|
+
const v = cross3$6(normal2, u2);
|
|
51217
|
+
const maxPlaneError = points.reduce((max2, point2) => Math.max(max2, Math.abs(dot3$4(sub3(point2, origin), normal2))), 0);
|
|
51218
|
+
if (maxPlaneError > tolerance) throw new Error(`${context} boundary loop must be planar for sampled SDF triangulation.`);
|
|
51219
|
+
return { origin, u: u2, v, tolerance };
|
|
51220
|
+
}
|
|
51221
|
+
function meshFromPlanarBoundaryLoop(loop, context) {
|
|
51222
|
+
const frame = planarProjectionFrame(loop, context);
|
|
51223
|
+
const projected = loop.map((point2) => {
|
|
51224
|
+
const relative = sub3(point2, frame.origin);
|
|
51225
|
+
return new Vector2(dot3$4(relative, frame.u), dot3$4(relative, frame.v));
|
|
51226
|
+
});
|
|
51227
|
+
const triangles = ShapeUtils.triangulateShape(projected, []);
|
|
51228
|
+
if (triangles.length === 0) throw new Error(`${context} boundary loop could not be triangulated.`);
|
|
51229
|
+
const positions = loop;
|
|
51230
|
+
const indices = [];
|
|
51231
|
+
for (const triangle3 of triangles) {
|
|
51232
|
+
const [a2, b, c2] = triangle3;
|
|
51233
|
+
const areaNormal = cross3$6(sub3(positions[b], positions[a2]), sub3(positions[c2], positions[a2]));
|
|
51234
|
+
if (Math.hypot(...areaNormal) > frame.tolerance * frame.tolerance) indices.push(a2, b, c2);
|
|
51235
|
+
}
|
|
51236
|
+
if (indices.length === 0) throw new Error(`${context} boundary loop collapsed to zero area.`);
|
|
51237
|
+
const normals = computeGridNormals(positions, indices);
|
|
51238
|
+
const vertProperties = new Float32Array(positions.length * 6);
|
|
51239
|
+
for (let index2 = 0; index2 < positions.length; index2 += 1) {
|
|
51240
|
+
const offset = index2 * 6;
|
|
51241
|
+
vertProperties[offset] = positions[index2][0];
|
|
51242
|
+
vertProperties[offset + 1] = positions[index2][1];
|
|
51243
|
+
vertProperties[offset + 2] = positions[index2][2];
|
|
51244
|
+
vertProperties[offset + 3] = normals[index2][0];
|
|
51245
|
+
vertProperties[offset + 4] = normals[index2][1];
|
|
51246
|
+
vertProperties[offset + 5] = normals[index2][2];
|
|
51247
|
+
}
|
|
51248
|
+
return {
|
|
51249
|
+
numProp: 6,
|
|
51250
|
+
numVert: positions.length,
|
|
51251
|
+
numTri: indices.length / 3,
|
|
51252
|
+
vertProperties,
|
|
51253
|
+
triVerts: new Uint32Array(indices)
|
|
51254
|
+
};
|
|
51255
|
+
}
|
|
51256
|
+
function meshFromSurfaceFillPlan(plan) {
|
|
51257
|
+
if (!hasUnconstrainedCoonsFillBoundaries(plan))
|
|
51258
|
+
return meshFromPlanarBoundaryLoop(sampledFillBoundaryLoop(plan), "SDF sampled Surface.Fill()");
|
|
51259
|
+
return meshFromSurfaceGrid(surfaceGridForFillPlan(plan), null, "SDF filled surface");
|
|
51260
|
+
}
|
|
51261
|
+
function meshFromOpenNurbsSurface(plan) {
|
|
51262
|
+
const sample = surfaceGridForNurbsPlan(plan);
|
|
51263
|
+
return meshFromSurfaceGrid(sample.grid, sample.trim ?? null, "SDF NURBS surface", sample.uvGrid);
|
|
51264
|
+
}
|
|
51265
|
+
function surfaceGridForNurbsPlan(plan) {
|
|
51266
|
+
const surface = new NurbsSurface(plan.controlGrid, {
|
|
51267
|
+
degreeU: plan.degreeU,
|
|
51268
|
+
degreeV: plan.degreeV,
|
|
51269
|
+
weights: plan.weightsGrid,
|
|
51270
|
+
knotsU: plan.knotsU,
|
|
51271
|
+
knotsV: plan.knotsV,
|
|
51272
|
+
domain: plan.domain
|
|
51273
|
+
});
|
|
51274
|
+
const resolution = Math.max(2, Math.round(plan.resolution));
|
|
51275
|
+
const grid = [];
|
|
51276
|
+
const uvGrid = [];
|
|
51277
|
+
for (let i = 0; i <= resolution; i += 1) {
|
|
51278
|
+
const u2 = i / resolution;
|
|
51279
|
+
const row = [];
|
|
51280
|
+
const uvRow = [];
|
|
51281
|
+
for (let j = 0; j <= resolution; j += 1) {
|
|
51282
|
+
const v = j / resolution;
|
|
51283
|
+
row.push(surface.pointAt(u2, v));
|
|
51284
|
+
uvRow.push([u2, v]);
|
|
51285
|
+
}
|
|
51286
|
+
grid.push(row);
|
|
51287
|
+
uvGrid.push(uvRow);
|
|
51288
|
+
}
|
|
51289
|
+
return { grid, rowAxis: "u", trim: sampleTrim(plan.trim), uDomain: [0, 1], vDomain: [0, 1], uvGrid };
|
|
51290
|
+
}
|
|
51291
|
+
function surfaceGridForSheetPlan(plan) {
|
|
51292
|
+
if (plan.kind === "queryOwner") return surfaceGridForSheetPlan(plan.base);
|
|
51293
|
+
if (plan.kind === "transform") {
|
|
51294
|
+
const sample = surfaceGridForSheetPlan(plan.base);
|
|
51295
|
+
let grid = sample.grid;
|
|
51296
|
+
for (const step of plan.steps) {
|
|
51297
|
+
const matrix = matrixFromShapeCompileTransformStep(step);
|
|
51298
|
+
grid = grid.map((row) => row.map((point2) => transformPoint$1(matrix, point2)));
|
|
51299
|
+
}
|
|
51300
|
+
return { ...sample, grid };
|
|
51301
|
+
}
|
|
51302
|
+
if (plan.kind === "nurbsSurface") return surfaceGridForNurbsPlan(plan);
|
|
51303
|
+
if (plan.kind === "analyticSurface") {
|
|
51304
|
+
const { grid, trim, uvGrid } = surfaceGridForAnalyticPlan(plan);
|
|
51305
|
+
return { grid, rowAxis: "u", trim, uDomain: [0, 1], vDomain: [0, 1], uvGrid };
|
|
51306
|
+
}
|
|
51307
|
+
if (plan.kind === "surfaceRuled") return { grid: surfaceGridForRuledPlan(plan), rowAxis: "v" };
|
|
51308
|
+
if (plan.kind === "surfaceFill") return { grid: surfaceGridForFillPlan(plan), rowAxis: "v" };
|
|
51309
|
+
if (plan.kind === "surfaceExtend") return surfaceGridForExtendedPlan(plan);
|
|
51310
|
+
throw new Error("SDF backend can Surface.Extend() only sampled NURBS, analytic, ruled, fill, or already-extended sheets right now.");
|
|
51311
|
+
}
|
|
51312
|
+
function averageBoundaryStep(points, adjacent) {
|
|
51313
|
+
let total = 0;
|
|
51314
|
+
let count = 0;
|
|
51315
|
+
for (let index2 = 0; index2 < points.length; index2 += 1) {
|
|
51316
|
+
const distance = distance3(points[index2], adjacent[index2]);
|
|
51317
|
+
if (distance > 1e-9) {
|
|
51318
|
+
total += distance;
|
|
51319
|
+
count += 1;
|
|
51320
|
+
}
|
|
51321
|
+
}
|
|
51322
|
+
return count === 0 ? 1 : total / count;
|
|
51323
|
+
}
|
|
51324
|
+
function extendPoint(boundary, adjacent, scale2) {
|
|
51325
|
+
return [
|
|
51326
|
+
boundary[0] + (boundary[0] - adjacent[0]) * scale2,
|
|
51327
|
+
boundary[1] + (boundary[1] - adjacent[1]) * scale2,
|
|
51328
|
+
boundary[2] + (boundary[2] - adjacent[2]) * scale2
|
|
51329
|
+
];
|
|
51330
|
+
}
|
|
51331
|
+
function defaultUvGrid(rows, cols, uDomain, vDomain) {
|
|
51332
|
+
const grid = [];
|
|
51333
|
+
for (let row = 0; row < rows; row += 1) {
|
|
51334
|
+
const u2 = rows === 1 ? uDomain[0] : uDomain[0] + (uDomain[1] - uDomain[0]) * row / (rows - 1);
|
|
51335
|
+
const uvRow = [];
|
|
51336
|
+
for (let col = 0; col < cols; col += 1) {
|
|
51337
|
+
const v = cols === 1 ? vDomain[0] : vDomain[0] + (vDomain[1] - vDomain[0]) * col / (cols - 1);
|
|
51338
|
+
uvRow.push([u2, v]);
|
|
51339
|
+
}
|
|
51340
|
+
grid.push(uvRow);
|
|
51341
|
+
}
|
|
51342
|
+
return grid;
|
|
51343
|
+
}
|
|
51344
|
+
function averageUvAxis(points, axis) {
|
|
51345
|
+
return points.reduce((total, point2) => total + point2[axis], 0) / points.length;
|
|
51346
|
+
}
|
|
51347
|
+
function extendTrimLoop(loop, axis, from, to) {
|
|
51348
|
+
const tolerance = Math.max(1e-6, Math.abs(to - from) * 1e-6);
|
|
51349
|
+
let hits = 0;
|
|
51350
|
+
const extended = loop.map((point2) => {
|
|
51351
|
+
if (Math.abs(point2[axis] - from) > tolerance) return point2;
|
|
51352
|
+
hits += 1;
|
|
51353
|
+
const next = [...point2];
|
|
51354
|
+
next[axis] = to;
|
|
51355
|
+
return next;
|
|
51356
|
+
});
|
|
51357
|
+
return { loop: extended, hits };
|
|
51358
|
+
}
|
|
51359
|
+
function extendTrimForBoundary(trim, axis, from, to) {
|
|
51360
|
+
if (!trim) return null;
|
|
51361
|
+
const outer = extendTrimLoop(trim.outer, axis, from, to);
|
|
51362
|
+
if (outer.hits < 2) {
|
|
51363
|
+
const name = axis === 0 ? "u" : "v";
|
|
51364
|
+
throw new Error(`SDF backend Surface.Extend() trimmed sheet has no visible ${name} boundary on the selected edge.`);
|
|
51365
|
+
}
|
|
51366
|
+
return {
|
|
51367
|
+
outer: outer.loop,
|
|
51368
|
+
holes: trim.holes.map((hole) => extendTrimLoop(hole, axis, from, to).loop)
|
|
51369
|
+
};
|
|
51370
|
+
}
|
|
51371
|
+
function uvDomainFromGrid(uvGrid) {
|
|
51372
|
+
let uMin = Number.POSITIVE_INFINITY;
|
|
51373
|
+
let uMax = Number.NEGATIVE_INFINITY;
|
|
51374
|
+
let vMin = Number.POSITIVE_INFINITY;
|
|
51375
|
+
let vMax = Number.NEGATIVE_INFINITY;
|
|
51376
|
+
for (const row of uvGrid) {
|
|
51377
|
+
for (const [u2, v] of row) {
|
|
51378
|
+
uMin = Math.min(uMin, u2);
|
|
51379
|
+
uMax = Math.max(uMax, u2);
|
|
51380
|
+
vMin = Math.min(vMin, v);
|
|
51381
|
+
vMax = Math.max(vMax, v);
|
|
51382
|
+
}
|
|
51383
|
+
}
|
|
51384
|
+
return { uDomain: [uMin, uMax], vDomain: [vMin, vMax] };
|
|
51385
|
+
}
|
|
51386
|
+
function surfaceGridForExtendedPlan(plan) {
|
|
51387
|
+
var _a3;
|
|
51388
|
+
const sample = surfaceGridForSheetPlan(plan.base);
|
|
51389
|
+
const grid = sample.grid.map((row) => [...row]);
|
|
51390
|
+
const rows = grid.length;
|
|
51391
|
+
const cols = ((_a3 = grid[0]) == null ? void 0 : _a3.length) ?? 0;
|
|
51392
|
+
if (rows < 2 || cols < 2) throw new Error("SDF backend Surface.Extend() requires at least a 2x2 sampled sheet.");
|
|
51393
|
+
const uvGrid = sample.uvGrid ?? defaultUvGrid(rows, cols, sample.uDomain ?? [0, 1], sample.vDomain ?? [0, 1]);
|
|
51394
|
+
const trimAxis = plan.inU ? 0 : 1;
|
|
51395
|
+
const extendRows = plan.inU ? sample.rowAxis === "u" : sample.rowAxis === "v";
|
|
51396
|
+
if (extendRows) {
|
|
51397
|
+
const boundaryIndex = plan.after ? rows - 1 : 0;
|
|
51398
|
+
const adjacentIndex = plan.after ? rows - 2 : 1;
|
|
51399
|
+
const boundary2 = grid[boundaryIndex];
|
|
51400
|
+
const adjacent2 = grid[adjacentIndex];
|
|
51401
|
+
const boundaryUv2 = uvGrid[boundaryIndex];
|
|
51402
|
+
const adjacentUv2 = uvGrid[adjacentIndex];
|
|
51403
|
+
const scale22 = plan.length / averageBoundaryStep(boundary2, adjacent2);
|
|
51404
|
+
const extension = boundary2.map((point2, index2) => extendPoint(point2, adjacent2[index2], scale22));
|
|
51405
|
+
const extensionUv = boundaryUv2.map(
|
|
51406
|
+
(uv, index2) => [uv[0] + (uv[0] - adjacentUv2[index2][0]) * scale22, uv[1] + (uv[1] - adjacentUv2[index2][1]) * scale22]
|
|
51407
|
+
);
|
|
51408
|
+
const nextGrid2 = plan.after ? [...grid, extension] : [extension, ...grid];
|
|
51409
|
+
const nextUvGrid2 = plan.after ? [...uvGrid, extensionUv] : [extensionUv, ...uvGrid];
|
|
51410
|
+
const domain2 = uvDomainFromGrid(nextUvGrid2);
|
|
51411
|
+
return {
|
|
51412
|
+
grid: nextGrid2,
|
|
51413
|
+
rowAxis: sample.rowAxis,
|
|
51414
|
+
trim: extendTrimForBoundary(sample.trim, trimAxis, averageUvAxis(boundaryUv2, trimAxis), averageUvAxis(extensionUv, trimAxis)),
|
|
51415
|
+
uvGrid: nextUvGrid2,
|
|
51416
|
+
...domain2
|
|
51417
|
+
};
|
|
51418
|
+
}
|
|
51419
|
+
const boundaryCol = plan.after ? cols - 1 : 0;
|
|
51420
|
+
const adjacentCol = plan.after ? cols - 2 : 1;
|
|
51421
|
+
const boundary = grid.map((row) => row[boundaryCol]);
|
|
51422
|
+
const adjacent = grid.map((row) => row[adjacentCol]);
|
|
51423
|
+
const boundaryUv = uvGrid.map((row) => row[boundaryCol]);
|
|
51424
|
+
const adjacentUv = uvGrid.map((row) => row[adjacentCol]);
|
|
51425
|
+
const scale2 = plan.length / averageBoundaryStep(boundary, adjacent);
|
|
51426
|
+
const nextGrid = grid.map((row, rowIndex) => {
|
|
51427
|
+
const extension = extendPoint(row[boundaryCol], adjacent[rowIndex], scale2);
|
|
51428
|
+
return plan.after ? [...row, extension] : [extension, ...row];
|
|
51429
|
+
});
|
|
51430
|
+
const nextUvGrid = uvGrid.map((row, rowIndex) => {
|
|
51431
|
+
const uv = boundaryUv[rowIndex];
|
|
51432
|
+
const adjacent2 = adjacentUv[rowIndex];
|
|
51433
|
+
const extensionUv = [uv[0] + (uv[0] - adjacent2[0]) * scale2, uv[1] + (uv[1] - adjacent2[1]) * scale2];
|
|
51434
|
+
return plan.after ? [...row, extensionUv] : [extensionUv, ...row];
|
|
51435
|
+
});
|
|
51436
|
+
const domain = uvDomainFromGrid(nextUvGrid);
|
|
51437
|
+
return {
|
|
51438
|
+
grid: nextGrid,
|
|
51439
|
+
rowAxis: sample.rowAxis,
|
|
51440
|
+
trim: extendTrimForBoundary(
|
|
51441
|
+
sample.trim,
|
|
51442
|
+
trimAxis,
|
|
51443
|
+
averageUvAxis(boundaryUv, trimAxis),
|
|
51444
|
+
averageUvAxis(
|
|
51445
|
+
nextUvGrid.map((row) => row[plan.after ? cols : 0]),
|
|
51446
|
+
trimAxis
|
|
51447
|
+
)
|
|
51448
|
+
),
|
|
51449
|
+
uvGrid: nextUvGrid,
|
|
51450
|
+
...domain
|
|
51451
|
+
};
|
|
51452
|
+
}
|
|
51453
|
+
function vertex(mesh, index2) {
|
|
51454
|
+
const offset = index2 * mesh.numProp;
|
|
51455
|
+
return [mesh.vertProperties[offset], mesh.vertProperties[offset + 1], mesh.vertProperties[offset + 2]];
|
|
51456
|
+
}
|
|
51457
|
+
function normal(mesh, index2) {
|
|
51458
|
+
if (mesh.numProp < 6) throw new Error("SDF surface thickening requires mesh normals.");
|
|
51459
|
+
const offset = index2 * mesh.numProp;
|
|
51460
|
+
return [mesh.vertProperties[offset + 3], mesh.vertProperties[offset + 4], mesh.vertProperties[offset + 5]];
|
|
51461
|
+
}
|
|
51462
|
+
function boundaryEdges(mesh) {
|
|
51463
|
+
const edges = /* @__PURE__ */ new Map();
|
|
51464
|
+
const add2 = (a2, b) => {
|
|
51465
|
+
const key2 = a2 < b ? `${a2}/${b}` : `${b}/${a2}`;
|
|
51466
|
+
const existing = edges.get(key2);
|
|
51467
|
+
if (existing) existing.count += 1;
|
|
51468
|
+
else edges.set(key2, { a: a2, b, count: 1 });
|
|
51469
|
+
};
|
|
51470
|
+
for (let tri = 0; tri < mesh.numTri; tri += 1) {
|
|
51471
|
+
const a2 = mesh.triVerts[tri * 3];
|
|
51472
|
+
const b = mesh.triVerts[tri * 3 + 1];
|
|
51473
|
+
const c2 = mesh.triVerts[tri * 3 + 2];
|
|
51474
|
+
add2(a2, b);
|
|
51475
|
+
add2(b, c2);
|
|
51476
|
+
add2(c2, a2);
|
|
51477
|
+
}
|
|
51478
|
+
return [...edges.values()].filter((edge) => edge.count === 1).map((edge) => [edge.a, edge.b]);
|
|
51479
|
+
}
|
|
51480
|
+
function thicknessAtMeshVertex(openMesh, index2, thickness, field2) {
|
|
51481
|
+
if (!field2) return thickness;
|
|
51482
|
+
if (openMesh.numProp !== NUM_PROP_WITH_UV) {
|
|
51483
|
+
throw new Error(
|
|
51484
|
+
"Variable surface thickness requires a parametric UV sheet. Use Surface.Net, Surface.Nurbs, or an analytic Surface.* sheet."
|
|
51485
|
+
);
|
|
51486
|
+
}
|
|
51487
|
+
const offset = index2 * openMesh.numProp;
|
|
51488
|
+
const value = evaluateThicknessField(field2, openMesh.vertProperties[offset + UV_OFFSET], openMesh.vertProperties[offset + UV_OFFSET + 1]);
|
|
51489
|
+
if (!Number.isFinite(value) || value <= 0) throw new Error(`Variable surface thickness evaluated to ${value} at vertex ${index2}.`);
|
|
51490
|
+
return value;
|
|
51491
|
+
}
|
|
51492
|
+
function meshFromThickenedOpenSurface(openMesh, thickness, field2) {
|
|
51493
|
+
const topCount = openMesh.numVert ?? openMesh.vertProperties.length / openMesh.numProp;
|
|
51494
|
+
const allPositions = [];
|
|
51495
|
+
for (let index2 = 0; index2 < topCount; index2 += 1) {
|
|
51496
|
+
const [x2, y2, z2] = vertex(openMesh, index2);
|
|
51497
|
+
allPositions.push(x2, y2, z2);
|
|
51498
|
+
}
|
|
51499
|
+
for (let index2 = 0; index2 < topCount; index2 += 1) {
|
|
51500
|
+
const [x2, y2, z2] = vertex(openMesh, index2);
|
|
51501
|
+
const [nx, ny, nz] = normal(openMesh, index2);
|
|
51502
|
+
const localThickness = thicknessAtMeshVertex(openMesh, index2, thickness, field2);
|
|
51503
|
+
allPositions.push(x2 - nx * localThickness, y2 - ny * localThickness, z2 - nz * localThickness);
|
|
51504
|
+
}
|
|
51505
|
+
const allIndices = [];
|
|
51506
|
+
for (const index2 of openMesh.triVerts) allIndices.push(index2);
|
|
51507
|
+
for (let index2 = 0; index2 < openMesh.triVerts.length; index2 += 3) {
|
|
51508
|
+
allIndices.push(openMesh.triVerts[index2] + topCount, openMesh.triVerts[index2 + 2] + topCount, openMesh.triVerts[index2 + 1] + topCount);
|
|
51509
|
+
}
|
|
51510
|
+
for (const [a2, b] of boundaryEdges(openMesh)) {
|
|
51511
|
+
allIndices.push(a2, a2 + topCount, b, b, a2 + topCount, b + topCount);
|
|
51512
|
+
}
|
|
51513
|
+
return {
|
|
51514
|
+
numProp: 3,
|
|
51515
|
+
numVert: allPositions.length / 3,
|
|
51516
|
+
numTri: allIndices.length / 3,
|
|
51517
|
+
vertProperties: new Float32Array(allPositions),
|
|
51518
|
+
triVerts: new Uint32Array(allIndices)
|
|
51519
|
+
};
|
|
51520
|
+
}
|
|
51521
|
+
function mergeSurfaceMeshes(meshes) {
|
|
51522
|
+
const positions = [];
|
|
51523
|
+
const normals = [];
|
|
51524
|
+
const indices = [];
|
|
51525
|
+
const vertexByKey = /* @__PURE__ */ new Map();
|
|
51526
|
+
const keyFor2 = (point2) => point2.map((value) => value.toFixed(7)).join(",");
|
|
51527
|
+
for (const mesh of meshes) {
|
|
51528
|
+
const remap = /* @__PURE__ */ new Map();
|
|
51529
|
+
const count = mesh.numVert ?? mesh.vertProperties.length / mesh.numProp;
|
|
51530
|
+
for (let index2 = 0; index2 < count; index2 += 1) {
|
|
51531
|
+
const offset = index2 * mesh.numProp;
|
|
51532
|
+
const point2 = [mesh.vertProperties[offset], mesh.vertProperties[offset + 1], mesh.vertProperties[offset + 2]];
|
|
51533
|
+
const key2 = keyFor2(point2);
|
|
51534
|
+
let target = vertexByKey.get(key2);
|
|
51535
|
+
if (target === void 0) {
|
|
51536
|
+
target = positions.length;
|
|
51537
|
+
vertexByKey.set(key2, target);
|
|
51538
|
+
positions.push(point2);
|
|
51539
|
+
normals.push([0, 0, 0]);
|
|
51540
|
+
}
|
|
51541
|
+
if (mesh.numProp >= 6) {
|
|
51542
|
+
normals[target][0] += mesh.vertProperties[offset + 3];
|
|
51543
|
+
normals[target][1] += mesh.vertProperties[offset + 4];
|
|
51544
|
+
normals[target][2] += mesh.vertProperties[offset + 5];
|
|
51545
|
+
}
|
|
51546
|
+
remap.set(index2, target);
|
|
51547
|
+
}
|
|
51548
|
+
for (const sourceIndex of mesh.triVerts) {
|
|
51549
|
+
const mapped = remap.get(sourceIndex);
|
|
51550
|
+
if (mapped === void 0) throw new Error("SDF surface mesh merge encountered an invalid triangle index.");
|
|
51551
|
+
indices.push(mapped);
|
|
51552
|
+
}
|
|
51553
|
+
}
|
|
51554
|
+
const fallbackNormals = computeGridNormals(positions, indices);
|
|
51555
|
+
const vertProperties = new Float32Array(positions.length * 6);
|
|
51556
|
+
for (let index2 = 0; index2 < positions.length; index2 += 1) {
|
|
51557
|
+
const normal2 = Math.hypot(...normals[index2]) <= 1e-12 ? fallbackNormals[index2] : normalize3$2(normals[index2], "SDF surface mesh normal");
|
|
51558
|
+
const offset = index2 * 6;
|
|
51559
|
+
vertProperties[offset] = positions[index2][0];
|
|
51560
|
+
vertProperties[offset + 1] = positions[index2][1];
|
|
51561
|
+
vertProperties[offset + 2] = positions[index2][2];
|
|
51562
|
+
vertProperties[offset + 3] = normal2[0];
|
|
51563
|
+
vertProperties[offset + 4] = normal2[1];
|
|
51564
|
+
vertProperties[offset + 5] = normal2[2];
|
|
51565
|
+
}
|
|
51566
|
+
return {
|
|
51567
|
+
numProp: 6,
|
|
51568
|
+
numVert: positions.length,
|
|
51569
|
+
numTri: indices.length / 3,
|
|
51570
|
+
vertProperties,
|
|
51571
|
+
triVerts: new Uint32Array(indices)
|
|
51572
|
+
};
|
|
51573
|
+
}
|
|
51574
|
+
function isOpenSurfaceSheetMeshPlan(plan) {
|
|
51575
|
+
if (plan.kind === "queryOwner") return isOpenSurfaceSheetMeshPlan(plan.base);
|
|
51576
|
+
if (plan.kind === "transform") return isOpenSurfaceSheetMeshPlan(plan.base);
|
|
51577
|
+
if (plan.kind === "trimByPlane") return isOpenSurfaceSheetMeshPlan(plan.base);
|
|
51578
|
+
if (plan.kind === "boolean") return plan.op === "union" && plan.shapes.every(isOpenSurfaceSheetMeshPlan);
|
|
51579
|
+
return plan.kind === "nurbsSurface" && plan.thickness === 0 || plan.kind === "analyticSurface" || plan.kind === "surfaceRuled" || plan.kind === "surfaceFill" || plan.kind === "surfaceExtend" || plan.kind === "surfaceSew";
|
|
51580
|
+
}
|
|
51581
|
+
function meshFromOpenSurfaceSheetPlan(plan) {
|
|
51582
|
+
if (plan.kind === "queryOwner") return meshFromOpenSurfaceSheetPlan(plan.base);
|
|
51583
|
+
if (plan.kind === "transform") return transformRuntimeMeshSteps(meshFromOpenSurfaceSheetPlan(plan.base), plan.steps);
|
|
51584
|
+
if (plan.kind === "trimByPlane") {
|
|
51585
|
+
return clipSurfaceMeshByPlane(meshFromOpenSurfaceSheetPlan(plan.base), [plan.normalX, plan.normalY, plan.normalZ], plan.originOffset);
|
|
51586
|
+
}
|
|
51587
|
+
if (plan.kind === "boolean" && plan.op === "union" && plan.shapes.every(isOpenSurfaceSheetMeshPlan)) {
|
|
51588
|
+
return mergeSurfaceMeshes(plan.shapes.map(meshFromOpenSurfaceSheetPlan));
|
|
51589
|
+
}
|
|
51590
|
+
if (plan.kind === "nurbsSurface") return meshFromOpenNurbsSurface(plan);
|
|
51591
|
+
if (plan.kind === "analyticSurface") {
|
|
51592
|
+
const { grid, trim, uvGrid } = surfaceGridForAnalyticPlan(plan);
|
|
51593
|
+
return meshFromSurfaceGrid(grid, trim, "SDF analytic surface", uvGrid);
|
|
51594
|
+
}
|
|
51595
|
+
if (plan.kind === "surfaceRuled") return meshFromSurfaceGrid(surfaceGridForRuledPlan(plan), null, "SDF ruled surface");
|
|
51596
|
+
if (plan.kind === "surfaceFill") return meshFromSurfaceFillPlan(plan);
|
|
51597
|
+
if (plan.kind === "surfaceExtend") {
|
|
51598
|
+
const sample = surfaceGridForExtendedPlan(plan);
|
|
51599
|
+
return meshFromSurfaceGrid(sample.grid, sample.trim ?? null, "SDF extended surface", sample.uvGrid);
|
|
51600
|
+
}
|
|
51601
|
+
if (plan.kind === "surfaceSew") return mergeSurfaceMeshes(plan.shapes.map(meshFromOpenSurfaceSheetPlan));
|
|
51602
|
+
throw new Error("SDF backend can render open surface sheets only for NURBS, analytic, ruled, fill, sew, and union plans right now.");
|
|
51603
|
+
}
|
|
51604
|
+
function meshFromThickenedSurfaceSheetPlan(plan, thickness, field2) {
|
|
51605
|
+
return meshFromThickenedOpenSurface(meshFromOpenSurfaceSheetPlan(plan), thickness, field2);
|
|
51606
|
+
}
|
|
50007
51607
|
const DEFAULT_LEAF_SIZE = 8;
|
|
50008
51608
|
function cloneVec3$3(value) {
|
|
50009
51609
|
return [value[0], value[1], value[2]];
|
|
@@ -51306,9 +52906,9 @@ function summarizeRoughnessTriangles(triangles, edgeAngles, edgeCount, boundaryE
|
|
|
51306
52906
|
};
|
|
51307
52907
|
let totalArea = 0;
|
|
51308
52908
|
for (const tri of triangles) {
|
|
51309
|
-
const
|
|
51310
|
-
totalArea +=
|
|
51311
|
-
areaByClass[roughnessClassForAngle(tri.maxAngleDeg, options)] +=
|
|
52909
|
+
const area2 = Number.isFinite(tri.area) ? tri.area : 0;
|
|
52910
|
+
totalArea += area2;
|
|
52911
|
+
areaByClass[roughnessClassForAngle(tri.maxAngleDeg, options)] += area2;
|
|
51312
52912
|
}
|
|
51313
52913
|
const sortedAngles = [...edgeAngles].sort((lhs, rhs) => lhs - rhs);
|
|
51314
52914
|
const meanAngleDeg = sortedAngles.length > 0 ? Number((sortedAngles.reduce((sum2, angle) => sum2 + angle, 0) / sortedAngles.length).toFixed(2)) : null;
|
|
@@ -51439,22 +53039,22 @@ function readSurfaceTriangles(position) {
|
|
|
51439
53039
|
const b = new Vector3();
|
|
51440
53040
|
const c2 = new Vector3();
|
|
51441
53041
|
const ac = new Vector3();
|
|
51442
|
-
const
|
|
53042
|
+
const normal2 = new Vector3();
|
|
51443
53043
|
const triangleCount = Math.floor(position.count / 3);
|
|
51444
53044
|
for (let tri = 0; tri < triangleCount; tri += 1) {
|
|
51445
53045
|
const offset = tri * 3;
|
|
51446
53046
|
a2.fromBufferAttribute(position, offset);
|
|
51447
53047
|
b.fromBufferAttribute(position, offset + 1);
|
|
51448
53048
|
c2.fromBufferAttribute(position, offset + 2);
|
|
51449
|
-
|
|
51450
|
-
const areaTwice =
|
|
53049
|
+
normal2.subVectors(b, a2).cross(ac.subVectors(c2, a2));
|
|
53050
|
+
const areaTwice = normal2.length();
|
|
51451
53051
|
if (areaTwice <= MIN_TRIANGLE_AREA) continue;
|
|
51452
53052
|
triangles.push({
|
|
51453
53053
|
index: tri,
|
|
51454
53054
|
a: a2.clone(),
|
|
51455
53055
|
b: b.clone(),
|
|
51456
53056
|
c: c2.clone(),
|
|
51457
|
-
normal:
|
|
53057
|
+
normal: normal2.clone().multiplyScalar(1 / areaTwice),
|
|
51458
53058
|
area: areaTwice * 0.5
|
|
51459
53059
|
});
|
|
51460
53060
|
}
|
|
@@ -51578,7 +53178,7 @@ function analyzeRoughnessGeometry(sourceGeometry, rawOptions = {}) {
|
|
|
51578
53178
|
const b = new Vector3();
|
|
51579
53179
|
const c2 = new Vector3();
|
|
51580
53180
|
const ac = new Vector3();
|
|
51581
|
-
const
|
|
53181
|
+
const normal2 = new Vector3();
|
|
51582
53182
|
const bbox = new Box3().setFromBufferAttribute(position);
|
|
51583
53183
|
const snap2 = Math.max(1e-6, bbox.getSize(new Vector3()).length() * 1e-8);
|
|
51584
53184
|
for (let tri = 0; tri < triangleCount; tri += 1) {
|
|
@@ -51586,10 +53186,10 @@ function analyzeRoughnessGeometry(sourceGeometry, rawOptions = {}) {
|
|
|
51586
53186
|
readVertex(position, offset, a2);
|
|
51587
53187
|
readVertex(position, offset + 1, b);
|
|
51588
53188
|
readVertex(position, offset + 2, c2);
|
|
51589
|
-
|
|
51590
|
-
const areaTwice =
|
|
53189
|
+
normal2.subVectors(b, a2).cross(ac.subVectors(c2, a2));
|
|
53190
|
+
const areaTwice = normal2.length();
|
|
51591
53191
|
triangles[tri] = { area: areaTwice * 0.5, maxAngleDeg: 0 };
|
|
51592
|
-
normals[tri] = areaTwice > 1e-12 ?
|
|
53192
|
+
normals[tri] = areaTwice > 1e-12 ? normal2.multiplyScalar(1 / areaTwice).clone() : new Vector3(0, 0, 1);
|
|
51593
53193
|
const keys = [vertexKey$1(a2, snap2), vertexKey$1(b, snap2), vertexKey$1(c2, snap2)];
|
|
51594
53194
|
for (let edge = 0; edge < 3; edge += 1) {
|
|
51595
53195
|
const key2 = edgeKey$2(keys[edge], keys[(edge + 1) % 3]);
|
|
@@ -53518,7 +55118,7 @@ function checkIntersection(ray2, pA, pB, pC, point2, side, near, far) {
|
|
|
53518
55118
|
point: point2.clone()
|
|
53519
55119
|
};
|
|
53520
55120
|
}
|
|
53521
|
-
function checkBufferGeometryIntersection(ray2, position,
|
|
55121
|
+
function checkBufferGeometryIntersection(ray2, position, normal2, uv, uv1, a2, b, c2, side, near, far) {
|
|
53522
55122
|
_vA.fromBufferAttribute(position, a2);
|
|
53523
55123
|
_vB.fromBufferAttribute(position, b);
|
|
53524
55124
|
_vC.fromBufferAttribute(position, c2);
|
|
@@ -53538,10 +55138,10 @@ function checkBufferGeometryIntersection(ray2, position, normal, uv, uv1, a2, b,
|
|
|
53538
55138
|
_uvC.fromBufferAttribute(uv1, c2);
|
|
53539
55139
|
intersection2.uv1 = Triangle.getInterpolation(_intersectionPoint, _vA, _vB, _vC, _uvA, _uvB, _uvC, new Vector2());
|
|
53540
55140
|
}
|
|
53541
|
-
if (
|
|
53542
|
-
_normalA.fromBufferAttribute(
|
|
53543
|
-
_normalB.fromBufferAttribute(
|
|
53544
|
-
_normalC.fromBufferAttribute(
|
|
55141
|
+
if (normal2) {
|
|
55142
|
+
_normalA.fromBufferAttribute(normal2, a2);
|
|
55143
|
+
_normalB.fromBufferAttribute(normal2, b);
|
|
55144
|
+
_normalC.fromBufferAttribute(normal2, c2);
|
|
53545
55145
|
intersection2.normal = Triangle.getInterpolation(_intersectionPoint, _vA, _vB, _vC, _normalA, _normalB, _normalC, new Vector3());
|
|
53546
55146
|
if (intersection2.normal.dot(ray2.direction) > 0) {
|
|
53547
55147
|
intersection2.normal.multiplyScalar(-1);
|
|
@@ -53574,8 +55174,8 @@ function intersectTri(geo, side, ray2, tri, intersections, near, far) {
|
|
|
53574
55174
|
b = index2.getX(b);
|
|
53575
55175
|
c2 = index2.getX(c2);
|
|
53576
55176
|
}
|
|
53577
|
-
const { position, normal, uv, uv1 } = geo.attributes;
|
|
53578
|
-
const intersection2 = checkBufferGeometryIntersection(ray2, position,
|
|
55177
|
+
const { position, normal: normal2, uv, uv1 } = geo.attributes;
|
|
55178
|
+
const intersection2 = checkBufferGeometryIntersection(ray2, position, normal2, uv, uv1, a2, b, c2, side, near, far);
|
|
53579
55179
|
if (intersection2) {
|
|
53580
55180
|
intersection2.faceIndex = tri;
|
|
53581
55181
|
if (intersections) intersections.push(intersection2);
|
|
@@ -53815,27 +55415,27 @@ function iterateOverTriangles_indirect(offset, count, bvh, intersectsTriangleFun
|
|
|
53815
55415
|
}
|
|
53816
55416
|
return false;
|
|
53817
55417
|
}
|
|
53818
|
-
function raycast(bvh, root, side, ray2,
|
|
55418
|
+
function raycast(bvh, root, side, ray2, intersects2, near, far) {
|
|
53819
55419
|
BufferStack.setBuffer(bvh._roots[root]);
|
|
53820
|
-
_raycast$1(0, bvh, side, ray2,
|
|
55420
|
+
_raycast$1(0, bvh, side, ray2, intersects2, near, far);
|
|
53821
55421
|
BufferStack.clearBuffer();
|
|
53822
55422
|
}
|
|
53823
|
-
function _raycast$1(nodeIndex32, bvh, side, ray2,
|
|
55423
|
+
function _raycast$1(nodeIndex32, bvh, side, ray2, intersects2, near, far) {
|
|
53824
55424
|
const { float32Array: float32Array2, uint16Array: uint16Array2, uint32Array: uint32Array2 } = BufferStack;
|
|
53825
55425
|
const nodeIndex16 = nodeIndex32 * 2;
|
|
53826
55426
|
const isLeaf = IS_LEAF(nodeIndex16, uint16Array2);
|
|
53827
55427
|
if (isLeaf) {
|
|
53828
55428
|
const offset = OFFSET(nodeIndex32, uint32Array2);
|
|
53829
55429
|
const count = COUNT(nodeIndex16, uint16Array2);
|
|
53830
|
-
intersectTris(bvh, side, ray2, offset, count,
|
|
55430
|
+
intersectTris(bvh, side, ray2, offset, count, intersects2, near, far);
|
|
53831
55431
|
} else {
|
|
53832
55432
|
const leftIndex = LEFT_NODE(nodeIndex32);
|
|
53833
55433
|
if (intersectRay(leftIndex, float32Array2, ray2, near, far)) {
|
|
53834
|
-
_raycast$1(leftIndex, bvh, side, ray2,
|
|
55434
|
+
_raycast$1(leftIndex, bvh, side, ray2, intersects2, near, far);
|
|
53835
55435
|
}
|
|
53836
55436
|
const rightIndex = RIGHT_NODE(nodeIndex32, uint32Array2);
|
|
53837
55437
|
if (intersectRay(rightIndex, float32Array2, ray2, near, far)) {
|
|
53838
|
-
_raycast$1(rightIndex, bvh, side, ray2,
|
|
55438
|
+
_raycast$1(rightIndex, bvh, side, ray2, intersects2, near, far);
|
|
53839
55439
|
}
|
|
53840
55440
|
}
|
|
53841
55441
|
}
|
|
@@ -54209,27 +55809,27 @@ function refit_indirect(bvh, nodeIndices = null) {
|
|
|
54209
55809
|
}
|
|
54210
55810
|
}
|
|
54211
55811
|
}
|
|
54212
|
-
function raycast_indirect(bvh, root, side, ray2,
|
|
55812
|
+
function raycast_indirect(bvh, root, side, ray2, intersects2, near, far) {
|
|
54213
55813
|
BufferStack.setBuffer(bvh._roots[root]);
|
|
54214
|
-
_raycast(0, bvh, side, ray2,
|
|
55814
|
+
_raycast(0, bvh, side, ray2, intersects2, near, far);
|
|
54215
55815
|
BufferStack.clearBuffer();
|
|
54216
55816
|
}
|
|
54217
|
-
function _raycast(nodeIndex32, bvh, side, ray2,
|
|
55817
|
+
function _raycast(nodeIndex32, bvh, side, ray2, intersects2, near, far) {
|
|
54218
55818
|
const { float32Array: float32Array2, uint16Array: uint16Array2, uint32Array: uint32Array2 } = BufferStack;
|
|
54219
55819
|
const nodeIndex16 = nodeIndex32 * 2;
|
|
54220
55820
|
const isLeaf = IS_LEAF(nodeIndex16, uint16Array2);
|
|
54221
55821
|
if (isLeaf) {
|
|
54222
55822
|
const offset = OFFSET(nodeIndex32, uint32Array2);
|
|
54223
55823
|
const count = COUNT(nodeIndex16, uint16Array2);
|
|
54224
|
-
intersectTris_indirect(bvh, side, ray2, offset, count,
|
|
55824
|
+
intersectTris_indirect(bvh, side, ray2, offset, count, intersects2, near, far);
|
|
54225
55825
|
} else {
|
|
54226
55826
|
const leftIndex = LEFT_NODE(nodeIndex32);
|
|
54227
55827
|
if (intersectRay(leftIndex, float32Array2, ray2, near, far)) {
|
|
54228
|
-
_raycast(leftIndex, bvh, side, ray2,
|
|
55828
|
+
_raycast(leftIndex, bvh, side, ray2, intersects2, near, far);
|
|
54229
55829
|
}
|
|
54230
55830
|
const rightIndex = RIGHT_NODE(nodeIndex32, uint32Array2);
|
|
54231
55831
|
if (intersectRay(rightIndex, float32Array2, ray2, near, far)) {
|
|
54232
|
-
_raycast(rightIndex, bvh, side, ray2,
|
|
55832
|
+
_raycast(rightIndex, bvh, side, ray2, intersects2, near, far);
|
|
54233
55833
|
}
|
|
54234
55834
|
}
|
|
54235
55835
|
}
|
|
@@ -54899,7 +56499,7 @@ class MeshBVH {
|
|
|
54899
56499
|
raycast(ray2, materialOrSide = FrontSide, near = 0, far = Infinity) {
|
|
54900
56500
|
const roots = this._roots;
|
|
54901
56501
|
const geometry = this.geometry;
|
|
54902
|
-
const
|
|
56502
|
+
const intersects2 = [];
|
|
54903
56503
|
const isMaterial = materialOrSide.isMaterial;
|
|
54904
56504
|
const isArrayMaterial = Array.isArray(materialOrSide);
|
|
54905
56505
|
const groups = geometry.groups;
|
|
@@ -54907,16 +56507,16 @@ class MeshBVH {
|
|
|
54907
56507
|
const raycastFunc = this.indirect ? raycast_indirect : raycast;
|
|
54908
56508
|
for (let i = 0, l = roots.length; i < l; i++) {
|
|
54909
56509
|
const materialSide = isArrayMaterial ? materialOrSide[groups[i].materialIndex].side : side;
|
|
54910
|
-
const startCount =
|
|
54911
|
-
raycastFunc(this, i, materialSide, ray2,
|
|
56510
|
+
const startCount = intersects2.length;
|
|
56511
|
+
raycastFunc(this, i, materialSide, ray2, intersects2, near, far);
|
|
54912
56512
|
if (isArrayMaterial) {
|
|
54913
56513
|
const materialIndex = groups[i].materialIndex;
|
|
54914
|
-
for (let j = startCount, jl =
|
|
54915
|
-
|
|
56514
|
+
for (let j = startCount, jl = intersects2.length; j < jl; j++) {
|
|
56515
|
+
intersects2[j].face.materialIndex = materialIndex;
|
|
54916
56516
|
}
|
|
54917
56517
|
}
|
|
54918
56518
|
}
|
|
54919
|
-
return
|
|
56519
|
+
return intersects2;
|
|
54920
56520
|
}
|
|
54921
56521
|
raycastFirst(ray2, materialOrSide = FrontSide, near = 0, far = Infinity) {
|
|
54922
56522
|
const roots = this._roots;
|
|
@@ -55115,14 +56715,14 @@ const origBatchedRaycastFunc = BatchedMesh.prototype.raycast;
|
|
|
55115
56715
|
const _worldScale = /* @__PURE__ */ new Vector3();
|
|
55116
56716
|
const _mesh = /* @__PURE__ */ new Mesh();
|
|
55117
56717
|
const _batchIntersects = [];
|
|
55118
|
-
function acceleratedRaycast(raycaster,
|
|
56718
|
+
function acceleratedRaycast(raycaster, intersects2) {
|
|
55119
56719
|
if (this.isBatchedMesh) {
|
|
55120
|
-
acceleratedBatchedMeshRaycast.call(this, raycaster,
|
|
56720
|
+
acceleratedBatchedMeshRaycast.call(this, raycaster, intersects2);
|
|
55121
56721
|
} else {
|
|
55122
|
-
acceleratedMeshRaycast.call(this, raycaster,
|
|
56722
|
+
acceleratedMeshRaycast.call(this, raycaster, intersects2);
|
|
55123
56723
|
}
|
|
55124
56724
|
}
|
|
55125
|
-
function acceleratedBatchedMeshRaycast(raycaster,
|
|
56725
|
+
function acceleratedBatchedMeshRaycast(raycaster, intersects2) {
|
|
55126
56726
|
if (this.boundsTrees) {
|
|
55127
56727
|
const boundsTrees = this.boundsTrees;
|
|
55128
56728
|
const drawInfo = this._drawInfo || this._instanceInfo;
|
|
@@ -55153,7 +56753,7 @@ function acceleratedBatchedMeshRaycast(raycaster, intersects) {
|
|
|
55153
56753
|
const intersect2 = _batchIntersects[j];
|
|
55154
56754
|
intersect2.object = this;
|
|
55155
56755
|
intersect2.batchId = i;
|
|
55156
|
-
|
|
56756
|
+
intersects2.push(intersect2);
|
|
55157
56757
|
}
|
|
55158
56758
|
_batchIntersects.length = 0;
|
|
55159
56759
|
}
|
|
@@ -55162,10 +56762,10 @@ function acceleratedBatchedMeshRaycast(raycaster, intersects) {
|
|
|
55162
56762
|
_mesh.material = null;
|
|
55163
56763
|
_mesh.geometry = null;
|
|
55164
56764
|
} else {
|
|
55165
|
-
origBatchedRaycastFunc.call(this, raycaster,
|
|
56765
|
+
origBatchedRaycastFunc.call(this, raycaster, intersects2);
|
|
55166
56766
|
}
|
|
55167
56767
|
}
|
|
55168
|
-
function acceleratedMeshRaycast(raycaster,
|
|
56768
|
+
function acceleratedMeshRaycast(raycaster, intersects2) {
|
|
55169
56769
|
if (this.geometry.boundsTree) {
|
|
55170
56770
|
if (this.material === void 0) return;
|
|
55171
56771
|
tmpInverseMatrix.copy(this.matrixWorld).invert();
|
|
@@ -55179,19 +56779,19 @@ function acceleratedMeshRaycast(raycaster, intersects) {
|
|
|
55179
56779
|
if (raycaster.firstHitOnly === true) {
|
|
55180
56780
|
const hit = convertRaycastIntersect(bvh.raycastFirst(ray, this.material, near, far), this, raycaster);
|
|
55181
56781
|
if (hit) {
|
|
55182
|
-
|
|
56782
|
+
intersects2.push(hit);
|
|
55183
56783
|
}
|
|
55184
56784
|
} else {
|
|
55185
56785
|
const hits = bvh.raycast(ray, this.material, near, far);
|
|
55186
56786
|
for (let i = 0, l = hits.length; i < l; i++) {
|
|
55187
56787
|
const hit = convertRaycastIntersect(hits[i], this, raycaster);
|
|
55188
56788
|
if (hit) {
|
|
55189
|
-
|
|
56789
|
+
intersects2.push(hit);
|
|
55190
56790
|
}
|
|
55191
56791
|
}
|
|
55192
56792
|
}
|
|
55193
56793
|
} else {
|
|
55194
|
-
origMeshRaycastFunc.call(this, raycaster,
|
|
56794
|
+
origMeshRaycastFunc.call(this, raycaster, intersects2);
|
|
55195
56795
|
}
|
|
55196
56796
|
}
|
|
55197
56797
|
function cloneGeometryForFaceColors$1(geometry) {
|
|
@@ -55248,13 +56848,13 @@ function firstOppositeSurfaceDistance(raycaster, rayTargetMeshes, point2, direct
|
|
|
55248
56848
|
}
|
|
55249
56849
|
return null;
|
|
55250
56850
|
}
|
|
55251
|
-
function triangleThickness(raycaster, rayTargetMeshes, centroid,
|
|
55252
|
-
const forward = firstOppositeSurfaceDistance(raycaster, rayTargetMeshes, centroid,
|
|
56851
|
+
function triangleThickness(raycaster, rayTargetMeshes, centroid, normal2, epsilon2, far, contactTolerance) {
|
|
56852
|
+
const forward = firstOppositeSurfaceDistance(raycaster, rayTargetMeshes, centroid, normal2, epsilon2, far, contactTolerance);
|
|
55253
56853
|
const backward = firstOppositeSurfaceDistance(
|
|
55254
56854
|
raycaster,
|
|
55255
56855
|
rayTargetMeshes,
|
|
55256
56856
|
centroid,
|
|
55257
|
-
|
|
56857
|
+
normal2.clone().negate(),
|
|
55258
56858
|
epsilon2,
|
|
55259
56859
|
far,
|
|
55260
56860
|
contactTolerance
|
|
@@ -55263,12 +56863,12 @@ function triangleThickness(raycaster, rayTargetMeshes, centroid, normal, epsilon
|
|
|
55263
56863
|
if (backward == null) return forward;
|
|
55264
56864
|
return Math.min(forward, backward);
|
|
55265
56865
|
}
|
|
55266
|
-
function measureThicknessAtPoint(context, point2,
|
|
56866
|
+
function measureThicknessAtPoint(context, point2, normal2) {
|
|
55267
56867
|
return triangleThickness(
|
|
55268
56868
|
context.raycaster,
|
|
55269
56869
|
context.rayTargetMeshes,
|
|
55270
56870
|
point2,
|
|
55271
|
-
|
|
56871
|
+
normal2,
|
|
55272
56872
|
context.epsilon,
|
|
55273
56873
|
context.far,
|
|
55274
56874
|
context.contactTolerance
|
|
@@ -55372,8 +56972,8 @@ function triangleMetrics(position, tri, a2, b, c2) {
|
|
|
55372
56972
|
const ab = b.distanceTo(a2);
|
|
55373
56973
|
const bc = c2.distanceTo(b);
|
|
55374
56974
|
const ca = a2.distanceTo(c2);
|
|
55375
|
-
const
|
|
55376
|
-
return { area, maxEdge: Math.max(ab, bc, ca) };
|
|
56975
|
+
const area2 = b.clone().sub(a2).cross(c2.clone().sub(a2)).length() * 0.5;
|
|
56976
|
+
return { area: area2, maxEdge: Math.max(ab, bc, ca) };
|
|
55377
56977
|
}
|
|
55378
56978
|
function buildTriangleInfos(position) {
|
|
55379
56979
|
const triangleCount = Math.floor(position.count / 3);
|
|
@@ -55399,16 +56999,16 @@ function buildTriangleInfos(position) {
|
|
|
55399
56999
|
const caLen = vc.distanceTo(va);
|
|
55400
57000
|
ab.subVectors(vb, va);
|
|
55401
57001
|
ac.subVectors(vc, va);
|
|
55402
|
-
const
|
|
55403
|
-
const
|
|
55404
|
-
|
|
57002
|
+
const normal2 = ab.clone().cross(ac);
|
|
57003
|
+
const area2 = normal2.length() * 0.5;
|
|
57004
|
+
normal2.normalize();
|
|
55405
57005
|
infos.push({
|
|
55406
57006
|
tri,
|
|
55407
57007
|
a: va,
|
|
55408
57008
|
b: vb,
|
|
55409
57009
|
c: vc,
|
|
55410
|
-
normal,
|
|
55411
|
-
area,
|
|
57010
|
+
normal: normal2,
|
|
57011
|
+
area: area2,
|
|
55412
57012
|
maxEdge: Math.max(abLen, bcLen, caLen)
|
|
55413
57013
|
});
|
|
55414
57014
|
}
|
|
@@ -55450,8 +57050,8 @@ function buildTriangleAdjacency(infos, tolerance) {
|
|
|
55450
57050
|
}
|
|
55451
57051
|
return adjacency.map((neighbors) => [...neighbors]);
|
|
55452
57052
|
}
|
|
55453
|
-
function triangleOnPlane(info, origin,
|
|
55454
|
-
return Math.abs(info.a.clone().sub(origin).dot(
|
|
57053
|
+
function triangleOnPlane(info, origin, normal2, tolerance) {
|
|
57054
|
+
return Math.abs(info.a.clone().sub(origin).dot(normal2)) <= tolerance && Math.abs(info.b.clone().sub(origin).dot(normal2)) <= tolerance && Math.abs(info.c.clone().sub(origin).dot(normal2)) <= tolerance;
|
|
55455
57055
|
}
|
|
55456
57056
|
function detectPlanarComponents(infos, tolerance) {
|
|
55457
57057
|
const adjacency = buildTriangleAdjacency(infos, tolerance);
|
|
@@ -55481,12 +57081,12 @@ function detectPlanarComponents(infos, tolerance) {
|
|
|
55481
57081
|
}
|
|
55482
57082
|
function planarBasis(component, infos) {
|
|
55483
57083
|
const origin = infos[component[0]].a.clone();
|
|
55484
|
-
const
|
|
57084
|
+
const normal2 = new Vector3();
|
|
55485
57085
|
let bestEdge = new Vector3(1, 0, 0);
|
|
55486
57086
|
let bestEdgeLength = 0;
|
|
55487
57087
|
for (const tri of component) {
|
|
55488
57088
|
const info = infos[tri];
|
|
55489
|
-
|
|
57089
|
+
normal2.addScaledVector(info.normal, info.area);
|
|
55490
57090
|
for (const [left, right] of [
|
|
55491
57091
|
[info.a, info.b],
|
|
55492
57092
|
[info.b, info.c],
|
|
@@ -55500,15 +57100,15 @@ function planarBasis(component, infos) {
|
|
|
55500
57100
|
}
|
|
55501
57101
|
}
|
|
55502
57102
|
}
|
|
55503
|
-
|
|
55504
|
-
const uAxis = bestEdge.sub(
|
|
57103
|
+
normal2.normalize();
|
|
57104
|
+
const uAxis = bestEdge.sub(normal2.clone().multiplyScalar(bestEdge.dot(normal2)));
|
|
55505
57105
|
if (uAxis.lengthSq() < 1e-12) {
|
|
55506
|
-
uAxis.copy(Math.abs(
|
|
55507
|
-
uAxis.sub(
|
|
57106
|
+
uAxis.copy(Math.abs(normal2.z) < 0.9 ? new Vector3(0, 0, 1) : new Vector3(1, 0, 0));
|
|
57107
|
+
uAxis.sub(normal2.clone().multiplyScalar(uAxis.dot(normal2)));
|
|
55508
57108
|
}
|
|
55509
57109
|
uAxis.normalize();
|
|
55510
|
-
const vAxis =
|
|
55511
|
-
return { origin, normal, uAxis, vAxis };
|
|
57110
|
+
const vAxis = normal2.clone().cross(uAxis).normalize();
|
|
57111
|
+
return { origin, normal: normal2, uAxis, vAxis };
|
|
55512
57112
|
}
|
|
55513
57113
|
function planarCoordinate(point2, patch) {
|
|
55514
57114
|
const relative = point2.clone().sub(patch.origin);
|
|
@@ -55840,7 +57440,7 @@ function buildMeasuredSurfaceScalarField(sourceGeometry, rawOptions, fieldOption
|
|
|
55840
57440
|
const aValue = new Float32Array(position.count);
|
|
55841
57441
|
const measurementContext = measurement.createContext(fieldGeometry, rawOptions, context);
|
|
55842
57442
|
const point2 = new Vector3();
|
|
55843
|
-
const
|
|
57443
|
+
const normal2 = new Vector3();
|
|
55844
57444
|
const ab = new Vector3();
|
|
55845
57445
|
const ac = new Vector3();
|
|
55846
57446
|
try {
|
|
@@ -55864,7 +57464,7 @@ function buildMeasuredSurfaceScalarField(sourceGeometry, rawOptions, fieldOption
|
|
|
55864
57464
|
}
|
|
55865
57465
|
ab.subVectors(b, a2);
|
|
55866
57466
|
ac.subVectors(c2, a2);
|
|
55867
|
-
|
|
57467
|
+
normal2.copy(ab).cross(ac).normalize();
|
|
55868
57468
|
uvs[tri * 6] = (patch.x + PATCH_GUTTER + 0.5) / width;
|
|
55869
57469
|
uvs[tri * 6 + 1] = (patch.y + PATCH_GUTTER + 0.5) / height;
|
|
55870
57470
|
uvs[tri * 6 + 2] = (patch.x + PATCH_GUTTER + patch.inner + 0.5) / width;
|
|
@@ -55875,7 +57475,7 @@ function buildMeasuredSurfaceScalarField(sourceGeometry, rawOptions, fieldOption
|
|
|
55875
57475
|
for (let px = 0; px < patch.side; px += 1) {
|
|
55876
57476
|
const [u2, v] = triangleParamForTexel(px, py, patch.inner);
|
|
55877
57477
|
point2.copy(a2).addScaledVector(ab, u2).addScaledVector(ac, v);
|
|
55878
|
-
const value = measurement.measureAtPoint(measurementContext, point2,
|
|
57478
|
+
const value = measurement.measureAtPoint(measurementContext, point2, normal2);
|
|
55879
57479
|
const texel = (patch.y + py) * width + patch.x + px;
|
|
55880
57480
|
if (value != null) values[texel] = value;
|
|
55881
57481
|
}
|
|
@@ -55987,16 +57587,16 @@ function boxDistanceToPointSq(box, point2) {
|
|
|
55987
57587
|
const z2 = point2.z < box.min.z ? box.min.z - point2.z : point2.z > box.max.z ? point2.z - box.max.z : 0;
|
|
55988
57588
|
return x2 * x2 + y2 * y2 + z2 * z2;
|
|
55989
57589
|
}
|
|
55990
|
-
function candidateTravelsThroughMaterial(context, point2,
|
|
57590
|
+
function candidateTravelsThroughMaterial(context, point2, normal2, candidate, candidateDistance) {
|
|
55991
57591
|
if (candidateDistance <= Math.max(context.epsilon, context.contactTolerance)) return false;
|
|
55992
57592
|
const direction2 = candidate.clone().sub(point2).multiplyScalar(1 / candidateDistance);
|
|
55993
|
-
if (direction2.dot(
|
|
57593
|
+
if (direction2.dot(normal2) >= -1e-5) return false;
|
|
55994
57594
|
const firstHit = firstRayHitDistance(context, point2, direction2);
|
|
55995
57595
|
if (firstHit == null) return false;
|
|
55996
57596
|
const tolerance = Math.max(context.contactTolerance, context.epsilon * 8);
|
|
55997
57597
|
return Math.abs(firstHit - candidateDistance) <= tolerance;
|
|
55998
57598
|
}
|
|
55999
|
-
function measureThroughThicknessAtPoint(context, point2,
|
|
57599
|
+
function measureThroughThicknessAtPoint(context, point2, normal2) {
|
|
56000
57600
|
let bestDistanceSq = Infinity;
|
|
56001
57601
|
const closest = new Vector3();
|
|
56002
57602
|
const candidate = new Vector3();
|
|
@@ -56009,7 +57609,7 @@ function measureThroughThicknessAtPoint(context, point2, normal) {
|
|
|
56009
57609
|
const distanceSq = candidate.distanceToSquared(point2);
|
|
56010
57610
|
if (distanceSq >= bestDistanceSq) return;
|
|
56011
57611
|
const distance = Math.sqrt(distanceSq);
|
|
56012
|
-
if (!candidateTravelsThroughMaterial(context, point2,
|
|
57612
|
+
if (!candidateTravelsThroughMaterial(context, point2, normal2, candidate, distance)) return;
|
|
56013
57613
|
bestDistanceSq = distanceSq;
|
|
56014
57614
|
closest.copy(candidate);
|
|
56015
57615
|
}
|
|
@@ -56272,10 +57872,10 @@ function vertexNormals(mesh) {
|
|
|
56272
57872
|
const b = mesh.tris[t + 1];
|
|
56273
57873
|
const c2 = mesh.tris[t + 2];
|
|
56274
57874
|
const n = triNormal(mesh.positions, a2, b, c2);
|
|
56275
|
-
const
|
|
56276
|
-
const nx = n[0] *
|
|
56277
|
-
const ny = n[1] *
|
|
56278
|
-
const nz = n[2] *
|
|
57875
|
+
const area2 = triArea(mesh.positions, a2, b, c2);
|
|
57876
|
+
const nx = n[0] * area2;
|
|
57877
|
+
const ny = n[1] * area2;
|
|
57878
|
+
const nz = n[2] * area2;
|
|
56279
57879
|
for (const vi of [a2, b, c2]) {
|
|
56280
57880
|
acc[vi * 3] += nx;
|
|
56281
57881
|
acc[vi * 3 + 1] += ny;
|
|
@@ -56508,9 +58108,9 @@ function reconstructSurfaceScalarField(trianglePositions, samples, options = {})
|
|
|
56508
58108
|
vertexCount
|
|
56509
58109
|
};
|
|
56510
58110
|
}
|
|
56511
|
-
const DEFAULT_COLORMAP = "
|
|
58111
|
+
const DEFAULT_COLORMAP = "inferno";
|
|
56512
58112
|
const DEFAULT_THICKNESS_COLOR_SCALE = {
|
|
56513
|
-
colormap: "
|
|
58113
|
+
colormap: "inferno",
|
|
56514
58114
|
domainMin: 0,
|
|
56515
58115
|
domainMax: 6,
|
|
56516
58116
|
reversed: true
|
|
@@ -56878,17 +58478,17 @@ class FrozenShapeBackend {
|
|
|
56878
58478
|
scale(v) {
|
|
56879
58479
|
return this.getReconstructedBackend().scale(v);
|
|
56880
58480
|
}
|
|
56881
|
-
mirror(
|
|
56882
|
-
return this.getReconstructedBackend().mirror(
|
|
58481
|
+
mirror(normal2) {
|
|
58482
|
+
return this.getReconstructedBackend().mirror(normal2);
|
|
56883
58483
|
}
|
|
56884
58484
|
split(other) {
|
|
56885
58485
|
return this.getReconstructedBackend().split(other);
|
|
56886
58486
|
}
|
|
56887
|
-
splitByPlane(
|
|
56888
|
-
return this.getReconstructedBackend().splitByPlane(
|
|
58487
|
+
splitByPlane(normal2, originOffset) {
|
|
58488
|
+
return this.getReconstructedBackend().splitByPlane(normal2, originOffset);
|
|
56889
58489
|
}
|
|
56890
|
-
trimByPlane(
|
|
56891
|
-
return this.getReconstructedBackend().trimByPlane(
|
|
58490
|
+
trimByPlane(normal2, originOffset) {
|
|
58491
|
+
return this.getReconstructedBackend().trimByPlane(normal2, originOffset);
|
|
56892
58492
|
}
|
|
56893
58493
|
volume() {
|
|
56894
58494
|
return this.getReconstructedBackend().volume();
|