@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,5 +1,5 @@
1
1
  import { assert } from "../../../../core/assert.js";
2
- import { Graph } from "../../../../core/graph/Graph.js";
2
+ import { Graph } from "../../../../core/graph/v2/Graph.js";
3
3
 
4
4
  /**
5
5
  * Contains serializers for various data types as well as data upgraders which enable support for serialization format changes
@@ -39,25 +39,27 @@ export class BinarySerializationRegistry {
39
39
  assert.defined(adapter, 'adapter');
40
40
  assert.ok(adapter.isBinaryClassSerializationAdapter, 'adapter is not a BinaryClassSerializationAdapter');
41
41
 
42
- if (className === undefined) {
42
+ let _className = className;
43
+
44
+ if (_className === undefined) {
43
45
  const klass = adapter.getClass();
44
46
 
45
47
  if (typeof klass.typeName === "string") {
46
- className = klass.typeName;
48
+ _className = klass.typeName;
47
49
  } else {
48
50
  throw new Error(`className not specified, could not infer class name from the class itself`);
49
51
  }
50
52
  }
51
53
 
52
- if (this.serializers.has(className)) {
54
+ if (this.serializers.has(_className)) {
53
55
  //a serializer already exists
54
56
 
55
- console.warn(`Serializer for class '${className}' already exists, ignoring request`);
57
+ console.warn(`Serializer for class '${_className}' already exists, ignoring request`);
56
58
 
57
59
  return false;
58
60
  }
59
61
 
60
- this.serializers.set(className, adapter);
62
+ this.serializers.set(_className, adapter);
61
63
 
62
64
  return true;
63
65
  }
@@ -1,6 +1,6 @@
1
1
  import { assert } from "../../../../../../core/assert.js";
2
- import Graph from "../../../../../../core/graph/Graph.js";
3
2
  import { Edge, EdgeDirectionType } from "../../../../../../core/graph/Edge.js";
3
+ import { Graph } from "../../../../../../core/graph/v2/Graph.js";
4
4
  import { FunctionModuleReference } from "./FunctionModuleReference.js";
5
5
 
6
6
  export class FunctionModuleRegistry {
@@ -26,7 +26,7 @@ function index2point(result, index, width) {
26
26
  * @param {number} height
27
27
  * @returns {number}
28
28
  */
29
- function computeNeighbors(result, index, width, height) {
29
+ function compute_neighbors(result, index, width, height) {
30
30
  const x = index % width;
31
31
  const y = (index / width) | 0;
32
32
 
@@ -36,14 +36,17 @@ function computeNeighbors(result, index, width, height) {
36
36
  result[neighbour_count] = index - width;
37
37
  neighbour_count++
38
38
  }
39
+
39
40
  if (x > 0) {
40
41
  result[neighbour_count] = index - 1;
41
42
  neighbour_count++;
42
43
  }
44
+
43
45
  if (x < width - 1) {
44
46
  result[neighbour_count] = index + 1;
45
47
  neighbour_count++;
46
48
  }
49
+
47
50
  if (y < height - 1) {
48
51
  result[neighbour_count] = index + width;
49
52
  neighbour_count++
@@ -60,7 +63,7 @@ function computeNeighbors(result, index, width, height) {
60
63
  * @param {number} height
61
64
  * @returns {number[]}
62
65
  */
63
- function pathTo(node, g_score, width, height) {
66
+ function compute_path(node, g_score, width, height) {
64
67
  let v_previous = new Vector2(-1, -1);
65
68
  let v_current = new Vector2();
66
69
 
@@ -111,7 +114,7 @@ function pathTo(node, g_score, width, height) {
111
114
  v_current = t;
112
115
 
113
116
  // find next point
114
- const neighbour_count = computeNeighbors(neighbors, current, width, height);
117
+ const neighbour_count = compute_neighbors(neighbors, current, width, height);
115
118
 
116
119
  current = -1;
117
120
 
@@ -166,15 +169,15 @@ function heuristic(index0, index1, width) {
166
169
  const x1 = index0 % width;
167
170
  const y1 = (index0 / width) | 0;
168
171
 
169
- //
170
172
  const x2 = index1 % width;
171
173
  const y2 = (index1 / width) | 0;
172
174
 
173
- //
174
- const dx = Math.abs(x1 - x2);
175
- const dy = Math.abs(y1 - y2);
175
+ // deltas
176
+ const dx = x2 - x1;
177
+ const dy = y2 - y1;
176
178
 
177
- return dx + dy;
179
+ // we skip expensive SQRT, but still get a good guiding heuristic which has the same monotonic order
180
+ return dx * dx + dy * dy;
178
181
  }
179
182
 
180
183
 
@@ -190,16 +193,16 @@ closed.preventShrink();
190
193
  * @param {number} height
191
194
  * @param {number} start
192
195
  * @param {number} goal
193
- * @param {number} crossingPenalty
194
- * @param {number} blockValue value in the field that signifies impassible obstacle
196
+ * @param {number} crossing_penalty
197
+ * @param {number} block_value value in the field that signifies impassible obstacle
195
198
  * @returns {Array.<number>} array of indices representing path from start to end
196
199
  */
197
200
  export function find_path_on_grid_astar(
198
201
  field,
199
202
  width, height,
200
203
  start, goal,
201
- crossingPenalty,
202
- blockValue
204
+ crossing_penalty,
205
+ block_value
203
206
  ) {
204
207
 
205
208
  assert.defined(field, 'field');
@@ -208,8 +211,8 @@ export function find_path_on_grid_astar(
208
211
  assert.isNonNegativeInteger(start, "start");
209
212
  assert.isNonNegativeInteger(goal, "goal");
210
213
 
211
- assert.isNumber(crossingPenalty, 'crossingPenalty');
212
- assert.isNumber(blockValue, 'blockValue');
214
+ assert.isNumber(crossing_penalty, 'crossingPenalty');
215
+ assert.isNumber(block_value, 'blockValue');
213
216
 
214
217
  // prepare sets
215
218
  open.clear();
@@ -232,15 +235,15 @@ export function find_path_on_grid_astar(
232
235
  const currentNode = open.pop_min();
233
236
 
234
237
  if (currentNode === goal) {
235
- // End case -- result has been found, return the traced path.
236
- return pathTo(currentNode, g_score, width, height);
238
+ // End case - result has been found, return the traced path.
239
+ return compute_path(currentNode, g_score, width, height);
237
240
  }
238
241
 
239
242
  // Normal case -- move currentNode from open to closed, process each of its neighbors.
240
243
  closed.set(currentNode, true);
241
244
 
242
245
  // Find all neighbors for the current node.
243
- const neighbour_count = computeNeighbors(neighbors, currentNode, width, height);
246
+ const neighbour_count = compute_neighbors(neighbors, currentNode, width, height);
244
247
 
245
248
  for (let i = 0; i < neighbour_count; ++i) {
246
249
  const neighbor = neighbors[i];
@@ -252,39 +255,39 @@ export function find_path_on_grid_astar(
252
255
 
253
256
  // The g score is the shortest distance from start to current node.
254
257
  // We need to check if the path we have arrived at this neighbor is the shortest one we have seen yet.
255
- const neighborValue = field[neighbor];
258
+ const neighbor_value = field[neighbor];
256
259
 
257
- if (neighborValue === blockValue) {
260
+ if (neighbor_value === block_value) {
258
261
  //cell is blocked, close and continue
259
262
  closed.set(neighbor, true);
260
263
  continue;
261
264
  }
262
265
 
263
266
  // Cost of traversing to this neighbour
264
- const transition_cost = neighborValue * crossingPenalty + 1;
267
+ const transition_cost = neighbor_value * crossing_penalty + 1;
265
268
 
266
269
  // updated path cost
267
- const gScore = g_score[currentNode] + transition_cost;
270
+ const cost_so_far = g_score[currentNode] + transition_cost;
268
271
 
269
272
  const index_in_open_set = open.find_index_by_id(neighbor);
270
273
 
271
274
  const not_in_open_set = index_in_open_set === -1;
272
275
 
273
- if (not_in_open_set || gScore < g_score[neighbor]) {
276
+ if (not_in_open_set || cost_so_far < g_score[neighbor]) {
274
277
 
275
278
  // update refined score
276
- g_score[neighbor] = gScore;
279
+ g_score[neighbor] = cost_so_far;
277
280
 
278
- const h = heuristic(neighbor, goal, width);
281
+ const remaining_heuristic = heuristic(neighbor, goal, width);
279
282
 
280
- const fScore = gScore + h;
283
+ const refined_heuristic = cost_so_far + remaining_heuristic;
281
284
 
282
285
  if (not_in_open_set) {
283
286
  // Pushing to heap will put it in proper place based on the 'f' value.
284
- open.insert(neighbor, fScore);
287
+ open.insert(neighbor, refined_heuristic);
285
288
  } else {
286
289
  // Already seen the node, but since it has been re-scored we need to reorder it in the heap
287
- open.__update_score_by_index(index_in_open_set, fScore);
290
+ open.__update_score_by_index(index_in_open_set, refined_heuristic);
288
291
  }
289
292
  }
290
293
  }
@@ -33,7 +33,7 @@ test("path on open 3x3 grid", () => {
33
33
  0, 0, 0
34
34
  ], 3, 3, 0, 8, 0, 1);
35
35
 
36
- expect(path).toEqual([0, 6, 8]);
36
+ expect(path).toEqual([0, 3, 5, 8]);
37
37
  });
38
38
 
39
39
  test("performance, 256x256 random", () => {
@@ -45,7 +45,7 @@ test("performance, 256x256 random", () => {
45
45
 
46
46
  const last_field_index = field.length - 1;
47
47
 
48
- for (let i = 0; i < field.length * 0.05; i++) {
48
+ for (let i = 0; i < field.length * 0.15; i++) {
49
49
  const index = randomIntegerBetween(random, 0, last_field_index);
50
50
 
51
51
  field[index] = 255;
@@ -1,46 +1,30 @@
1
+ import { GridTags } from "../../../../../samples/generation/grid/GridTags.js";
2
+ import { MirGridLayers } from "../../../../../samples/generation/grid/MirGridLayers.js";
3
+ import { matcher_tag_traversable } from "../../../../../samples/generation/rules/matcher_tag_traversable.js";
4
+ import { BitSet } from "../../../../core/binary/BitSet.js";
5
+ import { groupArrayBy } from "../../../../core/collection/array/groupArrayBy.js";
6
+ import { collectIteratorValueToArray } from "../../../../core/collection/collectIteratorValueToArray.js";
7
+ import BinaryHeap from "../../../../core/collection/heap/FastBinaryHeap.js";
8
+ import { QuadTreeNode } from "../../../../core/geom/2d/quad-tree/QuadTreeNode.js";
9
+ import { Graph } from "../../../../core/graph/v2/Graph.js";
1
10
  import { seededRandom } from "../../../../core/math/random/seededRandom.js";
2
- import { GridTaskGenerator } from "../../GridTaskGenerator.js";
11
+ import { remap } from "../../../../core/math/remap.js";
3
12
  import TaskGroup from "../../../../core/process/task/TaskGroup.js";
4
- import Graph from "../../../../core/graph/Graph.js";
5
- import BinaryHeap from "../../../../core/collection/heap/FastBinaryHeap.js";
6
- import { BitSet } from "../../../../core/binary/BitSet.js";
7
- import { matcher_tag_traversable } from "../../../../../samples/generation/rules/matcher_tag_traversable.js";
8
- import { buildPathFromDistanceMap } from "../util/buildPathFromDistanceMap.js";
13
+ import { actionTask } from "../../../../core/process/task/util/actionTask.js";
14
+ import { countTask } from "../../../../core/process/task/util/countTask.js";
9
15
  import { GridCellActionPlaceTags } from "../../../placement/action/GridCellActionPlaceTags.js";
10
- import { GridTags } from "../../../../../samples/generation/grid/GridTags.js";
11
16
  import { CellMatcher } from "../../../rules/CellMatcher.js";
12
- import { collectIteratorValueToArray } from "../../../../core/collection/collectIteratorValueToArray.js";
13
- import { QuadTreeNode } from "../../../../core/geom/2d/quad-tree/QuadTreeNode.js";
14
- import AABB2 from "../../../../core/geom/2d/aabb/AABB2.js";
17
+ import { CellMatcherNot } from "../../../rules/logic/CellMatcherNot.js";
18
+ import { GridTaskGenerator } from "../../GridTaskGenerator.js";
19
+ import { buildPathFromDistanceMap } from "../util/buildPathFromDistanceMap.js";
20
+ import { buildUnsignedDistanceField } from "../util/buildUnsignedDistanceField.js";
15
21
  import { PathEndPoint } from "./PathEndPoint.js";
16
- import { RoadConnection } from "./RoadConnection.js";
17
22
  import { readMarkerNodeGroupId } from "./readMarkerNodeGroupId.js";
18
- import { buildUnsignedDistanceField } from "../util/buildUnsignedDistanceField.js";
19
- import { CellMatcherNot } from "../../../rules/logic/CellMatcherNot.js";
23
+ import { RoadConnection } from "./RoadConnection.js";
20
24
  import { RoadConnectionNetwork } from "./RoadConnectionNetwork.js";
21
- import { MirGridLayers } from "../../../../../samples/generation/grid/MirGridLayers.js";
22
- import { actionTask } from "../../../../core/process/task/util/actionTask.js";
23
- import { countTask } from "../../../../core/process/task/util/countTask.js";
24
- import { groupArrayBy } from "../../../../core/collection/array/groupArrayBy.js";
25
- import { remap } from "../../../../core/math/remap.js";
26
25
 
27
26
  const NODE_TYPE_ROAD_CONNECTOR = 'Road Connector';
28
27
 
29
-
30
- /**
31
- *
32
- * @param {QuadTreeNode} tree
33
- * @param {RoadConnection} path
34
- * @param {number} gridWidth
35
- */
36
- function addPathToQuadTree(tree, path, gridWidth) {
37
- const bounds = new AABB2();
38
-
39
- path.computeBounds(bounds, gridWidth);
40
-
41
- tree.add(path, bounds.x0, bounds.y0, bounds.x1, bounds.y1);
42
- }
43
-
44
28
  /**
45
29
  *
46
30
  * @param {MarkerNode[]} array
@@ -1,284 +0,0 @@
1
- /**
2
- * Created by Alex on 05/02/14.
3
- */
4
-
5
-
6
- import {
7
- line_segment_compute_line_segment_intersection_vectors_array_2d
8
- } from "../geom/2d/line/line_segment_compute_line_segment_intersection_vectors_array_2d.js";
9
-
10
- const Utils = {};
11
-
12
- function pointBetweenEdges(edge1, edge2, node, thickness) {
13
- const other1 = edge1.other(node);
14
- const other2 = edge2.other(node);
15
- const delta1 = other1.clone().sub(node);
16
- const delta2 = other2.clone().sub(node);
17
- const sum = delta2.normalize().clone().add(delta1.normalize());
18
- let angle = edge2.angle() - edge1.angle();
19
- if (angle < 0) {
20
- angle += Math.PI * 2;
21
- }
22
- // console.log(angle * (57.295));
23
- if (angle === 0) {
24
- //parallel edges
25
- sum.set(delta1.y, delta1.x);
26
- sum.multiplyScalar(thickness / 2);
27
- console.log(">");
28
- } else {
29
- const scalar = (thickness / 2) * (1 + sum.length() / 4);
30
- sum.normalize().multiplyScalar(scalar);
31
- if (angle > Math.PI) {
32
- console.log("<");
33
- sum.negate();
34
- }
35
- }
36
- return sum;
37
- }
38
-
39
- function angleDifference(edge1, edge2) {
40
- return edge1.angle() - edge2.angle();
41
- }
42
-
43
- function trace2(graph, thickness) {
44
- //clone graph
45
- const g = graph.clone();
46
- let closedNodes = [];
47
- let closedEdges = [];
48
- //edge needs to be covered twice to be closed
49
- let prevEdge, prevNode,
50
- currentEdge, currentNode;
51
- while (g.edges.length > 0) {
52
- //pick next edge
53
- const node = prevEdge.other(prevNode);
54
- const neighbours = g.getAttachedEdges(node);
55
- neighbours.sort(angleDifference);
56
- let index = neighbours.indexOf(prevEdge);
57
- index = (index + 1) % neighbours.length;
58
- const edge = neighbours[index];
59
- }
60
- }
61
-
62
- function makeCap(node, edge, thickness, type) {
63
- const result = [];
64
- //get direction
65
- const other = edge.other(node);
66
- const first = node.clone();
67
- const second = other.clone();
68
- const delta = second.clone().sub(first);
69
- const inverseDelta = delta.clone();
70
- //
71
- inverseDelta.x = delta.y;
72
- inverseDelta.y = -delta.x;
73
-
74
- inverseDelta.normalize();
75
- //projecting cap
76
- if (type === "projecting") {
77
- const half_thickness = thickness / 2;
78
- const sid = inverseDelta.clone().multiplyScalar(half_thickness);
79
- //projecting offset
80
- const offset = delta.clone().normalize().multiplyScalar(half_thickness);
81
- const anchor = node.clone().sub(offset);
82
- result.push(sid.clone().add(anchor));
83
- result.push(sid.negate().add(anchor));
84
- }
85
- return result;
86
- }
87
-
88
- function makeJoint2(node, edges, thickness) {
89
- const result = [];
90
- //sort edges by angle
91
- edges.sort(angleDifference);
92
-
93
- for (let i = 0; i < edges.length; i++) {
94
- const j = (i + 1) % edges.length;
95
- const edge1 = edges[i];
96
- const edge2 = edges[j];
97
- const sum = pointBetweenEdges(edge1, edge2, node, thickness);
98
- result.push({
99
- point: sum,
100
- edges: [edge1, edge2]
101
- })
102
- }
103
- result.forEach(function (element) {
104
- element.point.add(node);
105
- });
106
- return result;
107
- }
108
-
109
- function graph2paths(graph, thickness) {
110
- const points = [];
111
- const nodes = graph.nodes;
112
- //generating outline points
113
- for (let i = 0; i < nodes.length; i++) {
114
- const node = nodes[i];
115
- const attachedEdges = graph.getAttachedEdges(node);
116
- const length = attachedEdges.length;
117
- if (length === 0) {
118
- //this node is not attached to any edge
119
- console.warn("unconnected node, not representable");
120
- } else if (length === 1) {
121
- //this is an end point
122
- const attachedEdge = attachedEdges[0];
123
- const cap = makeCap(node, attachedEdge, thickness, "projecting");
124
- cap.forEach(function (point) {
125
- points.push({ node: node, edges: [attachedEdge], position: point });
126
- });
127
- } else if (length > 1) {
128
- //this is a joint
129
- const joint = makeJoint2(node, attachedEdges, thickness, null);
130
- joint.forEach(function (data) {
131
- points.push({ node: node, edges: data.edges, position: data.point })
132
- });
133
- }
134
- }
135
- let path;
136
-
137
- function getCommonEdge(point1, point2) {
138
- const edges1 = point1.edges;
139
- const edges2 = point2.edges;
140
- const l1 = edges1.length;
141
- const l2 = edges2.length;
142
- for (let i = 0; i < l1; i++) {
143
- const edge1 = edges1[i];
144
- for (let j = 0; j < l2; j++) {
145
- const edge2 = edges2[j];
146
- if (edge1 === edge2) {
147
- return edge1;
148
- }
149
- }
150
- }
151
- return null;
152
- }
153
-
154
- function lineIntersectsGraph(from, to, graph) {
155
- const edges = graph.edges;
156
- let i = 0;
157
- const l = edges.length;
158
- for (; i < l; i++) {
159
- const edge = edges[i];
160
- if (line_segment_compute_line_segment_intersection_vectors_array_2d(from, to, edge.first, edge.second)) {
161
- return true;
162
- }
163
- }
164
- return false;
165
- }
166
-
167
- function getNextPoint2(from) {
168
- //filter points based on common edge
169
- const edges0 = from.edges;
170
- const l0 = edges0.length;
171
- const candidates = [];
172
- points.forEach(function (point, index) {
173
- const edges1 = point.edges;
174
- const l1 = edges1.length;
175
- for (let i = 0; i < l0; i++) {
176
- const e0 = edges0[i];
177
- for (let j = 0; j < l1; j++) {
178
- const e1 = edges1[j];
179
- if (e0 === e1) {
180
- //now filter out those that cross the graph
181
- if (!lineIntersectsGraph(from.position, point.position, graph)) {
182
- candidates.push(index);
183
- }
184
- }
185
- }
186
- }
187
- });
188
- if (candidates.length > 0) {
189
- const index = candidates[0];
190
- const point = points[index];
191
- points.splice(index, 1);
192
- return point;
193
- } else {
194
- console.warn("No next point from ", from);
195
- }
196
-
197
- }
198
-
199
- function getNextPoint(from) {
200
- for (let i = 0; i < points.length; i++) {
201
- const p = points[i];
202
- const commonEdge = getCommonEdge(p, from);
203
- if (commonEdge != null) {
204
- //make sure line would not intersect the edge
205
- // var intersects = getLineIntersection(p.position, from.position, commonEdge.first, commonEdge.second);
206
- const intersects = lineIntersectsGraph(p.position, from.position, graph);
207
- if (intersects) {
208
- continue;
209
- }
210
- points.splice(i, 1);
211
- return p;
212
- }
213
- }
214
- console.warn("No next point from", from);
215
- return null;
216
- }
217
-
218
- function trace() {
219
- //pick a point
220
- let currentPoint = points.pop();
221
- let nextPoint;
222
- path.moveTo(currentPoint.position.x, currentPoint.position.y);
223
- // console.log("path.moveTo("+currentPoint.position.x+","+currentPoint.position.y+");");
224
- const firstPoint = currentPoint;
225
- for (nextPoint = getNextPoint2(currentPoint); nextPoint != null; nextPoint = getNextPoint2(currentPoint)) {
226
- path.lineTo(nextPoint.position.x, nextPoint.position.y);
227
- // console.log("path.lineTo("+nextPoint.position.x+","+nextPoint.position.y+");");
228
- currentPoint = nextPoint;
229
- }
230
- path.lineTo(firstPoint.position.x, firstPoint.position.y);
231
- // console.log("path.lineTo("+firstPoint.position.x+","+firstPoint.position.y+");");
232
- }
233
-
234
- const paths = [];
235
- while (points.length > 0) {
236
- path = new THREE.Path();
237
- trace();
238
- paths.push(path);
239
- }
240
- return paths;
241
- }
242
-
243
- function graph2rects(graph, thickness) {
244
- const edges = graph.edges;
245
- const paths = [];
246
- for (let i = 0; i < edges.length; i++) {
247
- const path = new THREE.Path();
248
- const edge = edges[i];
249
- //outline edge
250
- const cap1 = makeCap(edge.first, edge, thickness, "projecting");
251
- const cap2 = makeCap(edge.second, edge, thickness, "projecting");
252
- const points = cap1.concat(cap2);
253
- let point = points[0];
254
- path.moveTo(point.x, point.y);
255
- let j = 1;
256
- const l = points.length;
257
- for (; j < l + 1; j++) {
258
- point = points[j % l];
259
- path.lineTo(point.x, point.y);
260
- }
261
- paths.push(path);
262
- }
263
- return paths;
264
- }
265
-
266
- Utils.makeJoint2 = makeJoint2;
267
-
268
- Utils.paths2shapes = function (paths) {
269
- const shapes = [];
270
- paths.forEach(function (path) {
271
- const r = path.toShapes();
272
- Array.prototype.push.apply(shapes, r);
273
- });
274
- return shapes;
275
- };
276
-
277
- Utils.graph2shapes = function (graph, thickness) {
278
- const paths = Utils.graph2paths(graph, thickness);
279
- return Utils.paths2shapes(paths);
280
- };
281
-
282
- Utils.graph2paths = graph2paths;
283
-
284
- export default Utils;