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.
Files changed (104) hide show
  1. package/dist/assets/{AdminPage-raksfnNA.js → AdminPage-B1nIvqLS.js} +1 -1
  2. package/dist/assets/{BenchmarkPage-DP3RxhPs.js → BenchmarkPage-YZJbw5nd.js} +1 -1
  3. package/dist/assets/{BlogPage-D7Dos-vl.js → BlogPage-DIWRApKS.js} +1 -1
  4. package/dist/assets/{DocsPage-DO1kvBns.js → DocsPage-ClL6X1hR.js} +2 -22
  5. package/dist/assets/{EditorApp-DQJmcmRT.js → EditorApp-CYBDvSyT.js} +575 -119
  6. package/dist/assets/{EmbedViewer-DFDUhOma.js → EmbedViewer-Dmfu_LIw.js} +2 -2
  7. package/dist/assets/{LandingPageProofDriven-DbE_tp8-.js → LandingPageProofDriven-XYTiYxfM.js} +1 -1
  8. package/dist/assets/{LegalPage-CominSso.js → LegalPage-D5Z3CscF.js} +1 -1
  9. package/dist/assets/{PricingPage-CcVIN9yj.js → PricingPage-BP4lIGio.js} +1 -1
  10. package/dist/assets/{SettingsPage-DLWcP289.js → SettingsPage-D3bcPBsC.js} +1 -1
  11. package/dist/assets/{app-xW3hOdq9.js → app-BKjogwIZ.js} +2192 -231
  12. package/dist/assets/{backendInit-mDHk97u7.js → backendInit-6a9-ilom.js} +76448 -75066
  13. package/dist/assets/cli/{render--SIU27W_.js → render-CMNudGb0.js} +3 -3
  14. package/dist/assets/{constructionHistoryWorker-uEe_Q7Kg.js → constructionHistoryWorker-BuZgc606.js} +6985 -6706
  15. package/dist/assets/{evalWorker-BqyDHDcI.js → evalWorker-DQ82ueGu.js} +40862 -39497
  16. package/dist/assets/{inspectWorker-UXMxlcR8.js → inspectWorker-Cuby2qfT.js} +2078 -478
  17. package/dist/assets/{jointPose-bYMlwU3v.js → jointPose-CFql5I-u.js} +1 -1
  18. package/dist/assets/{manifold-CyOV5B9S.js → manifold-02pmr7O7.js} +2 -2
  19. package/dist/assets/{manifold-BR7UYI4P.js → manifold-C6KU0oII.js} +1 -1
  20. package/dist/assets/{manifold-D4d5NQst.js → manifold-P1yF3GKn.js} +1 -1
  21. package/dist/assets/{reportWorker-DsaICZsn.js → reportWorker-kg065BVL.js} +85183 -78309
  22. package/dist/cli/render.html +1 -1
  23. package/dist/docs/index.html +2 -2
  24. package/dist/docs-raw/AI/usage.md +6 -8
  25. package/dist/docs-raw/CLI.md +10 -10
  26. package/dist/docs-raw/component-model.md +28 -9
  27. package/dist/docs-raw/generated/concepts.md +13 -4
  28. package/dist/docs-raw/generated/core.md +244 -56
  29. package/dist/docs-raw/generated/curves.md +13 -0
  30. package/dist/docs-raw/generated/runtime-names.md +2 -2
  31. package/dist/docs-raw/guides/inspection-bundles.md +1 -1
  32. package/dist/docs-raw/guides/structural-fea.md +11 -0
  33. package/dist/docs-raw/skills/forgecad-build-model.md +70 -147
  34. package/dist/docs-raw/skills/forgecad-image-prompt.md +1 -1
  35. package/dist/docs-raw/skills/forgecad-project-sync.md +3 -3
  36. package/dist/docs-raw/skills/forgecad-reconstruct-cad-file.md +2 -2
  37. package/dist/docs-raw/skills/forgecad-reconstruct-from-images.md +4 -5
  38. package/dist/docs-raw/skills/forgecad.md +3 -1
  39. package/dist/docs-raw/skills/index.md +1 -5
  40. package/dist/docs-raw/welcome.md +3 -4
  41. package/dist/index.html +1 -1
  42. package/dist/llms.txt +1 -2
  43. package/dist/sitemap.xml +15 -15
  44. package/dist-cli/{check-compiler-7YAHVXYM.js → check-compiler-UJWUEIDC.js} +1 -1
  45. package/dist-cli/{check-query-propagation-ZRR6IOJW.js → check-query-propagation-O2EPDJSY.js} +1 -1
  46. package/dist-cli/{chunk-VNM67DIV.js → chunk-MNDROM7T.js} +77145 -75767
  47. package/dist-cli/forgecad.js +1145 -441
  48. package/dist-skill/CONTEXT.md +429 -64
  49. package/dist-skill/SKILL.md +3 -1
  50. package/dist-skill/docs/API/core/concepts.md +31 -4
  51. package/dist-skill/docs/CLI.md +10 -10
  52. package/dist-skill/docs/generated/core.md +240 -57
  53. package/dist-skill/docs/generated/curves.md +13 -0
  54. package/dist-skill/docs/generated/runtime-names.md +2 -2
  55. package/dist-skill/docs/guides/inspection-bundles.md +1 -1
  56. package/dist-skill/docs/guides/manual-parameters.md +130 -0
  57. package/dist-skill/docs/guides/structural-fea.md +11 -0
  58. package/dist-skill/library/README.md +0 -4
  59. package/dist-skill/library/forgecad-build-model/SKILL.md +57 -150
  60. package/dist-skill/library/forgecad-build-model/references/inspection-feedback.md +58 -0
  61. package/dist-skill/library/forgecad-build-model/references/module-contracts.md +53 -0
  62. package/dist-skill/library/forgecad-build-model/references/parameter-controls.md +22 -0
  63. package/dist-skill/library/forgecad-build-model/references/readiness-review.md +43 -0
  64. package/dist-skill/library/forgecad-build-model/references/simulation-feedback.md +49 -0
  65. package/dist-skill/library/forgecad-build-model/references/stage-1-design-intent.md +21 -0
  66. package/dist-skill/library/forgecad-build-model/references/stage-2-architecture-plan.md +23 -0
  67. package/dist-skill/library/forgecad-build-model/references/stage-3-build-slices.md +39 -0
  68. package/dist-skill/library/forgecad-build-model/references/stage-4-feedback-iteration.md +24 -0
  69. package/dist-skill/library/forgecad-build-model/references/stage-5-readiness-package.md +34 -0
  70. package/dist-skill/library/forgecad-image-prompt/SKILL.md +1 -1
  71. package/dist-skill/library/forgecad-project-sync/SKILL.md +3 -3
  72. package/dist-skill/library/forgecad-reconstruct-cad-file/SKILL.md +2 -2
  73. package/dist-skill/library/forgecad-reconstruct-from-images/SKILL.md +4 -5
  74. package/dist-skill/website/skills/forgecad-build-model.md +70 -147
  75. package/dist-skill/website/skills/forgecad-image-prompt.md +1 -1
  76. package/dist-skill/website/skills/forgecad-project-sync.md +3 -3
  77. package/dist-skill/website/skills/forgecad-reconstruct-cad-file.md +2 -2
  78. package/dist-skill/website/skills/forgecad-reconstruct-from-images.md +4 -5
  79. package/dist-skill/website/skills/forgecad.md +3 -1
  80. package/dist-skill/website/skills/index.md +1 -5
  81. package/examples/api/param-path2d.forge.js +65 -0
  82. package/examples/api/param-placement2d.forge.js +80 -0
  83. package/examples/api/param-spline2d-g-continuity.forge.js +57 -0
  84. package/examples/api/spoon-full-tang-handle.forge.js +57 -17
  85. package/examples/api/surface-variable-thickness-panel.forge.js +62 -0
  86. package/examples/mechanical/airplane-propeller.forge.js +81 -28
  87. package/package.json +2 -2
  88. package/dist/docs-raw/skills/forgecad-design-spec.md +0 -145
  89. package/dist/docs-raw/skills/forgecad-grade-model.md +0 -84
  90. package/dist/docs-raw/skills/forgecad-inspect-model.md +0 -80
  91. package/dist/docs-raw/skills/forgecad-verify-mujoco.md +0 -78
  92. package/dist-skill/library/forgecad-design-spec/SKILL.md +0 -132
  93. package/dist-skill/library/forgecad-design-spec/references/default-profiles.md +0 -99
  94. package/dist-skill/library/forgecad-design-spec/references/master-prompt.md +0 -73
  95. package/dist-skill/library/forgecad-grade-model/SKILL.md +0 -72
  96. package/dist-skill/library/forgecad-grade-model/agents/openai.yaml +0 -4
  97. package/dist-skill/library/forgecad-inspect-model/SKILL.md +0 -68
  98. package/dist-skill/library/forgecad-verify-mujoco/SKILL.md +0 -66
  99. package/dist-skill/website/skills/forgecad-design-spec.md +0 -145
  100. package/dist-skill/website/skills/forgecad-grade-model.md +0 -84
  101. package/dist-skill/website/skills/forgecad-inspect-model.md +0 -80
  102. package/dist-skill/website/skills/forgecad-verify-mujoco.md +0 -78
  103. /package/dist-skill/library/{forgecad-verify-mujoco → forgecad-build-model}/scripts/mujoco_verify.py +0 -0
  104. /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(normal) {
4153
- return this.sub(_vector$c.copy(normal).multiplyScalar(2 * this.dot(normal)));
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 sign;
5495
+ let sign2;
5496
5496
  if (DdN > 0) {
5497
5497
  if (backfaceCulling) return null;
5498
- sign = 1;
5498
+ sign2 = 1;
5499
5499
  } else if (DdN < 0) {
5500
- sign = -1;
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 = sign * this.direction.dot(_edge2.crossVectors(_diff, _edge2));
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 = sign * this.direction.dot(_edge1.cross(_diff));
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 = -sign * _diff.dot(_normal$1);
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 normal = this.attributes.normal;
10120
- if (normal !== void 0) {
10119
+ const normal2 = this.attributes.normal;
10120
+ if (normal2 !== void 0) {
10121
10121
  const normalMatrix = new Matrix3().getNormalMatrix(matrix);
10122
- normal.applyNormalMatrix(normalMatrix);
10123
- normal.needsUpdate = true;
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, intersects) {
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, intersects, _ray$3);
10854
+ this._computeIntersections(raycaster, intersects2, _ray$3);
10855
10855
  }
10856
- _computeIntersections(raycaster, intersects, rayLocalSpace) {
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 normal = geometry.attributes.normal;
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, normal, a2, b, c2);
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
- intersects.push(intersection2);
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, normal, a2, b, c2);
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
- intersects.push(intersection2);
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, normal, a2, b, c2);
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
- intersects.push(intersection2);
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, normal, a2, b, c2);
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
- intersects.push(intersection2);
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, normal, a2, b, c2) {
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 (normal) {
10969
- intersection2.normal = Triangle.getInterpolatedAttribute(normal, a2, b, c2, barycoord, new Vector3());
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(normal = new Vector3(1, 0, 0), constant = 0) {
11023
+ constructor(normal2 = new Vector3(1, 0, 0), constant = 0) {
11024
11024
  this.isPlane = true;
11025
- this.normal = 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(normal, constant) {
11036
- this.normal.copy(normal);
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(normal, point2) {
11064
- this.normal.copy(normal);
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 normal = _vector1.subVectors(c2, b).cross(_vector2.subVectors(a2, b)).normalize();
11080
- this.setFromNormalAndCoplanarPoint(normal, a2);
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 normal = this.normal.applyMatrix3(normalMatrix).normalize();
11222
- this.constant = -referencePoint.dot(normal);
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, intersects) {
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
- intersects.push(intersect2);
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, intersects = []) {
12493
- intersect(object, this, intersects, recursive);
12494
- intersects.sort(ascSort);
12495
- return intersects;
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, intersects = []) {
13003
+ intersectObjects(objects, recursive = true, intersects2 = []) {
12508
13004
  for (let i = 0, l = objects.length; i < l; i++) {
12509
- intersect(objects[i], this, intersects, recursive);
13005
+ intersect(objects[i], this, intersects2, recursive);
12510
13006
  }
12511
- intersects.sort(ascSort);
12512
- return intersects;
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, intersects, recursive) {
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, intersects);
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, intersects, true);
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$3 = 1e-9;
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$3 ? 0 : angleDeg;
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$3) {
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$3)) {
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, normal) {
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: [normal[0], normal[1], normal[2]],
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$3 && Math.abs(y2) <= EPS$3 && Math.abs(z2) <= EPS$3) return cloneShapeCompilePlan(plan);
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, normal) {
13273
- const placement = transformPlacement(origin, u2, v, normal);
13274
- const matrix = [u2[0], u2[1], u2[2], 0, v[0], v[1], v[2], 0, normal[0], normal[1], normal[2], 0, origin[0], origin[1], origin[2], 1];
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, normal, planar, uAxis, vAxis, semantic = "face", memberNames = [name], coplanar = planar) {
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(normal),
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$2 = 1e-10;
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$2 || toLen < EPS$2) return 0;
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$2) {
13812
- if (mode === "line" && targetRadialLen >= EPS$2) {
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$2) {
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$2) {
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$2) throw new Error("Axis must be non-zero");
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$2) throw new Error("Transform matrix is not invertible");
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, normal, originOffset) {
15203
- const len2 = Math.sqrt(normal[0] * normal[0] + normal[1] * normal[1] + normal[2] * normal[2]);
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 = normal[0] / len2;
15206
- const ny = normal[1] / len2;
15207
- const nz = normal[2] / len2;
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 area = 0;
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
- area += x1 * y2 - x2 * y1;
18131
+ area2 += x1 * y2 - x2 * y1;
17607
18132
  }
17608
- return area * 0.5;
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 intersects = yi > py !== yj > py && px < (xj - xi) * (py - yi) / (yj - yi + 1e-20) + xi;
17617
- if (intersects) inside = !inside;
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 area = 0;
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
- area += x1 * y2 - x2 * y1;
19118
+ area2 += x1 * y2 - x2 * y1;
18594
19119
  }
18595
- return area * 0.5;
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 area = 0;
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
- area += x1 * y2 - x2 * y1;
20522
+ area2 += x1 * y2 - x2 * y1;
19982
20523
  }
19983
- return area * 0.5;
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 area = 0;
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
- area += current[0] * next[1] - next[0] * current[1];
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, normal) {
21252
+ function transformNormal(matrix, normal2) {
20674
21253
  const inverse = inverseMat4(matrix);
20675
21254
  return normalize3$2(
20676
21255
  [
20677
- inverse[0] * normal[0] + inverse[1] * normal[1] + inverse[2] * normal[2],
20678
- inverse[4] * normal[0] + inverse[5] * normal[1] + inverse[6] * normal[2],
20679
- inverse[8] * normal[0] + inverse[9] * normal[1] + inverse[10] * normal[2]
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 normal = transformNormal(matrix, [vertProperties[offset + 3], vertProperties[offset + 4], vertProperties[offset + 5]]);
20695
- vertProperties[offset + 3] = normal[0];
20696
- vertProperties[offset + 4] = normal[1];
20697
- vertProperties[offset + 5] = normal[2];
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 normal = [ab[1] * ac[2] - ab[2] * ac[1], ab[2] * ac[0] - ab[0] * ac[2], ab[0] * ac[1] - ab[1] * ac[0]];
20813
- const normalLenSq = Math.max(dot3$4(normal, normal), 1e-20);
20814
- const signed = dot3$4(ap, normal);
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$1 = 1e-8;
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$1) throw new Error("Edge feature selection requires a non-zero direction vector");
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$1) return Transform.identity();
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$1)) return false;
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
- normal[0],
22796
+ normal2[0],
22205
22797
  0,
22206
22798
  u2[1],
22207
22799
  v[1],
22208
- normal[1],
22800
+ normal2[1],
22209
22801
  0,
22210
22802
  u2[2],
22211
22803
  v[2],
22212
- normal[2],
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(-(normal[0] * origin[0] + normal[1] * origin[1] + normal[2] * origin[2])),
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 area = signedArea$3(loop);
22618
- if (area >= 0) {
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 area = 0;
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
- area += p1[0] * p2[1] - p2[0] * p1[1];
23264
+ area2 += p1[0] * p2[1] - p2[0] * p1[1];
22673
23265
  }
22674
- return area * 0.5;
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$1(b, a2), sub3$1(d2, a2));
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$1(sub3$1(stations[1][j], stations[0][j]), 1 / (t[1] - t[0]));
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$1(sub3$1(stations[R - 1][j], stations[R - 2][j]), 1 / (t[R - 1] - t[R - 2]));
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$1(sub3$1(stations[i][j], stations[i - 1][j]), 1 / hPrev);
23055
- const dNext = scale3$1(sub3$1(stations[i + 1][j], stations[i][j]), 1 / hNext);
23056
- return scale3$1(add3$1(scale3$1(dPrev, hNext), scale3$1(dNext, hPrev)), 1 / (hPrev + hNext));
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 area = signedArea$3(loop);
23084
- return area < 0 ? [...loop].reverse() : loop;
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$1(next, curr), tangents[j]);
23112
- const nBwd = surfaceNormal(sub3$1(curr, prev), tangents[j]);
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$1(next, prev), tangents[j]));
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 area = signedArea$3(loop);
23170
- return area < 0 ? [...loop].reverse() : loop;
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$1(next, curr), tangents[j]);
23200
- const nBwd = surfaceNormal(sub3$1(curr, prev), tangents[j]);
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$1(next, prev), tangents[j]));
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$1(frames[0].normal, -1);
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$1(a2, b) {
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$1(a2, b) {
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$1(a2, s) {
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(normal) {
23342
- return new _ManifoldShapeBackend(this.getLiveManifold("mirror()").mirror(normal));
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(normal, originOffset) {
23349
- const [inside, outside] = this.getLiveManifold("splitByPlane()").splitByPlane(normal, originOffset);
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(normal, originOffset) {
23353
- return new _ManifoldShapeBackend(this.getLiveManifold("trimByPlane()").trimByPlane(normal, originOffset));
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 area = 0;
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
- area += p1[0] * p2[1] - p2[0] * p1[1];
24234
+ area2 += p1[0] * p2[1] - p2[0] * p1[1];
23643
24235
  }
23644
- return area * 0.5;
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 normal = normalizeVec3$1(normalInput, "Shape.fromSlices group normal");
23999
- const [nx, ny, nz] = normal;
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, normal), "Shape.fromSlices profile u axis");
24011
- return { u: u2, v: cross3$4(normal, u2), normal };
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(normal) {
24014
- const frame = fromSlicesPlaneFrameForManifold(normal);
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, normal) {
24018
- const matrix = fromSlicesLocalToWorldMatrixForManifold(normal);
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 area = 0;
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
- area += current[0] * next[1] - next[0] * current[1];
24769
+ area2 += current[0] * next[1] - next[0] * current[1];
24157
24770
  }
24158
- return area * 0.5;
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(normal) {
24351
- const [nx, ny, nz] = normal;
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 sign = convex ? -1 : 1;
24788
- const quadrant = [projX >= 0 ? sign : -sign, projY >= 0 ? sign : -sign];
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 area = 0;
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
- area += a2[0] * b[1] - b[0] * a2[1];
25930
+ area2 += a2[0] * b[1] - b[0] * a2[1];
25312
25931
  }
25313
- if (Math.abs(area) <= 1e-12) throw new Error(`${context}: trim loop area is too small`);
25314
- if (area < 0) deduped.reverse();
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 normal = tri.Normal_1(i);
25457
- const transformedNormal = normal.Transformed(trsf);
25458
- const sign = reversed ? -1 : 1;
25459
- allNormals.push(transformedNormal.X() * sign, transformedNormal.Y() * sign, transformedNormal.Z() * sign);
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(normal) {
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(normal[0], normal[1], normal[2]));
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(normal, originOffset) {
26322
+ splitByPlane(normal2, originOffset) {
25704
26323
  const oc = getOCCT();
25705
- const dir = new oc.gp_Dir_4(normal[0], normal[1], normal[2]);
25706
- const pln = new oc.gp_Pln_3(new oc.gp_Pnt_3(normal[0] * originOffset, normal[1] * originOffset, normal[2] * originOffset), dir);
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(normal[0] * (originOffset + 1), normal[1] * (originOffset + 1), normal[2] * (originOffset + 1))
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(normal, originOffset) {
25718
- const [inside] = this.splitByPlane(normal, originOffset);
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 area = 0;
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
- area += 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;
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 area;
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 area = 0;
31612
+ var area2 = 0;
30994
31613
  for (var i = 0; i < poly.length; i++) {
30995
- area += ClipperLib2.Clipper.Area(poly[i]);
31614
+ area2 += ClipperLib2.Clipper.Area(poly[i]);
30996
31615
  }
30997
- return area / (scale2 * scale2);
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 area = signedArea2$1(loop);
33086
- return ccw && area < 0 || !ccw && area > 0 ? [...loop].reverse() : loop.map(([x2, y2]) => [x2, y2]);
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(normal) {
33518
- const n = normalize3$2(normal, "SDF mirror() normal");
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(normal) {
33627
- return this.transform(mirrorMatrix$2(normal));
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(normal, originOffset) {
33650
- return [this.trimByPlane(normal, originOffset), this.trimByPlane([-normal[0], -normal[1], -normal[2]], -originOffset)];
34268
+ splitByPlane(normal2, originOffset) {
34269
+ return [this.trimByPlane(normal2, originOffset), this.trimByPlane([-normal2[0], -normal2[1], -normal2[2]], -originOffset)];
33651
34270
  }
33652
- trimByPlane(normal, originOffset) {
33653
- const n = normalize3$2(normal, "SDF trimByPlane() normal");
33654
- const offset = originOffset / Math.hypot(normal[0], normal[1], normal[2]);
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 normal = transformSurfaceAxis(tx, surface.normal);
34421
- return normal ? { kind: "plane", normal } : void 0;
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 area = 0;
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
- area += x0 * y1 - x1 * y0;
35260
+ area2 += x0 * y1 - x1 * y0;
34556
35261
  }
34557
- return area / 2;
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 area = signedArea$1(points);
34576
- if (ccw && area < 0 || !ccw && area > 0) return [...points].reverse();
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(normal) {
35119
- const seed = Math.abs(normal[2]) < 0.9 ? [0, 0, 1] : [0, 1, 0];
35120
- const uAxis = normalizeVec3(cross$2(seed, normal));
35121
- const vAxis = normalizeVec3(cross$2(normal, uAxis));
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, normal, originOffset) {
35125
- const normalLength = Math.hypot(normal[0], normal[1], normal[2]);
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 = [normal[0] / normalLength, normal[1] / normalLength, normal[2] / normalLength];
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 area = 0;
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
- area += x0 * y1 - x1 * y0;
35939
+ area2 += x0 * y1 - x1 * y0;
35235
35940
  }
35236
- return area / 2;
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(normal) {
35478
- const [nx0, ny0, nz0] = normal;
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(normal, originOffset) {
35516
- return [this.trimByPlane(normal, originOffset), this.trimByPlane([-normal[0], -normal[1], -normal[2]], -originOffset)];
36220
+ splitByPlane(normal2, originOffset) {
36221
+ return [this.trimByPlane(normal2, originOffset), this.trimByPlane([-normal2[0], -normal2[1], -normal2[2]], -originOffset)];
35517
36222
  }
35518
- trimByPlane(normal, originOffset) {
36223
+ trimByPlane(normal2, originOffset) {
35519
36224
  const wasm = getTruckGeometryWasm();
35520
36225
  const bounds = this.boundingBox();
35521
- const normalLength = Math.hypot(normal[0], normal[1], normal[2]);
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 = [normal[0] / normalLength, normal[1] / normalLength, normal[2] / normalLength];
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, normal, originOffset);
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 area = signedArea(points);
35742
- if (ccw && area < 0 || !ccw && area > 0) {
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 area = 0;
36589
+ let area2 = 0;
35885
36590
  for (let i = 0; i < points.length; i++) {
35886
36591
  const next = (i + 1) % points.length;
35887
- area += points[i][0] * points[next][1] - points[next][0] * points[i][1];
36592
+ area2 += points[i][0] * points[next][1] - points[next][0] * points[i][1];
35888
36593
  }
35889
- return area / 2;
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, normal) {
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
- normal[0],
36100
- normal[1],
36101
- normal[2],
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, normal) {
36231
- const normalLengthSq = normal[0] * normal[0] + normal[1] * normal[1];
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] * normal[0] + point2[1] * normal[1]) / normalLengthSq;
36234
- return [point2[0] - signedDistanceScale * normal[0], point2[1] - signedDistanceScale * normal[1]];
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, normal) {
36941
+ function mirrorRegionAcrossVerticalPlane(region, normal2) {
36237
36942
  const mirrorLoop = (loop) => {
36238
- const mirrored = loop.map((point2) => mirrorPointAcrossLineNormal(point2, normal));
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 normal = [step.normalX, step.normalY];
36313
- const regions = prism.regions.map((region) => mirrorRegionAcrossVerticalPlane(region, normal));
36314
- const topRegions = (_d2 = prism.topRegions) == null ? void 0 : _d2.map((region) => mirrorRegionAcrossVerticalPlane(region, normal));
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 bilinear = [
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] - bilinear[0],
38061
- (1 - v) * bottomPoint[1] + v * topPoint[1] + (1 - u2) * leftPoint[1] + u2 * rightPoint[1] - bilinear[1],
38062
- (1 - v) * bottomPoint[2] + v * topPoint[2] + (1 - u2) * leftPoint[2] + u2 * rightPoint[2] - bilinear[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 normal = cross3$3(ab, ac);
38222
- const len2 = Math.hypot(normal[0], normal[1], normal[2]);
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 [normal[0] / len2, normal[1] / len2, normal[2] / len2];
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 normal = triangleNormal(mesh.vertices, triangle3);
38239
- if (!normal) return null;
38943
+ const normal2 = triangleNormal(mesh.vertices, triangle3);
38944
+ if (!normal2) return null;
38240
38945
  for (const vertexIndex of triangle3) {
38241
- normals[vertexIndex][0] += normal[0];
38242
- normals[vertexIndex][1] += normal[1];
38243
- normals[vertexIndex][2] += normal[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 normal = normals[index2];
38248
- const len2 = Math.hypot(normal[0], normal[1], normal[2]);
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] - normal[0] / len2 * thickness,
38252
- vertex2[1] - normal[1] / len2 * thickness,
38253
- vertex2[2] - normal[2] / len2 * thickness
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 normal = normalizedVector3(normalInput, "Shape.fromSlices group normal");
38376
- const [nx, ny, nz] = normal;
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, normal), "Shape.fromSlices profile u axis");
38388
- return { u: u2, v: cross3$3(normal, u2), normal };
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(normal) {
38391
- const frame = fromSlicesPlaneFrame(normal);
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, normal) {
38434
- const matrix = fromSlicesLocalToWorldMatrix(normal);
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 area = signedArea(points);
38626
- if (ccw && area < 0 || !ccw && area > 0) return [...points].reverse();
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(normal) {
38677
- const unit = normalizeVec3OrNull(normal);
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(normal) {
42186
- const ref = Math.abs(normal[0]) < 0.9 ? [1, 0, 0] : [0, 1, 0];
42187
- const v = normVec3(cross$1(normal, ref));
42188
- const u2 = normVec3(cross$1(v, normal));
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 normal = normVec3(rawCross);
42209
- if (!normal) continue;
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(normal, v0);
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, normal) > NORMAL_COS_EPS$1 && Math.abs(c2.planeOffset - planeOffset) < PLANE_OFFSET_EPS$1) {
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 normal = normalizeAxis(face.normal);
42403
- const alignment = Math.abs(firstNormal[0] * normal[0] + firstNormal[1] * normal[1] + firstNormal[2] * normal[2]);
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(normal) {
42547
- const len2 = Math.hypot(normal[0], normal[1], normal[2]);
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 = normal[0] / len2;
42550
- const ny = normal[1] / len2;
42551
- const nz = normal[2] / len2;
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(normal) {
42622
- const n = normalizeAxis(normal);
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 normal = normalizeAxis(cross3$2(edgeVec, depthVec));
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 normal = normalizeAxis([plan.normalX, plan.normalY, plan.normalZ]);
43655
- const planeDistance = averageCenter[0] * normal[0] + averageCenter[1] * normal[1] + averageCenter[2] * normal[2] - plan.originOffset;
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] - normal[0] * planeDistance,
43658
- averageCenter[1] - normal[1] * planeDistance,
43659
- averageCenter[2] - normal[2] * planeDistance
44368
+ averageCenter[0] - normal2[0] * planeDistance,
44369
+ averageCenter[1] - normal2[1] * planeDistance,
44370
+ averageCenter[2] - normal2[2] * planeDistance
43660
44371
  ];
43661
- const basis = orthonormalBasisFromNormal(normal);
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 area = twoArea * 0.5;
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 += area;
44432
- a2.cx += (ax + bx + cx) / 3 * area;
44433
- a2.cy += (ay + by + cy) / 3 * area;
44434
- a2.cz += (az + bz + cz) / 3 * area;
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 normal = nlen > 1e-9 ? [a2.nx / nlen, a2.ny / nlen, a2.nz / nlen] : a2.facetNormal ?? [0, 0, 1];
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(normal) {
45281
- const [nx0, ny0, nz0] = normal;
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(normal) {
45585
- return this.mirrorThrough(this._bboxCenter(), normal);
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, normal) {
46299
+ mirrorThrough(point2, normal2) {
45589
46300
  const mirrorPoint = requireFiniteVec3$1(point2, "ShapeGroup.mirrorThrough() point");
45590
- const mirrorNormal = requireNonZeroFiniteVec3(normal, "ShapeGroup.mirrorThrough() normal");
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 normal = [nx, ny, nz];
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, normal) > NORMAL_COS_EPS && Math.abs(cl.planeOffset - planeOffset) < PLANE_OFFSET_EPS) {
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(normal) {
47442
- const [nx0, ny0, nz0] = normal;
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(normal) {
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, normal);
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, normal) {
49882
+ mirrorThrough(point2, normal2) {
49066
49883
  const mirrorPoint = requireFiniteVec3$1(point2, "Shape.mirrorThrough() point");
49067
- const mirrorNormal = requireNonZeroFiniteVec3(normal, "Shape.mirrorThrough() normal");
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(normal, originOffset = 0) {
49324
- const planeNormal = requireNonZeroFiniteVec3(normal, "Shape.splitByPlane() normal");
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(normal, originOffset = 0) {
49354
- const planeNormal = requireNonZeroFiniteVec3(normal, "Shape.trimByPlane() normal");
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 wallThickness = requireFiniteNumber(thickness, "Shape.thicken() thickness");
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 representation = info.backend === "occt" || info.backend === "truck" ? "brep-solid" : "mesh-solid";
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", { representation, topology: info.backend === "truck" ? "kernel" : "none" })
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 area = Number.isFinite(tri.area) ? tri.area : 0;
51310
- totalArea += area;
51311
- areaByClass[roughnessClassForAngle(tri.maxAngleDeg, options)] += area;
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 normal = new Vector3();
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
- normal.subVectors(b, a2).cross(ac.subVectors(c2, a2));
51450
- const areaTwice = normal.length();
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: normal.clone().multiplyScalar(1 / areaTwice),
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 normal = new Vector3();
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
- normal.subVectors(b, a2).cross(ac.subVectors(c2, a2));
51590
- const areaTwice = normal.length();
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 ? normal.multiplyScalar(1 / areaTwice).clone() : new Vector3(0, 0, 1);
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, normal, uv, uv1, a2, b, c2, side, near, far) {
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 (normal) {
53542
- _normalA.fromBufferAttribute(normal, a2);
53543
- _normalB.fromBufferAttribute(normal, b);
53544
- _normalC.fromBufferAttribute(normal, c2);
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, normal, uv, uv1, a2, b, c2, side, near, far);
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, intersects, near, far) {
55418
+ function raycast(bvh, root, side, ray2, intersects2, near, far) {
53819
55419
  BufferStack.setBuffer(bvh._roots[root]);
53820
- _raycast$1(0, bvh, side, ray2, intersects, near, far);
55420
+ _raycast$1(0, bvh, side, ray2, intersects2, near, far);
53821
55421
  BufferStack.clearBuffer();
53822
55422
  }
53823
- function _raycast$1(nodeIndex32, bvh, side, ray2, intersects, near, far) {
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, intersects, near, far);
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, intersects, near, far);
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, intersects, near, far);
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, intersects, near, far) {
55812
+ function raycast_indirect(bvh, root, side, ray2, intersects2, near, far) {
54213
55813
  BufferStack.setBuffer(bvh._roots[root]);
54214
- _raycast(0, bvh, side, ray2, intersects, near, far);
55814
+ _raycast(0, bvh, side, ray2, intersects2, near, far);
54215
55815
  BufferStack.clearBuffer();
54216
55816
  }
54217
- function _raycast(nodeIndex32, bvh, side, ray2, intersects, near, far) {
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, intersects, near, far);
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, intersects, near, far);
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, intersects, near, far);
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 intersects = [];
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 = intersects.length;
54911
- raycastFunc(this, i, materialSide, ray2, intersects, near, far);
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 = intersects.length; j < jl; j++) {
54915
- intersects[j].face.materialIndex = materialIndex;
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 intersects;
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, intersects) {
56718
+ function acceleratedRaycast(raycaster, intersects2) {
55119
56719
  if (this.isBatchedMesh) {
55120
- acceleratedBatchedMeshRaycast.call(this, raycaster, intersects);
56720
+ acceleratedBatchedMeshRaycast.call(this, raycaster, intersects2);
55121
56721
  } else {
55122
- acceleratedMeshRaycast.call(this, raycaster, intersects);
56722
+ acceleratedMeshRaycast.call(this, raycaster, intersects2);
55123
56723
  }
55124
56724
  }
55125
- function acceleratedBatchedMeshRaycast(raycaster, intersects) {
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
- intersects.push(intersect2);
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, intersects);
56765
+ origBatchedRaycastFunc.call(this, raycaster, intersects2);
55166
56766
  }
55167
56767
  }
55168
- function acceleratedMeshRaycast(raycaster, intersects) {
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
- intersects.push(hit);
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
- intersects.push(hit);
56789
+ intersects2.push(hit);
55190
56790
  }
55191
56791
  }
55192
56792
  }
55193
56793
  } else {
55194
- origMeshRaycastFunc.call(this, raycaster, intersects);
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, normal, epsilon2, far, contactTolerance) {
55252
- const forward = firstOppositeSurfaceDistance(raycaster, rayTargetMeshes, centroid, normal, epsilon2, far, contactTolerance);
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
- normal.clone().negate(),
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, normal) {
56866
+ function measureThicknessAtPoint(context, point2, normal2) {
55267
56867
  return triangleThickness(
55268
56868
  context.raycaster,
55269
56869
  context.rayTargetMeshes,
55270
56870
  point2,
55271
- normal,
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 area = b.clone().sub(a2).cross(c2.clone().sub(a2)).length() * 0.5;
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 normal = ab.clone().cross(ac);
55403
- const area = normal.length() * 0.5;
55404
- normal.normalize();
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, normal, tolerance) {
55454
- return Math.abs(info.a.clone().sub(origin).dot(normal)) <= tolerance && Math.abs(info.b.clone().sub(origin).dot(normal)) <= tolerance && Math.abs(info.c.clone().sub(origin).dot(normal)) <= tolerance;
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 normal = new Vector3();
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
- normal.addScaledVector(info.normal, info.area);
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
- normal.normalize();
55504
- const uAxis = bestEdge.sub(normal.clone().multiplyScalar(bestEdge.dot(normal)));
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(normal.z) < 0.9 ? new Vector3(0, 0, 1) : new Vector3(1, 0, 0));
55507
- uAxis.sub(normal.clone().multiplyScalar(uAxis.dot(normal)));
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 = normal.clone().cross(uAxis).normalize();
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 normal = new Vector3();
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
- normal.copy(ab).cross(ac).normalize();
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, normal);
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, normal, candidate, candidateDistance) {
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(normal) >= -1e-5) return false;
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, normal) {
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, normal, candidate, distance)) return;
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 area = triArea(mesh.positions, a2, b, c2);
56276
- const nx = n[0] * area;
56277
- const ny = n[1] * area;
56278
- const nz = n[2] * area;
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 = "viridis";
58111
+ const DEFAULT_COLORMAP = "inferno";
56512
58112
  const DEFAULT_THICKNESS_COLOR_SCALE = {
56513
- colormap: "viridis",
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(normal) {
56882
- return this.getReconstructedBackend().mirror(normal);
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(normal, originOffset) {
56888
- return this.getReconstructedBackend().splitByPlane(normal, originOffset);
58487
+ splitByPlane(normal2, originOffset) {
58488
+ return this.getReconstructedBackend().splitByPlane(normal2, originOffset);
56889
58489
  }
56890
- trimByPlane(normal, originOffset) {
56891
- return this.getReconstructedBackend().trimByPlane(normal, originOffset);
58490
+ trimByPlane(normal2, originOffset) {
58491
+ return this.getReconstructedBackend().trimByPlane(normal2, originOffset);
56892
58492
  }
56893
58493
  volume() {
56894
58494
  return this.getReconstructedBackend().volume();