forgecad 0.10.3 → 0.10.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/assets/{AdminPage-CK7ObBz3.js → AdminPage-B3L3W1Uo.js} +1 -1
- package/dist/assets/{BenchmarkPage-Ds7Z2doN.js → BenchmarkPage-DXKVXMrJ.js} +2 -2
- package/dist/assets/{BlogPage-DlPbpt6A.js → BlogPage-B7BWxOCg.js} +1 -1
- package/dist/assets/{DocsPage-vZb3b3Y0.js → DocsPage-BPGGwht1.js} +28 -43
- package/dist/assets/{EditorApp-HLoKfe15.js → EditorApp-BWUGCdD5.js} +49 -16
- package/dist/assets/{EmbedViewer--KnqBKrJ.js → EmbedViewer-DygByZS2.js} +2 -2
- package/dist/assets/{LandingPageProofDriven-C_LssmnA.js → LandingPageProofDriven-BoVE7JGY.js} +54 -36
- package/dist/assets/{LegalPage-DGsyo4n1.js → LegalPage-Din8wv8d.js} +2 -2
- package/dist/assets/{PricingPage-BOE27B-R.js → PricingPage-C2PMzmDc.js} +2 -2
- package/dist/assets/{SettingsPage-f47cnk39.js → SettingsPage-BlJDCRe8.js} +1 -1
- package/dist/assets/{app-D6ccu2Xx.js → app-BsRYSfxY.js} +238 -3714
- package/dist/assets/{backendInit-DbTkQN9J.js → backendInit-6C0DLgH0.js} +5972 -1566
- package/dist/assets/cli/{render-BsngirjC.js → render-XXol_ET7.js} +724 -112
- package/dist/assets/{constructionHistoryWorker-PCwXrTDB.js → constructionHistoryWorker-cTHWRJEi.js} +528 -252
- package/dist/assets/{evalWorker-CS63PfZu.js → evalWorker-BssDYW9u.js} +1453 -902
- package/dist/assets/{inspectWorker-Y4cOzNyA.js → inspectWorker-ymhBV4Ll.js} +2635 -1024
- package/dist/assets/{jointPose-AMvCywzS.js → jointPose-B0blBj9A.js} +1 -1
- package/dist/assets/{landing-proof-driven-ORyigZ6p.css → landing-proof-driven-Cpf-MIbI.css} +73 -13
- package/dist/assets/{manifold-Crd_F2qx.js → manifold-B_7QXpGB.js} +1 -1
- package/dist/assets/{manifold-k2kRcc85.js → manifold-CNShmpEJ.js} +1 -1
- package/dist/assets/{manifold-CBry38ly.js → manifold-CYlIm-M6.js} +2 -2
- package/dist/assets/{reportWorker-CWvn0CEv.js → reportWorker-Cb5eyM7D.js} +1407 -892
- package/dist/cli/render.html +1 -1
- package/dist/docs/index.html +2 -2
- package/dist/docs-raw/AI/usage.md +17 -15
- package/dist/docs-raw/component-model.md +2 -2
- package/dist/docs-raw/generated/concepts.md +5 -1
- package/dist/docs-raw/generated/core.md +26 -0
- package/dist/docs-raw/generated/runtime-names.md +1 -1
- package/dist/docs-raw/guides/inspection-bundles.md +1 -1
- package/dist/docs-raw/simulation-workflow.md +1 -1
- package/dist/docs-raw/skills/{forgecad-make-a-model.md → forgecad-build-model.md} +18 -8
- package/dist/docs-raw/skills/{forgecad-spec-by-walking-through-it.md → forgecad-design-spec.md} +6 -6
- package/dist/docs-raw/skills/{forgecad-model-grader.md → forgecad-grade-model.md} +8 -6
- package/{dist-skill/website/skills/forgecad-visual-spec.md → dist/docs-raw/skills/forgecad-image-prompt.md} +7 -7
- package/dist/docs-raw/skills/{forgecad-render-inspect.md → forgecad-inspect-model.md} +6 -6
- package/{dist-skill/website/skills/forgecad-project.md → dist/docs-raw/skills/forgecad-project-sync.md} +5 -5
- package/dist/docs-raw/skills/{forgecad-3d-reconstruction.md → forgecad-reconstruct-cad-file.md} +7 -7
- package/dist/docs-raw/skills/{forgecad-image-replicator.md → forgecad-reconstruct-from-images.md} +12 -12
- package/dist/docs-raw/skills/{forgecad-mujoco-verify.md → forgecad-verify-mujoco.md} +6 -6
- package/dist/docs-raw/skills/index.md +9 -12
- package/dist/index.html +9 -9
- package/dist/llms.txt +7 -7
- package/dist/sitemap.xml +16 -16
- package/dist-cli/{check-compiler-HPF2T2FS.js → check-compiler-4RPB6SB5.js} +1 -1
- package/dist-cli/{check-query-propagation-HYSLTXAB.js → check-query-propagation-KN3DFQTX.js} +1 -1
- package/dist-cli/{chunk-WLUKAW3H.js → chunk-UHBRMYA6.js} +28802 -28152
- package/dist-cli/forgecad.js +660 -9
- package/dist-skill/CONTEXT.md +27 -1
- package/dist-skill/docs/generated/core.md +26 -0
- package/dist-skill/docs/generated/runtime-names.md +1 -1
- package/dist-skill/docs/guides/inspection-bundles.md +1 -1
- package/dist-skill/library/README.md +9 -12
- package/dist-skill/library/{forgecad-make-a-model → forgecad-build-model}/SKILL.md +16 -6
- package/dist-skill/library/{forgecad-spec-by-walking-through-it → forgecad-design-spec}/SKILL.md +4 -4
- package/dist-skill/library/{forgecad-spec-by-walking-through-it → forgecad-design-spec}/references/master-prompt.md +1 -1
- package/dist-skill/library/{forgecad-model-grader → forgecad-grade-model}/SKILL.md +6 -4
- package/dist-skill/library/forgecad-grade-model/agents/openai.yaml +4 -0
- package/dist-skill/library/{forgecad-visual-spec → forgecad-image-prompt}/SKILL.md +5 -5
- package/dist-skill/library/forgecad-image-prompt/agents/openai.yaml +4 -0
- package/dist-skill/library/{forgecad-render-inspect → forgecad-inspect-model}/SKILL.md +4 -4
- package/dist-skill/library/{forgecad-project → forgecad-project-sync}/SKILL.md +3 -3
- package/dist-skill/library/{forgecad-3d-reconstruction → forgecad-reconstruct-cad-file}/SKILL.md +5 -5
- package/dist-skill/library/forgecad-reconstruct-cad-file/agents/openai.yaml +4 -0
- package/dist-skill/library/{forgecad-image-replicator → forgecad-reconstruct-from-images}/SKILL.md +10 -10
- package/dist-skill/library/forgecad-reconstruct-from-images/agents/openai.yaml +4 -0
- package/dist-skill/library/{forgecad-mujoco-verify → forgecad-verify-mujoco}/SKILL.md +4 -4
- package/dist-skill/website/skills/{forgecad-make-a-model.md → forgecad-build-model.md} +18 -8
- package/dist-skill/website/skills/{forgecad-spec-by-walking-through-it.md → forgecad-design-spec.md} +6 -6
- package/dist-skill/website/skills/{forgecad-model-grader.md → forgecad-grade-model.md} +8 -6
- package/{dist/docs-raw/skills/forgecad-visual-spec.md → dist-skill/website/skills/forgecad-image-prompt.md} +7 -7
- package/dist-skill/website/skills/{forgecad-render-inspect.md → forgecad-inspect-model.md} +6 -6
- package/{dist/docs-raw/skills/forgecad-project.md → dist-skill/website/skills/forgecad-project-sync.md} +5 -5
- package/dist-skill/website/skills/{forgecad-3d-reconstruction.md → forgecad-reconstruct-cad-file.md} +7 -7
- package/dist-skill/website/skills/{forgecad-image-replicator.md → forgecad-reconstruct-from-images.md} +12 -12
- package/dist-skill/website/skills/{forgecad-mujoco-verify.md → forgecad-verify-mujoco.md} +6 -6
- package/dist-skill/website/skills/index.md +9 -12
- package/examples/api/texture-projection.forge.js +75 -0
- package/examples/assets/uv-grid.png +0 -0
- package/package.json +1 -1
- package/dist/docs-raw/skills/forgecad-blockout-model.md +0 -49
- package/dist/docs-raw/skills/forgecad-component-model.md +0 -53
- package/dist/docs-raw/skills/forgecad-reconstruction-benchmark.md +0 -60
- package/dist-skill/library/forgecad-3d-reconstruction/agents/openai.yaml +0 -4
- package/dist-skill/library/forgecad-blockout-model/SKILL.md +0 -42
- package/dist-skill/library/forgecad-component-model/SKILL.md +0 -46
- package/dist-skill/library/forgecad-image-replicator/agents/openai.yaml +0 -4
- package/dist-skill/library/forgecad-model-grader/agents/openai.yaml +0 -4
- package/dist-skill/library/forgecad-reconstruction-benchmark/SKILL.md +0 -48
- package/dist-skill/library/forgecad-reconstruction-benchmark/agents/openai.yaml +0 -4
- package/dist-skill/library/forgecad-visual-spec/agents/openai.yaml +0 -4
- package/dist-skill/website/skills/forgecad-blockout-model.md +0 -49
- package/dist-skill/website/skills/forgecad-component-model.md +0 -53
- package/dist-skill/website/skills/forgecad-reconstruction-benchmark.md +0 -60
- /package/dist/assets/{landing-proof-driven-DiGqdtWa.js → landing-proof-driven-BxZZh5r5.js} +0 -0
- /package/dist-skill/library/{forgecad-spec-by-walking-through-it → forgecad-design-spec}/references/default-profiles.md +0 -0
- /package/dist-skill/library/{forgecad-render-inspect → forgecad-inspect-model}/summarize_manifest.py +0 -0
- /package/dist-skill/library/{forgecad-image-replicator → forgecad-reconstruct-from-images}/scripts/compare_images.py +0 -0
- /package/dist-skill/library/{forgecad-mujoco-verify → forgecad-verify-mujoco}/scripts/mujoco_verify.py +0 -0
|
@@ -21,11 +21,14 @@ const UVMapping = 300;
|
|
|
21
21
|
const RepeatWrapping = 1e3;
|
|
22
22
|
const ClampToEdgeWrapping = 1001;
|
|
23
23
|
const MirroredRepeatWrapping = 1002;
|
|
24
|
+
const NearestFilter = 1003;
|
|
24
25
|
const LinearFilter = 1006;
|
|
25
26
|
const LinearMipmapLinearFilter = 1008;
|
|
26
27
|
const UnsignedByteType = 1009;
|
|
28
|
+
const UnsignedIntType = 1014;
|
|
27
29
|
const FloatType = 1015;
|
|
28
30
|
const RGBAFormat = 1023;
|
|
31
|
+
const RedIntegerFormat = 1029;
|
|
29
32
|
const NoColorSpace = "";
|
|
30
33
|
const SRGBColorSpace = "srgb";
|
|
31
34
|
const LinearSRGBColorSpace = "srgb-linear";
|
|
@@ -1083,12 +1086,12 @@ class Vector2 {
|
|
|
1083
1086
|
* @param {number} angle - The angle to rotate, in radians.
|
|
1084
1087
|
* @return {Vector2} A reference to this vector.
|
|
1085
1088
|
*/
|
|
1086
|
-
rotateAround(
|
|
1089
|
+
rotateAround(center2, angle) {
|
|
1087
1090
|
const c2 = Math.cos(angle), s = Math.sin(angle);
|
|
1088
|
-
const x2 = this.x -
|
|
1089
|
-
const y2 = this.y -
|
|
1090
|
-
this.x = x2 * c2 - y2 * s +
|
|
1091
|
-
this.y = x2 * s + y2 * c2 +
|
|
1091
|
+
const x2 = this.x - center2.x;
|
|
1092
|
+
const y2 = this.y - center2.y;
|
|
1093
|
+
this.x = x2 * c2 - y2 * s + center2.x;
|
|
1094
|
+
this.y = x2 * s + y2 * c2 + center2.y;
|
|
1092
1095
|
return this;
|
|
1093
1096
|
}
|
|
1094
1097
|
/**
|
|
@@ -4472,10 +4475,10 @@ class Box3 {
|
|
|
4472
4475
|
* @param {Vector3} size - The x, y and z dimensions of the box.
|
|
4473
4476
|
* @return {Box3} A reference to this bounding box.
|
|
4474
4477
|
*/
|
|
4475
|
-
setFromCenterAndSize(
|
|
4478
|
+
setFromCenterAndSize(center2, size) {
|
|
4476
4479
|
const halfSize = _vector$b.copy(size).multiplyScalar(0.5);
|
|
4477
|
-
this.min.copy(
|
|
4478
|
-
this.max.copy(
|
|
4480
|
+
this.min.copy(center2).sub(halfSize);
|
|
4481
|
+
this.max.copy(center2).add(halfSize);
|
|
4479
4482
|
return this;
|
|
4480
4483
|
}
|
|
4481
4484
|
/**
|
|
@@ -4925,9 +4928,9 @@ class Sphere {
|
|
|
4925
4928
|
* @param {Vector3} [center=(0,0,0)] - The center of the sphere
|
|
4926
4929
|
* @param {number} [radius=-1] - The radius of the sphere.
|
|
4927
4930
|
*/
|
|
4928
|
-
constructor(
|
|
4931
|
+
constructor(center2 = new Vector3(), radius = -1) {
|
|
4929
4932
|
this.isSphere = true;
|
|
4930
|
-
this.center =
|
|
4933
|
+
this.center = center2;
|
|
4931
4934
|
this.radius = radius;
|
|
4932
4935
|
}
|
|
4933
4936
|
/**
|
|
@@ -4937,8 +4940,8 @@ class Sphere {
|
|
|
4937
4940
|
* @param {number} radius - The radius.
|
|
4938
4941
|
* @return {Sphere} A reference to this sphere.
|
|
4939
4942
|
*/
|
|
4940
|
-
set(
|
|
4941
|
-
this.center.copy(
|
|
4943
|
+
set(center2, radius) {
|
|
4944
|
+
this.center.copy(center2);
|
|
4942
4945
|
this.radius = radius;
|
|
4943
4946
|
return this;
|
|
4944
4947
|
}
|
|
@@ -4953,15 +4956,15 @@ class Sphere {
|
|
|
4953
4956
|
* @return {Sphere} A reference to this sphere.
|
|
4954
4957
|
*/
|
|
4955
4958
|
setFromPoints(points, optionalCenter) {
|
|
4956
|
-
const
|
|
4959
|
+
const center2 = this.center;
|
|
4957
4960
|
if (optionalCenter !== void 0) {
|
|
4958
|
-
|
|
4961
|
+
center2.copy(optionalCenter);
|
|
4959
4962
|
} else {
|
|
4960
|
-
_box$3.setFromPoints(points).getCenter(
|
|
4963
|
+
_box$3.setFromPoints(points).getCenter(center2);
|
|
4961
4964
|
}
|
|
4962
4965
|
let maxRadiusSq = 0;
|
|
4963
4966
|
for (let i = 0, il = points.length; i < il; i++) {
|
|
4964
|
-
maxRadiusSq = Math.max(maxRadiusSq,
|
|
4967
|
+
maxRadiusSq = Math.max(maxRadiusSq, center2.distanceToSquared(points[i]));
|
|
4965
4968
|
}
|
|
4966
4969
|
this.radius = Math.sqrt(maxRadiusSq);
|
|
4967
4970
|
return this;
|
|
@@ -5178,9 +5181,9 @@ class Ray {
|
|
|
5178
5181
|
* @param {Vector3} [origin=(0,0,0)] - The origin of the ray.
|
|
5179
5182
|
* @param {Vector3} [direction=(0,0,-1)] - The (normalized) direction of the ray.
|
|
5180
5183
|
*/
|
|
5181
|
-
constructor(origin = new Vector3(),
|
|
5184
|
+
constructor(origin = new Vector3(), direction2 = new Vector3(0, 0, -1)) {
|
|
5182
5185
|
this.origin = origin;
|
|
5183
|
-
this.direction =
|
|
5186
|
+
this.direction = direction2;
|
|
5184
5187
|
}
|
|
5185
5188
|
/**
|
|
5186
5189
|
* Sets the ray's components by copying the given values.
|
|
@@ -5189,9 +5192,9 @@ class Ray {
|
|
|
5189
5192
|
* @param {Vector3} direction - The direction.
|
|
5190
5193
|
* @return {Ray} A reference to this ray.
|
|
5191
5194
|
*/
|
|
5192
|
-
set(origin,
|
|
5195
|
+
set(origin, direction2) {
|
|
5193
5196
|
this.origin.copy(origin);
|
|
5194
|
-
this.direction.copy(
|
|
5197
|
+
this.direction.copy(direction2);
|
|
5195
5198
|
return this;
|
|
5196
5199
|
}
|
|
5197
5200
|
/**
|
|
@@ -5200,9 +5203,9 @@ class Ray {
|
|
|
5200
5203
|
* @param {Ray} ray - The ray to copy.
|
|
5201
5204
|
* @return {Ray} A reference to this ray.
|
|
5202
5205
|
*/
|
|
5203
|
-
copy(
|
|
5204
|
-
this.origin.copy(
|
|
5205
|
-
this.direction.copy(
|
|
5206
|
+
copy(ray2) {
|
|
5207
|
+
this.origin.copy(ray2.origin);
|
|
5208
|
+
this.direction.copy(ray2.direction);
|
|
5206
5209
|
return this;
|
|
5207
5210
|
}
|
|
5208
5211
|
/**
|
|
@@ -5534,8 +5537,8 @@ class Ray {
|
|
|
5534
5537
|
* @param {Ray} ray - The ray to test for equality.
|
|
5535
5538
|
* @return {boolean} Whether this ray is equal with the given one.
|
|
5536
5539
|
*/
|
|
5537
|
-
equals(
|
|
5538
|
-
return
|
|
5540
|
+
equals(ray2) {
|
|
5541
|
+
return ray2.origin.equals(this.origin) && ray2.direction.equals(this.direction);
|
|
5539
5542
|
}
|
|
5540
5543
|
/**
|
|
5541
5544
|
* Returns a new ray with copied values from this instance.
|
|
@@ -8069,10 +8072,10 @@ class Triangle {
|
|
|
8069
8072
|
* @param {Vector3} direction - The (normalized) direction vector.
|
|
8070
8073
|
* @return {boolean} Whether the triangle is oriented towards the given direction or not.
|
|
8071
8074
|
*/
|
|
8072
|
-
static isFrontFacing(a2, b, c2,
|
|
8075
|
+
static isFrontFacing(a2, b, c2, direction2) {
|
|
8073
8076
|
_v0$1.subVectors(c2, b);
|
|
8074
8077
|
_v1$3.subVectors(a2, b);
|
|
8075
|
-
return _v0$1.cross(_v1$3).dot(
|
|
8078
|
+
return _v0$1.cross(_v1$3).dot(direction2) < 0 ? true : false;
|
|
8076
8079
|
}
|
|
8077
8080
|
/**
|
|
8078
8081
|
* Sets the triangle's vertices by copying the given values.
|
|
@@ -8217,8 +8220,8 @@ class Triangle {
|
|
|
8217
8220
|
* @param {Vector3} direction - The (normalized) direction vector.
|
|
8218
8221
|
* @return {boolean} Whether the triangle is oriented towards the given direction or not.
|
|
8219
8222
|
*/
|
|
8220
|
-
isFrontFacing(
|
|
8221
|
-
return Triangle.isFrontFacing(this.a, this.b, this.c,
|
|
8223
|
+
isFrontFacing(direction2) {
|
|
8224
|
+
return Triangle.isFrontFacing(this.a, this.b, this.c, direction2);
|
|
8222
8225
|
}
|
|
8223
8226
|
/**
|
|
8224
8227
|
* Returns `true` if this triangle intersects with the given box.
|
|
@@ -10330,7 +10333,7 @@ class BufferGeometry extends EventDispatcher {
|
|
|
10330
10333
|
return;
|
|
10331
10334
|
}
|
|
10332
10335
|
if (position) {
|
|
10333
|
-
const
|
|
10336
|
+
const center2 = this.boundingSphere.center;
|
|
10334
10337
|
_box$2.setFromBufferAttribute(position);
|
|
10335
10338
|
if (morphAttributesPosition) {
|
|
10336
10339
|
for (let i = 0, il = morphAttributesPosition.length; i < il; i++) {
|
|
@@ -10347,11 +10350,11 @@ class BufferGeometry extends EventDispatcher {
|
|
|
10347
10350
|
}
|
|
10348
10351
|
}
|
|
10349
10352
|
}
|
|
10350
|
-
_box$2.getCenter(
|
|
10353
|
+
_box$2.getCenter(center2);
|
|
10351
10354
|
let maxRadiusSq = 0;
|
|
10352
10355
|
for (let i = 0, il = position.count; i < il; i++) {
|
|
10353
10356
|
_vector$8.fromBufferAttribute(position, i);
|
|
10354
|
-
maxRadiusSq = Math.max(maxRadiusSq,
|
|
10357
|
+
maxRadiusSq = Math.max(maxRadiusSq, center2.distanceToSquared(_vector$8));
|
|
10355
10358
|
}
|
|
10356
10359
|
if (morphAttributesPosition) {
|
|
10357
10360
|
for (let i = 0, il = morphAttributesPosition.length; i < il; i++) {
|
|
@@ -10363,7 +10366,7 @@ class BufferGeometry extends EventDispatcher {
|
|
|
10363
10366
|
_offset.fromBufferAttribute(position, j);
|
|
10364
10367
|
_vector$8.add(_offset);
|
|
10365
10368
|
}
|
|
10366
|
-
maxRadiusSq = Math.max(maxRadiusSq,
|
|
10369
|
+
maxRadiusSq = Math.max(maxRadiusSq, center2.distanceToSquared(_vector$8));
|
|
10367
10370
|
}
|
|
10368
10371
|
}
|
|
10369
10372
|
}
|
|
@@ -10930,12 +10933,12 @@ class Mesh extends Object3D {
|
|
|
10930
10933
|
}
|
|
10931
10934
|
}
|
|
10932
10935
|
}
|
|
10933
|
-
function checkIntersection$1(object, material, raycaster,
|
|
10936
|
+
function checkIntersection$1(object, material, raycaster, ray2, pA, pB, pC, point2) {
|
|
10934
10937
|
let intersect2;
|
|
10935
10938
|
if (material.side === BackSide) {
|
|
10936
|
-
intersect2 =
|
|
10939
|
+
intersect2 = ray2.intersectTriangle(pC, pB, pA, true, point2);
|
|
10937
10940
|
} else {
|
|
10938
|
-
intersect2 =
|
|
10941
|
+
intersect2 = ray2.intersectTriangle(pA, pB, pC, material.side === FrontSide, point2);
|
|
10939
10942
|
}
|
|
10940
10943
|
if (intersect2 === null) return null;
|
|
10941
10944
|
_intersectionPointWorld.copy(point2);
|
|
@@ -10948,11 +10951,11 @@ function checkIntersection$1(object, material, raycaster, ray, pA, pB, pC, point
|
|
|
10948
10951
|
object
|
|
10949
10952
|
};
|
|
10950
10953
|
}
|
|
10951
|
-
function checkGeometryIntersection(object, material, raycaster,
|
|
10954
|
+
function checkGeometryIntersection(object, material, raycaster, ray2, uv, uv1, normal, a2, b, c2) {
|
|
10952
10955
|
object.getVertexPosition(a2, _vA$1);
|
|
10953
10956
|
object.getVertexPosition(b, _vB$1);
|
|
10954
10957
|
object.getVertexPosition(c2, _vC$1);
|
|
10955
|
-
const intersection2 = checkIntersection$1(object, material, raycaster,
|
|
10958
|
+
const intersection2 = checkIntersection$1(object, material, raycaster, ray2, _vA$1, _vB$1, _vC$1, _intersectionPoint$1);
|
|
10956
10959
|
if (intersection2) {
|
|
10957
10960
|
const barycoord = new Vector3();
|
|
10958
10961
|
Triangle.getBarycoord(_intersectionPoint$1, _vA$1, _vB$1, _vC$1, barycoord);
|
|
@@ -10964,7 +10967,7 @@ function checkGeometryIntersection(object, material, raycaster, ray, uv, uv1, no
|
|
|
10964
10967
|
}
|
|
10965
10968
|
if (normal) {
|
|
10966
10969
|
intersection2.normal = Triangle.getInterpolatedAttribute(normal, a2, b, c2, barycoord, new Vector3());
|
|
10967
|
-
if (intersection2.normal.dot(
|
|
10970
|
+
if (intersection2.normal.dot(ray2.direction) > 0) {
|
|
10968
10971
|
intersection2.normal.multiplyScalar(-1);
|
|
10969
10972
|
}
|
|
10970
10973
|
}
|
|
@@ -10981,6 +10984,32 @@ function checkGeometryIntersection(object, material, raycaster, ray, uv, uv1, no
|
|
|
10981
10984
|
}
|
|
10982
10985
|
return intersection2;
|
|
10983
10986
|
}
|
|
10987
|
+
class DataTexture extends Texture {
|
|
10988
|
+
/**
|
|
10989
|
+
* Constructs a new data texture.
|
|
10990
|
+
*
|
|
10991
|
+
* @param {?TypedArray} [data=null] - The buffer data.
|
|
10992
|
+
* @param {number} [width=1] - The width of the texture.
|
|
10993
|
+
* @param {number} [height=1] - The height of the texture.
|
|
10994
|
+
* @param {number} [format=RGBAFormat] - The texture format.
|
|
10995
|
+
* @param {number} [type=UnsignedByteType] - The texture type.
|
|
10996
|
+
* @param {number} [mapping=Texture.DEFAULT_MAPPING] - The texture mapping.
|
|
10997
|
+
* @param {number} [wrapS=ClampToEdgeWrapping] - The wrapS value.
|
|
10998
|
+
* @param {number} [wrapT=ClampToEdgeWrapping] - The wrapT value.
|
|
10999
|
+
* @param {number} [magFilter=NearestFilter] - The mag filter value.
|
|
11000
|
+
* @param {number} [minFilter=NearestFilter] - The min filter value.
|
|
11001
|
+
* @param {number} [anisotropy=Texture.DEFAULT_ANISOTROPY] - The anisotropy value.
|
|
11002
|
+
* @param {string} [colorSpace=NoColorSpace] - The color space.
|
|
11003
|
+
*/
|
|
11004
|
+
constructor(data = null, width = 1, height = 1, format, type, mapping, wrapS, wrapT, magFilter = NearestFilter, minFilter = NearestFilter, anisotropy, colorSpace) {
|
|
11005
|
+
super(null, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy, colorSpace);
|
|
11006
|
+
this.isDataTexture = true;
|
|
11007
|
+
this.image = { data, width, height };
|
|
11008
|
+
this.generateMipmaps = false;
|
|
11009
|
+
this.flipY = false;
|
|
11010
|
+
this.unpackAlignment = 1;
|
|
11011
|
+
}
|
|
11012
|
+
}
|
|
10984
11013
|
const _vector1 = /* @__PURE__ */ new Vector3();
|
|
10985
11014
|
const _vector2 = /* @__PURE__ */ new Vector3();
|
|
10986
11015
|
const _normalMatrix = /* @__PURE__ */ new Matrix3();
|
|
@@ -11121,8 +11150,8 @@ class Plane {
|
|
|
11121
11150
|
* @return {?Vector3} The intersection point.
|
|
11122
11151
|
*/
|
|
11123
11152
|
intersectLine(line, target) {
|
|
11124
|
-
const
|
|
11125
|
-
const denominator = this.normal.dot(
|
|
11153
|
+
const direction2 = line.delta(_vector1);
|
|
11154
|
+
const denominator = this.normal.dot(direction2);
|
|
11126
11155
|
if (denominator === 0) {
|
|
11127
11156
|
if (this.distanceToPoint(line.start) === 0) {
|
|
11128
11157
|
return target.copy(line.start);
|
|
@@ -11133,7 +11162,7 @@ class Plane {
|
|
|
11133
11162
|
if (t < 0 || t > 1) {
|
|
11134
11163
|
return null;
|
|
11135
11164
|
}
|
|
11136
|
-
return target.copy(line.start).addScaledVector(
|
|
11165
|
+
return target.copy(line.start).addScaledVector(direction2, t);
|
|
11137
11166
|
}
|
|
11138
11167
|
/**
|
|
11139
11168
|
* Returns `true` if the given line segment intersects with (passes through) the plane.
|
|
@@ -11222,6 +11251,1144 @@ class Plane {
|
|
|
11222
11251
|
return new this.constructor().copy(this);
|
|
11223
11252
|
}
|
|
11224
11253
|
}
|
|
11254
|
+
const _sphere$3 = /* @__PURE__ */ new Sphere();
|
|
11255
|
+
const _vector$6 = /* @__PURE__ */ new Vector3();
|
|
11256
|
+
class Frustum {
|
|
11257
|
+
/**
|
|
11258
|
+
* Constructs a new frustum.
|
|
11259
|
+
*
|
|
11260
|
+
* @param {Plane} [p0] - The first plane that encloses the frustum.
|
|
11261
|
+
* @param {Plane} [p1] - The second plane that encloses the frustum.
|
|
11262
|
+
* @param {Plane} [p2] - The third plane that encloses the frustum.
|
|
11263
|
+
* @param {Plane} [p3] - The fourth plane that encloses the frustum.
|
|
11264
|
+
* @param {Plane} [p4] - The fifth plane that encloses the frustum.
|
|
11265
|
+
* @param {Plane} [p5] - The sixth plane that encloses the frustum.
|
|
11266
|
+
*/
|
|
11267
|
+
constructor(p0 = new Plane(), p1 = new Plane(), p2 = new Plane(), p3 = new Plane(), p4 = new Plane(), p5 = new Plane()) {
|
|
11268
|
+
this.planes = [p0, p1, p2, p3, p4, p5];
|
|
11269
|
+
}
|
|
11270
|
+
/**
|
|
11271
|
+
* Sets the frustum planes by copying the given planes.
|
|
11272
|
+
*
|
|
11273
|
+
* @param {Plane} [p0] - The first plane that encloses the frustum.
|
|
11274
|
+
* @param {Plane} [p1] - The second plane that encloses the frustum.
|
|
11275
|
+
* @param {Plane} [p2] - The third plane that encloses the frustum.
|
|
11276
|
+
* @param {Plane} [p3] - The fourth plane that encloses the frustum.
|
|
11277
|
+
* @param {Plane} [p4] - The fifth plane that encloses the frustum.
|
|
11278
|
+
* @param {Plane} [p5] - The sixth plane that encloses the frustum.
|
|
11279
|
+
* @return {Frustum} A reference to this frustum.
|
|
11280
|
+
*/
|
|
11281
|
+
set(p0, p1, p2, p3, p4, p5) {
|
|
11282
|
+
const planes = this.planes;
|
|
11283
|
+
planes[0].copy(p0);
|
|
11284
|
+
planes[1].copy(p1);
|
|
11285
|
+
planes[2].copy(p2);
|
|
11286
|
+
planes[3].copy(p3);
|
|
11287
|
+
planes[4].copy(p4);
|
|
11288
|
+
planes[5].copy(p5);
|
|
11289
|
+
return this;
|
|
11290
|
+
}
|
|
11291
|
+
/**
|
|
11292
|
+
* Copies the values of the given frustum to this instance.
|
|
11293
|
+
*
|
|
11294
|
+
* @param {Frustum} frustum - The frustum to copy.
|
|
11295
|
+
* @return {Frustum} A reference to this frustum.
|
|
11296
|
+
*/
|
|
11297
|
+
copy(frustum) {
|
|
11298
|
+
const planes = this.planes;
|
|
11299
|
+
for (let i = 0; i < 6; i++) {
|
|
11300
|
+
planes[i].copy(frustum.planes[i]);
|
|
11301
|
+
}
|
|
11302
|
+
return this;
|
|
11303
|
+
}
|
|
11304
|
+
/**
|
|
11305
|
+
* Sets the frustum planes from the given projection matrix.
|
|
11306
|
+
*
|
|
11307
|
+
* @param {Matrix4} m - The projection matrix.
|
|
11308
|
+
* @param {(WebGLCoordinateSystem|WebGPUCoordinateSystem)} coordinateSystem - The coordinate system.
|
|
11309
|
+
* @return {Frustum} A reference to this frustum.
|
|
11310
|
+
*/
|
|
11311
|
+
setFromProjectionMatrix(m2, coordinateSystem = WebGLCoordinateSystem) {
|
|
11312
|
+
const planes = this.planes;
|
|
11313
|
+
const me = m2.elements;
|
|
11314
|
+
const me0 = me[0], me1 = me[1], me2 = me[2], me3 = me[3];
|
|
11315
|
+
const me4 = me[4], me5 = me[5], me6 = me[6], me7 = me[7];
|
|
11316
|
+
const me8 = me[8], me9 = me[9], me10 = me[10], me11 = me[11];
|
|
11317
|
+
const me12 = me[12], me13 = me[13], me14 = me[14], me15 = me[15];
|
|
11318
|
+
planes[0].setComponents(me3 - me0, me7 - me4, me11 - me8, me15 - me12).normalize();
|
|
11319
|
+
planes[1].setComponents(me3 + me0, me7 + me4, me11 + me8, me15 + me12).normalize();
|
|
11320
|
+
planes[2].setComponents(me3 + me1, me7 + me5, me11 + me9, me15 + me13).normalize();
|
|
11321
|
+
planes[3].setComponents(me3 - me1, me7 - me5, me11 - me9, me15 - me13).normalize();
|
|
11322
|
+
planes[4].setComponents(me3 - me2, me7 - me6, me11 - me10, me15 - me14).normalize();
|
|
11323
|
+
if (coordinateSystem === WebGLCoordinateSystem) {
|
|
11324
|
+
planes[5].setComponents(me3 + me2, me7 + me6, me11 + me10, me15 + me14).normalize();
|
|
11325
|
+
} else if (coordinateSystem === WebGPUCoordinateSystem) {
|
|
11326
|
+
planes[5].setComponents(me2, me6, me10, me14).normalize();
|
|
11327
|
+
} else {
|
|
11328
|
+
throw new Error("THREE.Frustum.setFromProjectionMatrix(): Invalid coordinate system: " + coordinateSystem);
|
|
11329
|
+
}
|
|
11330
|
+
return this;
|
|
11331
|
+
}
|
|
11332
|
+
/**
|
|
11333
|
+
* Returns `true` if the 3D object's bounding sphere is intersecting this frustum.
|
|
11334
|
+
*
|
|
11335
|
+
* Note that the 3D object must have a geometry so that the bounding sphere can be calculated.
|
|
11336
|
+
*
|
|
11337
|
+
* @param {Object3D} object - The 3D object to test.
|
|
11338
|
+
* @return {boolean} Whether the 3D object's bounding sphere is intersecting this frustum or not.
|
|
11339
|
+
*/
|
|
11340
|
+
intersectsObject(object) {
|
|
11341
|
+
if (object.boundingSphere !== void 0) {
|
|
11342
|
+
if (object.boundingSphere === null) object.computeBoundingSphere();
|
|
11343
|
+
_sphere$3.copy(object.boundingSphere).applyMatrix4(object.matrixWorld);
|
|
11344
|
+
} else {
|
|
11345
|
+
const geometry = object.geometry;
|
|
11346
|
+
if (geometry.boundingSphere === null) geometry.computeBoundingSphere();
|
|
11347
|
+
_sphere$3.copy(geometry.boundingSphere).applyMatrix4(object.matrixWorld);
|
|
11348
|
+
}
|
|
11349
|
+
return this.intersectsSphere(_sphere$3);
|
|
11350
|
+
}
|
|
11351
|
+
/**
|
|
11352
|
+
* Returns `true` if the given sprite is intersecting this frustum.
|
|
11353
|
+
*
|
|
11354
|
+
* @param {Sprite} sprite - The sprite to test.
|
|
11355
|
+
* @return {boolean} Whether the sprite is intersecting this frustum or not.
|
|
11356
|
+
*/
|
|
11357
|
+
intersectsSprite(sprite) {
|
|
11358
|
+
_sphere$3.center.set(0, 0, 0);
|
|
11359
|
+
_sphere$3.radius = 0.7071067811865476;
|
|
11360
|
+
_sphere$3.applyMatrix4(sprite.matrixWorld);
|
|
11361
|
+
return this.intersectsSphere(_sphere$3);
|
|
11362
|
+
}
|
|
11363
|
+
/**
|
|
11364
|
+
* Returns `true` if the given bounding sphere is intersecting this frustum.
|
|
11365
|
+
*
|
|
11366
|
+
* @param {Sphere} sphere - The bounding sphere to test.
|
|
11367
|
+
* @return {boolean} Whether the bounding sphere is intersecting this frustum or not.
|
|
11368
|
+
*/
|
|
11369
|
+
intersectsSphere(sphere) {
|
|
11370
|
+
const planes = this.planes;
|
|
11371
|
+
const center2 = sphere.center;
|
|
11372
|
+
const negRadius = -sphere.radius;
|
|
11373
|
+
for (let i = 0; i < 6; i++) {
|
|
11374
|
+
const distance = planes[i].distanceToPoint(center2);
|
|
11375
|
+
if (distance < negRadius) {
|
|
11376
|
+
return false;
|
|
11377
|
+
}
|
|
11378
|
+
}
|
|
11379
|
+
return true;
|
|
11380
|
+
}
|
|
11381
|
+
/**
|
|
11382
|
+
* Returns `true` if the given bounding box is intersecting this frustum.
|
|
11383
|
+
*
|
|
11384
|
+
* @param {Box3} box - The bounding box to test.
|
|
11385
|
+
* @return {boolean} Whether the bounding box is intersecting this frustum or not.
|
|
11386
|
+
*/
|
|
11387
|
+
intersectsBox(box) {
|
|
11388
|
+
const planes = this.planes;
|
|
11389
|
+
for (let i = 0; i < 6; i++) {
|
|
11390
|
+
const plane = planes[i];
|
|
11391
|
+
_vector$6.x = plane.normal.x > 0 ? box.max.x : box.min.x;
|
|
11392
|
+
_vector$6.y = plane.normal.y > 0 ? box.max.y : box.min.y;
|
|
11393
|
+
_vector$6.z = plane.normal.z > 0 ? box.max.z : box.min.z;
|
|
11394
|
+
if (plane.distanceToPoint(_vector$6) < 0) {
|
|
11395
|
+
return false;
|
|
11396
|
+
}
|
|
11397
|
+
}
|
|
11398
|
+
return true;
|
|
11399
|
+
}
|
|
11400
|
+
/**
|
|
11401
|
+
* Returns `true` if the given point lies within the frustum.
|
|
11402
|
+
*
|
|
11403
|
+
* @param {Vector3} point - The point to test.
|
|
11404
|
+
* @return {boolean} Whether the point lies within this frustum or not.
|
|
11405
|
+
*/
|
|
11406
|
+
containsPoint(point2) {
|
|
11407
|
+
const planes = this.planes;
|
|
11408
|
+
for (let i = 0; i < 6; i++) {
|
|
11409
|
+
if (planes[i].distanceToPoint(point2) < 0) {
|
|
11410
|
+
return false;
|
|
11411
|
+
}
|
|
11412
|
+
}
|
|
11413
|
+
return true;
|
|
11414
|
+
}
|
|
11415
|
+
/**
|
|
11416
|
+
* Returns a new frustum with copied values from this instance.
|
|
11417
|
+
*
|
|
11418
|
+
* @return {Frustum} A clone of this instance.
|
|
11419
|
+
*/
|
|
11420
|
+
clone() {
|
|
11421
|
+
return new this.constructor().copy(this);
|
|
11422
|
+
}
|
|
11423
|
+
}
|
|
11424
|
+
function ascIdSort(a2, b) {
|
|
11425
|
+
return a2 - b;
|
|
11426
|
+
}
|
|
11427
|
+
function sortOpaque(a2, b) {
|
|
11428
|
+
return a2.z - b.z;
|
|
11429
|
+
}
|
|
11430
|
+
function sortTransparent(a2, b) {
|
|
11431
|
+
return b.z - a2.z;
|
|
11432
|
+
}
|
|
11433
|
+
class MultiDrawRenderList {
|
|
11434
|
+
constructor() {
|
|
11435
|
+
this.index = 0;
|
|
11436
|
+
this.pool = [];
|
|
11437
|
+
this.list = [];
|
|
11438
|
+
}
|
|
11439
|
+
push(start, count, z2, index2) {
|
|
11440
|
+
const pool = this.pool;
|
|
11441
|
+
const list = this.list;
|
|
11442
|
+
if (this.index >= pool.length) {
|
|
11443
|
+
pool.push({
|
|
11444
|
+
start: -1,
|
|
11445
|
+
count: -1,
|
|
11446
|
+
z: -1,
|
|
11447
|
+
index: -1
|
|
11448
|
+
});
|
|
11449
|
+
}
|
|
11450
|
+
const item = pool[this.index];
|
|
11451
|
+
list.push(item);
|
|
11452
|
+
this.index++;
|
|
11453
|
+
item.start = start;
|
|
11454
|
+
item.count = count;
|
|
11455
|
+
item.z = z2;
|
|
11456
|
+
item.index = index2;
|
|
11457
|
+
}
|
|
11458
|
+
reset() {
|
|
11459
|
+
this.list.length = 0;
|
|
11460
|
+
this.index = 0;
|
|
11461
|
+
}
|
|
11462
|
+
}
|
|
11463
|
+
const _matrix$1 = /* @__PURE__ */ new Matrix4();
|
|
11464
|
+
const _whiteColor = /* @__PURE__ */ new Color(1, 1, 1);
|
|
11465
|
+
const _frustum = /* @__PURE__ */ new Frustum();
|
|
11466
|
+
const _box$1 = /* @__PURE__ */ new Box3();
|
|
11467
|
+
const _sphere$2 = /* @__PURE__ */ new Sphere();
|
|
11468
|
+
const _vector$5 = /* @__PURE__ */ new Vector3();
|
|
11469
|
+
const _forward = /* @__PURE__ */ new Vector3();
|
|
11470
|
+
const _temp = /* @__PURE__ */ new Vector3();
|
|
11471
|
+
const _renderList = /* @__PURE__ */ new MultiDrawRenderList();
|
|
11472
|
+
const _mesh$1 = /* @__PURE__ */ new Mesh();
|
|
11473
|
+
const _batchIntersects$1 = [];
|
|
11474
|
+
function copyAttributeData(src, target, targetOffset = 0) {
|
|
11475
|
+
const itemSize = target.itemSize;
|
|
11476
|
+
if (src.isInterleavedBufferAttribute || src.array.constructor !== target.array.constructor) {
|
|
11477
|
+
const vertexCount = src.count;
|
|
11478
|
+
for (let i = 0; i < vertexCount; i++) {
|
|
11479
|
+
for (let c2 = 0; c2 < itemSize; c2++) {
|
|
11480
|
+
target.setComponent(i + targetOffset, c2, src.getComponent(i, c2));
|
|
11481
|
+
}
|
|
11482
|
+
}
|
|
11483
|
+
} else {
|
|
11484
|
+
target.array.set(src.array, targetOffset * itemSize);
|
|
11485
|
+
}
|
|
11486
|
+
target.needsUpdate = true;
|
|
11487
|
+
}
|
|
11488
|
+
function copyArrayContents(src, target) {
|
|
11489
|
+
if (src.constructor !== target.constructor) {
|
|
11490
|
+
const len = Math.min(src.length, target.length);
|
|
11491
|
+
for (let i = 0; i < len; i++) {
|
|
11492
|
+
target[i] = src[i];
|
|
11493
|
+
}
|
|
11494
|
+
} else {
|
|
11495
|
+
const len = Math.min(src.length, target.length);
|
|
11496
|
+
target.set(new src.constructor(src.buffer, 0, len));
|
|
11497
|
+
}
|
|
11498
|
+
}
|
|
11499
|
+
class BatchedMesh extends Mesh {
|
|
11500
|
+
/**
|
|
11501
|
+
* Constructs a new batched mesh.
|
|
11502
|
+
*
|
|
11503
|
+
* @param {number} maxInstanceCount - The maximum number of individual instances planned to be added and rendered.
|
|
11504
|
+
* @param {number} maxVertexCount - The maximum number of vertices to be used by all unique geometries.
|
|
11505
|
+
* @param {number} [maxIndexCount=maxVertexCount*2] - The maximum number of indices to be used by all unique geometries
|
|
11506
|
+
* @param {Material|Array<Material>} [material] - The mesh material.
|
|
11507
|
+
*/
|
|
11508
|
+
constructor(maxInstanceCount, maxVertexCount, maxIndexCount = maxVertexCount * 2, material) {
|
|
11509
|
+
super(new BufferGeometry(), material);
|
|
11510
|
+
this.isBatchedMesh = true;
|
|
11511
|
+
this.perObjectFrustumCulled = true;
|
|
11512
|
+
this.sortObjects = true;
|
|
11513
|
+
this.boundingBox = null;
|
|
11514
|
+
this.boundingSphere = null;
|
|
11515
|
+
this.customSort = null;
|
|
11516
|
+
this._instanceInfo = [];
|
|
11517
|
+
this._geometryInfo = [];
|
|
11518
|
+
this._availableInstanceIds = [];
|
|
11519
|
+
this._availableGeometryIds = [];
|
|
11520
|
+
this._nextIndexStart = 0;
|
|
11521
|
+
this._nextVertexStart = 0;
|
|
11522
|
+
this._geometryCount = 0;
|
|
11523
|
+
this._visibilityChanged = true;
|
|
11524
|
+
this._geometryInitialized = false;
|
|
11525
|
+
this._maxInstanceCount = maxInstanceCount;
|
|
11526
|
+
this._maxVertexCount = maxVertexCount;
|
|
11527
|
+
this._maxIndexCount = maxIndexCount;
|
|
11528
|
+
this._multiDrawCounts = new Int32Array(maxInstanceCount);
|
|
11529
|
+
this._multiDrawStarts = new Int32Array(maxInstanceCount);
|
|
11530
|
+
this._multiDrawCount = 0;
|
|
11531
|
+
this._multiDrawInstances = null;
|
|
11532
|
+
this._matricesTexture = null;
|
|
11533
|
+
this._indirectTexture = null;
|
|
11534
|
+
this._colorsTexture = null;
|
|
11535
|
+
this._initMatricesTexture();
|
|
11536
|
+
this._initIndirectTexture();
|
|
11537
|
+
}
|
|
11538
|
+
/**
|
|
11539
|
+
* The maximum number of individual instances that can be stored in the batch.
|
|
11540
|
+
*
|
|
11541
|
+
* @type {number}
|
|
11542
|
+
* @readonly
|
|
11543
|
+
*/
|
|
11544
|
+
get maxInstanceCount() {
|
|
11545
|
+
return this._maxInstanceCount;
|
|
11546
|
+
}
|
|
11547
|
+
/**
|
|
11548
|
+
* The instance count.
|
|
11549
|
+
*
|
|
11550
|
+
* @type {number}
|
|
11551
|
+
* @readonly
|
|
11552
|
+
*/
|
|
11553
|
+
get instanceCount() {
|
|
11554
|
+
return this._instanceInfo.length - this._availableInstanceIds.length;
|
|
11555
|
+
}
|
|
11556
|
+
/**
|
|
11557
|
+
* The number of unused vertices.
|
|
11558
|
+
*
|
|
11559
|
+
* @type {number}
|
|
11560
|
+
* @readonly
|
|
11561
|
+
*/
|
|
11562
|
+
get unusedVertexCount() {
|
|
11563
|
+
return this._maxVertexCount - this._nextVertexStart;
|
|
11564
|
+
}
|
|
11565
|
+
/**
|
|
11566
|
+
* The number of unused indices.
|
|
11567
|
+
*
|
|
11568
|
+
* @type {number}
|
|
11569
|
+
* @readonly
|
|
11570
|
+
*/
|
|
11571
|
+
get unusedIndexCount() {
|
|
11572
|
+
return this._maxIndexCount - this._nextIndexStart;
|
|
11573
|
+
}
|
|
11574
|
+
_initMatricesTexture() {
|
|
11575
|
+
let size = Math.sqrt(this._maxInstanceCount * 4);
|
|
11576
|
+
size = Math.ceil(size / 4) * 4;
|
|
11577
|
+
size = Math.max(size, 4);
|
|
11578
|
+
const matricesArray = new Float32Array(size * size * 4);
|
|
11579
|
+
const matricesTexture = new DataTexture(matricesArray, size, size, RGBAFormat, FloatType);
|
|
11580
|
+
this._matricesTexture = matricesTexture;
|
|
11581
|
+
}
|
|
11582
|
+
_initIndirectTexture() {
|
|
11583
|
+
let size = Math.sqrt(this._maxInstanceCount);
|
|
11584
|
+
size = Math.ceil(size);
|
|
11585
|
+
const indirectArray = new Uint32Array(size * size);
|
|
11586
|
+
const indirectTexture = new DataTexture(indirectArray, size, size, RedIntegerFormat, UnsignedIntType);
|
|
11587
|
+
this._indirectTexture = indirectTexture;
|
|
11588
|
+
}
|
|
11589
|
+
_initColorsTexture() {
|
|
11590
|
+
let size = Math.sqrt(this._maxInstanceCount);
|
|
11591
|
+
size = Math.ceil(size);
|
|
11592
|
+
const colorsArray = new Float32Array(size * size * 4).fill(1);
|
|
11593
|
+
const colorsTexture = new DataTexture(colorsArray, size, size, RGBAFormat, FloatType);
|
|
11594
|
+
colorsTexture.colorSpace = ColorManagement.workingColorSpace;
|
|
11595
|
+
this._colorsTexture = colorsTexture;
|
|
11596
|
+
}
|
|
11597
|
+
_initializeGeometry(reference) {
|
|
11598
|
+
const geometry = this.geometry;
|
|
11599
|
+
const maxVertexCount = this._maxVertexCount;
|
|
11600
|
+
const maxIndexCount = this._maxIndexCount;
|
|
11601
|
+
if (this._geometryInitialized === false) {
|
|
11602
|
+
for (const attributeName in reference.attributes) {
|
|
11603
|
+
const srcAttribute = reference.getAttribute(attributeName);
|
|
11604
|
+
const { array, itemSize, normalized } = srcAttribute;
|
|
11605
|
+
const dstArray = new array.constructor(maxVertexCount * itemSize);
|
|
11606
|
+
const dstAttribute = new BufferAttribute(dstArray, itemSize, normalized);
|
|
11607
|
+
geometry.setAttribute(attributeName, dstAttribute);
|
|
11608
|
+
}
|
|
11609
|
+
if (reference.getIndex() !== null) {
|
|
11610
|
+
const indexArray = maxVertexCount > 65535 ? new Uint32Array(maxIndexCount) : new Uint16Array(maxIndexCount);
|
|
11611
|
+
geometry.setIndex(new BufferAttribute(indexArray, 1));
|
|
11612
|
+
}
|
|
11613
|
+
this._geometryInitialized = true;
|
|
11614
|
+
}
|
|
11615
|
+
}
|
|
11616
|
+
// Make sure the geometry is compatible with the existing combined geometry attributes
|
|
11617
|
+
_validateGeometry(geometry) {
|
|
11618
|
+
const batchGeometry = this.geometry;
|
|
11619
|
+
if (Boolean(geometry.getIndex()) !== Boolean(batchGeometry.getIndex())) {
|
|
11620
|
+
throw new Error('THREE.BatchedMesh: All geometries must consistently have "index".');
|
|
11621
|
+
}
|
|
11622
|
+
for (const attributeName in batchGeometry.attributes) {
|
|
11623
|
+
if (!geometry.hasAttribute(attributeName)) {
|
|
11624
|
+
throw new Error(`THREE.BatchedMesh: Added geometry missing "${attributeName}". All geometries must have consistent attributes.`);
|
|
11625
|
+
}
|
|
11626
|
+
const srcAttribute = geometry.getAttribute(attributeName);
|
|
11627
|
+
const dstAttribute = batchGeometry.getAttribute(attributeName);
|
|
11628
|
+
if (srcAttribute.itemSize !== dstAttribute.itemSize || srcAttribute.normalized !== dstAttribute.normalized) {
|
|
11629
|
+
throw new Error("THREE.BatchedMesh: All attributes must have a consistent itemSize and normalized value.");
|
|
11630
|
+
}
|
|
11631
|
+
}
|
|
11632
|
+
}
|
|
11633
|
+
/**
|
|
11634
|
+
* Validates the instance defined by the given ID.
|
|
11635
|
+
*
|
|
11636
|
+
* @param {number} instanceId - The instance to validate.
|
|
11637
|
+
*/
|
|
11638
|
+
validateInstanceId(instanceId) {
|
|
11639
|
+
const instanceInfo = this._instanceInfo;
|
|
11640
|
+
if (instanceId < 0 || instanceId >= instanceInfo.length || instanceInfo[instanceId].active === false) {
|
|
11641
|
+
throw new Error(`THREE.BatchedMesh: Invalid instanceId ${instanceId}. Instance is either out of range or has been deleted.`);
|
|
11642
|
+
}
|
|
11643
|
+
}
|
|
11644
|
+
/**
|
|
11645
|
+
* Validates the geometry defined by the given ID.
|
|
11646
|
+
*
|
|
11647
|
+
* @param {number} geometryId - The geometry to validate.
|
|
11648
|
+
*/
|
|
11649
|
+
validateGeometryId(geometryId) {
|
|
11650
|
+
const geometryInfoList = this._geometryInfo;
|
|
11651
|
+
if (geometryId < 0 || geometryId >= geometryInfoList.length || geometryInfoList[geometryId].active === false) {
|
|
11652
|
+
throw new Error(`THREE.BatchedMesh: Invalid geometryId ${geometryId}. Geometry is either out of range or has been deleted.`);
|
|
11653
|
+
}
|
|
11654
|
+
}
|
|
11655
|
+
/**
|
|
11656
|
+
* Takes a sort a function that is run before render. The function takes a list of instances to
|
|
11657
|
+
* sort and a camera. The objects in the list include a "z" field to perform a depth-ordered sort with.
|
|
11658
|
+
*
|
|
11659
|
+
* @param {Function} func - The custom sort function.
|
|
11660
|
+
* @return {BatchedMesh} A reference to this batched mesh.
|
|
11661
|
+
*/
|
|
11662
|
+
setCustomSort(func) {
|
|
11663
|
+
this.customSort = func;
|
|
11664
|
+
return this;
|
|
11665
|
+
}
|
|
11666
|
+
/**
|
|
11667
|
+
* Computes the bounding box, updating {@link BatchedMesh#boundingBox}.
|
|
11668
|
+
* Bounding boxes aren't computed by default. They need to be explicitly computed,
|
|
11669
|
+
* otherwise they are `null`.
|
|
11670
|
+
*/
|
|
11671
|
+
computeBoundingBox() {
|
|
11672
|
+
if (this.boundingBox === null) {
|
|
11673
|
+
this.boundingBox = new Box3();
|
|
11674
|
+
}
|
|
11675
|
+
const boundingBox2 = this.boundingBox;
|
|
11676
|
+
const instanceInfo = this._instanceInfo;
|
|
11677
|
+
boundingBox2.makeEmpty();
|
|
11678
|
+
for (let i = 0, l = instanceInfo.length; i < l; i++) {
|
|
11679
|
+
if (instanceInfo[i].active === false) continue;
|
|
11680
|
+
const geometryId = instanceInfo[i].geometryIndex;
|
|
11681
|
+
this.getMatrixAt(i, _matrix$1);
|
|
11682
|
+
this.getBoundingBoxAt(geometryId, _box$1).applyMatrix4(_matrix$1);
|
|
11683
|
+
boundingBox2.union(_box$1);
|
|
11684
|
+
}
|
|
11685
|
+
}
|
|
11686
|
+
/**
|
|
11687
|
+
* Computes the bounding sphere, updating {@link BatchedMesh#boundingSphere}.
|
|
11688
|
+
* Bounding spheres aren't computed by default. They need to be explicitly computed,
|
|
11689
|
+
* otherwise they are `null`.
|
|
11690
|
+
*/
|
|
11691
|
+
computeBoundingSphere() {
|
|
11692
|
+
if (this.boundingSphere === null) {
|
|
11693
|
+
this.boundingSphere = new Sphere();
|
|
11694
|
+
}
|
|
11695
|
+
const boundingSphere = this.boundingSphere;
|
|
11696
|
+
const instanceInfo = this._instanceInfo;
|
|
11697
|
+
boundingSphere.makeEmpty();
|
|
11698
|
+
for (let i = 0, l = instanceInfo.length; i < l; i++) {
|
|
11699
|
+
if (instanceInfo[i].active === false) continue;
|
|
11700
|
+
const geometryId = instanceInfo[i].geometryIndex;
|
|
11701
|
+
this.getMatrixAt(i, _matrix$1);
|
|
11702
|
+
this.getBoundingSphereAt(geometryId, _sphere$2).applyMatrix4(_matrix$1);
|
|
11703
|
+
boundingSphere.union(_sphere$2);
|
|
11704
|
+
}
|
|
11705
|
+
}
|
|
11706
|
+
/**
|
|
11707
|
+
* Adds a new instance to the batch using the geometry of the given ID and returns
|
|
11708
|
+
* a new id referring to the new instance to be used by other functions.
|
|
11709
|
+
*
|
|
11710
|
+
* @param {number} geometryId - The ID of a previously added geometry via {@link BatchedMesh#addGeometry}.
|
|
11711
|
+
* @return {number} The instance ID.
|
|
11712
|
+
*/
|
|
11713
|
+
addInstance(geometryId) {
|
|
11714
|
+
const atCapacity = this._instanceInfo.length >= this.maxInstanceCount;
|
|
11715
|
+
if (atCapacity && this._availableInstanceIds.length === 0) {
|
|
11716
|
+
throw new Error("THREE.BatchedMesh: Maximum item count reached.");
|
|
11717
|
+
}
|
|
11718
|
+
const instanceInfo = {
|
|
11719
|
+
visible: true,
|
|
11720
|
+
active: true,
|
|
11721
|
+
geometryIndex: geometryId
|
|
11722
|
+
};
|
|
11723
|
+
let drawId = null;
|
|
11724
|
+
if (this._availableInstanceIds.length > 0) {
|
|
11725
|
+
this._availableInstanceIds.sort(ascIdSort);
|
|
11726
|
+
drawId = this._availableInstanceIds.shift();
|
|
11727
|
+
this._instanceInfo[drawId] = instanceInfo;
|
|
11728
|
+
} else {
|
|
11729
|
+
drawId = this._instanceInfo.length;
|
|
11730
|
+
this._instanceInfo.push(instanceInfo);
|
|
11731
|
+
}
|
|
11732
|
+
const matricesTexture = this._matricesTexture;
|
|
11733
|
+
_matrix$1.identity().toArray(matricesTexture.image.data, drawId * 16);
|
|
11734
|
+
matricesTexture.needsUpdate = true;
|
|
11735
|
+
const colorsTexture = this._colorsTexture;
|
|
11736
|
+
if (colorsTexture) {
|
|
11737
|
+
_whiteColor.toArray(colorsTexture.image.data, drawId * 4);
|
|
11738
|
+
colorsTexture.needsUpdate = true;
|
|
11739
|
+
}
|
|
11740
|
+
this._visibilityChanged = true;
|
|
11741
|
+
return drawId;
|
|
11742
|
+
}
|
|
11743
|
+
/**
|
|
11744
|
+
* Adds the given geometry to the batch and returns the associated
|
|
11745
|
+
* geometry id referring to it to be used in other functions.
|
|
11746
|
+
*
|
|
11747
|
+
* @param {BufferGeometry} geometry - The geometry to add.
|
|
11748
|
+
* @param {number} [reservedVertexCount=-1] - Optional parameter specifying the amount of
|
|
11749
|
+
* vertex buffer space to reserve for the added geometry. This is necessary if it is planned
|
|
11750
|
+
* to set a new geometry at this index at a later time that is larger than the original geometry.
|
|
11751
|
+
* Defaults to the length of the given geometry vertex buffer.
|
|
11752
|
+
* @param {number} [reservedIndexCount=-1] - Optional parameter specifying the amount of index
|
|
11753
|
+
* buffer space to reserve for the added geometry. This is necessary if it is planned to set a
|
|
11754
|
+
* new geometry at this index at a later time that is larger than the original geometry. Defaults to
|
|
11755
|
+
* the length of the given geometry index buffer.
|
|
11756
|
+
* @return {number} The geometry ID.
|
|
11757
|
+
*/
|
|
11758
|
+
addGeometry(geometry, reservedVertexCount = -1, reservedIndexCount = -1) {
|
|
11759
|
+
this._initializeGeometry(geometry);
|
|
11760
|
+
this._validateGeometry(geometry);
|
|
11761
|
+
const geometryInfo = {
|
|
11762
|
+
// geometry information
|
|
11763
|
+
vertexStart: -1,
|
|
11764
|
+
vertexCount: -1,
|
|
11765
|
+
reservedVertexCount: -1,
|
|
11766
|
+
indexStart: -1,
|
|
11767
|
+
indexCount: -1,
|
|
11768
|
+
reservedIndexCount: -1,
|
|
11769
|
+
// draw range information
|
|
11770
|
+
start: -1,
|
|
11771
|
+
count: -1,
|
|
11772
|
+
// state
|
|
11773
|
+
boundingBox: null,
|
|
11774
|
+
boundingSphere: null,
|
|
11775
|
+
active: true
|
|
11776
|
+
};
|
|
11777
|
+
const geometryInfoList = this._geometryInfo;
|
|
11778
|
+
geometryInfo.vertexStart = this._nextVertexStart;
|
|
11779
|
+
geometryInfo.reservedVertexCount = reservedVertexCount === -1 ? geometry.getAttribute("position").count : reservedVertexCount;
|
|
11780
|
+
const index2 = geometry.getIndex();
|
|
11781
|
+
const hasIndex = index2 !== null;
|
|
11782
|
+
if (hasIndex) {
|
|
11783
|
+
geometryInfo.indexStart = this._nextIndexStart;
|
|
11784
|
+
geometryInfo.reservedIndexCount = reservedIndexCount === -1 ? index2.count : reservedIndexCount;
|
|
11785
|
+
}
|
|
11786
|
+
if (geometryInfo.indexStart !== -1 && geometryInfo.indexStart + geometryInfo.reservedIndexCount > this._maxIndexCount || geometryInfo.vertexStart + geometryInfo.reservedVertexCount > this._maxVertexCount) {
|
|
11787
|
+
throw new Error("THREE.BatchedMesh: Reserved space request exceeds the maximum buffer size.");
|
|
11788
|
+
}
|
|
11789
|
+
let geometryId;
|
|
11790
|
+
if (this._availableGeometryIds.length > 0) {
|
|
11791
|
+
this._availableGeometryIds.sort(ascIdSort);
|
|
11792
|
+
geometryId = this._availableGeometryIds.shift();
|
|
11793
|
+
geometryInfoList[geometryId] = geometryInfo;
|
|
11794
|
+
} else {
|
|
11795
|
+
geometryId = this._geometryCount;
|
|
11796
|
+
this._geometryCount++;
|
|
11797
|
+
geometryInfoList.push(geometryInfo);
|
|
11798
|
+
}
|
|
11799
|
+
this.setGeometryAt(geometryId, geometry);
|
|
11800
|
+
this._nextIndexStart = geometryInfo.indexStart + geometryInfo.reservedIndexCount;
|
|
11801
|
+
this._nextVertexStart = geometryInfo.vertexStart + geometryInfo.reservedVertexCount;
|
|
11802
|
+
return geometryId;
|
|
11803
|
+
}
|
|
11804
|
+
/**
|
|
11805
|
+
* Replaces the geometry at the given ID with the provided geometry. Throws an error if there
|
|
11806
|
+
* is not enough space reserved for geometry. Calling this will change all instances that are
|
|
11807
|
+
* rendering that geometry.
|
|
11808
|
+
*
|
|
11809
|
+
* @param {number} geometryId - The ID of the geometry that should be replaced with the given geometry.
|
|
11810
|
+
* @param {BufferGeometry} geometry - The new geometry.
|
|
11811
|
+
* @return {number} The geometry ID.
|
|
11812
|
+
*/
|
|
11813
|
+
setGeometryAt(geometryId, geometry) {
|
|
11814
|
+
if (geometryId >= this._geometryCount) {
|
|
11815
|
+
throw new Error("THREE.BatchedMesh: Maximum geometry count reached.");
|
|
11816
|
+
}
|
|
11817
|
+
this._validateGeometry(geometry);
|
|
11818
|
+
const batchGeometry = this.geometry;
|
|
11819
|
+
const hasIndex = batchGeometry.getIndex() !== null;
|
|
11820
|
+
const dstIndex = batchGeometry.getIndex();
|
|
11821
|
+
const srcIndex = geometry.getIndex();
|
|
11822
|
+
const geometryInfo = this._geometryInfo[geometryId];
|
|
11823
|
+
if (hasIndex && srcIndex.count > geometryInfo.reservedIndexCount || geometry.attributes.position.count > geometryInfo.reservedVertexCount) {
|
|
11824
|
+
throw new Error("THREE.BatchedMesh: Reserved space not large enough for provided geometry.");
|
|
11825
|
+
}
|
|
11826
|
+
const vertexStart = geometryInfo.vertexStart;
|
|
11827
|
+
const reservedVertexCount = geometryInfo.reservedVertexCount;
|
|
11828
|
+
geometryInfo.vertexCount = geometry.getAttribute("position").count;
|
|
11829
|
+
for (const attributeName in batchGeometry.attributes) {
|
|
11830
|
+
const srcAttribute = geometry.getAttribute(attributeName);
|
|
11831
|
+
const dstAttribute = batchGeometry.getAttribute(attributeName);
|
|
11832
|
+
copyAttributeData(srcAttribute, dstAttribute, vertexStart);
|
|
11833
|
+
const itemSize = srcAttribute.itemSize;
|
|
11834
|
+
for (let i = srcAttribute.count, l = reservedVertexCount; i < l; i++) {
|
|
11835
|
+
const index2 = vertexStart + i;
|
|
11836
|
+
for (let c2 = 0; c2 < itemSize; c2++) {
|
|
11837
|
+
dstAttribute.setComponent(index2, c2, 0);
|
|
11838
|
+
}
|
|
11839
|
+
}
|
|
11840
|
+
dstAttribute.needsUpdate = true;
|
|
11841
|
+
dstAttribute.addUpdateRange(vertexStart * itemSize, reservedVertexCount * itemSize);
|
|
11842
|
+
}
|
|
11843
|
+
if (hasIndex) {
|
|
11844
|
+
const indexStart = geometryInfo.indexStart;
|
|
11845
|
+
const reservedIndexCount = geometryInfo.reservedIndexCount;
|
|
11846
|
+
geometryInfo.indexCount = geometry.getIndex().count;
|
|
11847
|
+
for (let i = 0; i < srcIndex.count; i++) {
|
|
11848
|
+
dstIndex.setX(indexStart + i, vertexStart + srcIndex.getX(i));
|
|
11849
|
+
}
|
|
11850
|
+
for (let i = srcIndex.count, l = reservedIndexCount; i < l; i++) {
|
|
11851
|
+
dstIndex.setX(indexStart + i, vertexStart);
|
|
11852
|
+
}
|
|
11853
|
+
dstIndex.needsUpdate = true;
|
|
11854
|
+
dstIndex.addUpdateRange(indexStart, geometryInfo.reservedIndexCount);
|
|
11855
|
+
}
|
|
11856
|
+
geometryInfo.start = hasIndex ? geometryInfo.indexStart : geometryInfo.vertexStart;
|
|
11857
|
+
geometryInfo.count = hasIndex ? geometryInfo.indexCount : geometryInfo.vertexCount;
|
|
11858
|
+
geometryInfo.boundingBox = null;
|
|
11859
|
+
if (geometry.boundingBox !== null) {
|
|
11860
|
+
geometryInfo.boundingBox = geometry.boundingBox.clone();
|
|
11861
|
+
}
|
|
11862
|
+
geometryInfo.boundingSphere = null;
|
|
11863
|
+
if (geometry.boundingSphere !== null) {
|
|
11864
|
+
geometryInfo.boundingSphere = geometry.boundingSphere.clone();
|
|
11865
|
+
}
|
|
11866
|
+
this._visibilityChanged = true;
|
|
11867
|
+
return geometryId;
|
|
11868
|
+
}
|
|
11869
|
+
/**
|
|
11870
|
+
* Deletes the geometry defined by the given ID from this batch. Any instances referencing
|
|
11871
|
+
* this geometry will also be removed as a side effect.
|
|
11872
|
+
*
|
|
11873
|
+
* @param {number} geometryId - The ID of the geometry to remove from the batch.
|
|
11874
|
+
* @return {BatchedMesh} A reference to this batched mesh.
|
|
11875
|
+
*/
|
|
11876
|
+
deleteGeometry(geometryId) {
|
|
11877
|
+
const geometryInfoList = this._geometryInfo;
|
|
11878
|
+
if (geometryId >= geometryInfoList.length || geometryInfoList[geometryId].active === false) {
|
|
11879
|
+
return this;
|
|
11880
|
+
}
|
|
11881
|
+
const instanceInfo = this._instanceInfo;
|
|
11882
|
+
for (let i = 0, l = instanceInfo.length; i < l; i++) {
|
|
11883
|
+
if (instanceInfo[i].active && instanceInfo[i].geometryIndex === geometryId) {
|
|
11884
|
+
this.deleteInstance(i);
|
|
11885
|
+
}
|
|
11886
|
+
}
|
|
11887
|
+
geometryInfoList[geometryId].active = false;
|
|
11888
|
+
this._availableGeometryIds.push(geometryId);
|
|
11889
|
+
this._visibilityChanged = true;
|
|
11890
|
+
return this;
|
|
11891
|
+
}
|
|
11892
|
+
/**
|
|
11893
|
+
* Deletes an existing instance from the batch using the given ID.
|
|
11894
|
+
*
|
|
11895
|
+
* @param {number} instanceId - The ID of the instance to remove from the batch.
|
|
11896
|
+
* @return {BatchedMesh} A reference to this batched mesh.
|
|
11897
|
+
*/
|
|
11898
|
+
deleteInstance(instanceId) {
|
|
11899
|
+
this.validateInstanceId(instanceId);
|
|
11900
|
+
this._instanceInfo[instanceId].active = false;
|
|
11901
|
+
this._availableInstanceIds.push(instanceId);
|
|
11902
|
+
this._visibilityChanged = true;
|
|
11903
|
+
return this;
|
|
11904
|
+
}
|
|
11905
|
+
/**
|
|
11906
|
+
* Repacks the sub geometries in [name] to remove any unused space remaining from
|
|
11907
|
+
* previously deleted geometry, freeing up space to add new geometry.
|
|
11908
|
+
*
|
|
11909
|
+
* @param {number} instanceId - The ID of the instance to remove from the batch.
|
|
11910
|
+
* @return {BatchedMesh} A reference to this batched mesh.
|
|
11911
|
+
*/
|
|
11912
|
+
optimize() {
|
|
11913
|
+
let nextVertexStart = 0;
|
|
11914
|
+
let nextIndexStart = 0;
|
|
11915
|
+
const geometryInfoList = this._geometryInfo;
|
|
11916
|
+
const indices = geometryInfoList.map((e, i) => i).sort((a2, b) => {
|
|
11917
|
+
return geometryInfoList[a2].vertexStart - geometryInfoList[b].vertexStart;
|
|
11918
|
+
});
|
|
11919
|
+
const geometry = this.geometry;
|
|
11920
|
+
for (let i = 0, l = geometryInfoList.length; i < l; i++) {
|
|
11921
|
+
const index2 = indices[i];
|
|
11922
|
+
const geometryInfo = geometryInfoList[index2];
|
|
11923
|
+
if (geometryInfo.active === false) {
|
|
11924
|
+
continue;
|
|
11925
|
+
}
|
|
11926
|
+
if (geometry.index !== null) {
|
|
11927
|
+
if (geometryInfo.indexStart !== nextIndexStart) {
|
|
11928
|
+
const { indexStart, vertexStart, reservedIndexCount } = geometryInfo;
|
|
11929
|
+
const index3 = geometry.index;
|
|
11930
|
+
const array = index3.array;
|
|
11931
|
+
const elementDelta = nextVertexStart - vertexStart;
|
|
11932
|
+
for (let j = indexStart; j < indexStart + reservedIndexCount; j++) {
|
|
11933
|
+
array[j] = array[j] + elementDelta;
|
|
11934
|
+
}
|
|
11935
|
+
index3.array.copyWithin(nextIndexStart, indexStart, indexStart + reservedIndexCount);
|
|
11936
|
+
index3.addUpdateRange(nextIndexStart, reservedIndexCount);
|
|
11937
|
+
geometryInfo.indexStart = nextIndexStart;
|
|
11938
|
+
}
|
|
11939
|
+
nextIndexStart += geometryInfo.reservedIndexCount;
|
|
11940
|
+
}
|
|
11941
|
+
if (geometryInfo.vertexStart !== nextVertexStart) {
|
|
11942
|
+
const { vertexStart, reservedVertexCount } = geometryInfo;
|
|
11943
|
+
const attributes = geometry.attributes;
|
|
11944
|
+
for (const key2 in attributes) {
|
|
11945
|
+
const attribute = attributes[key2];
|
|
11946
|
+
const { array, itemSize } = attribute;
|
|
11947
|
+
array.copyWithin(nextVertexStart * itemSize, vertexStart * itemSize, (vertexStart + reservedVertexCount) * itemSize);
|
|
11948
|
+
attribute.addUpdateRange(nextVertexStart * itemSize, reservedVertexCount * itemSize);
|
|
11949
|
+
}
|
|
11950
|
+
geometryInfo.vertexStart = nextVertexStart;
|
|
11951
|
+
}
|
|
11952
|
+
nextVertexStart += geometryInfo.reservedVertexCount;
|
|
11953
|
+
geometryInfo.start = geometry.index ? geometryInfo.indexStart : geometryInfo.vertexStart;
|
|
11954
|
+
this._nextIndexStart = geometry.index ? geometryInfo.indexStart + geometryInfo.reservedIndexCount : 0;
|
|
11955
|
+
this._nextVertexStart = geometryInfo.vertexStart + geometryInfo.reservedVertexCount;
|
|
11956
|
+
}
|
|
11957
|
+
return this;
|
|
11958
|
+
}
|
|
11959
|
+
/**
|
|
11960
|
+
* Returns the bounding box for the given geometry.
|
|
11961
|
+
*
|
|
11962
|
+
* @param {number} geometryId - The ID of the geometry to return the bounding box for.
|
|
11963
|
+
* @param {Box3} target - The target object that is used to store the method's result.
|
|
11964
|
+
* @return {Box3|null} The geometry's bounding box. Returns `null` if no geometry has been found for the given ID.
|
|
11965
|
+
*/
|
|
11966
|
+
getBoundingBoxAt(geometryId, target) {
|
|
11967
|
+
if (geometryId >= this._geometryCount) {
|
|
11968
|
+
return null;
|
|
11969
|
+
}
|
|
11970
|
+
const geometry = this.geometry;
|
|
11971
|
+
const geometryInfo = this._geometryInfo[geometryId];
|
|
11972
|
+
if (geometryInfo.boundingBox === null) {
|
|
11973
|
+
const box = new Box3();
|
|
11974
|
+
const index2 = geometry.index;
|
|
11975
|
+
const position = geometry.attributes.position;
|
|
11976
|
+
for (let i = geometryInfo.start, l = geometryInfo.start + geometryInfo.count; i < l; i++) {
|
|
11977
|
+
let iv = i;
|
|
11978
|
+
if (index2) {
|
|
11979
|
+
iv = index2.getX(iv);
|
|
11980
|
+
}
|
|
11981
|
+
box.expandByPoint(_vector$5.fromBufferAttribute(position, iv));
|
|
11982
|
+
}
|
|
11983
|
+
geometryInfo.boundingBox = box;
|
|
11984
|
+
}
|
|
11985
|
+
target.copy(geometryInfo.boundingBox);
|
|
11986
|
+
return target;
|
|
11987
|
+
}
|
|
11988
|
+
/**
|
|
11989
|
+
* Returns the bounding sphere for the given geometry.
|
|
11990
|
+
*
|
|
11991
|
+
* @param {number} geometryId - The ID of the geometry to return the bounding sphere for.
|
|
11992
|
+
* @param {Sphere} target - The target object that is used to store the method's result.
|
|
11993
|
+
* @return {Sphere|null} The geometry's bounding sphere. Returns `null` if no geometry has been found for the given ID.
|
|
11994
|
+
*/
|
|
11995
|
+
getBoundingSphereAt(geometryId, target) {
|
|
11996
|
+
if (geometryId >= this._geometryCount) {
|
|
11997
|
+
return null;
|
|
11998
|
+
}
|
|
11999
|
+
const geometry = this.geometry;
|
|
12000
|
+
const geometryInfo = this._geometryInfo[geometryId];
|
|
12001
|
+
if (geometryInfo.boundingSphere === null) {
|
|
12002
|
+
const sphere = new Sphere();
|
|
12003
|
+
this.getBoundingBoxAt(geometryId, _box$1);
|
|
12004
|
+
_box$1.getCenter(sphere.center);
|
|
12005
|
+
const index2 = geometry.index;
|
|
12006
|
+
const position = geometry.attributes.position;
|
|
12007
|
+
let maxRadiusSq = 0;
|
|
12008
|
+
for (let i = geometryInfo.start, l = geometryInfo.start + geometryInfo.count; i < l; i++) {
|
|
12009
|
+
let iv = i;
|
|
12010
|
+
if (index2) {
|
|
12011
|
+
iv = index2.getX(iv);
|
|
12012
|
+
}
|
|
12013
|
+
_vector$5.fromBufferAttribute(position, iv);
|
|
12014
|
+
maxRadiusSq = Math.max(maxRadiusSq, sphere.center.distanceToSquared(_vector$5));
|
|
12015
|
+
}
|
|
12016
|
+
sphere.radius = Math.sqrt(maxRadiusSq);
|
|
12017
|
+
geometryInfo.boundingSphere = sphere;
|
|
12018
|
+
}
|
|
12019
|
+
target.copy(geometryInfo.boundingSphere);
|
|
12020
|
+
return target;
|
|
12021
|
+
}
|
|
12022
|
+
/**
|
|
12023
|
+
* Sets the given local transformation matrix to the defined instance.
|
|
12024
|
+
* Negatively scaled matrices are not supported.
|
|
12025
|
+
*
|
|
12026
|
+
* @param {number} instanceId - The ID of an instance to set the matrix of.
|
|
12027
|
+
* @param {Matrix4} matrix - A 4x4 matrix representing the local transformation of a single instance.
|
|
12028
|
+
* @return {BatchedMesh} A reference to this batched mesh.
|
|
12029
|
+
*/
|
|
12030
|
+
setMatrixAt(instanceId, matrix) {
|
|
12031
|
+
this.validateInstanceId(instanceId);
|
|
12032
|
+
const matricesTexture = this._matricesTexture;
|
|
12033
|
+
const matricesArray = this._matricesTexture.image.data;
|
|
12034
|
+
matrix.toArray(matricesArray, instanceId * 16);
|
|
12035
|
+
matricesTexture.needsUpdate = true;
|
|
12036
|
+
return this;
|
|
12037
|
+
}
|
|
12038
|
+
/**
|
|
12039
|
+
* Returns the local transformation matrix of the defined instance.
|
|
12040
|
+
*
|
|
12041
|
+
* @param {number} instanceId - The ID of an instance to get the matrix of.
|
|
12042
|
+
* @param {Matrix4} matrix - The target object that is used to store the method's result.
|
|
12043
|
+
* @return {Matrix4} The instance's local transformation matrix.
|
|
12044
|
+
*/
|
|
12045
|
+
getMatrixAt(instanceId, matrix) {
|
|
12046
|
+
this.validateInstanceId(instanceId);
|
|
12047
|
+
return matrix.fromArray(this._matricesTexture.image.data, instanceId * 16);
|
|
12048
|
+
}
|
|
12049
|
+
/**
|
|
12050
|
+
* Sets the given color to the defined instance.
|
|
12051
|
+
*
|
|
12052
|
+
* @param {number} instanceId - The ID of an instance to set the color of.
|
|
12053
|
+
* @param {Color} color - The color to set the instance to.
|
|
12054
|
+
* @return {BatchedMesh} A reference to this batched mesh.
|
|
12055
|
+
*/
|
|
12056
|
+
setColorAt(instanceId, color) {
|
|
12057
|
+
this.validateInstanceId(instanceId);
|
|
12058
|
+
if (this._colorsTexture === null) {
|
|
12059
|
+
this._initColorsTexture();
|
|
12060
|
+
}
|
|
12061
|
+
color.toArray(this._colorsTexture.image.data, instanceId * 4);
|
|
12062
|
+
this._colorsTexture.needsUpdate = true;
|
|
12063
|
+
return this;
|
|
12064
|
+
}
|
|
12065
|
+
/**
|
|
12066
|
+
* Returns the color of the defined instance.
|
|
12067
|
+
*
|
|
12068
|
+
* @param {number} instanceId - The ID of an instance to get the color of.
|
|
12069
|
+
* @param {Color} color - The target object that is used to store the method's result.
|
|
12070
|
+
* @return {Color} The instance's color.
|
|
12071
|
+
*/
|
|
12072
|
+
getColorAt(instanceId, color) {
|
|
12073
|
+
this.validateInstanceId(instanceId);
|
|
12074
|
+
return color.fromArray(this._colorsTexture.image.data, instanceId * 4);
|
|
12075
|
+
}
|
|
12076
|
+
/**
|
|
12077
|
+
* Sets the visibility of the instance.
|
|
12078
|
+
*
|
|
12079
|
+
* @param {number} instanceId - The id of the instance to set the visibility of.
|
|
12080
|
+
* @param {boolean} visible - Whether the instance is visible or not.
|
|
12081
|
+
* @return {BatchedMesh} A reference to this batched mesh.
|
|
12082
|
+
*/
|
|
12083
|
+
setVisibleAt(instanceId, visible) {
|
|
12084
|
+
this.validateInstanceId(instanceId);
|
|
12085
|
+
if (this._instanceInfo[instanceId].visible === visible) {
|
|
12086
|
+
return this;
|
|
12087
|
+
}
|
|
12088
|
+
this._instanceInfo[instanceId].visible = visible;
|
|
12089
|
+
this._visibilityChanged = true;
|
|
12090
|
+
return this;
|
|
12091
|
+
}
|
|
12092
|
+
/**
|
|
12093
|
+
* Returns the visibility state of the defined instance.
|
|
12094
|
+
*
|
|
12095
|
+
* @param {number} instanceId - The ID of an instance to get the visibility state of.
|
|
12096
|
+
* @return {boolean} Whether the instance is visible or not.
|
|
12097
|
+
*/
|
|
12098
|
+
getVisibleAt(instanceId) {
|
|
12099
|
+
this.validateInstanceId(instanceId);
|
|
12100
|
+
return this._instanceInfo[instanceId].visible;
|
|
12101
|
+
}
|
|
12102
|
+
/**
|
|
12103
|
+
* Sets the geometry ID of the instance at the given index.
|
|
12104
|
+
*
|
|
12105
|
+
* @param {number} instanceId - The ID of the instance to set the geometry ID of.
|
|
12106
|
+
* @param {number} geometryId - The geometry ID to be use by the instance.
|
|
12107
|
+
* @return {BatchedMesh} A reference to this batched mesh.
|
|
12108
|
+
*/
|
|
12109
|
+
setGeometryIdAt(instanceId, geometryId) {
|
|
12110
|
+
this.validateInstanceId(instanceId);
|
|
12111
|
+
this.validateGeometryId(geometryId);
|
|
12112
|
+
this._instanceInfo[instanceId].geometryIndex = geometryId;
|
|
12113
|
+
return this;
|
|
12114
|
+
}
|
|
12115
|
+
/**
|
|
12116
|
+
* Returns the geometry ID of the defined instance.
|
|
12117
|
+
*
|
|
12118
|
+
* @param {number} instanceId - The ID of an instance to get the geometry ID of.
|
|
12119
|
+
* @return {number} The instance's geometry ID.
|
|
12120
|
+
*/
|
|
12121
|
+
getGeometryIdAt(instanceId) {
|
|
12122
|
+
this.validateInstanceId(instanceId);
|
|
12123
|
+
return this._instanceInfo[instanceId].geometryIndex;
|
|
12124
|
+
}
|
|
12125
|
+
/**
|
|
12126
|
+
* Get the range representing the subset of triangles related to the attached geometry,
|
|
12127
|
+
* indicating the starting offset and count, or `null` if invalid.
|
|
12128
|
+
*
|
|
12129
|
+
* @param {number} geometryId - The id of the geometry to get the range of.
|
|
12130
|
+
* @param {Object} [target] - The target object that is used to store the method's result.
|
|
12131
|
+
* @return {{
|
|
12132
|
+
* vertexStart:number,vertexCount:number,reservedVertexCount:number,
|
|
12133
|
+
* indexStart:number,indexCount:number,reservedIndexCount:number,
|
|
12134
|
+
* start:number,count:number
|
|
12135
|
+
* }} The result object with range data.
|
|
12136
|
+
*/
|
|
12137
|
+
getGeometryRangeAt(geometryId, target = {}) {
|
|
12138
|
+
this.validateGeometryId(geometryId);
|
|
12139
|
+
const geometryInfo = this._geometryInfo[geometryId];
|
|
12140
|
+
target.vertexStart = geometryInfo.vertexStart;
|
|
12141
|
+
target.vertexCount = geometryInfo.vertexCount;
|
|
12142
|
+
target.reservedVertexCount = geometryInfo.reservedVertexCount;
|
|
12143
|
+
target.indexStart = geometryInfo.indexStart;
|
|
12144
|
+
target.indexCount = geometryInfo.indexCount;
|
|
12145
|
+
target.reservedIndexCount = geometryInfo.reservedIndexCount;
|
|
12146
|
+
target.start = geometryInfo.start;
|
|
12147
|
+
target.count = geometryInfo.count;
|
|
12148
|
+
return target;
|
|
12149
|
+
}
|
|
12150
|
+
/**
|
|
12151
|
+
* Resizes the necessary buffers to support the provided number of instances.
|
|
12152
|
+
* If the provided arguments shrink the number of instances but there are not enough
|
|
12153
|
+
* unused Ids at the end of the list then an error is thrown.
|
|
12154
|
+
*
|
|
12155
|
+
* @param {number} maxInstanceCount - The max number of individual instances that can be added and rendered by the batch.
|
|
12156
|
+
*/
|
|
12157
|
+
setInstanceCount(maxInstanceCount) {
|
|
12158
|
+
const availableInstanceIds = this._availableInstanceIds;
|
|
12159
|
+
const instanceInfo = this._instanceInfo;
|
|
12160
|
+
availableInstanceIds.sort(ascIdSort);
|
|
12161
|
+
while (availableInstanceIds[availableInstanceIds.length - 1] === instanceInfo.length) {
|
|
12162
|
+
instanceInfo.pop();
|
|
12163
|
+
availableInstanceIds.pop();
|
|
12164
|
+
}
|
|
12165
|
+
if (maxInstanceCount < instanceInfo.length) {
|
|
12166
|
+
throw new Error(`BatchedMesh: Instance ids outside the range ${maxInstanceCount} are being used. Cannot shrink instance count.`);
|
|
12167
|
+
}
|
|
12168
|
+
const multiDrawCounts = new Int32Array(maxInstanceCount);
|
|
12169
|
+
const multiDrawStarts = new Int32Array(maxInstanceCount);
|
|
12170
|
+
copyArrayContents(this._multiDrawCounts, multiDrawCounts);
|
|
12171
|
+
copyArrayContents(this._multiDrawStarts, multiDrawStarts);
|
|
12172
|
+
this._multiDrawCounts = multiDrawCounts;
|
|
12173
|
+
this._multiDrawStarts = multiDrawStarts;
|
|
12174
|
+
this._maxInstanceCount = maxInstanceCount;
|
|
12175
|
+
const indirectTexture = this._indirectTexture;
|
|
12176
|
+
const matricesTexture = this._matricesTexture;
|
|
12177
|
+
const colorsTexture = this._colorsTexture;
|
|
12178
|
+
indirectTexture.dispose();
|
|
12179
|
+
this._initIndirectTexture();
|
|
12180
|
+
copyArrayContents(indirectTexture.image.data, this._indirectTexture.image.data);
|
|
12181
|
+
matricesTexture.dispose();
|
|
12182
|
+
this._initMatricesTexture();
|
|
12183
|
+
copyArrayContents(matricesTexture.image.data, this._matricesTexture.image.data);
|
|
12184
|
+
if (colorsTexture) {
|
|
12185
|
+
colorsTexture.dispose();
|
|
12186
|
+
this._initColorsTexture();
|
|
12187
|
+
copyArrayContents(colorsTexture.image.data, this._colorsTexture.image.data);
|
|
12188
|
+
}
|
|
12189
|
+
}
|
|
12190
|
+
/**
|
|
12191
|
+
* Resizes the available space in the batch's vertex and index buffer attributes to the provided sizes.
|
|
12192
|
+
* If the provided arguments shrink the geometry buffers but there is not enough unused space at the
|
|
12193
|
+
* end of the geometry attributes then an error is thrown.
|
|
12194
|
+
*
|
|
12195
|
+
* @param {number} maxVertexCount - The maximum number of vertices to be used by all unique geometries to resize to.
|
|
12196
|
+
* @param {number} maxIndexCount - The maximum number of indices to be used by all unique geometries to resize to.
|
|
12197
|
+
*/
|
|
12198
|
+
setGeometrySize(maxVertexCount, maxIndexCount) {
|
|
12199
|
+
const validRanges = [...this._geometryInfo].filter((info) => info.active);
|
|
12200
|
+
const requiredVertexLength = Math.max(...validRanges.map((range) => range.vertexStart + range.reservedVertexCount));
|
|
12201
|
+
if (requiredVertexLength > maxVertexCount) {
|
|
12202
|
+
throw new Error(`BatchedMesh: Geometry vertex values are being used outside the range ${maxIndexCount}. Cannot shrink further.`);
|
|
12203
|
+
}
|
|
12204
|
+
if (this.geometry.index) {
|
|
12205
|
+
const requiredIndexLength = Math.max(...validRanges.map((range) => range.indexStart + range.reservedIndexCount));
|
|
12206
|
+
if (requiredIndexLength > maxIndexCount) {
|
|
12207
|
+
throw new Error(`BatchedMesh: Geometry index values are being used outside the range ${maxIndexCount}. Cannot shrink further.`);
|
|
12208
|
+
}
|
|
12209
|
+
}
|
|
12210
|
+
const oldGeometry = this.geometry;
|
|
12211
|
+
oldGeometry.dispose();
|
|
12212
|
+
this._maxVertexCount = maxVertexCount;
|
|
12213
|
+
this._maxIndexCount = maxIndexCount;
|
|
12214
|
+
if (this._geometryInitialized) {
|
|
12215
|
+
this._geometryInitialized = false;
|
|
12216
|
+
this.geometry = new BufferGeometry();
|
|
12217
|
+
this._initializeGeometry(oldGeometry);
|
|
12218
|
+
}
|
|
12219
|
+
const geometry = this.geometry;
|
|
12220
|
+
if (oldGeometry.index) {
|
|
12221
|
+
copyArrayContents(oldGeometry.index.array, geometry.index.array);
|
|
12222
|
+
}
|
|
12223
|
+
for (const key2 in oldGeometry.attributes) {
|
|
12224
|
+
copyArrayContents(oldGeometry.attributes[key2].array, geometry.attributes[key2].array);
|
|
12225
|
+
}
|
|
12226
|
+
}
|
|
12227
|
+
raycast(raycaster, intersects) {
|
|
12228
|
+
const instanceInfo = this._instanceInfo;
|
|
12229
|
+
const geometryInfoList = this._geometryInfo;
|
|
12230
|
+
const matrixWorld = this.matrixWorld;
|
|
12231
|
+
const batchGeometry = this.geometry;
|
|
12232
|
+
_mesh$1.material = this.material;
|
|
12233
|
+
_mesh$1.geometry.index = batchGeometry.index;
|
|
12234
|
+
_mesh$1.geometry.attributes = batchGeometry.attributes;
|
|
12235
|
+
if (_mesh$1.geometry.boundingBox === null) {
|
|
12236
|
+
_mesh$1.geometry.boundingBox = new Box3();
|
|
12237
|
+
}
|
|
12238
|
+
if (_mesh$1.geometry.boundingSphere === null) {
|
|
12239
|
+
_mesh$1.geometry.boundingSphere = new Sphere();
|
|
12240
|
+
}
|
|
12241
|
+
for (let i = 0, l = instanceInfo.length; i < l; i++) {
|
|
12242
|
+
if (!instanceInfo[i].visible || !instanceInfo[i].active) {
|
|
12243
|
+
continue;
|
|
12244
|
+
}
|
|
12245
|
+
const geometryId = instanceInfo[i].geometryIndex;
|
|
12246
|
+
const geometryInfo = geometryInfoList[geometryId];
|
|
12247
|
+
_mesh$1.geometry.setDrawRange(geometryInfo.start, geometryInfo.count);
|
|
12248
|
+
this.getMatrixAt(i, _mesh$1.matrixWorld).premultiply(matrixWorld);
|
|
12249
|
+
this.getBoundingBoxAt(geometryId, _mesh$1.geometry.boundingBox);
|
|
12250
|
+
this.getBoundingSphereAt(geometryId, _mesh$1.geometry.boundingSphere);
|
|
12251
|
+
_mesh$1.raycast(raycaster, _batchIntersects$1);
|
|
12252
|
+
for (let j = 0, l2 = _batchIntersects$1.length; j < l2; j++) {
|
|
12253
|
+
const intersect2 = _batchIntersects$1[j];
|
|
12254
|
+
intersect2.object = this;
|
|
12255
|
+
intersect2.batchId = i;
|
|
12256
|
+
intersects.push(intersect2);
|
|
12257
|
+
}
|
|
12258
|
+
_batchIntersects$1.length = 0;
|
|
12259
|
+
}
|
|
12260
|
+
_mesh$1.material = null;
|
|
12261
|
+
_mesh$1.geometry.index = null;
|
|
12262
|
+
_mesh$1.geometry.attributes = {};
|
|
12263
|
+
_mesh$1.geometry.setDrawRange(0, Infinity);
|
|
12264
|
+
}
|
|
12265
|
+
copy(source) {
|
|
12266
|
+
super.copy(source);
|
|
12267
|
+
this.geometry = source.geometry.clone();
|
|
12268
|
+
this.perObjectFrustumCulled = source.perObjectFrustumCulled;
|
|
12269
|
+
this.sortObjects = source.sortObjects;
|
|
12270
|
+
this.boundingBox = source.boundingBox !== null ? source.boundingBox.clone() : null;
|
|
12271
|
+
this.boundingSphere = source.boundingSphere !== null ? source.boundingSphere.clone() : null;
|
|
12272
|
+
this._geometryInfo = source._geometryInfo.map((info) => ({
|
|
12273
|
+
...info,
|
|
12274
|
+
boundingBox: info.boundingBox !== null ? info.boundingBox.clone() : null,
|
|
12275
|
+
boundingSphere: info.boundingSphere !== null ? info.boundingSphere.clone() : null
|
|
12276
|
+
}));
|
|
12277
|
+
this._instanceInfo = source._instanceInfo.map((info) => ({ ...info }));
|
|
12278
|
+
this._maxInstanceCount = source._maxInstanceCount;
|
|
12279
|
+
this._maxVertexCount = source._maxVertexCount;
|
|
12280
|
+
this._maxIndexCount = source._maxIndexCount;
|
|
12281
|
+
this._geometryInitialized = source._geometryInitialized;
|
|
12282
|
+
this._geometryCount = source._geometryCount;
|
|
12283
|
+
this._multiDrawCounts = source._multiDrawCounts.slice();
|
|
12284
|
+
this._multiDrawStarts = source._multiDrawStarts.slice();
|
|
12285
|
+
this._matricesTexture = source._matricesTexture.clone();
|
|
12286
|
+
this._matricesTexture.image.data = this._matricesTexture.image.data.slice();
|
|
12287
|
+
if (this._colorsTexture !== null) {
|
|
12288
|
+
this._colorsTexture = source._colorsTexture.clone();
|
|
12289
|
+
this._colorsTexture.image.data = this._colorsTexture.image.data.slice();
|
|
12290
|
+
}
|
|
12291
|
+
return this;
|
|
12292
|
+
}
|
|
12293
|
+
/**
|
|
12294
|
+
* Frees the GPU-related resources allocated by this instance. Call this
|
|
12295
|
+
* method whenever this instance is no longer used in your app.
|
|
12296
|
+
*/
|
|
12297
|
+
dispose() {
|
|
12298
|
+
this.geometry.dispose();
|
|
12299
|
+
this._matricesTexture.dispose();
|
|
12300
|
+
this._matricesTexture = null;
|
|
12301
|
+
this._indirectTexture.dispose();
|
|
12302
|
+
this._indirectTexture = null;
|
|
12303
|
+
if (this._colorsTexture !== null) {
|
|
12304
|
+
this._colorsTexture.dispose();
|
|
12305
|
+
this._colorsTexture = null;
|
|
12306
|
+
}
|
|
12307
|
+
}
|
|
12308
|
+
onBeforeRender(renderer, scene, camera, geometry, material) {
|
|
12309
|
+
if (!this._visibilityChanged && !this.perObjectFrustumCulled && !this.sortObjects) {
|
|
12310
|
+
return;
|
|
12311
|
+
}
|
|
12312
|
+
const index2 = geometry.getIndex();
|
|
12313
|
+
const bytesPerElement = index2 === null ? 1 : index2.array.BYTES_PER_ELEMENT;
|
|
12314
|
+
const instanceInfo = this._instanceInfo;
|
|
12315
|
+
const multiDrawStarts = this._multiDrawStarts;
|
|
12316
|
+
const multiDrawCounts = this._multiDrawCounts;
|
|
12317
|
+
const geometryInfoList = this._geometryInfo;
|
|
12318
|
+
const perObjectFrustumCulled = this.perObjectFrustumCulled;
|
|
12319
|
+
const indirectTexture = this._indirectTexture;
|
|
12320
|
+
const indirectArray = indirectTexture.image.data;
|
|
12321
|
+
if (perObjectFrustumCulled) {
|
|
12322
|
+
_matrix$1.multiplyMatrices(camera.projectionMatrix, camera.matrixWorldInverse).multiply(this.matrixWorld);
|
|
12323
|
+
_frustum.setFromProjectionMatrix(
|
|
12324
|
+
_matrix$1,
|
|
12325
|
+
renderer.coordinateSystem
|
|
12326
|
+
);
|
|
12327
|
+
}
|
|
12328
|
+
let multiDrawCount = 0;
|
|
12329
|
+
if (this.sortObjects) {
|
|
12330
|
+
_matrix$1.copy(this.matrixWorld).invert();
|
|
12331
|
+
_vector$5.setFromMatrixPosition(camera.matrixWorld).applyMatrix4(_matrix$1);
|
|
12332
|
+
_forward.set(0, 0, -1).transformDirection(camera.matrixWorld).transformDirection(_matrix$1);
|
|
12333
|
+
for (let i = 0, l = instanceInfo.length; i < l; i++) {
|
|
12334
|
+
if (instanceInfo[i].visible && instanceInfo[i].active) {
|
|
12335
|
+
const geometryId = instanceInfo[i].geometryIndex;
|
|
12336
|
+
this.getMatrixAt(i, _matrix$1);
|
|
12337
|
+
this.getBoundingSphereAt(geometryId, _sphere$2).applyMatrix4(_matrix$1);
|
|
12338
|
+
let culled = false;
|
|
12339
|
+
if (perObjectFrustumCulled) {
|
|
12340
|
+
culled = !_frustum.intersectsSphere(_sphere$2);
|
|
12341
|
+
}
|
|
12342
|
+
if (!culled) {
|
|
12343
|
+
const geometryInfo = geometryInfoList[geometryId];
|
|
12344
|
+
const z2 = _temp.subVectors(_sphere$2.center, _vector$5).dot(_forward);
|
|
12345
|
+
_renderList.push(geometryInfo.start, geometryInfo.count, z2, i);
|
|
12346
|
+
}
|
|
12347
|
+
}
|
|
12348
|
+
}
|
|
12349
|
+
const list = _renderList.list;
|
|
12350
|
+
const customSort = this.customSort;
|
|
12351
|
+
if (customSort === null) {
|
|
12352
|
+
list.sort(material.transparent ? sortTransparent : sortOpaque);
|
|
12353
|
+
} else {
|
|
12354
|
+
customSort.call(this, list, camera);
|
|
12355
|
+
}
|
|
12356
|
+
for (let i = 0, l = list.length; i < l; i++) {
|
|
12357
|
+
const item = list[i];
|
|
12358
|
+
multiDrawStarts[multiDrawCount] = item.start * bytesPerElement;
|
|
12359
|
+
multiDrawCounts[multiDrawCount] = item.count;
|
|
12360
|
+
indirectArray[multiDrawCount] = item.index;
|
|
12361
|
+
multiDrawCount++;
|
|
12362
|
+
}
|
|
12363
|
+
_renderList.reset();
|
|
12364
|
+
} else {
|
|
12365
|
+
for (let i = 0, l = instanceInfo.length; i < l; i++) {
|
|
12366
|
+
if (instanceInfo[i].visible && instanceInfo[i].active) {
|
|
12367
|
+
const geometryId = instanceInfo[i].geometryIndex;
|
|
12368
|
+
let culled = false;
|
|
12369
|
+
if (perObjectFrustumCulled) {
|
|
12370
|
+
this.getMatrixAt(i, _matrix$1);
|
|
12371
|
+
this.getBoundingSphereAt(geometryId, _sphere$2).applyMatrix4(_matrix$1);
|
|
12372
|
+
culled = !_frustum.intersectsSphere(_sphere$2);
|
|
12373
|
+
}
|
|
12374
|
+
if (!culled) {
|
|
12375
|
+
const geometryInfo = geometryInfoList[geometryId];
|
|
12376
|
+
multiDrawStarts[multiDrawCount] = geometryInfo.start * bytesPerElement;
|
|
12377
|
+
multiDrawCounts[multiDrawCount] = geometryInfo.count;
|
|
12378
|
+
indirectArray[multiDrawCount] = i;
|
|
12379
|
+
multiDrawCount++;
|
|
12380
|
+
}
|
|
12381
|
+
}
|
|
12382
|
+
}
|
|
12383
|
+
}
|
|
12384
|
+
indirectTexture.needsUpdate = true;
|
|
12385
|
+
this._multiDrawCount = multiDrawCount;
|
|
12386
|
+
this._visibilityChanged = false;
|
|
12387
|
+
}
|
|
12388
|
+
onBeforeShadow(renderer, object, camera, shadowCamera, geometry, depthMaterial) {
|
|
12389
|
+
this.onBeforeRender(renderer, null, shadowCamera, geometry, depthMaterial);
|
|
12390
|
+
}
|
|
12391
|
+
}
|
|
11225
12392
|
const _matrix = /* @__PURE__ */ new Matrix4();
|
|
11226
12393
|
class Raycaster {
|
|
11227
12394
|
/**
|
|
@@ -11232,8 +12399,8 @@ class Raycaster {
|
|
|
11232
12399
|
* @param {number} [near=0] - All results returned are further away than near. Near can't be negative.
|
|
11233
12400
|
* @param {number} [far=Infinity] - All results returned are closer than far. Far can't be lower than near.
|
|
11234
12401
|
*/
|
|
11235
|
-
constructor(origin,
|
|
11236
|
-
this.ray = new Ray(origin,
|
|
12402
|
+
constructor(origin, direction2, near = 0, far = Infinity) {
|
|
12403
|
+
this.ray = new Ray(origin, direction2);
|
|
11237
12404
|
this.near = near;
|
|
11238
12405
|
this.far = far;
|
|
11239
12406
|
this.camera = null;
|
|
@@ -11252,8 +12419,8 @@ class Raycaster {
|
|
|
11252
12419
|
* @param {Vector3} origin - The origin vector where the ray casts from.
|
|
11253
12420
|
* @param {Vector3} direction - The (normalized) direction vector that gives direction to the ray.
|
|
11254
12421
|
*/
|
|
11255
|
-
set(origin,
|
|
11256
|
-
this.ray.set(origin,
|
|
12422
|
+
set(origin, direction2) {
|
|
12423
|
+
this.ray.set(origin, direction2);
|
|
11257
12424
|
}
|
|
11258
12425
|
/**
|
|
11259
12426
|
* Uses the given coordinates and camera to compute a new origin and direction for the internal ray.
|
|
@@ -11663,6 +12830,7 @@ function cloneTopologyRewritePropagation(propagation) {
|
|
|
11663
12830
|
}
|
|
11664
12831
|
function faceQueryRefsEqual(a2, b) {
|
|
11665
12832
|
if (a2 == null || b == null) return a2 == null && b == null;
|
|
12833
|
+
if (a2 === b) return true;
|
|
11666
12834
|
if (a2.kind !== b.kind) return false;
|
|
11667
12835
|
switch (a2.kind) {
|
|
11668
12836
|
case "canonical-face":
|
|
@@ -11679,6 +12847,7 @@ function faceQueryRefsEqual(a2, b) {
|
|
|
11679
12847
|
}
|
|
11680
12848
|
function edgeQueryRefsEqual(a2, b) {
|
|
11681
12849
|
if (a2 == null || b == null) return a2 == null && b == null;
|
|
12850
|
+
if (a2 === b) return true;
|
|
11682
12851
|
if (a2.kind !== b.kind) return false;
|
|
11683
12852
|
switch (a2.kind) {
|
|
11684
12853
|
case "tracked-edge":
|
|
@@ -12045,8 +13214,8 @@ function deriveSheetMetalModel(model) {
|
|
|
12045
13214
|
const trimStart = flanges.has(adjacent.start) ? model.cornerRelief.size : 0;
|
|
12046
13215
|
const trimEnd = flanges.has(adjacent.end) ? model.cornerRelief.size : 0;
|
|
12047
13216
|
const fullLength = edge === "top" || edge === "bottom" ? model.panel.width : model.panel.height;
|
|
12048
|
-
const
|
|
12049
|
-
if (!(
|
|
13217
|
+
const span2 = fullLength - trimStart - trimEnd;
|
|
13218
|
+
if (!(span2 > EPS$3)) {
|
|
12050
13219
|
throw new Error(
|
|
12051
13220
|
`${edgeDisplayName(edge)} loses all usable span after applying the defended rectangular corner relief size ${model.cornerRelief.size}.`
|
|
12052
13221
|
);
|
|
@@ -12058,7 +13227,7 @@ function deriveSheetMetalModel(model) {
|
|
|
12058
13227
|
bendAllowance,
|
|
12059
13228
|
trimStart,
|
|
12060
13229
|
trimEnd,
|
|
12061
|
-
span,
|
|
13230
|
+
span: span2,
|
|
12062
13231
|
centerAlongEdge: (trimStart - trimEnd) / 2
|
|
12063
13232
|
});
|
|
12064
13233
|
}
|
|
@@ -12237,10 +13406,10 @@ function lowerSheetMetalBasePlan(model, output) {
|
|
|
12237
13406
|
const pieces = lowerSheetMetalBasePiecePlans(model, output).map((piece) => piece.plan);
|
|
12238
13407
|
return pieces.length === 1 ? pieces[0] : buildBooleanShapeCompilePlan("union", pieces);
|
|
12239
13408
|
}
|
|
12240
|
-
function descriptor(name,
|
|
13409
|
+
function descriptor(name, center2, normal, planar, uAxis, vAxis, semantic = "face", memberNames = [name], coplanar = planar) {
|
|
12241
13410
|
return {
|
|
12242
13411
|
name,
|
|
12243
|
-
center: cloneVec3$7(
|
|
13412
|
+
center: cloneVec3$7(center2),
|
|
12244
13413
|
normal: cloneVec3$7(normal),
|
|
12245
13414
|
planar,
|
|
12246
13415
|
uAxis: cloneFaceAxis(uAxis),
|
|
@@ -16089,6 +17258,23 @@ function analyzeNodeUV(node, toLocal) {
|
|
|
16089
17258
|
function clampUnit$1(v) {
|
|
16090
17259
|
return v < -1 ? -1 : v > 1 ? 1 : v;
|
|
16091
17260
|
}
|
|
17261
|
+
function sphereUVLocal(lx, ly, lz, radius) {
|
|
17262
|
+
const u2 = atan2(ly, lx) * radius;
|
|
17263
|
+
const len = sqrt$3(lx * lx + ly * ly + lz * lz);
|
|
17264
|
+
const v = acos(clampUnit$1(lz / (len || 1))) * radius;
|
|
17265
|
+
return [u2, v];
|
|
17266
|
+
}
|
|
17267
|
+
function cylinderUVLocal(lx, ly, lz, radius) {
|
|
17268
|
+
const u2 = atan2(ly, lx) * radius;
|
|
17269
|
+
const v = lz;
|
|
17270
|
+
return [u2, v];
|
|
17271
|
+
}
|
|
17272
|
+
function torusUVLocal(lx, ly, lz, majorRadius, minorRadius) {
|
|
17273
|
+
const u2 = atan2(ly, lx) * majorRadius;
|
|
17274
|
+
const xyDist = sqrt$3(lx * lx + ly * ly) - majorRadius;
|
|
17275
|
+
const v = atan2(lz, xyDist) * minorRadius;
|
|
17276
|
+
return [u2, v];
|
|
17277
|
+
}
|
|
16092
17278
|
function compileUVFunction(analysis) {
|
|
16093
17279
|
if (analysis.mode === "triplanar") return null;
|
|
16094
17280
|
const toLocal = analysis.toLocal;
|
|
@@ -16097,19 +17283,14 @@ function compileUVFunction(analysis) {
|
|
|
16097
17283
|
const R = analysis.radius;
|
|
16098
17284
|
return (p2) => {
|
|
16099
17285
|
const lp = toLocal(p2);
|
|
16100
|
-
|
|
16101
|
-
const len = sqrt$3(lp[0] * lp[0] + lp[1] * lp[1] + lp[2] * lp[2]);
|
|
16102
|
-
const v = acos(clampUnit$1(lp[2] / (len || 1))) * R;
|
|
16103
|
-
return [u2, v];
|
|
17286
|
+
return sphereUVLocal(lp[0], lp[1], lp[2], R);
|
|
16104
17287
|
};
|
|
16105
17288
|
}
|
|
16106
17289
|
case "cylinder": {
|
|
16107
17290
|
const r = analysis.radius;
|
|
16108
17291
|
return (p2) => {
|
|
16109
17292
|
const lp = toLocal(p2);
|
|
16110
|
-
|
|
16111
|
-
const v = lp[2];
|
|
16112
|
-
return [u2, v];
|
|
17293
|
+
return cylinderUVLocal(lp[0], lp[1], lp[2], r);
|
|
16113
17294
|
};
|
|
16114
17295
|
}
|
|
16115
17296
|
case "torus": {
|
|
@@ -16117,10 +17298,7 @@ function compileUVFunction(analysis) {
|
|
|
16117
17298
|
const r = analysis.radius;
|
|
16118
17299
|
return (p2) => {
|
|
16119
17300
|
const lp = toLocal(p2);
|
|
16120
|
-
|
|
16121
|
-
const xyDist = sqrt$3(lp[0] * lp[0] + lp[1] * lp[1]) - R;
|
|
16122
|
-
const v = atan2(lp[2], xyDist) * r;
|
|
16123
|
-
return [u2, v];
|
|
17301
|
+
return torusUVLocal(lp[0], lp[1], lp[2], R, r);
|
|
16124
17302
|
};
|
|
16125
17303
|
}
|
|
16126
17304
|
}
|
|
@@ -16431,8 +17609,8 @@ function sdProfileRevolve$1(profileFn, degrees, x2, y2, z2) {
|
|
|
16431
17609
|
const profileDistance = profileFn(radial, z2);
|
|
16432
17610
|
if (abs(degrees) >= 360) return profileDistance;
|
|
16433
17611
|
const sweep = abs(degrees) * DEG$1;
|
|
16434
|
-
const
|
|
16435
|
-
let angle = Math.atan2(y2, x2) -
|
|
17612
|
+
const center2 = degrees * DEG$1 * 0.5;
|
|
17613
|
+
let angle = Math.atan2(y2, x2) - center2;
|
|
16436
17614
|
while (angle <= -PI$1) angle += PI$1 * 2;
|
|
16437
17615
|
while (angle > PI$1) angle -= PI$1 * 2;
|
|
16438
17616
|
const half = sweep * 0.5;
|
|
@@ -16450,9 +17628,9 @@ function smax$1(a2, b, k2) {
|
|
|
16450
17628
|
function repeatCoord$1(v, spacing, count) {
|
|
16451
17629
|
if (spacing <= 0) return v;
|
|
16452
17630
|
if (count > 0) {
|
|
16453
|
-
const
|
|
16454
|
-
const index2 = clamp$3(Math.round(v / spacing +
|
|
16455
|
-
return v - (index2 -
|
|
17631
|
+
const center2 = (count - 1) * 0.5;
|
|
17632
|
+
const index2 = clamp$3(Math.round(v / spacing + center2), 0, count - 1);
|
|
17633
|
+
return v - (index2 - center2) * spacing;
|
|
16456
17634
|
}
|
|
16457
17635
|
return v - spacing * Math.round(v / spacing);
|
|
16458
17636
|
}
|
|
@@ -16482,13 +17660,13 @@ function compileTypedSurfacePattern(pattern) {
|
|
|
16482
17660
|
case "surfacePattern:constant":
|
|
16483
17661
|
return () => pattern.value;
|
|
16484
17662
|
case "surfacePattern:sineWave": {
|
|
16485
|
-
const { direction, wavelength, amplitude, phase, bias } = pattern;
|
|
17663
|
+
const { direction: direction2, wavelength, amplitude, phase, bias } = pattern;
|
|
16486
17664
|
const frequency = 2 * PI$1 / wavelength;
|
|
16487
|
-
return (u2, v) => bias + sin$1((u2 *
|
|
17665
|
+
return (u2, v) => bias + sin$1((u2 * direction2[0] + v * direction2[1]) * frequency + phase) * amplitude;
|
|
16488
17666
|
}
|
|
16489
17667
|
case "surfacePattern:stripes": {
|
|
16490
|
-
const { direction, spacing, width, depth } = pattern;
|
|
16491
|
-
return (u2, v) => evalStripesPattern(u2, v,
|
|
17668
|
+
const { direction: direction2, spacing, width, depth } = pattern;
|
|
17669
|
+
return (u2, v) => evalStripesPattern(u2, v, direction2[0], direction2[1], spacing, width, depth);
|
|
16492
17670
|
}
|
|
16493
17671
|
case "surfacePattern:overUnderWeave": {
|
|
16494
17672
|
const { spacing, threadWidth, depth, underScale } = pattern;
|
|
@@ -17378,8 +18556,8 @@ function sdProfileRevolve(b, node, x2, y2, z2) {
|
|
|
17378
18556
|
const profileDistance = profilePolygonsSdf(b, node.polygons, radial, z2);
|
|
17379
18557
|
if (Math.abs(node.degrees) >= 360) return profileDistance;
|
|
17380
18558
|
const sweep = Math.abs(node.degrees) * DEG;
|
|
17381
|
-
const
|
|
17382
|
-
const angle = b.sub(b.atan2(y2, x2), b.constant(
|
|
18559
|
+
const center2 = node.degrees * DEG * 0.5;
|
|
18560
|
+
const angle = b.sub(b.atan2(y2, x2), b.constant(center2));
|
|
17383
18561
|
const wrapped = b.sub(angle, b.mul(b.constant(TAU), b.round(b.div(angle, b.constant(TAU)))));
|
|
17384
18562
|
const absAngle = b.abs(wrapped);
|
|
17385
18563
|
const half = sweep * 0.5;
|
|
@@ -17446,9 +18624,9 @@ function select01(b, selector, ifOne, ifZero) {
|
|
|
17446
18624
|
function repeatCoord(b, v, spacing, count) {
|
|
17447
18625
|
if (spacing <= 0) return v;
|
|
17448
18626
|
if (count > 0) {
|
|
17449
|
-
const
|
|
17450
|
-
const index2 = clampSlot(b, b.round(b.add(b.div(v, b.constant(spacing)), b.constant(
|
|
17451
|
-
return b.sub(v, b.mul(b.sub(index2, b.constant(
|
|
18627
|
+
const center2 = (count - 1) * 0.5;
|
|
18628
|
+
const index2 = clampSlot(b, b.round(b.add(b.div(v, b.constant(spacing)), b.constant(center2))), 0, count - 1);
|
|
18629
|
+
return b.sub(v, b.mul(b.sub(index2, b.constant(center2)), b.constant(spacing)));
|
|
17452
18630
|
}
|
|
17453
18631
|
return b.sub(v, b.mul(b.constant(spacing), b.round(b.div(v, b.constant(spacing)))));
|
|
17454
18632
|
}
|
|
@@ -17719,6 +18897,11 @@ function deepFreezePlanData(value) {
|
|
|
17719
18897
|
return value;
|
|
17720
18898
|
}
|
|
17721
18899
|
const SHAPE_BACKEND_MARKER = Symbol.for("forgecad.shapeBackend");
|
|
18900
|
+
const NORMAL_OFFSET = 3;
|
|
18901
|
+
const UV_OFFSET = 6;
|
|
18902
|
+
const NUM_PROP_POSITION_ONLY = 3;
|
|
18903
|
+
const NUM_PROP_WITH_NORMAL = 6;
|
|
18904
|
+
const NUM_PROP_WITH_UV = 8;
|
|
17722
18905
|
function isShapeBackend(value) {
|
|
17723
18906
|
return Boolean(value && typeof value === "object" && value[SHAPE_BACKEND_MARKER] === true);
|
|
17724
18907
|
}
|
|
@@ -18252,14 +19435,14 @@ function findSpan(n, degree, u2, knots) {
|
|
|
18252
19435
|
}
|
|
18253
19436
|
return mid;
|
|
18254
19437
|
}
|
|
18255
|
-
function basisFuns(
|
|
19438
|
+
function basisFuns(span2, u2, degree, knots) {
|
|
18256
19439
|
const N = new Array(degree + 1);
|
|
18257
19440
|
const left = new Array(degree + 1);
|
|
18258
19441
|
const right = new Array(degree + 1);
|
|
18259
19442
|
N[0] = 1;
|
|
18260
19443
|
for (let j = 1; j <= degree; j++) {
|
|
18261
|
-
left[j] = u2 - knots[
|
|
18262
|
-
right[j] = knots[
|
|
19444
|
+
left[j] = u2 - knots[span2 + 1 - j];
|
|
19445
|
+
right[j] = knots[span2 + j] - u2;
|
|
18263
19446
|
let saved = 0;
|
|
18264
19447
|
for (let r = 0; r < j; r++) {
|
|
18265
19448
|
const denom = right[r + 1] + left[j - r];
|
|
@@ -18271,15 +19454,15 @@ function basisFuns(span, u2, degree, knots) {
|
|
|
18271
19454
|
}
|
|
18272
19455
|
return N;
|
|
18273
19456
|
}
|
|
18274
|
-
function basisFunsDeriv(
|
|
19457
|
+
function basisFunsDeriv(span2, u2, degree, knots, nDeriv) {
|
|
18275
19458
|
const ndu = Array.from({ length: degree + 1 }, () => new Array(degree + 1).fill(0));
|
|
18276
19459
|
const a2 = Array.from({ length: 2 }, () => new Array(degree + 1).fill(0));
|
|
18277
19460
|
const left = new Array(degree + 1);
|
|
18278
19461
|
const right = new Array(degree + 1);
|
|
18279
19462
|
ndu[0][0] = 1;
|
|
18280
19463
|
for (let j = 1; j <= degree; j++) {
|
|
18281
|
-
left[j] = u2 - knots[
|
|
18282
|
-
right[j] = knots[
|
|
19464
|
+
left[j] = u2 - knots[span2 + 1 - j];
|
|
19465
|
+
right[j] = knots[span2 + j] - u2;
|
|
18283
19466
|
let saved = 0;
|
|
18284
19467
|
for (let r2 = 0; r2 < j; r2++) {
|
|
18285
19468
|
ndu[j][r2] = right[r2 + 1] + left[j - r2];
|
|
@@ -18332,11 +19515,11 @@ function basisFunsDeriv(span, u2, degree, knots, nDeriv) {
|
|
|
18332
19515
|
}
|
|
18333
19516
|
function deBoor3D(controlPoints, weights, knots, degree, u2) {
|
|
18334
19517
|
const n = controlPoints.length;
|
|
18335
|
-
const
|
|
18336
|
-
const N = basisFuns(
|
|
19518
|
+
const span2 = findSpan(n, degree, u2, knots);
|
|
19519
|
+
const N = basisFuns(span2, u2, degree, knots);
|
|
18337
19520
|
let wx = 0, wy = 0, wz = 0, wSum = 0;
|
|
18338
19521
|
for (let j = 0; j <= degree; j++) {
|
|
18339
|
-
const idx =
|
|
19522
|
+
const idx = span2 - degree + j;
|
|
18340
19523
|
const w2 = weights[idx] * N[j];
|
|
18341
19524
|
wx += w2 * controlPoints[idx][0];
|
|
18342
19525
|
wy += w2 * controlPoints[idx][1];
|
|
@@ -18732,49 +19915,55 @@ function signedArea2D(loop) {
|
|
|
18732
19915
|
}
|
|
18733
19916
|
return area * 0.5;
|
|
18734
19917
|
}
|
|
18735
|
-
function
|
|
19918
|
+
function buildSdfLoopEdges(pts) {
|
|
19919
|
+
const n = pts.length;
|
|
19920
|
+
const ax = new Float64Array(n);
|
|
19921
|
+
const ay = new Float64Array(n);
|
|
19922
|
+
const ex = new Float64Array(n);
|
|
19923
|
+
const ey = new Float64Array(n);
|
|
19924
|
+
const invLen2 = new Float64Array(n);
|
|
19925
|
+
for (let i = 0; i < n; i += 1) {
|
|
19926
|
+
const a2 = pts[i];
|
|
19927
|
+
const b = pts[(i + 1) % n];
|
|
19928
|
+
const vx = b[0] - a2[0];
|
|
19929
|
+
const vy = b[1] - a2[1];
|
|
19930
|
+
ax[i] = a2[0];
|
|
19931
|
+
ay[i] = a2[1];
|
|
19932
|
+
ex[i] = vx;
|
|
19933
|
+
ey[i] = vy;
|
|
19934
|
+
const len2 = vx * vx + vy * vy;
|
|
19935
|
+
invLen2[i] = len2 < 1e-12 ? 0 : 1 / len2;
|
|
19936
|
+
}
|
|
19937
|
+
return { n, area: signedArea2D(pts), ax, ay, ex, ey, invLen2 };
|
|
19938
|
+
}
|
|
19939
|
+
function loopSignedDistanceScalar(px, py, e) {
|
|
19940
|
+
let minDist2 = Infinity;
|
|
18736
19941
|
let inside = false;
|
|
18737
|
-
|
|
18738
|
-
|
|
18739
|
-
const
|
|
18740
|
-
const
|
|
18741
|
-
const
|
|
18742
|
-
|
|
18743
|
-
|
|
18744
|
-
|
|
18745
|
-
|
|
18746
|
-
|
|
18747
|
-
|
|
18748
|
-
|
|
18749
|
-
|
|
18750
|
-
const
|
|
18751
|
-
|
|
18752
|
-
const t = den < 1e-12 ? 0 : clamp$1((apx * abx + apy * aby) / den, 0, 1);
|
|
18753
|
-
const qx = a2[0] + abx * t;
|
|
18754
|
-
const qy = a2[1] + aby * t;
|
|
18755
|
-
const dx = point2[0] - qx;
|
|
18756
|
-
const dy = point2[1] - qy;
|
|
18757
|
-
return Math.sqrt(dx * dx + dy * dy);
|
|
18758
|
-
}
|
|
18759
|
-
function loopSignedDistance(point2, loop) {
|
|
18760
|
-
let minDist = Infinity;
|
|
18761
|
-
for (let index2 = 0; index2 < loop.length; index2 += 1) {
|
|
18762
|
-
const a2 = loop[index2];
|
|
18763
|
-
const b = loop[(index2 + 1) % loop.length];
|
|
18764
|
-
minDist = Math.min(minDist, pointSegDist2D(point2, a2, b));
|
|
18765
|
-
}
|
|
18766
|
-
return pointInLoop$1(point2, loop) ? minDist : -minDist;
|
|
19942
|
+
for (let i = 0; i < e.n; i += 1) {
|
|
19943
|
+
const ax = e.ax[i];
|
|
19944
|
+
const ay = e.ay[i];
|
|
19945
|
+
const vx = e.ex[i];
|
|
19946
|
+
const vy = e.ey[i];
|
|
19947
|
+
const t = clamp$1(((px - ax) * vx + (py - ay) * vy) * e.invLen2[i], 0, 1);
|
|
19948
|
+
const ddx = px - (ax + vx * t);
|
|
19949
|
+
const ddy = py - (ay + vy * t);
|
|
19950
|
+
const d22 = ddx * ddx + ddy * ddy;
|
|
19951
|
+
if (d22 < minDist2) minDist2 = d22;
|
|
19952
|
+
const by = ay + vy;
|
|
19953
|
+
if (ay > py !== by > py && px < vx * (py - ay) / (vy + 1e-20) + ax) inside = !inside;
|
|
19954
|
+
}
|
|
19955
|
+
const d2 = Math.sqrt(minDist2);
|
|
19956
|
+
return inside ? d2 : -d2;
|
|
18767
19957
|
}
|
|
18768
19958
|
function compilePolygonsSdf(polygons) {
|
|
18769
|
-
const loops = polygons.filter((loop) => Array.isArray(loop) && loop.length >= 3).map((loop) => (
|
|
19959
|
+
const loops = polygons.filter((loop) => Array.isArray(loop) && loop.length >= 3).map((loop) => buildSdfLoopEdges(loop.map(([x2, y2]) => [x2, y2])));
|
|
18770
19960
|
if (loops.length === 0) {
|
|
18771
19961
|
return () => -1;
|
|
18772
19962
|
}
|
|
18773
19963
|
return (x2, y2) => {
|
|
18774
|
-
const point2 = [x2, y2];
|
|
18775
19964
|
let field2 = -Infinity;
|
|
18776
19965
|
for (const loop of loops) {
|
|
18777
|
-
const loopField =
|
|
19966
|
+
const loopField = loopSignedDistanceScalar(x2, y2, loop);
|
|
18778
19967
|
field2 = loop.area >= 0 ? Math.max(field2, loopField) : Math.min(field2, -loopField);
|
|
18779
19968
|
}
|
|
18780
19969
|
return field2;
|
|
@@ -18932,24 +20121,40 @@ function interpolateSweepFrame(segment, alpha, origin) {
|
|
|
18932
20121
|
function findNearestSweepPoint(point2, segments) {
|
|
18933
20122
|
let bestIndex = 0;
|
|
18934
20123
|
let bestAlpha = 0;
|
|
18935
|
-
let
|
|
20124
|
+
let bestAlong = 0;
|
|
18936
20125
|
let bestDist2 = Infinity;
|
|
20126
|
+
const px = point2[0];
|
|
20127
|
+
const py = point2[1];
|
|
20128
|
+
const pz = point2[2];
|
|
18937
20129
|
for (let index2 = 0; index2 < segments.length; index2 += 1) {
|
|
18938
20130
|
const segment = segments[index2];
|
|
18939
|
-
const
|
|
18940
|
-
const
|
|
18941
|
-
const
|
|
18942
|
-
const
|
|
18943
|
-
const
|
|
18944
|
-
const
|
|
20131
|
+
const ax = segment.a[0];
|
|
20132
|
+
const ay = segment.a[1];
|
|
20133
|
+
const az = segment.a[2];
|
|
20134
|
+
const tx = segment.t[0];
|
|
20135
|
+
const ty = segment.t[1];
|
|
20136
|
+
const tz = segment.t[2];
|
|
20137
|
+
const along = clamp$1((px - ax) * tx + (py - ay) * ty + (pz - az) * tz, 0, segment.len);
|
|
20138
|
+
const qx = ax + tx * along;
|
|
20139
|
+
const qy = ay + ty * along;
|
|
20140
|
+
const qz = az + tz * along;
|
|
20141
|
+
const dx = px - qx;
|
|
20142
|
+
const dy = py - qy;
|
|
20143
|
+
const dz = pz - qz;
|
|
20144
|
+
const dist2 = dx * dx + dy * dy + dz * dz;
|
|
18945
20145
|
if (dist2 < bestDist2) {
|
|
18946
20146
|
bestIndex = index2;
|
|
18947
|
-
|
|
18948
|
-
|
|
20147
|
+
bestAlong = along;
|
|
20148
|
+
bestAlpha = segment.len > 1e-9 ? along / segment.len : 0;
|
|
18949
20149
|
bestDist2 = dist2;
|
|
18950
20150
|
}
|
|
18951
20151
|
}
|
|
18952
20152
|
const bestSegment = segments[bestIndex];
|
|
20153
|
+
const bestPoint = [
|
|
20154
|
+
bestSegment.a[0] + bestSegment.t[0] * bestAlong,
|
|
20155
|
+
bestSegment.a[1] + bestSegment.t[1] * bestAlong,
|
|
20156
|
+
bestSegment.a[2] + bestSegment.t[2] * bestAlong
|
|
20157
|
+
];
|
|
18953
20158
|
return {
|
|
18954
20159
|
segmentIndex: bestIndex,
|
|
18955
20160
|
segment: bestSegment,
|
|
@@ -19946,11 +21151,11 @@ function applyFilletSelectionToManifold(base, selection, radius, segments, wasm)
|
|
|
19946
21151
|
const height = edgeLength(selection);
|
|
19947
21152
|
if (!(height > 1e-6)) return base;
|
|
19948
21153
|
const pad = Math.max(MIN_EDGE_PAD, radius);
|
|
19949
|
-
const
|
|
21154
|
+
const span2 = height + pad * 2;
|
|
19950
21155
|
const frame = edgeFrameMatrix(selection, -pad);
|
|
19951
21156
|
const cs = buildFilletCrossSection(selection, radius, segments, wasm) ?? legacyFilletCrossSection(selection, radius, segments, wasm);
|
|
19952
|
-
const corner = cs.wedge.extrude(
|
|
19953
|
-
const cyl = cs.cylinder.extrude(
|
|
21157
|
+
const corner = cs.wedge.extrude(span2, 0, 0, void 0, false).transform(frame);
|
|
21158
|
+
const cyl = cs.cylinder.extrude(span2, 0, 0, void 0, false).transform(frame);
|
|
19954
21159
|
const crescent = wasm.Manifold.difference([corner, cyl]);
|
|
19955
21160
|
return wasm.Manifold.difference([base, crescent]);
|
|
19956
21161
|
}
|
|
@@ -19958,11 +21163,11 @@ function applyConcaveFilletSelectionToManifold(base, selection, radius, segments
|
|
|
19958
21163
|
const height = edgeLength(selection);
|
|
19959
21164
|
if (!(height > 1e-6)) return base;
|
|
19960
21165
|
const pad = Math.max(MIN_EDGE_PAD, radius);
|
|
19961
|
-
const
|
|
21166
|
+
const span2 = height + pad * 2;
|
|
19962
21167
|
const frame = edgeFrameMatrix(selection, -pad);
|
|
19963
21168
|
const cs = buildFilletCrossSection(selection, radius, segments, wasm) ?? legacyFilletCrossSection(selection, radius, segments, wasm);
|
|
19964
|
-
const corner = cs.wedge.extrude(
|
|
19965
|
-
const cyl = cs.cylinder.extrude(
|
|
21169
|
+
const corner = cs.wedge.extrude(span2, 0, 0, void 0, false).transform(frame);
|
|
21170
|
+
const cyl = cs.cylinder.extrude(span2, 0, 0, void 0, false).transform(frame);
|
|
19966
21171
|
const crescent = wasm.Manifold.difference([corner, cyl]);
|
|
19967
21172
|
return wasm.Manifold.union([base, crescent]);
|
|
19968
21173
|
}
|
|
@@ -19970,20 +21175,20 @@ function applyChamferSelectionToManifold(base, selection, size, wasm) {
|
|
|
19970
21175
|
const height = edgeLength(selection);
|
|
19971
21176
|
if (!(height > 1e-6)) return base;
|
|
19972
21177
|
const pad = Math.max(MIN_EDGE_PAD, size);
|
|
19973
|
-
const
|
|
21178
|
+
const span2 = height + pad * 2;
|
|
19974
21179
|
const frame = edgeFrameMatrix(selection, -pad);
|
|
19975
21180
|
const triangle3 = buildChamferCrossSection(selection, size, wasm) ?? legacyChamferCrossSection(selection, size, wasm);
|
|
19976
|
-
const chamfer = triangle3.extrude(
|
|
21181
|
+
const chamfer = triangle3.extrude(span2, 0, 0, void 0, false).transform(frame);
|
|
19977
21182
|
return wasm.Manifold.difference([base, chamfer]);
|
|
19978
21183
|
}
|
|
19979
21184
|
function applyConcaveChamferSelectionToManifold(base, selection, size, wasm) {
|
|
19980
21185
|
const height = edgeLength(selection);
|
|
19981
21186
|
if (!(height > 1e-6)) return base;
|
|
19982
21187
|
const pad = Math.max(MIN_EDGE_PAD, size);
|
|
19983
|
-
const
|
|
21188
|
+
const span2 = height + pad * 2;
|
|
19984
21189
|
const frame = edgeFrameMatrix(selection, -pad);
|
|
19985
21190
|
const triangle3 = buildChamferCrossSection(selection, size, wasm) ?? legacyChamferCrossSection(selection, size, wasm);
|
|
19986
|
-
const chamfer = triangle3.extrude(
|
|
21191
|
+
const chamfer = triangle3.extrude(span2, 0, 0, void 0, false).transform(frame);
|
|
19987
21192
|
return wasm.Manifold.union([base, chamfer]);
|
|
19988
21193
|
}
|
|
19989
21194
|
const EPS$1 = 1e-8;
|
|
@@ -21832,8 +23037,8 @@ function stitchSingleLoopLoft(loops, heights, wasm, options) {
|
|
|
21832
23037
|
return null;
|
|
21833
23038
|
}
|
|
21834
23039
|
}
|
|
21835
|
-
function surfaceNormal(chord,
|
|
21836
|
-
const n = cross3$5(chord,
|
|
23040
|
+
function surfaceNormal(chord, span2) {
|
|
23041
|
+
const n = cross3$5(chord, span2);
|
|
21837
23042
|
const len = Math.hypot(n[0], n[1], n[2]);
|
|
21838
23043
|
if (len < 1e-12) {
|
|
21839
23044
|
const radial = Math.hypot(chord[0], chord[1]);
|
|
@@ -22476,6 +23681,16 @@ function fromSlicesSingleSliceHalfExtentForManifold(plan) {
|
|
|
22476
23681
|
return Math.max(1, radius + maxOffsetMagnitude + plan.boundsPadding + plan.edgeLength * 3);
|
|
22477
23682
|
}
|
|
22478
23683
|
const BOOLEAN_OPERAND_NORMAL_SHARP_ANGLE_DEG = 60;
|
|
23684
|
+
const BOOLEAN_OPERAND_UV_EXTRA_PROP_MIN = 4;
|
|
23685
|
+
function rejectParametricUvBooleanOperands(shapes) {
|
|
23686
|
+
for (const shape of shapes) {
|
|
23687
|
+
if (shape.numProp() >= BOOLEAN_OPERAND_UV_EXTRA_PROP_MIN) {
|
|
23688
|
+
throw new Error(
|
|
23689
|
+
"Cannot boolean a shape that carries parametric UV (mesh numProp 8, vertProperties[6..7]). Parametric UV is baked into the mesh and is destroyed by cuts — Manifold interpolates the uv channels from the other operand onto every new cut/seam vertex. Apply booleans BEFORE texturing the result, or use a projected texture (Shape.wrapTexture with Wrap.*), which is computed from final position and survives booleans."
|
|
23690
|
+
);
|
|
23691
|
+
}
|
|
23692
|
+
}
|
|
23693
|
+
}
|
|
22479
23694
|
function promoteBooleanOperandNormals(shapes) {
|
|
22480
23695
|
let maxExtra = 0;
|
|
22481
23696
|
for (const shape of shapes) maxExtra = Math.max(maxExtra, shape.numProp());
|
|
@@ -22497,6 +23712,12 @@ function lowerShapeBooleanCompilePlan(plan, wasm) {
|
|
|
22497
23712
|
if (shapes.length === 1) {
|
|
22498
23713
|
return shapes[0];
|
|
22499
23714
|
}
|
|
23715
|
+
try {
|
|
23716
|
+
rejectParametricUvBooleanOperands(shapes);
|
|
23717
|
+
} catch (error) {
|
|
23718
|
+
disposeWasmObjects(shapes);
|
|
23719
|
+
throw error;
|
|
23720
|
+
}
|
|
22500
23721
|
const { operands, created } = promoteBooleanOperandNormals(shapes);
|
|
22501
23722
|
try {
|
|
22502
23723
|
switch (plan.op) {
|
|
@@ -22538,8 +23759,8 @@ function vectorLength3$1(v) {
|
|
|
22538
23759
|
function subtract3$1(a2, b) {
|
|
22539
23760
|
return [a2[0] - b[0], a2[1] - b[1], a2[2] - b[2]];
|
|
22540
23761
|
}
|
|
22541
|
-
function addScaled3$1(point2,
|
|
22542
|
-
return [point2[0] +
|
|
23762
|
+
function addScaled3$1(point2, direction2, scale2) {
|
|
23763
|
+
return [point2[0] + direction2[0] * scale2, point2[1] + direction2[1] * scale2, point2[2] + direction2[2] * scale2];
|
|
22543
23764
|
}
|
|
22544
23765
|
function cross3$4(a2, b) {
|
|
22545
23766
|
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]];
|
|
@@ -23254,9 +24475,9 @@ function lowerVerticalVariableSweepStitchedForManifold(plan, sectionPolygons, wa
|
|
|
23254
24475
|
return null;
|
|
23255
24476
|
}
|
|
23256
24477
|
const frameY = cross3$4(tangent, frameX);
|
|
23257
|
-
const
|
|
24478
|
+
const span2 = end[2] - start[2];
|
|
23258
24479
|
const sections = sectionPolygons.map((section) => ({
|
|
23259
|
-
height: start[2] +
|
|
24480
|
+
height: start[2] + span2 * section.t,
|
|
23260
24481
|
polygons: section.polygons.map(
|
|
23261
24482
|
(loop) => loop.map(([u2, v]) => [start[0] + u2 * frameX[0] + v * frameY[0], start[1] + u2 * frameX[1] + v * frameY[1]])
|
|
23262
24483
|
)
|
|
@@ -31765,8 +32986,8 @@ function revolveProfilePolygonsToSdfField(polygons, degrees = 360) {
|
|
|
31765
32986
|
const profileDistance = profile.eval(radial, z2);
|
|
31766
32987
|
if (Math.abs(degrees) >= 360) return profileDistance;
|
|
31767
32988
|
const sweep = Math.abs(degrees) * (Math.PI / 180);
|
|
31768
|
-
const
|
|
31769
|
-
let angle = Math.atan2(y2, x2) -
|
|
32989
|
+
const center2 = degrees * Math.PI / 360;
|
|
32990
|
+
let angle = Math.atan2(y2, x2) - center2;
|
|
31770
32991
|
while (angle <= -Math.PI) angle += Math.PI * 2;
|
|
31771
32992
|
while (angle > Math.PI) angle -= Math.PI * 2;
|
|
31772
32993
|
const half = sweep / 2;
|
|
@@ -32683,18 +33904,18 @@ function circleFootprintFromProfile(plan) {
|
|
|
32683
33904
|
if (plan.kind !== "circle") return null;
|
|
32684
33905
|
const radius = Math.abs(plan.radius);
|
|
32685
33906
|
if (!finitePositive$1(radius)) return null;
|
|
32686
|
-
const
|
|
33907
|
+
const center2 = transformProfilePointThrough([0, 0], plan.transforms);
|
|
32687
33908
|
const xPoint = transformProfilePointThrough([1, 0], plan.transforms);
|
|
32688
33909
|
const yPoint = transformProfilePointThrough([0, 1], plan.transforms);
|
|
32689
|
-
const xAxis = [xPoint[0] -
|
|
32690
|
-
const yAxis = [yPoint[0] -
|
|
33910
|
+
const xAxis = [xPoint[0] - center2[0], xPoint[1] - center2[1]];
|
|
33911
|
+
const yAxis = [yPoint[0] - center2[0], yPoint[1] - center2[1]];
|
|
32691
33912
|
const xScale = Math.hypot(xAxis[0], xAxis[1]);
|
|
32692
33913
|
const yScale = Math.hypot(yAxis[0], yAxis[1]);
|
|
32693
33914
|
const dot2 = xAxis[0] * yAxis[0] + xAxis[1] * yAxis[1];
|
|
32694
33915
|
if (!finitePositive$1(xScale) || !finitePositive$1(yScale)) return null;
|
|
32695
33916
|
if (Math.abs(xScale - yScale) > EPS || Math.abs(dot2) > EPS * xScale * yScale) return null;
|
|
32696
33917
|
return {
|
|
32697
|
-
center,
|
|
33918
|
+
center: center2,
|
|
32698
33919
|
radius: radius * xScale,
|
|
32699
33920
|
segments: plan.segments
|
|
32700
33921
|
};
|
|
@@ -33493,19 +34714,19 @@ function explicitGeometrySurface(geometry, face) {
|
|
|
33493
34714
|
}
|
|
33494
34715
|
}
|
|
33495
34716
|
if ("AnalyticSphere" in geometry) {
|
|
33496
|
-
const
|
|
34717
|
+
const center2 = geometry.AnalyticSphere.center;
|
|
33497
34718
|
const radius = geometry.AnalyticSphere.radius;
|
|
33498
|
-
if (isVec3(
|
|
33499
|
-
return { kind: "sphere", center, radius };
|
|
34719
|
+
if (isVec3(center2) && isFiniteNumber(radius) && radius > 0) {
|
|
34720
|
+
return { kind: "sphere", center: center2, radius };
|
|
33500
34721
|
}
|
|
33501
34722
|
}
|
|
33502
34723
|
if ("AnalyticTorus" in geometry) {
|
|
33503
|
-
const
|
|
34724
|
+
const center2 = geometry.AnalyticTorus.center;
|
|
33504
34725
|
const axis = geometry.AnalyticTorus.axis;
|
|
33505
34726
|
const majorRadius = geometry.AnalyticTorus.major_radius;
|
|
33506
34727
|
const minorRadius = geometry.AnalyticTorus.minor_radius;
|
|
33507
|
-
if (isVec3(
|
|
33508
|
-
return { kind: "torus", center, axis: normalizeVec3(axis), majorRadius, minorRadius };
|
|
34728
|
+
if (isVec3(center2) && isVec3(axis) && isFiniteNumber(majorRadius) && isFiniteNumber(minorRadius) && majorRadius > 0 && minorRadius > 0) {
|
|
34729
|
+
return { kind: "torus", center: center2, axis: normalizeVec3(axis), majorRadius, minorRadius };
|
|
33509
34730
|
}
|
|
33510
34731
|
}
|
|
33511
34732
|
if ("NurbsPatch" in geometry) {
|
|
@@ -33599,13 +34820,13 @@ function explicitGeometrySurface(geometry, face) {
|
|
|
33599
34820
|
function explicitEdgeCurve(geometry, faceName) {
|
|
33600
34821
|
var _a3, _b3, _c2, _d2, _e2;
|
|
33601
34822
|
if (!geometry) return void 0;
|
|
33602
|
-
const
|
|
34823
|
+
const center2 = (_a3 = geometry.CircularArc) == null ? void 0 : _a3.center;
|
|
33603
34824
|
const axis = (_b3 = geometry.CircularArc) == null ? void 0 : _b3.axis;
|
|
33604
34825
|
const radius = (_c2 = geometry.CircularArc) == null ? void 0 : _c2.radius;
|
|
33605
|
-
if (
|
|
34826
|
+
if (center2 !== void 0 && axis !== void 0 && radius !== void 0 && isVec3(center2) && isVec3(axis) && isFiniteNumber(radius) && radius > 0) {
|
|
33606
34827
|
return {
|
|
33607
34828
|
kind: "circle",
|
|
33608
|
-
center,
|
|
34829
|
+
center: center2,
|
|
33609
34830
|
axis: normalizeVec3(axis),
|
|
33610
34831
|
radius,
|
|
33611
34832
|
faceName
|
|
@@ -36221,15 +37442,15 @@ function regionsHaveMatchingTopology$1(stations) {
|
|
|
36221
37442
|
);
|
|
36222
37443
|
}
|
|
36223
37444
|
function lowerDraftPlan(plan) {
|
|
36224
|
-
const
|
|
36225
|
-
if (Math.abs(
|
|
37445
|
+
const direction2 = normalizedVector3(plan.pullDirection, "draft() pull direction");
|
|
37446
|
+
if (Math.abs(direction2[0]) > 1e-9 || Math.abs(direction2[1]) > 1e-9 || Math.abs(Math.abs(direction2[2]) - 1) > 1e-9) {
|
|
36226
37447
|
return truckUnsupported("draft() for non-Z pull directions");
|
|
36227
37448
|
}
|
|
36228
37449
|
const prism = lowerPlanToVerticalPrism(plan.base, true);
|
|
36229
37450
|
if (!prism) return truckUnsupported("draft() for non-vertical-prism solids");
|
|
36230
37451
|
if (!(prism.zMax > prism.zMin + 1e-9)) return truckUnsupported("draft() with collapsed vertical span");
|
|
36231
37452
|
const tanAngle = Math.tan(plan.angleDeg * Math.PI / 180);
|
|
36232
|
-
const axialSign =
|
|
37453
|
+
const axialSign = direction2[2] >= 0 ? 1 : -1;
|
|
36233
37454
|
const offsetAtZ = (z2) => (axialSign * z2 - plan.neutralPlaneOffset) * tanAngle;
|
|
36234
37455
|
const bottomReferenceRegions = prism.regions.map(simplifyCollinearRegion);
|
|
36235
37456
|
const sourceTopRegions = prism.topRegions ?? prism.regions;
|
|
@@ -36279,8 +37500,8 @@ function offsetLoftPlan(plan, thickness) {
|
|
|
36279
37500
|
)
|
|
36280
37501
|
);
|
|
36281
37502
|
}
|
|
36282
|
-
function addScaled3(point2,
|
|
36283
|
-
return [point2[0] +
|
|
37503
|
+
function addScaled3(point2, direction2, scale2) {
|
|
37504
|
+
return [point2[0] + direction2[0] * scale2, point2[1] + direction2[1] * scale2, point2[2] + direction2[2] * scale2];
|
|
36284
37505
|
}
|
|
36285
37506
|
function isStraightMonotonePolyline(points) {
|
|
36286
37507
|
if (points.length < 2) return false;
|
|
@@ -36549,8 +37770,8 @@ function resamplePolyline(points, count) {
|
|
|
36549
37770
|
for (let idx = 0; idx < count; idx++) {
|
|
36550
37771
|
const target = idx / (count - 1) * total;
|
|
36551
37772
|
while (segment < cumulative.length - 2 && cumulative[segment + 1] < target) segment++;
|
|
36552
|
-
const
|
|
36553
|
-
const t =
|
|
37773
|
+
const span2 = cumulative[segment + 1] - cumulative[segment];
|
|
37774
|
+
const t = span2 > 1e-12 ? (target - cumulative[segment]) / span2 : 0;
|
|
36554
37775
|
const a2 = points[segment];
|
|
36555
37776
|
const b = points[segment + 1];
|
|
36556
37777
|
out.push([a2[0] + (b[0] - a2[0]) * t, a2[1] + (b[1] - a2[1]) * t, a2[2] + (b[2] - a2[2]) * t]);
|
|
@@ -37308,12 +38529,12 @@ function transformedSphereProfile(basePlan, steps, sliceOffset) {
|
|
|
37308
38529
|
transform = transform.mul(transformForShapeTransform(step));
|
|
37309
38530
|
scale2 *= stepScale;
|
|
37310
38531
|
}
|
|
37311
|
-
const
|
|
38532
|
+
const center2 = transform.point([0, 0, 0]);
|
|
37312
38533
|
const radius = Math.abs(source.radius * scale2);
|
|
37313
|
-
const sectionRadius = sliceOffset == null ? radius : Math.sqrt(Math.max(0, radius * radius - (sliceOffset -
|
|
38534
|
+
const sectionRadius = sliceOffset == null ? radius : Math.sqrt(Math.max(0, radius * radius - (sliceOffset - center2[2]) * (sliceOffset - center2[2])));
|
|
37314
38535
|
if (sectionRadius <= EXACT_PROFILE_EPS) return emptyProfilePlan();
|
|
37315
38536
|
const profile = circleProfilePlan(sectionRadius, source.segments);
|
|
37316
|
-
if (!isNearlyZero(
|
|
38537
|
+
if (!isNearlyZero(center2[0]) || !isNearlyZero(center2[1])) profile.transforms.push({ kind: "translate", x: center2[0], y: center2[1] });
|
|
37317
38538
|
return profile;
|
|
37318
38539
|
}
|
|
37319
38540
|
function profileTransformsForShapeTransform(step) {
|
|
@@ -37416,20 +38637,20 @@ function sliceOffsetBeforeShapeTransforms(steps, offset) {
|
|
|
37416
38637
|
}
|
|
37417
38638
|
return sourceOffset;
|
|
37418
38639
|
}
|
|
37419
|
-
function transformZSpan(
|
|
38640
|
+
function transformZSpan(span2, step) {
|
|
37420
38641
|
switch (step.kind) {
|
|
37421
38642
|
case "translate":
|
|
37422
|
-
return [
|
|
38643
|
+
return [span2[0] + step.z, span2[1] + step.z];
|
|
37423
38644
|
case "scale":
|
|
37424
38645
|
if (!Number.isFinite(step.z) || isNearlyZero(step.z)) return null;
|
|
37425
|
-
return [Math.min(
|
|
38646
|
+
return [Math.min(span2[0] * step.z, span2[1] * step.z), Math.max(span2[0] * step.z, span2[1] * step.z)];
|
|
37426
38647
|
case "rotateAround": {
|
|
37427
38648
|
const axisLength = Math.hypot(step.axisX, step.axisY, step.axisZ);
|
|
37428
38649
|
if (axisLength <= EXACT_PROFILE_EPS) return null;
|
|
37429
38650
|
const axisX = step.axisX / axisLength;
|
|
37430
38651
|
const axisY = step.axisY / axisLength;
|
|
37431
38652
|
const axisZ = step.axisZ / axisLength;
|
|
37432
|
-
return !isNearlyZero(axisX) || !isNearlyZero(axisY) || Math.abs(Math.abs(axisZ) - 1) > EXACT_PROFILE_EPS ? null :
|
|
38653
|
+
return !isNearlyZero(axisX) || !isNearlyZero(axisY) || Math.abs(Math.abs(axisZ) - 1) > EXACT_PROFILE_EPS ? null : span2;
|
|
37433
38654
|
}
|
|
37434
38655
|
case "mirror": {
|
|
37435
38656
|
const normalLength = Math.hypot(step.normalX, step.normalY, step.normalZ);
|
|
@@ -37437,14 +38658,14 @@ function transformZSpan(span, step) {
|
|
|
37437
38658
|
const normalX = step.normalX / normalLength;
|
|
37438
38659
|
const normalY = step.normalY / normalLength;
|
|
37439
38660
|
const normalZ = step.normalZ / normalLength;
|
|
37440
|
-
if (isNearlyZero(normalX) && isNearlyZero(normalY)) return [-
|
|
37441
|
-
return isNearlyZero(normalZ) ?
|
|
38661
|
+
if (isNearlyZero(normalX) && isNearlyZero(normalY)) return [-span2[1], -span2[0]];
|
|
38662
|
+
return isNearlyZero(normalZ) ? span2 : null;
|
|
37442
38663
|
}
|
|
37443
38664
|
case "workplanePlacement": {
|
|
37444
38665
|
const replay = workplanePlacementReplay(step.matrix);
|
|
37445
38666
|
if (!replay) return null;
|
|
37446
|
-
const z0 = replay.zScale *
|
|
37447
|
-
const z1 = replay.zScale *
|
|
38667
|
+
const z0 = replay.zScale * span2[0] + replay.zTranslate;
|
|
38668
|
+
const z1 = replay.zScale * span2[1] + replay.zTranslate;
|
|
37448
38669
|
return [Math.min(z0, z1), Math.max(z0, z1)];
|
|
37449
38670
|
}
|
|
37450
38671
|
default:
|
|
@@ -37498,14 +38719,14 @@ function transformProfilePointThroughRadial(point2, transforms) {
|
|
|
37498
38719
|
return out;
|
|
37499
38720
|
}
|
|
37500
38721
|
function profileRadialTransformBasis(transforms) {
|
|
37501
|
-
const
|
|
38722
|
+
const center2 = transformProfilePointThroughRadial([0, 0], transforms);
|
|
37502
38723
|
const xBasis = transformProfilePointThroughRadial([1, 0], transforms);
|
|
37503
38724
|
const yBasis = transformProfilePointThroughRadial([0, 1], transforms);
|
|
37504
|
-
if (!
|
|
38725
|
+
if (!center2 || !xBasis || !yBasis) return null;
|
|
37505
38726
|
return {
|
|
37506
|
-
center,
|
|
37507
|
-
xAxis: [xBasis[0] -
|
|
37508
|
-
yAxis: [yBasis[0] -
|
|
38727
|
+
center: center2,
|
|
38728
|
+
xAxis: [xBasis[0] - center2[0], xBasis[1] - center2[1]],
|
|
38729
|
+
yAxis: [yBasis[0] - center2[0], yBasis[1] - center2[1]]
|
|
37509
38730
|
};
|
|
37510
38731
|
}
|
|
37511
38732
|
function circleRadialProjectionInterval(plan) {
|
|
@@ -37625,11 +38846,11 @@ function radialRoundedRectSignedDistance(footprint, point2) {
|
|
|
37625
38846
|
const qy = Math.abs(localPoint[1]) - Math.max(0, footprint.halfHeight - footprint.radius);
|
|
37626
38847
|
return Math.hypot(Math.max(qx, 0), Math.max(qy, 0)) + Math.min(Math.max(qx, qy), 0) - footprint.radius;
|
|
37627
38848
|
}
|
|
37628
|
-
function radialRoundedRectHalfExtentAlong(footprint,
|
|
38849
|
+
function radialRoundedRectHalfExtentAlong(footprint, direction2) {
|
|
37629
38850
|
const coreHalfWidth = Math.max(0, footprint.halfWidth - footprint.radius);
|
|
37630
38851
|
const coreHalfHeight = Math.max(0, footprint.halfHeight - footprint.radius);
|
|
37631
|
-
const directionLength = Math.hypot(
|
|
37632
|
-
return Math.abs(
|
|
38852
|
+
const directionLength = Math.hypot(direction2[0], direction2[1]);
|
|
38853
|
+
return Math.abs(direction2[0] * footprint.xAxis[0] + direction2[1] * footprint.xAxis[1]) * coreHalfWidth + Math.abs(direction2[0] * footprint.yAxis[0] + direction2[1] * footprint.yAxis[1]) * coreHalfHeight + footprint.radius * directionLength;
|
|
37633
38854
|
}
|
|
37634
38855
|
function radialRoundedRectBoundaryMaxDistanceFromPoint(footprint, point2) {
|
|
37635
38856
|
const coreHalfWidth = Math.max(0, footprint.halfWidth - footprint.radius);
|
|
@@ -37653,13 +38874,13 @@ function radialRoundedRectBoundaryMaxDistanceFromPoint(footprint, point2) {
|
|
|
37653
38874
|
[-1, -1]
|
|
37654
38875
|
];
|
|
37655
38876
|
for (const [sx, sy] of cornerSigns) {
|
|
37656
|
-
const
|
|
37657
|
-
includeLocal([
|
|
37658
|
-
includeLocal([
|
|
37659
|
-
const away = [
|
|
38877
|
+
const center2 = [sx * coreHalfWidth, sy * coreHalfHeight];
|
|
38878
|
+
includeLocal([center2[0] + sx * footprint.radius, center2[1]]);
|
|
38879
|
+
includeLocal([center2[0], center2[1] + sy * footprint.radius]);
|
|
38880
|
+
const away = [center2[0] - localPoint[0], center2[1] - localPoint[1]];
|
|
37660
38881
|
const awayLength = Math.hypot(away[0], away[1]);
|
|
37661
38882
|
if (awayLength > EXACT_PROFILE_EPS && away[0] * sx >= -EXACT_PROFILE_EPS && away[1] * sy >= -EXACT_PROFILE_EPS) {
|
|
37662
|
-
includeLocal([
|
|
38883
|
+
includeLocal([center2[0] + away[0] / awayLength * footprint.radius, center2[1] + away[1] / awayLength * footprint.radius]);
|
|
37663
38884
|
}
|
|
37664
38885
|
}
|
|
37665
38886
|
return maxDistance;
|
|
@@ -37746,10 +38967,10 @@ function lineIntervalsForRect(base, tangent, halfWidth, halfHeight) {
|
|
|
37746
38967
|
if (halfWidth < -EXACT_PROFILE_EPS || halfHeight < -EXACT_PROFILE_EPS) return null;
|
|
37747
38968
|
let min2 = -Infinity;
|
|
37748
38969
|
let max2 = Infinity;
|
|
37749
|
-
const applyAxis = (origin,
|
|
37750
|
-
if (Math.abs(
|
|
37751
|
-
const a2 = (-extent - origin) /
|
|
37752
|
-
const b = (extent - origin) /
|
|
38970
|
+
const applyAxis = (origin, direction2, extent) => {
|
|
38971
|
+
if (Math.abs(direction2) <= EXACT_PROFILE_EPS) return Math.abs(origin) <= extent + EXACT_PROFILE_EPS;
|
|
38972
|
+
const a2 = (-extent - origin) / direction2;
|
|
38973
|
+
const b = (extent - origin) / direction2;
|
|
37753
38974
|
min2 = Math.max(min2, Math.min(a2, b));
|
|
37754
38975
|
max2 = Math.min(max2, Math.max(a2, b));
|
|
37755
38976
|
return min2 <= max2 + EXACT_PROFILE_EPS;
|
|
@@ -37757,10 +38978,10 @@ function lineIntervalsForRect(base, tangent, halfWidth, halfHeight) {
|
|
|
37757
38978
|
if (!applyAxis(base[0], tangent[0], halfWidth) || !applyAxis(base[1], tangent[1], halfHeight)) return [];
|
|
37758
38979
|
return [[min2, max2]];
|
|
37759
38980
|
}
|
|
37760
|
-
function lineIntervalsForCircle(base, tangent,
|
|
38981
|
+
function lineIntervalsForCircle(base, tangent, center2, radius) {
|
|
37761
38982
|
if (radius < -EXACT_PROFILE_EPS) return null;
|
|
37762
|
-
const dx = base[0] -
|
|
37763
|
-
const dy = base[1] -
|
|
38983
|
+
const dx = base[0] - center2[0];
|
|
38984
|
+
const dy = base[1] - center2[1];
|
|
37764
38985
|
const projection = dx * tangent[0] + dy * tangent[1];
|
|
37765
38986
|
const distanceSq = dx * dx + dy * dy - projection * projection;
|
|
37766
38987
|
const radiusSq = radius * radius;
|
|
@@ -37803,7 +39024,7 @@ function roundedRectRadialSliceIntervals(plan, y2) {
|
|
|
37803
39024
|
[-coreHalfWidth, coreHalfHeight],
|
|
37804
39025
|
[-coreHalfWidth, -coreHalfHeight]
|
|
37805
39026
|
];
|
|
37806
|
-
for (const
|
|
39027
|
+
for (const center2 of centers) include(lineIntervalsForCircle(base, tangent, center2, radius));
|
|
37807
39028
|
}
|
|
37808
39029
|
const xFunctional = [basis.xAxis[0], basis.yAxis[0]];
|
|
37809
39030
|
const xAtBase = basis.center[0] + xFunctional[0] * base[0] + xFunctional[1] * base[1];
|
|
@@ -39111,9 +40332,9 @@ function expandSimpleFullRevolutionProfileFootprint(plan, distance) {
|
|
|
39111
40332
|
}
|
|
39112
40333
|
}
|
|
39113
40334
|
function profilePlanForSimpleFullRevolutionFootprint(footprint, segments) {
|
|
39114
|
-
const translate = (profile,
|
|
39115
|
-
if (!isNearlyZero(
|
|
39116
|
-
profile.transforms.push({ kind: "translate", x:
|
|
40335
|
+
const translate = (profile, center2) => {
|
|
40336
|
+
if (!isNearlyZero(center2[0]) || !isNearlyZero(center2[1])) {
|
|
40337
|
+
profile.transforms.push({ kind: "translate", x: center2[0], y: center2[1] });
|
|
39117
40338
|
}
|
|
39118
40339
|
return profile;
|
|
39119
40340
|
};
|
|
@@ -39131,7 +40352,7 @@ function profilePlanForSimpleFullRevolutionFootprint(footprint, segments) {
|
|
|
39131
40352
|
footprint.footprint.center
|
|
39132
40353
|
) : null;
|
|
39133
40354
|
case "roundedRect": {
|
|
39134
|
-
const { halfWidth, halfHeight, radius, xAxis, yAxis, center } = footprint.footprint;
|
|
40355
|
+
const { halfWidth, halfHeight, radius, xAxis, yAxis, center: center2 } = footprint.footprint;
|
|
39135
40356
|
if (halfWidth <= EXACT_PROFILE_EPS || halfHeight <= EXACT_PROFILE_EPS || radius < -EXACT_PROFILE_EPS) return null;
|
|
39136
40357
|
const profile = roundedRectProfilePlan({
|
|
39137
40358
|
width: halfWidth * 2,
|
|
@@ -39146,7 +40367,7 @@ function profilePlanForSimpleFullRevolutionFootprint(footprint, segments) {
|
|
|
39146
40367
|
m11: yAxis[1]
|
|
39147
40368
|
})
|
|
39148
40369
|
);
|
|
39149
|
-
return translate(profile,
|
|
40370
|
+
return translate(profile, center2);
|
|
39150
40371
|
}
|
|
39151
40372
|
default:
|
|
39152
40373
|
return assertExhaustive(footprint);
|
|
@@ -39603,28 +40824,28 @@ function cleanSweepPolyline(points) {
|
|
|
39603
40824
|
function verticalSweepFrameTransforms(path, up) {
|
|
39604
40825
|
if (!up.every(Number.isFinite)) return null;
|
|
39605
40826
|
const [originX, originY] = path[0];
|
|
39606
|
-
let
|
|
40827
|
+
let direction2 = 0;
|
|
39607
40828
|
for (let idx = 1; idx < path.length; idx += 1) {
|
|
39608
40829
|
const [x2, y2, z2] = path[idx];
|
|
39609
40830
|
if (!isNearlyZero(x2 - originX) || !isNearlyZero(y2 - originY)) return null;
|
|
39610
40831
|
const dz = z2 - path[idx - 1][2];
|
|
39611
40832
|
if (isNearlyZero(dz)) return null;
|
|
39612
40833
|
const segmentDirection = dz > 0 ? 1 : -1;
|
|
39613
|
-
if (
|
|
39614
|
-
if (
|
|
40834
|
+
if (direction2 === 0) direction2 = segmentDirection;
|
|
40835
|
+
if (direction2 !== segmentDirection) return null;
|
|
39615
40836
|
}
|
|
39616
|
-
let xAxisX = up[1] *
|
|
39617
|
-
let xAxisY = -up[0] *
|
|
40837
|
+
let xAxisX = up[1] * direction2;
|
|
40838
|
+
let xAxisY = -up[0] * direction2;
|
|
39618
40839
|
let xAxisLength = Math.hypot(xAxisX, xAxisY);
|
|
39619
40840
|
if (xAxisLength <= 1e-8) {
|
|
39620
40841
|
xAxisX = 0;
|
|
39621
|
-
xAxisY = -
|
|
40842
|
+
xAxisY = -direction2;
|
|
39622
40843
|
xAxisLength = 1;
|
|
39623
40844
|
}
|
|
39624
40845
|
xAxisX /= xAxisLength;
|
|
39625
40846
|
xAxisY /= xAxisLength;
|
|
39626
|
-
const yAxisX = -
|
|
39627
|
-
const yAxisY =
|
|
40847
|
+
const yAxisX = -direction2 * xAxisY;
|
|
40848
|
+
const yAxisY = direction2 * xAxisX;
|
|
39628
40849
|
const determinant = xAxisX * yAxisY - yAxisX * xAxisY;
|
|
39629
40850
|
if (Math.abs(Math.abs(determinant) - 1) > 1e-7) return null;
|
|
39630
40851
|
const expectedYAxisX = determinant > 0 ? -xAxisY : xAxisY;
|
|
@@ -39733,16 +40954,16 @@ function exactVerticalProjectionProfilePlan(plan) {
|
|
|
39733
40954
|
const base = exactVerticalProjectionProfilePlan(plan.base);
|
|
39734
40955
|
if (!base) return null;
|
|
39735
40956
|
let profile = base.profile;
|
|
39736
|
-
let
|
|
40957
|
+
let span2 = [base.zMin, base.zMax];
|
|
39737
40958
|
for (const step of plan.steps) {
|
|
39738
40959
|
const projectedTransforms = profileTransformsForShapeTransform(step);
|
|
39739
40960
|
if (!projectedTransforms) return null;
|
|
39740
|
-
const nextSpan = transformZSpan(
|
|
40961
|
+
const nextSpan = transformZSpan(span2, step);
|
|
39741
40962
|
if (!nextSpan) return null;
|
|
39742
40963
|
profile = appendProfileTransforms(profile, projectedTransforms);
|
|
39743
|
-
|
|
40964
|
+
span2 = nextSpan;
|
|
39744
40965
|
}
|
|
39745
|
-
return { profile, zMin:
|
|
40966
|
+
return { profile, zMin: span2[0], zMax: span2[1] };
|
|
39746
40967
|
}
|
|
39747
40968
|
default:
|
|
39748
40969
|
return null;
|
|
@@ -39762,7 +40983,7 @@ function projectVerticalDifferenceProfilePlan(subject, clips) {
|
|
|
39762
40983
|
const clipped = clips.map((clip) => ({ clip, span: clippedZSpan(subject, clip) })).filter((entry) => entry.span != null);
|
|
39763
40984
|
if (clipped.length === 0) return cloneProfileCompilePlan(subject.profile);
|
|
39764
40985
|
const zBreaks = [subject.zMin, subject.zMax];
|
|
39765
|
-
for (const { span } of clipped) zBreaks.push(
|
|
40986
|
+
for (const { span: span2 } of clipped) zBreaks.push(span2[0], span2[1]);
|
|
39766
40987
|
zBreaks.sort((a2, b) => a2 - b);
|
|
39767
40988
|
const uniqueBreaks = [];
|
|
39768
40989
|
for (const z2 of zBreaks) {
|
|
@@ -39775,7 +40996,7 @@ function projectVerticalDifferenceProfilePlan(subject, clips) {
|
|
|
39775
40996
|
const zMax = uniqueBreaks[idx + 1];
|
|
39776
40997
|
if (zMax - zMin <= EXACT_PROFILE_EPS) continue;
|
|
39777
40998
|
const zMid = (zMin + zMax) / 2;
|
|
39778
|
-
const activeClips = clipped.filter(({ span }) => offsetInRange(zMid,
|
|
40999
|
+
const activeClips = clipped.filter(({ span: span2 }) => offsetInRange(zMid, span2[0], span2[1]));
|
|
39779
41000
|
if (activeClips.length === 0) return cloneProfileCompilePlan(subject.profile);
|
|
39780
41001
|
slabProfiles.push({
|
|
39781
41002
|
kind: "boolean",
|
|
@@ -39933,9 +41154,9 @@ function offsetSolidVerticalVariableSweepSlicedProfilePlan(plan, offset) {
|
|
|
39933
41154
|
if (base.kind !== "variableSweep" || !Number.isFinite(plan.thickness) || isNearlyZero(plan.thickness)) return null;
|
|
39934
41155
|
const pathInfo = verticalSweepPathInfo(base.path, base.up);
|
|
39935
41156
|
if (!pathInfo || isNearlyZero(pathInfo.endZ - pathInfo.startZ)) return null;
|
|
39936
|
-
const
|
|
39937
|
-
const startZ = pathInfo.startZ -
|
|
39938
|
-
const endZ = pathInfo.endZ +
|
|
41157
|
+
const direction2 = pathInfo.endZ > pathInfo.startZ ? 1 : -1;
|
|
41158
|
+
const startZ = pathInfo.startZ - direction2 * plan.thickness;
|
|
41159
|
+
const endZ = pathInfo.endZ + direction2 * plan.thickness;
|
|
39939
41160
|
if (Math.abs(endZ - startZ) <= EXACT_PROFILE_EPS) return null;
|
|
39940
41161
|
if (!offsetInRange(offset, startZ, endZ)) return emptyProfilePlan();
|
|
39941
41162
|
const offsetProfileSections = base.sections.map(
|
|
@@ -40748,7 +41969,7 @@ function clusterMeshFaces(shape) {
|
|
|
40748
41969
|
return clusters;
|
|
40749
41970
|
}
|
|
40750
41971
|
function clusterToFaceRef(cluster, name = "") {
|
|
40751
|
-
const
|
|
41972
|
+
const center2 = [
|
|
40752
41973
|
cluster.centroidSum[0] / cluster.count,
|
|
40753
41974
|
cluster.centroidSum[1] / cluster.count,
|
|
40754
41975
|
cluster.centroidSum[2] / cluster.count
|
|
@@ -40757,7 +41978,7 @@ function clusterToFaceRef(cluster, name = "") {
|
|
|
40757
41978
|
return {
|
|
40758
41979
|
name,
|
|
40759
41980
|
normal: cluster.normal,
|
|
40760
|
-
center,
|
|
41981
|
+
center: center2,
|
|
40761
41982
|
planar: true,
|
|
40762
41983
|
uAxis: u2,
|
|
40763
41984
|
vAxis: v
|
|
@@ -40929,7 +42150,7 @@ function representativeFaceForMembers(name, faces, query, semantic) {
|
|
|
40929
42150
|
const cloned = faces.map((face) => cloneFaceRefValue(face));
|
|
40930
42151
|
const first = cloned[0];
|
|
40931
42152
|
const coplanar = facesAreCoplanar(cloned);
|
|
40932
|
-
const
|
|
42153
|
+
const center2 = cloned.reduce(
|
|
40933
42154
|
(acc, face) => [acc[0] + face.center[0], acc[1] + face.center[1], acc[2] + face.center[2]],
|
|
40934
42155
|
[0, 0, 0]
|
|
40935
42156
|
);
|
|
@@ -40937,7 +42158,7 @@ function representativeFaceForMembers(name, faces, query, semantic) {
|
|
|
40937
42158
|
const representative = {
|
|
40938
42159
|
...first,
|
|
40939
42160
|
name,
|
|
40940
|
-
center: [
|
|
42161
|
+
center: [center2[0] / count, center2[1] / count, center2[2] / count],
|
|
40941
42162
|
query: cloneFaceQueryRef(query),
|
|
40942
42163
|
planar: coplanar ? first.planar : false,
|
|
40943
42164
|
uAxis: coplanar ? first.uAxis : void 0,
|
|
@@ -42057,10 +43278,10 @@ function resolveShapeFaceTableInternal(plan, owner) {
|
|
|
42057
43278
|
if (!planeCapQuery) return table;
|
|
42058
43279
|
const baseTable = resolveShapeFaceTable(plan.base);
|
|
42059
43280
|
const centers = Array.from(baseTable.faces.values()).map((face) => face.center);
|
|
42060
|
-
const averageCenter = centers.length > 0 ? centers.reduce((acc,
|
|
43281
|
+
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];
|
|
42061
43282
|
const normal = normalizeAxis([plan.normalX, plan.normalY, plan.normalZ]);
|
|
42062
43283
|
const planeDistance = averageCenter[0] * normal[0] + averageCenter[1] * normal[1] + averageCenter[2] * normal[2] - plan.originOffset;
|
|
42063
|
-
const
|
|
43284
|
+
const center2 = [
|
|
42064
43285
|
averageCenter[0] - normal[0] * planeDistance,
|
|
42065
43286
|
averageCenter[1] - normal[1] * planeDistance,
|
|
42066
43287
|
averageCenter[2] - normal[2] * planeDistance
|
|
@@ -42069,7 +43290,7 @@ function resolveShapeFaceTableInternal(plan, owner) {
|
|
|
42069
43290
|
registerFace(table, {
|
|
42070
43291
|
name: "plane-cap",
|
|
42071
43292
|
normal,
|
|
42072
|
-
center,
|
|
43293
|
+
center: center2,
|
|
42073
43294
|
planar: true,
|
|
42074
43295
|
uAxis: basis.u,
|
|
42075
43296
|
vAxis: basis.v,
|
|
@@ -43256,8 +44477,8 @@ class ShapeGroup {
|
|
|
43256
44477
|
);
|
|
43257
44478
|
}
|
|
43258
44479
|
/** Reorient the group so its local Z axis points along `direction`. */
|
|
43259
|
-
pointAlong(
|
|
43260
|
-
const [dx, dy, dz] = requireNonZeroFiniteVec3(
|
|
44480
|
+
pointAlong(direction2) {
|
|
44481
|
+
const [dx, dy, dz] = requireNonZeroFiniteVec3(direction2, "ShapeGroup.pointAlong() direction");
|
|
43261
44482
|
const len = Math.sqrt(dx * dx + dy * dy + dz * dz) || 1;
|
|
43262
44483
|
const nx = dx / len, ny = dy / len, nz = dz / len;
|
|
43263
44484
|
const cx = -ny, cy = nx, cz = 0;
|
|
@@ -44801,10 +46022,10 @@ function rayTriangle(ox, oy, oz, dx, dy, dz, ax, ay, az, bx, by, bz, cx, cy, cz)
|
|
|
44801
46022
|
const t = (e2x * qx + e2y * qy + e2z * qz) * invDet;
|
|
44802
46023
|
return t;
|
|
44803
46024
|
}
|
|
44804
|
-
function rayMeshIntersect(mesh, origin,
|
|
46025
|
+
function rayMeshIntersect(mesh, origin, direction2) {
|
|
44805
46026
|
const { numProp, numTri, triVerts, vertProperties } = mesh;
|
|
44806
46027
|
const [ox, oy, oz] = origin;
|
|
44807
|
-
const [dx, dy, dz] =
|
|
46028
|
+
const [dx, dy, dz] = direction2;
|
|
44808
46029
|
const hits = [];
|
|
44809
46030
|
for (let t = 0; t < numTri; t++) {
|
|
44810
46031
|
const i0 = triVerts[t * 3];
|
|
@@ -44969,6 +46190,99 @@ function computeSeatOverTranslation(targetFaceVertices, targetFaceNormal, selfMe
|
|
|
44969
46190
|
sampleCount: targetFaceVertices.length
|
|
44970
46191
|
};
|
|
44971
46192
|
}
|
|
46193
|
+
const UV_ANCHORS = ["top", "bottom", "front", "back", "left", "right"];
|
|
46194
|
+
new Set(UV_ANCHORS);
|
|
46195
|
+
const FACE_FRAME = {
|
|
46196
|
+
front: { u: 0, v: 2 },
|
|
46197
|
+
// -y face: u→x, v→z
|
|
46198
|
+
back: { u: 0, v: 2 },
|
|
46199
|
+
// +y face
|
|
46200
|
+
left: { u: 1, v: 2 },
|
|
46201
|
+
// -x face: u→y, v→z
|
|
46202
|
+
right: { u: 1, v: 2 },
|
|
46203
|
+
// +x face
|
|
46204
|
+
top: { u: 0, v: 1 },
|
|
46205
|
+
// +z face: u→x, v→y
|
|
46206
|
+
bottom: { u: 0, v: 1 }
|
|
46207
|
+
// -z face
|
|
46208
|
+
};
|
|
46209
|
+
const AXIS_INDEX = { x: 0, y: 1, z: 2 };
|
|
46210
|
+
function span(bbox, axis) {
|
|
46211
|
+
return bbox.max[axis] - bbox.min[axis];
|
|
46212
|
+
}
|
|
46213
|
+
function center(bbox) {
|
|
46214
|
+
return [
|
|
46215
|
+
(bbox.min[0] + bbox.max[0]) / 2,
|
|
46216
|
+
(bbox.min[1] + bbox.max[1]) / 2,
|
|
46217
|
+
(bbox.min[2] + bbox.max[2]) / 2
|
|
46218
|
+
];
|
|
46219
|
+
}
|
|
46220
|
+
function autoFitProjection(spec, bbox) {
|
|
46221
|
+
switch (spec.kind) {
|
|
46222
|
+
case "flat": {
|
|
46223
|
+
const frame = FACE_FRAME[spec.onto];
|
|
46224
|
+
const out = { ...spec };
|
|
46225
|
+
if (out.width === void 0) {
|
|
46226
|
+
const w2 = span(bbox, frame.u);
|
|
46227
|
+
if (w2 > 0) {
|
|
46228
|
+
out.width = w2;
|
|
46229
|
+
if (out.offsetU === void 0) out.offsetU = bbox.min[frame.u];
|
|
46230
|
+
}
|
|
46231
|
+
}
|
|
46232
|
+
if (out.height === void 0) {
|
|
46233
|
+
const h = span(bbox, frame.v);
|
|
46234
|
+
if (h > 0) {
|
|
46235
|
+
out.height = h;
|
|
46236
|
+
if (out.offsetV === void 0) out.offsetV = bbox.min[frame.v];
|
|
46237
|
+
}
|
|
46238
|
+
}
|
|
46239
|
+
return out;
|
|
46240
|
+
}
|
|
46241
|
+
case "box": {
|
|
46242
|
+
const out = { ...spec };
|
|
46243
|
+
if (out.size === void 0) {
|
|
46244
|
+
const sx = span(bbox, 0);
|
|
46245
|
+
const sy = span(bbox, 1);
|
|
46246
|
+
const sz = span(bbox, 2);
|
|
46247
|
+
if (sx > 0 && sy > 0 && sz > 0) out.size = [sx, sy, sz];
|
|
46248
|
+
}
|
|
46249
|
+
if (out.origin === void 0) out.origin = center(bbox);
|
|
46250
|
+
return out;
|
|
46251
|
+
}
|
|
46252
|
+
case "cylinder": {
|
|
46253
|
+
const axis = AXIS_INDEX[spec.axis];
|
|
46254
|
+
const out = { ...spec };
|
|
46255
|
+
if (out.height === void 0) {
|
|
46256
|
+
const h = span(bbox, axis);
|
|
46257
|
+
if (h > 0) {
|
|
46258
|
+
out.height = h;
|
|
46259
|
+
if (out.offsetV === void 0) out.offsetV = bbox.min[axis];
|
|
46260
|
+
}
|
|
46261
|
+
}
|
|
46262
|
+
if (out.origin === void 0) out.origin = center(bbox);
|
|
46263
|
+
return out;
|
|
46264
|
+
}
|
|
46265
|
+
case "sphere": {
|
|
46266
|
+
const out = { ...spec };
|
|
46267
|
+
if (out.origin === void 0) out.origin = center(bbox);
|
|
46268
|
+
if (out.radius === void 0) {
|
|
46269
|
+
const c2 = center(bbox);
|
|
46270
|
+
const radius = Math.max(
|
|
46271
|
+
bbox.max[0] - c2[0],
|
|
46272
|
+
bbox.max[1] - c2[1],
|
|
46273
|
+
bbox.max[2] - c2[2]
|
|
46274
|
+
);
|
|
46275
|
+
if (radius > 0) out.radius = radius;
|
|
46276
|
+
}
|
|
46277
|
+
return out;
|
|
46278
|
+
}
|
|
46279
|
+
default:
|
|
46280
|
+
throw new Error(`autoFitProjection: unknown projection kind "${spec.kind}"`);
|
|
46281
|
+
}
|
|
46282
|
+
}
|
|
46283
|
+
function isImageHandle(value) {
|
|
46284
|
+
return typeof value === "object" && value !== null && value.__forgeImage === true;
|
|
46285
|
+
}
|
|
44972
46286
|
const _shapeDimensions = /* @__PURE__ */ new WeakMap();
|
|
44973
46287
|
let _shapeDimensionCounter = 0;
|
|
44974
46288
|
function nextShapeDimensionId() {
|
|
@@ -45321,8 +46635,8 @@ function mergeShapeSourceSpans(sources, target) {
|
|
|
45321
46635
|
records = /* @__PURE__ */ new Map();
|
|
45322
46636
|
_shapeSourceSpans.set(target, records);
|
|
45323
46637
|
}
|
|
45324
|
-
for (const [key2,
|
|
45325
|
-
if (!records.has(key2)) records.set(key2,
|
|
46638
|
+
for (const [key2, span2] of sourceRecords) {
|
|
46639
|
+
if (!records.has(key2)) records.set(key2, span2);
|
|
45326
46640
|
}
|
|
45327
46641
|
}
|
|
45328
46642
|
}
|
|
@@ -45559,6 +46873,7 @@ function withBaseDimensions(base, out) {
|
|
|
45559
46873
|
if (baseTopo) _shapeTopology.set(out, cloneTopology(baseTopo));
|
|
45560
46874
|
const baseLabels = cloneFaceLabelMap(_shapeFaceLabels.get(base));
|
|
45561
46875
|
if (baseLabels) _shapeFaceLabels.set(out, baseLabels);
|
|
46876
|
+
if (base.materialProps) out.materialProps = { ...base.materialProps };
|
|
45562
46877
|
copyShapeReferenceMetadata(base, out);
|
|
45563
46878
|
copyShapeSourceSpans(base, out);
|
|
45564
46879
|
return setShapeCompilePlanInternal(out, getShapeCompilePlanInternal(base));
|
|
@@ -45623,6 +46938,30 @@ function createOwnedTopologyRewritePlan(plan, operation2, buildPropagation) {
|
|
|
45623
46938
|
const owner = createShapeQueryOwner(operation2);
|
|
45624
46939
|
return wrapShapeCompilePlanWithQueryOwner(attachTopologyRewritePropagation(plan, buildPropagation(owner)), owner);
|
|
45625
46940
|
}
|
|
46941
|
+
const KNOWN_PROJECTION_KINDS = /* @__PURE__ */ new Set(["flat", "cylinder", "sphere", "box"]);
|
|
46942
|
+
function validateProjectionFinite(spec) {
|
|
46943
|
+
switch (spec.kind) {
|
|
46944
|
+
case "flat":
|
|
46945
|
+
if (spec.width !== void 0) requireFiniteNumber(spec.width, "wrapTexture() flat width");
|
|
46946
|
+
if (spec.height !== void 0) requireFiniteNumber(spec.height, "wrapTexture() flat height");
|
|
46947
|
+
if (spec.offsetU !== void 0) requireFiniteNumber(spec.offsetU, "wrapTexture() flat offsetU");
|
|
46948
|
+
if (spec.offsetV !== void 0) requireFiniteNumber(spec.offsetV, "wrapTexture() flat offsetV");
|
|
46949
|
+
break;
|
|
46950
|
+
case "box":
|
|
46951
|
+
if (spec.size !== void 0) requireFiniteVec3$1(spec.size, "wrapTexture() box size");
|
|
46952
|
+
if (spec.origin !== void 0) requireFiniteVec3$1(spec.origin, "wrapTexture() box origin");
|
|
46953
|
+
break;
|
|
46954
|
+
case "cylinder":
|
|
46955
|
+
if (spec.height !== void 0) requireFiniteNumber(spec.height, "wrapTexture() cylinder height");
|
|
46956
|
+
if (spec.offsetV !== void 0) requireFiniteNumber(spec.offsetV, "wrapTexture() cylinder offsetV");
|
|
46957
|
+
if (spec.origin !== void 0) requireFiniteVec3$1(spec.origin, "wrapTexture() cylinder origin");
|
|
46958
|
+
break;
|
|
46959
|
+
case "sphere":
|
|
46960
|
+
if (spec.origin !== void 0) requireFiniteVec3$1(spec.origin, "wrapTexture() sphere origin");
|
|
46961
|
+
if (spec.radius !== void 0) requireFiniteNumber(spec.radius, "wrapTexture() sphere radius");
|
|
46962
|
+
break;
|
|
46963
|
+
}
|
|
46964
|
+
}
|
|
45626
46965
|
function parseReferencePath(path) {
|
|
45627
46966
|
const trimmed = path.trim();
|
|
45628
46967
|
if (!trimmed) throw new Error("Shape.ref() requires a non-empty path.");
|
|
@@ -46000,6 +47339,61 @@ class Shape {
|
|
|
46000
47339
|
out.materialProps = { ...this.materialProps ?? {}, ...props };
|
|
46001
47340
|
return out;
|
|
46002
47341
|
}
|
|
47342
|
+
/**
|
|
47343
|
+
* Wrap an imported bitmap image around this shape using a projection.
|
|
47344
|
+
*
|
|
47345
|
+
* **Details**
|
|
47346
|
+
*
|
|
47347
|
+
* The `image` comes from `Import.image('path.png')`; the `projection` is one of the `Wrap.*`
|
|
47348
|
+
* helpers — `Wrap.flat({ onto: 'top' })` lays it flat on a face, `Wrap.aroundCylinder({ axis: 'z' })`
|
|
47349
|
+
* wraps it like a can label, `Wrap.onSphere()` maps it like a globe, and `Wrap.box()` cube-maps
|
|
47350
|
+
* it onto the six sides.
|
|
47351
|
+
*
|
|
47352
|
+
* By default the image **auto-fits** the shape — one copy across the relevant extent, so no
|
|
47353
|
+
* `width`/`height`/`size` is needed (pass them only to override). The (u,v) is derived from each
|
|
47354
|
+
* vertex's final world position, so the image stays glued to the surface through transforms and
|
|
47355
|
+
* boolean cuts with no UV layout to maintain — apply `wrapTexture` *after* positioning the shape.
|
|
47356
|
+
* Returns a new Shape; the original is unchanged.
|
|
47357
|
+
*
|
|
47358
|
+
* **Example**
|
|
47359
|
+
*
|
|
47360
|
+
* ```js
|
|
47361
|
+
* const logo = Import.image('./logo.png');
|
|
47362
|
+
* box(80, 80, 10).wrapTexture(logo, Wrap.flat({ onto: 'top' })); // auto-fits the face
|
|
47363
|
+
*
|
|
47364
|
+
* const label = Import.image('./label.jpg');
|
|
47365
|
+
* cylinder(60, 20).wrapTexture(label, Wrap.aroundCylinder({ axis: 'z' })); // wraps the side
|
|
47366
|
+
* ```
|
|
47367
|
+
*
|
|
47368
|
+
* @param image - An imported bitmap from `Import.image(...)`
|
|
47369
|
+
* @param projection - A projection spec from `Wrap.flat` / `Wrap.aroundCylinder` / `Wrap.onSphere` / `Wrap.box`
|
|
47370
|
+
* @returns A new Shape with the projected texture recorded in its material properties
|
|
47371
|
+
* @category Materials
|
|
47372
|
+
*/
|
|
47373
|
+
wrapTexture(image, projection) {
|
|
47374
|
+
if (!isImageHandle(image)) {
|
|
47375
|
+
throw new Error("wrapTexture() expects an image from Import.image(...) as its first argument");
|
|
47376
|
+
}
|
|
47377
|
+
if (!projection || typeof projection !== "object" || !KNOWN_PROJECTION_KINDS.has(projection.kind)) {
|
|
47378
|
+
throw new Error(
|
|
47379
|
+
`wrapTexture() expects a projection from Wrap.flat / Wrap.aroundCylinder / Wrap.onSphere / Wrap.box, got ${JSON.stringify(projection == null ? void 0 : projection.kind)}`
|
|
47380
|
+
);
|
|
47381
|
+
}
|
|
47382
|
+
const bbox = this.boundingBox();
|
|
47383
|
+
const filled = autoFitProjection(projection, bbox);
|
|
47384
|
+
validateProjectionFinite(filled);
|
|
47385
|
+
const out = this.clone();
|
|
47386
|
+
out.materialProps = {
|
|
47387
|
+
...this.materialProps ?? {},
|
|
47388
|
+
texture: {
|
|
47389
|
+
image: image.dataUri,
|
|
47390
|
+
projection: filled,
|
|
47391
|
+
imageWidth: image.width,
|
|
47392
|
+
imageHeight: image.height
|
|
47393
|
+
}
|
|
47394
|
+
};
|
|
47395
|
+
return out;
|
|
47396
|
+
}
|
|
46003
47397
|
/** Return a new Shape wrapper for explicit duplication in scripts. */
|
|
46004
47398
|
clone() {
|
|
46005
47399
|
const out = withCopiedDimensions(this, new Shape(getShapeRuntimeBackendInternal(this).clone(), this.colorHex));
|
|
@@ -46527,12 +47921,12 @@ class Shape {
|
|
|
46527
47921
|
scale(v) {
|
|
46528
47922
|
const scale2 = requireNonZeroFiniteScale3(v, "Shape.scale() scale");
|
|
46529
47923
|
const bb = this.boundingBox();
|
|
46530
|
-
const
|
|
47924
|
+
const center2 = [
|
|
46531
47925
|
(bb.min[0] + bb.max[0]) / 2,
|
|
46532
47926
|
(bb.min[1] + bb.max[1]) / 2,
|
|
46533
47927
|
(bb.min[2] + bb.max[2]) / 2
|
|
46534
47928
|
];
|
|
46535
|
-
return this.scaleAround(
|
|
47929
|
+
return this.scaleAround(center2, scale2);
|
|
46536
47930
|
}
|
|
46537
47931
|
/** Scale the shape uniformly or per-axis from an explicit pivot point. */
|
|
46538
47932
|
scaleAround(pivot, v) {
|
|
@@ -46566,12 +47960,12 @@ class Shape {
|
|
|
46566
47960
|
/** Mirror across a plane through the shape's bounding box center, defined by its normal vector. */
|
|
46567
47961
|
mirror(normal) {
|
|
46568
47962
|
const bb = this.boundingBox();
|
|
46569
|
-
const
|
|
47963
|
+
const center2 = [
|
|
46570
47964
|
(bb.min[0] + bb.max[0]) / 2,
|
|
46571
47965
|
(bb.min[1] + bb.max[1]) / 2,
|
|
46572
47966
|
(bb.min[2] + bb.max[2]) / 2
|
|
46573
47967
|
];
|
|
46574
|
-
return this.mirrorThrough(
|
|
47968
|
+
return this.mirrorThrough(center2, normal);
|
|
46575
47969
|
}
|
|
46576
47970
|
/** Mirror across a plane through an explicit point, defined by its normal vector. */
|
|
46577
47971
|
mirrorThrough(point2, normal) {
|
|
@@ -46611,8 +48005,8 @@ class Shape {
|
|
|
46611
48005
|
*
|
|
46612
48006
|
* Example: cylinder(40, 5).pointAlong([1, 0, 0]) — lays cylinder along X, starting at origin
|
|
46613
48007
|
*/
|
|
46614
|
-
pointAlong(
|
|
46615
|
-
const [dx, dy, dz] = requireNonZeroFiniteVec3(
|
|
48008
|
+
pointAlong(direction2) {
|
|
48009
|
+
const [dx, dy, dz] = requireNonZeroFiniteVec3(direction2, "Shape.pointAlong() direction");
|
|
46616
48010
|
const len = Math.sqrt(dx * dx + dy * dy + dz * dz) || 1;
|
|
46617
48011
|
const nx = dx / len, ny = dy / len, nz = dz / len;
|
|
46618
48012
|
const cx = -ny, cy = nx, cz = 0;
|
|
@@ -49304,731 +50698,204 @@ function thicknessClass(thickness, options) {
|
|
|
49304
50698
|
}
|
|
49305
50699
|
function thicknessColor(thickness, options) {
|
|
49306
50700
|
if (thickness == null || !Number.isFinite(thickness) || thickness <= 0) return THICKNESS_COLORS.unknown;
|
|
49307
|
-
const
|
|
49308
|
-
return gradientColor(THICKNESS_GRADIENT_COLORS, (thickness - options.colorMinThickness) /
|
|
50701
|
+
const span2 = Math.max(1e-9, options.colorMaxThickness - options.colorMinThickness);
|
|
50702
|
+
return gradientColor(THICKNESS_GRADIENT_COLORS, (thickness - options.colorMinThickness) / span2);
|
|
49309
50703
|
}
|
|
49310
|
-
|
|
49311
|
-
|
|
50704
|
+
const CENTER = 0;
|
|
50705
|
+
const AVERAGE = 1;
|
|
50706
|
+
const SAH = 2;
|
|
50707
|
+
const CONTAINED = 2;
|
|
50708
|
+
const TRIANGLE_INTERSECT_COST = 1.25;
|
|
50709
|
+
const TRAVERSAL_COST = 1;
|
|
50710
|
+
const BYTES_PER_NODE = 6 * 4 + 4 + 4;
|
|
50711
|
+
const IS_LEAFNODE_FLAG = 65535;
|
|
50712
|
+
const FLOAT32_EPSILON = Math.pow(2, -24);
|
|
50713
|
+
const SKIP_GENERATION = Symbol("SKIP_GENERATION");
|
|
50714
|
+
function getVertexCount(geo) {
|
|
50715
|
+
return geo.index ? geo.index.count : geo.attributes.position.count;
|
|
49312
50716
|
}
|
|
49313
|
-
function
|
|
49314
|
-
|
|
49315
|
-
const box = geometry.boundingBox;
|
|
49316
|
-
if (!box) return 1;
|
|
49317
|
-
const size = new Vector3();
|
|
49318
|
-
box.getSize(size);
|
|
49319
|
-
return Math.max(1, size.x, size.y, size.z);
|
|
50717
|
+
function getTriCount(geo) {
|
|
50718
|
+
return getVertexCount(geo) / 3;
|
|
49320
50719
|
}
|
|
49321
|
-
function
|
|
49322
|
-
|
|
49323
|
-
|
|
49324
|
-
|
|
49325
|
-
|
|
49326
|
-
const hits = raycaster.intersectObjects(rayTargetMeshes, false);
|
|
49327
|
-
for (const hit of hits) {
|
|
49328
|
-
if (hit.distance <= epsilon2) continue;
|
|
49329
|
-
if (hit.distance <= contactTolerance && jumpableMeshes.has(hit.object)) continue;
|
|
49330
|
-
return hit.distance + epsilon2;
|
|
50720
|
+
function getIndexArray(vertexCount, BufferConstructor = ArrayBuffer) {
|
|
50721
|
+
if (vertexCount > 65535) {
|
|
50722
|
+
return new Uint32Array(new BufferConstructor(4 * vertexCount));
|
|
50723
|
+
} else {
|
|
50724
|
+
return new Uint16Array(new BufferConstructor(2 * vertexCount));
|
|
49331
50725
|
}
|
|
49332
|
-
return null;
|
|
49333
50726
|
}
|
|
49334
|
-
function
|
|
49335
|
-
|
|
49336
|
-
|
|
49337
|
-
|
|
49338
|
-
|
|
49339
|
-
|
|
49340
|
-
|
|
49341
|
-
|
|
49342
|
-
|
|
49343
|
-
|
|
49344
|
-
);
|
|
49345
|
-
const backward = firstOppositeSurfaceDistance(
|
|
49346
|
-
raycaster,
|
|
49347
|
-
rayTargetMeshes,
|
|
49348
|
-
jumpableMeshes,
|
|
49349
|
-
centroid,
|
|
49350
|
-
normal.clone().negate(),
|
|
49351
|
-
epsilon2,
|
|
49352
|
-
far,
|
|
49353
|
-
contactTolerance
|
|
49354
|
-
);
|
|
49355
|
-
if (forward == null) return backward;
|
|
49356
|
-
if (backward == null) return forward;
|
|
49357
|
-
return Math.min(forward, backward);
|
|
50727
|
+
function ensureIndex(geo, options) {
|
|
50728
|
+
if (!geo.index) {
|
|
50729
|
+
const vertexCount = geo.attributes.position.count;
|
|
50730
|
+
const BufferConstructor = options.useSharedArrayBuffer ? SharedArrayBuffer : ArrayBuffer;
|
|
50731
|
+
const index2 = getIndexArray(vertexCount, BufferConstructor);
|
|
50732
|
+
geo.setIndex(new BufferAttribute(index2, 1));
|
|
50733
|
+
for (let i = 0; i < vertexCount; i++) {
|
|
50734
|
+
index2[i] = i;
|
|
50735
|
+
}
|
|
50736
|
+
}
|
|
49358
50737
|
}
|
|
49359
|
-
function
|
|
49360
|
-
const
|
|
49361
|
-
const
|
|
49362
|
-
const
|
|
49363
|
-
|
|
49364
|
-
|
|
49365
|
-
|
|
49366
|
-
|
|
49367
|
-
|
|
49368
|
-
|
|
49369
|
-
|
|
49370
|
-
|
|
49371
|
-
|
|
49372
|
-
|
|
50738
|
+
function getFullGeometryRange(geo, range) {
|
|
50739
|
+
const triCount = getTriCount(geo);
|
|
50740
|
+
const drawRange = range ? range : geo.drawRange;
|
|
50741
|
+
const start = drawRange.start / 3;
|
|
50742
|
+
const end = (drawRange.start + drawRange.count) / 3;
|
|
50743
|
+
const offset = Math.max(0, start);
|
|
50744
|
+
const count = Math.min(triCount, end) - offset;
|
|
50745
|
+
return [{
|
|
50746
|
+
offset: Math.floor(offset),
|
|
50747
|
+
count: Math.floor(count)
|
|
50748
|
+
}];
|
|
50749
|
+
}
|
|
50750
|
+
function getRootIndexRanges(geo, range) {
|
|
50751
|
+
if (!geo.groups || !geo.groups.length) {
|
|
50752
|
+
return getFullGeometryRange(geo, range);
|
|
49373
50753
|
}
|
|
49374
|
-
const
|
|
49375
|
-
const
|
|
49376
|
-
const
|
|
49377
|
-
const
|
|
49378
|
-
const
|
|
49379
|
-
const
|
|
49380
|
-
|
|
49381
|
-
|
|
49382
|
-
|
|
49383
|
-
|
|
49384
|
-
const pointSamples = [];
|
|
49385
|
-
const warnings = [];
|
|
49386
|
-
const rayMaterial = new MeshBasicMaterial({ side: DoubleSide });
|
|
49387
|
-
const rayTargets = [
|
|
49388
|
-
{ mesh: new Mesh(geometry, rayMaterial), jumpable: false },
|
|
49389
|
-
...connectedGeometries.map((connectedGeometry) => ({
|
|
49390
|
-
mesh: new Mesh(connectedGeometry, rayMaterial),
|
|
49391
|
-
jumpable: true
|
|
49392
|
-
}))
|
|
49393
|
-
];
|
|
49394
|
-
const rayTargetMeshes = rayTargets.map((target) => target.mesh);
|
|
49395
|
-
const jumpableMeshes = new Set(rayTargets.filter((target) => target.jumpable).map((target) => target.mesh));
|
|
49396
|
-
const raycaster = new Raycaster();
|
|
49397
|
-
if (surfaceTriangles.length === 0) {
|
|
49398
|
-
warnings.push("No non-degenerate triangle surface was available for thickness sampling.");
|
|
49399
|
-
} else if (surfaceSamples.length < surfaceTriangles.length) {
|
|
49400
|
-
warnings.push(
|
|
49401
|
-
`Area sampling budget ${surfaceSamples.length} covers ${surfaceTriangles.length} surface triangles; increase --thickness-samples for denser analysis.`
|
|
49402
|
-
);
|
|
50754
|
+
const ranges = [];
|
|
50755
|
+
const rangeBoundaries = /* @__PURE__ */ new Set();
|
|
50756
|
+
const drawRange = range ? range : geo.drawRange;
|
|
50757
|
+
const drawRangeStart = drawRange.start / 3;
|
|
50758
|
+
const drawRangeEnd = (drawRange.start + drawRange.count) / 3;
|
|
50759
|
+
for (const group of geo.groups) {
|
|
50760
|
+
const groupStart = group.start / 3;
|
|
50761
|
+
const groupEnd = (group.start + group.count) / 3;
|
|
50762
|
+
rangeBoundaries.add(Math.max(drawRangeStart, groupStart));
|
|
50763
|
+
rangeBoundaries.add(Math.min(drawRangeEnd, groupEnd));
|
|
49403
50764
|
}
|
|
49404
|
-
const
|
|
49405
|
-
for (
|
|
49406
|
-
|
|
49407
|
-
const
|
|
49408
|
-
|
|
49409
|
-
|
|
49410
|
-
|
|
49411
|
-
sample.position,
|
|
49412
|
-
sample.normal,
|
|
49413
|
-
epsilon2,
|
|
49414
|
-
far,
|
|
49415
|
-
options.contactTolerance
|
|
49416
|
-
);
|
|
49417
|
-
samples.push({ thickness, area: sample.area });
|
|
49418
|
-
const previous = triangleThicknessValues[sample.triangle.index];
|
|
49419
|
-
if (previous === void 0 || previous == null || thickness != null && thickness < previous) {
|
|
49420
|
-
triangleThicknessValues[sample.triangle.index] = thickness;
|
|
49421
|
-
}
|
|
49422
|
-
pointSamples.push({
|
|
49423
|
-
position: [sample.position.x, sample.position.y, sample.position.z],
|
|
49424
|
-
normal: [sample.normal.x, sample.normal.y, sample.normal.z],
|
|
49425
|
-
value: thickness,
|
|
49426
|
-
className: thicknessClass(thickness, options),
|
|
49427
|
-
color: thicknessColor(thickness, options),
|
|
49428
|
-
area: sample.area
|
|
50765
|
+
const sortedBoundaries = Array.from(rangeBoundaries.values()).sort((a2, b) => a2 - b);
|
|
50766
|
+
for (let i = 0; i < sortedBoundaries.length - 1; i++) {
|
|
50767
|
+
const start = sortedBoundaries[i];
|
|
50768
|
+
const end = sortedBoundaries[i + 1];
|
|
50769
|
+
ranges.push({
|
|
50770
|
+
offset: Math.floor(start),
|
|
50771
|
+
count: Math.floor(end - start)
|
|
49429
50772
|
});
|
|
49430
50773
|
}
|
|
49431
|
-
|
|
49432
|
-
const color = thicknessColor(triangleThicknessValues[tri], options);
|
|
49433
|
-
const offset = tri * 3;
|
|
49434
|
-
for (let vertex2 = 0; vertex2 < 3; vertex2 += 1) {
|
|
49435
|
-
const colorOffset = (offset + vertex2) * 3;
|
|
49436
|
-
colors[colorOffset] = color[0] / 255;
|
|
49437
|
-
colors[colorOffset + 1] = color[1] / 255;
|
|
49438
|
-
colors[colorOffset + 2] = color[2] / 255;
|
|
49439
|
-
}
|
|
49440
|
-
}
|
|
49441
|
-
geometry.setAttribute("color", new BufferAttribute(colors, 3));
|
|
49442
|
-
rayMaterial.dispose();
|
|
49443
|
-
return {
|
|
49444
|
-
geometry,
|
|
49445
|
-
samples,
|
|
49446
|
-
pointSamples,
|
|
49447
|
-
triangleCount,
|
|
49448
|
-
sampledTriangleCount: sampledTriangleIndexes.size,
|
|
49449
|
-
sampleStride: Math.max(1, Math.ceil(Math.max(1, surfaceTriangles.length) / Math.max(1, sampledTriangleIndexes.size))),
|
|
49450
|
-
warnings
|
|
49451
|
-
};
|
|
49452
|
-
}
|
|
49453
|
-
const DEFAULT_VERTEX_CAP = 2e6;
|
|
49454
|
-
const DEFAULT_TARGET_EDGE_SPACING_FACTOR = 2;
|
|
49455
|
-
const DEFAULT_K = 8;
|
|
49456
|
-
const DEFAULT_GATE_DOT = 0.3;
|
|
49457
|
-
const SCATTER_CELL_SPACING_FACTOR = 1.5;
|
|
49458
|
-
const SCATTER_RADIUS_SPACING_FACTOR = 3;
|
|
49459
|
-
const IDW_DISTANCE_FLOOR = 1e-9;
|
|
49460
|
-
const MAX_SUBDIVISION_PASSES = 24;
|
|
49461
|
-
function subVec(a2, b) {
|
|
49462
|
-
return [a2[0] - b[0], a2[1] - b[1], a2[2] - b[2]];
|
|
49463
|
-
}
|
|
49464
|
-
function crossVec(a2, b) {
|
|
49465
|
-
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]];
|
|
49466
|
-
}
|
|
49467
|
-
function lenVec(a2) {
|
|
49468
|
-
return Math.hypot(a2[0], a2[1], a2[2]);
|
|
49469
|
-
}
|
|
49470
|
-
function getVert(positions, i) {
|
|
49471
|
-
const o = i * 3;
|
|
49472
|
-
return [positions[o], positions[o + 1], positions[o + 2]];
|
|
49473
|
-
}
|
|
49474
|
-
function triArea(positions, a2, b, c2) {
|
|
49475
|
-
const va = getVert(positions, a2);
|
|
49476
|
-
return 0.5 * lenVec(crossVec(subVec(getVert(positions, b), va), subVec(getVert(positions, c2), va)));
|
|
49477
|
-
}
|
|
49478
|
-
function triNormal(positions, a2, b, c2) {
|
|
49479
|
-
const va = getVert(positions, a2);
|
|
49480
|
-
const n = crossVec(subVec(getVert(positions, b), va), subVec(getVert(positions, c2), va));
|
|
49481
|
-
const l = lenVec(n) || 1;
|
|
49482
|
-
return [n[0] / l, n[1] / l, n[2] / l];
|
|
50774
|
+
return ranges;
|
|
49483
50775
|
}
|
|
49484
|
-
function
|
|
49485
|
-
|
|
50776
|
+
function hasGroupGaps(geometry, range) {
|
|
50777
|
+
const vertexCount = getTriCount(geometry);
|
|
50778
|
+
const groups = getRootIndexRanges(geometry, range).sort((a2, b) => a2.offset - b.offset);
|
|
50779
|
+
const finalGroup = groups[groups.length - 1];
|
|
50780
|
+
finalGroup.count = Math.min(vertexCount - finalGroup.offset, finalGroup.count);
|
|
50781
|
+
let total = 0;
|
|
50782
|
+
groups.forEach(({ count }) => total += count);
|
|
50783
|
+
return vertexCount !== total;
|
|
49486
50784
|
}
|
|
49487
|
-
function
|
|
49488
|
-
|
|
50785
|
+
function getBounds(triangleBounds2, offset, count, target, centroidTarget) {
|
|
50786
|
+
let minx = Infinity;
|
|
50787
|
+
let miny = Infinity;
|
|
50788
|
+
let minz = Infinity;
|
|
50789
|
+
let maxx = -Infinity;
|
|
50790
|
+
let maxy = -Infinity;
|
|
50791
|
+
let maxz = -Infinity;
|
|
50792
|
+
let cminx = Infinity;
|
|
50793
|
+
let cminy = Infinity;
|
|
50794
|
+
let cminz = Infinity;
|
|
50795
|
+
let cmaxx = -Infinity;
|
|
50796
|
+
let cmaxy = -Infinity;
|
|
50797
|
+
let cmaxz = -Infinity;
|
|
50798
|
+
for (let i = offset * 6, end = (offset + count) * 6; i < end; i += 6) {
|
|
50799
|
+
const cx = triangleBounds2[i + 0];
|
|
50800
|
+
const hx = triangleBounds2[i + 1];
|
|
50801
|
+
const lx = cx - hx;
|
|
50802
|
+
const rx = cx + hx;
|
|
50803
|
+
if (lx < minx) minx = lx;
|
|
50804
|
+
if (rx > maxx) maxx = rx;
|
|
50805
|
+
if (cx < cminx) cminx = cx;
|
|
50806
|
+
if (cx > cmaxx) cmaxx = cx;
|
|
50807
|
+
const cy = triangleBounds2[i + 2];
|
|
50808
|
+
const hy = triangleBounds2[i + 3];
|
|
50809
|
+
const ly = cy - hy;
|
|
50810
|
+
const ry = cy + hy;
|
|
50811
|
+
if (ly < miny) miny = ly;
|
|
50812
|
+
if (ry > maxy) maxy = ry;
|
|
50813
|
+
if (cy < cminy) cminy = cy;
|
|
50814
|
+
if (cy > cmaxy) cmaxy = cy;
|
|
50815
|
+
const cz = triangleBounds2[i + 4];
|
|
50816
|
+
const hz = triangleBounds2[i + 5];
|
|
50817
|
+
const lz = cz - hz;
|
|
50818
|
+
const rz = cz + hz;
|
|
50819
|
+
if (lz < minz) minz = lz;
|
|
50820
|
+
if (rz > maxz) maxz = rz;
|
|
50821
|
+
if (cz < cminz) cminz = cz;
|
|
50822
|
+
if (cz > cmaxz) cmaxz = cz;
|
|
50823
|
+
}
|
|
50824
|
+
target[0] = minx;
|
|
50825
|
+
target[1] = miny;
|
|
50826
|
+
target[2] = minz;
|
|
50827
|
+
target[3] = maxx;
|
|
50828
|
+
target[4] = maxy;
|
|
50829
|
+
target[5] = maxz;
|
|
50830
|
+
centroidTarget[0] = cminx;
|
|
50831
|
+
centroidTarget[1] = cminy;
|
|
50832
|
+
centroidTarget[2] = cminz;
|
|
50833
|
+
centroidTarget[3] = cmaxx;
|
|
50834
|
+
centroidTarget[4] = cmaxy;
|
|
50835
|
+
centroidTarget[5] = cmaxz;
|
|
49489
50836
|
}
|
|
49490
|
-
function
|
|
49491
|
-
|
|
49492
|
-
|
|
49493
|
-
|
|
49494
|
-
|
|
50837
|
+
function computeTriangleBounds(geo, target = null, offset = null, count = null) {
|
|
50838
|
+
const posAttr = geo.attributes.position;
|
|
50839
|
+
const index2 = geo.index ? geo.index.array : null;
|
|
50840
|
+
const triCount = getTriCount(geo);
|
|
50841
|
+
const normalized = posAttr.normalized;
|
|
50842
|
+
let triangleBounds2;
|
|
50843
|
+
if (target === null) {
|
|
50844
|
+
triangleBounds2 = new Float32Array(triCount * 6);
|
|
50845
|
+
offset = 0;
|
|
50846
|
+
count = triCount;
|
|
50847
|
+
} else {
|
|
50848
|
+
triangleBounds2 = target;
|
|
50849
|
+
offset = offset || 0;
|
|
50850
|
+
count = count || triCount;
|
|
49495
50851
|
}
|
|
49496
|
-
|
|
49497
|
-
|
|
49498
|
-
let
|
|
49499
|
-
|
|
49500
|
-
|
|
49501
|
-
let maxY = -Infinity;
|
|
49502
|
-
let maxZ = -Infinity;
|
|
49503
|
-
for (let i = 0; i < positions.length; i += 3) {
|
|
49504
|
-
const x2 = positions[i];
|
|
49505
|
-
const y2 = positions[i + 1];
|
|
49506
|
-
const z2 = positions[i + 2];
|
|
49507
|
-
if (!Number.isFinite(x2) || !Number.isFinite(y2) || !Number.isFinite(z2)) {
|
|
49508
|
-
throw new Error(`weld: non-finite vertex position at float index ${i}`);
|
|
49509
|
-
}
|
|
49510
|
-
if (x2 < minX) minX = x2;
|
|
49511
|
-
if (y2 < minY) minY = y2;
|
|
49512
|
-
if (z2 < minZ) minZ = z2;
|
|
49513
|
-
if (x2 > maxX) maxX = x2;
|
|
49514
|
-
if (y2 > maxY) maxY = y2;
|
|
49515
|
-
if (z2 > maxZ) maxZ = z2;
|
|
50852
|
+
const posArr = posAttr.array;
|
|
50853
|
+
const bufferOffset = posAttr.offset || 0;
|
|
50854
|
+
let stride = 3;
|
|
50855
|
+
if (posAttr.isInterleavedBufferAttribute) {
|
|
50856
|
+
stride = posAttr.data.stride;
|
|
49516
50857
|
}
|
|
49517
|
-
const
|
|
49518
|
-
|
|
49519
|
-
|
|
49520
|
-
|
|
49521
|
-
|
|
49522
|
-
|
|
49523
|
-
|
|
49524
|
-
|
|
49525
|
-
|
|
49526
|
-
|
|
49527
|
-
|
|
49528
|
-
};
|
|
49529
|
-
for (let tri = 0; tri < positions.length; tri += 9) {
|
|
49530
|
-
const idx = [];
|
|
49531
|
-
for (let corner = 0; corner < 3; corner += 1) {
|
|
49532
|
-
const o = tri + corner * 3;
|
|
49533
|
-
const key2 = quantKey(o);
|
|
49534
|
-
let vi = remap.get(key2);
|
|
49535
|
-
if (vi === void 0) {
|
|
49536
|
-
vi = out.length / 3;
|
|
49537
|
-
out.push(positions[o], positions[o + 1], positions[o + 2]);
|
|
49538
|
-
remap.set(key2, vi);
|
|
49539
|
-
}
|
|
49540
|
-
idx.push(vi);
|
|
50858
|
+
const getters = ["getX", "getY", "getZ"];
|
|
50859
|
+
for (let tri = offset; tri < offset + count; tri++) {
|
|
50860
|
+
const tri3 = tri * 3;
|
|
50861
|
+
const tri6 = tri * 6;
|
|
50862
|
+
let ai = tri3 + 0;
|
|
50863
|
+
let bi = tri3 + 1;
|
|
50864
|
+
let ci = tri3 + 2;
|
|
50865
|
+
if (index2) {
|
|
50866
|
+
ai = index2[ai];
|
|
50867
|
+
bi = index2[bi];
|
|
50868
|
+
ci = index2[ci];
|
|
49541
50869
|
}
|
|
49542
|
-
if (
|
|
49543
|
-
|
|
50870
|
+
if (!normalized) {
|
|
50871
|
+
ai = ai * stride + bufferOffset;
|
|
50872
|
+
bi = bi * stride + bufferOffset;
|
|
50873
|
+
ci = ci * stride + bufferOffset;
|
|
49544
50874
|
}
|
|
49545
|
-
|
|
49546
|
-
|
|
49547
|
-
|
|
49548
|
-
|
|
49549
|
-
|
|
49550
|
-
|
|
49551
|
-
requirePositiveFiniteNumber(targetEdge, "adaptiveSubdivide targetEdge");
|
|
49552
|
-
requireIntegerAtLeast(vertexCap, "adaptiveSubdivide vertexCap", 3);
|
|
49553
|
-
const positions = mesh.positions.slice();
|
|
49554
|
-
let tris = mesh.tris.slice();
|
|
49555
|
-
let capped = false;
|
|
49556
|
-
const keyOf = (a2, b) => a2 < b ? `${a2}_${b}` : `${b}_${a2}`;
|
|
49557
|
-
for (let pass = 0; pass < MAX_SUBDIVISION_PASSES; pass += 1) {
|
|
49558
|
-
const next = [];
|
|
49559
|
-
const midCache = /* @__PURE__ */ new Map();
|
|
49560
|
-
let changed = false;
|
|
49561
|
-
const getMid = (a2, b) => {
|
|
49562
|
-
const key2 = keyOf(a2, b);
|
|
49563
|
-
let mi = midCache.get(key2);
|
|
49564
|
-
if (mi === void 0) {
|
|
49565
|
-
mi = positions.length / 3;
|
|
49566
|
-
const ao = a2 * 3;
|
|
49567
|
-
const bo = b * 3;
|
|
49568
|
-
positions.push(
|
|
49569
|
-
(positions[ao] + positions[bo]) / 2,
|
|
49570
|
-
(positions[ao + 1] + positions[bo + 1]) / 2,
|
|
49571
|
-
(positions[ao + 2] + positions[bo + 2]) / 2
|
|
49572
|
-
);
|
|
49573
|
-
midCache.set(key2, mi);
|
|
49574
|
-
}
|
|
49575
|
-
return mi;
|
|
49576
|
-
};
|
|
49577
|
-
for (let t = 0; t < tris.length; t += 3) {
|
|
49578
|
-
const a2 = tris[t];
|
|
49579
|
-
const b = tris[t + 1];
|
|
49580
|
-
const c2 = tris[t + 2];
|
|
49581
|
-
const vertexCount = positions.length / 3;
|
|
49582
|
-
if (maxEdge(positions, a2, b, c2) > targetEdge && vertexCount < vertexCap) {
|
|
49583
|
-
const ab = getMid(a2, b);
|
|
49584
|
-
const bc = getMid(b, c2);
|
|
49585
|
-
const ca = getMid(c2, a2);
|
|
49586
|
-
next.push(a2, ab, ca, ab, b, bc, ca, bc, c2, ab, bc, ca);
|
|
49587
|
-
changed = true;
|
|
50875
|
+
for (let el = 0; el < 3; el++) {
|
|
50876
|
+
let a2, b, c2;
|
|
50877
|
+
if (normalized) {
|
|
50878
|
+
a2 = posAttr[getters[el]](ai);
|
|
50879
|
+
b = posAttr[getters[el]](bi);
|
|
50880
|
+
c2 = posAttr[getters[el]](ci);
|
|
49588
50881
|
} else {
|
|
49589
|
-
|
|
49590
|
-
|
|
50882
|
+
a2 = posArr[ai + el];
|
|
50883
|
+
b = posArr[bi + el];
|
|
50884
|
+
c2 = posArr[ci + el];
|
|
49591
50885
|
}
|
|
50886
|
+
let min2 = a2;
|
|
50887
|
+
if (b < min2) min2 = b;
|
|
50888
|
+
if (c2 < min2) min2 = c2;
|
|
50889
|
+
let max2 = a2;
|
|
50890
|
+
if (b > max2) max2 = b;
|
|
50891
|
+
if (c2 > max2) max2 = c2;
|
|
50892
|
+
const halfExtents = (max2 - min2) / 2;
|
|
50893
|
+
const el2 = el * 2;
|
|
50894
|
+
triangleBounds2[tri6 + el2 + 0] = min2 + halfExtents;
|
|
50895
|
+
triangleBounds2[tri6 + el2 + 1] = halfExtents + (Math.abs(min2) + halfExtents) * FLOAT32_EPSILON;
|
|
49592
50896
|
}
|
|
49593
|
-
tris = next;
|
|
49594
|
-
if (!changed) break;
|
|
49595
50897
|
}
|
|
49596
|
-
return
|
|
49597
|
-
}
|
|
49598
|
-
function vertexNormals(mesh) {
|
|
49599
|
-
const vertexCount = mesh.positions.length / 3;
|
|
49600
|
-
const acc = new Float32Array(vertexCount * 3);
|
|
49601
|
-
for (let t = 0; t < mesh.tris.length; t += 3) {
|
|
49602
|
-
const a2 = mesh.tris[t];
|
|
49603
|
-
const b = mesh.tris[t + 1];
|
|
49604
|
-
const c2 = mesh.tris[t + 2];
|
|
49605
|
-
const n = triNormal(mesh.positions, a2, b, c2);
|
|
49606
|
-
const area = triArea(mesh.positions, a2, b, c2);
|
|
49607
|
-
const nx = n[0] * area;
|
|
49608
|
-
const ny = n[1] * area;
|
|
49609
|
-
const nz = n[2] * area;
|
|
49610
|
-
for (const vi of [a2, b, c2]) {
|
|
49611
|
-
acc[vi * 3] += nx;
|
|
49612
|
-
acc[vi * 3 + 1] += ny;
|
|
49613
|
-
acc[vi * 3 + 2] += nz;
|
|
49614
|
-
}
|
|
49615
|
-
}
|
|
49616
|
-
for (let i = 0; i < vertexCount; i += 1) {
|
|
49617
|
-
const o = i * 3;
|
|
49618
|
-
const l = Math.hypot(acc[o], acc[o + 1], acc[o + 2]) || 1;
|
|
49619
|
-
acc[o] /= l;
|
|
49620
|
-
acc[o + 1] /= l;
|
|
49621
|
-
acc[o + 2] /= l;
|
|
49622
|
-
}
|
|
49623
|
-
return acc;
|
|
49624
|
-
}
|
|
49625
|
-
function buildSampleGrid(positions, cell) {
|
|
49626
|
-
const grid = /* @__PURE__ */ new Map();
|
|
49627
|
-
const sampleCount = positions.length / 3;
|
|
49628
|
-
for (let i = 0; i < sampleCount; i += 1) {
|
|
49629
|
-
const o = i * 3;
|
|
49630
|
-
const key2 = `${Math.floor(positions[o] / cell)},${Math.floor(positions[o + 1] / cell)},${Math.floor(positions[o + 2] / cell)}`;
|
|
49631
|
-
let arr = grid.get(key2);
|
|
49632
|
-
if (!arr) {
|
|
49633
|
-
arr = [];
|
|
49634
|
-
grid.set(key2, arr);
|
|
49635
|
-
}
|
|
49636
|
-
arr.push(i);
|
|
49637
|
-
}
|
|
49638
|
-
return { grid, cell };
|
|
49639
|
-
}
|
|
49640
|
-
function gatherSamples(sampleGrid, p2, rings, out) {
|
|
49641
|
-
out.length = 0;
|
|
49642
|
-
const { cell, grid } = sampleGrid;
|
|
49643
|
-
const bx = Math.floor(p2[0] / cell);
|
|
49644
|
-
const by = Math.floor(p2[1] / cell);
|
|
49645
|
-
const bz = Math.floor(p2[2] / cell);
|
|
49646
|
-
for (let dx = -rings; dx <= rings; dx += 1) {
|
|
49647
|
-
for (let dy = -rings; dy <= rings; dy += 1) {
|
|
49648
|
-
for (let dz = -rings; dz <= rings; dz += 1) {
|
|
49649
|
-
const arr = grid.get(`${bx + dx},${by + dy},${bz + dz}`);
|
|
49650
|
-
if (arr) for (const i of arr) out.push(i);
|
|
49651
|
-
}
|
|
49652
|
-
}
|
|
49653
|
-
}
|
|
49654
|
-
}
|
|
49655
|
-
function scatterToVertices(positions, vnormals, samples, spacing, k2, gateDot) {
|
|
49656
|
-
const cell = spacing * SCATTER_CELL_SPACING_FACTOR;
|
|
49657
|
-
const sampleGrid = buildSampleGrid(samples.positions, cell);
|
|
49658
|
-
const radius = spacing * SCATTER_RADIUS_SPACING_FACTOR;
|
|
49659
|
-
const radius2 = radius * radius;
|
|
49660
|
-
const vertexCount = positions.length / 3;
|
|
49661
|
-
const values = new Float32Array(vertexCount);
|
|
49662
|
-
let holeCount = 0;
|
|
49663
|
-
const candidates = [];
|
|
49664
|
-
const scratchP = [0, 0, 0];
|
|
49665
|
-
const bestD2 = new Float64Array(k2);
|
|
49666
|
-
const bestVal = new Float64Array(k2);
|
|
49667
|
-
for (let vi = 0; vi < vertexCount; vi += 1) {
|
|
49668
|
-
const pi = vi * 3;
|
|
49669
|
-
const px = positions[pi];
|
|
49670
|
-
const py = positions[pi + 1];
|
|
49671
|
-
const pz = positions[pi + 2];
|
|
49672
|
-
const nx = vnormals[pi];
|
|
49673
|
-
const ny = vnormals[pi + 1];
|
|
49674
|
-
const nz = vnormals[pi + 2];
|
|
49675
|
-
scratchP[0] = px;
|
|
49676
|
-
scratchP[1] = py;
|
|
49677
|
-
scratchP[2] = pz;
|
|
49678
|
-
gatherSamples(sampleGrid, scratchP, 3, candidates);
|
|
49679
|
-
let count = 0;
|
|
49680
|
-
let worst = 0;
|
|
49681
|
-
let worstD2 = -Infinity;
|
|
49682
|
-
for (let c2 = 0; c2 < candidates.length; c2 += 1) {
|
|
49683
|
-
const si = candidates[c2];
|
|
49684
|
-
const so = si * 3;
|
|
49685
|
-
const dx = samples.positions[so] - px;
|
|
49686
|
-
const dy = samples.positions[so + 1] - py;
|
|
49687
|
-
const dz = samples.positions[so + 2] - pz;
|
|
49688
|
-
const d2 = dx * dx + dy * dy + dz * dz;
|
|
49689
|
-
if (d2 > radius2) continue;
|
|
49690
|
-
if (samples.normals[so] * nx + samples.normals[so + 1] * ny + samples.normals[so + 2] * nz < gateDot) continue;
|
|
49691
|
-
const val = samples.values[si];
|
|
49692
|
-
if (count < k2) {
|
|
49693
|
-
bestD2[count] = d2;
|
|
49694
|
-
bestVal[count] = val;
|
|
49695
|
-
if (d2 > worstD2) {
|
|
49696
|
-
worstD2 = d2;
|
|
49697
|
-
worst = count;
|
|
49698
|
-
}
|
|
49699
|
-
count += 1;
|
|
49700
|
-
} else if (d2 < worstD2) {
|
|
49701
|
-
bestD2[worst] = d2;
|
|
49702
|
-
bestVal[worst] = val;
|
|
49703
|
-
worstD2 = -Infinity;
|
|
49704
|
-
for (let t = 0; t < k2; t += 1) {
|
|
49705
|
-
if (bestD2[t] > worstD2) {
|
|
49706
|
-
worstD2 = bestD2[t];
|
|
49707
|
-
worst = t;
|
|
49708
|
-
}
|
|
49709
|
-
}
|
|
49710
|
-
}
|
|
49711
|
-
}
|
|
49712
|
-
if (count === 0) {
|
|
49713
|
-
holeCount += 1;
|
|
49714
|
-
values[vi] = NaN;
|
|
49715
|
-
continue;
|
|
49716
|
-
}
|
|
49717
|
-
let w2 = 0;
|
|
49718
|
-
let acc = 0;
|
|
49719
|
-
for (let t = 0; t < count; t += 1) {
|
|
49720
|
-
const ww = 1 / Math.max(bestD2[t], IDW_DISTANCE_FLOOR);
|
|
49721
|
-
w2 += ww;
|
|
49722
|
-
acc += ww * bestVal[t];
|
|
49723
|
-
}
|
|
49724
|
-
values[vi] = acc / w2;
|
|
49725
|
-
}
|
|
49726
|
-
return { values, holeCount };
|
|
49727
|
-
}
|
|
49728
|
-
function backfillHoles(values, mesh) {
|
|
49729
|
-
const vertexCount = values.length;
|
|
49730
|
-
const adjacency = Array.from({ length: vertexCount }, () => []);
|
|
49731
|
-
for (let t = 0; t < mesh.tris.length; t += 3) {
|
|
49732
|
-
const a2 = mesh.tris[t];
|
|
49733
|
-
const b = mesh.tris[t + 1];
|
|
49734
|
-
const c2 = mesh.tris[t + 2];
|
|
49735
|
-
adjacency[a2].push(b, c2);
|
|
49736
|
-
adjacency[b].push(a2, c2);
|
|
49737
|
-
adjacency[c2].push(a2, b);
|
|
49738
|
-
}
|
|
49739
|
-
let frontier = [];
|
|
49740
|
-
for (let i = 0; i < vertexCount; i += 1) {
|
|
49741
|
-
if (Number.isFinite(values[i])) frontier.push(i);
|
|
49742
|
-
}
|
|
49743
|
-
if (frontier.length === 0) {
|
|
49744
|
-
values.fill(0);
|
|
49745
|
-
return;
|
|
49746
|
-
}
|
|
49747
|
-
while (frontier.length > 0) {
|
|
49748
|
-
const nextFrontier = [];
|
|
49749
|
-
for (const v of frontier) {
|
|
49750
|
-
const val = values[v];
|
|
49751
|
-
for (const n of adjacency[v]) {
|
|
49752
|
-
if (!Number.isFinite(values[n])) {
|
|
49753
|
-
values[n] = val;
|
|
49754
|
-
nextFrontier.push(n);
|
|
49755
|
-
}
|
|
49756
|
-
}
|
|
49757
|
-
}
|
|
49758
|
-
frontier = nextFrontier;
|
|
49759
|
-
}
|
|
49760
|
-
}
|
|
49761
|
-
function reconstructSurfaceScalarField(trianglePositions, samples, options = {}) {
|
|
49762
|
-
if (!(trianglePositions instanceof Float32Array)) {
|
|
49763
|
-
throw new Error("reconstructSurfaceScalarField: trianglePositions must be a Float32Array");
|
|
49764
|
-
}
|
|
49765
|
-
if (trianglePositions.length === 0 || trianglePositions.length % 9 !== 0) {
|
|
49766
|
-
throw new Error(
|
|
49767
|
-
`reconstructSurfaceScalarField: trianglePositions length must be a positive multiple of 9, got ${trianglePositions.length}`
|
|
49768
|
-
);
|
|
49769
|
-
}
|
|
49770
|
-
if (!(samples.positions instanceof Float32Array) || !(samples.values instanceof Float32Array) || !(samples.normals instanceof Float32Array)) {
|
|
49771
|
-
throw new Error("reconstructSurfaceScalarField: samples positions/values/normals must be Float32Arrays");
|
|
49772
|
-
}
|
|
49773
|
-
const sampleCount = samples.values.length;
|
|
49774
|
-
if (sampleCount === 0) {
|
|
49775
|
-
throw new Error("reconstructSurfaceScalarField: samples must be non-empty");
|
|
49776
|
-
}
|
|
49777
|
-
if (samples.positions.length !== sampleCount * 3) {
|
|
49778
|
-
throw new Error(
|
|
49779
|
-
`reconstructSurfaceScalarField: samples.positions length ${samples.positions.length} must equal values*3 (${sampleCount * 3})`
|
|
49780
|
-
);
|
|
49781
|
-
}
|
|
49782
|
-
if (samples.normals.length !== sampleCount * 3) {
|
|
49783
|
-
throw new Error(
|
|
49784
|
-
`reconstructSurfaceScalarField: samples.normals length ${samples.normals.length} must equal values*3 (${sampleCount * 3})`
|
|
49785
|
-
);
|
|
49786
|
-
}
|
|
49787
|
-
for (let i = 0; i < sampleCount; i += 1) {
|
|
49788
|
-
requireFiniteNumber(samples.values[i], `samples.values[${i}]`);
|
|
49789
|
-
}
|
|
49790
|
-
const vertexCap = options.vertexCap === void 0 ? DEFAULT_VERTEX_CAP : requireIntegerAtLeast(options.vertexCap, "vertexCap", 3);
|
|
49791
|
-
const targetEdgeSpacingFactor = options.targetEdgeSpacingFactor === void 0 ? DEFAULT_TARGET_EDGE_SPACING_FACTOR : requirePositiveFiniteNumber(options.targetEdgeSpacingFactor, "targetEdgeSpacingFactor");
|
|
49792
|
-
const k2 = options.k === void 0 ? DEFAULT_K : requireIntegerAtLeast(options.k, "k", 1);
|
|
49793
|
-
const gateDot = options.gateDot === void 0 ? DEFAULT_GATE_DOT : requireFiniteNumber(options.gateDot, "gateDot");
|
|
49794
|
-
const welded = weld(trianglePositions);
|
|
49795
|
-
let surfaceArea = 0;
|
|
49796
|
-
for (let t = 0; t < welded.tris.length; t += 3) {
|
|
49797
|
-
surfaceArea += triArea(welded.positions, welded.tris[t], welded.tris[t + 1], welded.tris[t + 2]);
|
|
49798
|
-
}
|
|
49799
|
-
const sampleSpacing = surfaceArea > 0 ? Math.sqrt(surfaceArea / sampleCount) : 0;
|
|
49800
|
-
let subdivided;
|
|
49801
|
-
if (welded.degenerate || !(sampleSpacing > 0)) {
|
|
49802
|
-
subdivided = { positions: welded.positions, tris: welded.tris, capped: false };
|
|
49803
|
-
} else {
|
|
49804
|
-
const targetEdge = targetEdgeSpacingFactor * sampleSpacing;
|
|
49805
|
-
subdivided = adaptiveSubdivide(welded, targetEdge, vertexCap);
|
|
49806
|
-
}
|
|
49807
|
-
const normals = vertexNormals(subdivided);
|
|
49808
|
-
const effectiveSpacing = sampleSpacing > 0 ? sampleSpacing : 1;
|
|
49809
|
-
const scatter = scatterToVertices(subdivided.positions, normals, samples, effectiveSpacing, k2, gateDot);
|
|
49810
|
-
let valueMin = Infinity;
|
|
49811
|
-
let valueMax = -Infinity;
|
|
49812
|
-
for (let i = 0; i < scatter.values.length; i += 1) {
|
|
49813
|
-
const v = scatter.values[i];
|
|
49814
|
-
if (!Number.isFinite(v)) continue;
|
|
49815
|
-
if (v < valueMin) valueMin = v;
|
|
49816
|
-
if (v > valueMax) valueMax = v;
|
|
49817
|
-
}
|
|
49818
|
-
if (!Number.isFinite(valueMin) || !Number.isFinite(valueMax)) {
|
|
49819
|
-
valueMin = 0;
|
|
49820
|
-
valueMax = 0;
|
|
49821
|
-
}
|
|
49822
|
-
backfillHoles(scatter.values, subdivided);
|
|
49823
|
-
const vertexCount = subdivided.positions.length / 3;
|
|
49824
|
-
return {
|
|
49825
|
-
positions: Float32Array.from(subdivided.positions),
|
|
49826
|
-
normals,
|
|
49827
|
-
index: Uint32Array.from(subdivided.tris),
|
|
49828
|
-
values: scatter.values,
|
|
49829
|
-
valueMin,
|
|
49830
|
-
valueMax,
|
|
49831
|
-
capped: subdivided.capped,
|
|
49832
|
-
degenerate: welded.degenerate,
|
|
49833
|
-
holeCount: scatter.holeCount,
|
|
49834
|
-
vertexCount
|
|
49835
|
-
};
|
|
49836
|
-
}
|
|
49837
|
-
const CENTER = 0;
|
|
49838
|
-
const AVERAGE = 1;
|
|
49839
|
-
const SAH = 2;
|
|
49840
|
-
const CONTAINED = 2;
|
|
49841
|
-
const TRIANGLE_INTERSECT_COST = 1.25;
|
|
49842
|
-
const TRAVERSAL_COST = 1;
|
|
49843
|
-
const BYTES_PER_NODE = 6 * 4 + 4 + 4;
|
|
49844
|
-
const IS_LEAFNODE_FLAG = 65535;
|
|
49845
|
-
const FLOAT32_EPSILON = Math.pow(2, -24);
|
|
49846
|
-
const SKIP_GENERATION = Symbol("SKIP_GENERATION");
|
|
49847
|
-
function getVertexCount(geo) {
|
|
49848
|
-
return geo.index ? geo.index.count : geo.attributes.position.count;
|
|
49849
|
-
}
|
|
49850
|
-
function getTriCount(geo) {
|
|
49851
|
-
return getVertexCount(geo) / 3;
|
|
49852
|
-
}
|
|
49853
|
-
function getIndexArray(vertexCount, BufferConstructor = ArrayBuffer) {
|
|
49854
|
-
if (vertexCount > 65535) {
|
|
49855
|
-
return new Uint32Array(new BufferConstructor(4 * vertexCount));
|
|
49856
|
-
} else {
|
|
49857
|
-
return new Uint16Array(new BufferConstructor(2 * vertexCount));
|
|
49858
|
-
}
|
|
49859
|
-
}
|
|
49860
|
-
function ensureIndex(geo, options) {
|
|
49861
|
-
if (!geo.index) {
|
|
49862
|
-
const vertexCount = geo.attributes.position.count;
|
|
49863
|
-
const BufferConstructor = options.useSharedArrayBuffer ? SharedArrayBuffer : ArrayBuffer;
|
|
49864
|
-
const index2 = getIndexArray(vertexCount, BufferConstructor);
|
|
49865
|
-
geo.setIndex(new BufferAttribute(index2, 1));
|
|
49866
|
-
for (let i = 0; i < vertexCount; i++) {
|
|
49867
|
-
index2[i] = i;
|
|
49868
|
-
}
|
|
49869
|
-
}
|
|
49870
|
-
}
|
|
49871
|
-
function getFullGeometryRange(geo, range) {
|
|
49872
|
-
const triCount = getTriCount(geo);
|
|
49873
|
-
const drawRange = range ? range : geo.drawRange;
|
|
49874
|
-
const start = drawRange.start / 3;
|
|
49875
|
-
const end = (drawRange.start + drawRange.count) / 3;
|
|
49876
|
-
const offset = Math.max(0, start);
|
|
49877
|
-
const count = Math.min(triCount, end) - offset;
|
|
49878
|
-
return [{
|
|
49879
|
-
offset: Math.floor(offset),
|
|
49880
|
-
count: Math.floor(count)
|
|
49881
|
-
}];
|
|
49882
|
-
}
|
|
49883
|
-
function getRootIndexRanges(geo, range) {
|
|
49884
|
-
if (!geo.groups || !geo.groups.length) {
|
|
49885
|
-
return getFullGeometryRange(geo, range);
|
|
49886
|
-
}
|
|
49887
|
-
const ranges = [];
|
|
49888
|
-
const rangeBoundaries = /* @__PURE__ */ new Set();
|
|
49889
|
-
const drawRange = range ? range : geo.drawRange;
|
|
49890
|
-
const drawRangeStart = drawRange.start / 3;
|
|
49891
|
-
const drawRangeEnd = (drawRange.start + drawRange.count) / 3;
|
|
49892
|
-
for (const group of geo.groups) {
|
|
49893
|
-
const groupStart = group.start / 3;
|
|
49894
|
-
const groupEnd = (group.start + group.count) / 3;
|
|
49895
|
-
rangeBoundaries.add(Math.max(drawRangeStart, groupStart));
|
|
49896
|
-
rangeBoundaries.add(Math.min(drawRangeEnd, groupEnd));
|
|
49897
|
-
}
|
|
49898
|
-
const sortedBoundaries = Array.from(rangeBoundaries.values()).sort((a2, b) => a2 - b);
|
|
49899
|
-
for (let i = 0; i < sortedBoundaries.length - 1; i++) {
|
|
49900
|
-
const start = sortedBoundaries[i];
|
|
49901
|
-
const end = sortedBoundaries[i + 1];
|
|
49902
|
-
ranges.push({
|
|
49903
|
-
offset: Math.floor(start),
|
|
49904
|
-
count: Math.floor(end - start)
|
|
49905
|
-
});
|
|
49906
|
-
}
|
|
49907
|
-
return ranges;
|
|
49908
|
-
}
|
|
49909
|
-
function hasGroupGaps(geometry, range) {
|
|
49910
|
-
const vertexCount = getTriCount(geometry);
|
|
49911
|
-
const groups = getRootIndexRanges(geometry, range).sort((a2, b) => a2.offset - b.offset);
|
|
49912
|
-
const finalGroup = groups[groups.length - 1];
|
|
49913
|
-
finalGroup.count = Math.min(vertexCount - finalGroup.offset, finalGroup.count);
|
|
49914
|
-
let total = 0;
|
|
49915
|
-
groups.forEach(({ count }) => total += count);
|
|
49916
|
-
return vertexCount !== total;
|
|
49917
|
-
}
|
|
49918
|
-
function getBounds(triangleBounds2, offset, count, target, centroidTarget) {
|
|
49919
|
-
let minx = Infinity;
|
|
49920
|
-
let miny = Infinity;
|
|
49921
|
-
let minz = Infinity;
|
|
49922
|
-
let maxx = -Infinity;
|
|
49923
|
-
let maxy = -Infinity;
|
|
49924
|
-
let maxz = -Infinity;
|
|
49925
|
-
let cminx = Infinity;
|
|
49926
|
-
let cminy = Infinity;
|
|
49927
|
-
let cminz = Infinity;
|
|
49928
|
-
let cmaxx = -Infinity;
|
|
49929
|
-
let cmaxy = -Infinity;
|
|
49930
|
-
let cmaxz = -Infinity;
|
|
49931
|
-
for (let i = offset * 6, end = (offset + count) * 6; i < end; i += 6) {
|
|
49932
|
-
const cx = triangleBounds2[i + 0];
|
|
49933
|
-
const hx = triangleBounds2[i + 1];
|
|
49934
|
-
const lx = cx - hx;
|
|
49935
|
-
const rx = cx + hx;
|
|
49936
|
-
if (lx < minx) minx = lx;
|
|
49937
|
-
if (rx > maxx) maxx = rx;
|
|
49938
|
-
if (cx < cminx) cminx = cx;
|
|
49939
|
-
if (cx > cmaxx) cmaxx = cx;
|
|
49940
|
-
const cy = triangleBounds2[i + 2];
|
|
49941
|
-
const hy = triangleBounds2[i + 3];
|
|
49942
|
-
const ly = cy - hy;
|
|
49943
|
-
const ry = cy + hy;
|
|
49944
|
-
if (ly < miny) miny = ly;
|
|
49945
|
-
if (ry > maxy) maxy = ry;
|
|
49946
|
-
if (cy < cminy) cminy = cy;
|
|
49947
|
-
if (cy > cmaxy) cmaxy = cy;
|
|
49948
|
-
const cz = triangleBounds2[i + 4];
|
|
49949
|
-
const hz = triangleBounds2[i + 5];
|
|
49950
|
-
const lz = cz - hz;
|
|
49951
|
-
const rz = cz + hz;
|
|
49952
|
-
if (lz < minz) minz = lz;
|
|
49953
|
-
if (rz > maxz) maxz = rz;
|
|
49954
|
-
if (cz < cminz) cminz = cz;
|
|
49955
|
-
if (cz > cmaxz) cmaxz = cz;
|
|
49956
|
-
}
|
|
49957
|
-
target[0] = minx;
|
|
49958
|
-
target[1] = miny;
|
|
49959
|
-
target[2] = minz;
|
|
49960
|
-
target[3] = maxx;
|
|
49961
|
-
target[4] = maxy;
|
|
49962
|
-
target[5] = maxz;
|
|
49963
|
-
centroidTarget[0] = cminx;
|
|
49964
|
-
centroidTarget[1] = cminy;
|
|
49965
|
-
centroidTarget[2] = cminz;
|
|
49966
|
-
centroidTarget[3] = cmaxx;
|
|
49967
|
-
centroidTarget[4] = cmaxy;
|
|
49968
|
-
centroidTarget[5] = cmaxz;
|
|
49969
|
-
}
|
|
49970
|
-
function computeTriangleBounds(geo, target = null, offset = null, count = null) {
|
|
49971
|
-
const posAttr = geo.attributes.position;
|
|
49972
|
-
const index2 = geo.index ? geo.index.array : null;
|
|
49973
|
-
const triCount = getTriCount(geo);
|
|
49974
|
-
const normalized = posAttr.normalized;
|
|
49975
|
-
let triangleBounds2;
|
|
49976
|
-
if (target === null) {
|
|
49977
|
-
triangleBounds2 = new Float32Array(triCount * 6);
|
|
49978
|
-
offset = 0;
|
|
49979
|
-
count = triCount;
|
|
49980
|
-
} else {
|
|
49981
|
-
triangleBounds2 = target;
|
|
49982
|
-
offset = offset || 0;
|
|
49983
|
-
count = count || triCount;
|
|
49984
|
-
}
|
|
49985
|
-
const posArr = posAttr.array;
|
|
49986
|
-
const bufferOffset = posAttr.offset || 0;
|
|
49987
|
-
let stride = 3;
|
|
49988
|
-
if (posAttr.isInterleavedBufferAttribute) {
|
|
49989
|
-
stride = posAttr.data.stride;
|
|
49990
|
-
}
|
|
49991
|
-
const getters = ["getX", "getY", "getZ"];
|
|
49992
|
-
for (let tri = offset; tri < offset + count; tri++) {
|
|
49993
|
-
const tri3 = tri * 3;
|
|
49994
|
-
const tri6 = tri * 6;
|
|
49995
|
-
let ai = tri3 + 0;
|
|
49996
|
-
let bi = tri3 + 1;
|
|
49997
|
-
let ci = tri3 + 2;
|
|
49998
|
-
if (index2) {
|
|
49999
|
-
ai = index2[ai];
|
|
50000
|
-
bi = index2[bi];
|
|
50001
|
-
ci = index2[ci];
|
|
50002
|
-
}
|
|
50003
|
-
if (!normalized) {
|
|
50004
|
-
ai = ai * stride + bufferOffset;
|
|
50005
|
-
bi = bi * stride + bufferOffset;
|
|
50006
|
-
ci = ci * stride + bufferOffset;
|
|
50007
|
-
}
|
|
50008
|
-
for (let el = 0; el < 3; el++) {
|
|
50009
|
-
let a2, b, c2;
|
|
50010
|
-
if (normalized) {
|
|
50011
|
-
a2 = posAttr[getters[el]](ai);
|
|
50012
|
-
b = posAttr[getters[el]](bi);
|
|
50013
|
-
c2 = posAttr[getters[el]](ci);
|
|
50014
|
-
} else {
|
|
50015
|
-
a2 = posArr[ai + el];
|
|
50016
|
-
b = posArr[bi + el];
|
|
50017
|
-
c2 = posArr[ci + el];
|
|
50018
|
-
}
|
|
50019
|
-
let min2 = a2;
|
|
50020
|
-
if (b < min2) min2 = b;
|
|
50021
|
-
if (c2 < min2) min2 = c2;
|
|
50022
|
-
let max2 = a2;
|
|
50023
|
-
if (b > max2) max2 = b;
|
|
50024
|
-
if (c2 > max2) max2 = c2;
|
|
50025
|
-
const halfExtents = (max2 - min2) / 2;
|
|
50026
|
-
const el2 = el * 2;
|
|
50027
|
-
triangleBounds2[tri6 + el2 + 0] = min2 + halfExtents;
|
|
50028
|
-
triangleBounds2[tri6 + el2 + 1] = halfExtents + (Math.abs(min2) + halfExtents) * FLOAT32_EPSILON;
|
|
50029
|
-
}
|
|
50030
|
-
}
|
|
50031
|
-
return triangleBounds2;
|
|
50898
|
+
return triangleBounds2;
|
|
50032
50899
|
}
|
|
50033
50900
|
function arrayToBox(nodeIndex32, array, target) {
|
|
50034
50901
|
target.min.x = array[nodeIndex32];
|
|
@@ -50154,10 +51021,10 @@ function getOptimalSplit(nodeBoundingData, centroidBoundingData, triangleBounds2
|
|
|
50154
51021
|
}
|
|
50155
51022
|
}
|
|
50156
51023
|
for (let c2 = cStart; c2 < cEnd; c2 += 6) {
|
|
50157
|
-
const
|
|
51024
|
+
const center2 = triangleBounds2[c2 + 2 * a2];
|
|
50158
51025
|
for (let bi = 0; bi < splitCount; bi++) {
|
|
50159
51026
|
const bin = truncatedBins[bi];
|
|
50160
|
-
if (
|
|
51027
|
+
if (center2 >= bin.candidate) {
|
|
50161
51028
|
expandByTriangleBounds(c2, triangleBounds2, bin.rightCacheBounds);
|
|
50162
51029
|
} else {
|
|
50163
51030
|
expandByTriangleBounds(c2, triangleBounds2, bin.leftCacheBounds);
|
|
@@ -50652,24 +51519,24 @@ const sphereIntersectTriangle = (function() {
|
|
|
50652
51519
|
const planeTemp = new Plane();
|
|
50653
51520
|
const lineTemp = new Line3();
|
|
50654
51521
|
return function sphereIntersectTriangle2(sphere, triangle3) {
|
|
50655
|
-
const { radius, center } = sphere;
|
|
51522
|
+
const { radius, center: center2 } = sphere;
|
|
50656
51523
|
const { a: a2, b, c: c2 } = triangle3;
|
|
50657
51524
|
lineTemp.start = a2;
|
|
50658
51525
|
lineTemp.end = b;
|
|
50659
|
-
const closestPoint1 = lineTemp.closestPointToPoint(
|
|
50660
|
-
if (closestPoint1.distanceTo(
|
|
51526
|
+
const closestPoint1 = lineTemp.closestPointToPoint(center2, true, closestPointTemp);
|
|
51527
|
+
if (closestPoint1.distanceTo(center2) <= radius) return true;
|
|
50661
51528
|
lineTemp.start = a2;
|
|
50662
51529
|
lineTemp.end = c2;
|
|
50663
|
-
const closestPoint2 = lineTemp.closestPointToPoint(
|
|
50664
|
-
if (closestPoint2.distanceTo(
|
|
51530
|
+
const closestPoint2 = lineTemp.closestPointToPoint(center2, true, closestPointTemp);
|
|
51531
|
+
if (closestPoint2.distanceTo(center2) <= radius) return true;
|
|
50665
51532
|
lineTemp.start = b;
|
|
50666
51533
|
lineTemp.end = c2;
|
|
50667
|
-
const closestPoint3 = lineTemp.closestPointToPoint(
|
|
50668
|
-
if (closestPoint3.distanceTo(
|
|
51534
|
+
const closestPoint3 = lineTemp.closestPointToPoint(center2, true, closestPointTemp);
|
|
51535
|
+
if (closestPoint3.distanceTo(center2) <= radius) return true;
|
|
50669
51536
|
const plane = triangle3.getPlane(planeTemp);
|
|
50670
|
-
const dp = Math.abs(plane.distanceToPoint(
|
|
51537
|
+
const dp = Math.abs(plane.distanceToPoint(center2));
|
|
50671
51538
|
if (dp <= radius) {
|
|
50672
|
-
const pp = plane.projectPoint(
|
|
51539
|
+
const pp = plane.projectPoint(center2, projectedPointTemp);
|
|
50673
51540
|
const cp = triangle3.containsPoint(pp);
|
|
50674
51541
|
if (cp) return true;
|
|
50675
51542
|
}
|
|
@@ -51467,26 +52334,26 @@ const _normalA = /* @__PURE__ */ new Vector3();
|
|
|
51467
52334
|
const _normalB = /* @__PURE__ */ new Vector3();
|
|
51468
52335
|
const _normalC = /* @__PURE__ */ new Vector3();
|
|
51469
52336
|
const _intersectionPoint = /* @__PURE__ */ new Vector3();
|
|
51470
|
-
function checkIntersection(
|
|
52337
|
+
function checkIntersection(ray2, pA, pB, pC, point2, side, near, far) {
|
|
51471
52338
|
let intersect2;
|
|
51472
52339
|
if (side === BackSide) {
|
|
51473
|
-
intersect2 =
|
|
52340
|
+
intersect2 = ray2.intersectTriangle(pC, pB, pA, true, point2);
|
|
51474
52341
|
} else {
|
|
51475
|
-
intersect2 =
|
|
52342
|
+
intersect2 = ray2.intersectTriangle(pA, pB, pC, side !== DoubleSide, point2);
|
|
51476
52343
|
}
|
|
51477
52344
|
if (intersect2 === null) return null;
|
|
51478
|
-
const distance =
|
|
52345
|
+
const distance = ray2.origin.distanceTo(point2);
|
|
51479
52346
|
if (distance < near || distance > far) return null;
|
|
51480
52347
|
return {
|
|
51481
52348
|
distance,
|
|
51482
52349
|
point: point2.clone()
|
|
51483
52350
|
};
|
|
51484
52351
|
}
|
|
51485
|
-
function checkBufferGeometryIntersection(
|
|
52352
|
+
function checkBufferGeometryIntersection(ray2, position, normal, uv, uv1, a2, b, c2, side, near, far) {
|
|
51486
52353
|
_vA.fromBufferAttribute(position, a2);
|
|
51487
52354
|
_vB.fromBufferAttribute(position, b);
|
|
51488
52355
|
_vC.fromBufferAttribute(position, c2);
|
|
51489
|
-
const intersection2 = checkIntersection(
|
|
52356
|
+
const intersection2 = checkIntersection(ray2, _vA, _vB, _vC, _intersectionPoint, side, near, far);
|
|
51490
52357
|
if (intersection2) {
|
|
51491
52358
|
const barycoord = new Vector3();
|
|
51492
52359
|
Triangle.getBarycoord(_intersectionPoint, _vA, _vB, _vC, barycoord);
|
|
@@ -51507,7 +52374,7 @@ function checkBufferGeometryIntersection(ray, position, normal, uv, uv1, a2, b,
|
|
|
51507
52374
|
_normalB.fromBufferAttribute(normal, b);
|
|
51508
52375
|
_normalC.fromBufferAttribute(normal, c2);
|
|
51509
52376
|
intersection2.normal = Triangle.getInterpolation(_intersectionPoint, _vA, _vB, _vC, _normalA, _normalB, _normalC, new Vector3());
|
|
51510
|
-
if (intersection2.normal.dot(
|
|
52377
|
+
if (intersection2.normal.dot(ray2.direction) > 0) {
|
|
51511
52378
|
intersection2.normal.multiplyScalar(-1);
|
|
51512
52379
|
}
|
|
51513
52380
|
}
|
|
@@ -51527,7 +52394,7 @@ function checkBufferGeometryIntersection(ray, position, normal, uv, uv1, a2, b,
|
|
|
51527
52394
|
}
|
|
51528
52395
|
return intersection2;
|
|
51529
52396
|
}
|
|
51530
|
-
function intersectTri(geo, side,
|
|
52397
|
+
function intersectTri(geo, side, ray2, tri, intersections, near, far) {
|
|
51531
52398
|
const triOffset = tri * 3;
|
|
51532
52399
|
let a2 = triOffset + 0;
|
|
51533
52400
|
let b = triOffset + 1;
|
|
@@ -51539,7 +52406,7 @@ function intersectTri(geo, side, ray, tri, intersections, near, far) {
|
|
|
51539
52406
|
c2 = index2.getX(c2);
|
|
51540
52407
|
}
|
|
51541
52408
|
const { position, normal, uv, uv1 } = geo.attributes;
|
|
51542
|
-
const intersection2 = checkBufferGeometryIntersection(
|
|
52409
|
+
const intersection2 = checkBufferGeometryIntersection(ray2, position, normal, uv, uv1, a2, b, c2, side, near, far);
|
|
51543
52410
|
if (intersection2) {
|
|
51544
52411
|
intersection2.faceIndex = tri;
|
|
51545
52412
|
if (intersections) intersections.push(intersection2);
|
|
@@ -51569,19 +52436,19 @@ function setTriangle(tri, i, index2, pos) {
|
|
|
51569
52436
|
tc.y = pos.getY(i2);
|
|
51570
52437
|
tc.z = pos.getZ(i2);
|
|
51571
52438
|
}
|
|
51572
|
-
function intersectTris(bvh, side,
|
|
52439
|
+
function intersectTris(bvh, side, ray2, offset, count, intersections, near, far) {
|
|
51573
52440
|
const { geometry, _indirectBuffer } = bvh;
|
|
51574
52441
|
for (let i = offset, end = offset + count; i < end; i++) {
|
|
51575
|
-
intersectTri(geometry, side,
|
|
52442
|
+
intersectTri(geometry, side, ray2, i, intersections, near, far);
|
|
51576
52443
|
}
|
|
51577
52444
|
}
|
|
51578
|
-
function intersectClosestTri(bvh, side,
|
|
52445
|
+
function intersectClosestTri(bvh, side, ray2, offset, count, near, far) {
|
|
51579
52446
|
const { geometry, _indirectBuffer } = bvh;
|
|
51580
52447
|
let dist = Infinity;
|
|
51581
52448
|
let res = null;
|
|
51582
52449
|
for (let i = offset, end = offset + count; i < end; i++) {
|
|
51583
52450
|
let intersection2;
|
|
51584
|
-
intersection2 = intersectTri(geometry, side,
|
|
52451
|
+
intersection2 = intersectTri(geometry, side, ray2, i, null, near, far);
|
|
51585
52452
|
if (intersection2 && intersection2.distance < dist) {
|
|
51586
52453
|
res = intersection2;
|
|
51587
52454
|
dist = intersection2.distance;
|
|
@@ -51702,12 +52569,12 @@ function refit(bvh, nodeIndices = null) {
|
|
|
51702
52569
|
}
|
|
51703
52570
|
}
|
|
51704
52571
|
}
|
|
51705
|
-
function intersectRay(nodeIndex32, array,
|
|
52572
|
+
function intersectRay(nodeIndex32, array, ray2, near, far) {
|
|
51706
52573
|
let tmin, tmax, tymin, tymax, tzmin, tzmax;
|
|
51707
|
-
const invdirx = 1 /
|
|
51708
|
-
const ox =
|
|
51709
|
-
const oy =
|
|
51710
|
-
const oz =
|
|
52574
|
+
const invdirx = 1 / ray2.direction.x, invdiry = 1 / ray2.direction.y, invdirz = 1 / ray2.direction.z;
|
|
52575
|
+
const ox = ray2.origin.x;
|
|
52576
|
+
const oy = ray2.origin.y;
|
|
52577
|
+
const oz = ray2.origin.z;
|
|
51711
52578
|
let minx = array[nodeIndex32];
|
|
51712
52579
|
let maxx = array[nodeIndex32 + 3];
|
|
51713
52580
|
let miny = array[nodeIndex32 + 1];
|
|
@@ -51743,20 +52610,20 @@ function intersectRay(nodeIndex32, array, ray, near, far) {
|
|
|
51743
52610
|
if (tzmax < tmax || tmax !== tmax) tmax = tzmax;
|
|
51744
52611
|
return tmin <= far && tmax >= near;
|
|
51745
52612
|
}
|
|
51746
|
-
function intersectTris_indirect(bvh, side,
|
|
52613
|
+
function intersectTris_indirect(bvh, side, ray2, offset, count, intersections, near, far) {
|
|
51747
52614
|
const { geometry, _indirectBuffer } = bvh;
|
|
51748
52615
|
for (let i = offset, end = offset + count; i < end; i++) {
|
|
51749
52616
|
let vi = _indirectBuffer ? _indirectBuffer[i] : i;
|
|
51750
|
-
intersectTri(geometry, side,
|
|
52617
|
+
intersectTri(geometry, side, ray2, vi, intersections, near, far);
|
|
51751
52618
|
}
|
|
51752
52619
|
}
|
|
51753
|
-
function intersectClosestTri_indirect(bvh, side,
|
|
52620
|
+
function intersectClosestTri_indirect(bvh, side, ray2, offset, count, near, far) {
|
|
51754
52621
|
const { geometry, _indirectBuffer } = bvh;
|
|
51755
52622
|
let dist = Infinity;
|
|
51756
52623
|
let res = null;
|
|
51757
52624
|
for (let i = offset, end = offset + count; i < end; i++) {
|
|
51758
52625
|
let intersection2;
|
|
51759
|
-
intersection2 = intersectTri(geometry, side,
|
|
52626
|
+
intersection2 = intersectTri(geometry, side, ray2, _indirectBuffer ? _indirectBuffer[i] : i, null, near, far);
|
|
51760
52627
|
if (intersection2 && intersection2.distance < dist) {
|
|
51761
52628
|
res = intersection2;
|
|
51762
52629
|
dist = intersection2.distance;
|
|
@@ -51779,49 +52646,49 @@ function iterateOverTriangles_indirect(offset, count, bvh, intersectsTriangleFun
|
|
|
51779
52646
|
}
|
|
51780
52647
|
return false;
|
|
51781
52648
|
}
|
|
51782
|
-
function raycast(bvh, root, side,
|
|
52649
|
+
function raycast(bvh, root, side, ray2, intersects, near, far) {
|
|
51783
52650
|
BufferStack.setBuffer(bvh._roots[root]);
|
|
51784
|
-
_raycast$1(0, bvh, side,
|
|
52651
|
+
_raycast$1(0, bvh, side, ray2, intersects, near, far);
|
|
51785
52652
|
BufferStack.clearBuffer();
|
|
51786
52653
|
}
|
|
51787
|
-
function _raycast$1(nodeIndex32, bvh, side,
|
|
52654
|
+
function _raycast$1(nodeIndex32, bvh, side, ray2, intersects, near, far) {
|
|
51788
52655
|
const { float32Array: float32Array2, uint16Array: uint16Array2, uint32Array: uint32Array2 } = BufferStack;
|
|
51789
52656
|
const nodeIndex16 = nodeIndex32 * 2;
|
|
51790
52657
|
const isLeaf = IS_LEAF(nodeIndex16, uint16Array2);
|
|
51791
52658
|
if (isLeaf) {
|
|
51792
52659
|
const offset = OFFSET(nodeIndex32, uint32Array2);
|
|
51793
52660
|
const count = COUNT(nodeIndex16, uint16Array2);
|
|
51794
|
-
intersectTris(bvh, side,
|
|
52661
|
+
intersectTris(bvh, side, ray2, offset, count, intersects, near, far);
|
|
51795
52662
|
} else {
|
|
51796
52663
|
const leftIndex = LEFT_NODE(nodeIndex32);
|
|
51797
|
-
if (intersectRay(leftIndex, float32Array2,
|
|
51798
|
-
_raycast$1(leftIndex, bvh, side,
|
|
52664
|
+
if (intersectRay(leftIndex, float32Array2, ray2, near, far)) {
|
|
52665
|
+
_raycast$1(leftIndex, bvh, side, ray2, intersects, near, far);
|
|
51799
52666
|
}
|
|
51800
52667
|
const rightIndex = RIGHT_NODE(nodeIndex32, uint32Array2);
|
|
51801
|
-
if (intersectRay(rightIndex, float32Array2,
|
|
51802
|
-
_raycast$1(rightIndex, bvh, side,
|
|
52668
|
+
if (intersectRay(rightIndex, float32Array2, ray2, near, far)) {
|
|
52669
|
+
_raycast$1(rightIndex, bvh, side, ray2, intersects, near, far);
|
|
51803
52670
|
}
|
|
51804
52671
|
}
|
|
51805
52672
|
}
|
|
51806
52673
|
const _xyzFields$1 = ["x", "y", "z"];
|
|
51807
|
-
function raycastFirst(bvh, root, side,
|
|
52674
|
+
function raycastFirst(bvh, root, side, ray2, near, far) {
|
|
51808
52675
|
BufferStack.setBuffer(bvh._roots[root]);
|
|
51809
|
-
const result = _raycastFirst$1(0, bvh, side,
|
|
52676
|
+
const result = _raycastFirst$1(0, bvh, side, ray2, near, far);
|
|
51810
52677
|
BufferStack.clearBuffer();
|
|
51811
52678
|
return result;
|
|
51812
52679
|
}
|
|
51813
|
-
function _raycastFirst$1(nodeIndex32, bvh, side,
|
|
52680
|
+
function _raycastFirst$1(nodeIndex32, bvh, side, ray2, near, far) {
|
|
51814
52681
|
const { float32Array: float32Array2, uint16Array: uint16Array2, uint32Array: uint32Array2 } = BufferStack;
|
|
51815
52682
|
let nodeIndex16 = nodeIndex32 * 2;
|
|
51816
52683
|
const isLeaf = IS_LEAF(nodeIndex16, uint16Array2);
|
|
51817
52684
|
if (isLeaf) {
|
|
51818
52685
|
const offset = OFFSET(nodeIndex32, uint32Array2);
|
|
51819
52686
|
const count = COUNT(nodeIndex16, uint16Array2);
|
|
51820
|
-
return intersectClosestTri(bvh, side,
|
|
52687
|
+
return intersectClosestTri(bvh, side, ray2, offset, count, near, far);
|
|
51821
52688
|
} else {
|
|
51822
52689
|
const splitAxis = SPLIT_AXIS(nodeIndex32, uint32Array2);
|
|
51823
52690
|
const xyzAxis = _xyzFields$1[splitAxis];
|
|
51824
|
-
const rayDir =
|
|
52691
|
+
const rayDir = ray2.direction[xyzAxis];
|
|
51825
52692
|
const leftToRight = rayDir >= 0;
|
|
51826
52693
|
let c1, c2;
|
|
51827
52694
|
if (leftToRight) {
|
|
@@ -51831,8 +52698,8 @@ function _raycastFirst$1(nodeIndex32, bvh, side, ray, near, far) {
|
|
|
51831
52698
|
c1 = RIGHT_NODE(nodeIndex32, uint32Array2);
|
|
51832
52699
|
c2 = LEFT_NODE(nodeIndex32);
|
|
51833
52700
|
}
|
|
51834
|
-
const c1Intersection = intersectRay(c1, float32Array2,
|
|
51835
|
-
const c1Result = c1Intersection ? _raycastFirst$1(c1, bvh, side,
|
|
52701
|
+
const c1Intersection = intersectRay(c1, float32Array2, ray2, near, far);
|
|
52702
|
+
const c1Result = c1Intersection ? _raycastFirst$1(c1, bvh, side, ray2, near, far) : null;
|
|
51836
52703
|
if (c1Result) {
|
|
51837
52704
|
const point2 = c1Result.point[xyzAxis];
|
|
51838
52705
|
const isOutside = leftToRight ? point2 <= float32Array2[c2 + splitAxis] : (
|
|
@@ -51843,8 +52710,8 @@ function _raycastFirst$1(nodeIndex32, bvh, side, ray, near, far) {
|
|
|
51843
52710
|
return c1Result;
|
|
51844
52711
|
}
|
|
51845
52712
|
}
|
|
51846
|
-
const c2Intersection = intersectRay(c2, float32Array2,
|
|
51847
|
-
const c2Result = c2Intersection ? _raycastFirst$1(c2, bvh, side,
|
|
52713
|
+
const c2Intersection = intersectRay(c2, float32Array2, ray2, near, far);
|
|
52714
|
+
const c2Result = c2Intersection ? _raycastFirst$1(c2, bvh, side, ray2, near, far) : null;
|
|
51848
52715
|
if (c1Result && c2Result) {
|
|
51849
52716
|
return c1Result.distance <= c2Result.distance ? c1Result : c2Result;
|
|
51850
52717
|
} else {
|
|
@@ -52173,49 +53040,49 @@ function refit_indirect(bvh, nodeIndices = null) {
|
|
|
52173
53040
|
}
|
|
52174
53041
|
}
|
|
52175
53042
|
}
|
|
52176
|
-
function raycast_indirect(bvh, root, side,
|
|
53043
|
+
function raycast_indirect(bvh, root, side, ray2, intersects, near, far) {
|
|
52177
53044
|
BufferStack.setBuffer(bvh._roots[root]);
|
|
52178
|
-
_raycast(0, bvh, side,
|
|
53045
|
+
_raycast(0, bvh, side, ray2, intersects, near, far);
|
|
52179
53046
|
BufferStack.clearBuffer();
|
|
52180
53047
|
}
|
|
52181
|
-
function _raycast(nodeIndex32, bvh, side,
|
|
53048
|
+
function _raycast(nodeIndex32, bvh, side, ray2, intersects, near, far) {
|
|
52182
53049
|
const { float32Array: float32Array2, uint16Array: uint16Array2, uint32Array: uint32Array2 } = BufferStack;
|
|
52183
53050
|
const nodeIndex16 = nodeIndex32 * 2;
|
|
52184
53051
|
const isLeaf = IS_LEAF(nodeIndex16, uint16Array2);
|
|
52185
53052
|
if (isLeaf) {
|
|
52186
53053
|
const offset = OFFSET(nodeIndex32, uint32Array2);
|
|
52187
53054
|
const count = COUNT(nodeIndex16, uint16Array2);
|
|
52188
|
-
intersectTris_indirect(bvh, side,
|
|
53055
|
+
intersectTris_indirect(bvh, side, ray2, offset, count, intersects, near, far);
|
|
52189
53056
|
} else {
|
|
52190
53057
|
const leftIndex = LEFT_NODE(nodeIndex32);
|
|
52191
|
-
if (intersectRay(leftIndex, float32Array2,
|
|
52192
|
-
_raycast(leftIndex, bvh, side,
|
|
53058
|
+
if (intersectRay(leftIndex, float32Array2, ray2, near, far)) {
|
|
53059
|
+
_raycast(leftIndex, bvh, side, ray2, intersects, near, far);
|
|
52193
53060
|
}
|
|
52194
53061
|
const rightIndex = RIGHT_NODE(nodeIndex32, uint32Array2);
|
|
52195
|
-
if (intersectRay(rightIndex, float32Array2,
|
|
52196
|
-
_raycast(rightIndex, bvh, side,
|
|
53062
|
+
if (intersectRay(rightIndex, float32Array2, ray2, near, far)) {
|
|
53063
|
+
_raycast(rightIndex, bvh, side, ray2, intersects, near, far);
|
|
52197
53064
|
}
|
|
52198
53065
|
}
|
|
52199
53066
|
}
|
|
52200
53067
|
const _xyzFields = ["x", "y", "z"];
|
|
52201
|
-
function raycastFirst_indirect(bvh, root, side,
|
|
53068
|
+
function raycastFirst_indirect(bvh, root, side, ray2, near, far) {
|
|
52202
53069
|
BufferStack.setBuffer(bvh._roots[root]);
|
|
52203
|
-
const result = _raycastFirst(0, bvh, side,
|
|
53070
|
+
const result = _raycastFirst(0, bvh, side, ray2, near, far);
|
|
52204
53071
|
BufferStack.clearBuffer();
|
|
52205
53072
|
return result;
|
|
52206
53073
|
}
|
|
52207
|
-
function _raycastFirst(nodeIndex32, bvh, side,
|
|
53074
|
+
function _raycastFirst(nodeIndex32, bvh, side, ray2, near, far) {
|
|
52208
53075
|
const { float32Array: float32Array2, uint16Array: uint16Array2, uint32Array: uint32Array2 } = BufferStack;
|
|
52209
53076
|
let nodeIndex16 = nodeIndex32 * 2;
|
|
52210
53077
|
const isLeaf = IS_LEAF(nodeIndex16, uint16Array2);
|
|
52211
53078
|
if (isLeaf) {
|
|
52212
53079
|
const offset = OFFSET(nodeIndex32, uint32Array2);
|
|
52213
53080
|
const count = COUNT(nodeIndex16, uint16Array2);
|
|
52214
|
-
return intersectClosestTri_indirect(bvh, side,
|
|
53081
|
+
return intersectClosestTri_indirect(bvh, side, ray2, offset, count, near, far);
|
|
52215
53082
|
} else {
|
|
52216
53083
|
const splitAxis = SPLIT_AXIS(nodeIndex32, uint32Array2);
|
|
52217
53084
|
const xyzAxis = _xyzFields[splitAxis];
|
|
52218
|
-
const rayDir =
|
|
53085
|
+
const rayDir = ray2.direction[xyzAxis];
|
|
52219
53086
|
const leftToRight = rayDir >= 0;
|
|
52220
53087
|
let c1, c2;
|
|
52221
53088
|
if (leftToRight) {
|
|
@@ -52225,8 +53092,8 @@ function _raycastFirst(nodeIndex32, bvh, side, ray, near, far) {
|
|
|
52225
53092
|
c1 = RIGHT_NODE(nodeIndex32, uint32Array2);
|
|
52226
53093
|
c2 = LEFT_NODE(nodeIndex32);
|
|
52227
53094
|
}
|
|
52228
|
-
const c1Intersection = intersectRay(c1, float32Array2,
|
|
52229
|
-
const c1Result = c1Intersection ? _raycastFirst(c1, bvh, side,
|
|
53095
|
+
const c1Intersection = intersectRay(c1, float32Array2, ray2, near, far);
|
|
53096
|
+
const c1Result = c1Intersection ? _raycastFirst(c1, bvh, side, ray2, near, far) : null;
|
|
52230
53097
|
if (c1Result) {
|
|
52231
53098
|
const point2 = c1Result.point[xyzAxis];
|
|
52232
53099
|
const isOutside = leftToRight ? point2 <= float32Array2[c2 + splitAxis] : (
|
|
@@ -52237,8 +53104,8 @@ function _raycastFirst(nodeIndex32, bvh, side, ray, near, far) {
|
|
|
52237
53104
|
return c1Result;
|
|
52238
53105
|
}
|
|
52239
53106
|
}
|
|
52240
|
-
const c2Intersection = intersectRay(c2, float32Array2,
|
|
52241
|
-
const c2Result = c2Intersection ? _raycastFirst(c2, bvh, side,
|
|
53107
|
+
const c2Intersection = intersectRay(c2, float32Array2, ray2, near, far);
|
|
53108
|
+
const c2Result = c2Intersection ? _raycastFirst(c2, bvh, side, ray2, near, far) : null;
|
|
52242
53109
|
if (c1Result && c2Result) {
|
|
52243
53110
|
return c1Result.distance <= c2Result.distance ? c1Result : c2Result;
|
|
52244
53111
|
} else {
|
|
@@ -52860,7 +53727,7 @@ class MeshBVH {
|
|
|
52860
53727
|
}
|
|
52861
53728
|
}
|
|
52862
53729
|
/* Core Cast Functions */
|
|
52863
|
-
raycast(
|
|
53730
|
+
raycast(ray2, materialOrSide = FrontSide, near = 0, far = Infinity) {
|
|
52864
53731
|
const roots = this._roots;
|
|
52865
53732
|
const geometry = this.geometry;
|
|
52866
53733
|
const intersects = [];
|
|
@@ -52872,7 +53739,7 @@ class MeshBVH {
|
|
|
52872
53739
|
for (let i = 0, l = roots.length; i < l; i++) {
|
|
52873
53740
|
const materialSide = isArrayMaterial ? materialOrSide[groups[i].materialIndex].side : side;
|
|
52874
53741
|
const startCount = intersects.length;
|
|
52875
|
-
raycastFunc(this, i, materialSide,
|
|
53742
|
+
raycastFunc(this, i, materialSide, ray2, intersects, near, far);
|
|
52876
53743
|
if (isArrayMaterial) {
|
|
52877
53744
|
const materialIndex = groups[i].materialIndex;
|
|
52878
53745
|
for (let j = startCount, jl = intersects.length; j < jl; j++) {
|
|
@@ -52882,7 +53749,7 @@ class MeshBVH {
|
|
|
52882
53749
|
}
|
|
52883
53750
|
return intersects;
|
|
52884
53751
|
}
|
|
52885
|
-
raycastFirst(
|
|
53752
|
+
raycastFirst(ray2, materialOrSide = FrontSide, near = 0, far = Infinity) {
|
|
52886
53753
|
const roots = this._roots;
|
|
52887
53754
|
const geometry = this.geometry;
|
|
52888
53755
|
const isMaterial = materialOrSide.isMaterial;
|
|
@@ -52893,7 +53760,7 @@ class MeshBVH {
|
|
|
52893
53760
|
const raycastFirstFunc = this.indirect ? raycastFirst_indirect : raycastFirst;
|
|
52894
53761
|
for (let i = 0, l = roots.length; i < l; i++) {
|
|
52895
53762
|
const materialSide = isArrayMaterial ? materialOrSide[groups[i].materialIndex].side : side;
|
|
52896
|
-
const result = raycastFirstFunc(this, i, materialSide,
|
|
53763
|
+
const result = raycastFirstFunc(this, i, materialSide, ray2, near, far);
|
|
52897
53764
|
if (result != null && (closestResult == null || result.distance < closestResult.distance)) {
|
|
52898
53765
|
closestResult = result;
|
|
52899
53766
|
if (isArrayMaterial) {
|
|
@@ -53062,6 +53929,637 @@ class MeshBVH {
|
|
|
53062
53929
|
return target;
|
|
53063
53930
|
}
|
|
53064
53931
|
}
|
|
53932
|
+
function convertRaycastIntersect(hit, object, raycaster) {
|
|
53933
|
+
if (hit === null) {
|
|
53934
|
+
return null;
|
|
53935
|
+
}
|
|
53936
|
+
hit.point.applyMatrix4(object.matrixWorld);
|
|
53937
|
+
hit.distance = hit.point.distanceTo(raycaster.ray.origin);
|
|
53938
|
+
hit.object = object;
|
|
53939
|
+
return hit;
|
|
53940
|
+
}
|
|
53941
|
+
const ray = /* @__PURE__ */ new Ray();
|
|
53942
|
+
const direction = /* @__PURE__ */ new Vector3();
|
|
53943
|
+
const tmpInverseMatrix = /* @__PURE__ */ new Matrix4();
|
|
53944
|
+
const origMeshRaycastFunc = Mesh.prototype.raycast;
|
|
53945
|
+
const origBatchedRaycastFunc = BatchedMesh.prototype.raycast;
|
|
53946
|
+
const _worldScale = /* @__PURE__ */ new Vector3();
|
|
53947
|
+
const _mesh = /* @__PURE__ */ new Mesh();
|
|
53948
|
+
const _batchIntersects = [];
|
|
53949
|
+
function acceleratedRaycast(raycaster, intersects) {
|
|
53950
|
+
if (this.isBatchedMesh) {
|
|
53951
|
+
acceleratedBatchedMeshRaycast.call(this, raycaster, intersects);
|
|
53952
|
+
} else {
|
|
53953
|
+
acceleratedMeshRaycast.call(this, raycaster, intersects);
|
|
53954
|
+
}
|
|
53955
|
+
}
|
|
53956
|
+
function acceleratedBatchedMeshRaycast(raycaster, intersects) {
|
|
53957
|
+
if (this.boundsTrees) {
|
|
53958
|
+
const boundsTrees = this.boundsTrees;
|
|
53959
|
+
const drawInfo = this._drawInfo || this._instanceInfo;
|
|
53960
|
+
const drawRanges = this._drawRanges || this._geometryInfo;
|
|
53961
|
+
const matrixWorld = this.matrixWorld;
|
|
53962
|
+
_mesh.material = this.material;
|
|
53963
|
+
_mesh.geometry = this.geometry;
|
|
53964
|
+
const oldBoundsTree = _mesh.geometry.boundsTree;
|
|
53965
|
+
const oldDrawRange = _mesh.geometry.drawRange;
|
|
53966
|
+
if (_mesh.geometry.boundingSphere === null) {
|
|
53967
|
+
_mesh.geometry.boundingSphere = new Sphere();
|
|
53968
|
+
}
|
|
53969
|
+
for (let i = 0, l = drawInfo.length; i < l; i++) {
|
|
53970
|
+
if (!this.getVisibleAt(i)) {
|
|
53971
|
+
continue;
|
|
53972
|
+
}
|
|
53973
|
+
const geometryId = drawInfo[i].geometryIndex;
|
|
53974
|
+
_mesh.geometry.boundsTree = boundsTrees[geometryId];
|
|
53975
|
+
this.getMatrixAt(i, _mesh.matrixWorld).premultiply(matrixWorld);
|
|
53976
|
+
if (!_mesh.geometry.boundsTree) {
|
|
53977
|
+
this.getBoundingBoxAt(geometryId, _mesh.geometry.boundingBox);
|
|
53978
|
+
this.getBoundingSphereAt(geometryId, _mesh.geometry.boundingSphere);
|
|
53979
|
+
const drawRange = drawRanges[geometryId];
|
|
53980
|
+
_mesh.geometry.setDrawRange(drawRange.start, drawRange.count);
|
|
53981
|
+
}
|
|
53982
|
+
_mesh.raycast(raycaster, _batchIntersects);
|
|
53983
|
+
for (let j = 0, l2 = _batchIntersects.length; j < l2; j++) {
|
|
53984
|
+
const intersect2 = _batchIntersects[j];
|
|
53985
|
+
intersect2.object = this;
|
|
53986
|
+
intersect2.batchId = i;
|
|
53987
|
+
intersects.push(intersect2);
|
|
53988
|
+
}
|
|
53989
|
+
_batchIntersects.length = 0;
|
|
53990
|
+
}
|
|
53991
|
+
_mesh.geometry.boundsTree = oldBoundsTree;
|
|
53992
|
+
_mesh.geometry.drawRange = oldDrawRange;
|
|
53993
|
+
_mesh.material = null;
|
|
53994
|
+
_mesh.geometry = null;
|
|
53995
|
+
} else {
|
|
53996
|
+
origBatchedRaycastFunc.call(this, raycaster, intersects);
|
|
53997
|
+
}
|
|
53998
|
+
}
|
|
53999
|
+
function acceleratedMeshRaycast(raycaster, intersects) {
|
|
54000
|
+
if (this.geometry.boundsTree) {
|
|
54001
|
+
if (this.material === void 0) return;
|
|
54002
|
+
tmpInverseMatrix.copy(this.matrixWorld).invert();
|
|
54003
|
+
ray.copy(raycaster.ray).applyMatrix4(tmpInverseMatrix);
|
|
54004
|
+
_worldScale.setFromMatrixScale(this.matrixWorld);
|
|
54005
|
+
direction.copy(ray.direction).multiply(_worldScale);
|
|
54006
|
+
const scaleFactor = direction.length();
|
|
54007
|
+
const near = raycaster.near / scaleFactor;
|
|
54008
|
+
const far = raycaster.far / scaleFactor;
|
|
54009
|
+
const bvh = this.geometry.boundsTree;
|
|
54010
|
+
if (raycaster.firstHitOnly === true) {
|
|
54011
|
+
const hit = convertRaycastIntersect(bvh.raycastFirst(ray, this.material, near, far), this, raycaster);
|
|
54012
|
+
if (hit) {
|
|
54013
|
+
intersects.push(hit);
|
|
54014
|
+
}
|
|
54015
|
+
} else {
|
|
54016
|
+
const hits = bvh.raycast(ray, this.material, near, far);
|
|
54017
|
+
for (let i = 0, l = hits.length; i < l; i++) {
|
|
54018
|
+
const hit = convertRaycastIntersect(hits[i], this, raycaster);
|
|
54019
|
+
if (hit) {
|
|
54020
|
+
intersects.push(hit);
|
|
54021
|
+
}
|
|
54022
|
+
}
|
|
54023
|
+
}
|
|
54024
|
+
} else {
|
|
54025
|
+
origMeshRaycastFunc.call(this, raycaster, intersects);
|
|
54026
|
+
}
|
|
54027
|
+
}
|
|
54028
|
+
function cloneGeometryForFaceColors(geometry) {
|
|
54029
|
+
return geometry.index ? geometry.toNonIndexed() : geometry.clone();
|
|
54030
|
+
}
|
|
54031
|
+
function makeThicknessRaycastTarget(sourceGeometry, rayMaterial, jumpable) {
|
|
54032
|
+
const geometry = sourceGeometry.clone();
|
|
54033
|
+
geometry.boundsTree = new MeshBVH(geometry);
|
|
54034
|
+
const mesh = new Mesh(geometry, rayMaterial);
|
|
54035
|
+
mesh.raycast = acceleratedRaycast;
|
|
54036
|
+
return { mesh, jumpable, geometry };
|
|
54037
|
+
}
|
|
54038
|
+
function geometryMaxDimension(geometry) {
|
|
54039
|
+
geometry.computeBoundingBox();
|
|
54040
|
+
const box = geometry.boundingBox;
|
|
54041
|
+
if (!box) return 1;
|
|
54042
|
+
const size = new Vector3();
|
|
54043
|
+
box.getSize(size);
|
|
54044
|
+
return Math.max(1, size.x, size.y, size.z);
|
|
54045
|
+
}
|
|
54046
|
+
function firstOppositeSurfaceDistance(raycaster, rayTargetMeshes, jumpableMeshes, point2, direction2, epsilon2, far, contactTolerance) {
|
|
54047
|
+
const origin = point2.clone().addScaledVector(direction2, epsilon2);
|
|
54048
|
+
raycaster.set(origin, direction2);
|
|
54049
|
+
raycaster.near = epsilon2;
|
|
54050
|
+
raycaster.far = far;
|
|
54051
|
+
const hits = raycaster.intersectObjects(rayTargetMeshes, false);
|
|
54052
|
+
for (const hit of hits) {
|
|
54053
|
+
if (hit.distance <= epsilon2) continue;
|
|
54054
|
+
if (hit.distance <= contactTolerance && jumpableMeshes.has(hit.object)) continue;
|
|
54055
|
+
return hit.distance + epsilon2;
|
|
54056
|
+
}
|
|
54057
|
+
return null;
|
|
54058
|
+
}
|
|
54059
|
+
function triangleThickness(raycaster, rayTargetMeshes, jumpableMeshes, centroid, normal, epsilon2, far, contactTolerance) {
|
|
54060
|
+
const forward = firstOppositeSurfaceDistance(
|
|
54061
|
+
raycaster,
|
|
54062
|
+
rayTargetMeshes,
|
|
54063
|
+
jumpableMeshes,
|
|
54064
|
+
centroid,
|
|
54065
|
+
normal,
|
|
54066
|
+
epsilon2,
|
|
54067
|
+
far,
|
|
54068
|
+
contactTolerance
|
|
54069
|
+
);
|
|
54070
|
+
const backward = firstOppositeSurfaceDistance(
|
|
54071
|
+
raycaster,
|
|
54072
|
+
rayTargetMeshes,
|
|
54073
|
+
jumpableMeshes,
|
|
54074
|
+
centroid,
|
|
54075
|
+
normal.clone().negate(),
|
|
54076
|
+
epsilon2,
|
|
54077
|
+
far,
|
|
54078
|
+
contactTolerance
|
|
54079
|
+
);
|
|
54080
|
+
if (forward == null) return backward;
|
|
54081
|
+
if (backward == null) return forward;
|
|
54082
|
+
return Math.min(forward, backward);
|
|
54083
|
+
}
|
|
54084
|
+
function analyzeThicknessGeometry(sourceGeometry, rawOptions = {}, context = {}) {
|
|
54085
|
+
const options = resolveThicknessInspectionOptions(rawOptions);
|
|
54086
|
+
const geometry = cloneGeometryForFaceColors(sourceGeometry);
|
|
54087
|
+
const position = geometry.getAttribute("position");
|
|
54088
|
+
if (!position || position.count < 3) {
|
|
54089
|
+
return {
|
|
54090
|
+
geometry,
|
|
54091
|
+
samples: [],
|
|
54092
|
+
pointSamples: [],
|
|
54093
|
+
triangleCount: 0,
|
|
54094
|
+
sampledTriangleCount: 0,
|
|
54095
|
+
sampleStride: 1,
|
|
54096
|
+
warnings: ["No triangle geometry."]
|
|
54097
|
+
};
|
|
54098
|
+
}
|
|
54099
|
+
const triangleCount = Math.floor(position.count / 3);
|
|
54100
|
+
const surfaceTriangles = readSurfaceTriangles(position);
|
|
54101
|
+
const surfaceSamples = sampleSurfaceTriangles(surfaceTriangles, options.maxSamplesPerObject);
|
|
54102
|
+
const connectedGeometries = context.connectedGeometries ?? [];
|
|
54103
|
+
const maxDim2 = Math.max(geometryMaxDimension(geometry), ...connectedGeometries.map(geometryMaxDimension));
|
|
54104
|
+
const epsilon2 = Math.max(1e-4, maxDim2 * 1e-6);
|
|
54105
|
+
const far = Math.max(maxDim2 * 4, options.maxThickness * 4, 1);
|
|
54106
|
+
const colors = new Float32Array(position.count * 3);
|
|
54107
|
+
const triangleThicknessValues = new Array(triangleCount).fill(void 0);
|
|
54108
|
+
const samples = [];
|
|
54109
|
+
const pointSamples = [];
|
|
54110
|
+
const warnings = [];
|
|
54111
|
+
const rayMaterial = new MeshBasicMaterial({ side: DoubleSide });
|
|
54112
|
+
const rayTargets = [
|
|
54113
|
+
makeThicknessRaycastTarget(geometry, rayMaterial, false),
|
|
54114
|
+
...connectedGeometries.map((connectedGeometry) => makeThicknessRaycastTarget(connectedGeometry, rayMaterial, true))
|
|
54115
|
+
];
|
|
54116
|
+
try {
|
|
54117
|
+
const rayTargetMeshes = rayTargets.map((target) => target.mesh);
|
|
54118
|
+
const jumpableMeshes = new Set(rayTargets.filter((target) => target.jumpable).map((target) => target.mesh));
|
|
54119
|
+
const raycaster = new Raycaster();
|
|
54120
|
+
if (surfaceTriangles.length === 0) {
|
|
54121
|
+
warnings.push("No non-degenerate triangle surface was available for thickness sampling.");
|
|
54122
|
+
} else if (surfaceSamples.length < surfaceTriangles.length) {
|
|
54123
|
+
warnings.push(
|
|
54124
|
+
`Area sampling budget ${surfaceSamples.length} covers ${surfaceTriangles.length} surface triangles; increase --thickness-samples for denser analysis.`
|
|
54125
|
+
);
|
|
54126
|
+
}
|
|
54127
|
+
const sampledTriangleIndexes = /* @__PURE__ */ new Set();
|
|
54128
|
+
for (const sample of surfaceSamples) {
|
|
54129
|
+
sampledTriangleIndexes.add(sample.triangle.index);
|
|
54130
|
+
const thickness = triangleThickness(
|
|
54131
|
+
raycaster,
|
|
54132
|
+
rayTargetMeshes,
|
|
54133
|
+
jumpableMeshes,
|
|
54134
|
+
sample.position,
|
|
54135
|
+
sample.normal,
|
|
54136
|
+
epsilon2,
|
|
54137
|
+
far,
|
|
54138
|
+
options.contactTolerance
|
|
54139
|
+
);
|
|
54140
|
+
samples.push({ thickness, area: sample.area });
|
|
54141
|
+
const previous = triangleThicknessValues[sample.triangle.index];
|
|
54142
|
+
if (previous === void 0 || previous == null || thickness != null && thickness < previous) {
|
|
54143
|
+
triangleThicknessValues[sample.triangle.index] = thickness;
|
|
54144
|
+
}
|
|
54145
|
+
pointSamples.push({
|
|
54146
|
+
position: [sample.position.x, sample.position.y, sample.position.z],
|
|
54147
|
+
normal: [sample.normal.x, sample.normal.y, sample.normal.z],
|
|
54148
|
+
value: thickness,
|
|
54149
|
+
className: thicknessClass(thickness, options),
|
|
54150
|
+
color: thicknessColor(thickness, options),
|
|
54151
|
+
area: sample.area
|
|
54152
|
+
});
|
|
54153
|
+
}
|
|
54154
|
+
for (let tri = 0; tri < triangleCount; tri += 1) {
|
|
54155
|
+
const color = thicknessColor(triangleThicknessValues[tri], options);
|
|
54156
|
+
const offset = tri * 3;
|
|
54157
|
+
for (let vertex2 = 0; vertex2 < 3; vertex2 += 1) {
|
|
54158
|
+
const colorOffset = (offset + vertex2) * 3;
|
|
54159
|
+
colors[colorOffset] = color[0] / 255;
|
|
54160
|
+
colors[colorOffset + 1] = color[1] / 255;
|
|
54161
|
+
colors[colorOffset + 2] = color[2] / 255;
|
|
54162
|
+
}
|
|
54163
|
+
}
|
|
54164
|
+
geometry.setAttribute("color", new BufferAttribute(colors, 3));
|
|
54165
|
+
return {
|
|
54166
|
+
geometry,
|
|
54167
|
+
samples,
|
|
54168
|
+
pointSamples,
|
|
54169
|
+
triangleCount,
|
|
54170
|
+
sampledTriangleCount: sampledTriangleIndexes.size,
|
|
54171
|
+
sampleStride: Math.max(1, Math.ceil(Math.max(1, surfaceTriangles.length) / Math.max(1, sampledTriangleIndexes.size))),
|
|
54172
|
+
warnings
|
|
54173
|
+
};
|
|
54174
|
+
} finally {
|
|
54175
|
+
rayTargets.forEach((target) => target.geometry.dispose());
|
|
54176
|
+
rayMaterial.dispose();
|
|
54177
|
+
}
|
|
54178
|
+
}
|
|
54179
|
+
const DEFAULT_VERTEX_CAP = 2e6;
|
|
54180
|
+
const DEFAULT_TARGET_EDGE_SPACING_FACTOR = 2;
|
|
54181
|
+
const DEFAULT_K = 8;
|
|
54182
|
+
const DEFAULT_GATE_DOT = 0.3;
|
|
54183
|
+
const SCATTER_CELL_SPACING_FACTOR = 1.5;
|
|
54184
|
+
const SCATTER_RADIUS_SPACING_FACTOR = 3;
|
|
54185
|
+
const IDW_DISTANCE_FLOOR = 1e-9;
|
|
54186
|
+
const MAX_SUBDIVISION_PASSES = 24;
|
|
54187
|
+
function subVec(a2, b) {
|
|
54188
|
+
return [a2[0] - b[0], a2[1] - b[1], a2[2] - b[2]];
|
|
54189
|
+
}
|
|
54190
|
+
function crossVec(a2, b) {
|
|
54191
|
+
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]];
|
|
54192
|
+
}
|
|
54193
|
+
function lenVec(a2) {
|
|
54194
|
+
return Math.hypot(a2[0], a2[1], a2[2]);
|
|
54195
|
+
}
|
|
54196
|
+
function getVert(positions, i) {
|
|
54197
|
+
const o = i * 3;
|
|
54198
|
+
return [positions[o], positions[o + 1], positions[o + 2]];
|
|
54199
|
+
}
|
|
54200
|
+
function triArea(positions, a2, b, c2) {
|
|
54201
|
+
const va = getVert(positions, a2);
|
|
54202
|
+
return 0.5 * lenVec(crossVec(subVec(getVert(positions, b), va), subVec(getVert(positions, c2), va)));
|
|
54203
|
+
}
|
|
54204
|
+
function triNormal(positions, a2, b, c2) {
|
|
54205
|
+
const va = getVert(positions, a2);
|
|
54206
|
+
const n = crossVec(subVec(getVert(positions, b), va), subVec(getVert(positions, c2), va));
|
|
54207
|
+
const l = lenVec(n) || 1;
|
|
54208
|
+
return [n[0] / l, n[1] / l, n[2] / l];
|
|
54209
|
+
}
|
|
54210
|
+
function edgeLen(positions, a2, b) {
|
|
54211
|
+
return lenVec(subVec(getVert(positions, a2), getVert(positions, b)));
|
|
54212
|
+
}
|
|
54213
|
+
function maxEdge(positions, a2, b, c2) {
|
|
54214
|
+
return Math.max(edgeLen(positions, a2, b), edgeLen(positions, b, c2), edgeLen(positions, c2, a2));
|
|
54215
|
+
}
|
|
54216
|
+
function weld(positions) {
|
|
54217
|
+
if (positions.length % 9 !== 0) {
|
|
54218
|
+
throw new Error(
|
|
54219
|
+
`weld: positions length must be a multiple of 9 (9 floats per triangle), got ${positions.length}`
|
|
54220
|
+
);
|
|
54221
|
+
}
|
|
54222
|
+
positions.length / 3;
|
|
54223
|
+
let minX = Infinity;
|
|
54224
|
+
let minY = Infinity;
|
|
54225
|
+
let minZ = Infinity;
|
|
54226
|
+
let maxX = -Infinity;
|
|
54227
|
+
let maxY = -Infinity;
|
|
54228
|
+
let maxZ = -Infinity;
|
|
54229
|
+
for (let i = 0; i < positions.length; i += 3) {
|
|
54230
|
+
const x2 = positions[i];
|
|
54231
|
+
const y2 = positions[i + 1];
|
|
54232
|
+
const z2 = positions[i + 2];
|
|
54233
|
+
if (!Number.isFinite(x2) || !Number.isFinite(y2) || !Number.isFinite(z2)) {
|
|
54234
|
+
throw new Error(`weld: non-finite vertex position at float index ${i}`);
|
|
54235
|
+
}
|
|
54236
|
+
if (x2 < minX) minX = x2;
|
|
54237
|
+
if (y2 < minY) minY = y2;
|
|
54238
|
+
if (z2 < minZ) minZ = z2;
|
|
54239
|
+
if (x2 > maxX) maxX = x2;
|
|
54240
|
+
if (y2 > maxY) maxY = y2;
|
|
54241
|
+
if (z2 > maxZ) maxZ = z2;
|
|
54242
|
+
}
|
|
54243
|
+
const diagonal = Math.hypot(maxX - minX, maxY - minY, maxZ - minZ);
|
|
54244
|
+
const tolerance = Math.max(diagonal * 1e-5, Number.EPSILON);
|
|
54245
|
+
const remap = /* @__PURE__ */ new Map();
|
|
54246
|
+
const out = [];
|
|
54247
|
+
const tris = [];
|
|
54248
|
+
const inv = 1 / tolerance;
|
|
54249
|
+
const quantKey = (i) => {
|
|
54250
|
+
const qx = Math.round(positions[i] * inv);
|
|
54251
|
+
const qy = Math.round(positions[i + 1] * inv);
|
|
54252
|
+
const qz = Math.round(positions[i + 2] * inv);
|
|
54253
|
+
return `${qx},${qy},${qz}`;
|
|
54254
|
+
};
|
|
54255
|
+
for (let tri = 0; tri < positions.length; tri += 9) {
|
|
54256
|
+
const idx = [];
|
|
54257
|
+
for (let corner = 0; corner < 3; corner += 1) {
|
|
54258
|
+
const o = tri + corner * 3;
|
|
54259
|
+
const key2 = quantKey(o);
|
|
54260
|
+
let vi = remap.get(key2);
|
|
54261
|
+
if (vi === void 0) {
|
|
54262
|
+
vi = out.length / 3;
|
|
54263
|
+
out.push(positions[o], positions[o + 1], positions[o + 2]);
|
|
54264
|
+
remap.set(key2, vi);
|
|
54265
|
+
}
|
|
54266
|
+
idx.push(vi);
|
|
54267
|
+
}
|
|
54268
|
+
if (idx[0] !== idx[1] && idx[1] !== idx[2] && idx[2] !== idx[0]) {
|
|
54269
|
+
tris.push(idx[0], idx[1], idx[2]);
|
|
54270
|
+
}
|
|
54271
|
+
}
|
|
54272
|
+
const distinctVertexCount = out.length / 3;
|
|
54273
|
+
const degenerate = distinctVertexCount < 3 || tris.length === 0;
|
|
54274
|
+
return { positions: out, tris, degenerate };
|
|
54275
|
+
}
|
|
54276
|
+
function adaptiveSubdivide(mesh, targetEdge, vertexCap) {
|
|
54277
|
+
requirePositiveFiniteNumber(targetEdge, "adaptiveSubdivide targetEdge");
|
|
54278
|
+
requireIntegerAtLeast(vertexCap, "adaptiveSubdivide vertexCap", 3);
|
|
54279
|
+
const positions = mesh.positions.slice();
|
|
54280
|
+
let tris = mesh.tris.slice();
|
|
54281
|
+
let capped = false;
|
|
54282
|
+
const keyOf = (a2, b) => a2 < b ? `${a2}_${b}` : `${b}_${a2}`;
|
|
54283
|
+
for (let pass = 0; pass < MAX_SUBDIVISION_PASSES; pass += 1) {
|
|
54284
|
+
const next = [];
|
|
54285
|
+
const midCache = /* @__PURE__ */ new Map();
|
|
54286
|
+
let changed = false;
|
|
54287
|
+
const getMid = (a2, b) => {
|
|
54288
|
+
const key2 = keyOf(a2, b);
|
|
54289
|
+
let mi = midCache.get(key2);
|
|
54290
|
+
if (mi === void 0) {
|
|
54291
|
+
mi = positions.length / 3;
|
|
54292
|
+
const ao = a2 * 3;
|
|
54293
|
+
const bo = b * 3;
|
|
54294
|
+
positions.push(
|
|
54295
|
+
(positions[ao] + positions[bo]) / 2,
|
|
54296
|
+
(positions[ao + 1] + positions[bo + 1]) / 2,
|
|
54297
|
+
(positions[ao + 2] + positions[bo + 2]) / 2
|
|
54298
|
+
);
|
|
54299
|
+
midCache.set(key2, mi);
|
|
54300
|
+
}
|
|
54301
|
+
return mi;
|
|
54302
|
+
};
|
|
54303
|
+
for (let t = 0; t < tris.length; t += 3) {
|
|
54304
|
+
const a2 = tris[t];
|
|
54305
|
+
const b = tris[t + 1];
|
|
54306
|
+
const c2 = tris[t + 2];
|
|
54307
|
+
const vertexCount = positions.length / 3;
|
|
54308
|
+
if (maxEdge(positions, a2, b, c2) > targetEdge && vertexCount < vertexCap) {
|
|
54309
|
+
const ab = getMid(a2, b);
|
|
54310
|
+
const bc = getMid(b, c2);
|
|
54311
|
+
const ca = getMid(c2, a2);
|
|
54312
|
+
next.push(a2, ab, ca, ab, b, bc, ca, bc, c2, ab, bc, ca);
|
|
54313
|
+
changed = true;
|
|
54314
|
+
} else {
|
|
54315
|
+
if (positions.length / 3 >= vertexCap) capped = true;
|
|
54316
|
+
next.push(a2, b, c2);
|
|
54317
|
+
}
|
|
54318
|
+
}
|
|
54319
|
+
tris = next;
|
|
54320
|
+
if (!changed) break;
|
|
54321
|
+
}
|
|
54322
|
+
return { positions, tris, capped };
|
|
54323
|
+
}
|
|
54324
|
+
function vertexNormals(mesh) {
|
|
54325
|
+
const vertexCount = mesh.positions.length / 3;
|
|
54326
|
+
const acc = new Float32Array(vertexCount * 3);
|
|
54327
|
+
for (let t = 0; t < mesh.tris.length; t += 3) {
|
|
54328
|
+
const a2 = mesh.tris[t];
|
|
54329
|
+
const b = mesh.tris[t + 1];
|
|
54330
|
+
const c2 = mesh.tris[t + 2];
|
|
54331
|
+
const n = triNormal(mesh.positions, a2, b, c2);
|
|
54332
|
+
const area = triArea(mesh.positions, a2, b, c2);
|
|
54333
|
+
const nx = n[0] * area;
|
|
54334
|
+
const ny = n[1] * area;
|
|
54335
|
+
const nz = n[2] * area;
|
|
54336
|
+
for (const vi of [a2, b, c2]) {
|
|
54337
|
+
acc[vi * 3] += nx;
|
|
54338
|
+
acc[vi * 3 + 1] += ny;
|
|
54339
|
+
acc[vi * 3 + 2] += nz;
|
|
54340
|
+
}
|
|
54341
|
+
}
|
|
54342
|
+
for (let i = 0; i < vertexCount; i += 1) {
|
|
54343
|
+
const o = i * 3;
|
|
54344
|
+
const l = Math.hypot(acc[o], acc[o + 1], acc[o + 2]) || 1;
|
|
54345
|
+
acc[o] /= l;
|
|
54346
|
+
acc[o + 1] /= l;
|
|
54347
|
+
acc[o + 2] /= l;
|
|
54348
|
+
}
|
|
54349
|
+
return acc;
|
|
54350
|
+
}
|
|
54351
|
+
function buildSampleGrid(positions, cell) {
|
|
54352
|
+
const grid = /* @__PURE__ */ new Map();
|
|
54353
|
+
const sampleCount = positions.length / 3;
|
|
54354
|
+
for (let i = 0; i < sampleCount; i += 1) {
|
|
54355
|
+
const o = i * 3;
|
|
54356
|
+
const key2 = `${Math.floor(positions[o] / cell)},${Math.floor(positions[o + 1] / cell)},${Math.floor(positions[o + 2] / cell)}`;
|
|
54357
|
+
let arr = grid.get(key2);
|
|
54358
|
+
if (!arr) {
|
|
54359
|
+
arr = [];
|
|
54360
|
+
grid.set(key2, arr);
|
|
54361
|
+
}
|
|
54362
|
+
arr.push(i);
|
|
54363
|
+
}
|
|
54364
|
+
return { grid, cell };
|
|
54365
|
+
}
|
|
54366
|
+
function gatherSamples(sampleGrid, p2, rings, out) {
|
|
54367
|
+
out.length = 0;
|
|
54368
|
+
const { cell, grid } = sampleGrid;
|
|
54369
|
+
const bx = Math.floor(p2[0] / cell);
|
|
54370
|
+
const by = Math.floor(p2[1] / cell);
|
|
54371
|
+
const bz = Math.floor(p2[2] / cell);
|
|
54372
|
+
for (let dx = -rings; dx <= rings; dx += 1) {
|
|
54373
|
+
for (let dy = -rings; dy <= rings; dy += 1) {
|
|
54374
|
+
for (let dz = -rings; dz <= rings; dz += 1) {
|
|
54375
|
+
const arr = grid.get(`${bx + dx},${by + dy},${bz + dz}`);
|
|
54376
|
+
if (arr) for (const i of arr) out.push(i);
|
|
54377
|
+
}
|
|
54378
|
+
}
|
|
54379
|
+
}
|
|
54380
|
+
}
|
|
54381
|
+
function scatterToVertices(positions, vnormals, samples, spacing, k2, gateDot) {
|
|
54382
|
+
const cell = spacing * SCATTER_CELL_SPACING_FACTOR;
|
|
54383
|
+
const sampleGrid = buildSampleGrid(samples.positions, cell);
|
|
54384
|
+
const radius = spacing * SCATTER_RADIUS_SPACING_FACTOR;
|
|
54385
|
+
const radius2 = radius * radius;
|
|
54386
|
+
const vertexCount = positions.length / 3;
|
|
54387
|
+
const values = new Float32Array(vertexCount);
|
|
54388
|
+
let holeCount = 0;
|
|
54389
|
+
const candidates = [];
|
|
54390
|
+
const scratchP = [0, 0, 0];
|
|
54391
|
+
const bestD2 = new Float64Array(k2);
|
|
54392
|
+
const bestVal = new Float64Array(k2);
|
|
54393
|
+
for (let vi = 0; vi < vertexCount; vi += 1) {
|
|
54394
|
+
const pi = vi * 3;
|
|
54395
|
+
const px = positions[pi];
|
|
54396
|
+
const py = positions[pi + 1];
|
|
54397
|
+
const pz = positions[pi + 2];
|
|
54398
|
+
const nx = vnormals[pi];
|
|
54399
|
+
const ny = vnormals[pi + 1];
|
|
54400
|
+
const nz = vnormals[pi + 2];
|
|
54401
|
+
scratchP[0] = px;
|
|
54402
|
+
scratchP[1] = py;
|
|
54403
|
+
scratchP[2] = pz;
|
|
54404
|
+
gatherSamples(sampleGrid, scratchP, 3, candidates);
|
|
54405
|
+
let count = 0;
|
|
54406
|
+
let worst = 0;
|
|
54407
|
+
let worstD2 = -Infinity;
|
|
54408
|
+
for (let c2 = 0; c2 < candidates.length; c2 += 1) {
|
|
54409
|
+
const si = candidates[c2];
|
|
54410
|
+
const so = si * 3;
|
|
54411
|
+
const dx = samples.positions[so] - px;
|
|
54412
|
+
const dy = samples.positions[so + 1] - py;
|
|
54413
|
+
const dz = samples.positions[so + 2] - pz;
|
|
54414
|
+
const d2 = dx * dx + dy * dy + dz * dz;
|
|
54415
|
+
if (d2 > radius2) continue;
|
|
54416
|
+
if (samples.normals[so] * nx + samples.normals[so + 1] * ny + samples.normals[so + 2] * nz < gateDot) continue;
|
|
54417
|
+
const val = samples.values[si];
|
|
54418
|
+
if (count < k2) {
|
|
54419
|
+
bestD2[count] = d2;
|
|
54420
|
+
bestVal[count] = val;
|
|
54421
|
+
if (d2 > worstD2) {
|
|
54422
|
+
worstD2 = d2;
|
|
54423
|
+
worst = count;
|
|
54424
|
+
}
|
|
54425
|
+
count += 1;
|
|
54426
|
+
} else if (d2 < worstD2) {
|
|
54427
|
+
bestD2[worst] = d2;
|
|
54428
|
+
bestVal[worst] = val;
|
|
54429
|
+
worstD2 = -Infinity;
|
|
54430
|
+
for (let t = 0; t < k2; t += 1) {
|
|
54431
|
+
if (bestD2[t] > worstD2) {
|
|
54432
|
+
worstD2 = bestD2[t];
|
|
54433
|
+
worst = t;
|
|
54434
|
+
}
|
|
54435
|
+
}
|
|
54436
|
+
}
|
|
54437
|
+
}
|
|
54438
|
+
if (count === 0) {
|
|
54439
|
+
holeCount += 1;
|
|
54440
|
+
values[vi] = NaN;
|
|
54441
|
+
continue;
|
|
54442
|
+
}
|
|
54443
|
+
let w2 = 0;
|
|
54444
|
+
let acc = 0;
|
|
54445
|
+
for (let t = 0; t < count; t += 1) {
|
|
54446
|
+
const ww = 1 / Math.max(bestD2[t], IDW_DISTANCE_FLOOR);
|
|
54447
|
+
w2 += ww;
|
|
54448
|
+
acc += ww * bestVal[t];
|
|
54449
|
+
}
|
|
54450
|
+
values[vi] = acc / w2;
|
|
54451
|
+
}
|
|
54452
|
+
return { values, holeCount };
|
|
54453
|
+
}
|
|
54454
|
+
function backfillHoles(values, mesh) {
|
|
54455
|
+
const vertexCount = values.length;
|
|
54456
|
+
const adjacency = Array.from({ length: vertexCount }, () => []);
|
|
54457
|
+
for (let t = 0; t < mesh.tris.length; t += 3) {
|
|
54458
|
+
const a2 = mesh.tris[t];
|
|
54459
|
+
const b = mesh.tris[t + 1];
|
|
54460
|
+
const c2 = mesh.tris[t + 2];
|
|
54461
|
+
adjacency[a2].push(b, c2);
|
|
54462
|
+
adjacency[b].push(a2, c2);
|
|
54463
|
+
adjacency[c2].push(a2, b);
|
|
54464
|
+
}
|
|
54465
|
+
let frontier = [];
|
|
54466
|
+
for (let i = 0; i < vertexCount; i += 1) {
|
|
54467
|
+
if (Number.isFinite(values[i])) frontier.push(i);
|
|
54468
|
+
}
|
|
54469
|
+
if (frontier.length === 0) {
|
|
54470
|
+
values.fill(0);
|
|
54471
|
+
return;
|
|
54472
|
+
}
|
|
54473
|
+
while (frontier.length > 0) {
|
|
54474
|
+
const nextFrontier = [];
|
|
54475
|
+
for (const v of frontier) {
|
|
54476
|
+
const val = values[v];
|
|
54477
|
+
for (const n of adjacency[v]) {
|
|
54478
|
+
if (!Number.isFinite(values[n])) {
|
|
54479
|
+
values[n] = val;
|
|
54480
|
+
nextFrontier.push(n);
|
|
54481
|
+
}
|
|
54482
|
+
}
|
|
54483
|
+
}
|
|
54484
|
+
frontier = nextFrontier;
|
|
54485
|
+
}
|
|
54486
|
+
}
|
|
54487
|
+
function reconstructSurfaceScalarField(trianglePositions, samples, options = {}) {
|
|
54488
|
+
if (!(trianglePositions instanceof Float32Array)) {
|
|
54489
|
+
throw new Error("reconstructSurfaceScalarField: trianglePositions must be a Float32Array");
|
|
54490
|
+
}
|
|
54491
|
+
if (trianglePositions.length === 0 || trianglePositions.length % 9 !== 0) {
|
|
54492
|
+
throw new Error(
|
|
54493
|
+
`reconstructSurfaceScalarField: trianglePositions length must be a positive multiple of 9, got ${trianglePositions.length}`
|
|
54494
|
+
);
|
|
54495
|
+
}
|
|
54496
|
+
if (!(samples.positions instanceof Float32Array) || !(samples.values instanceof Float32Array) || !(samples.normals instanceof Float32Array)) {
|
|
54497
|
+
throw new Error("reconstructSurfaceScalarField: samples positions/values/normals must be Float32Arrays");
|
|
54498
|
+
}
|
|
54499
|
+
const sampleCount = samples.values.length;
|
|
54500
|
+
if (sampleCount === 0) {
|
|
54501
|
+
throw new Error("reconstructSurfaceScalarField: samples must be non-empty");
|
|
54502
|
+
}
|
|
54503
|
+
if (samples.positions.length !== sampleCount * 3) {
|
|
54504
|
+
throw new Error(
|
|
54505
|
+
`reconstructSurfaceScalarField: samples.positions length ${samples.positions.length} must equal values*3 (${sampleCount * 3})`
|
|
54506
|
+
);
|
|
54507
|
+
}
|
|
54508
|
+
if (samples.normals.length !== sampleCount * 3) {
|
|
54509
|
+
throw new Error(
|
|
54510
|
+
`reconstructSurfaceScalarField: samples.normals length ${samples.normals.length} must equal values*3 (${sampleCount * 3})`
|
|
54511
|
+
);
|
|
54512
|
+
}
|
|
54513
|
+
for (let i = 0; i < sampleCount; i += 1) {
|
|
54514
|
+
requireFiniteNumber(samples.values[i], `samples.values[${i}]`);
|
|
54515
|
+
}
|
|
54516
|
+
const vertexCap = options.vertexCap === void 0 ? DEFAULT_VERTEX_CAP : requireIntegerAtLeast(options.vertexCap, "vertexCap", 3);
|
|
54517
|
+
const targetEdgeSpacingFactor = options.targetEdgeSpacingFactor === void 0 ? DEFAULT_TARGET_EDGE_SPACING_FACTOR : requirePositiveFiniteNumber(options.targetEdgeSpacingFactor, "targetEdgeSpacingFactor");
|
|
54518
|
+
const k2 = options.k === void 0 ? DEFAULT_K : requireIntegerAtLeast(options.k, "k", 1);
|
|
54519
|
+
const gateDot = options.gateDot === void 0 ? DEFAULT_GATE_DOT : requireFiniteNumber(options.gateDot, "gateDot");
|
|
54520
|
+
const welded = weld(trianglePositions);
|
|
54521
|
+
let surfaceArea = 0;
|
|
54522
|
+
for (let t = 0; t < welded.tris.length; t += 3) {
|
|
54523
|
+
surfaceArea += triArea(welded.positions, welded.tris[t], welded.tris[t + 1], welded.tris[t + 2]);
|
|
54524
|
+
}
|
|
54525
|
+
const sampleSpacing = surfaceArea > 0 ? Math.sqrt(surfaceArea / sampleCount) : 0;
|
|
54526
|
+
let subdivided;
|
|
54527
|
+
if (welded.degenerate || !(sampleSpacing > 0)) {
|
|
54528
|
+
subdivided = { positions: welded.positions, tris: welded.tris, capped: false };
|
|
54529
|
+
} else {
|
|
54530
|
+
const targetEdge = targetEdgeSpacingFactor * sampleSpacing;
|
|
54531
|
+
subdivided = adaptiveSubdivide(welded, targetEdge, vertexCap);
|
|
54532
|
+
}
|
|
54533
|
+
const normals = vertexNormals(subdivided);
|
|
54534
|
+
const effectiveSpacing = sampleSpacing > 0 ? sampleSpacing : 1;
|
|
54535
|
+
const scatter = scatterToVertices(subdivided.positions, normals, samples, effectiveSpacing, k2, gateDot);
|
|
54536
|
+
let valueMin = Infinity;
|
|
54537
|
+
let valueMax = -Infinity;
|
|
54538
|
+
for (let i = 0; i < scatter.values.length; i += 1) {
|
|
54539
|
+
const v = scatter.values[i];
|
|
54540
|
+
if (!Number.isFinite(v)) continue;
|
|
54541
|
+
if (v < valueMin) valueMin = v;
|
|
54542
|
+
if (v > valueMax) valueMax = v;
|
|
54543
|
+
}
|
|
54544
|
+
if (!Number.isFinite(valueMin) || !Number.isFinite(valueMax)) {
|
|
54545
|
+
valueMin = 0;
|
|
54546
|
+
valueMax = 0;
|
|
54547
|
+
}
|
|
54548
|
+
backfillHoles(scatter.values, subdivided);
|
|
54549
|
+
const vertexCount = subdivided.positions.length / 3;
|
|
54550
|
+
return {
|
|
54551
|
+
positions: Float32Array.from(subdivided.positions),
|
|
54552
|
+
normals,
|
|
54553
|
+
index: Uint32Array.from(subdivided.tris),
|
|
54554
|
+
values: scatter.values,
|
|
54555
|
+
valueMin,
|
|
54556
|
+
valueMax,
|
|
54557
|
+
capped: subdivided.capped,
|
|
54558
|
+
degenerate: welded.degenerate,
|
|
54559
|
+
holeCount: scatter.holeCount,
|
|
54560
|
+
vertexCount
|
|
54561
|
+
};
|
|
54562
|
+
}
|
|
53065
54563
|
const DEFAULT_COLORMAP = "viridis";
|
|
53066
54564
|
function cloneSerializedFaceRef(face) {
|
|
53067
54565
|
return {
|
|
@@ -53096,7 +54594,8 @@ class FrozenShapeBackend {
|
|
|
53096
54594
|
edgePositions: this._data.geometryEdgePositions,
|
|
53097
54595
|
triangleFaceIds: this._data.geometryTriangleFaceIds,
|
|
53098
54596
|
faceIdNames: this._data.geometryFaceIdNames,
|
|
53099
|
-
hasSmoothNormals: this._data.hasSmoothNormals ?? false
|
|
54597
|
+
hasSmoothNormals: this._data.hasSmoothNormals ?? false,
|
|
54598
|
+
uvs: this._data.geometryUvs
|
|
53100
54599
|
};
|
|
53101
54600
|
}
|
|
53102
54601
|
getMeshReconstructionData() {
|
|
@@ -53264,9 +54763,17 @@ const EDGE_THRESHOLD_DOT = Math.cos(Math.PI / 180);
|
|
|
53264
54763
|
const SMOOTH_THRESHOLD_DOT = Math.cos(30 * Math.PI / 180);
|
|
53265
54764
|
function computeGeometryArrays(mesh, options = {}) {
|
|
53266
54765
|
const { numProp, numTri: triCount, triVerts, vertProperties, vertNormals, cornerNormals } = mesh;
|
|
54766
|
+
if (numProp !== NUM_PROP_POSITION_ONLY && numProp !== NUM_PROP_WITH_NORMAL && numProp !== NUM_PROP_WITH_UV) {
|
|
54767
|
+
throw new Error(
|
|
54768
|
+
`computeGeometryArrays: illegal vertProperties numProp ${numProp}. Only ${NUM_PROP_POSITION_ONLY} (position), ${NUM_PROP_WITH_NORMAL} (position+normal), and ${NUM_PROP_WITH_UV} (position+normal+uv) are valid; ${numProp} (e.g. a truncated uv channel) is not.`
|
|
54769
|
+
);
|
|
54770
|
+
}
|
|
54771
|
+
const hasStoredNormals = numProp === NUM_PROP_WITH_NORMAL || numProp === NUM_PROP_WITH_UV;
|
|
54772
|
+
const hasStoredUvs = numProp === NUM_PROP_WITH_UV;
|
|
53267
54773
|
const useCornerNormals = !!cornerNormals && cornerNormals.length === triCount * 9;
|
|
53268
54774
|
const positions = new Float32Array(triCount * 9);
|
|
53269
54775
|
const normals = new Float32Array(triCount * 9);
|
|
54776
|
+
const uvs = hasStoredUvs ? new Float32Array(triCount * 6) : void 0;
|
|
53270
54777
|
const faceNx = new Float32Array(triCount);
|
|
53271
54778
|
const faceNy = new Float32Array(triCount);
|
|
53272
54779
|
const faceNz = new Float32Array(triCount);
|
|
@@ -53296,6 +54803,15 @@ function computeGeometryArrays(mesh, options = {}) {
|
|
|
53296
54803
|
positions[o + 6] = cx;
|
|
53297
54804
|
positions[o + 7] = cy;
|
|
53298
54805
|
positions[o + 8] = cz;
|
|
54806
|
+
if (uvs) {
|
|
54807
|
+
const u2 = t * 6;
|
|
54808
|
+
uvs[u2] = vertProperties[i0 * numProp + UV_OFFSET];
|
|
54809
|
+
uvs[u2 + 1] = vertProperties[i0 * numProp + UV_OFFSET + 1];
|
|
54810
|
+
uvs[u2 + 2] = vertProperties[i1 * numProp + UV_OFFSET];
|
|
54811
|
+
uvs[u2 + 3] = vertProperties[i1 * numProp + UV_OFFSET + 1];
|
|
54812
|
+
uvs[u2 + 4] = vertProperties[i2 * numProp + UV_OFFSET];
|
|
54813
|
+
uvs[u2 + 5] = vertProperties[i2 * numProp + UV_OFFSET + 1];
|
|
54814
|
+
}
|
|
53299
54815
|
if (useCornerNormals) {
|
|
53300
54816
|
for (let k2 = 0; k2 < 9; k2++) normals[o + k2] = cornerNormals[o + k2];
|
|
53301
54817
|
} else if (vertNormals) {
|
|
@@ -53308,13 +54824,13 @@ function computeGeometryArrays(mesh, options = {}) {
|
|
|
53308
54824
|
normals[o + 6] = vertNormals[i2 * 3];
|
|
53309
54825
|
normals[o + 7] = vertNormals[i2 * 3 + 1];
|
|
53310
54826
|
normals[o + 8] = vertNormals[i2 * 3 + 2];
|
|
53311
|
-
} else if (
|
|
54827
|
+
} else if (hasStoredNormals) {
|
|
53312
54828
|
const corners = [i0, i1, i2];
|
|
53313
54829
|
for (let v = 0; v < 3; v++) {
|
|
53314
54830
|
const base = corners[v] * numProp;
|
|
53315
|
-
const nx = vertProperties[base +
|
|
53316
|
-
const ny = vertProperties[base +
|
|
53317
|
-
const nz = vertProperties[base +
|
|
54831
|
+
const nx = vertProperties[base + NORMAL_OFFSET];
|
|
54832
|
+
const ny = vertProperties[base + NORMAL_OFFSET + 1];
|
|
54833
|
+
const nz = vertProperties[base + NORMAL_OFFSET + 2];
|
|
53318
54834
|
const oc = o + v * 3;
|
|
53319
54835
|
if (nx * nx + ny * ny + nz * nz > 1e-12) {
|
|
53320
54836
|
normals[oc] = nx;
|
|
@@ -53341,7 +54857,7 @@ function computeGeometryArrays(mesh, options = {}) {
|
|
|
53341
54857
|
faceNy[t] = fny;
|
|
53342
54858
|
faceNz[t] = fnz;
|
|
53343
54859
|
}
|
|
53344
|
-
if (!useCornerNormals && !vertNormals &&
|
|
54860
|
+
if (!useCornerNormals && !vertNormals && !hasStoredNormals && triCount > 0) {
|
|
53345
54861
|
computeAutoSmoothNormals(
|
|
53346
54862
|
triVerts,
|
|
53347
54863
|
vertProperties,
|
|
@@ -53360,7 +54876,8 @@ function computeGeometryArrays(mesh, options = {}) {
|
|
|
53360
54876
|
positions,
|
|
53361
54877
|
normals,
|
|
53362
54878
|
edgePositions,
|
|
53363
|
-
hasSmoothNormals: triCount > 0
|
|
54879
|
+
hasSmoothNormals: triCount > 0,
|
|
54880
|
+
uvs
|
|
53364
54881
|
};
|
|
53365
54882
|
}
|
|
53366
54883
|
function computeAutoSmoothNormals(triVerts, vertProperties, numProp, triCount, faceNx, faceNy, faceNz, normals, mergeFromVert, mergeToVert) {
|
|
@@ -53495,10 +55012,11 @@ function attachKernelFaceMetadata(geometry, triangleFaceIds, faceIdNames) {
|
|
|
53495
55012
|
}
|
|
53496
55013
|
function shapeToGeometry(shape) {
|
|
53497
55014
|
if (shape instanceof FrozenShape) {
|
|
53498
|
-
const { positions, normals, edgePositions, triangleFaceIds, faceIdNames, hasSmoothNormals } = shape.getPrecomputedGeometry();
|
|
55015
|
+
const { positions, normals, edgePositions, triangleFaceIds, faceIdNames, hasSmoothNormals, uvs } = shape.getPrecomputedGeometry();
|
|
53499
55016
|
const solid = new BufferGeometry();
|
|
53500
55017
|
solid.setAttribute("position", new BufferAttribute(positions, 3));
|
|
53501
55018
|
solid.setAttribute("normal", new BufferAttribute(normals, 3));
|
|
55019
|
+
if (uvs) solid.setAttribute("uv", new BufferAttribute(uvs, 2));
|
|
53502
55020
|
attachKernelFaceMetadata(solid, triangleFaceIds, faceIdNames);
|
|
53503
55021
|
const edges = new BufferGeometry();
|
|
53504
55022
|
edges.setAttribute("position", new BufferAttribute(edgePositions, 3));
|
|
@@ -53521,7 +55039,7 @@ function shapeToGeometryFallback(shape) {
|
|
|
53521
55039
|
} catch {
|
|
53522
55040
|
mesh = shape.getMesh();
|
|
53523
55041
|
}
|
|
53524
|
-
const { positions, normals, edgePositions, hasSmoothNormals } = computeGeometryArrays({
|
|
55042
|
+
const { positions, normals, edgePositions, hasSmoothNormals, uvs } = computeGeometryArrays({
|
|
53525
55043
|
numProp: mesh.numProp,
|
|
53526
55044
|
numTri: mesh.numTri,
|
|
53527
55045
|
triVerts: mesh.triVerts,
|
|
@@ -53534,6 +55052,7 @@ function shapeToGeometryFallback(shape) {
|
|
|
53534
55052
|
const solid = new BufferGeometry();
|
|
53535
55053
|
solid.setAttribute("position", new BufferAttribute(positions, 3));
|
|
53536
55054
|
solid.setAttribute("normal", new BufferAttribute(normals, 3));
|
|
55055
|
+
if (uvs) solid.setAttribute("uv", new BufferAttribute(uvs, 2));
|
|
53537
55056
|
attachKernelFaceMetadata(solid, mesh.faceID, mesh.faceIdNames);
|
|
53538
55057
|
const edges = new BufferGeometry();
|
|
53539
55058
|
edges.setAttribute("position", new BufferAttribute(edgePositions, 3));
|
|
@@ -53727,8 +55246,25 @@ function meshVertexColorBuffersFor(input, colorForEntryId) {
|
|
|
53727
55246
|
}
|
|
53728
55247
|
return out;
|
|
53729
55248
|
}
|
|
55249
|
+
const COLLISION_SOURCE_COLOR = [180, 200, 220];
|
|
55250
|
+
const COLLISION_HIGHLIGHT_COLOR = [255, 68, 16];
|
|
53730
55251
|
const FLOATING_HIGHLIGHT_COLOR = [255, 68, 16];
|
|
53731
55252
|
const FLOATING_HIDDEN_COLOR = [0, 0, 0];
|
|
55253
|
+
const FLOATING_CONTEXT_COLOR = [38, 49, 58];
|
|
55254
|
+
const COLLISION_PALETTE = [
|
|
55255
|
+
COLLISION_HIGHLIGHT_COLOR,
|
|
55256
|
+
[0, 204, 255],
|
|
55257
|
+
[255, 214, 0],
|
|
55258
|
+
[66, 220, 120],
|
|
55259
|
+
[255, 76, 196],
|
|
55260
|
+
[142, 106, 255],
|
|
55261
|
+
[255, 145, 48],
|
|
55262
|
+
[86, 232, 202],
|
|
55263
|
+
[210, 245, 60],
|
|
55264
|
+
[255, 120, 120],
|
|
55265
|
+
[80, 150, 255],
|
|
55266
|
+
[190, 110, 60]
|
|
55267
|
+
];
|
|
53732
55268
|
const MASK_PALETTE = [
|
|
53733
55269
|
[230, 25, 75],
|
|
53734
55270
|
[60, 180, 75],
|
|
@@ -53764,6 +55300,9 @@ function maskRgbForIndex(index2) {
|
|
|
53764
55300
|
function maskColorForIndex(index2) {
|
|
53765
55301
|
return rgbToHex(maskRgbForIndex(index2));
|
|
53766
55302
|
}
|
|
55303
|
+
function collisionColorForIndex(index2) {
|
|
55304
|
+
return rgbToHex(COLLISION_PALETTE[(index2 - 1) % COLLISION_PALETTE.length]);
|
|
55305
|
+
}
|
|
53767
55306
|
function lerp(a2, b, t) {
|
|
53768
55307
|
return a2 + (b - a2) * Math.max(0, Math.min(1, t));
|
|
53769
55308
|
}
|
|
@@ -53779,6 +55318,7 @@ function distanceColorForRootDistance(distance, maxDistance) {
|
|
|
53779
55318
|
}
|
|
53780
55319
|
const workerScope = self;
|
|
53781
55320
|
const SCALAR_SURFACE_VERTEX_CAP = 2e6;
|
|
55321
|
+
const SCALAR_SURFACE_TARGET_EDGE_SPACING_FACTOR = 8;
|
|
53782
55322
|
class EmptyIntersectionShape {
|
|
53783
55323
|
intersect() {
|
|
53784
55324
|
return {
|
|
@@ -53852,6 +55392,69 @@ function objectColorsFor(objects, input, colorByEntryId) {
|
|
|
53852
55392
|
})
|
|
53853
55393
|
);
|
|
53854
55394
|
}
|
|
55395
|
+
function countLabel(count, singular, plural) {
|
|
55396
|
+
return `${count} ${count === 1 ? singular : plural}`;
|
|
55397
|
+
}
|
|
55398
|
+
function componentBodyDetail(component) {
|
|
55399
|
+
if (component.objectCount === component.bodyCount) return countLabel(component.bodyCount, "body", "bodies");
|
|
55400
|
+
return `${countLabel(component.bodyCount, "body", "bodies")}, ${countLabel(component.objectCount, "object", "objects")}`;
|
|
55401
|
+
}
|
|
55402
|
+
function formatDistance(value) {
|
|
55403
|
+
if (!Number.isFinite(value)) return "unreachable";
|
|
55404
|
+
if (Math.abs(value) <= 1e-9) return "root";
|
|
55405
|
+
const fixed = Math.abs(value) < 10 ? value.toFixed(2) : value.toFixed(1);
|
|
55406
|
+
return `${fixed.replace(/\.?0+$/, "")} from root`;
|
|
55407
|
+
}
|
|
55408
|
+
function connectivityLegendSwatches(report) {
|
|
55409
|
+
return report.components.map(
|
|
55410
|
+
(component) => ({
|
|
55411
|
+
label: `Component ${component.index}`,
|
|
55412
|
+
detail: componentBodyDetail(component),
|
|
55413
|
+
color: maskColorForIndex(component.index - 1)
|
|
55414
|
+
})
|
|
55415
|
+
);
|
|
55416
|
+
}
|
|
55417
|
+
function distanceLegendSwatches(report) {
|
|
55418
|
+
return report.components.map(
|
|
55419
|
+
(component) => ({
|
|
55420
|
+
label: component.isRoot ? `Root ${component.index}` : `Component ${component.index}`,
|
|
55421
|
+
detail: `${componentBodyDetail(component)}, ${formatDistance(component.rootDistance)}`,
|
|
55422
|
+
color: distanceColorForRootDistance(component.rootDistance, report.maxRootDistance)
|
|
55423
|
+
})
|
|
55424
|
+
);
|
|
55425
|
+
}
|
|
55426
|
+
function floatingLegendSwatches(report) {
|
|
55427
|
+
const bodyCount = report.components.reduce((total, component) => total + component.bodyCount, 0);
|
|
55428
|
+
const groundedBodyCount = Math.max(0, bodyCount - report.floatingBodyCount);
|
|
55429
|
+
return [
|
|
55430
|
+
{
|
|
55431
|
+
label: "Floating",
|
|
55432
|
+
detail: countLabel(report.floatingBodyCount, "body", "bodies"),
|
|
55433
|
+
color: rgbToHex(FLOATING_HIGHLIGHT_COLOR)
|
|
55434
|
+
},
|
|
55435
|
+
{
|
|
55436
|
+
label: "Context",
|
|
55437
|
+
detail: countLabel(groundedBodyCount, "grounded body", "grounded bodies"),
|
|
55438
|
+
color: rgbToHex(FLOATING_CONTEXT_COLOR)
|
|
55439
|
+
}
|
|
55440
|
+
];
|
|
55441
|
+
}
|
|
55442
|
+
function collisionLegendSwatches(collisions) {
|
|
55443
|
+
return [
|
|
55444
|
+
...collisions.map(
|
|
55445
|
+
(collision) => ({
|
|
55446
|
+
label: `Overlap ${collision.index}`,
|
|
55447
|
+
detail: `${collision.sourceName} vs ${collision.targetName}`,
|
|
55448
|
+
color: collisionColorForIndex(collision.index)
|
|
55449
|
+
})
|
|
55450
|
+
),
|
|
55451
|
+
{
|
|
55452
|
+
label: "Ghost body",
|
|
55453
|
+
detail: "source geometry",
|
|
55454
|
+
color: rgbToHex(COLLISION_SOURCE_COLOR)
|
|
55455
|
+
}
|
|
55456
|
+
];
|
|
55457
|
+
}
|
|
53855
55458
|
function scalarSamplesFromPointSamples(pointSamples) {
|
|
53856
55459
|
const finite = pointSamples.filter((sample) => sample.value != null && Number.isFinite(sample.value));
|
|
53857
55460
|
const positions = new Float32Array(finite.length * 3);
|
|
@@ -53887,7 +55490,10 @@ function analyzeScalarChannel(request) {
|
|
|
53887
55490
|
});
|
|
53888
55491
|
const samples = scalarSamplesFromPointSamples(analysis.pointSamples);
|
|
53889
55492
|
if (samples.values.length > 0) {
|
|
53890
|
-
const field2 = reconstructSurfaceScalarField(object.positions, samples, {
|
|
55493
|
+
const field2 = reconstructSurfaceScalarField(object.positions, samples, {
|
|
55494
|
+
vertexCap: SCALAR_SURFACE_VERTEX_CAP,
|
|
55495
|
+
targetEdgeSpacingFactor: SCALAR_SURFACE_TARGET_EDGE_SPACING_FACTOR
|
|
55496
|
+
});
|
|
53891
55497
|
const bvhGeometry = new BufferGeometry();
|
|
53892
55498
|
bvhGeometry.setAttribute("position", new BufferAttribute(field2.positions, 3));
|
|
53893
55499
|
bvhGeometry.setIndex(new BufferAttribute(field2.index, 1));
|
|
@@ -53937,6 +55543,7 @@ function analyzeScalarChannel(request) {
|
|
|
53937
55543
|
meshColorObjects: [],
|
|
53938
55544
|
scalarSurfaceObjects,
|
|
53939
55545
|
collisionGeometryObjects: [],
|
|
55546
|
+
legendSwatches: [],
|
|
53940
55547
|
warnings
|
|
53941
55548
|
};
|
|
53942
55549
|
}
|
|
@@ -53968,6 +55575,7 @@ function analyzeConnectivityChannel(request) {
|
|
|
53968
55575
|
meshColorObjects: meshColorObjectsFor(bodyInput, colorByEntryId2),
|
|
53969
55576
|
scalarSurfaceObjects: [],
|
|
53970
55577
|
collisionGeometryObjects: [],
|
|
55578
|
+
legendSwatches: distanceLegendSwatches(report2),
|
|
53971
55579
|
warnings: report2.warnings
|
|
53972
55580
|
};
|
|
53973
55581
|
}
|
|
@@ -53983,6 +55591,7 @@ function analyzeConnectivityChannel(request) {
|
|
|
53983
55591
|
meshColorObjects: meshColorObjectsFor(bodyInput, colorByEntryId2),
|
|
53984
55592
|
scalarSurfaceObjects: [],
|
|
53985
55593
|
collisionGeometryObjects: [],
|
|
55594
|
+
legendSwatches: floatingLegendSwatches(report2),
|
|
53986
55595
|
warnings: report2.warnings
|
|
53987
55596
|
};
|
|
53988
55597
|
}
|
|
@@ -53995,6 +55604,7 @@ function analyzeConnectivityChannel(request) {
|
|
|
53995
55604
|
meshColorObjects: meshColorObjectsFor(bodyInput, colorByEntryId),
|
|
53996
55605
|
scalarSurfaceObjects: [],
|
|
53997
55606
|
collisionGeometryObjects: [],
|
|
55607
|
+
legendSwatches: connectivityLegendSwatches(report),
|
|
53998
55608
|
warnings: report.warnings
|
|
53999
55609
|
};
|
|
54000
55610
|
}
|
|
@@ -54101,6 +55711,7 @@ function analyzeCollisionChannel(request) {
|
|
|
54101
55711
|
meshColorObjects: [],
|
|
54102
55712
|
scalarSurfaceObjects: [],
|
|
54103
55713
|
collisionGeometryObjects,
|
|
55714
|
+
legendSwatches: collisionLegendSwatches(collisionGeometryObjects),
|
|
54104
55715
|
warnings: [...request.warnings ?? [], ...report.warnings]
|
|
54105
55716
|
};
|
|
54106
55717
|
}
|