@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.
Files changed (48) hide show
  1. package/core/binary/BinaryBuffer.js +13 -1
  2. package/core/binary/BitSet.js +2 -2
  3. package/core/collection/array/array_range_equal_strict.js +22 -0
  4. package/core/color/sRGB_to_linear.js +9 -4
  5. package/core/geom/3d/plane/orient3d_fast.js +3 -0
  6. package/core/geom/3d/plane/orient3d_robust.js +41 -0
  7. package/core/geom/3d/sphere/harmonics/README.md +15 -0
  8. package/core/geom/3d/sphere/harmonics/sh3_add.js +21 -0
  9. package/core/geom/3d/sphere/harmonics/sh3_dering_optimize_positive.js +618 -0
  10. package/core/geom/3d/sphere/harmonics/sh3_sample_by_direction.js +49 -0
  11. package/core/geom/3d/sphere/harmonics/sh3_sample_irradiance_by_direction.js +53 -0
  12. package/core/geom/3d/tetrahedra/TetrahedralMesh.js +251 -68
  13. package/core/geom/3d/tetrahedra/TetrahedralMesh.spec.js +80 -3
  14. package/core/geom/3d/tetrahedra/build_tetrahedral_mesh_buffer_geometry.js +75 -0
  15. package/core/geom/3d/tetrahedra/delaunay/Cavity.js +5 -1
  16. package/core/geom/3d/tetrahedra/delaunay/compute_delaunay_tetrahedral_mesh.js +30 -31
  17. package/core/geom/3d/tetrahedra/delaunay/fill_in_a_cavity.js +54 -18
  18. package/core/geom/3d/tetrahedra/delaunay/push_boundary_with_validation.js +27 -0
  19. package/core/geom/3d/tetrahedra/delaunay/tetrahedral_mesh_compute_cavity.js +89 -0
  20. package/core/geom/3d/tetrahedra/delaunay/{tetrahedral_mesh_walk_toward_cavity.js → tetrahedral_mesh_walk_towards_containing_tetrahedron.js} +15 -12
  21. package/core/geom/3d/tetrahedra/delaunay/validate_cavity_boundary.js +60 -0
  22. package/core/geom/3d/tetrahedra/{point_in_tetrahedron_circumsphere.js → in_sphere_fast.js} +2 -4
  23. package/core/geom/3d/tetrahedra/in_sphere_robust.js +53 -0
  24. package/core/geom/3d/tetrahedra/prototypeTetrahedraBuilder.js +44 -35
  25. package/core/geom/3d/tetrahedra/validate_tetrahedral_mesh.js +85 -38
  26. package/core/geom/3d/util/make_justified_point_grid.js +31 -0
  27. package/core/process/delay.js +5 -0
  28. package/editor/Editor.js +3 -0
  29. package/editor/ecs/component/editors/ecs/ParameterLookupTableEditor.js +195 -11
  30. package/editor/ecs/component/editors/ecs/ParameterTrackSetEditor.js +16 -0
  31. package/editor/ecs/component/editors/ecs/ParticleEmitterLayerEditor.js +4 -0
  32. package/engine/EngineHarness.js +11 -5
  33. package/engine/ecs/terrain/ecs/TerrainSystem.js +7 -1
  34. package/engine/ecs/transform/copy_three_transform.js +15 -0
  35. package/engine/graphics/ecs/light/Light.js +6 -1
  36. package/engine/graphics/ecs/light/LightSystem.d.ts +1 -1
  37. package/engine/graphics/ecs/mesh-v2/three_object_to_entity_composition.js +2 -17
  38. package/engine/graphics/geometry/instancing/InstancedMeshGroup.js +2 -2
  39. package/engine/graphics/sh3/LightProbeVolume.js +595 -0
  40. package/engine/graphics/sh3/SH3VisualisationMaterial.js +79 -0
  41. package/engine/graphics/sh3/prototypeSH3Probe.js +427 -0
  42. package/engine/graphics/sh3/visualise_probe.js +40 -0
  43. package/engine/graphics/texture/atlas/TextureAtlas.js +15 -3
  44. package/engine/intelligence/blackboard/AbstractBlackboard.d.ts +1 -1
  45. package/package.json +2 -1
  46. package/samples/terrain/from_image_2.js +127 -82
  47. package/core/geom/3d/tetrahedra/delaunay/tetrahedral_mesh_compute_cavity2.js +0 -224
  48. 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 { enableEditor } from "../../editor/enableEditor.js";
20
- import "../../../../../css/main.scss";
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 {string} path
54
- * @param {AssetManager} am
28
+ * @param {Sampler2D} source
29
+ * @param {Terrain} terrain
55
30
  */
56
- async function load_sampler(path, am) {
57
-
58
- const asset = await am.promise(path, 'image');
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
- * @type {Sampler2D}
63
- */
64
- const sampler = asset.create();
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
- return sampler;
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
- const ecd = em.dataset;
49
+ let rotated_v;
50
+ rotated_v = b1 | (b0 << 8);
79
51
 
80
- new EntityBuilder()
81
- .add(Mesh.fromJSON({
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
- const source_height_data = sampler.data;
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
- "data/textures/materials/terrain_township_set/Grass_2.png",
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
- "data/textures/materials/terrain_township_set/1024/Ground_1_dark.png",
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
- "data/textures/materials/Sci-Fi Planet/Sand_01.png",
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
- }