@woosh/meep-engine 2.33.36 → 2.33.40
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/core/bvh2/binary/2/BinaryUint32BVH.js +3 -3
- package/core/collection/HashMap.js +19 -12
- package/core/collection/array/typed/typed_array_copy.js +2 -2
- package/core/collection/table/RowFirstTable.js +13 -8
- package/core/collection/table/RowFirstTableSpec.js +6 -0
- package/core/color/Color.js +5 -9
- package/core/color/ColorUtils.js +4 -150
- package/core/color/YCbCr_to_rgb_uint24.js +20 -0
- package/core/color/hsv2rgb.js +54 -0
- package/core/color/int2rgb.js +12 -0
- package/core/color/parseHex.js +18 -0
- package/core/color/rgb2hex.js +16 -0
- package/core/color/rgb2hsv.js +47 -0
- package/core/color/rgb2uint24.js +17 -0
- package/core/color/rgb_to_YCbCr_uint24.js +18 -0
- package/core/geom/3d/aabb/aabb3_matrix4_project_by_corners.js +1 -1
- package/core/geom/3d/aabb/compute_aabb_from_points.js +28 -0
- package/core/geom/3d/morton/mortonEncode_magicbits.js +7 -6
- package/core/geom/3d/morton/v3_morton_encode_transformed.js +15 -11
- package/core/geom/3d/plane/orient3d_fast.js +51 -0
- package/core/geom/3d/plane/plane_computeConvex3PlaneIntersection.js +5 -0
- package/core/geom/3d/tetrahedra/GetDepthForTetrahedronProbe.glsl +43 -0
- package/core/geom/3d/tetrahedra/compute_bounding_simplex_3d.js +177 -0
- package/core/geom/3d/tetrahedra/compute_bounding_simplex_3d.spec.js +66 -0
- package/core/geom/3d/tetrahedra/compute_circumsphere.js +271 -0
- package/core/geom/3d/tetrahedra/compute_delaunay_tetrahedral_mesh.js +50 -0
- package/core/geom/3d/tetrahedra/compute_delaunay_tetrahedral_mesh.spec.js +14 -0
- package/core/geom/3d/tetrahedra/point_in_tetrahedron_circumsphere.js +77 -0
- package/core/geom/3d/tetrahedra/tetrahedra_collection.js +454 -0
- package/core/geom/3d/tetrahedra/tetrahedron_contains_point.js +26 -0
- package/core/geom/Quaternion.js +4 -0
- package/core/math/hash/murmur3_32.js +39 -0
- package/core/process/undo/ActionProcessor.d.ts +2 -0
- package/core/process/undo/ActionProcessor.js +15 -4
- package/editor/tools/FoliagePaintTool.js +1 -1
- package/editor/tools/GridPaintTool.js +1 -1
- package/engine/asset/loaders/GLTFAssetLoader.js +4 -8
- package/engine/ecs/System.d.ts +24 -1
- package/engine/ecs/foliage/InstancedFoliage.js +45 -0
- package/engine/ecs/foliage/ecs/InstancedMeshLayer.js +4 -0
- package/engine/ecs/storage/BinaryBufferSerializer.js +48 -38
- package/engine/ecs/storage/binary/collection/BinaryCollectionSerializer.js +1 -1
- package/engine/ecs/terrain/ecs/splat/SplatMapOptimizerDebugger.js +1 -1
- package/engine/ecs/terrain/tiles/TerrainTile.js +1 -1
- package/engine/graphics/GraphicsEngine.js +7 -0
- package/engine/graphics/ecs/light/binding/fp/FPLightBinding.js +1 -1
- package/engine/graphics/ecs/mesh/Mesh.js +2 -2
- package/engine/graphics/ecs/mesh-v2/ShadedGeometry.js +13 -0
- package/engine/graphics/geometry/instancing/InstancedMeshGroup.js +339 -314
- package/engine/graphics/micron/prototypeVirtualGeometry.js +4 -1
- package/engine/graphics/micron/render/v1/VGThreeRenderer.js +6 -2
- package/engine/graphics/particles/node-based/rendering/billboard/ParticleBillboardShader.js +1 -1
- package/engine/graphics/particles/particular/engine/parameter/ParameterLookupTable.js +20 -24
- package/engine/graphics/particles/particular/engine/renderers/billboard/ParticleBillboardMaterial.js +100 -55
- package/engine/graphics/particles/particular/engine/shader/ShaderManager.js +7 -2
- package/engine/graphics/particles/particular/engine/utils/volume/ParticleVolume.js +1 -0
- package/engine/graphics/particles/particular/engine/utils/volume/prototypeParticleVolume.js +2 -2
- package/engine/graphics/render/buffer/simple-fx/DepthLimitedBlur.js +9 -4
- package/engine/graphics/render/buffer/simple-fx/ao/AmbientOcclusionPostProcessEffect.js +7 -1
- package/engine/graphics/render/forward_plus/LightManager.js +295 -51
- package/engine/graphics/render/forward_plus/LightManager.spec.js +1 -1
- package/engine/graphics/render/forward_plus/PointLightData.js +9 -13
- package/engine/graphics/render/forward_plus/cluster/compute_light_data_hash_0.js +1 -1
- package/engine/graphics/render/forward_plus/data/TextureBackedMemoryRegion.js +10 -1
- package/engine/graphics/render/forward_plus/debug/LightClusterVolumeMaterial.js +1 -1
- package/engine/graphics/render/forward_plus/debug/buildLightClusterWidget.js +3 -1
- package/engine/graphics/render/forward_plus/materials/FP_SHADER_CHUNK_ACCUMULATION.js +31 -18
- package/engine/graphics/render/forward_plus/materials/fp_build_fragment_shader.js +18 -4
- package/engine/graphics/render/forward_plus/model/AbstractLight.js +50 -0
- package/engine/graphics/render/forward_plus/model/Decal.js +68 -0
- package/engine/graphics/render/forward_plus/{PointLight.js → model/PointLight.js} +19 -11
- package/engine/graphics/render/forward_plus/{SpotLight.js → model/SpotLight.js} +20 -12
- package/engine/graphics/render/forward_plus/plugin/ForwardPlusRenderingPlugin.js +1 -1
- package/engine/graphics/render/forward_plus/plugin/ptototypeFPPlugin.js +6 -5
- package/engine/graphics/render/forward_plus/{prototypeLightManager.js → prototype/prototypeLightManager.js} +100 -25
- package/engine/graphics/render/forward_plus/query/query_bvh_frustum_from_texture.js +29 -20
- package/engine/graphics/render/visibility/IncrementalDeltaSet.d.ts +2 -0
- package/engine/graphics/render/visibility/IncrementalDeltaSet.js +1 -0
- package/engine/graphics/render/visibility/VisibilityComputer.js +8 -7
- package/engine/graphics/shaders/TerrainShader.js +5 -5
- package/engine/graphics/shadows/testShadowMapRendering.js +192 -0
- package/engine/graphics/texture/atlas/AbstractTextureAtlas.js +19 -0
- package/engine/graphics/texture/atlas/CachingTextureAtlas.js +99 -0
- package/engine/graphics/texture/atlas/ManagedTextureAtlas.js +19 -39
- package/engine/graphics/texture/atlas/ReferencedTextureAtlas.js +75 -0
- package/engine/graphics/texture/atlas/TextureAtlas.js +22 -2
- package/engine/reference/v2/Reference.d.ts +4 -0
- package/engine/reference/v2/Reference.js +3 -1
- package/package.json +2 -1
- package/view/elements/ColorPickerView.js +2 -1
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { mortonEncode_magicbits } from "./mortonEncode_magicbits.js";
|
|
2
|
+
import { clamp } from "../../../math/clamp.js";
|
|
2
3
|
|
|
3
4
|
/**
|
|
4
5
|
* Assumes that coordinates will be mapped to -1..1 range after transform
|
|
@@ -16,18 +17,21 @@ export function v3_morton_encode_transformed(x, y, z, matrix) {
|
|
|
16
17
|
const _z = matrix[2] * x + matrix[6] * y + matrix[10] * z + matrix[14];
|
|
17
18
|
const _w = matrix[3] * x + matrix[7] * y + matrix[11] * z + matrix[15];
|
|
18
19
|
|
|
19
|
-
const d =
|
|
20
|
+
const d = 511.5 / _w;
|
|
20
21
|
|
|
21
|
-
// apply perspective divide
|
|
22
|
-
const
|
|
23
|
-
const
|
|
24
|
-
const
|
|
22
|
+
// apply perspective divide as well as scaling to 10 bits
|
|
23
|
+
const ndc_x = _x * d;
|
|
24
|
+
const ndc_y = _y * d;
|
|
25
|
+
const ndc_z = _z * d;
|
|
25
26
|
|
|
26
|
-
//
|
|
27
|
+
// Normalize values (0,1023) and clamp to prevent wrapping
|
|
28
|
+
const px = clamp(ndc_x + 511.5, 0, 1023);
|
|
29
|
+
const py = clamp(ndc_y + 511.5, 0, 1023);
|
|
30
|
+
const pz = clamp(ndc_z + 511.5, 0, 1023);
|
|
27
31
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
32
|
+
return mortonEncode_magicbits(
|
|
33
|
+
Math.round(px),
|
|
34
|
+
Math.round(py),
|
|
35
|
+
Math.round(pz)
|
|
36
|
+
);
|
|
33
37
|
}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Return a positive value if the point pd lies below the
|
|
3
|
+
* plane passing through pa, pb, and pc; "below" is defined so
|
|
4
|
+
* that pa, pb, and pc appear in counterclockwise order when
|
|
5
|
+
* viewed from above the plane. Returns a negative value if
|
|
6
|
+
* pd lies above the plane. Returns zero if the points are
|
|
7
|
+
* coplanar. The result is also a rough approximation of six
|
|
8
|
+
* times the signed volume of the tetrahedron defined by the
|
|
9
|
+
* four points.
|
|
10
|
+
*
|
|
11
|
+
* NOTE: ported from http://www.cs.cmu.edu/afs/cs/project/quake/public/code/predicates.c
|
|
12
|
+
*
|
|
13
|
+
* @param {number[]} points
|
|
14
|
+
* @param {number} a index of point a
|
|
15
|
+
* @param {number} b index of point b
|
|
16
|
+
* @param {number} c index of point c
|
|
17
|
+
* @param {number} d index of point d
|
|
18
|
+
* @returns {number}
|
|
19
|
+
*/
|
|
20
|
+
export function orient3d_fast(points, a, b, c, d) {
|
|
21
|
+
const a3 = a * 3;
|
|
22
|
+
const d3 = d * 3;
|
|
23
|
+
|
|
24
|
+
const d_x = points[d3];
|
|
25
|
+
|
|
26
|
+
const adx = points[a3] - d_x;
|
|
27
|
+
|
|
28
|
+
const b3 = b * 3;
|
|
29
|
+
|
|
30
|
+
const bdx = points[b3] - d_x;
|
|
31
|
+
|
|
32
|
+
const c3 = c * 3;
|
|
33
|
+
|
|
34
|
+
const cdx = points[c3] - d_x;
|
|
35
|
+
|
|
36
|
+
const d_y = points[d3 + 1];
|
|
37
|
+
|
|
38
|
+
const ady = points[a3 + 1] - d_y;
|
|
39
|
+
const bdy = points[b3 + 1] - d_y;
|
|
40
|
+
const cdy = points[c3 + 1] - d_y;
|
|
41
|
+
|
|
42
|
+
const d_z = points[d3 + 2];
|
|
43
|
+
|
|
44
|
+
const adz = points[a3 + 2] - d_z;
|
|
45
|
+
const bdz = points[b3 + 2] - d_z;
|
|
46
|
+
const cdz = points[c3 + 2] - d_z;
|
|
47
|
+
|
|
48
|
+
return adx * (bdy * cdz - bdz * cdy)
|
|
49
|
+
+ bdx * (cdy * adz - cdz * ady)
|
|
50
|
+
+ cdx * (ady * bdz - adz * bdy);
|
|
51
|
+
}
|
|
@@ -24,7 +24,12 @@ export function plane_three_computeConvex3PlaneIntersection(result, result_offse
|
|
|
24
24
|
}
|
|
25
25
|
|
|
26
26
|
/**
|
|
27
|
+
* Given 3 planes, compute point of their intersection.
|
|
28
|
+
* This only works when the planes are "convex", that is - no two planes are parallel.
|
|
29
|
+
* Simply put - intersection must exist to be found.
|
|
30
|
+
*
|
|
27
31
|
* NOTE: Based on Intersection of 3 planes, Graphics Gems 1 pg 305
|
|
32
|
+
*
|
|
28
33
|
* @param {Float32Array|number[]|vec3} result
|
|
29
34
|
* @param {number} result_offset
|
|
30
35
|
* @param {number} a_normal_x
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
// Sample triangular depth map
|
|
2
|
+
// see CoD SIGGRAPH 2017 "Advances in Real-Time Graphics in Games" course
|
|
3
|
+
float GetDepthForTetrahedronProbe(float2 bary, uint4 encodedDepth)
|
|
4
|
+
{
|
|
5
|
+
float sampleY = floor(bary.y * 4.0f);
|
|
6
|
+
float sampleX = floor(bary.x * 4.0f);
|
|
7
|
+
|
|
8
|
+
int baseIndex = (int)(((11.0f - sampleY) * sampleY) * 0.5f + sampleX + 0.5f);
|
|
9
|
+
int lineLength = 5 - (int)sampleY;
|
|
10
|
+
|
|
11
|
+
float2 baseBary = float2(sampleX * 0.25f, sampleY * 0.25f);
|
|
12
|
+
|
|
13
|
+
int3 indices = int3(baseIndex + 1, baseIndex + lineLength, baseIndex);
|
|
14
|
+
|
|
15
|
+
float3 sampleBary;
|
|
16
|
+
sampleBary.x = (bary.x - baseBary.x) * 4.0f;
|
|
17
|
+
sampleBary.y = (bary.y - baseBary.y) * 4.0f;
|
|
18
|
+
|
|
19
|
+
if (sampleBary.x + sampleBary.y > 1.0f)
|
|
20
|
+
{
|
|
21
|
+
// above the diagonal
|
|
22
|
+
indices = int3(baseIndex + lineLength, baseIndex + 1, baseIndex + lineLength + 1);
|
|
23
|
+
|
|
24
|
+
float3 newSampleBary;
|
|
25
|
+
newSampleBary.x = -(sampleBary.y - 1.0f);
|
|
26
|
+
newSampleBary.y = -(sampleBary.x - 1.0f);
|
|
27
|
+
sampleBary = newSampleBary;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
sampleBary.z = 1.0f - sampleBary.x - sampleBary.y;
|
|
31
|
+
|
|
32
|
+
float result = 0.0f;
|
|
33
|
+
for (int i=0; i<3; ++i)
|
|
34
|
+
{
|
|
35
|
+
uint currIndex = indices[i];
|
|
36
|
+
int intDepth = (encodedDepth[currIndex / 4] >> ((currIndex % 4) * 8)) & 0xFF;
|
|
37
|
+
float depth = (float)intDepth / 255.0f;
|
|
38
|
+
|
|
39
|
+
result += sampleBary[i] * depth;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
return result;
|
|
43
|
+
}
|
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
import { v3_dot } from "../../v3_dot.js";
|
|
2
|
+
import { min2 } from "../../../math/min2.js";
|
|
3
|
+
import { max2 } from "../../../math/max2.js";
|
|
4
|
+
import { plane_computeConvex3PlaneIntersection } from "../plane/plane_computeConvex3PlaneIntersection.js";
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Planes used to bound the simplex
|
|
8
|
+
* NOTE: these might be computed for a given set of points instead, to produce a tighter fit, but this was good enough for my needs so far
|
|
9
|
+
*
|
|
10
|
+
* @readonly
|
|
11
|
+
* @type {Float32Array}
|
|
12
|
+
*/
|
|
13
|
+
const SIMPLEX_PROJECTION_AXES = new Float32Array([
|
|
14
|
+
Math.sqrt(8 / 9), 0, -1 / 3.,
|
|
15
|
+
-Math.sqrt(2 / 9), Math.sqrt(2 / 3), -1 / 3,
|
|
16
|
+
-Math.sqrt(2 / 9), -Math.sqrt(2 / 3), -1 / 3,
|
|
17
|
+
0, 0, 1
|
|
18
|
+
]);
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Compute bounding tetrahedron (3d simplex) for a given set of input points
|
|
22
|
+
*
|
|
23
|
+
* @see https://github.com/bryanmcnett/aabo/blob/master/aabo.cpp
|
|
24
|
+
* @author Alexander Goldring (c) 2021
|
|
25
|
+
*
|
|
26
|
+
* @param {number[]|Float32Array|Float64Array} result
|
|
27
|
+
* @param {number} result_offset
|
|
28
|
+
* @param {number[]|Float32Array|Float64Array} input
|
|
29
|
+
* @param {number} input_count
|
|
30
|
+
* @param {number} padding Planar offset for each of the simple sides, positive padding value will create a larger simplex. Useful for ensuring that input points do not lie directly on the simplex planes
|
|
31
|
+
*/
|
|
32
|
+
export function compute_bounding_simplex_3d(
|
|
33
|
+
result,
|
|
34
|
+
result_offset,
|
|
35
|
+
input,
|
|
36
|
+
input_count,
|
|
37
|
+
padding
|
|
38
|
+
) {
|
|
39
|
+
if (input_count <= 0) {
|
|
40
|
+
// no inputs
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// initialize
|
|
45
|
+
let x = input[0];
|
|
46
|
+
let y = input[1];
|
|
47
|
+
let z = input[2];
|
|
48
|
+
|
|
49
|
+
let a = v3_dot(
|
|
50
|
+
x,
|
|
51
|
+
y,
|
|
52
|
+
z,
|
|
53
|
+
SIMPLEX_PROJECTION_AXES[0],
|
|
54
|
+
SIMPLEX_PROJECTION_AXES[1],
|
|
55
|
+
SIMPLEX_PROJECTION_AXES[2],
|
|
56
|
+
);
|
|
57
|
+
let b = v3_dot(
|
|
58
|
+
x,
|
|
59
|
+
y,
|
|
60
|
+
z,
|
|
61
|
+
SIMPLEX_PROJECTION_AXES[3],
|
|
62
|
+
SIMPLEX_PROJECTION_AXES[4],
|
|
63
|
+
SIMPLEX_PROJECTION_AXES[5],
|
|
64
|
+
);
|
|
65
|
+
let c = v3_dot(
|
|
66
|
+
x,
|
|
67
|
+
y,
|
|
68
|
+
z,
|
|
69
|
+
SIMPLEX_PROJECTION_AXES[6],
|
|
70
|
+
SIMPLEX_PROJECTION_AXES[7],
|
|
71
|
+
SIMPLEX_PROJECTION_AXES[8],
|
|
72
|
+
);
|
|
73
|
+
let d = v3_dot(
|
|
74
|
+
x,
|
|
75
|
+
y,
|
|
76
|
+
z,
|
|
77
|
+
SIMPLEX_PROJECTION_AXES[9],
|
|
78
|
+
SIMPLEX_PROJECTION_AXES[10],
|
|
79
|
+
SIMPLEX_PROJECTION_AXES[11],
|
|
80
|
+
);
|
|
81
|
+
|
|
82
|
+
let min_a = a;
|
|
83
|
+
let min_b = b;
|
|
84
|
+
let min_c = c;
|
|
85
|
+
let min_d = d;
|
|
86
|
+
|
|
87
|
+
let max_a = a;
|
|
88
|
+
let max_b = b;
|
|
89
|
+
let max_c = c;
|
|
90
|
+
let max_d = d;
|
|
91
|
+
|
|
92
|
+
for (let i = 1; i < input_count; i++) {
|
|
93
|
+
|
|
94
|
+
const i3 = i * 3;
|
|
95
|
+
|
|
96
|
+
x = input[i3];
|
|
97
|
+
y = input[i3 + 1];
|
|
98
|
+
z = input[i3 + 2];
|
|
99
|
+
|
|
100
|
+
a = v3_dot(
|
|
101
|
+
x,
|
|
102
|
+
y,
|
|
103
|
+
z,
|
|
104
|
+
SIMPLEX_PROJECTION_AXES[0],
|
|
105
|
+
SIMPLEX_PROJECTION_AXES[1],
|
|
106
|
+
SIMPLEX_PROJECTION_AXES[2],
|
|
107
|
+
);
|
|
108
|
+
b = v3_dot(
|
|
109
|
+
x,
|
|
110
|
+
y,
|
|
111
|
+
z,
|
|
112
|
+
SIMPLEX_PROJECTION_AXES[3],
|
|
113
|
+
SIMPLEX_PROJECTION_AXES[4],
|
|
114
|
+
SIMPLEX_PROJECTION_AXES[5],
|
|
115
|
+
);
|
|
116
|
+
c = v3_dot(
|
|
117
|
+
x,
|
|
118
|
+
y,
|
|
119
|
+
z,
|
|
120
|
+
SIMPLEX_PROJECTION_AXES[6],
|
|
121
|
+
SIMPLEX_PROJECTION_AXES[7],
|
|
122
|
+
SIMPLEX_PROJECTION_AXES[8],
|
|
123
|
+
);
|
|
124
|
+
d = v3_dot(
|
|
125
|
+
x,
|
|
126
|
+
y,
|
|
127
|
+
z,
|
|
128
|
+
SIMPLEX_PROJECTION_AXES[9],
|
|
129
|
+
SIMPLEX_PROJECTION_AXES[10],
|
|
130
|
+
SIMPLEX_PROJECTION_AXES[11],
|
|
131
|
+
);
|
|
132
|
+
|
|
133
|
+
min_a = min2(min_a, a);
|
|
134
|
+
min_b = min2(min_b, b);
|
|
135
|
+
min_c = min2(min_c, c);
|
|
136
|
+
min_d = min2(min_d, d);
|
|
137
|
+
|
|
138
|
+
max_a = max2(max_a, a);
|
|
139
|
+
max_b = max2(max_b, b);
|
|
140
|
+
max_c = max2(max_c, c);
|
|
141
|
+
max_d = max2(max_d, d);
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
// we now have the planar offset for each projection axis
|
|
145
|
+
|
|
146
|
+
// apply padding offset
|
|
147
|
+
min_a -= padding;
|
|
148
|
+
min_b -= padding;
|
|
149
|
+
min_c -= padding;
|
|
150
|
+
min_d -= padding;
|
|
151
|
+
|
|
152
|
+
// lets compute intersection points for each tri-plane combination to find simplex corners
|
|
153
|
+
plane_computeConvex3PlaneIntersection(
|
|
154
|
+
result, result_offset,
|
|
155
|
+
SIMPLEX_PROJECTION_AXES[0], SIMPLEX_PROJECTION_AXES[1], SIMPLEX_PROJECTION_AXES[2], -min_a,
|
|
156
|
+
SIMPLEX_PROJECTION_AXES[3], SIMPLEX_PROJECTION_AXES[4], SIMPLEX_PROJECTION_AXES[5], -min_b,
|
|
157
|
+
SIMPLEX_PROJECTION_AXES[6], SIMPLEX_PROJECTION_AXES[7], SIMPLEX_PROJECTION_AXES[8], -min_c
|
|
158
|
+
);
|
|
159
|
+
plane_computeConvex3PlaneIntersection(
|
|
160
|
+
result, result_offset + 3,
|
|
161
|
+
SIMPLEX_PROJECTION_AXES[3], SIMPLEX_PROJECTION_AXES[4], SIMPLEX_PROJECTION_AXES[5], -min_b,
|
|
162
|
+
SIMPLEX_PROJECTION_AXES[6], SIMPLEX_PROJECTION_AXES[7], SIMPLEX_PROJECTION_AXES[8], -min_c,
|
|
163
|
+
SIMPLEX_PROJECTION_AXES[9], SIMPLEX_PROJECTION_AXES[10], SIMPLEX_PROJECTION_AXES[11], -min_d
|
|
164
|
+
);
|
|
165
|
+
plane_computeConvex3PlaneIntersection(
|
|
166
|
+
result, result_offset + 6,
|
|
167
|
+
SIMPLEX_PROJECTION_AXES[0], SIMPLEX_PROJECTION_AXES[1], SIMPLEX_PROJECTION_AXES[2], -min_a,
|
|
168
|
+
SIMPLEX_PROJECTION_AXES[3], SIMPLEX_PROJECTION_AXES[4], SIMPLEX_PROJECTION_AXES[5], -min_b,
|
|
169
|
+
SIMPLEX_PROJECTION_AXES[9], SIMPLEX_PROJECTION_AXES[10], SIMPLEX_PROJECTION_AXES[11], -min_d
|
|
170
|
+
);
|
|
171
|
+
plane_computeConvex3PlaneIntersection(
|
|
172
|
+
result, result_offset + 9,
|
|
173
|
+
SIMPLEX_PROJECTION_AXES[6], SIMPLEX_PROJECTION_AXES[7], SIMPLEX_PROJECTION_AXES[8], -min_c,
|
|
174
|
+
SIMPLEX_PROJECTION_AXES[0], SIMPLEX_PROJECTION_AXES[1], SIMPLEX_PROJECTION_AXES[2], -min_a,
|
|
175
|
+
SIMPLEX_PROJECTION_AXES[9], SIMPLEX_PROJECTION_AXES[10], SIMPLEX_PROJECTION_AXES[11], -min_d
|
|
176
|
+
);
|
|
177
|
+
}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import { compute_bounding_simplex_3d } from "./compute_bounding_simplex_3d.js";
|
|
2
|
+
import { v3_distance } from "../../v3_distance.js";
|
|
3
|
+
import { orient3d_fast } from "../plane/orient3d_fast.js";
|
|
4
|
+
|
|
5
|
+
test('one point', () => {
|
|
6
|
+
const r = [];
|
|
7
|
+
compute_bounding_simplex_3d(r, 0, [1, 2, 3], 1, 0);
|
|
8
|
+
|
|
9
|
+
for (let i = 0; i < 4; i++) {
|
|
10
|
+
const i3 = i * 3;
|
|
11
|
+
|
|
12
|
+
expect(r[i3]).toBeCloseTo(1);
|
|
13
|
+
expect(r[i3 + 1]).toBeCloseTo(2);
|
|
14
|
+
expect(r[i3 + 2]).toBeCloseTo(3);
|
|
15
|
+
}
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
test('planar containment, one point', () => {
|
|
19
|
+
const r = [];
|
|
20
|
+
|
|
21
|
+
compute_bounding_simplex_3d(r, 0, [0, 0, 0], 1, 1);
|
|
22
|
+
|
|
23
|
+
r.push(0, 0, 0);
|
|
24
|
+
|
|
25
|
+
expect(orient3d_fast(r, 1, 3, 2, 4)).toBeLessThan(0);
|
|
26
|
+
expect(orient3d_fast(r, 2, 3, 0, 4)).toBeLessThan(0);
|
|
27
|
+
expect(orient3d_fast(r, 3, 1, 0, 4)).toBeLessThan(0);
|
|
28
|
+
expect(orient3d_fast(r, 0, 1, 2, 4)).toBeLessThan(0);
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
test('positive padding results in larger simplex', () => {
|
|
32
|
+
const r_0 = [];
|
|
33
|
+
const r_n = [];
|
|
34
|
+
const r_p = [];
|
|
35
|
+
|
|
36
|
+
const volume = [
|
|
37
|
+
-100, 0, 0,
|
|
38
|
+
100, 0, 0,
|
|
39
|
+
0, -100, 0,
|
|
40
|
+
0, 100, 0,
|
|
41
|
+
0, 0, -100,
|
|
42
|
+
0, 0, 100,
|
|
43
|
+
];
|
|
44
|
+
|
|
45
|
+
compute_bounding_simplex_3d(r_0, 0, volume, 6, 0);
|
|
46
|
+
compute_bounding_simplex_3d(r_n, 0, volume, 6, -1);
|
|
47
|
+
compute_bounding_simplex_3d(r_p, 0, volume, 6, 1);
|
|
48
|
+
|
|
49
|
+
function compute_distance_sum(ref, points, point_count) {
|
|
50
|
+
let r = 0;
|
|
51
|
+
for (let i = 0; i < point_count; i++) {
|
|
52
|
+
const i3 = i * 3;
|
|
53
|
+
|
|
54
|
+
r += v3_distance(points[i3], points[i3 + 1], points[i3 + 2], ref[0], ref[1], ref[2]);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
return r;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
const d_0 = compute_distance_sum([0, 0, 0], r_0, 4);
|
|
61
|
+
const d_n = compute_distance_sum([0, 0, 0], r_n, 4);
|
|
62
|
+
const d_p = compute_distance_sum([0, 0, 0], r_p, 4);
|
|
63
|
+
|
|
64
|
+
expect(d_0).toBeLessThan(d_p);
|
|
65
|
+
expect(d_0).toBeGreaterThan(d_n);
|
|
66
|
+
});
|
|
@@ -0,0 +1,271 @@
|
|
|
1
|
+
import { array_copy } from "../../../collection/array/copyArray.js";
|
|
2
|
+
import { v3_dot } from "../../v3_dot.js";
|
|
3
|
+
|
|
4
|
+
const MAX_FLOAT32 = 3.4028234663852886e+38;
|
|
5
|
+
const SMALL_NUMBER = 1e-12;
|
|
6
|
+
const VTK_MAX_WARNS = 3;
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Compute the circumcenter (center[3]) and radius squared (method
|
|
10
|
+
* return value) of a tetrahedron defined by the four points x1, x2,
|
|
11
|
+
* x3, and x4.
|
|
12
|
+
*
|
|
13
|
+
* @see https://github.com/Kitware/VTK/blob/ac3fd8005bce7b3da4423c305f61ffd9df9695ef/Common/DataModel/vtkTetra.cxx
|
|
14
|
+
* @param {number[]} result [center_x, center_y, center_z, radius_squared]
|
|
15
|
+
* @param {number[]} points
|
|
16
|
+
* @param {number} a
|
|
17
|
+
* @param {number} b
|
|
18
|
+
* @param {number} c
|
|
19
|
+
* @param {number} d
|
|
20
|
+
*/
|
|
21
|
+
export function compute_circumsphere(
|
|
22
|
+
result,
|
|
23
|
+
points,
|
|
24
|
+
a, b, c, d
|
|
25
|
+
) {
|
|
26
|
+
const n12 = [];
|
|
27
|
+
const n13 = [];
|
|
28
|
+
const n14 = [];
|
|
29
|
+
|
|
30
|
+
const x12 = [];
|
|
31
|
+
const x13 = [];
|
|
32
|
+
const x14 = [];
|
|
33
|
+
|
|
34
|
+
// calculate normals and intersection points of bisecting planes.
|
|
35
|
+
for (let i = 0; i < 3; i++) {
|
|
36
|
+
const v_a = points[a * 3 + i];
|
|
37
|
+
|
|
38
|
+
const v_b = points[b * 3 + i];
|
|
39
|
+
n12[i] = v_b - v_a;
|
|
40
|
+
const v_c = points[c * 3 + i];
|
|
41
|
+
n13[i] = v_c - v_a;
|
|
42
|
+
const v_d = points[d * 3 + i];
|
|
43
|
+
n14[i] = v_d - v_a;
|
|
44
|
+
|
|
45
|
+
x12[i] = (v_b + v_a) * 0.5;
|
|
46
|
+
x13[i] = (v_c + v_a) * 0.5;
|
|
47
|
+
x14[i] = (v_d + v_a) * 0.5;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
const A = [];
|
|
51
|
+
|
|
52
|
+
array_copy(n12, 0, A, 0, 3);
|
|
53
|
+
array_copy(n13, 0, A, 3, 3);
|
|
54
|
+
array_copy(n14, 0, A, 6, 3);
|
|
55
|
+
|
|
56
|
+
const rhs = [];
|
|
57
|
+
|
|
58
|
+
rhs[0] = v3_dot(n12[0], n12[1], n12[2], x12[0], x12[1], x12[2]);
|
|
59
|
+
rhs[1] = v3_dot(n13[0], n13[1], n13[2], x13[0], x13[1], x13[2]);
|
|
60
|
+
rhs[2] = v3_dot(n14[0], n14[1], n14[2], x14[0], x14[1], x14[2]);
|
|
61
|
+
|
|
62
|
+
// Solve system of equations
|
|
63
|
+
if (solve_linear_system(A, rhs, 3) === false) {
|
|
64
|
+
// failed to solve, fall-back to infinitely-sized sphere centered around origin
|
|
65
|
+
result[0] = result[1] = result[2] = 0;
|
|
66
|
+
result[3] = MAX_FLOAT32;
|
|
67
|
+
return;
|
|
68
|
+
} else {
|
|
69
|
+
result[0] = rhs[0];
|
|
70
|
+
result[1] = rhs[1];
|
|
71
|
+
result[2] = rhs[2];
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
let sum = 0;
|
|
75
|
+
let diff;
|
|
76
|
+
|
|
77
|
+
for (let i = 0; i < 3; i++) {
|
|
78
|
+
const rhs_offset = rhs[i];
|
|
79
|
+
|
|
80
|
+
diff = points[a * 3 + i] - rhs_offset;
|
|
81
|
+
sum += diff * diff;
|
|
82
|
+
diff = points[b * 3 + i] - rhs_offset;
|
|
83
|
+
sum += diff * diff;
|
|
84
|
+
diff = points[c * 3 + i] - rhs_offset;
|
|
85
|
+
sum += diff * diff;
|
|
86
|
+
diff = points[d * 3 + i] - rhs_offset;
|
|
87
|
+
sum += diff * diff;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
// divide
|
|
91
|
+
sum *= 0.25;
|
|
92
|
+
|
|
93
|
+
if (sum >= MAX_FLOAT32) {
|
|
94
|
+
result[3] = MAX_FLOAT32;
|
|
95
|
+
} else {
|
|
96
|
+
result[3] = sum;
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* Solve linear equations Ax = b using Crout's method. Input is square matrix A
|
|
102
|
+
* and load vector b. Solution x is written over load vector. The dimension of
|
|
103
|
+
* the matrix is specified in size. If error is found, method returns a 0.
|
|
104
|
+
*
|
|
105
|
+
* @see https://github.com/Kitware/VTK/blob/af928016f4041ad8a6a193d032355b909721fc95/Common/Core/vtkMath.cxx
|
|
106
|
+
*
|
|
107
|
+
* @param {number[]} A
|
|
108
|
+
* @param {number[]} x
|
|
109
|
+
* @param {number} size
|
|
110
|
+
* @returns {boolean}
|
|
111
|
+
*/
|
|
112
|
+
function solve_linear_system(A, x, size) {
|
|
113
|
+
const index = [];
|
|
114
|
+
|
|
115
|
+
if (luf_factor_linear_system(A, index, size) === 0) {
|
|
116
|
+
return false;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
luf_solve_linear_system(A, index, x, size);
|
|
120
|
+
|
|
121
|
+
return true;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
|
|
125
|
+
/**
|
|
126
|
+
* Factor linear equations Ax = b using LU decomposition A = LU where L is
|
|
127
|
+
* lower triangular matrix and U is upper triangular matrix. Input is
|
|
128
|
+
* square matrix A, integer array of pivot indices index[0->n-1], and size
|
|
129
|
+
* of square matrix n. Output factorization LU is in matrix A. If error is
|
|
130
|
+
* found, method returns 0.
|
|
131
|
+
* @param {number[]} A
|
|
132
|
+
* @param {number[]} index
|
|
133
|
+
* @param {number} size
|
|
134
|
+
*/
|
|
135
|
+
function luf_factor_linear_system(A, index, size) {
|
|
136
|
+
const scale = [];
|
|
137
|
+
|
|
138
|
+
// double scratch[10];
|
|
139
|
+
// double* scale = (size < 10 ? scratch : new double[size]);
|
|
140
|
+
//
|
|
141
|
+
// int i, j, k;
|
|
142
|
+
// int maxI = 0;
|
|
143
|
+
// double largest, temp1, temp2, sum;
|
|
144
|
+
//
|
|
145
|
+
// // Manage number of output warnings
|
|
146
|
+
// static int numWarns = 0;
|
|
147
|
+
//
|
|
148
|
+
// //
|
|
149
|
+
|
|
150
|
+
let numWarns = 0;
|
|
151
|
+
let i, j, k;
|
|
152
|
+
let maxI = 0;
|
|
153
|
+
let largest, temp1, temp2, sum;
|
|
154
|
+
// Loop over rows to get implicit scaling information
|
|
155
|
+
//
|
|
156
|
+
for (i = 0; i < size; ++i) {
|
|
157
|
+
for (largest = 0.0, j = 0; j < size; ++j) {
|
|
158
|
+
if ((temp2 = Math.abs(A[i * size + j])) > largest) {
|
|
159
|
+
largest = temp2;
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
if (largest === 0.0 && numWarns++ < VTK_MAX_WARNS) {
|
|
164
|
+
// vtkGenericWarningMacro(<< "Unable to factor linear system");
|
|
165
|
+
return 0;
|
|
166
|
+
}
|
|
167
|
+
scale[i] = 1.0 / largest;
|
|
168
|
+
}
|
|
169
|
+
//
|
|
170
|
+
// Loop over all columns using Crout's method
|
|
171
|
+
//
|
|
172
|
+
for (j = 0; j < size; ++j) {
|
|
173
|
+
for (i = 0; i < j; ++i) {
|
|
174
|
+
sum = A[i * size + j];
|
|
175
|
+
for (k = 0; k < i; ++k) {
|
|
176
|
+
sum -= A[i * size + k] * A[k * size + j];
|
|
177
|
+
}
|
|
178
|
+
A[i * size + j] = sum;
|
|
179
|
+
}
|
|
180
|
+
//
|
|
181
|
+
// Begin search for largest pivot element
|
|
182
|
+
//
|
|
183
|
+
for (largest = 0.0, i = j; i < size; ++i) {
|
|
184
|
+
sum = A[i * size + j];
|
|
185
|
+
for (k = 0; k < j; ++k) {
|
|
186
|
+
sum -= A[i * size + k] * A[k * size + j];
|
|
187
|
+
}
|
|
188
|
+
A[i * size + j] = sum;
|
|
189
|
+
|
|
190
|
+
if ((temp1 = scale[i] * Math.abs(sum)) >= largest) {
|
|
191
|
+
largest = temp1;
|
|
192
|
+
maxI = i;
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
//
|
|
196
|
+
// Check for row interchange
|
|
197
|
+
//
|
|
198
|
+
if (j !== maxI) {
|
|
199
|
+
for (k = 0; k < size; ++k) {
|
|
200
|
+
temp1 = A[maxI * size + k];
|
|
201
|
+
A[maxI * size + k] = A[j * size + k];
|
|
202
|
+
A[j * size + k] = temp1;
|
|
203
|
+
}
|
|
204
|
+
scale[maxI] = scale[j];
|
|
205
|
+
}
|
|
206
|
+
//
|
|
207
|
+
// Divide by pivot element and perform elimination
|
|
208
|
+
//
|
|
209
|
+
index[j] = maxI;
|
|
210
|
+
|
|
211
|
+
if (Math.abs(A[j * size + j]) <= SMALL_NUMBER && numWarns++ < VTK_MAX_WARNS) {
|
|
212
|
+
//vtkGenericWarningMacro(<< "Unable to factor linear system");
|
|
213
|
+
return 0;
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
if (j !== (size - 1)) {
|
|
217
|
+
temp1 = 1.0 / A[j * size + j];
|
|
218
|
+
for (i = j + 1; i < size; ++i) {
|
|
219
|
+
A[i * size + j] *= temp1;
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
return 1;
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
/**
|
|
228
|
+
* Solve linear equations Ax = b using LU decomposition A = LU where L is
|
|
229
|
+
* lower triangular matrix and U is upper triangular matrix. Input is
|
|
230
|
+
* factored matrix A=LU, integer array of pivot indices index[0->n-1],
|
|
231
|
+
* load vector x[0->n-1], and size of square matrix n. Note that A=LU and
|
|
232
|
+
* index[] are generated from method LUFactorLinearSystem). Also, solution
|
|
233
|
+
* vector is written directly over input load vector.
|
|
234
|
+
* @param {number[]} A
|
|
235
|
+
* @param {number[]} index
|
|
236
|
+
* @param {number[]} x
|
|
237
|
+
* @param {number} size
|
|
238
|
+
*/
|
|
239
|
+
function luf_solve_linear_system(A, index, x, size) {
|
|
240
|
+
let i, j, ii, idx;
|
|
241
|
+
let sum;
|
|
242
|
+
//
|
|
243
|
+
// Proceed with forward and backsubstitution for L and U
|
|
244
|
+
// matrices. First, forward substitution.
|
|
245
|
+
//
|
|
246
|
+
for (ii = -1, i = 0; i < size; ++i) {
|
|
247
|
+
idx = index[i];
|
|
248
|
+
sum = x[idx];
|
|
249
|
+
x[idx] = x[i];
|
|
250
|
+
|
|
251
|
+
if (ii >= 0) {
|
|
252
|
+
for (j = ii; j <= (i - 1); ++j) {
|
|
253
|
+
sum -= A[i * size + j] * x[j];
|
|
254
|
+
}
|
|
255
|
+
} else if (sum !== 0.0) {
|
|
256
|
+
ii = i;
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
x[i] = sum;
|
|
260
|
+
}
|
|
261
|
+
//
|
|
262
|
+
// Now, back substitution
|
|
263
|
+
//
|
|
264
|
+
for (i = size - 1; i >= 0; i--) {
|
|
265
|
+
sum = x[i];
|
|
266
|
+
for (j = i + 1; j < size; ++j) {
|
|
267
|
+
sum -= A[i * size + j] * x[j];
|
|
268
|
+
}
|
|
269
|
+
x[i] = sum / A[i * size + i];
|
|
270
|
+
}
|
|
271
|
+
}
|