@woosh/meep-engine 2.48.18 → 2.48.19

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/package.json CHANGED
@@ -5,7 +5,7 @@
5
5
  "description": "Fully featured ECS game engine written in JavaScript",
6
6
  "type": "module",
7
7
  "author": "Alexander Goldring",
8
- "version": "2.48.18",
8
+ "version": "2.48.19",
9
9
  "main": "build/meep.module.js",
10
10
  "module": "build/meep.module.js",
11
11
  "exports": {
@@ -4,6 +4,9 @@ const _z = new Vector3();
4
4
  const _x = new Vector3();
5
5
  const _y = new Vector3();
6
6
 
7
+ /**
8
+ * @deprecated use arrays instead or mat4 from gl-matrix
9
+ */
7
10
  export class Matrix4 {
8
11
  /**
9
12
  *
@@ -197,7 +200,7 @@ export class Matrix4 {
197
200
  const sz = Math.hypot(this.c0, this.c1, this.c2);
198
201
 
199
202
  // if determine is negative, we need to invert one scale
200
- const det = this.determinant();
203
+ const det = this.determinant();
201
204
  if (det < 0) sx = -sx;
202
205
 
203
206
  position.set(
@@ -26,8 +26,8 @@ export class Edge {
26
26
  * @constructor
27
27
  */
28
28
  constructor(a, b) {
29
- assert.notEqual(a, undefined, 'a is undefined');
30
- assert.notEqual(b, undefined, 'b is undefined');
29
+ assert.defined(a, 'a');
30
+ assert.defined(b, 'b');
31
31
 
32
32
  /**
33
33
  *
@@ -46,6 +46,11 @@ export class Edge {
46
46
  this.direction = EdgeDirectionType.Undirected;
47
47
  }
48
48
 
49
+ /**
50
+ *
51
+ * @param {N} node
52
+ * @return {boolean}
53
+ */
49
54
  contains(node) {
50
55
  return this.first === node || this.second === node;
51
56
  }
@@ -86,6 +91,8 @@ export class Edge {
86
91
  * @returns {number}
87
92
  */
88
93
  angle() {
94
+ console.error('method is deprecated, do not use');
95
+
89
96
  const delta = this.second.clone().sub(this.first);
90
97
  return Math.atan2(delta.y, delta.x);
91
98
  }
@@ -104,6 +111,8 @@ export class Edge {
104
111
  * @returns {number}
105
112
  */
106
113
  get length() {
114
+ console.error('method is deprecated, do not use');
115
+
107
116
  return this.first.distanceTo(this.second);
108
117
  }
109
118
  }
@@ -26,29 +26,31 @@ function construct_path(goal_node_container, cameFrom) {
26
26
  export class Graph {
27
27
 
28
28
  /**
29
- * @template N
29
+ *
30
+ * @type {Map<N, NodeContainer<N>>}
31
+ * @private
32
+ */
33
+ __nodes = new Map();
34
+ /**
35
+ *
36
+ * @type {Set<Edge<N>>}
37
+ * @private
30
38
  */
31
- constructor() {
39
+ __edges = new Set();
40
+
41
+ on = {
32
42
  /**
33
- *
34
- * @type {Map<N, NodeContainer<N>>}
35
- * @private
43
+ * @type {Signal<N,this>}
36
44
  */
37
- this.__nodes = new Map();
45
+ nodeAdded: new Signal(),
38
46
  /**
39
- *
40
- * @type {Set<Edge<N>>}
41
- * @private
47
+ * @type {Signal<N,this>}
42
48
  */
43
- this.__edges = new Set();
44
-
45
- this.on = {
46
- nodeAdded: new Signal(),
47
- nodeRemoved: new Signal(),
48
- edgeAdded: new Signal(),
49
- edgeRemoved: new Signal()
50
- };
51
- }
49
+ nodeRemoved: new Signal(),
50
+ edgeAdded: new Signal(),
51
+ edgeRemoved: new Signal()
52
+ };
53
+
52
54
 
53
55
  /**
54
56
  *
@@ -115,6 +117,14 @@ export class Graph {
115
117
  return this.__nodes.size;
116
118
  }
117
119
 
120
+ /**
121
+ *
122
+ * @returns {number}
123
+ */
124
+ getNodeCount() {
125
+ return this.__nodes.size;
126
+ }
127
+
118
128
  /**
119
129
  *
120
130
  * @param {function(N):boolean} filter
@@ -169,14 +179,6 @@ export class Graph {
169
179
  return this.__nodes.keys();
170
180
  }
171
181
 
172
- /**
173
- *
174
- * @returns {number}
175
- */
176
- getNodeCount() {
177
- return this.__nodes.size;
178
- }
179
-
180
182
  /**
181
183
  * Do not modify this set directly
182
184
  * @return {Set<Edge<N>>}
@@ -217,8 +219,10 @@ export class Graph {
217
219
  const context_0 = this.__nodes.get(edge.first);
218
220
  const context_1 = this.__nodes.get(edge.second);
219
221
 
220
- if (context_0 === undefined || context_1 === undefined) {
221
- throw new Error('One or more of the edge nodes are not part of the graph');
222
+ if (context_0 === undefined) {
223
+ throw new Error(`First node(=${edge.first}) of the edge is not part of the graph`);
224
+ } else if (context_1 === undefined) {
225
+ throw new Error(`Second node(=${edge.second}) of the edge is not part of the graph`);
222
226
  }
223
227
 
224
228
  context_0.addEdge(edge);
@@ -246,6 +250,7 @@ export class Graph {
246
250
  const context_1 = this.__nodes.get(edge.second);
247
251
 
248
252
  if (context_0 === undefined || context_1 === undefined) {
253
+ // this is a critical error, it should never happen as long as the API is used correctly
249
254
  throw new Error('One or both nodes of the edge are not present on the graph. This is a critical error');
250
255
  }
251
256
 
@@ -316,7 +321,7 @@ export class Graph {
316
321
  const context_a = this.__nodes.get(a);
317
322
 
318
323
  if (context_a === undefined) {
319
- // a is not in the graph
324
+ // A is not in the graph
320
325
  return undefined;
321
326
  }
322
327
 
@@ -334,10 +339,10 @@ export class Graph {
334
339
  * @param {N} to
335
340
  * @returns {Edge<N>|undefined}
336
341
  */
337
- getAnyDirectedEdge(from, to){
342
+ getAnyDirectedEdge(from, to) {
338
343
  const ctx_a = this.__nodes.get(from);
339
344
 
340
- if(ctx_a === undefined){
345
+ if (ctx_a === undefined) {
341
346
  return undefined;
342
347
  }
343
348
 
@@ -1,10 +1,89 @@
1
- import { Edge } from "../Edge.js";
1
+ import { Edge, EdgeDirectionType } from "../Edge.js";
2
2
  import { Graph } from "./Graph.js";
3
+ import { jest } from "@jest/globals";
3
4
 
4
5
  test("constructor doesn't throw", () => {
5
6
  expect(() => new Graph()).not.toThrow();
6
7
  });
7
8
 
9
+ test("adding same node twice", () => {
10
+
11
+ const graph = new Graph();
12
+
13
+ expect(graph.addNode(1)).toBe(true);
14
+ expect(graph.addNode(1)).toBe(false); // node already added
15
+
16
+ });
17
+
18
+ test("adding node triggers nodeAdded signal", () => {
19
+
20
+ const graph = new Graph();
21
+
22
+ const callback = jest.fn();
23
+
24
+ graph.on.nodeAdded.add(callback);
25
+
26
+ graph.addNode(7);
27
+
28
+ expect(callback).toHaveBeenCalledTimes(1);
29
+ expect(callback).toHaveBeenCalledWith(7, graph);
30
+
31
+ });
32
+
33
+ test("removing node triggers nodeRemoved signal", () => {
34
+
35
+ const graph = new Graph();
36
+
37
+ const callback = jest.fn();
38
+
39
+ graph.on.nodeRemoved.add(callback);
40
+
41
+ graph.addNode(7);
42
+
43
+ expect(callback).not.toHaveBeenCalled();
44
+
45
+ graph.removeNode(1); // trying to remove non-existent node
46
+
47
+ expect(callback).not.toHaveBeenCalled();
48
+
49
+ graph.removeNode(7);
50
+
51
+ expect(callback).toHaveBeenCalledTimes(1);
52
+ expect(callback).toHaveBeenCalledWith(7, graph);
53
+
54
+ graph.removeNode(7); //node was already removed, so we expect nothing to happen
55
+
56
+ expect(callback).toHaveBeenCalledTimes(1);
57
+ });
58
+
59
+ test("check node existence", () => {
60
+
61
+ const graph = new Graph();
62
+
63
+ expect(graph.hasNode(1)).toBe(false);
64
+
65
+ graph.addNode(1);
66
+
67
+ expect(graph.hasNode(1)).toBe(true);
68
+
69
+ });
70
+
71
+ test("removing node that does not exist", () => {
72
+ const graph = new Graph();
73
+
74
+ expect(graph.removeNode(1)).toBe(false);
75
+
76
+ });
77
+
78
+ test("removing same node twice", () => {
79
+ const graph = new Graph();
80
+
81
+ graph.addNode(1);
82
+
83
+ expect(graph.removeNode(1)).toBe(true);
84
+ expect(graph.removeNode(1)).toBe(false);
85
+ });
86
+
8
87
  test("nodeCount", () => {
9
88
  const g = new Graph();
10
89
 
@@ -19,6 +98,122 @@ test("nodeCount", () => {
19
98
  expect(g.nodeCount).toBe(0);
20
99
  });
21
100
 
101
+ test("findNode on empty graph", () => {
102
+ const graph = new Graph();
103
+
104
+ expect(graph.findNode(n => n === 1)).toBe(undefined);
105
+ });
106
+
107
+ test("findNode that doesn't exist on graph with 1 node", () => {
108
+ const graph = new Graph();
109
+
110
+ graph.addNode(3);
111
+
112
+ expect(graph.findNode(n => n === 1)).toBe(undefined);
113
+ });
114
+
115
+ test("findNode amongst two", () => {
116
+ const graph = new Graph();
117
+
118
+ graph.addNode(1);
119
+ graph.addNode(3);
120
+
121
+ expect(graph.findNode(n => n === 3)).toBe(3);
122
+ });
123
+
124
+ test("getNodeDegree", () => {
125
+
126
+ const graph = new Graph();
127
+
128
+ expect(graph.getNodeDegree(1)).toBe(0);
129
+
130
+ graph.addNode(1);
131
+
132
+ expect(graph.getNodeDegree(1)).toBe(0);
133
+
134
+ graph.addNode(3);
135
+
136
+ expect(graph.getNodeDegree(1)).toBe(0);
137
+ expect(graph.getNodeDegree(3)).toBe(0);
138
+
139
+ graph.createEdge(1, 3, EdgeDirectionType.Forward);
140
+
141
+ expect(graph.getNodeDegree(1)).toBe(1);
142
+ expect(graph.getNodeDegree(3)).toBe(1);
143
+ });
144
+
145
+ test("createEdge", () => {
146
+ const graph = new Graph();
147
+
148
+ graph.addNode(1);
149
+ graph.addNode(2);
150
+
151
+ graph.createEdge(1, 2, EdgeDirectionType.Forward);
152
+
153
+ expect(graph.edgeCount).toBe(1);
154
+
155
+ expect(graph.edgeExistsBetween(1, 2)).toBe(true);
156
+ });
157
+
158
+ test("adding edge where one of the nodes is not part of the graph should throw and exception", () => {
159
+ const graph = new Graph();
160
+
161
+ expect(() => graph.addEdge(new Edge(1, 2))).toThrow();
162
+
163
+ graph.addNode(1);
164
+
165
+ expect(() => graph.addEdge(new Edge(1, 2))).toThrow();
166
+
167
+ graph.removeNode(1);
168
+ graph.addNode(2);
169
+
170
+ expect(() => graph.addEdge(new Edge(1, 2))).toThrow();
171
+ });
172
+
173
+ test("add one valid edge", () => {
174
+
175
+ const graph = new Graph();
176
+
177
+ graph.addNode(1);
178
+ graph.addNode(2);
179
+
180
+ const edge = new Edge(1, 2);
181
+ expect(graph.addEdge(edge)).toBe(true);
182
+
183
+ expect(graph.hasEdge(edge)).toBe(true);
184
+
185
+ expect(graph.edgeCount).toBe(1);
186
+ });
187
+
188
+ test("add same edge twice", () => {
189
+
190
+ const graph = new Graph();
191
+
192
+ graph.addNode(1);
193
+ graph.addNode(2);
194
+
195
+ const edge = new Edge(1, 2);
196
+
197
+ expect(graph.addEdge(edge)).toBe(true);
198
+ expect(graph.addEdge(edge)).toBe(false); //already exists
199
+
200
+ expect(graph.hasEdge(edge)).toBe(true);
201
+
202
+ expect(graph.edgeCount).toBe(1);
203
+ });
204
+
205
+ test("remove non-existing edge", () => {
206
+
207
+ const graph = new Graph();
208
+
209
+ graph.addNode(1);
210
+ graph.addNode(2);
211
+
212
+ const edge = new Edge(1, 2);
213
+
214
+ expect(graph.removeEdge(edge)).toBe(false);
215
+ });
216
+
22
217
  test("edgeCount", () => {
23
218
  const g = new Graph();
24
219
 
@@ -54,3 +249,116 @@ test("after removing an edge, neighborhood is properly updated", () => {
54
249
  expect(g.getAttachedEdges(t, 1)).toBe(0);
55
250
  expect(g.getAttachedEdges(t, 2)).toBe(0);
56
251
  });
252
+
253
+ test("edgeExistsBetween", () => {
254
+ const graph = new Graph();
255
+
256
+ expect(graph.edgeExistsBetween(1, 2)).toBe(false);
257
+ expect(graph.edgeExistsBetween(2, 1)).toBe(false);
258
+
259
+ graph.addNode(1);
260
+
261
+ expect(graph.edgeExistsBetween(1, 2)).toBe(false);
262
+ expect(graph.edgeExistsBetween(2, 1)).toBe(false);
263
+
264
+ graph.addNode(2);
265
+
266
+ expect(graph.edgeExistsBetween(1, 2)).toBe(false);
267
+ expect(graph.edgeExistsBetween(2, 1)).toBe(false);
268
+
269
+ graph.createEdge(1, 2, EdgeDirectionType.Forward);
270
+
271
+ expect(graph.edgeExistsBetween(1, 2)).toBe(true);
272
+ expect(graph.edgeExistsBetween(2, 1)).toBe(true);
273
+
274
+ });
275
+
276
+ test("nodeHasEdges", () => {
277
+ const graph = new Graph();
278
+
279
+ expect(graph.nodeHasEdges(1)).toBe(false);
280
+
281
+ graph.addNode(1);
282
+
283
+ expect(graph.nodeHasEdges(1)).toBe(false);
284
+
285
+ graph.addNode(2);
286
+
287
+ expect(graph.nodeHasEdges(1)).toBe(false);
288
+
289
+ graph.createEdge(1, 2, EdgeDirectionType.Forward);
290
+
291
+ expect(graph.nodeHasEdges(1)).toBe(true);
292
+ expect(graph.nodeHasEdges(2)).toBe(true);
293
+ });
294
+
295
+ test("getAnyEdgeBetween", () => {
296
+
297
+ const graph = new Graph();
298
+
299
+ expect(graph.getAnyEdgeBetween(1, 2)).toBe(undefined);
300
+ expect(graph.getAnyEdgeBetween(2, 1)).toBe(undefined);
301
+
302
+ graph.addNode(1);
303
+
304
+ expect(graph.getAnyEdgeBetween(1, 2)).toBe(undefined);
305
+ expect(graph.getAnyEdgeBetween(2, 1)).toBe(undefined);
306
+
307
+ graph.addNode(2);
308
+
309
+ expect(graph.getAnyEdgeBetween(1, 2)).toBe(undefined);
310
+ expect(graph.getAnyEdgeBetween(2, 1)).toBe(undefined);
311
+
312
+ const edge = graph.createEdge(1, 2, EdgeDirectionType.Forward);
313
+
314
+ expect(graph.getAnyEdgeBetween(1, 2)).toBe(edge);
315
+ expect(graph.getAnyEdgeBetween(2, 1)).toBe(edge);
316
+ });
317
+
318
+ test("find path from node to itself", () => {
319
+ const graph = new Graph();
320
+
321
+ graph.addNode(1);
322
+
323
+ const path = graph.findPath(1, 1);
324
+
325
+ expect(path).toEqual([1]);
326
+ });
327
+
328
+ test("find path with 2 hops", () => {
329
+ const graph = new Graph();
330
+
331
+ graph.addNode(1);
332
+ graph.addNode(2);
333
+ graph.addNode(3);
334
+
335
+ graph.createEdge(1, 2, EdgeDirectionType.Forward);
336
+ graph.createEdge(2, 3, EdgeDirectionType.Forward);
337
+
338
+ const path = graph.findPath(1, 3);
339
+
340
+ expect(path).toEqual([1, 2, 3]);
341
+ });
342
+
343
+ test("clear method removes all nodes", () => {
344
+ const graph = new Graph();
345
+
346
+ graph.addNode(1);
347
+
348
+ graph.clear();
349
+
350
+ expect(graph.nodeCount).toBe(0);
351
+ });
352
+
353
+ test("clear method removes all edges", () => {
354
+ const graph = new Graph();
355
+
356
+ graph.addNode(1);
357
+ graph.addNode(2);
358
+
359
+ graph.createEdge(1, 2, EdgeDirectionType.Forward);
360
+
361
+ graph.clear();
362
+
363
+ expect(graph.edgeCount).toBe(0);
364
+ });
File without changes