@woosh/meep-engine 2.37.20 → 2.38.2
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/collection/array/array_get_index_in_range.js +16 -0
- package/{engine/navigation/grid → core/collection/heap}/BinaryHeap.js +6 -1
- package/{engine/navigation/grid → core/collection/heap}/FastBinaryHeap.js +3 -2
- package/{engine/navigation/grid → core/collection/heap}/FastBinaryHeap.spec.js +3 -3
- package/core/collection/heap/Uin32Heap.spec.js +59 -0
- package/core/collection/heap/Uint32Heap.js +385 -0
- package/core/geom/3d/topology/computeTopoMeshVertexDuplicates.js +9 -6
- package/core/geom/3d/topology/expandConnectivityByLocality.js +5 -5
- package/core/geom/3d/topology/query/query_edge_is_boundary.js +7 -0
- package/core/geom/3d/topology/query/query_edge_is_manifold.js +13 -0
- package/core/geom/3d/topology/query/query_edge_is_manifold_or_boundary.js +11 -0
- package/core/geom/3d/topology/query/query_edge_is_wire.js +13 -0
- package/core/geom/3d/topology/query/query_edge_other_vertex.js +20 -0
- package/core/geom/3d/topology/query/query_edge_share_vert.js +9 -0
- package/core/geom/3d/topology/query/query_face_get_other_edges.js +39 -0
- package/core/geom/3d/topology/query/query_face_next_vertex.js +19 -0
- package/core/geom/3d/topology/query/query_face_prev_vertex.js +18 -0
- package/core/geom/3d/topology/query/query_vertex_in_edge.js +14 -0
- package/core/geom/3d/topology/query/query_vertex_pair_share_face.js +24 -0
- package/core/geom/3d/topology/query/query_vertices_in_edge.js +19 -0
- package/core/geom/3d/topology/simplify/collapseEdge.spec.js +3 -5
- package/core/geom/3d/topology/simplify/collapse_all_degenerate_edges.js +8 -10
- package/core/geom/3d/topology/simplify/compute_face_normal_change_dot_product.js +12 -2
- package/core/geom/3d/topology/simplify/decimate_edge_collapse_snap.js +277 -0
- package/core/geom/3d/topology/simplify/edge_collapse_quadratic.js +126 -0
- package/core/geom/3d/topology/simplify/prototypeMeshSimplification.js +502 -0
- package/core/geom/3d/topology/simplify/quadratic/Quadratic3.js +37 -5
- package/core/geom/3d/topology/simplify/quadratic/build_vertex_quadratics.js +86 -1
- package/core/geom/3d/topology/simplify/simplifyTopoMesh.js +4 -4
- package/core/geom/3d/topology/simplify/simplifyTopoMesh2.js +119 -0
- package/core/geom/3d/topology/simplify/tm_edge_collapse_is_degenerate_flip.js +81 -0
- package/core/geom/3d/topology/{TopoEdge.js → struct/TopoEdge.js} +47 -20
- package/core/geom/3d/topology/{TopoEdge.spec.js → struct/TopoEdge.spec.js} +0 -0
- package/core/geom/3d/topology/{TopoMesh.js → struct/TopoMesh.js} +20 -41
- package/core/geom/3d/topology/{TopoTriangle.js → struct/TopoTriangle.js} +15 -25
- package/core/geom/3d/topology/{TopoVertex.js → struct/TopoVertex.js} +21 -4
- package/core/geom/3d/topology/{TopoVertex.spec.js → struct/TopoVertex.spec.js} +0 -0
- package/core/geom/3d/topology/tm_edge_kill.js +24 -0
- package/core/geom/3d/topology/tm_edge_splice.js +42 -0
- package/core/geom/3d/topology/tm_face_area.js +18 -0
- package/core/geom/3d/topology/tm_face_kill.js +12 -0
- package/core/geom/3d/topology/tm_face_normal.js +14 -0
- package/core/geom/3d/topology/tm_kill_only_edge.js +35 -0
- package/core/geom/3d/topology/tm_kill_only_face.js +12 -0
- package/core/geom/3d/topology/tm_kill_only_vert.js +14 -0
- package/core/geom/3d/topology/tm_vert_kill.js +19 -0
- package/core/geom/3d/topology/tm_vert_splice.js +64 -0
- package/core/geom/3d/topology/tm_vertex_compute_normal.js +42 -0
- package/core/geom/3d/topology/topoMeshToBufferGeometry.js +18 -4
- package/core/geom/3d/topology/weld_duplicate_vertices.js +63 -0
- package/core/geom/packing/MaxRectangles.js +1 -1
- package/core/graph/cluster_mesh_metis.js +16 -0
- package/core/graph/coarsen_graph.js +1 -1
- package/core/graph/graph_k_means_cluster.js +1 -1
- package/core/math/random/seededRandom.js +2 -31
- package/core/math/random/seededRandom_Mulberry32.js +31 -0
- package/core/math/random/seededRandom_sine.js +33 -0
- package/editor/view/node-graph/NodeGraphView.js +2 -2
- package/editor/view/node-graph/NodeView.js +7 -9
- package/engine/ecs/parent/ParentEntitySystem.js +57 -0
- package/engine/ecs/terrain/util/tensionOptimizeUV.js +1 -1
- package/engine/graphics/ecs/mesh-v2/sg_hierarchy_compute_bounding_box_via_parent_entity.d.ts +4 -0
- package/engine/graphics/ecs/mesh-v2/sg_hierarchy_compute_bounding_box_via_parent_entity.js +31 -0
- package/engine/graphics/ecs/sprite/prototypeSpriteSystem.js +4 -0
- package/engine/graphics/micron/build/PatchRepresentation.js +7 -3
- package/engine/graphics/micron/build/buildMicronGeometryFromBufferGeometry.js +14 -8
- package/engine/graphics/micron/build/clustering/build_clustering_2.js +1 -1
- package/engine/graphics/micron/build/clustering/build_leaf_patches.js +2 -2
- package/engine/graphics/micron/build/clustering/build_leaf_patches_metis.js +1 -1
- package/engine/graphics/micron/build/hierarchy/buildAbstractPatchHierarchy.js +21 -3
- package/engine/graphics/micron/build/hierarchy/merge_patches.js +96 -43
- package/engine/graphics/micron/build/hierarchy/qvdr_build_simplified_clusters.js +11 -5
- package/engine/graphics/micron/format/VirtualGeometry.js +46 -3
- package/engine/graphics/micron/format/micron_build_proxy_geometry.js +4 -2
- package/engine/graphics/micron/prototypeVirtualGeometry.js +45 -8
- package/engine/graphics/micron/render/instanced/shader/shader_rewrite_standard.js +2 -2
- package/engine/graphics/micron/render/refinement/get_geometry_patch_cut.js +15 -3
- package/engine/graphics/micron/simplifyGeometry.js +1 -1
- package/engine/input/devices/PointerDevice.d.ts +1 -1
- package/engine/input/devices/PointerDevice.js +17 -2
- package/engine/navigation/grid/AStar.js +1 -1
- package/engine/navigation/grid/GridField.js +3 -2
- package/engine/ui/DraggableAspect.js +2 -2
- package/generation/grid/generation/discrete/GridTaskConnectRooms.js +1 -1
- package/generation/grid/generation/discrete/layer/GridTaskBuildSourceDistanceMap.js +1 -1
- package/generation/grid/generation/discrete/layer/GridTaskDistanceToMarkers.js +1 -1
- package/generation/grid/generation/road/GridTaskGenerateRoads.js +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @template T
|
|
3
|
+
* @param {T[]} array
|
|
4
|
+
* @param {T} needle
|
|
5
|
+
* @param {number} min_index
|
|
6
|
+
* @param {number} max_index
|
|
7
|
+
*/
|
|
8
|
+
export function array_get_index_in_range(array, needle, min_index, max_index) {
|
|
9
|
+
for (let i = min_index; i <= max_index; i++) {
|
|
10
|
+
if (array[i] === needle) {
|
|
11
|
+
return i;
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
return -1;
|
|
16
|
+
}
|
|
@@ -1,3 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @deprecated use {@link FastBinaryHeap} instead
|
|
3
|
+
* @param scoreFunction
|
|
4
|
+
* @constructor
|
|
5
|
+
*/
|
|
1
6
|
function BinaryHeap(scoreFunction) {
|
|
2
7
|
this.content = [];
|
|
3
8
|
this.hash = [];
|
|
@@ -99,7 +104,7 @@ BinaryHeap.prototype = {
|
|
|
99
104
|
element = content[n],
|
|
100
105
|
elemScore = scoreFunction(element);
|
|
101
106
|
|
|
102
|
-
for (
|
|
107
|
+
for (; ;) {
|
|
103
108
|
// Compute the indices of the child elements.
|
|
104
109
|
const child2N = (n + 1) << 1,
|
|
105
110
|
child1N = child2N - 1;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { assert } from "
|
|
1
|
+
import { assert } from "../../assert.js";
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* Min-Heap implementation with a score function. The data structure is a binary heap where elements are removed in order defined by scoring function
|
|
@@ -6,7 +6,8 @@ import { assert } from "../../../core/assert.js";
|
|
|
6
6
|
*/
|
|
7
7
|
class BinaryHeap {
|
|
8
8
|
/**
|
|
9
|
-
* @
|
|
9
|
+
* @template T
|
|
10
|
+
* @param {function(el:T):number} scoreFunction
|
|
10
11
|
* @constructor
|
|
11
12
|
*/
|
|
12
13
|
constructor(scoreFunction) {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { seededRandom } from "
|
|
1
|
+
import { seededRandom } from "../../math/random/seededRandom.js";
|
|
2
2
|
import BinaryHeap from "./FastBinaryHeap.js";
|
|
3
|
-
import { passThrough, returnZero } from "
|
|
4
|
-
import { randomIntegerBetween } from "
|
|
3
|
+
import { passThrough, returnZero } from "../../function/Functions.js";
|
|
4
|
+
import { randomIntegerBetween } from "../../math/random/randomIntegerBetween.js";
|
|
5
5
|
|
|
6
6
|
test("constructor doesn't throw", () => {
|
|
7
7
|
new BinaryHeap(returnZero);
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { Uint32Heap } from "./Uint32Heap.js";
|
|
2
|
+
|
|
3
|
+
test('initial capacity setting via constructor', () => {
|
|
4
|
+
const heap = new Uint32Heap(3);
|
|
5
|
+
|
|
6
|
+
expect(heap.capacity).toBe(3);
|
|
7
|
+
});
|
|
8
|
+
|
|
9
|
+
test('heap capacity grows as needed', () => {
|
|
10
|
+
const heap = new Uint32Heap(0);
|
|
11
|
+
|
|
12
|
+
heap.insert(1, 1);
|
|
13
|
+
|
|
14
|
+
expect(heap.capacity).toBeGreaterThanOrEqual(1);
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
test('initial heap size is 0', () => {
|
|
18
|
+
const heap = new Uint32Heap();
|
|
19
|
+
|
|
20
|
+
expect(heap.size).toBe(0);
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
test('insert operation increases size by 1', () => {
|
|
24
|
+
const heap = new Uint32Heap();
|
|
25
|
+
|
|
26
|
+
const s0 = heap.size;
|
|
27
|
+
|
|
28
|
+
heap.insert(0, 0);
|
|
29
|
+
|
|
30
|
+
expect(heap.size).toBe(s0 + 1);
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
test('pop operation reduces size by 1', () => {
|
|
34
|
+
const heap = new Uint32Heap();
|
|
35
|
+
|
|
36
|
+
heap.insert(0, 0);
|
|
37
|
+
|
|
38
|
+
const s0 = heap.size;
|
|
39
|
+
|
|
40
|
+
heap.pop_min();
|
|
41
|
+
|
|
42
|
+
expect(heap.size).toBe(s0 - 1);
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
test('insert 5 out of order, retrieve in order', () => {
|
|
46
|
+
const heap = new Uint32Heap();
|
|
47
|
+
|
|
48
|
+
heap.insert(3, 4);
|
|
49
|
+
heap.insert(5, 5);
|
|
50
|
+
heap.insert(7, 2);
|
|
51
|
+
heap.insert(11, 3);
|
|
52
|
+
heap.insert(13, 1);
|
|
53
|
+
|
|
54
|
+
expect(heap.pop_min()).toBe(13);
|
|
55
|
+
expect(heap.pop_min()).toBe(7);
|
|
56
|
+
expect(heap.pop_min()).toBe(11);
|
|
57
|
+
expect(heap.pop_min()).toBe(3);
|
|
58
|
+
expect(heap.pop_min()).toBe(5);
|
|
59
|
+
});
|
|
@@ -0,0 +1,385 @@
|
|
|
1
|
+
import { assert } from "../../assert.js";
|
|
2
|
+
import { max2 } from "../../math/max2.js";
|
|
3
|
+
|
|
4
|
+
const UINT32_MAX = 4294967295;
|
|
5
|
+
|
|
6
|
+
const DEFAULT_CAPACITY = 64;
|
|
7
|
+
const ELEMENT_BYTE_SIZE = 8;
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* % to increase capacity by when growing
|
|
11
|
+
* NOTE: Must be greater than 1
|
|
12
|
+
* @type {number}
|
|
13
|
+
*/
|
|
14
|
+
const RESIZE_GROW_FACTOR = 1.2;
|
|
15
|
+
/**
|
|
16
|
+
* Minimum number of elements to expand the size by when growing
|
|
17
|
+
* NOTE: Must be an integer
|
|
18
|
+
* NOTE: Must be greater than 0
|
|
19
|
+
* @type {number}
|
|
20
|
+
*/
|
|
21
|
+
const RESIZE_GROW_MIN_COUNT = 16;
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
*
|
|
25
|
+
* @param {number} i
|
|
26
|
+
* @returns {number}
|
|
27
|
+
*/
|
|
28
|
+
function HEAP_PARENT(i) {
|
|
29
|
+
return ((i) - 1) >> 1;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
*
|
|
34
|
+
* @param {number} i
|
|
35
|
+
* @returns {number}
|
|
36
|
+
*/
|
|
37
|
+
function HEAP_LEFT(i) {
|
|
38
|
+
return ((i) << 1) + 1;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
*
|
|
43
|
+
* @param {number} i
|
|
44
|
+
* @returns {number}
|
|
45
|
+
*/
|
|
46
|
+
function HEAP_RIGHT(i) {
|
|
47
|
+
return ((i) << 1) + 2;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Binary Heap implementation that stores uin32 ID along with a floating point score value
|
|
52
|
+
* Inspired by Blender's heap implementation found here: https://github.com/blender/blender/blob/594f47ecd2d5367ca936cf6fc6ec8168c2b360d0/source/blender/blenlib/intern/BLI_heap.c
|
|
53
|
+
*/
|
|
54
|
+
export class Uint32Heap {
|
|
55
|
+
/**
|
|
56
|
+
*
|
|
57
|
+
* @param {number} [capacity] Can supply initial capacity, heap will still grow when necessary. This allows to prevent needless re-allocations when max heap size is known in advance
|
|
58
|
+
*/
|
|
59
|
+
constructor(capacity = DEFAULT_CAPACITY) {
|
|
60
|
+
assert.isNonNegativeInteger(capacity, 'capacity');
|
|
61
|
+
|
|
62
|
+
this.__data_buffer = new ArrayBuffer(capacity * ELEMENT_BYTE_SIZE);
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Used to access stored IDs
|
|
66
|
+
* @type {Uint32Array}
|
|
67
|
+
* @private
|
|
68
|
+
*/
|
|
69
|
+
this.__data_uint32 = new Uint32Array(this.__data_buffer);
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* Used to access stored Score values
|
|
73
|
+
* @type {Float32Array}
|
|
74
|
+
* @private
|
|
75
|
+
*/
|
|
76
|
+
this.__data_float32 = new Float32Array(this.__data_buffer);
|
|
77
|
+
|
|
78
|
+
this.__capacity = capacity;
|
|
79
|
+
this.__size = 0;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
*
|
|
84
|
+
* @private
|
|
85
|
+
*/
|
|
86
|
+
__capacity_grow() {
|
|
87
|
+
const old_capacity = this.__capacity;
|
|
88
|
+
|
|
89
|
+
const new_capacity = max2(
|
|
90
|
+
old_capacity * RESIZE_GROW_FACTOR,
|
|
91
|
+
old_capacity + RESIZE_GROW_MIN_COUNT
|
|
92
|
+
);
|
|
93
|
+
|
|
94
|
+
assert.greaterThan(new_capacity, old_capacity, 'invalid growth');
|
|
95
|
+
|
|
96
|
+
const new_buffer = new ArrayBuffer(new_capacity * ELEMENT_BYTE_SIZE);
|
|
97
|
+
const new_uint32 = new Uint32Array(new_buffer);
|
|
98
|
+
|
|
99
|
+
// copy old data into new container
|
|
100
|
+
new_uint32.set(this.__data_uint32);
|
|
101
|
+
|
|
102
|
+
this.__data_buffer = new_buffer;
|
|
103
|
+
this.__data_uint32 = new_uint32;
|
|
104
|
+
this.__data_float32 = new Float32Array(new_buffer);
|
|
105
|
+
|
|
106
|
+
// update capacity
|
|
107
|
+
this.__capacity = new_capacity;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* @private
|
|
112
|
+
* @param {number} a index of an element
|
|
113
|
+
* @param {number} b index of an element
|
|
114
|
+
* @returns {boolean}
|
|
115
|
+
*/
|
|
116
|
+
compare(a, b) {
|
|
117
|
+
const float32 = this.__data_float32;
|
|
118
|
+
|
|
119
|
+
return float32[a * 2] < float32[b * 2];
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
/**
|
|
123
|
+
* Swap two elements
|
|
124
|
+
* @private
|
|
125
|
+
* @param {number} i element index
|
|
126
|
+
* @param {number} j element index
|
|
127
|
+
*/
|
|
128
|
+
swap(i, j) {
|
|
129
|
+
const i2 = i * 2;
|
|
130
|
+
const j2 = j * 2;
|
|
131
|
+
|
|
132
|
+
const uint32 = this.__data_uint32;
|
|
133
|
+
|
|
134
|
+
const mem_0 = uint32[i2];
|
|
135
|
+
uint32[i2] = uint32[j2];
|
|
136
|
+
uint32[j2] = mem_0;
|
|
137
|
+
|
|
138
|
+
const mem_1 = uint32[i2 + 1];
|
|
139
|
+
uint32[i2 + 1] = uint32[j2 + 1];
|
|
140
|
+
uint32[j2 + 1] = mem_1;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
/**
|
|
144
|
+
* @private
|
|
145
|
+
* @param {number} index
|
|
146
|
+
*/
|
|
147
|
+
heap_down(index) {
|
|
148
|
+
let i = index;
|
|
149
|
+
|
|
150
|
+
// size does not change, cache it for performance
|
|
151
|
+
const size = this.__size;
|
|
152
|
+
|
|
153
|
+
while (true) {
|
|
154
|
+
const l = ((i) << 1) + 1;
|
|
155
|
+
const r = l + 1;
|
|
156
|
+
|
|
157
|
+
let smallest = i;
|
|
158
|
+
|
|
159
|
+
if (l < size && this.compare(l, smallest)) {
|
|
160
|
+
smallest = l;
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
if (r < size && this.compare(r, smallest)) {
|
|
164
|
+
smallest = r;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
if (smallest === i) {
|
|
168
|
+
break;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
this.swap(i, smallest);
|
|
172
|
+
|
|
173
|
+
i = smallest;
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
/**
|
|
179
|
+
* Bubble up given element into its correct position
|
|
180
|
+
* @private
|
|
181
|
+
* @param {number} index
|
|
182
|
+
*/
|
|
183
|
+
heap_up(index) {
|
|
184
|
+
let i = index;
|
|
185
|
+
|
|
186
|
+
while (i > 0) {
|
|
187
|
+
// get parent
|
|
188
|
+
const p = ((i) - 1) >> 1;
|
|
189
|
+
|
|
190
|
+
if (this.compare(p, i)) {
|
|
191
|
+
break;
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
this.swap(p, i);
|
|
195
|
+
|
|
196
|
+
i = p;
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
/**
|
|
201
|
+
*
|
|
202
|
+
* @returns {number}
|
|
203
|
+
*/
|
|
204
|
+
get size() {
|
|
205
|
+
return this.__size;
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
/**
|
|
209
|
+
*
|
|
210
|
+
* @returns {number}
|
|
211
|
+
*/
|
|
212
|
+
get capacity() {
|
|
213
|
+
return this.__capacity;
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
/**
|
|
217
|
+
* Node with the lowest score
|
|
218
|
+
* @returns {number}
|
|
219
|
+
*/
|
|
220
|
+
get top_id() {
|
|
221
|
+
return this.__data_uint32[1];
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
/**
|
|
225
|
+
*
|
|
226
|
+
* @returns {boolean}
|
|
227
|
+
*/
|
|
228
|
+
is_empty() {
|
|
229
|
+
return this.__size === 0;
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
pop_min() {
|
|
233
|
+
assert.greaterThan(this.__size, 0, 'heap is empty');
|
|
234
|
+
|
|
235
|
+
const result = this.top_id;
|
|
236
|
+
|
|
237
|
+
this.__size--;
|
|
238
|
+
|
|
239
|
+
if (this.__size > 0) {
|
|
240
|
+
// move top element to the bottom
|
|
241
|
+
this.swap(0, this.__size);
|
|
242
|
+
|
|
243
|
+
// rebalance
|
|
244
|
+
this.heap_down(0);
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
return result;
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
/**
|
|
251
|
+
*
|
|
252
|
+
* @param {number} id
|
|
253
|
+
* @returns {number}
|
|
254
|
+
*/
|
|
255
|
+
find_index_by_id(id) {
|
|
256
|
+
const n = this.__size
|
|
257
|
+
const n2 = n * 2;
|
|
258
|
+
|
|
259
|
+
const uint32 = this.__data_uint32;
|
|
260
|
+
|
|
261
|
+
for (let address = 1; address < n2; address += 2) {
|
|
262
|
+
const _id = uint32[address];
|
|
263
|
+
|
|
264
|
+
if (_id === id) {
|
|
265
|
+
return (address >>> 1);
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
// not found
|
|
270
|
+
return -1;
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
|
|
274
|
+
/**
|
|
275
|
+
*
|
|
276
|
+
* @param {number} id
|
|
277
|
+
*/
|
|
278
|
+
remove(id) {
|
|
279
|
+
const i = this.find_index_by_id(id);
|
|
280
|
+
|
|
281
|
+
if (i !== -1) {
|
|
282
|
+
this.__remove_by_index(i);
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
/**
|
|
287
|
+
*
|
|
288
|
+
* @param {number} index
|
|
289
|
+
*/
|
|
290
|
+
__remove_by_index(index) {
|
|
291
|
+
assert.greaterThan(this.__size, 0, 'heap is empty');
|
|
292
|
+
|
|
293
|
+
let i = index;
|
|
294
|
+
|
|
295
|
+
while (i > 0) {
|
|
296
|
+
const p = HEAP_PARENT(i);
|
|
297
|
+
this.swap(p, i);
|
|
298
|
+
|
|
299
|
+
i = p;
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
this.pop_min();
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
/**
|
|
306
|
+
*
|
|
307
|
+
* @param {number} id
|
|
308
|
+
* @param {number} score
|
|
309
|
+
*/
|
|
310
|
+
update_score(id, score) {
|
|
311
|
+
const index = this.find_index_by_id(id);
|
|
312
|
+
|
|
313
|
+
if (index === -1) {
|
|
314
|
+
throw new Error('Not found');
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
this.__update_score_by_index(index, score);
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
/**
|
|
321
|
+
*
|
|
322
|
+
* @param {number} index
|
|
323
|
+
* @param {number} score
|
|
324
|
+
*/
|
|
325
|
+
__update_score_by_index(index, score) {
|
|
326
|
+
|
|
327
|
+
const float32 = this.__data_float32;
|
|
328
|
+
const index2 = index * 2;
|
|
329
|
+
const existing_score = float32[index2];
|
|
330
|
+
|
|
331
|
+
if (score < existing_score) {
|
|
332
|
+
float32[index2] = score;
|
|
333
|
+
this.heap_up(index);
|
|
334
|
+
} else if (score > existing_score) {
|
|
335
|
+
float32[index2] = score;
|
|
336
|
+
this.heap_down(index);
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
|
|
341
|
+
/**
|
|
342
|
+
*
|
|
343
|
+
* @param {number} id
|
|
344
|
+
* @param {number} score
|
|
345
|
+
*/
|
|
346
|
+
insert_or_update(id, score) {
|
|
347
|
+
const i = this.find_index_by_id(id);
|
|
348
|
+
|
|
349
|
+
if (i === -1) {
|
|
350
|
+
this.insert(id, score);
|
|
351
|
+
} else {
|
|
352
|
+
this.__update_score_by_index(i, score);
|
|
353
|
+
}
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
/**
|
|
357
|
+
*
|
|
358
|
+
* @param {number} id
|
|
359
|
+
* @param {number} score
|
|
360
|
+
*/
|
|
361
|
+
insert(id, score) {
|
|
362
|
+
assert.isNonNegativeInteger(id, 'value');
|
|
363
|
+
assert.lessThanOrEqual(id, UINT32_MAX - 1, 'must be less than or equal to (2^32 - 2)');
|
|
364
|
+
|
|
365
|
+
if (this.__size >= this.__capacity) {
|
|
366
|
+
// need to re-allocate
|
|
367
|
+
this.__capacity_grow();
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
// insert at the end
|
|
371
|
+
const index = this.__size;
|
|
372
|
+
const address = index * 2;
|
|
373
|
+
|
|
374
|
+
// write data
|
|
375
|
+
this.__data_float32[address] = score;
|
|
376
|
+
this.__data_uint32[address + 1] = id;
|
|
377
|
+
|
|
378
|
+
// record increased size
|
|
379
|
+
this.__size++;
|
|
380
|
+
|
|
381
|
+
this.heap_up(index);
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
|
|
385
|
+
}
|
|
@@ -5,11 +5,12 @@ import { mortonEncode_magicbits } from "../morton/mortonEncode_magicbits.js";
|
|
|
5
5
|
*
|
|
6
6
|
* @param {TopoVertex} a
|
|
7
7
|
* @param {TopoVertex} b
|
|
8
|
+
* @param {number} tolerance
|
|
8
9
|
*/
|
|
9
|
-
function isPositionEquivalent(a, b) {
|
|
10
|
-
return epsilonEquals(b.x, a.x,
|
|
11
|
-
&& epsilonEquals(b.y, a.y,
|
|
12
|
-
&& epsilonEquals(b.z, a.z,
|
|
10
|
+
function isPositionEquivalent(a, b, tolerance) {
|
|
11
|
+
return epsilonEquals(b.x, a.x, tolerance)
|
|
12
|
+
&& epsilonEquals(b.y, a.y, tolerance)
|
|
13
|
+
&& epsilonEquals(b.z, a.z, tolerance)
|
|
13
14
|
;
|
|
14
15
|
}
|
|
15
16
|
|
|
@@ -35,8 +36,10 @@ function recordDuplicate(result, a, b) {
|
|
|
35
36
|
*
|
|
36
37
|
* @param {TopoMesh} mesh
|
|
37
38
|
* @param {AABB3} aabb
|
|
39
|
+
* @param {number} tolerance
|
|
40
|
+
* @returns {Map<TopoVertex, TopoVertex[]>}
|
|
38
41
|
*/
|
|
39
|
-
export function computeTopoMeshVertexDuplicates(mesh, aabb) {
|
|
42
|
+
export function computeTopoMeshVertexDuplicates(mesh, aabb, tolerance = EPSILON) {
|
|
40
43
|
const vertices = mesh.vertices;
|
|
41
44
|
|
|
42
45
|
const n = vertices.length;
|
|
@@ -84,7 +87,7 @@ export function computeTopoMeshVertexDuplicates(mesh, aabb) {
|
|
|
84
87
|
*/
|
|
85
88
|
const vertex_b = spatial_bucket[j];
|
|
86
89
|
|
|
87
|
-
if (isPositionEquivalent(vertex_a, vertex_b)) {
|
|
90
|
+
if (isPositionEquivalent(vertex_a, vertex_b, tolerance)) {
|
|
88
91
|
// same coordinates
|
|
89
92
|
recordDuplicate(result, vertex_a, vertex_b);
|
|
90
93
|
recordDuplicate(result, vertex_b, vertex_a);
|
|
@@ -76,16 +76,16 @@ export function expandConnectivityByLocality(mesh, aabb) {
|
|
|
76
76
|
|
|
77
77
|
let j;
|
|
78
78
|
|
|
79
|
-
for (let
|
|
79
|
+
for (let edge of edges) {
|
|
80
80
|
|
|
81
|
-
const duplicate_v0s = vertex_duplicates.get(
|
|
81
|
+
const duplicate_v0s = vertex_duplicates.get(edge.v0);
|
|
82
82
|
|
|
83
83
|
if (duplicate_v0s === undefined) {
|
|
84
84
|
// no duplicate vertices, edge is unique
|
|
85
85
|
continue;
|
|
86
86
|
}
|
|
87
87
|
|
|
88
|
-
const duplicate_v1s = vertex_duplicates.get(
|
|
88
|
+
const duplicate_v1s = vertex_duplicates.get(edge.v1);
|
|
89
89
|
|
|
90
90
|
if (duplicate_v1s === undefined) {
|
|
91
91
|
// no duplicate vertices, edge is unique
|
|
@@ -95,8 +95,8 @@ export function expandConnectivityByLocality(mesh, aabb) {
|
|
|
95
95
|
const n = findCommonDuplicateEdges(duplicate_edges, duplicate_v0s, duplicate_v1s);
|
|
96
96
|
|
|
97
97
|
for (j = 0; j < n; j++) {
|
|
98
|
-
const
|
|
99
|
-
connectEdges(
|
|
98
|
+
const duplicate_edge = duplicate_edges[j];
|
|
99
|
+
connectEdges(edge, duplicate_edge);
|
|
100
100
|
}
|
|
101
101
|
}
|
|
102
102
|
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { assert } from "../../../../assert.js";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Tests whether this edge is manifold.
|
|
5
|
+
* A manifold edge has exactly 2 faces attached to it.
|
|
6
|
+
* @param {TopoEdge} edge
|
|
7
|
+
* @returns {boolean}
|
|
8
|
+
*/
|
|
9
|
+
export function query_edge_is_manifold(edge) {
|
|
10
|
+
assert.notNull(edge, 'edge');
|
|
11
|
+
return edge.faces.length === 2;
|
|
12
|
+
}
|
|
13
|
+
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { query_edge_is_boundary } from "./query_edge_is_boundary.js";
|
|
2
|
+
import { query_edge_is_manifold } from "./query_edge_is_manifold.js";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
*
|
|
6
|
+
* @param {TopoEdge} edge
|
|
7
|
+
* @returns {boolean}
|
|
8
|
+
*/
|
|
9
|
+
export function query_edge_is_manifold_or_boundary(edge) {
|
|
10
|
+
return query_edge_is_manifold(edge) || query_edge_is_boundary(edge);
|
|
11
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { assert } from "../../../../assert.js";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
*
|
|
5
|
+
* @param {TopoEdge} edge
|
|
6
|
+
* @returns {boolean}
|
|
7
|
+
*/
|
|
8
|
+
export function query_edge_is_wire(edge) {
|
|
9
|
+
assert.notNull(edge, 'edge');
|
|
10
|
+
|
|
11
|
+
const faces = edge.faces;
|
|
12
|
+
return faces.length === 0;
|
|
13
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { assert } from "../../../../assert.js";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Given a vertex, returns other vertex on the edge
|
|
5
|
+
* @param {TopoEdge} edge
|
|
6
|
+
* @param {TopoVertex} v
|
|
7
|
+
* @returns {TopoVertex|null}
|
|
8
|
+
*/
|
|
9
|
+
export function query_edge_other_vertex(edge, v) {
|
|
10
|
+
assert.notNull(edge, 'edge');
|
|
11
|
+
assert.notNull(v, 'v');
|
|
12
|
+
|
|
13
|
+
if (edge.v0 === v) {
|
|
14
|
+
return edge.v1;
|
|
15
|
+
} else if (edge.v1 === v) {
|
|
16
|
+
return edge.v0;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
return null;
|
|
20
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { assert } from "../../../../assert.js";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
*
|
|
5
|
+
* @param {TopoEdge[]} result
|
|
6
|
+
* @param {number} result_offset
|
|
7
|
+
* @param {TopoTriangle} face
|
|
8
|
+
* @param {TopoEdge} edge
|
|
9
|
+
*/
|
|
10
|
+
export function query_face_get_other_edges(result, result_offset, face, edge) {
|
|
11
|
+
|
|
12
|
+
let a, b;
|
|
13
|
+
|
|
14
|
+
const edges = face.edges;
|
|
15
|
+
|
|
16
|
+
if (edges.length < 3) {
|
|
17
|
+
return false;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
assert.equal(edges.length, 3, `must have 3 edges, instead has ${edges.length}`);
|
|
21
|
+
|
|
22
|
+
if (edges[0] === edge) {
|
|
23
|
+
a = 1;
|
|
24
|
+
b = 2;
|
|
25
|
+
} else if (edges[1] === edge) {
|
|
26
|
+
a = 0;
|
|
27
|
+
b = 2;
|
|
28
|
+
} else if (edges[2] === edge) {
|
|
29
|
+
a = 0;
|
|
30
|
+
b = 1;
|
|
31
|
+
} else {
|
|
32
|
+
throw new Error('Edge not contained in the face');
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
result[result_offset] = edges[a];
|
|
36
|
+
result[result_offset + 1] = edges[b];
|
|
37
|
+
|
|
38
|
+
return true;
|
|
39
|
+
}
|