@woosh/meep-engine 2.42.7 → 2.43.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/core/binary/BitSet.js +4 -4
- package/core/binary/ctz32.js +40 -0
- package/core/collection/ObservedMap.js +61 -57
- package/core/collection/heap/FastBinaryHeap.js +7 -1
- package/core/collection/heap/Uint32Heap.js +19 -0
- package/core/collection/map/AsyncLoadingCache.js +3 -1
- package/core/geom/2d/compute_polygon_area_2d.js +32 -0
- package/core/geom/2d/compute_polygon_area_2d.spec.js +10 -0
- package/core/geom/2d/compute_triangle_area_2d.js +15 -0
- package/core/geom/2d/compute_triangle_area_2d.spec.js +9 -0
- package/core/geom/2d/convex-hull/convex_hull_jarvis_2d.js +64 -0
- package/core/geom/2d/convex-hull/convex_hull_jarvis_2d.spec.js +33 -0
- package/core/geom/2d/convex-hull/convex_hull_monotone_2d.js +82 -0
- package/core/geom/2d/convex-hull/fixed_convex_hull_humus.js +135 -0
- package/core/geom/2d/convex-hull/fixed_convex_hull_relaxation.js +282 -0
- package/core/geom/2d/convex-hull/orientation3.js +444 -0
- package/core/geom/2d/convex-hull/orientation3_array.js +22 -0
- package/core/geom/2d/convex-hull/orientation3_v2.js +12 -0
- package/core/geom/2d/intersect_ray_2d.js +56 -0
- package/core/geom/2d/quad-tree/QuadTreeNode.js +0 -81
- package/core/geom/2d/quad-tree/qt_match_data_by_circle.js +70 -0
- package/core/geom/3d/matrix/m4_multiply_alphatensor.js +131 -0
- package/core/geom/3d/plane/orient3d_fast.js +2 -6
- package/core/geom/3d/tetrahedra/README.md +7 -0
- package/core/geom/3d/tetrahedra/compute_bounding_simplex_3d.js +3 -1
- package/core/geom/3d/tetrahedra/delaunay/Cavity.js +48 -0
- package/core/geom/3d/tetrahedra/{compute_delaunay_tetrahedral_mesh.js → delaunay/compute_delaunay_tetrahedral_mesh.js} +15 -7
- package/core/geom/3d/tetrahedra/{compute_delaunay_tetrahedral_mesh.spec.js → delaunay/compute_delaunay_tetrahedral_mesh.spec.js} +0 -0
- package/core/geom/3d/tetrahedra/delaunay/tetrahedral_mesh_compute_cavity.js +73 -0
- package/core/geom/3d/tetrahedra/delaunay/tetrahedral_mesh_walk_toward_cavity.js +48 -0
- package/core/geom/3d/tetrahedra/hxt/a.js +524 -0
- package/core/geom/3d/tetrahedra/hxt/hxt.js +140 -0
- package/core/geom/3d/tetrahedra/hxt/hxt.wasm +0 -0
- package/core/geom/3d/tetrahedra/point_in_tetrahedron_circumsphere.js +35 -20
- package/core/geom/3d/tetrahedra/prototypeTetrahedraBuilder.js +98 -0
- package/core/geom/3d/tetrahedra/tetrahedra_collection.js +60 -131
- package/core/geom/packing/{MaxRectangles.js → max-rect/MaxRectangles.js} +28 -124
- package/core/geom/packing/max-rect/removeRedundantBoxes.js +69 -0
- package/core/geom/packing/max-rect/removeRedundantBoxesArray.js +40 -0
- package/core/geom/v3_distance_above_plane.js +1 -1
- package/core/graph/layout/BoxLayouter.js +2 -88
- package/core/graph/layout/CircleLayout.js +2 -1
- package/core/graph/layout/box/forceIntoBox.js +45 -0
- package/core/graph/layout/box/pullBoxTowardsPoint.js +20 -0
- package/core/graph/layout/box/resolveAABB2Overlap.js +22 -0
- package/core/math/bessel_3.js +11 -0
- package/core/math/bessel_i0.js +26 -0
- package/core/process/executor/ConcurrentExecutor.spec.js +2 -1
- package/core/process/task/util/actionTask.js +19 -0
- package/core/process/task/util/countTask.js +62 -0
- package/core/process/task/util/delayTask.js +45 -0
- package/core/process/task/util/emptyTask.js +19 -0
- package/core/process/task/util/failingTask.js +17 -0
- package/core/process/task/util/futureTask.js +48 -0
- package/core/process/task/util/promiseTask.js +42 -0
- package/core/process/task/util/randomCountTask.js +64 -0
- package/core/process/task/util/wrapTaskIgnoreFailure.js +47 -0
- package/engine/Engine.js +8 -8
- package/engine/EngineBootstrapper.js +1 -1
- package/engine/asset/AssetManager.js +197 -53
- package/engine/asset/AssetRequest.js +32 -0
- package/engine/asset/loaders/ArrayBufferLoader.js +62 -50
- package/engine/asset/loaders/image/png/PNG.js +15 -1
- package/engine/asset/loaders/image/png/PNGReader.js +3 -2
- package/engine/ecs/foliage/ecs/InstancedMeshUtils.js +2 -1
- package/engine/ecs/storage/BinaryBufferDeSerializer.js +1 -1
- package/engine/ecs/storage/JSONDeSerializer.js +2 -1
- package/engine/ecs/terrain/ecs/splat/SplatMapOptimizer.js +2 -1
- package/engine/ecs/terrain/ecs/splat/SplatMapping.js +1 -1
- package/engine/graphics/camera/makeScreenScissorFrustum.js +1 -1
- package/engine/graphics/camera/testClippingPlaneComputation.js +4 -45
- package/engine/graphics/ecs/camera/FrustumProjector.js +6 -0
- package/engine/graphics/ecs/decal/v2/FPDecalSystem.js +5 -0
- package/engine/graphics/ecs/decal/v2/prototypeDecalSystem.js +23 -4
- package/engine/graphics/ecs/highlight/plugin/OutlineRenderPlugin.js +1 -1
- package/engine/graphics/ecs/mesh-v2/ShadedGeometry.js +11 -0
- package/engine/graphics/geometry/FULL_SCREEN_TRIANGLE_GEOMETRY.js +1 -2
- package/engine/graphics/impostors/octahedral/ImpostorBaker.js +5 -2
- package/engine/graphics/impostors/octahedral/ImpostorDescription.js +18 -0
- package/engine/graphics/impostors/octahedral/bake/prepare_bake_material.js +15 -0
- package/engine/graphics/impostors/octahedral/prototypeBaker.js +66 -79
- package/engine/graphics/impostors/octahedral/shader/ImpostorShaderWireframeV0.js +134 -0
- package/engine/graphics/impostors/octahedral/util/build_cutout_from_atlas_by_alpha.js +128 -0
- package/engine/graphics/impostors/octahedral/util/build_geometry_from_cutout_shape.js +32 -0
- package/engine/graphics/impostors/octahedral/util/load_mesh_for_bake.js +31 -0
- package/engine/graphics/impostors/octahedral/util/makeImpostorAtlasPreview.js +107 -0
- package/engine/graphics/material/manager/ManagedMaterial.js +4 -0
- package/engine/graphics/material/manager/MaterialManager.js +1 -0
- package/engine/graphics/material/optimization/MaterialOptimizationContext.js +7 -3
- package/engine/graphics/particles/particular/engine/renderers/billboard/ParticleBillboardMaterial.js +2 -2
- package/engine/graphics/render/forward_plus/plugin/ForwardPlusRenderingPlugin.js +0 -19
- package/engine/graphics/render/forward_plus/prototype/prototypeLightManager.js +2 -2
- package/engine/graphics/render/visibility/hiz/buildCanvasViewFromTexture.js +83 -27
- package/engine/graphics/shadows/ShadowMapRenderer.js +11 -4
- package/engine/graphics/texture/atlas/AbstractTextureAtlas.js +2 -1
- package/engine/graphics/texture/atlas/CachingTextureAtlas.js +208 -38
- package/engine/graphics/texture/atlas/TextureAtlas.js +31 -24
- package/engine/graphics/texture/atlas/gpu/WebGLTextureAtlas.js +1 -1
- package/engine/graphics/texture/sampler/filter/box.js +16 -0
- package/engine/graphics/texture/sampler/filter/cubic2.js +32 -0
- package/engine/graphics/texture/sampler/filter/gaussian.js +16 -0
- package/engine/graphics/texture/sampler/filter/kaiser_1.js +19 -0
- package/engine/graphics/texture/sampler/filter/kaiser_bessel_window.js +19 -0
- package/engine/graphics/texture/sampler/filter/mitchell.js +55 -0
- package/engine/graphics/texture/sampler/filter/sampler2d_scale_down_generic.js +109 -0
- package/engine/graphics/texture/sampler/filter/triangle.js +19 -0
- package/engine/graphics/texture/sampler/prototypeSamplerFiltering.js +187 -86
- package/engine/graphics/texture/sampler/sampler2_d_scale_down_lanczos.js +77 -25
- package/engine/graphics/texture/sampler/search/make_edge_condition_channel_threshold.js +34 -0
- package/engine/graphics/texture/sampler/search/sampler2d_find_pixels.js +24 -0
- package/engine/graphics/texture/sprite/prototypeSpriteCutoutGeometry.js +212 -0
- package/engine/knowledge/database/StaticKnowledgeDataTable.js +1 -1
- package/engine/navigation/grid/AStar.js +1 -1
- package/engine/plugin/EnginePluginManager.js +28 -27
- package/engine/plugin/PluginReferenceContext.js +9 -0
- package/engine/scene/Scene.js +1 -1
- package/engine/scene/SerializedScene.js +1 -1
- package/engine/scene/transitionToScene.js +3 -1
- package/generation/example/main.js +1 -1
- package/generation/grid/generation/GridTaskApplyActionToCells.js +1 -1
- package/generation/grid/generation/GridTaskDensityMarkerDistribution.js +1 -1
- package/generation/grid/generation/GridTaskExecuteRuleTimes.js +1 -1
- package/generation/grid/generation/NoopGridTaskGenerator.js +1 -1
- package/generation/grid/generation/discrete/GridTaskCellularAutomata.js +2 -1
- package/generation/grid/generation/discrete/GridTaskConnectRooms.js +1 -1
- package/generation/grid/generation/discrete/layer/GridTaskBuildSourceDistanceMap.js +3 -2
- package/generation/grid/generation/discrete/layer/GridTaskDistanceToMarkers.js +1 -1
- package/generation/grid/generation/grid/GridTaskAddNodesFixed.js +1 -1
- package/generation/grid/generation/road/GridTaskGenerateRoads.js +3 -2
- package/generation/grid/generation/util/buildDistanceMapToObjective.js +1 -1
- package/generation/markers/GridActionRuleSet.js +2 -1
- package/generation/placement/GridCellActionTransformNearbyMarkers.js +2 -4
- package/generation/theme/ThemeEngine.js +4 -1
- package/package.json +1 -1
- package/view/asset/AssetLoaderStatusView.js +5 -5
- package/view/minimap/gl/MinimapTerrainGL.js +1 -2
- package/view/renderModel.js +1 -1
- package/view/tooltip/TooltipView.js +5 -5
- package/core/process/task/TaskUtils.js +0 -352
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { orientation3 } from "./orientation3.js";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
*
|
|
5
|
+
* @param {number[]} points
|
|
6
|
+
* @param {number} a
|
|
7
|
+
* @param {number} b
|
|
8
|
+
* @param {number} c
|
|
9
|
+
* @returns {number}
|
|
10
|
+
*/
|
|
11
|
+
export function orientation3_array(points, a, b, c) {
|
|
12
|
+
const ax = points[a * 2];
|
|
13
|
+
const ay = points[a * 2 + 1];
|
|
14
|
+
|
|
15
|
+
const bx = points[b * 2];
|
|
16
|
+
const by = points[b * 2 + 1];
|
|
17
|
+
|
|
18
|
+
const cx = points[c * 2];
|
|
19
|
+
const cy = points[c * 2 + 1];
|
|
20
|
+
|
|
21
|
+
return orientation3(ax, ay, bx, by, cx, cy);
|
|
22
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { orientation3 } from "./orientation3.js";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
*
|
|
5
|
+
* @param {number[]} a
|
|
6
|
+
* @param {number[]} b
|
|
7
|
+
* @param {number[]} c
|
|
8
|
+
* @returns {number}
|
|
9
|
+
*/
|
|
10
|
+
export function orientation3_v2(a, b, c) {
|
|
11
|
+
return orientation3(a[0], a[1], b[0], b[1], c[0], c[1]);
|
|
12
|
+
}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { fabsf } from "../../math/fabsf.js";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
*
|
|
5
|
+
* @param {number} ux
|
|
6
|
+
* @param {number} uy
|
|
7
|
+
* @param {number} vx
|
|
8
|
+
* @param {number} vy
|
|
9
|
+
* @returns {number}
|
|
10
|
+
*/
|
|
11
|
+
function perp(ux, uy, vx, vy) {
|
|
12
|
+
return (ux * vy - uy * vx);
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* NOTE: that direction must not be normalized for correct results and instead derived from line length
|
|
17
|
+
* @param {number[]|Float32Array|Float64Array} out
|
|
18
|
+
* @param {number} out_offset
|
|
19
|
+
* @param {number} origin_a_x
|
|
20
|
+
* @param {number} origin_a_y
|
|
21
|
+
* @param {number} direction_a_x
|
|
22
|
+
* @param {number} direction_a_y
|
|
23
|
+
* @param {number} origin_b_x
|
|
24
|
+
* @param {number} origin_b_y
|
|
25
|
+
* @param {number} direction_b_x
|
|
26
|
+
* @param {number} direction_b_y
|
|
27
|
+
* @returns {boolean} false if lines are coplanar or intersect on the wrong side
|
|
28
|
+
*/
|
|
29
|
+
export function intersect_ray_2d(
|
|
30
|
+
out, out_offset,
|
|
31
|
+
origin_a_x, origin_a_y, direction_a_x, direction_a_y,
|
|
32
|
+
origin_b_x, origin_b_y, direction_b_x, direction_b_y
|
|
33
|
+
) {
|
|
34
|
+
const d = perp(direction_a_x, direction_a_y, direction_b_x, direction_b_y);
|
|
35
|
+
if (fabsf(d) < 0.000000000001) // Parallel lines
|
|
36
|
+
return false;
|
|
37
|
+
|
|
38
|
+
const t = perp(direction_b_x, direction_b_y, origin_a_x - origin_b_x, origin_a_y - origin_b_y) / d;
|
|
39
|
+
|
|
40
|
+
if (t < 0.5) // Intersects on the wrong side
|
|
41
|
+
return false;
|
|
42
|
+
|
|
43
|
+
const point_x = origin_a_x + t * direction_a_x;
|
|
44
|
+
const point_y = origin_a_y + t * direction_a_y;
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
// if (Number.isNaN(point_x)) {
|
|
48
|
+
// debugger;
|
|
49
|
+
// }
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
out[out_offset] = point_x;
|
|
53
|
+
out[out_offset + 1] = point_y;
|
|
54
|
+
|
|
55
|
+
return true;
|
|
56
|
+
}
|
|
@@ -2,7 +2,6 @@ import { assert } from "../../../assert.js";
|
|
|
2
2
|
import { max2 } from "../../../math/max2.js";
|
|
3
3
|
import { min2 } from "../../../math/min2.js";
|
|
4
4
|
import AABB2 from "../../AABB2.js";
|
|
5
|
-
import { aabb2_sqrDistanceToPoint } from "../AABB2Math.js";
|
|
6
5
|
import { QuadTreeDatum } from "./QuadTreeDatum.js";
|
|
7
6
|
|
|
8
7
|
|
|
@@ -486,25 +485,6 @@ export class QuadTreeNode extends AABB2 {
|
|
|
486
485
|
}
|
|
487
486
|
}
|
|
488
487
|
|
|
489
|
-
/**
|
|
490
|
-
*
|
|
491
|
-
* @param {QuadTreeDatum<D>[]} result
|
|
492
|
-
* @param {number} x
|
|
493
|
-
* @param {number} y
|
|
494
|
-
* @param {number} radius
|
|
495
|
-
* @returns {number} number of intersecting objects added to the result
|
|
496
|
-
*/
|
|
497
|
-
requestDatumIntersectionsCircle(result, x, y, radius) {
|
|
498
|
-
//TODO optimize closures out to avoid GC
|
|
499
|
-
let count = 0;
|
|
500
|
-
|
|
501
|
-
this.traverseCircleIntersections(x, y, radius, datum => {
|
|
502
|
-
return result[count++] = datum;
|
|
503
|
-
});
|
|
504
|
-
|
|
505
|
-
return count;
|
|
506
|
-
}
|
|
507
|
-
|
|
508
488
|
/**
|
|
509
489
|
*
|
|
510
490
|
* @param {QuadTreeDatum<D>[]} result
|
|
@@ -595,65 +575,4 @@ export class QuadTreeNode extends AABB2 {
|
|
|
595
575
|
}
|
|
596
576
|
}
|
|
597
577
|
|
|
598
|
-
/**
|
|
599
|
-
*
|
|
600
|
-
* @param {number} x
|
|
601
|
-
* @param {number} y
|
|
602
|
-
* @param {number} radius
|
|
603
|
-
* @param {function(QuadTreeDatum)} visitor
|
|
604
|
-
* @param {*} [thisArg]
|
|
605
|
-
*/
|
|
606
|
-
traverseCircleIntersections(x, y, radius, visitor, thisArg) {
|
|
607
|
-
assert.isNumber(x, 'x');
|
|
608
|
-
assert.isNumber(y, 'y');
|
|
609
|
-
assert.isNumber(radius, 'radius');
|
|
610
|
-
|
|
611
|
-
const radius2 = radius * radius;
|
|
612
|
-
|
|
613
|
-
const data = this.data;
|
|
614
|
-
const dataCount = data.length;
|
|
615
|
-
|
|
616
|
-
for (let i = 0; i < dataCount; i++) {
|
|
617
|
-
const datum = data[i];
|
|
618
|
-
|
|
619
|
-
const d2 = aabb2_sqrDistanceToPoint(datum.x0, datum.y0, datum.x1, datum.y1, x, y);
|
|
620
|
-
|
|
621
|
-
if (d2 < radius2) {
|
|
622
|
-
const continueTraversal = visitor.call(thisArg, datum);
|
|
623
|
-
|
|
624
|
-
if (continueTraversal === false) {
|
|
625
|
-
return;
|
|
626
|
-
}
|
|
627
|
-
}
|
|
628
|
-
}
|
|
629
|
-
|
|
630
|
-
if (this.isSplit()) {
|
|
631
|
-
|
|
632
|
-
const x0 = this.x0;
|
|
633
|
-
const x1 = this.x1;
|
|
634
|
-
|
|
635
|
-
const y0 = this.y0;
|
|
636
|
-
const y1 = this.y1;
|
|
637
|
-
|
|
638
|
-
const hx = (x0 + x1) / 2;
|
|
639
|
-
const hy = (y0 + y1) / 2;
|
|
640
|
-
|
|
641
|
-
if (aabb2_sqrDistanceToPoint(x0, y0, hx, hy, x, y) < radius2) {
|
|
642
|
-
this.topLeft.traverseCircleIntersections(x, y, radius, visitor, thisArg);
|
|
643
|
-
}
|
|
644
|
-
|
|
645
|
-
if (aabb2_sqrDistanceToPoint(x0, hy, hx, y1, x, y) < radius2) {
|
|
646
|
-
this.bottomLeft.traverseCircleIntersections(x, y, radius, visitor, thisArg);
|
|
647
|
-
}
|
|
648
|
-
|
|
649
|
-
if (aabb2_sqrDistanceToPoint(hx, y0, x1, hy, x, y) < radius2) {
|
|
650
|
-
this.topRight.traverseCircleIntersections(x, y, radius, visitor, thisArg);
|
|
651
|
-
}
|
|
652
|
-
|
|
653
|
-
if (aabb2_sqrDistanceToPoint(hx, hy, x1, y1, x, y) < radius2) {
|
|
654
|
-
this.bottomRight.traverseCircleIntersections(x, y, radius, visitor, thisArg);
|
|
655
|
-
}
|
|
656
|
-
|
|
657
|
-
}
|
|
658
|
-
}
|
|
659
578
|
}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import { aabb2_sqrDistanceToPoint } from "../AABB2Math.js";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
*
|
|
5
|
+
* @type {QuadTreeNode[]}
|
|
6
|
+
*/
|
|
7
|
+
const node_stack = [];
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* @template T
|
|
11
|
+
* @param {QuadTreeDatum<T>[]} result
|
|
12
|
+
* @param {number} result_offset
|
|
13
|
+
* @param {QuadTreeNode<T>} tree
|
|
14
|
+
* @param {number} x
|
|
15
|
+
* @param {number} y
|
|
16
|
+
* @param {number} radius
|
|
17
|
+
* @param {function(data:T):boolean} [predicate]
|
|
18
|
+
* @param {*} [predicateContext]
|
|
19
|
+
* @returns {number}
|
|
20
|
+
*/
|
|
21
|
+
export function qt_match_data_by_circle(
|
|
22
|
+
result, result_offset,
|
|
23
|
+
tree,
|
|
24
|
+
x, y, radius,
|
|
25
|
+
predicate, predicateContext
|
|
26
|
+
) {
|
|
27
|
+
let result_cursor = result_offset;
|
|
28
|
+
|
|
29
|
+
let stack_pointer = 0;
|
|
30
|
+
|
|
31
|
+
const r2 = radius * radius;
|
|
32
|
+
|
|
33
|
+
node_stack[stack_pointer] = tree;
|
|
34
|
+
stack_pointer++;
|
|
35
|
+
|
|
36
|
+
while (stack_pointer > 0) {
|
|
37
|
+
|
|
38
|
+
--stack_pointer;
|
|
39
|
+
const node = node_stack[stack_pointer];
|
|
40
|
+
|
|
41
|
+
const d2 = aabb2_sqrDistanceToPoint(node.x0, node.y0, node.x1, node.y1, x, y);
|
|
42
|
+
|
|
43
|
+
if (d2 > r2) {
|
|
44
|
+
// not a match
|
|
45
|
+
continue;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
const data = node.data;
|
|
49
|
+
const data_count = data.length;
|
|
50
|
+
|
|
51
|
+
for (let i = 0; i < data_count; i++) {
|
|
52
|
+
const datum = data[i];
|
|
53
|
+
|
|
54
|
+
const d2_to_datum = aabb2_sqrDistanceToPoint(datum.x0, datum.y0, datum.x1, datum.y1, x, y);
|
|
55
|
+
|
|
56
|
+
if (d2_to_datum <= r2 && predicate.call(predicateContext, datum.data)) {
|
|
57
|
+
result[result_cursor++] = datum;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
if (node.isSplit()) {
|
|
62
|
+
node_stack[stack_pointer++] = node.topLeft;
|
|
63
|
+
node_stack[stack_pointer++] = node.bottomLeft;
|
|
64
|
+
node_stack[stack_pointer++] = node.topRight;
|
|
65
|
+
node_stack[stack_pointer++] = node.bottomRight;
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
return result_cursor - result_offset;
|
|
70
|
+
}
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Performs 4x4 matrix multiplication using algorithm discovered by AlphaTensor
|
|
3
|
+
* @see AlphaTensor2022 by Fawzi etAl
|
|
4
|
+
* @param {number[]} out
|
|
5
|
+
* @param {number[]} a
|
|
6
|
+
* @param {number[]} b
|
|
7
|
+
*/
|
|
8
|
+
export function m4_multiply_alphatensor(out, a, b) {
|
|
9
|
+
// read out matricies
|
|
10
|
+
const a11 = a[0];
|
|
11
|
+
const a12 = a[1];
|
|
12
|
+
const a13 = a[2];
|
|
13
|
+
const a14 = a[3];
|
|
14
|
+
const a21 = a[4];
|
|
15
|
+
const a22 = a[5];
|
|
16
|
+
const a23 = a[6];
|
|
17
|
+
const a24 = a[7];
|
|
18
|
+
const a31 = a[8];
|
|
19
|
+
const a32 = a[9];
|
|
20
|
+
const a33 = a[10];
|
|
21
|
+
const a34 = a[11];
|
|
22
|
+
const a41 = a[12];
|
|
23
|
+
const a42 = a[13];
|
|
24
|
+
const a43 = a[14];
|
|
25
|
+
const a44 = a[15];
|
|
26
|
+
|
|
27
|
+
const b11 = b[0];
|
|
28
|
+
const b12 = b[1];
|
|
29
|
+
const b13 = b[2];
|
|
30
|
+
const b14 = b[3];
|
|
31
|
+
const b21 = b[4];
|
|
32
|
+
const b22 = b[5];
|
|
33
|
+
const b23 = b[6];
|
|
34
|
+
const b24 = b[7];
|
|
35
|
+
const b31 = b[8];
|
|
36
|
+
const b32 = b[9];
|
|
37
|
+
const b33 = b[10];
|
|
38
|
+
const b34 = b[11];
|
|
39
|
+
const b41 = b[12];
|
|
40
|
+
const b42 = b[13];
|
|
41
|
+
const b43 = b[14];
|
|
42
|
+
const b44 = b[15];
|
|
43
|
+
|
|
44
|
+
// apply multiplication algorithm
|
|
45
|
+
const h1 = (a11 + a31) * (b11 + b31)
|
|
46
|
+
const h2 = (a11 - a13 + a31) * (b11 - b13 + b31)
|
|
47
|
+
const h3 = -a13 * (b11 - b13 + b31 - b33)
|
|
48
|
+
const h4 = -a33 * -b33
|
|
49
|
+
const h5 = -a31 * -b13
|
|
50
|
+
const h6 = (a11 - a13 + a31 - a33) * -b31
|
|
51
|
+
const h7 = (-a21 + a22 - a23 - a24) * (-b21 + b22 - b23 - b24)
|
|
52
|
+
const h8 = (-a21 + a22 - a23 - a24 - a41 + a42) * (-b21 + b22 - b23 - b24 - b41 + b42)
|
|
53
|
+
const h9 = (a11 - a13) * (b11 - b13)
|
|
54
|
+
const h10 = (-a21 + a22 - a41 + a42) * (-b21 + b22 - b41 + b42)
|
|
55
|
+
const h11 = (a41 - a42) * (-b23 - b24)
|
|
56
|
+
const h12 = (-a21 + a22 - a23 - a24 - a41 + a42 - a43 - a44) * (b41 - b42)
|
|
57
|
+
const h13 = (-a23 - a24) * (-b21 + b22 - b23 - b24 - b41 + b42 - b43 - b44)
|
|
58
|
+
const h14 = (a11 - a12 + a21 - a22) * (-b12 - b14)
|
|
59
|
+
const h15 = (-a12 - a14) * -b21
|
|
60
|
+
const h16 = (a12 + a14 - a21 + a22 + a23 + a24) * (b12 + b14 - b21 + b22 + b23 + b24)
|
|
61
|
+
const h17 = (a12 + a14 - a21 + a22 + a23 + a24 + a32 + a41 - a42) * (b12 + b14 - b21 + b22 + b23 + b24 + b32 + b41 - b42)
|
|
62
|
+
const h18 = (a12 - a21 + a22 + a32 + a41 - a42) * (b12 - b21 + b22 + b32 + b41 - b42)
|
|
63
|
+
const h19 = (a14 + a23 + a24) * (b12 + b14 - b21 + b22 + b23 + b24 + b32 + b34 + b41 - b42 - b43 - b44)
|
|
64
|
+
const h20 = (a12 + a14 - a21 + a22 + a23 + a24 + a32 + a34 + a41 - a42 - a43 - a44) * (b32 + b41 - b42)
|
|
65
|
+
const h21 = (a32 + a41 - a42) * (b14 + b23 + b24)
|
|
66
|
+
const h22 = (a12 + a14 + a22 + a24) * (b12 + b14 + b22 + b24)
|
|
67
|
+
const h23 = (a12 + a14 + a22 + a24 + a32 - a42) * (b12 + b14 + b22 + b24 + b32 - b42)
|
|
68
|
+
const h24 = (a14 + a24) * (b12 + b14 + b22 + b24 + b32 + b34 - b42 - b44)
|
|
69
|
+
const h25 = (a12 + a14 + a22 + a24 + a32 + a34 - a42 - a44) * (b32 - b42)
|
|
70
|
+
const h26 = (a32 - a42) * (b14 + b24)
|
|
71
|
+
const h27 = (a34 - a44) * (b34 - b44)
|
|
72
|
+
const h28 = (a34 - a43 - a44) * (b34 - b43 - b44)
|
|
73
|
+
const h29 = (a14 + a34) * -b43
|
|
74
|
+
const h30 = (a13 + a14 + a23 + a24 + a33 + a34 - a43 - a44) * (b14 + b34)
|
|
75
|
+
const h31 = (a11 - a12 - a13 - a14 + a21 - a22 - a23 - a24 + a31 - a32 - a33 - a34 - a41 + a42 + a43 + a44) * b14
|
|
76
|
+
const h32 = -a43 * (b13 + b14 + b23 + b24 + b33 + b34 - b43 - b44)
|
|
77
|
+
const h33 = a14 * (-b21 + b41)
|
|
78
|
+
const h34 = (a14 - a32) * (-b21 + b41 - b43)
|
|
79
|
+
const h35 = (a13 + a14 + a23 + a24 - a31 + a32 + a33 + a34 + a41 - a42 - a43 - a44) * (b14 - b32)
|
|
80
|
+
const h36 = (-a31 + a32 + a33 + a34 + a41 - a42 - a43 - a44) * b32
|
|
81
|
+
const h37 = (-a12 - a32) * -b23
|
|
82
|
+
const h38 = (a32 + a34) * (b41 - b43)
|
|
83
|
+
const h39 = (-a13 - a14 - a23 - a24) * (b32 + b34)
|
|
84
|
+
const h40 = a32 * (-b21 + b23 + b41 - b43)
|
|
85
|
+
const h41 = -a21 * (b11 - b12 + b21 - b22)
|
|
86
|
+
const h42 = (-a21 + a41) * (b11 - b12 - b13 - b14 + b21 - b22 - b23 - b24 + b31 - b32 - b33 - b34 - b41 + b42 + b43 + b44)
|
|
87
|
+
const h43 = (-a21 + a41 - a43) * (b13 + b14 + b23 + b24 - b31 + b32 + b33 + b34 + b41 - b42 - b43 - b44)
|
|
88
|
+
const h44 = (a12 + a22 + a32 - a42) * (b12 + b22 + b32 - b42)
|
|
89
|
+
const h45 = (-a21 + a23 + a41 - a43) * (-b31 + b32 + b33 + b34 + b41 - b42 - b43 - b44)
|
|
90
|
+
const h46 = (-a31 + a32 + a41 - a42) * (-b12 - b32)
|
|
91
|
+
const h47 = (a41 - a43) * (-b13 - b14 - b23 - b24)
|
|
92
|
+
const h48 = (-a43 - a44) * (-b43 - b44)
|
|
93
|
+
const h49 = -a23 * (-b31 + b32 + b41 - b42)
|
|
94
|
+
const c11 = h1 - h2 - h5 + h9 + h15 + h33
|
|
95
|
+
const c12 = -h15 - h16 + h17 - h18 - h21 + h22 - h23 + h26 - h33 - h41 + h44 + h49
|
|
96
|
+
const c13 = h2 + h5 + h6 - h9 - h29 - h33 + h34 + h38
|
|
97
|
+
const c14 = -h16 + h17 - h20 - h21 + h22 - h23 + h25 + h26 - h29 - h32 - h33 + h34 + h38 - h41 + h42 + h43
|
|
98
|
+
const c21 = -h7 + h8 - h10 + h11 - h14 + h15 + h16 - h17 + h18 + h21 - h31 + h33 - h35 - h36
|
|
99
|
+
const c22 = h7 - h8 + h10 - h11 - h15 - h16 + h17 - h18 - h21 + h22 - h23 + h26 - h33 + h44
|
|
100
|
+
const c23 = -h7 + h8 + h11 + h12 - h16 + h17 - h20 - h21 - h29 - h33 + h34 + h36 + h38 + h46
|
|
101
|
+
const c24 = -h7 + h8 + h11 + h12 - h16 + h17 - h20 - h21 + h22 - h23 + h25 + h26 - h29 - h33 + h34 + h38
|
|
102
|
+
const c31 = h1 - h2 + h3 - h5 + h33 - h34 + h37 - h40
|
|
103
|
+
const c32 = h17 - h18 - h19 - h21 - h23 + h24 + h26 - h33 + h34 - h37 + h40 - h43 + h44 + h45 - h47 + h49
|
|
104
|
+
const c33 = h4 + h5 - h29 - h33 + h34 + h40
|
|
105
|
+
const c34 = -h21 + h26 - h27 + h28 - h29 - h32 - h33 + h34 + h40 - h47
|
|
106
|
+
const c41 = h8 - h10 + h11 - h13 + h17 - h18 - h19 - h21 + h31 - h33 + h34 + h35 + h36 - h37 - h39 + h40
|
|
107
|
+
const c42 = -h8 + h10 - h11 + h13 - h17 + h18 + h19 + h21 + h23 - h24 - h26 + h33 - h34 + h37 - h40 - h44
|
|
108
|
+
const c43 = h11 + h21 - h28 + h29 + h30 + h33 - h34 - h35 - h36 + h39 - h40 + h48
|
|
109
|
+
const c44 = h11 + h21 - h26 + h27 - h28 + h29 + h33 - h34 - h40 + h48
|
|
110
|
+
|
|
111
|
+
// write out results
|
|
112
|
+
out[0] = c11;
|
|
113
|
+
out[1] = c12;
|
|
114
|
+
out[2] = c13;
|
|
115
|
+
out[3] = c14;
|
|
116
|
+
|
|
117
|
+
out[4] = c21;
|
|
118
|
+
out[5] = c22;
|
|
119
|
+
out[6] = c23;
|
|
120
|
+
out[7] = c24;
|
|
121
|
+
|
|
122
|
+
out[8] = c31;
|
|
123
|
+
out[9] = c32;
|
|
124
|
+
out[10] = c33;
|
|
125
|
+
out[11] = c34;
|
|
126
|
+
|
|
127
|
+
out[12] = c41;
|
|
128
|
+
out[13] = c42;
|
|
129
|
+
out[14] = c43;
|
|
130
|
+
out[15] = c44;
|
|
131
|
+
}
|
|
@@ -20,17 +20,13 @@
|
|
|
20
20
|
export function orient3d_fast(points, a, b, c, d) {
|
|
21
21
|
const a3 = a * 3;
|
|
22
22
|
const d3 = d * 3;
|
|
23
|
+
const b3 = b * 3;
|
|
24
|
+
const c3 = c * 3;
|
|
23
25
|
|
|
24
26
|
const d_x = points[d3];
|
|
25
27
|
|
|
26
28
|
const adx = points[a3] - d_x;
|
|
27
|
-
|
|
28
|
-
const b3 = b * 3;
|
|
29
|
-
|
|
30
29
|
const bdx = points[b3] - d_x;
|
|
31
|
-
|
|
32
|
-
const c3 = c * 3;
|
|
33
|
-
|
|
34
30
|
const cdx = points[c3] - d_x;
|
|
35
31
|
|
|
36
32
|
const d_y = points[d3 + 1];
|
|
@@ -19,6 +19,8 @@ const SIMPLEX_PROJECTION_AXES = new Float32Array([
|
|
|
19
19
|
|
|
20
20
|
/**
|
|
21
21
|
* Compute bounding tetrahedron (3d simplex) for a given set of input points
|
|
22
|
+
* The algorithm is pretty basic, it projects each point onto 4 planes and pushes planes away from origin to the furthest projected point
|
|
23
|
+
* then, we take intersection points between those planes to get our bounding tetrahedron
|
|
22
24
|
*
|
|
23
25
|
* @see https://github.com/bryanmcnett/aabo/blob/master/aabo.cpp
|
|
24
26
|
* @author Alexander Goldring (c) 2021
|
|
@@ -149,7 +151,7 @@ export function compute_bounding_simplex_3d(
|
|
|
149
151
|
min_c -= padding;
|
|
150
152
|
min_d -= padding;
|
|
151
153
|
|
|
152
|
-
//
|
|
154
|
+
// let's compute intersection points for each tri-plane combination to find simplex corners
|
|
153
155
|
plane_computeConvex3PlaneIntersection(
|
|
154
156
|
result, result_offset,
|
|
155
157
|
SIMPLEX_PROJECTION_AXES[0], SIMPLEX_PROJECTION_AXES[1], SIMPLEX_PROJECTION_AXES[2], -min_a,
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
export class Cavity {
|
|
2
|
+
constructor() {
|
|
3
|
+
/**
|
|
4
|
+
*
|
|
5
|
+
* @type {number[]}
|
|
6
|
+
*/
|
|
7
|
+
this.indices = [];
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
*
|
|
11
|
+
* @type {number}
|
|
12
|
+
*/
|
|
13
|
+
this.size = 0;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
update() {
|
|
17
|
+
// compute in/out state for each side of each tetra
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
*
|
|
22
|
+
* @param {number} i
|
|
23
|
+
*/
|
|
24
|
+
push(i) {
|
|
25
|
+
this.indices[this.size++] = i;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
*
|
|
30
|
+
* @param {number} i
|
|
31
|
+
* @returns {boolean}
|
|
32
|
+
*/
|
|
33
|
+
includes(i) {
|
|
34
|
+
const n = this.size;
|
|
35
|
+
|
|
36
|
+
for (let j = 0; j < n; j++) {
|
|
37
|
+
if (this.indices[j] === i) {
|
|
38
|
+
return true;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
return false;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
reset() {
|
|
46
|
+
this.size = 0;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
@@ -1,19 +1,16 @@
|
|
|
1
1
|
//
|
|
2
2
|
|
|
3
|
-
import { compute_bounding_simplex_3d } from "
|
|
4
|
-
import {
|
|
3
|
+
import { compute_bounding_simplex_3d } from "../compute_bounding_simplex_3d.js";
|
|
4
|
+
import { TetrahedralMesh } from "../tetrahedra_collection.js";
|
|
5
5
|
|
|
6
6
|
/**
|
|
7
7
|
* @see https://en.wikipedia.org/wiki/Bowyer%E2%80%93Watson_algorithm
|
|
8
8
|
* @see [1] "One machine, one minute, three billion tetrahedra" by Célestin Marot et al
|
|
9
9
|
* @param {number[]} input serialized set of 3d points (x,y,z)
|
|
10
10
|
* @param {number} n number of points in the input
|
|
11
|
+
* @returns {TetrahedralMesh}
|
|
11
12
|
*/
|
|
12
13
|
export function compute_delaunay_tetrahedral_mesh(input, n) {
|
|
13
|
-
if (n < 4) {
|
|
14
|
-
// no mesh can be created, too few points
|
|
15
|
-
return;
|
|
16
|
-
}
|
|
17
14
|
|
|
18
15
|
/**
|
|
19
16
|
* According to [1] number of tetrahedra is around 6 times greater than number of input vertices, we use that fact to pre-allocate memory
|
|
@@ -24,7 +21,14 @@ export function compute_delaunay_tetrahedral_mesh(input, n) {
|
|
|
24
21
|
* The +7 is for the initial "super" tetrahedron and 6 tetras for intermediate triangulation
|
|
25
22
|
*/
|
|
26
23
|
const tetrahedron_count_upper_bound = Math.ceil((n * n - 3 * n - 2) / 2) + 7;
|
|
27
|
-
|
|
24
|
+
|
|
25
|
+
const tetrahedrons = new TetrahedralMesh(tetrahedron_count_upper_bound);
|
|
26
|
+
|
|
27
|
+
if (n < 4) {
|
|
28
|
+
// no mesh can be created, too few points
|
|
29
|
+
return tetrahedrons;
|
|
30
|
+
}
|
|
31
|
+
|
|
28
32
|
// TODO apply spatial sort to point, to get better cache locality
|
|
29
33
|
|
|
30
34
|
// compute bounds over the input
|
|
@@ -46,5 +50,9 @@ export function compute_delaunay_tetrahedral_mesh(input, n) {
|
|
|
46
50
|
|
|
47
51
|
// remove tetras formed by with the super bounding volume
|
|
48
52
|
tetrahedrons.removeTetrasConnectedToPoints(points, n, n + 3);
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
return tetrahedrons;
|
|
49
56
|
}
|
|
50
57
|
|
|
58
|
+
|
|
File without changes
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import { assert } from "../../../../assert.js";
|
|
2
|
+
import { point_in_tetrahedron_circumsphere } from "../point_in_tetrahedron_circumsphere.js";
|
|
3
|
+
import { INVALID_NEIGHBOUR } from "../tetrahedra_collection.js";
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
*
|
|
7
|
+
* @param {TetrahedralMesh} mesh
|
|
8
|
+
* @param {Cavity} cavity
|
|
9
|
+
* @param {number[]|Float32Array} points
|
|
10
|
+
* @param {number} containing_tetra tetrahedron that contains point
|
|
11
|
+
* @param {number} point_index point that forms the cavity
|
|
12
|
+
*/
|
|
13
|
+
export function tetrahedral_mesh_compute_cavity(mesh, cavity, points, containing_tetra, point_index) {
|
|
14
|
+
assert.isNonNegativeInteger(containing_tetra, 'containing_tetra');
|
|
15
|
+
|
|
16
|
+
cavity.reset();
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
*
|
|
20
|
+
* @type {number[]}
|
|
21
|
+
*/
|
|
22
|
+
const open_set = [
|
|
23
|
+
containing_tetra
|
|
24
|
+
];
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
*
|
|
28
|
+
* @type {number[]}
|
|
29
|
+
*/
|
|
30
|
+
const closed_set = [];
|
|
31
|
+
|
|
32
|
+
// 2. find the Delaunay "cavity", a set of tetrahedrons who's circumsphere overlarlaps the point
|
|
33
|
+
// perform breadth-first expansion on the containing tetra to identify the cavity
|
|
34
|
+
while (open_set.length > 0) {
|
|
35
|
+
|
|
36
|
+
const tetra = open_set.pop();
|
|
37
|
+
cavity.push(tetra);
|
|
38
|
+
closed_set.push(tetra);
|
|
39
|
+
|
|
40
|
+
// get neighbours
|
|
41
|
+
for (let i = 0; i < 4; i++) {
|
|
42
|
+
|
|
43
|
+
const neighbour_encoded = mesh.getNeighbour(tetra, i);
|
|
44
|
+
const neighbour_tetra_index = neighbour_encoded >>> 2;
|
|
45
|
+
|
|
46
|
+
if (
|
|
47
|
+
(neighbour_encoded === INVALID_NEIGHBOUR) // no neighbour
|
|
48
|
+
|| closed_set.includes(neighbour_tetra_index) // already visited
|
|
49
|
+
|| open_set.includes(neighbour_tetra_index) // already in open set
|
|
50
|
+
) {
|
|
51
|
+
|
|
52
|
+
continue;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
const a = mesh.getCornerIndex(neighbour_tetra_index, 0);
|
|
56
|
+
const b = mesh.getCornerIndex(neighbour_tetra_index, 1);
|
|
57
|
+
const c = mesh.getCornerIndex(neighbour_tetra_index, 2);
|
|
58
|
+
const d = mesh.getCornerIndex(neighbour_tetra_index, 3);
|
|
59
|
+
|
|
60
|
+
// check neighbour
|
|
61
|
+
const is_in_sphere = point_in_tetrahedron_circumsphere(points, a, b, c, d, containing_tetra);
|
|
62
|
+
|
|
63
|
+
if (is_in_sphere) {
|
|
64
|
+
open_set.push(neighbour_tetra_index);
|
|
65
|
+
} else {
|
|
66
|
+
// move directly to closed set
|
|
67
|
+
closed_set.push(neighbour_tetra_index);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { orient3d_fast } from "../../plane/orient3d_fast.js";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Walk from a given tetrahedron in the mesh towards tetrahedron that contains input point
|
|
5
|
+
* This is an essential method for incrementally finding the next tetrahedron for cavity computation
|
|
6
|
+
*
|
|
7
|
+
* @see https://git.immc.ucl.ac.be/hextreme/hxt_seqdel/-/blob/master/src/hxt_tetrahedra.c#L330
|
|
8
|
+
* @see p3 "One machine, one minute, three billion tetrahedra" by Célestin Marot, Jeanne Pellerin, Jean-François Remacle
|
|
9
|
+
* @param {TetrahedralMesh} mesh
|
|
10
|
+
* @param {number[]} points
|
|
11
|
+
* @param {number} current_tet
|
|
12
|
+
* @param {number} current_vertex
|
|
13
|
+
* @returns {number}
|
|
14
|
+
*/
|
|
15
|
+
function tetrahedral_mesh_walk_toward_cavity(mesh, points, current_tet, current_vertex) {
|
|
16
|
+
|
|
17
|
+
let entering_face = 4;
|
|
18
|
+
|
|
19
|
+
let curTet = current_tet;
|
|
20
|
+
|
|
21
|
+
while (true) {
|
|
22
|
+
|
|
23
|
+
let i;
|
|
24
|
+
for (i = 0; i < 4; i++) {
|
|
25
|
+
|
|
26
|
+
// we walk whenever the volume is positive
|
|
27
|
+
const a_i = (i + 1) & 3;
|
|
28
|
+
const b_i = (i & 2) ^ 3;
|
|
29
|
+
const c_i = (i + 3) & 2;
|
|
30
|
+
|
|
31
|
+
const a_index = mesh.getCornerIndex(curTet, a_i);
|
|
32
|
+
const b_index = mesh.getCornerIndex(curTet, b_i);
|
|
33
|
+
const c_index = mesh.getCornerIndex(curTet, c_i);
|
|
34
|
+
|
|
35
|
+
if (i !== entering_face && orient3d_fast(points, a_index, b_index, c_index, current_vertex) < 0.0) {
|
|
36
|
+
const neighbour = mesh.getNeighbour(curTet, i);
|
|
37
|
+
curTet = neighbour >> 2;
|
|
38
|
+
entering_face = neighbour & 3;
|
|
39
|
+
break;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
if (i === 4) {
|
|
44
|
+
return curTet;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
}
|