@woosh/meep-engine 2.76.3 → 2.77.0

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 (26) hide show
  1. package/build/meep.cjs +202 -621
  2. package/build/meep.min.js +1 -1
  3. package/build/meep.module.js +202 -621
  4. package/editor/view/ecs/components/TerrainController.js +9 -16
  5. package/package.json +1 -1
  6. package/src/core/collection/heap/Uint32Heap.js +10 -1
  7. package/src/core/graph/Edge.js +20 -0
  8. package/src/core/graph/Graph.js +1 -0
  9. package/src/core/graph/SquareMatrix.js +4 -2
  10. package/src/core/graph/WeightedEdge.js +5 -9
  11. package/src/core/graph/coloring/validateGraphColoring.js +1 -1
  12. package/src/core/graph/eigen/matrix_eigenvalues_in_place.js +21 -0
  13. package/src/core/graph/eigen/{eigen.spec.js → matrix_eigenvalues_in_place.spec.js} +2 -2
  14. package/src/core/graph/eigen/matrix_householder_in_place.js +92 -0
  15. package/src/core/graph/eigen/{eigen.js → matrix_qr_in_place.js} +2 -113
  16. package/src/core/graph/v2/Graph.js +16 -9
  17. package/src/core/graph/v2/NodeContainer.js +120 -22
  18. package/src/engine/ecs/storage/binary/BinarySerializationRegistry.js +8 -6
  19. package/src/engine/graphics/particles/node-based/codegen/modules/FunctionModuleRegistry.js +1 -1
  20. package/src/engine/navigation/grid/find_path_on_grid_astar.js +30 -27
  21. package/src/engine/navigation/grid/find_path_on_grid_astar.spec.js +2 -2
  22. package/src/generation/grid/generation/road/GridTaskGenerateRoads.js +17 -33
  23. package/src/core/graph/GraphUtils.js +0 -284
  24. package/src/engine/ecs/terrain/ecs/splat/SplatMapMaterialPatch.js +0 -464
  25. package/src/engine/ecs/terrain/ecs/splat/SplatMapOptimizer.js +0 -622
  26. package/src/engine/ecs/terrain/ecs/splat/SplatMapOptimizerDebugger.js +0 -383
@@ -1,20 +1,19 @@
1
- import DatGuiController from "./DatGuiController.js";
1
+ import Signal from "../../../../src/core/events/signal/Signal.js";
2
2
  import Vector2 from "../../../../src/core/geom/Vector2.js";
3
- import View from "../../../../src/view/View.js";
4
- import { NativeListController } from "../../../../src/view/controller/controls/NativeListController.js";
3
+ import ObservedValue from "../../../../src/core/model/ObservedValue.js";
5
4
  import { TerrainLayer } from "../../../../src/engine/ecs/terrain/ecs/layers/TerrainLayer.js";
6
5
  import CheckersTextureURI from "../../../../src/engine/graphics/texture/CheckersTextureURI.js";
7
- import EmptyView from "../../../../src/view/elements/EmptyView.js";
8
- import convertSampler2D2Canvas from "../../../../src/engine/graphics/texture/sampler/Sampler2D2Canvas.js";
9
- import { CanvasView } from "../../../../src/view/elements/CanvasView.js";
10
6
  import { sampler2d_scale } from "../../../../src/engine/graphics/texture/sampler/resize/sampler2d_scale.js";
11
7
  import { Sampler2D } from "../../../../src/engine/graphics/texture/sampler/Sampler2D.js";
12
- import Signal from "../../../../src/core/events/signal/Signal.js";
8
+ import convertSampler2D2Canvas from "../../../../src/engine/graphics/texture/sampler/Sampler2D2Canvas.js";
9
+ import LabelView from "../../../../src/view/common/LabelView.js";
10
+ import { NativeListController } from "../../../../src/view/controller/controls/NativeListController.js";
13
11
  import Vector2Control from "../../../../src/view/controller/controls/Vector2Control.js";
12
+ import { CanvasView } from "../../../../src/view/elements/CanvasView.js";
13
+ import EmptyView from "../../../../src/view/elements/EmptyView.js";
14
14
  import GroupView from "../../../../src/view/elements/Group.js";
15
- import LabelView from "../../../../src/view/common/LabelView.js";
16
- import ObservedValue from "../../../../src/core/model/ObservedValue.js";
17
- import { SplatMapOptimizer } from "../../../../src/engine/ecs/terrain/ecs/splat/SplatMapOptimizer.js";
15
+ import View from "../../../../src/view/View.js";
16
+ import DatGuiController from "./DatGuiController.js";
18
17
 
19
18
  class LayersController extends View {
20
19
  /**
@@ -173,12 +172,6 @@ export class TerrainController extends View {
173
172
  model.__tiles.rebuild();
174
173
  }, 'Rebuild');
175
174
 
176
- controller.addAction(() => {
177
-
178
- SplatMapOptimizer.optimizeSynchronous(model.splat)
179
-
180
- }, 'Optimize Textures');
181
-
182
175
  controller.add(model, 'size', { step: 1 });
183
176
  controller.add(model, 'resolution').step(1);
184
177
  controller.add(model, 'gridScale').step(1).name('Gird Size');
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.76.3",
8
+ "version": "2.77.0",
9
9
  "main": "build/meep.module.js",
10
10
  "module": "build/meep.module.js",
11
11
  "exports": {
@@ -159,7 +159,7 @@ export class Uint32Heap {
159
159
  const size = this.__size;
160
160
 
161
161
  while (true) {
162
- const l = ((i) << 1) + 1;
162
+ const l = (i << 1) + 1;
163
163
  const r = l + 1;
164
164
 
165
165
  let smallest = i;
@@ -282,6 +282,15 @@ export class Uint32Heap {
282
282
  return -1;
283
283
  }
284
284
 
285
+ /**
286
+ *
287
+ * @param {number} id
288
+ * @returns {boolean}
289
+ */
290
+ contains(id){
291
+ return this.find_index_by_id(id) !== -1;
292
+ }
293
+
285
294
  /**
286
295
  * Clear out all the data, heap will be made empty
287
296
  */
@@ -86,6 +86,26 @@ export class Edge {
86
86
  return (this.direction & EdgeDirectionType.Backward) !== 0;
87
87
  }
88
88
 
89
+ /**
90
+ * Checks direction of the edge, if the edge is directed towards supplied node - returns true, false otherwise
91
+ * @param {N} node
92
+ * @returns {boolean}
93
+ */
94
+ isDirectedTowards(node) {
95
+ return (this.first === node && this.direction === EdgeDirectionType.Backward)
96
+ || (this.second === node && this.direction === EdgeDirectionType.Forward);
97
+ }
98
+
99
+ /**
100
+ * Checks direction of the edge, if the edge is directed away from the supplied node - returns true, false otherwise
101
+ * @param {N} node
102
+ * @returns {boolean}
103
+ */
104
+ isDirectedAwayFrom(node) {
105
+ return (this.first === node && this.direction === EdgeDirectionType.Forward)
106
+ || (this.second === node && this.direction === EdgeDirectionType.Backward)
107
+ }
108
+
89
109
  /**
90
110
  * @deprecated
91
111
  * @returns {number}
@@ -15,6 +15,7 @@ import { Edge, EdgeDirectionType } from "./Edge.js";
15
15
 
16
16
  /**
17
17
  * @template N
18
+ * @deprecated use v2 `Graph` class instead, it's faster and has a wider range of algorithms built on top of it
18
19
  */
19
20
  export class Graph {
20
21
  /**
@@ -1,5 +1,5 @@
1
- import { DataType2TypedArrayConstructorMapping } from "../binary/type/DataType2TypedArrayConstructorMapping.js";
2
1
  import { assert } from "../assert.js";
2
+ import { DataType2TypedArrayConstructorMapping } from "../binary/type/DataType2TypedArrayConstructorMapping.js";
3
3
  import { array_copy } from "../collection/array/array_copy.js";
4
4
 
5
5
  export class SquareMatrix {
@@ -9,6 +9,8 @@ export class SquareMatrix {
9
9
  * @param {BinaryDataType|string} type
10
10
  */
11
11
  constructor(size, type) {
12
+ assert.isNonNegativeInteger(size, 'size');
13
+
12
14
  const TypedArray = DataType2TypedArrayConstructorMapping[type];
13
15
 
14
16
  if (TypedArray === undefined) {
@@ -162,7 +164,7 @@ export class SquareMatrix {
162
164
  * @param {number[]} [destination]
163
165
  * @param {number} [offset]
164
166
  */
165
- toArray(destination = new Array(this.length), offset=0) {
167
+ toArray(destination = new Array(this.length), offset = 0) {
166
168
  array_copy(this.data, 0, destination, offset, this.length);
167
169
 
168
170
  return destination;
@@ -1,15 +1,11 @@
1
1
  import { Edge } from "./Edge.js";
2
2
 
3
3
  export class WeightedEdge extends Edge {
4
- constructor(a, b) {
5
- super(a, b);
6
-
7
- /**
8
- *
9
- * @type {number}
10
- */
11
- this.weight = 0;
12
- }
4
+ /**
5
+ *
6
+ * @type {number}
7
+ */
8
+ weight = 0;
13
9
 
14
10
  /**
15
11
  *
@@ -1,5 +1,5 @@
1
1
  /**
2
- *
2
+ * Debug method used for validating coloring. Will pass if no two nodes share a color
3
3
  * @param {number[]} colors
4
4
  * @param {Graph} graph
5
5
  * @returns {boolean}
@@ -0,0 +1,21 @@
1
+ import { matrix_householder_in_place } from "./matrix_householder_in_place.js";
2
+ import { matrix_qr_in_place } from "./matrix_qr_in_place.js";
3
+
4
+
5
+ /**
6
+ * list of eigen values square matrix (allow non symmetric)
7
+ * NOTE: Modifies input matrix
8
+ * @param {SquareMatrix} mat
9
+ * @return {number[]}
10
+ */
11
+ export function matrix_eigenvalues_in_place(mat) {
12
+ const n = mat.size;
13
+ matrix_householder_in_place(mat.data, n);
14
+ matrix_qr_in_place(mat.data, n);
15
+
16
+ const result = new Float32Array(n);
17
+
18
+ mat.readDiagonal(result);
19
+
20
+ return result;
21
+ }
@@ -1,6 +1,6 @@
1
- import { SquareMatrix } from "../SquareMatrix.js";
2
1
  import { BinaryDataType } from "../../binary/type/BinaryDataType.js";
3
- import { matrix_eigenvalues_in_place } from "./eigen.js";
2
+ import { SquareMatrix } from "../SquareMatrix.js";
3
+ import { matrix_eigenvalues_in_place } from "./matrix_eigenvalues_in_place.js";
4
4
 
5
5
  function roughly_equal_array_vectors(actual, expected) {
6
6
  expect(actual.length).toBe(expected.length);
@@ -0,0 +1,92 @@
1
+ const EPSILON = 1e-10;
2
+
3
+ /**
4
+ * NxN matrix Householder reduction
5
+ * Return subfunction to upper Hessenberg matrix by Householder transformation
6
+ * @see http://www-in.aut.ac.jp/~minemura/pub/Csimu/C/QRmethod.html
7
+ * @param {number[]} a
8
+ * @param {number} n
9
+ */
10
+ export function matrix_householder_in_place(a, n) {
11
+ const u = new Float64Array(n);
12
+ const d = new Float64Array(n);
13
+ const ds = new Float64Array(n);
14
+
15
+ let i, j, k;
16
+ let sum;
17
+
18
+ for (k = 0; k <= n - 3; k++) {
19
+
20
+ for (i = 0; i <= k; i++) {
21
+ u[i] = 0;
22
+ }
23
+
24
+ for (i = k + 1; i < n; i++) {
25
+ u[i] = a[n * i + k];
26
+ }
27
+
28
+ // Build transformation matrix H
29
+ sum = 0.0;
30
+
31
+ for (i = k + 1; i < n; i++) {
32
+ sum = sum + u[i] * u[i];
33
+ }
34
+
35
+ const u_k_1 = u[k + 1];
36
+
37
+ const u_k_1_abs = Math.abs(u_k_1);
38
+ if (u_k_1_abs < EPSILON) {
39
+ continue;
40
+ }
41
+
42
+ const sigma = Math.sqrt(sum) * u_k_1 / u_k_1_abs;
43
+
44
+ u[k + 1] += sigma;
45
+
46
+ const v_norm = Math.sqrt(2.0 * sigma * u[k + 1]);
47
+
48
+ for (i = k + 1; i < n; i++) {
49
+ u[i] /= v_norm;
50
+ }
51
+
52
+ // Similarity transformation
53
+ for (i = 0; i < n; i++) {
54
+ d[i] = 0.0;
55
+ ds[i] = 0.0;
56
+ for (j = k + 1; j <= n - 1; j++) {
57
+ const u_j = u[j];
58
+
59
+ d[i] += a[n * i + j] * u_j;
60
+ ds[i] += a[n * j + i] * u_j;
61
+ }
62
+ }
63
+
64
+ let ud = 0.0;
65
+ let uds = 0.0;
66
+
67
+ for (i = k + 1; i < n; i++) {
68
+ const u_i = u[i];
69
+
70
+ ud += u_i * d[i];
71
+ uds += u_i * ds[i];
72
+ }
73
+
74
+ for (i = 0; i < n; i++) {
75
+ const u_i = u[i];
76
+
77
+ d[i] = 2.0 * (d[i] - ud * u_i);
78
+ ds[i] = 2.0 * (ds[i] - uds * u_i);
79
+ }
80
+
81
+ for (i = 0; i < n; i++) {
82
+ const u_i = u[i];
83
+ const d_i = d[i];
84
+
85
+ const n_i = n * i;
86
+
87
+ for (j = 0; j < n; j++) {
88
+ a[n_i + j] -= u_i * ds[j] + d_i * u[j];
89
+ }
90
+ }
91
+ }
92
+ }
@@ -1,97 +1,5 @@
1
1
  const EPSILON = 1e-10;
2
2
 
3
- /**
4
- * NxN matrix Householder reduction
5
- * Return subfunction to upper Hessenberg matrix by Householder transformation
6
- * @see http://www-in.aut.ac.jp/~minemura/pub/Csimu/C/QRmethod.html
7
- * @param {number[]} a
8
- * @param {number} n
9
- */
10
- function householder_in_place(a, n) {
11
- const u = new Float64Array(n);
12
- const d = new Float64Array(n);
13
- const ds = new Float64Array(n);
14
-
15
- let i, j, k;
16
- let sum;
17
-
18
- for (k = 0; k <= n - 3; k++) {
19
-
20
- for (i = 0; i <= k; i++) {
21
- u[i] = 0;
22
- }
23
-
24
- for (i = k + 1; i < n; i++) {
25
- u[i] = a[n * i + k];
26
- }
27
-
28
- // Build transformation matrix H
29
- sum = 0.0;
30
-
31
- for (i = k + 1; i < n; i++) {
32
- sum = sum + u[i] * u[i];
33
- }
34
-
35
- const u_k_1 = u[k + 1];
36
-
37
- const u_k_1_abs = Math.abs(u_k_1);
38
- if (u_k_1_abs < EPSILON) {
39
- continue;
40
- }
41
-
42
- const sigma = Math.sqrt(sum) * u_k_1 / u_k_1_abs;
43
-
44
- u[k + 1] += sigma;
45
-
46
- const v_norm = Math.sqrt(2.0 * sigma * u[k + 1]);
47
-
48
- for (i = k + 1; i < n; i++) {
49
- u[i] /= v_norm;
50
- }
51
-
52
- // Similarity transformation
53
- for (i = 0; i < n; i++) {
54
- d[i] = 0.0;
55
- ds[i] = 0.0;
56
- for (j = k + 1; j <= n - 1; j++) {
57
- const u_j = u[j];
58
-
59
- d[i] += a[n * i + j] * u_j;
60
- ds[i] += a[n * j + i] * u_j;
61
- }
62
- }
63
-
64
- let ud = 0.0;
65
- let uds = 0.0;
66
-
67
- for (i = k + 1; i < n; i++) {
68
- const u_i = u[i];
69
-
70
- ud += u_i * d[i];
71
- uds += u_i * ds[i];
72
- }
73
-
74
- for (i = 0; i < n; i++) {
75
- const u_i = u[i];
76
-
77
- d[i] = 2.0 * (d[i] - ud * u_i);
78
- ds[i] = 2.0 * (ds[i] - uds * u_i);
79
- }
80
-
81
- for (i = 0; i < n; i++) {
82
- const u_i = u[i];
83
- const d_i = d[i];
84
-
85
- const n_i = n * i;
86
-
87
- for (j = 0; j < n; j++) {
88
- a[n_i + j] -= u_i * ds[j] + d_i * u[j];
89
- }
90
- }
91
- }
92
- }
93
-
94
-
95
3
  /**
96
4
  * Perform QR factorization in-place
97
5
  * Subfunction that analyzes eigenvalues by QR decomposition
@@ -99,7 +7,7 @@ function householder_in_place(a, n) {
99
7
  * @param {number[]} a Square matrix
100
8
  * @param {number} n size of the matrix in single dimension
101
9
  */
102
- function qr_in_place(a, n) {
10
+ export function matrix_qr_in_place(a, n) {
103
11
  const q = new Float64Array(n * n);
104
12
  const w = new Float64Array(n);
105
13
 
@@ -207,23 +115,4 @@ function qr_in_place(a, n) {
207
115
  a[n * i + i] += mu;
208
116
  }
209
117
  }
210
- }
211
-
212
-
213
- /**
214
- * list of eigen values square matrix (allow non symmetric)
215
- * NOTE: Modifies input matrix
216
- * @param {SquareMatrix} mat
217
- * @return {number[]}
218
- */
219
- export function matrix_eigenvalues_in_place(mat) {
220
- const n = mat.size;
221
- householder_in_place(mat.data, n);
222
- qr_in_place(mat.data, n);
223
-
224
- const result = new Float32Array(n);
225
-
226
- mat.readDiagonal(result);
227
-
228
- return result;
229
- }
118
+ }
@@ -1,20 +1,23 @@
1
1
  import { assert } from "../../assert.js";
2
2
  import Signal from "../../events/signal/Signal.js";
3
- import { NodeContainer } from "./NodeContainer.js";
4
3
  import { Edge, EdgeDirectionType } from "../Edge.js";
4
+ import { NodeContainer } from "./NodeContainer.js";
5
5
 
6
6
  /**
7
+ * Reconstruct path from search metadata
7
8
  * @template T
8
9
  * @param {NodeContainer<T>} goal_node_container
9
- * @param {Map<NodeContainer<T>,NodeContainer<T>>} cameFrom
10
- * @returns {T[]}
10
+ * @param {Map<NodeContainer<T>,NodeContainer<T>>} came_from
11
+ * @returns {T[]} Nodes comprising the path from start to goal
11
12
  */
12
- function construct_path(goal_node_container, cameFrom) {
13
+ function construct_path(goal_node_container, came_from) {
13
14
  const result = [];
15
+
14
16
  let c = goal_node_container;
17
+
15
18
  do {
16
19
  result.unshift(c.node);
17
- c = cameFrom.get(c);
20
+ c = came_from.get(c);
18
21
  } while (c !== undefined);
19
22
 
20
23
  return result;
@@ -28,16 +31,21 @@ export class Graph {
28
31
  /**
29
32
  *
30
33
  * @type {Map<N, NodeContainer<N>>}
34
+ * @readonly
31
35
  * @private
32
36
  */
33
37
  __nodes = new Map();
34
38
  /**
35
39
  *
36
40
  * @type {Set<Edge<N>>}
41
+ * @readonly
37
42
  * @private
38
43
  */
39
44
  __edges = new Set();
40
45
 
46
+ /**
47
+ * @readonly
48
+ */
41
49
  on = {
42
50
  /**
43
51
  * @type {Signal<N,this>}
@@ -191,10 +199,10 @@ export class Graph {
191
199
  *
192
200
  * @param {N} source
193
201
  * @param {N} target
194
- * @param {EdgeDirectionType} type
202
+ * @param {EdgeDirectionType} [type] Undirected by default
195
203
  * @returns {Edge<N>}
196
204
  */
197
- createEdge(source, target, type) {
205
+ createEdge(source, target, type = EdgeDirectionType.Undirected) {
198
206
  const edge = new Edge(source, target);
199
207
 
200
208
  edge.direction = type;
@@ -376,8 +384,7 @@ export class Graph {
376
384
  const edge_count = edges.length;
377
385
 
378
386
  for (let i = 0; i < edge_count; i++) {
379
- const edge = edges[i];
380
- result[i] = edge;
387
+ result[i] = edges[i];
381
388
  }
382
389
 
383
390
  return edge_count;
@@ -1,45 +1,141 @@
1
1
  import { EdgeDirectionType } from "../Edge.js";
2
2
 
3
+ /**
4
+ * Supplementary structure to `Graph`, holds edges and neighbour nodes for fast access
5
+ * Used internally by `Graph`
6
+ * @template N
7
+ */
3
8
  export class NodeContainer {
4
9
  /**
5
- * @template N
10
+ * Node being described
11
+ * @type {N}
6
12
  */
7
- constructor() {
8
- /**
9
- *
10
- * @type {N}
11
- */
12
- this.node = null;
13
+ node = null;
14
+
15
+ /**
16
+ * Attached edges
17
+ * @type {Edge<N>[]}
18
+ * @private
19
+ */
20
+ __edges = [];
21
+
22
+ /**
23
+ *
24
+ * @type {Map<N,number>}
25
+ * @private
26
+ */
27
+ __neighbors = new Map();
28
+
29
+ /**
30
+ *
31
+ * @return {number}
32
+ */
33
+ getEdgeCount() {
34
+ return this.__edges.length;
35
+ }
36
+
37
+ /**
38
+ * Do not modify the returned value
39
+ * @return {Edge<N>[]}
40
+ */
41
+ getEdges() {
42
+ return this.__edges;
43
+ }
13
44
 
45
+ /**
46
+ *
47
+ * @returns {N[]}
48
+ */
49
+ get inNodes() {
50
+ return this.inEdges.map(e => e.other(this.node));
51
+ }
52
+
53
+ /**
54
+ *
55
+ * @returns {N[]}
56
+ */
57
+ get outNodes() {
58
+ return this.outEdges.map(e => e.other(this.node));
59
+ }
60
+
61
+
62
+ get outEdges() {
14
63
  /**
15
64
  *
16
65
  * @type {Edge<N>[]}
17
- * @private
18
66
  */
19
- this.__edges = [];
67
+ const result = [];
20
68
 
69
+ this.getOutgoingEdges(result);
70
+
71
+ return result;
72
+ }
73
+
74
+ get inEdges() {
21
75
  /**
22
76
  *
23
- * @type {Map<N,number>}
24
- * @private
77
+ * @type {Edge<N>[]}
25
78
  */
26
- this.__neighbors = new Map();
79
+ const result = [];
80
+
81
+ this.getIncomingEdges(result);
82
+
83
+ return result;
27
84
  }
28
85
 
86
+
29
87
  /**
30
88
  *
31
- * @return {number}
89
+ * @param {Edge<N>[]} result
90
+ * @returns {number}
32
91
  */
33
- getEdgeCount() {
34
- return this.__edges.length;
92
+ getIncomingEdges(result) {
93
+ const edges = this.__edges;
94
+
95
+ const edge_count = edges.length;
96
+
97
+ let result_count = 0;
98
+
99
+ for (let i = 0; i < edge_count; i++) {
100
+ const edge = edges[i];
101
+
102
+ if (edge.isDirectedTowards(this.node)) {
103
+
104
+ result.push(edge);
105
+ result_count++;
106
+
107
+ }
108
+
109
+ }
110
+
111
+ return result_count;
35
112
  }
36
113
 
37
114
  /**
38
- * Do not modify the returned value
39
- * @return {Edge<N>[]}
115
+ *
116
+ * @param {Edge<N>[]} result
117
+ * @returns {number}
40
118
  */
41
- getEdges() {
42
- return this.__edges;
119
+ getOutgoingEdges(result) {
120
+ const edges = this.__edges;
121
+
122
+ const edge_count = edges.length;
123
+
124
+ let result_count = 0;
125
+
126
+ for (let i = 0; i < edge_count; i++) {
127
+ const edge = edges[i];
128
+
129
+ if (edge.isDirectedAwayFrom(this.node)) {
130
+
131
+ result.push(edge);
132
+ result_count++;
133
+
134
+ }
135
+
136
+ }
137
+
138
+ return result_count;
43
139
  }
44
140
 
45
141
  /**
@@ -52,12 +148,14 @@ export class NodeContainer {
52
148
  const edges = this.__edges;
53
149
  const edge_count = edges.length;
54
150
 
151
+ const current_node = this.node;
152
+
55
153
  for (let i = 0; i < edge_count; i++) {
56
154
  const edge = edges[i];
57
155
 
58
156
  if (
59
- (edge.first === this.node && edge.direction === EdgeDirectionType.Forward)
60
- || (edge.second === this.node && edge.direction === EdgeDirectionType.Backward)
157
+ (edge.first === current_node && edge.direction === EdgeDirectionType.Forward)
158
+ || (edge.second === current_node && edge.direction === EdgeDirectionType.Backward)
61
159
 
62
160
  ) {
63
161
  r++;
@@ -81,7 +179,7 @@ export class NodeContainer {
81
179
 
82
180
  /**
83
181
  *
84
- * @param {function(Edge)} visitor
182
+ * @param {function(Edge<N>)} visitor
85
183
  * @param {*} [thisArg]
86
184
  * @returns {number}
87
185
  */