@woosh/meep-engine 2.43.21 → 2.43.23

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 (50) hide show
  1. package/core/collection/HashMap.d.ts +2 -2
  2. package/core/collection/HashMap.js +22 -2
  3. package/core/geom/3d/morton/mortonEncode_magicbits.js +18 -0
  4. package/core/geom/3d/tetrahedra/delaunay/compute_delaunay_tetrahedral_mesh.js +2 -2
  5. package/core/geom/3d/topology/struct/TopoEdge.js +4 -0
  6. package/core/geom/3d/topology/struct/TopoMesh.js +25 -0
  7. package/core/geom/3d/topology/struct/TopoTriangle.js +4 -0
  8. package/core/geom/3d/topology/struct/TopoVertex.js +8 -0
  9. package/core/geom/3d/topology/struct/binary/BinaryElementPool.js +288 -0
  10. package/core/geom/3d/topology/struct/binary/BinaryElementPool.spec.js +36 -0
  11. package/core/geom/3d/topology/struct/binary/BinaryTopology.js +617 -0
  12. package/core/geom/3d/topology/struct/binary/BinaryTopology.spec.js +16 -0
  13. package/core/geom/3d/topology/struct/binary/io/OrderedEdge.js +66 -0
  14. package/core/geom/3d/topology/struct/binary/io/bt_index_geometry_to_topology.js +188 -0
  15. package/core/geom/3d/topology/struct/binary/io/bt_index_geometry_to_topology.spec.js +84 -0
  16. package/core/geom/3d/topology/struct/binary/io/bt_mesh_calc_edges.js +51 -0
  17. package/core/geom/3d/topology/struct/binary/io/create_edge.js +106 -0
  18. package/core/geom/3d/topology/struct/binary/io/get_or_create_edge_map.js +26 -0
  19. package/core/geom/3d/topology/struct/binary/query/bt_mesh_edge_has_vertex.js +16 -0
  20. package/core/geom/3d/topology/struct/binary/query/bt_mesh_edge_has_vertex.spec.js +15 -0
  21. package/core/geom/3d/topology/struct/binary/query/bt_mesh_edge_other_vertex.js +21 -0
  22. package/core/geom/3d/topology/struct/binary/query/bt_mesh_edge_other_vertex.spec.js +16 -0
  23. package/core/geom/3d/topology/struct/prototypeBinaryTopology.js +55 -0
  24. package/core/path/PATH_SEPARATOR.js +1 -0
  25. package/core/path/computeFileExtension.js +24 -0
  26. package/core/path/computeFileExtension.spec.js +13 -0
  27. package/core/path/computePathBase.js +21 -0
  28. package/core/path/computePathBase.spec.js +13 -0
  29. package/core/path/computePathDirectory.js +25 -0
  30. package/editor/view/library/MeshLibraryView.js +1 -1
  31. package/engine/asset/guessAssetType.js +1 -1
  32. package/engine/asset/loaders/image/ImageRGBADataLoader.js +1 -1
  33. package/engine/asset/loaders/texture/TextureAssetLoader.js +1 -1
  34. package/engine/ecs/storage/BinaryBufferSerializer.js +7 -0
  35. package/engine/graphics/material/composeCompile.js +3 -5
  36. package/engine/graphics/micron/plugin/GLTFAssetTransformer.js +90 -65
  37. package/engine/graphics/sh3/README.md +2 -0
  38. package/engine/graphics/sh3/path_tracer/PathTracer.js +2 -15
  39. package/engine/graphics/sh3/path_tracer/getBiasedNormalSample.js +1 -1
  40. package/engine/graphics/sh3/path_tracer/prototypePathTracer.js +14 -9
  41. package/engine/graphics/texture/cubemap/load_environment_map.js +1 -1
  42. package/engine/graphics/util/makeMeshPreviewScene.js +38 -26
  43. package/engine/network/RemoteController.js +98 -0
  44. package/engine/network/remoteEditor.js +33 -0
  45. package/engine/save/storage/IndexedDBStorage.js +1 -0
  46. package/package.json +1 -1
  47. package/view/elements/MeshPreview.js +5 -1
  48. package/core/FilePath.js +0 -73
  49. package/core/FilePath.spec.js +0 -25
  50. package/core/geom/3d/topology/struct/BinaryTopology.js +0 -112
@@ -0,0 +1,188 @@
1
+ import { NULL_POINTER } from "../BinaryTopology.js";
2
+ import { create_edge } from "./create_edge.js";
3
+
4
+
5
+ /**
6
+ * Populates supplied topology with data from supplied indexed geometry
7
+ * @see https://github.com/blender/blender/blob/9cb061f4f0119e647173e7d354e1457e97632333/source/blender/blenkernel/intern/mesh_calc_edges.cc
8
+ * @see https://github.com/blender/blender/blob/9cb061f4f0119e647173e7d354e1457e97632333/source/blender/io/stl/importer/stl_import_mesh.cc#L63
9
+ * @param {BinaryTopology} out
10
+ * @param {number[]} indices
11
+ * @param {number[]} vertex_positions
12
+ * @param {number[]} [vertex_normals]
13
+ */
14
+ export function bt_index_geometry_to_topology(
15
+ out,
16
+ indices,
17
+ vertex_positions,
18
+ vertex_normals
19
+ ) {
20
+
21
+ // remove any existing data
22
+ out.clear();
23
+
24
+ /*
25
+ NOTES:
26
+ - we use {@link BinaryElementPool#allocate_continuous} to avoid having to allocate additional mapping structure
27
+ */
28
+
29
+ // ingest all vertices
30
+ const vertex_count = vertex_positions.length / 3;
31
+
32
+ const vertex_allocation_offset = out.vertices.allocate_continuous(vertex_count);
33
+
34
+ for (let i = 0; i < vertex_count; i++) {
35
+ const i3 = i * 3;
36
+
37
+ const vertex_id = i + vertex_allocation_offset;
38
+
39
+ out.vertex_write_coordinate(vertex_id, vertex_positions, i3);
40
+
41
+ if (vertex_normals !== undefined) {
42
+ out.vertex_write_normal(vertex_id, vertex_normals, i3);
43
+ }
44
+
45
+ // initialize edge to NULL
46
+ out.vertex_write_edge(vertex_id, NULL_POINTER);
47
+ }
48
+
49
+ const face_count = indices.length / 3;
50
+
51
+ // create faces
52
+ const face_allocation_offset = out.faces.allocate_continuous(face_count);
53
+
54
+ // reserve some memory to avoid extra allocations
55
+ out.loops.ensure_capacity(face_count * 3);
56
+ out.edges.ensure_capacity(face_count * 1.6);
57
+
58
+ for (let i = 0; i < face_count; i++) {
59
+ const i3 = i * 3;
60
+
61
+ const a = indices[i3];
62
+ const b = indices[i3 + 1];
63
+ const c = indices[i3 + 2];
64
+
65
+ const vertex_a = a + vertex_allocation_offset;
66
+ const vertex_b = b + vertex_allocation_offset;
67
+ const vertex_c = c + vertex_allocation_offset;
68
+
69
+ const face_id = i + face_allocation_offset;
70
+
71
+ // create edges
72
+ const edge_ab = get_or_create_edge_2(vertex_a, vertex_b, out);
73
+ const edge_bc = get_or_create_edge_2(vertex_b, vertex_c, out);
74
+ const edge_ca = get_or_create_edge_2(vertex_c, vertex_a, out);
75
+
76
+ // allocate loops
77
+ const loop_a = out.loop_create();
78
+ const loop_b = out.loop_create();
79
+ const loop_c = out.loop_create();
80
+
81
+ // write loops
82
+ out.loop_write_vertex(loop_a, vertex_a);
83
+ out.loop_write_vertex(loop_b, vertex_b);
84
+ out.loop_write_vertex(loop_c, vertex_c);
85
+
86
+ // link loops to edges
87
+ link_loop_to_edge(loop_a, edge_ab, out);
88
+ link_loop_to_edge(loop_b, edge_bc, out);
89
+ link_loop_to_edge(loop_c, edge_ca, out);
90
+
91
+ out.loop_write_face(loop_a, face_id);
92
+ out.loop_write_face(loop_b, face_id);
93
+ out.loop_write_face(loop_c, face_id);
94
+
95
+ /*
96
+ NOTE: Vertices (#BMLoop.v & #BMLoop.next.v) always contain vertices from (#BMEdge.v1 & #BMEdge.v2).
97
+ */
98
+ // link up loops around the face
99
+ out.loop_write_next(loop_a, loop_b);
100
+ out.loop_write_prev(loop_a, loop_c);
101
+
102
+ out.loop_write_next(loop_b, loop_c);
103
+ out.loop_write_prev(loop_b, loop_a);
104
+
105
+ out.loop_write_next(loop_c, loop_a);
106
+ out.loop_write_prev(loop_c, loop_b);
107
+
108
+ // update face
109
+ out.face_write_loop(face_id, loop_a);
110
+
111
+ }
112
+ }
113
+
114
+ /**
115
+ *
116
+ * @param {number} loop_id
117
+ * @param {number} edge_id
118
+ * @param {BinaryTopology} mesh
119
+ */
120
+ function link_loop_to_edge(loop_id, edge_id, mesh) {
121
+ mesh.loop_write_edge(loop_id, edge_id);
122
+
123
+ /**
124
+ * First loop attached to the edge
125
+ * @type {number}
126
+ */
127
+ const existing_loop = mesh.edge_read_loop(edge_id);
128
+
129
+ if (existing_loop === NULL_POINTER) {
130
+ // no loops connected yet
131
+ mesh.edge_write_loop(edge_id, loop_id);
132
+
133
+
134
+ } else {
135
+ // insert loop between existing loop and the next one
136
+ const next = mesh.loop_read_radial_next(existing_loop);
137
+
138
+ mesh.loop_write_radial_next(existing_loop, loop_id);
139
+ mesh.loop_write_radial_prev(next, loop_id);
140
+
141
+ mesh.loop_write_radial_next(loop_id, next);
142
+ mesh.loop_write_radial_prev(loop_id, existing_loop);
143
+ }
144
+
145
+ }
146
+
147
+
148
+ /**
149
+ * Ensure an edge between two vertices
150
+ * NOTE: works without having to use a separate hash map, resulting in faster execution and smaller RAM requirement
151
+ * @param {number} v0
152
+ * @param {number} v1
153
+ * @param {BinaryTopology} mesh
154
+ */
155
+ function get_or_create_edge_2(v0, v1, mesh) {
156
+ const first_edge = mesh.vertex_read_edge(v0);
157
+
158
+ if (first_edge !== NULL_POINTER) {
159
+
160
+ // iterate over all edges around the vertex
161
+ let edge = first_edge;
162
+
163
+ do {
164
+ const edge_v1 = mesh.edge_read_vertex1(edge);
165
+ const edge_v2 = mesh.edge_read_vertex2(edge);
166
+
167
+ if (edge_v1 === v1 || edge_v2 === v1) {
168
+ // found edge that connects between v0 and v1
169
+ return edge;
170
+ }
171
+
172
+ if (edge_v1 === v0) {
173
+ edge = mesh.edge_read_v1_disk_next(edge);
174
+ } else if (edge_v2 === v0) {
175
+ edge = mesh.edge_read_v2_disk_next(edge);
176
+ } else {
177
+ // invalid edge connection
178
+ throw new Error('Invalid edge, not connected to first vertex');
179
+ }
180
+
181
+ } while (edge !== first_edge);
182
+
183
+ }
184
+
185
+ // if match is found - return the match, else create a new edge and assign
186
+
187
+ return create_edge(mesh, v0, v1);
188
+ }
@@ -0,0 +1,84 @@
1
+ import { bt_index_geometry_to_topology } from "./bt_index_geometry_to_topology.js";
2
+ import { BinaryTopology } from "../BinaryTopology.js";
3
+ import { bt_mesh_edge_has_vertex } from "../query/bt_mesh_edge_has_vertex.js";
4
+
5
+ test('Empty geometry work as expected', () => {
6
+ const mesh = new BinaryTopology();
7
+ bt_index_geometry_to_topology(mesh, [], []);
8
+
9
+ expect(mesh.faces.size).toBe(0);
10
+ expect(mesh.vertices.size).toBe(0);
11
+ expect(mesh.edges.size).toBe(0);
12
+ expect(mesh.loops.size).toBe(0);
13
+ });
14
+
15
+ test('Single triangle', () => {
16
+ const mesh = new BinaryTopology();
17
+ bt_index_geometry_to_topology(mesh, [0, 1, 2], [
18
+ 1, 3, 7,
19
+ 11, 13, 17,
20
+ 23, 27, -1
21
+ ]);
22
+
23
+ expect(mesh.faces.size).toBe(1);
24
+ expect(mesh.loops.size).toBe(3);
25
+ expect(mesh.edges.size).toBe(3);
26
+ expect(mesh.vertices.size).toBe(3);
27
+
28
+ // validate loops
29
+ for (let loop_id = 0; loop_id < 3; loop_id++) {
30
+ const face = mesh.loop_read_face(loop_id);
31
+ expect(face).toEqual(0);
32
+
33
+ const loop_next = mesh.loop_read_next(loop_id);
34
+ expect(loop_next).not.toEqual(loop_id);
35
+ expect(mesh.loop_read_prev(loop_next)).toEqual(loop_id);
36
+
37
+ const loop_prev = mesh.loop_read_prev(loop_id);
38
+ expect(loop_prev).not.toEqual(loop_id);
39
+ expect(mesh.loop_read_next(loop_prev)).toEqual(loop_id);
40
+
41
+ expect(loop_prev).not.toEqual(loop_next);
42
+
43
+ // should loop around
44
+ expect(mesh.loop_read_next(loop_next)).toEqual(loop_prev);
45
+ expect(mesh.loop_read_prev(loop_prev)).toEqual(loop_next);
46
+ }
47
+
48
+
49
+ // validate edges
50
+ for (let edge_id = 0; edge_id < 3; edge_id++) {
51
+ const v1 = mesh.edge_read_vertex1(edge_id);
52
+ const v2 = mesh.edge_read_vertex2(edge_id);
53
+
54
+ // different vertices
55
+ expect(v1).not.toEqual(v2);
56
+
57
+ // validate disk links
58
+ const disk_v1_next = mesh.edge_read_v1_disk_next(edge_id);
59
+
60
+ expect(disk_v1_next).not.toEqual(edge_id);
61
+
62
+ expect(bt_mesh_edge_has_vertex(mesh, disk_v1_next, v1)).toBe(true);
63
+
64
+ const disk_v1_prev = mesh.edge_read_v1_disk_prev(edge_id);
65
+
66
+ expect(disk_v1_prev).not.toEqual(edge_id);
67
+
68
+ expect(bt_mesh_edge_has_vertex(mesh, disk_v1_prev, v1)).toBe(true);
69
+
70
+ const disk_v2_next = mesh.edge_read_v2_disk_next(edge_id);
71
+
72
+ expect(disk_v2_next).not.toEqual(edge_id);
73
+
74
+ expect(bt_mesh_edge_has_vertex(mesh, disk_v2_next, v2)).toBe(true);
75
+
76
+ const disk_v2_prev = mesh.edge_read_v2_disk_prev(edge_id);
77
+
78
+ expect(disk_v2_prev).not.toEqual(edge_id);
79
+
80
+ expect(bt_mesh_edge_has_vertex(mesh, disk_v2_prev, v2)).toBe(true);
81
+
82
+ }
83
+
84
+ });
@@ -0,0 +1,51 @@
1
+ import { OrderedEdge } from "./OrderedEdge.js";
2
+ import { HashMap } from "../../../../../../collection/HashMap.d.ts";
3
+
4
+ /**
5
+ * @see https://github.com/blender/blender/blob/9cb061f4f0119e647173e7d354e1457e97632333/source/blender/blenkernel/intern/mesh_calc_edges.cc#L209
6
+ * @param {BinaryTopology} mesh
7
+ */
8
+ function bt_mesh_calc_edges(mesh) {
9
+ /**
10
+ *
11
+ * @type {HashMap<OrderedEdge, unknown>}
12
+ */
13
+ const map = new HashMap();
14
+
15
+ add_polygon_edges_to_map(mesh, map);
16
+ }
17
+
18
+ /**
19
+ * @see https://github.com/blender/blender/blob/9cb061f4f0119e647173e7d354e1457e97632333/source/blender/blenkernel/intern/mesh_calc_edges.cc#L96
20
+ * @param {BinaryTopology} mesh
21
+ * @param {HashMap<OrderedEdge,*>} edge_map
22
+ */
23
+ function add_polygon_edges_to_map(mesh, edge_map) {
24
+
25
+ const faces = mesh.faces;
26
+ const face_count = faces.size;
27
+
28
+ for (let i = 0; i < face_count; i++) {
29
+ if (!faces.is_allocated(i)) {
30
+ continue;
31
+ }
32
+
33
+ const first_loop = mesh.face_read_loop(i);
34
+ let prev_loop = first_loop + j;
35
+
36
+ for (let j = 0; j < 3; j++) {
37
+ const loop = first_loop + j;
38
+
39
+
40
+ const prev_v = mesh.loop_read_vertex(prev_loop);
41
+ const next_v = mesh.loop_read_vertex(loop);
42
+
43
+ const edge = new OrderedEdge(prev_v, next_v);
44
+
45
+ edge_map.getOrSet(edge, null);
46
+
47
+ prev_loop = loop;
48
+ }
49
+ }
50
+
51
+ }
@@ -0,0 +1,106 @@
1
+ import { NULL_POINTER } from "../BinaryTopology.js";
2
+
3
+ /**
4
+ *
5
+ * @param {BinaryTopology} mesh
6
+ * @param {number} edge_from
7
+ * @param {number} edge_to
8
+ * @param {number} vertex
9
+ */
10
+ function edge_link_disk_forward(mesh, edge_from, edge_to, vertex) {
11
+ const from_v1 = mesh.edge_read_vertex1(edge_from);
12
+
13
+ let displaced_edge;
14
+
15
+ if (from_v1 === vertex) {
16
+ displaced_edge = mesh.edge_read_v1_disk_next(edge_from);
17
+
18
+ mesh.edge_write_v1_disk_next(edge_from, edge_to);
19
+
20
+ } else {
21
+ displaced_edge = mesh.edge_read_v2_disk_next(edge_from);
22
+
23
+ mesh.edge_write_v2_disk_next(edge_from, edge_to);
24
+ }
25
+
26
+ return displaced_edge;
27
+ }
28
+
29
+ function edge_link_disk_back(mesh, edge_from, edge_to, vertex) {
30
+ const from_v1 = mesh.edge_read_vertex1(edge_from);
31
+
32
+ let displaced_edge;
33
+
34
+ if (from_v1 === vertex) {
35
+ displaced_edge = mesh.edge_read_v1_disk_prev(edge_from);
36
+
37
+ mesh.edge_write_v1_disk_prev(edge_from, edge_to);
38
+
39
+ } else {
40
+ displaced_edge = mesh.edge_read_v2_disk_prev(edge_from);
41
+
42
+ mesh.edge_write_v2_disk_prev(edge_from, edge_to);
43
+ }
44
+
45
+ return displaced_edge;
46
+ }
47
+
48
+ /**
49
+ *
50
+ * @param {BinaryTopology} mesh
51
+ * @param {number} edge_source anchor edge, new edge is inserted after this one
52
+ * @param {number} edge_new edge that is being introduced
53
+ * @param {number} vertex
54
+ */
55
+ function edge_link_disk(mesh, edge_source, edge_new, vertex) {
56
+ const forward_link = edge_link_disk_forward(mesh, edge_source, edge_new, vertex);
57
+ edge_link_disk_forward(mesh, edge_new, forward_link, vertex);
58
+
59
+ edge_link_disk_back(mesh, forward_link, edge_new, vertex);
60
+ edge_link_disk_back(mesh, edge_new, edge_source, vertex);
61
+ }
62
+
63
+ /**
64
+ *
65
+ * @param {BinaryTopology} mesh
66
+ * @param {number} v0
67
+ * @param {number} v1
68
+ * @return {number}
69
+ */
70
+ export function create_edge(mesh, v0, v1) {
71
+ const edge_id = mesh.edges.allocate();
72
+
73
+ mesh.edge_write_vertex1(edge_id, v0);
74
+ mesh.edge_write_vertex2(edge_id, v1);
75
+
76
+ // initialize rest of the edge
77
+ mesh.edge_write_loop(edge_id, NULL_POINTER);
78
+
79
+ // process disk links
80
+ const first_v0_edge = mesh.vertex_read_edge(v0);
81
+
82
+ if (first_v0_edge !== NULL_POINTER) {
83
+ edge_link_disk(mesh, first_v0_edge, edge_id, v0);
84
+ } else {
85
+ // no edges attached yet, attach this one as the first
86
+ mesh.vertex_write_edge(v0, edge_id);
87
+ // link to self
88
+ mesh.edge_write_v1_disk_next(edge_id, edge_id);
89
+ mesh.edge_write_v1_disk_prev(edge_id, edge_id);
90
+ }
91
+
92
+ const first_v1_edge = mesh.vertex_read_edge(v1);
93
+
94
+ if (first_v1_edge !== NULL_POINTER) {
95
+
96
+ edge_link_disk(mesh, first_v1_edge, edge_id, v1);
97
+
98
+ } else {
99
+ // no edges attached yet, attach this one as the first
100
+ mesh.vertex_write_edge(v1, edge_id);
101
+ // link to self
102
+ mesh.edge_write_v2_disk_next(edge_id, edge_id);
103
+ mesh.edge_write_v2_disk_prev(edge_id, edge_id);
104
+ }
105
+ return edge_id;
106
+ }
@@ -0,0 +1,26 @@
1
+ import { OrderedEdge } from "./OrderedEdge.js";
2
+ import { create_edge } from "./create_edge.js";
3
+
4
+ /**
5
+ *
6
+ * @param {number} v0
7
+ * @param {number} v1
8
+ * @param {HashMap<OrderedEdge,number>} map
9
+ * @param {BinaryTopology} mesh
10
+ */
11
+ function get_or_create_edge_map(v0, v1, map, mesh) {
12
+ const scratch_ordered_edge = new OrderedEdge(v0, v1);
13
+
14
+ const existing = map.get(scratch_ordered_edge);
15
+
16
+ if (existing !== undefined) {
17
+ return existing;
18
+ }
19
+
20
+ // doesn't exist - create
21
+ const edge_id = create_edge(mesh, v0, v1);
22
+
23
+ map.set(scratch_ordered_edge, edge_id);
24
+
25
+ return edge_id;
26
+ }
@@ -0,0 +1,16 @@
1
+ /**
2
+ *
3
+ * @param {BinaryTopology} mesh
4
+ * @param {number} edge_id
5
+ * @param {number} vertex_id
6
+ * @returns {boolean}
7
+ */
8
+ export function bt_mesh_edge_has_vertex(mesh, edge_id, vertex_id) {
9
+ const v1 = mesh.edge_read_vertex1(edge_id);
10
+
11
+ if (v1 === vertex_id) {
12
+ return true;
13
+ }
14
+
15
+ return mesh.edge_read_vertex2(edge_id) === vertex_id;
16
+ }
@@ -0,0 +1,15 @@
1
+ import { BinaryTopology } from "../BinaryTopology.js";
2
+ import { bt_mesh_edge_has_vertex } from "./bt_mesh_edge_has_vertex.js";
3
+
4
+ test('main', () => {
5
+ const mesh = new BinaryTopology();
6
+
7
+ const edge = mesh.edges.allocate();
8
+
9
+ mesh.edge_write_vertex1(edge, 7);
10
+ mesh.edge_write_vertex2(edge, 3);
11
+
12
+ expect(bt_mesh_edge_has_vertex(mesh, edge, 7)).toBe(true);
13
+ expect(bt_mesh_edge_has_vertex(mesh, edge, 3)).toBe(true);
14
+ expect(bt_mesh_edge_has_vertex(mesh, edge, 1)).toBe(false);
15
+ });
@@ -0,0 +1,21 @@
1
+ /**
2
+ * Returns other vertex ID
3
+ * Assumes that given vertex belongs to this edge
4
+ * Assumes that given edge exists
5
+ * @param {BinaryTopology} mesh
6
+ * @param {number} edge_id edge ID
7
+ * @param {number} vertex_id
8
+ * @returns {number}
9
+ */
10
+ export function bt_mesh_edge_other_vertex(mesh, edge_id, vertex_id) {
11
+
12
+ const v1 = mesh.edge_read_vertex1(edge_id);
13
+ const v2 = mesh.edge_read_vertex2(edge_id);
14
+
15
+ if (v1 === vertex_id) {
16
+ return v2;
17
+ } else {
18
+ return v1;
19
+ }
20
+
21
+ }
@@ -0,0 +1,16 @@
1
+ import { BinaryTopology } from "../BinaryTopology.js";
2
+ import { bt_mesh_edge_other_vertex } from "./bt_mesh_edge_other_vertex.js";
3
+
4
+ test('main', () => {
5
+
6
+ const mesh = new BinaryTopology();
7
+
8
+ const edge = mesh.edges.allocate();
9
+
10
+ mesh.edge_write_vertex1(edge, 7);
11
+ mesh.edge_write_vertex2(edge, 3);
12
+
13
+ expect(bt_mesh_edge_other_vertex(mesh, edge, 7)).toBe(3);
14
+ expect(bt_mesh_edge_other_vertex(mesh, edge, 3)).toBe(7);
15
+
16
+ });
@@ -0,0 +1,55 @@
1
+ import { PLYLoader } from "three/examples/jsm/loaders/PLYLoader.js";
2
+ import { noop } from "../../../../function/Functions.js";
3
+ import { bt_index_geometry_to_topology } from "./binary/io/bt_index_geometry_to_topology.js";
4
+ import { BinaryTopology } from "./binary/BinaryTopology.js";
5
+ import {
6
+ compute_buffer_geometry_byte_size
7
+ } from "../../../../../engine/graphics/geometry/buffered/compute_buffer_geometry_byte_size.js";
8
+ import { prettyPrint } from "../../../../NumberFormat.js";
9
+ import { TopoMesh } from "./TopoMesh.js";
10
+
11
+ function promise_ply(url) {
12
+
13
+ return new Promise((resolve, reject) => {
14
+ new PLYLoader().load(url, resolve, noop, reject);
15
+ });
16
+ }
17
+
18
+
19
+ async function main() {
20
+
21
+ const url = "data/models/stanford/Lucy100k.ply";
22
+ // const url = "data/models/stanford/dragon_recon/dragon_vrip.ply";
23
+ const lucy_geom = await promise_ply(url);
24
+
25
+ const mesh = new BinaryTopology();
26
+ const topoMesh = new TopoMesh();
27
+
28
+ const positions_array = lucy_geom.getAttribute('position').array;
29
+ const index_array = lucy_geom.getIndex().array;
30
+
31
+
32
+ console.time('topo build - bin');
33
+ // console.profile('topo build - bin');
34
+ bt_index_geometry_to_topology(mesh, index_array, positions_array);
35
+ // console.profileEnd('topo build - bin');
36
+ console.timeEnd('topo build - bin');
37
+
38
+ //
39
+ // console.time('topo build - obj');
40
+ // topoMesh.build(positions_array, index_array);
41
+ // console.timeEnd('topo build - obj');
42
+
43
+ mesh.trim();
44
+
45
+ console.log(mesh, lucy_geom);
46
+
47
+ console.log(`source mesh size: ${prettyPrint(compute_buffer_geometry_byte_size(lucy_geom))} bytes`);
48
+ console.log(`binary topology size: ${prettyPrint(mesh.byteSize)} bytes`);
49
+ console.log(`object topology size: ${prettyPrint(topoMesh.byteSize)} bytes`);
50
+
51
+ window.topo_obj = topoMesh;
52
+ }
53
+
54
+ main();
55
+
@@ -0,0 +1 @@
1
+ export const PATH_SEPARATOR = '/';
@@ -0,0 +1,24 @@
1
+ import { computePathBase } from "./computePathBase.js";
2
+
3
+ /**
4
+ *
5
+ * @param {string} path
6
+ * @returns {String|null}
7
+ */
8
+ export function computeFileExtension(path) {
9
+ if (typeof path !== "string") {
10
+ throw new Error('path is not a string');
11
+ }
12
+
13
+ //get base
14
+ const pathBase = computePathBase(path);
15
+
16
+ const lastDotIndex = pathBase.lastIndexOf('.');
17
+
18
+ if (lastDotIndex !== -1) {
19
+ return pathBase.substring(lastDotIndex + 1);
20
+ } else {
21
+ //no extension
22
+ return null;
23
+ }
24
+ }
@@ -0,0 +1,13 @@
1
+ import { computeFileExtension } from "./computeFileExtension.js";
2
+
3
+ test('extract extension of cat.txt', () => {
4
+ expect(computeFileExtension('cat.txt')).toEqual('txt');
5
+ });
6
+
7
+ test('extract extension of ../hmm/cat.txt', () => {
8
+ expect(computeFileExtension('../hmm/cat.txt')).toEqual('txt');
9
+ });
10
+
11
+ test('extract extension of empty string', () => {
12
+ expect(computeFileExtension('')).toBeNull();
13
+ });
@@ -0,0 +1,21 @@
1
+ import { PATH_SEPARATOR } from "./PATH_SEPARATOR.js";
2
+
3
+ /**
4
+ * Strips all directories from the path.
5
+ * @example 'a/b/c' -> 'c'
6
+ * @param {string} path
7
+ * @returns {string}
8
+ */
9
+ export function computePathBase(path) {
10
+ if (typeof path !== "string") {
11
+ throw new Error('path is not a string');
12
+ }
13
+
14
+ const lastSlashIndex = path.lastIndexOf(PATH_SEPARATOR);
15
+
16
+ if (lastSlashIndex !== -1) {
17
+ return path.substring(lastSlashIndex + 1);
18
+ } else {
19
+ return path;
20
+ }
21
+ }
@@ -0,0 +1,13 @@
1
+ import { computePathBase } from "./computePathBase.js";
2
+
3
+ test('extract base path of empty string', () => {
4
+ expect(computePathBase('')).toBe('');
5
+ });
6
+
7
+ test('extract base path of hello', () => {
8
+ expect(computePathBase('hello')).toBe('hello');
9
+ });
10
+
11
+ test('extract base path of hello/there/world', () => {
12
+ expect(computePathBase('hello/there/world')).toBe('world');
13
+ });
@@ -0,0 +1,25 @@
1
+ import { PATH_SEPARATOR } from "./PATH_SEPARATOR.js";
2
+
3
+ /**
4
+ * Returns the directory name of a path, similar to the Unix dirname command.
5
+ * @param {string} path
6
+ * @return {string}
7
+ */
8
+ export function computePathDirectory(path) {
9
+ if (typeof path !== "string") {
10
+ throw new Error('path is not a string');
11
+ }
12
+
13
+ let lastSlashIndex = path.lastIndexOf(PATH_SEPARATOR);
14
+
15
+ //rewind in case of trailing slashes
16
+ while (lastSlashIndex > 0 && path.charAt(lastSlashIndex - 1) === PATH_SEPARATOR) {
17
+ lastSlashIndex--;
18
+ }
19
+
20
+ if (lastSlashIndex !== -1) {
21
+ return path.substring(0, lastSlashIndex);
22
+ } else {
23
+ return path;
24
+ }
25
+ }