@woosh/meep-engine 2.43.3 → 2.43.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/core/binary/BinaryBuffer.js +13 -1
- package/core/binary/BitSet.js +2 -2
- package/core/collection/array/array_range_equal_strict.js +22 -0
- package/core/color/sRGB_to_linear.js +9 -4
- package/core/geom/3d/plane/orient3d_fast.js +3 -0
- package/core/geom/3d/plane/orient3d_robust.js +41 -0
- package/core/geom/3d/sphere/harmonics/README.md +15 -0
- package/core/geom/3d/sphere/harmonics/sh3_add.js +21 -0
- package/core/geom/3d/sphere/harmonics/sh3_dering_optimize_positive.js +618 -0
- package/core/geom/3d/sphere/harmonics/sh3_sample_by_direction.js +49 -0
- package/core/geom/3d/sphere/harmonics/sh3_sample_irradiance_by_direction.js +53 -0
- package/core/geom/3d/tetrahedra/TetrahedralMesh.js +251 -68
- package/core/geom/3d/tetrahedra/TetrahedralMesh.spec.js +80 -3
- package/core/geom/3d/tetrahedra/build_tetrahedral_mesh_buffer_geometry.js +75 -0
- package/core/geom/3d/tetrahedra/delaunay/Cavity.js +5 -1
- package/core/geom/3d/tetrahedra/delaunay/compute_delaunay_tetrahedral_mesh.js +30 -31
- package/core/geom/3d/tetrahedra/delaunay/fill_in_a_cavity.js +54 -18
- package/core/geom/3d/tetrahedra/delaunay/push_boundary_with_validation.js +27 -0
- package/core/geom/3d/tetrahedra/delaunay/tetrahedral_mesh_compute_cavity.js +89 -0
- package/core/geom/3d/tetrahedra/delaunay/{tetrahedral_mesh_walk_toward_cavity.js → tetrahedral_mesh_walk_towards_containing_tetrahedron.js} +15 -12
- package/core/geom/3d/tetrahedra/delaunay/validate_cavity_boundary.js +60 -0
- package/core/geom/3d/tetrahedra/{point_in_tetrahedron_circumsphere.js → in_sphere_fast.js} +2 -4
- package/core/geom/3d/tetrahedra/in_sphere_robust.js +53 -0
- package/core/geom/3d/tetrahedra/prototypeTetrahedraBuilder.js +44 -35
- package/core/geom/3d/tetrahedra/validate_tetrahedral_mesh.js +85 -38
- package/core/geom/3d/util/make_justified_point_grid.js +31 -0
- package/core/process/delay.js +5 -0
- package/editor/Editor.js +3 -0
- package/editor/ecs/component/editors/ecs/ParameterLookupTableEditor.js +195 -11
- package/editor/ecs/component/editors/ecs/ParameterTrackSetEditor.js +16 -0
- package/editor/ecs/component/editors/ecs/ParticleEmitterLayerEditor.js +4 -0
- package/engine/EngineHarness.js +11 -5
- package/engine/ecs/terrain/ecs/TerrainSystem.js +7 -1
- package/engine/ecs/transform/copy_three_transform.js +15 -0
- package/engine/graphics/ecs/light/Light.js +6 -1
- package/engine/graphics/ecs/light/LightSystem.d.ts +1 -1
- package/engine/graphics/ecs/mesh-v2/three_object_to_entity_composition.js +2 -17
- package/engine/graphics/geometry/instancing/InstancedMeshGroup.js +2 -2
- package/engine/graphics/sh3/LightProbeVolume.js +595 -0
- package/engine/graphics/sh3/SH3VisualisationMaterial.js +79 -0
- package/engine/graphics/sh3/prototypeSH3Probe.js +427 -0
- package/engine/graphics/sh3/visualise_probe.js +40 -0
- package/engine/graphics/texture/atlas/TextureAtlas.js +15 -3
- package/engine/intelligence/blackboard/AbstractBlackboard.d.ts +1 -1
- package/package.json +2 -1
- package/samples/terrain/from_image_2.js +127 -82
- package/core/geom/3d/tetrahedra/delaunay/tetrahedral_mesh_compute_cavity2.js +0 -224
- package/core/geom/3d/tetrahedra/delaunay/tetrahedral_mesh_insert_point.js +0 -98
|
@@ -7,7 +7,6 @@ import EntityBuilder from "../../engine/ecs/EntityBuilder.js";
|
|
|
7
7
|
import Terrain from "../../engine/ecs/terrain/ecs/Terrain.js";
|
|
8
8
|
import { ImageRGBADataLoader } from "../../engine/asset/loaders/image/ImageRGBADataLoader.js";
|
|
9
9
|
import TerrainSystem from "../../engine/ecs/terrain/ecs/TerrainSystem.js";
|
|
10
|
-
import WaterSystem from "../../engine/graphics/ecs/water/WaterSystem.js";
|
|
11
10
|
import Water from "../../engine/graphics/ecs/water/Water.js";
|
|
12
11
|
import {
|
|
13
12
|
AmbientOcclusionPostProcessEffect
|
|
@@ -16,73 +15,42 @@ import { TerrainLayer } from "../../engine/ecs/terrain/ecs/layers/TerrainLayer.j
|
|
|
16
15
|
import Mesh from "../../engine/graphics/ecs/mesh/Mesh.js";
|
|
17
16
|
import { Transform } from "../../engine/ecs/transform/Transform.js";
|
|
18
17
|
import { MeshSystem } from "../../engine/graphics/ecs/mesh/MeshSystem.js";
|
|
19
|
-
import
|
|
20
|
-
import "
|
|
21
|
-
import '../../../../../css/editor/EntityEditorView.scss';
|
|
22
|
-
import '../../../../../css/editor/EditorView.scss';
|
|
23
|
-
import { initializeEditor } from "../../../model/game/initializeEditor.js";
|
|
18
|
+
import ButtonView from "../../view/elements/button/ButtonView.js";
|
|
19
|
+
import { downloadAsFile } from "../../core/binary/ByteArrayTools.js";
|
|
24
20
|
|
|
25
21
|
const HEIGHT_RANGE = 64;
|
|
26
22
|
|
|
27
23
|
const eh = new EngineHarness();
|
|
28
24
|
|
|
29
|
-
/**
|
|
30
|
-
*
|
|
31
|
-
* @param {Engine} engine
|
|
32
|
-
* @return {EngineConfiguration}
|
|
33
|
-
*/
|
|
34
|
-
function makeConfig(engine) {
|
|
35
|
-
const r = new EngineConfiguration();
|
|
36
|
-
|
|
37
|
-
// configure engine here, add systems, loaders etc.
|
|
38
|
-
r.addLoader(GameAssetType.Texture, new TextureAssetLoader());
|
|
39
|
-
r.addLoader(GameAssetType.Image, new ImageRGBADataLoader());
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
r.addSystem(new TerrainSystem(engine.graphics, engine.assetManager));
|
|
43
|
-
r.addSystem(new WaterSystem(engine.graphics));
|
|
44
|
-
r.addSystem(new MeshSystem(engine));
|
|
45
|
-
|
|
46
|
-
r.addPlugin(AmbientOcclusionPostProcessEffect);
|
|
47
|
-
|
|
48
|
-
return r;
|
|
49
|
-
}
|
|
50
25
|
|
|
51
26
|
/**
|
|
52
27
|
*
|
|
53
|
-
* @param {
|
|
54
|
-
* @param {
|
|
28
|
+
* @param {Sampler2D} source
|
|
29
|
+
* @param {Terrain} terrain
|
|
55
30
|
*/
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
const
|
|
31
|
+
function scale_terrain_heights(source, terrain) {
|
|
32
|
+
const source_height_data = source.data;
|
|
33
|
+
const sampler_pixel_count = source_height_data.length;
|
|
34
|
+
const terrain_height_data = terrain.samplerHeight.data;
|
|
59
35
|
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
36
|
+
let divisor;
|
|
37
|
+
if (source_height_data instanceof Uint8Array) {
|
|
38
|
+
divisor = 255;
|
|
39
|
+
} else if (source_height_data instanceof Uint16Array) {
|
|
40
|
+
divisor = 65536 - 1;
|
|
41
|
+
}
|
|
65
42
|
|
|
66
|
-
|
|
67
|
-
|
|
43
|
+
for (let i = 0; i < sampler_pixel_count; i++) {
|
|
44
|
+
const source_v = source_height_data[i];
|
|
68
45
|
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
* @param {string} path
|
|
72
|
-
* @param {Engine} engine
|
|
73
|
-
* @param {Transform} transform
|
|
74
|
-
*/
|
|
75
|
-
async function load_gltf(path, engine, transform) {
|
|
76
|
-
const em = engine.entityManager;
|
|
46
|
+
const b0 = source_v & 0xFF;
|
|
47
|
+
const b1 = (source_v >> 8) & 0xFF;
|
|
77
48
|
|
|
78
|
-
|
|
49
|
+
let rotated_v;
|
|
50
|
+
rotated_v = b1 | (b0 << 8);
|
|
79
51
|
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
url: path
|
|
83
|
-
}))
|
|
84
|
-
.add(transform)
|
|
85
|
-
.build(ecd);
|
|
52
|
+
terrain_height_data[i] = (rotated_v / divisor) * HEIGHT_RANGE
|
|
53
|
+
}
|
|
86
54
|
}
|
|
87
55
|
|
|
88
56
|
/**
|
|
@@ -139,43 +107,22 @@ async function main(engine) {
|
|
|
139
107
|
await load_splat_layer("moicon/23_Nov_21_Skogplanter/01/splat_stone.png", 2);
|
|
140
108
|
|
|
141
109
|
terrain.samplerHeight.resize(sampler.width, sampler.height);
|
|
142
|
-
|
|
143
|
-
const sampler_pixel_count = source_height_data.length;
|
|
144
|
-
const terrain_height_data = terrain.samplerHeight.data;
|
|
145
|
-
|
|
146
|
-
let divisor;
|
|
147
|
-
if (source_height_data instanceof Uint8Array) {
|
|
148
|
-
divisor = 255;
|
|
149
|
-
} else if (source_height_data instanceof Uint16Array) {
|
|
150
|
-
divisor = 65536 - 1;
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
for (let i = 0; i < sampler_pixel_count; i++) {
|
|
154
|
-
const source_v = source_height_data[i];
|
|
155
|
-
|
|
156
|
-
const b0 = source_v & 0xFF;
|
|
157
|
-
const b1 = (source_v >> 8) & 0xFF;
|
|
158
|
-
|
|
159
|
-
let rotated_v;
|
|
160
|
-
rotated_v = b1 | (b0 << 8);
|
|
161
|
-
|
|
162
|
-
terrain_height_data[i] = (rotated_v / divisor) * HEIGHT_RANGE
|
|
163
|
-
}
|
|
110
|
+
scale_terrain_heights(sampler, terrain);
|
|
164
111
|
|
|
165
112
|
terrain.layers.resolution.set(1024, 1024);
|
|
166
113
|
|
|
167
114
|
terrain.layers.addLayer(TerrainLayer.from(
|
|
168
|
-
"
|
|
115
|
+
"moicon/23_Nov_21_Skogplanter/01/textures/Grass_2.png",
|
|
169
116
|
20,
|
|
170
117
|
20
|
|
171
118
|
));
|
|
172
119
|
terrain.layers.addLayer(TerrainLayer.from(
|
|
173
|
-
"
|
|
120
|
+
"moicon/23_Nov_21_Skogplanter/01/textures/Ground_1_dark.png",
|
|
174
121
|
20,
|
|
175
122
|
20
|
|
176
123
|
));
|
|
177
124
|
terrain.layers.addLayer(TerrainLayer.from(
|
|
178
|
-
"
|
|
125
|
+
"moicon/23_Nov_21_Skogplanter/01/textures/Sand_01.png",
|
|
179
126
|
20,
|
|
180
127
|
20
|
|
181
128
|
));
|
|
@@ -188,7 +135,8 @@ async function main(engine) {
|
|
|
188
135
|
water.shoreDepthTransition.set(0.1, 0.3);
|
|
189
136
|
water.scattering.set(3);
|
|
190
137
|
|
|
191
|
-
new EntityBuilder()
|
|
138
|
+
const terrain_builder = new EntityBuilder();
|
|
139
|
+
terrain_builder
|
|
192
140
|
.add(terrain)
|
|
193
141
|
// .add(water)
|
|
194
142
|
.build(ecd);
|
|
@@ -204,6 +152,47 @@ async function main(engine) {
|
|
|
204
152
|
load_gltf("moicon/23_Nov_21_Skogplanter/02/model.gltf", engine, transform);
|
|
205
153
|
// load_gltf("moicon/23_Nov_21_Skogplanter/03/model.gltf", engine, transform);
|
|
206
154
|
// load_gltf("moicon/23_Nov_21_Skogplanter/04/model.gltf", engine, transform);
|
|
155
|
+
|
|
156
|
+
engine.gui.view.addChild(new ButtonView({
|
|
157
|
+
name: 'Download',
|
|
158
|
+
action() {
|
|
159
|
+
// we wrap the terrain data into "component json" format that meep editor recognizes to make this compatible with the standalone terrain editor
|
|
160
|
+
const json_payload = {
|
|
161
|
+
type: "Terrain",
|
|
162
|
+
data: terrain.toJSON()
|
|
163
|
+
};
|
|
164
|
+
|
|
165
|
+
downloadAsFile(
|
|
166
|
+
JSON.stringify(json_payload),
|
|
167
|
+
'terrain.json'
|
|
168
|
+
);
|
|
169
|
+
},
|
|
170
|
+
css: {
|
|
171
|
+
bottom: '4px',
|
|
172
|
+
left: '4px',
|
|
173
|
+
position: 'absolute',
|
|
174
|
+
background: 'white',
|
|
175
|
+
border: '1px solid black',
|
|
176
|
+
padding: '2px',
|
|
177
|
+
pointerEvents: 'auto'
|
|
178
|
+
}
|
|
179
|
+
}));
|
|
180
|
+
|
|
181
|
+
engine.gui.view.addChild(new ButtonView({
|
|
182
|
+
name: 'Remove',
|
|
183
|
+
action() {
|
|
184
|
+
engine.entityManager.dataset.removeEntity(terrain_builder.entity);
|
|
185
|
+
},
|
|
186
|
+
css: {
|
|
187
|
+
bottom: '4px',
|
|
188
|
+
left: '104px',
|
|
189
|
+
position: 'absolute',
|
|
190
|
+
background: 'white',
|
|
191
|
+
border: '1px solid black',
|
|
192
|
+
padding: '2px',
|
|
193
|
+
pointerEvents: 'auto'
|
|
194
|
+
}
|
|
195
|
+
}));
|
|
207
196
|
}
|
|
208
197
|
|
|
209
198
|
/**
|
|
@@ -215,11 +204,67 @@ async function init(harness) {
|
|
|
215
204
|
|
|
216
205
|
await makeConfig(engine).apply(engine);
|
|
217
206
|
|
|
218
|
-
enableEditor(engine,initializeEditor);
|
|
219
|
-
|
|
220
207
|
await eh.initialize();
|
|
221
208
|
|
|
222
209
|
main(engine);
|
|
223
210
|
}
|
|
224
211
|
|
|
225
212
|
init(eh);
|
|
213
|
+
|
|
214
|
+
/**
|
|
215
|
+
*
|
|
216
|
+
* @param {Engine} engine
|
|
217
|
+
* @return {EngineConfiguration}
|
|
218
|
+
*/
|
|
219
|
+
function makeConfig(engine) {
|
|
220
|
+
const r = new EngineConfiguration();
|
|
221
|
+
|
|
222
|
+
// configure engine here, add systems, loaders etc.
|
|
223
|
+
r.addLoader(GameAssetType.Texture, new TextureAssetLoader());
|
|
224
|
+
r.addLoader(GameAssetType.Image, new ImageRGBADataLoader());
|
|
225
|
+
|
|
226
|
+
|
|
227
|
+
r.addSystem(new TerrainSystem(engine.graphics, engine.assetManager));
|
|
228
|
+
r.addSystem(new MeshSystem(engine));
|
|
229
|
+
|
|
230
|
+
r.addPlugin(AmbientOcclusionPostProcessEffect);
|
|
231
|
+
|
|
232
|
+
return r;
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
/**
|
|
236
|
+
*
|
|
237
|
+
* @param {string} path
|
|
238
|
+
* @param {AssetManager} am
|
|
239
|
+
*/
|
|
240
|
+
async function load_sampler(path, am) {
|
|
241
|
+
|
|
242
|
+
const asset = await am.promise(path, 'image');
|
|
243
|
+
|
|
244
|
+
/**
|
|
245
|
+
*
|
|
246
|
+
* @type {Sampler2D}
|
|
247
|
+
*/
|
|
248
|
+
const sampler = asset.create();
|
|
249
|
+
|
|
250
|
+
return sampler;
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
/**
|
|
254
|
+
*
|
|
255
|
+
* @param {string} path
|
|
256
|
+
* @param {Engine} engine
|
|
257
|
+
* @param {Transform} transform
|
|
258
|
+
*/
|
|
259
|
+
async function load_gltf(path, engine, transform) {
|
|
260
|
+
const em = engine.entityManager;
|
|
261
|
+
|
|
262
|
+
const ecd = em.dataset;
|
|
263
|
+
|
|
264
|
+
new EntityBuilder()
|
|
265
|
+
.add(Mesh.fromJSON({
|
|
266
|
+
url: path
|
|
267
|
+
}))
|
|
268
|
+
.add(transform)
|
|
269
|
+
.build(ecd);
|
|
270
|
+
}
|
|
@@ -1,224 +0,0 @@
|
|
|
1
|
-
import { assert } from "../../../../assert.js";
|
|
2
|
-
import { point_in_tetrahedron_circumsphere } from "../point_in_tetrahedron_circumsphere.js";
|
|
3
|
-
import { INVALID_NEIGHBOUR } from "../TetrahedralMesh.js";
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
/**
|
|
7
|
-
*
|
|
8
|
-
* @param {Cavity} cavity
|
|
9
|
-
* @param {TetrahedralMesh} mesh
|
|
10
|
-
* @param {number} tet
|
|
11
|
-
* @param {number} point_index
|
|
12
|
-
* @param {number} k0
|
|
13
|
-
* @param {number} k1
|
|
14
|
-
* @param {number} k2
|
|
15
|
-
* @param {number} k3
|
|
16
|
-
*/
|
|
17
|
-
function store_special(cavity, mesh, tet, point_index, k0, k1, k2, k3) {
|
|
18
|
-
|
|
19
|
-
const node_0 = mesh.getVertexIndex(tet, k0);
|
|
20
|
-
const node_1 = mesh.getVertexIndex(tet, k1);
|
|
21
|
-
const node_2 = mesh.getVertexIndex(tet, k2);
|
|
22
|
-
|
|
23
|
-
cavity.push_boundary(
|
|
24
|
-
point_index,
|
|
25
|
-
node_0,
|
|
26
|
-
node_1,
|
|
27
|
-
node_2,
|
|
28
|
-
mesh.getNeighbour(tet, k3),
|
|
29
|
-
);
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
/**
|
|
33
|
-
*
|
|
34
|
-
* @param {TetrahedralMesh} mesh
|
|
35
|
-
* @param {Cavity} cavity
|
|
36
|
-
* @param {number[]|Float32Array} points
|
|
37
|
-
* @param {Float32Array} subdets
|
|
38
|
-
* @param {number} containing_tetra tetrahedron that contains point
|
|
39
|
-
* @param {number} point_index point that forms the cavity
|
|
40
|
-
*/
|
|
41
|
-
export function tetrahedral_mesh_compute_cavity3(
|
|
42
|
-
mesh,
|
|
43
|
-
points,
|
|
44
|
-
subdets,
|
|
45
|
-
cavity,
|
|
46
|
-
containing_tetra,
|
|
47
|
-
point_index
|
|
48
|
-
) {
|
|
49
|
-
assert.isNonNegativeInteger(containing_tetra, 'containing_tetra');
|
|
50
|
-
|
|
51
|
-
// add the tet to cavity
|
|
52
|
-
cavity.push_deleted(containing_tetra);
|
|
53
|
-
subdets[containing_tetra * 4 + 3] = -1;
|
|
54
|
-
|
|
55
|
-
for (let start = cavity.__deleted_size - 1; start < cavity.__deleted_size; start++) {
|
|
56
|
-
const cur_tet = cavity.__deleted[start];
|
|
57
|
-
|
|
58
|
-
for (let i = 0; i < 4; i++) {
|
|
59
|
-
const encoded_neighbour = mesh.getNeighbour(cur_tet, i);
|
|
60
|
-
|
|
61
|
-
const k0 = (1 << i) & 3;
|
|
62
|
-
const k1 = (i + 2) % 3;
|
|
63
|
-
const k2 = (~((i + 1) >> 1) & 2) + 1;
|
|
64
|
-
const k3 = i;
|
|
65
|
-
|
|
66
|
-
if (encoded_neighbour === INVALID_NEIGHBOUR) {
|
|
67
|
-
// no neighbour, include this side into boundary
|
|
68
|
-
|
|
69
|
-
const node_0 = mesh.getVertexIndex(cur_tet, k0);
|
|
70
|
-
const node_1 = mesh.getVertexIndex(cur_tet, k1);
|
|
71
|
-
const node_2 = mesh.getVertexIndex(cur_tet, k2);
|
|
72
|
-
|
|
73
|
-
if(i === 3 || node_2 >= node_1) {
|
|
74
|
-
cavity.push_boundary(
|
|
75
|
-
point_index,
|
|
76
|
-
node_2,
|
|
77
|
-
node_0,
|
|
78
|
-
node_1,
|
|
79
|
-
mesh.getNeighbour(cur_tet, k3),
|
|
80
|
-
);
|
|
81
|
-
}else{
|
|
82
|
-
cavity.push_boundary(
|
|
83
|
-
point_index,
|
|
84
|
-
node_0,
|
|
85
|
-
node_1,
|
|
86
|
-
node_2,
|
|
87
|
-
mesh.getNeighbour(cur_tet, k3),
|
|
88
|
-
);
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
continue;
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
const neighbour_index = encoded_neighbour >> 2;
|
|
95
|
-
|
|
96
|
-
if (subdets[neighbour_index * 4 + 3] === -1) {
|
|
97
|
-
// already visited
|
|
98
|
-
continue;
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
if (point_in_tetrahedron_circumsphere(
|
|
102
|
-
points,
|
|
103
|
-
mesh.getVertexIndex(neighbour_index, 0),
|
|
104
|
-
mesh.getVertexIndex(neighbour_index, 1),
|
|
105
|
-
mesh.getVertexIndex(neighbour_index, 2),
|
|
106
|
-
mesh.getVertexIndex(neighbour_index, 3),
|
|
107
|
-
point_index
|
|
108
|
-
) < 0) {
|
|
109
|
-
// outside the cavity, meaning it defines boundary
|
|
110
|
-
|
|
111
|
-
const node_0 = mesh.getVertexIndex(cur_tet, k0);
|
|
112
|
-
const node_1 = mesh.getVertexIndex(cur_tet, k1);
|
|
113
|
-
const node_2 = mesh.getVertexIndex(cur_tet, k2);
|
|
114
|
-
|
|
115
|
-
if(i === 3 || node_2 >= node_1) {
|
|
116
|
-
cavity.push_boundary(
|
|
117
|
-
point_index,
|
|
118
|
-
node_2,
|
|
119
|
-
node_0,
|
|
120
|
-
node_1,
|
|
121
|
-
mesh.getNeighbour(cur_tet, k3),
|
|
122
|
-
);
|
|
123
|
-
}else{
|
|
124
|
-
cavity.push_boundary(
|
|
125
|
-
point_index,
|
|
126
|
-
node_0,
|
|
127
|
-
node_1,
|
|
128
|
-
node_2,
|
|
129
|
-
mesh.getNeighbour(cur_tet, k3),
|
|
130
|
-
);
|
|
131
|
-
}
|
|
132
|
-
} else {
|
|
133
|
-
//part of the cavity, remove
|
|
134
|
-
cavity.push_deleted(neighbour_index);
|
|
135
|
-
subdets[neighbour_index * 4 + 3] = -1;
|
|
136
|
-
}
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
}
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
/**
|
|
144
|
-
*
|
|
145
|
-
* @param {TetrahedralMesh} mesh
|
|
146
|
-
* @param {Cavity} cavity
|
|
147
|
-
* @param {number[]|Float32Array} points
|
|
148
|
-
* @param {Float32Array} subdets
|
|
149
|
-
* @param {number} containing_tetra tetrahedron that contains point
|
|
150
|
-
* @param {number} point_index point that forms the cavity
|
|
151
|
-
*/
|
|
152
|
-
export function tetrahedral_mesh_compute_cavity2(
|
|
153
|
-
mesh,
|
|
154
|
-
points,
|
|
155
|
-
subdets,
|
|
156
|
-
cavity,
|
|
157
|
-
containing_tetra,
|
|
158
|
-
point_index
|
|
159
|
-
) {
|
|
160
|
-
assert.isNonNegativeInteger(containing_tetra, 'containing_tetra');
|
|
161
|
-
|
|
162
|
-
// add the tet to cavity
|
|
163
|
-
cavity.push_deleted(containing_tetra);
|
|
164
|
-
subdets[containing_tetra * 4 + 3] = -1;
|
|
165
|
-
|
|
166
|
-
for (let start = cavity.__deleted_size - 1; start < cavity.__deleted_size; start++) {
|
|
167
|
-
const cur_tet = cavity.__deleted[start];
|
|
168
|
-
|
|
169
|
-
for (let i = 0; i < 4; i++) {
|
|
170
|
-
const encoded_neighbour = mesh.getNeighbour(cur_tet, i);
|
|
171
|
-
|
|
172
|
-
const k0 = (1 << i) & 3;
|
|
173
|
-
const k1 = (i + 2) % 3;
|
|
174
|
-
const k2 = (~((i + 1) >> 1) & 2) + 1;
|
|
175
|
-
const k3 = i;
|
|
176
|
-
|
|
177
|
-
if (encoded_neighbour === INVALID_NEIGHBOUR) {
|
|
178
|
-
// no neighbour, include this side into boundary
|
|
179
|
-
|
|
180
|
-
cavity.push_boundary(
|
|
181
|
-
point_index,
|
|
182
|
-
mesh.getVertexIndex(cur_tet, k0),
|
|
183
|
-
mesh.getVertexIndex(cur_tet, k1),
|
|
184
|
-
mesh.getVertexIndex(cur_tet, k2),
|
|
185
|
-
mesh.getNeighbour(cur_tet, k3),
|
|
186
|
-
);
|
|
187
|
-
|
|
188
|
-
continue;
|
|
189
|
-
}
|
|
190
|
-
|
|
191
|
-
const neighbour_index = encoded_neighbour >> 2;
|
|
192
|
-
|
|
193
|
-
if (subdets[neighbour_index * 4 + 3] === -1) {
|
|
194
|
-
// already visited
|
|
195
|
-
continue;
|
|
196
|
-
}
|
|
197
|
-
|
|
198
|
-
if (point_in_tetrahedron_circumsphere(
|
|
199
|
-
points,
|
|
200
|
-
mesh.getVertexIndex(neighbour_index, 0),
|
|
201
|
-
mesh.getVertexIndex(neighbour_index, 1),
|
|
202
|
-
mesh.getVertexIndex(neighbour_index, 2),
|
|
203
|
-
mesh.getVertexIndex(neighbour_index, 3),
|
|
204
|
-
point_index
|
|
205
|
-
) < 0) {
|
|
206
|
-
// outside the cavity, meaning it defines boundary
|
|
207
|
-
|
|
208
|
-
cavity.push_boundary(
|
|
209
|
-
point_index,
|
|
210
|
-
mesh.getVertexIndex(cur_tet, k0),
|
|
211
|
-
mesh.getVertexIndex(cur_tet, k1),
|
|
212
|
-
mesh.getVertexIndex(cur_tet, k2),
|
|
213
|
-
mesh.getNeighbour(cur_tet, k3),
|
|
214
|
-
);
|
|
215
|
-
|
|
216
|
-
} else {
|
|
217
|
-
//part of the cavity, remove
|
|
218
|
-
cavity.push_deleted(neighbour_index);
|
|
219
|
-
subdets[neighbour_index * 4 + 3] = -1;
|
|
220
|
-
}
|
|
221
|
-
}
|
|
222
|
-
|
|
223
|
-
}
|
|
224
|
-
}
|
|
@@ -1,98 +0,0 @@
|
|
|
1
|
-
import { tetrahedral_mesh_compute_cavity } from "./tetrahedral_mesh_compute_cavity.js";
|
|
2
|
-
import { assert } from "../../../../assert.js";
|
|
3
|
-
import { Cavity } from "./Cavity.js";
|
|
4
|
-
import { INVALID_NEIGHBOUR, LAYOUT_TETRA_BYTE_SIZE } from "../TetrahedralMesh.js";
|
|
5
|
-
|
|
6
|
-
const SCRATCH_CAVITY = new Cavity();
|
|
7
|
-
|
|
8
|
-
/**
|
|
9
|
-
*
|
|
10
|
-
* @param {TetrahedralMesh} mesh
|
|
11
|
-
* @param {number[]|Float32Array} points
|
|
12
|
-
* @param {number} index
|
|
13
|
-
*/
|
|
14
|
-
export function tetrahedral_mesh_insert_point(mesh, points, index) {
|
|
15
|
-
const debug_length_initial = mesh.__length;
|
|
16
|
-
|
|
17
|
-
// Compute the cavity, that is the set of tetrahedra that need to be removed and rebuilt
|
|
18
|
-
tetrahedral_mesh_compute_cavity(mesh, SCRATCH_CAVITY, points, index);
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
// identify cavity "edge" - the set of tetras that are neighbours of the tetras that form the cavity
|
|
22
|
-
const cavity_size = SCRATCH_CAVITY.__deleted_size;
|
|
23
|
-
const cavity_indices = SCRATCH_CAVITY.__deleted;
|
|
24
|
-
|
|
25
|
-
for (let i = 0; i < cavity_size; i++) {
|
|
26
|
-
const data = mesh.__view;
|
|
27
|
-
|
|
28
|
-
const cavity_index = cavity_indices[i];
|
|
29
|
-
|
|
30
|
-
// take each side of the tetra
|
|
31
|
-
const tetra_address = cavity_index * LAYOUT_TETRA_BYTE_SIZE;
|
|
32
|
-
|
|
33
|
-
const a = data.getUint32(tetra_address);
|
|
34
|
-
const b = data.getUint32(tetra_address + 4);
|
|
35
|
-
const c = data.getUint32(tetra_address + 8);
|
|
36
|
-
const d = data.getUint32(tetra_address + 12);
|
|
37
|
-
|
|
38
|
-
// attempt to form 4 tetras using the sides of the cavity
|
|
39
|
-
const a_neighbour = data.getUint32(tetra_address + 16);
|
|
40
|
-
const a_neighbour_index = a_neighbour >> 2;
|
|
41
|
-
|
|
42
|
-
const b_neighbour = data.getUint32(tetra_address + 20);
|
|
43
|
-
const b_neighbour_index = b_neighbour >> 2;
|
|
44
|
-
|
|
45
|
-
const c_neighbour = data.getUint32(tetra_address + 24);
|
|
46
|
-
const c_neighbour_index = c_neighbour >> 2;
|
|
47
|
-
|
|
48
|
-
const d_neighbour = data.getUint32(tetra_address + 28);
|
|
49
|
-
const d_neighbour_index = d_neighbour >> 2;
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
if (a_neighbour === INVALID_NEIGHBOUR || cavity_indices.indexOf(a_neighbour_index) === 0) {
|
|
53
|
-
// ABC is a valid side
|
|
54
|
-
const tet = mesh.append(points, b, d, c, index);
|
|
55
|
-
// patch in neighbours
|
|
56
|
-
if (a_neighbour !== INVALID_NEIGHBOUR) {
|
|
57
|
-
mesh.setNeighbour(tet, 3, a_neighbour);
|
|
58
|
-
mesh.setNeighbour(a_neighbour_index, a_neighbour & 3, tet);
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
if (b_neighbour === INVALID_NEIGHBOUR || cavity_indices.indexOf(b_neighbour_index) === 0) {
|
|
62
|
-
// ABC is a valid side
|
|
63
|
-
const tet = mesh.append(points, c, d, a, index);
|
|
64
|
-
if (b_neighbour !== INVALID_NEIGHBOUR) {
|
|
65
|
-
mesh.setNeighbour(tet, 3, b_neighbour);
|
|
66
|
-
mesh.setNeighbour(b_neighbour_index, b_neighbour & 3, tet);
|
|
67
|
-
}
|
|
68
|
-
}
|
|
69
|
-
if (c_neighbour === INVALID_NEIGHBOUR || cavity_indices.indexOf(c_neighbour_index) === 0) {
|
|
70
|
-
// ABC is a valid side
|
|
71
|
-
const tet = mesh.append(points, d, b, a, index);
|
|
72
|
-
if (c_neighbour !== INVALID_NEIGHBOUR) {
|
|
73
|
-
mesh.setNeighbour(tet, 3, c_neighbour);
|
|
74
|
-
mesh.setNeighbour(c_neighbour_index, c_neighbour & 3, tet);
|
|
75
|
-
}
|
|
76
|
-
}
|
|
77
|
-
if (d_neighbour === INVALID_NEIGHBOUR || cavity_indices.indexOf(d_neighbour_index) === 0) {
|
|
78
|
-
// ABC is a valid side
|
|
79
|
-
const tet = mesh.append(points, a, b, c, index);
|
|
80
|
-
if (d_neighbour !== INVALID_NEIGHBOUR) {
|
|
81
|
-
mesh.setNeighbour(tet, 3, d_neighbour);
|
|
82
|
-
mesh.setNeighbour(d_neighbour_index, d_neighbour & 3, tet);
|
|
83
|
-
}
|
|
84
|
-
}
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
// 3. remove the cavity tetrahedrons
|
|
89
|
-
for (let i = 0; i < cavity_size; i++) {
|
|
90
|
-
const cavity_index = cavity_indices[i];
|
|
91
|
-
|
|
92
|
-
// clear out cavity, connectivity was already patched in the previous step
|
|
93
|
-
mesh.__occupancy.set(cavity_index, false);
|
|
94
|
-
mesh.__length--;
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
assert.greaterThan(mesh.__length, debug_length_initial, 'after insertion number of tetrahedra must grow, not shrink');
|
|
98
|
-
}
|