@footgun/cobalt 0.3.3 → 0.5.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.
- package/CHANGELOG.md +7 -2
- package/bundle.js +9 -9
- package/examples/07-sdl/main.js +0 -1
- package/examples/07-sdl/package.json +2 -2
- package/examples/09-sdl-polar-meters/package.json +3 -3
- package/package.json +8 -3
- package/packages/box-intersect/index.js +138 -0
- package/packages/box-intersect/lib/brute.js +144 -0
- package/packages/box-intersect/lib/intersect.js +494 -0
- package/packages/box-intersect/lib/median.js +142 -0
- package/packages/box-intersect/lib/partition.js +20 -0
- package/packages/box-intersect/lib/sort.js +236 -0
- package/packages/box-intersect/lib/sweep.js +434 -0
- package/packages/box-intersect/package.json +24 -0
- package/packages/clean-pslg/clean-pslg.js +381 -0
- package/packages/clean-pslg/lib/rat-seg-intersect.js +42 -0
- package/packages/clean-pslg/package.json +29 -0
- package/packages/poly-to-pslg/package.json +15 -0
- package/packages/poly-to-pslg/poly-to-pslg.js +51 -0
- package/packages/typedarray-pool/package.json +17 -0
- package/packages/typedarray-pool/pool.js +225 -0
- package/src/primitives/primitives.js +13 -3
- package/src/primitives/public-api.js +44 -0
|
@@ -0,0 +1,381 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
module.exports = cleanPSLG
|
|
4
|
+
|
|
5
|
+
var UnionFind = require('union-find')
|
|
6
|
+
var boxIntersect = require('box-intersect')
|
|
7
|
+
var segseg = require('robust-segment-intersect')
|
|
8
|
+
var rat = require('big-rat')
|
|
9
|
+
var ratCmp = require('big-rat/cmp')
|
|
10
|
+
var ratToFloat = require('big-rat/to-float')
|
|
11
|
+
var ratVec = require('rat-vec')
|
|
12
|
+
var nextafter = require('nextafter')
|
|
13
|
+
|
|
14
|
+
var solveIntersection = require('./lib/rat-seg-intersect')
|
|
15
|
+
|
|
16
|
+
// Bounds on a rational number when rounded to a float
|
|
17
|
+
function boundRat (r) {
|
|
18
|
+
var f = ratToFloat(r)
|
|
19
|
+
return [
|
|
20
|
+
nextafter(f, -Infinity),
|
|
21
|
+
nextafter(f, Infinity)
|
|
22
|
+
]
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
// Convert a list of edges in a pslg to bounding boxes
|
|
26
|
+
function boundEdges (points, edges) {
|
|
27
|
+
var bounds = new Array(edges.length)
|
|
28
|
+
for (var i = 0; i < edges.length; ++i) {
|
|
29
|
+
var e = edges[i]
|
|
30
|
+
var a = points[e[0]]
|
|
31
|
+
var b = points[e[1]]
|
|
32
|
+
bounds[i] = [
|
|
33
|
+
nextafter(Math.min(a[0], b[0]), -Infinity),
|
|
34
|
+
nextafter(Math.min(a[1], b[1]), -Infinity),
|
|
35
|
+
nextafter(Math.max(a[0], b[0]), Infinity),
|
|
36
|
+
nextafter(Math.max(a[1], b[1]), Infinity)
|
|
37
|
+
]
|
|
38
|
+
}
|
|
39
|
+
return bounds
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
// Convert a list of points into bounding boxes by duplicating coords
|
|
43
|
+
function boundPoints (points) {
|
|
44
|
+
var bounds = new Array(points.length)
|
|
45
|
+
for (var i = 0; i < points.length; ++i) {
|
|
46
|
+
var p = points[i]
|
|
47
|
+
bounds[i] = [
|
|
48
|
+
nextafter(p[0], -Infinity),
|
|
49
|
+
nextafter(p[1], -Infinity),
|
|
50
|
+
nextafter(p[0], Infinity),
|
|
51
|
+
nextafter(p[1], Infinity)
|
|
52
|
+
]
|
|
53
|
+
}
|
|
54
|
+
return bounds
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// Find all pairs of crossing edges in a pslg (given edge bounds)
|
|
58
|
+
function getCrossings (points, edges, edgeBounds) {
|
|
59
|
+
var result = []
|
|
60
|
+
boxIntersect(edgeBounds, function (i, j) {
|
|
61
|
+
var e = edges[i]
|
|
62
|
+
var f = edges[j]
|
|
63
|
+
if (e[0] === f[0] || e[0] === f[1] ||
|
|
64
|
+
e[1] === f[0] || e[1] === f[1]) {
|
|
65
|
+
return
|
|
66
|
+
}
|
|
67
|
+
var a = points[e[0]]
|
|
68
|
+
var b = points[e[1]]
|
|
69
|
+
var c = points[f[0]]
|
|
70
|
+
var d = points[f[1]]
|
|
71
|
+
if (segseg(a, b, c, d)) {
|
|
72
|
+
result.push([i, j])
|
|
73
|
+
}
|
|
74
|
+
})
|
|
75
|
+
return result
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
// Find all pairs of crossing vertices in a pslg (given edge/vert bounds)
|
|
79
|
+
function getTJunctions (points, edges, edgeBounds, vertBounds) {
|
|
80
|
+
var result = []
|
|
81
|
+
boxIntersect(edgeBounds, vertBounds, function (i, v) {
|
|
82
|
+
var e = edges[i]
|
|
83
|
+
if (e[0] === v || e[1] === v) {
|
|
84
|
+
return
|
|
85
|
+
}
|
|
86
|
+
var p = points[v]
|
|
87
|
+
var a = points[e[0]]
|
|
88
|
+
var b = points[e[1]]
|
|
89
|
+
if (segseg(a, b, p, p)) {
|
|
90
|
+
result.push([i, v])
|
|
91
|
+
}
|
|
92
|
+
})
|
|
93
|
+
return result
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
// Cut edges along crossings/tjunctions
|
|
97
|
+
function cutEdges (floatPoints, edges, crossings, junctions, useColor) {
|
|
98
|
+
var i, e
|
|
99
|
+
|
|
100
|
+
// Convert crossings into tjunctions by constructing rational points
|
|
101
|
+
var ratPoints = floatPoints.map(function(p) {
|
|
102
|
+
return [
|
|
103
|
+
rat(p[0]),
|
|
104
|
+
rat(p[1])
|
|
105
|
+
]
|
|
106
|
+
})
|
|
107
|
+
for (i = 0; i < crossings.length; ++i) {
|
|
108
|
+
var crossing = crossings[i]
|
|
109
|
+
e = crossing[0]
|
|
110
|
+
var f = crossing[1]
|
|
111
|
+
var ee = edges[e]
|
|
112
|
+
var ef = edges[f]
|
|
113
|
+
var x = solveIntersection(
|
|
114
|
+
ratVec(floatPoints[ee[0]]),
|
|
115
|
+
ratVec(floatPoints[ee[1]]),
|
|
116
|
+
ratVec(floatPoints[ef[0]]),
|
|
117
|
+
ratVec(floatPoints[ef[1]]))
|
|
118
|
+
if (!x) {
|
|
119
|
+
// Segments are parallel, should already be handled by t-junctions
|
|
120
|
+
continue
|
|
121
|
+
}
|
|
122
|
+
var idx = floatPoints.length
|
|
123
|
+
floatPoints.push([ratToFloat(x[0]), ratToFloat(x[1])])
|
|
124
|
+
ratPoints.push(x)
|
|
125
|
+
junctions.push([e, idx], [f, idx])
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
// Sort tjunctions
|
|
129
|
+
junctions.sort(function (a, b) {
|
|
130
|
+
if (a[0] !== b[0]) {
|
|
131
|
+
return a[0] - b[0]
|
|
132
|
+
}
|
|
133
|
+
var u = ratPoints[a[1]]
|
|
134
|
+
var v = ratPoints[b[1]]
|
|
135
|
+
return ratCmp(u[0], v[0]) || ratCmp(u[1], v[1])
|
|
136
|
+
})
|
|
137
|
+
|
|
138
|
+
// Split edges along junctions
|
|
139
|
+
for (i = junctions.length - 1; i >= 0; --i) {
|
|
140
|
+
var junction = junctions[i]
|
|
141
|
+
e = junction[0]
|
|
142
|
+
|
|
143
|
+
var edge = edges[e]
|
|
144
|
+
var s = edge[0]
|
|
145
|
+
var t = edge[1]
|
|
146
|
+
|
|
147
|
+
// Check if edge is not lexicographically sorted
|
|
148
|
+
var a = floatPoints[s]
|
|
149
|
+
var b = floatPoints[t]
|
|
150
|
+
if (((a[0] - b[0]) || (a[1] - b[1])) < 0) {
|
|
151
|
+
var tmp = s
|
|
152
|
+
s = t
|
|
153
|
+
t = tmp
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
// Split leading edge
|
|
157
|
+
edge[0] = s
|
|
158
|
+
var last = edge[1] = junction[1]
|
|
159
|
+
|
|
160
|
+
// If we are grouping edges by color, remember to track data
|
|
161
|
+
var color
|
|
162
|
+
if (useColor) {
|
|
163
|
+
color = edge[2]
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
// Split other edges
|
|
167
|
+
while (i > 0 && junctions[i - 1][0] === e) {
|
|
168
|
+
var junction = junctions[--i]
|
|
169
|
+
var next = junction[1]
|
|
170
|
+
if (useColor) {
|
|
171
|
+
edges.push([last, next, color])
|
|
172
|
+
} else {
|
|
173
|
+
edges.push([last, next])
|
|
174
|
+
}
|
|
175
|
+
last = next
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
// Add final edge
|
|
179
|
+
if (useColor) {
|
|
180
|
+
edges.push([last, t, color])
|
|
181
|
+
} else {
|
|
182
|
+
edges.push([last, t])
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
// Return constructed rational points
|
|
187
|
+
return ratPoints
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
// Merge overlapping points
|
|
191
|
+
function dedupPoints (floatPoints, ratPoints, floatBounds) {
|
|
192
|
+
var numPoints = ratPoints.length
|
|
193
|
+
var uf = new UnionFind(numPoints)
|
|
194
|
+
|
|
195
|
+
// Compute rational bounds
|
|
196
|
+
var bounds = []
|
|
197
|
+
for (var i = 0; i < ratPoints.length; ++i) {
|
|
198
|
+
var p = ratPoints[i]
|
|
199
|
+
var xb = boundRat(p[0])
|
|
200
|
+
var yb = boundRat(p[1])
|
|
201
|
+
bounds.push([
|
|
202
|
+
nextafter(xb[0], -Infinity),
|
|
203
|
+
nextafter(yb[0], -Infinity),
|
|
204
|
+
nextafter(xb[1], Infinity),
|
|
205
|
+
nextafter(yb[1], Infinity)
|
|
206
|
+
])
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
// Link all points with over lapping boxes
|
|
210
|
+
boxIntersect(bounds, function (i, j) {
|
|
211
|
+
uf.link(i, j)
|
|
212
|
+
})
|
|
213
|
+
|
|
214
|
+
// Do 1 pass over points to combine points in label sets
|
|
215
|
+
var noDupes = true
|
|
216
|
+
var labels = new Array(numPoints)
|
|
217
|
+
for (var i = 0; i < numPoints; ++i) {
|
|
218
|
+
var j = uf.find(i)
|
|
219
|
+
if (j !== i) {
|
|
220
|
+
// Clear no-dupes flag, zero out label
|
|
221
|
+
noDupes = false
|
|
222
|
+
// Make each point the top-left point from its cell
|
|
223
|
+
floatPoints[j] = [
|
|
224
|
+
Math.min(floatPoints[i][0], floatPoints[j][0]),
|
|
225
|
+
Math.min(floatPoints[i][1], floatPoints[j][1])
|
|
226
|
+
]
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
// If no duplicates, return null to signal termination
|
|
231
|
+
if (noDupes) {
|
|
232
|
+
return null
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
var ptr = 0
|
|
236
|
+
for (var i = 0; i < numPoints; ++i) {
|
|
237
|
+
var j = uf.find(i)
|
|
238
|
+
if (j === i) {
|
|
239
|
+
labels[i] = ptr
|
|
240
|
+
floatPoints[ptr++] = floatPoints[i]
|
|
241
|
+
} else {
|
|
242
|
+
labels[i] = -1
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
floatPoints.length = ptr
|
|
247
|
+
|
|
248
|
+
// Do a second pass to fix up missing labels
|
|
249
|
+
for (var i = 0; i < numPoints; ++i) {
|
|
250
|
+
if (labels[i] < 0) {
|
|
251
|
+
labels[i] = labels[uf.find(i)]
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
// Return resulting union-find data structure
|
|
256
|
+
return labels
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
function compareLex2 (a, b) { return (a[0] - b[0]) || (a[1] - b[1]) }
|
|
260
|
+
function compareLex3 (a, b) {
|
|
261
|
+
var d = (a[0] - b[0]) || (a[1] - b[1])
|
|
262
|
+
if (d) {
|
|
263
|
+
return d
|
|
264
|
+
}
|
|
265
|
+
if (a[2] < b[2]) {
|
|
266
|
+
return -1
|
|
267
|
+
} else if (a[2] > b[2]) {
|
|
268
|
+
return 1
|
|
269
|
+
}
|
|
270
|
+
return 0
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
// Remove duplicate edge labels
|
|
274
|
+
function dedupEdges (edges, labels, useColor) {
|
|
275
|
+
if (edges.length === 0) {
|
|
276
|
+
return
|
|
277
|
+
}
|
|
278
|
+
if (labels) {
|
|
279
|
+
for (var i = 0; i < edges.length; ++i) {
|
|
280
|
+
var e = edges[i]
|
|
281
|
+
var a = labels[e[0]]
|
|
282
|
+
var b = labels[e[1]]
|
|
283
|
+
e[0] = Math.min(a, b)
|
|
284
|
+
e[1] = Math.max(a, b)
|
|
285
|
+
}
|
|
286
|
+
} else {
|
|
287
|
+
for (var i = 0; i < edges.length; ++i) {
|
|
288
|
+
var e = edges[i]
|
|
289
|
+
var a = e[0]
|
|
290
|
+
var b = e[1]
|
|
291
|
+
e[0] = Math.min(a, b)
|
|
292
|
+
e[1] = Math.max(a, b)
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
if (useColor) {
|
|
296
|
+
edges.sort(compareLex3)
|
|
297
|
+
} else {
|
|
298
|
+
edges.sort(compareLex2)
|
|
299
|
+
}
|
|
300
|
+
var ptr = 1
|
|
301
|
+
for (var i = 1; i < edges.length; ++i) {
|
|
302
|
+
var prev = edges[i - 1]
|
|
303
|
+
var next = edges[i]
|
|
304
|
+
if (next[0] === prev[0] && next[1] === prev[1] &&
|
|
305
|
+
(!useColor || next[2] === prev[2])) {
|
|
306
|
+
continue
|
|
307
|
+
}
|
|
308
|
+
edges[ptr++] = next
|
|
309
|
+
}
|
|
310
|
+
edges.length = ptr
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
function preRound (points, edges, useColor) {
|
|
314
|
+
var labels = dedupPoints(points, [], boundPoints(points))
|
|
315
|
+
dedupEdges(edges, labels, useColor)
|
|
316
|
+
return !!labels
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
// Repeat until convergence
|
|
320
|
+
function snapRound (points, edges, useColor) {
|
|
321
|
+
// 1. find edge crossings
|
|
322
|
+
var edgeBounds = boundEdges(points, edges)
|
|
323
|
+
var crossings = getCrossings(points, edges, edgeBounds)
|
|
324
|
+
|
|
325
|
+
// 2. find t-junctions
|
|
326
|
+
var vertBounds = boundPoints(points)
|
|
327
|
+
var tjunctions = getTJunctions(points, edges, edgeBounds, vertBounds)
|
|
328
|
+
|
|
329
|
+
// 3. cut edges, construct rational points
|
|
330
|
+
var ratPoints = cutEdges(points, edges, crossings, tjunctions, useColor)
|
|
331
|
+
|
|
332
|
+
// 4. dedupe verts
|
|
333
|
+
var labels = dedupPoints(points, ratPoints, vertBounds)
|
|
334
|
+
|
|
335
|
+
// 5. dedupe edges
|
|
336
|
+
dedupEdges(edges, labels, useColor)
|
|
337
|
+
|
|
338
|
+
// 6. check termination
|
|
339
|
+
if (!labels) {
|
|
340
|
+
return (crossings.length > 0 || tjunctions.length > 0)
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
// More iterations necessary
|
|
344
|
+
return true
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
// Main loop, runs PSLG clean up until completion
|
|
348
|
+
function cleanPSLG (points, edges, colors) {
|
|
349
|
+
// If using colors, augment edges with color data
|
|
350
|
+
var prevEdges
|
|
351
|
+
if (colors) {
|
|
352
|
+
prevEdges = edges
|
|
353
|
+
var augEdges = new Array(edges.length)
|
|
354
|
+
for (var i = 0; i < edges.length; ++i) {
|
|
355
|
+
var e = edges[i]
|
|
356
|
+
augEdges[i] = [e[0], e[1], colors[i]]
|
|
357
|
+
}
|
|
358
|
+
edges = augEdges
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
// First round: remove duplicate edges and points
|
|
362
|
+
var modified = preRound(points, edges, !!colors)
|
|
363
|
+
|
|
364
|
+
// Run snap rounding until convergence
|
|
365
|
+
while (snapRound(points, edges, !!colors)) {
|
|
366
|
+
modified = true
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
// Strip color tags
|
|
370
|
+
if (!!colors && modified) {
|
|
371
|
+
prevEdges.length = 0
|
|
372
|
+
colors.length = 0
|
|
373
|
+
for (var i = 0; i < edges.length; ++i) {
|
|
374
|
+
var e = edges[i]
|
|
375
|
+
prevEdges.push([e[0], e[1]])
|
|
376
|
+
colors.push(e[2])
|
|
377
|
+
}
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
return modified
|
|
381
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
module.exports = solveIntersection
|
|
4
|
+
|
|
5
|
+
var ratMul = require('big-rat/mul')
|
|
6
|
+
var ratDiv = require('big-rat/div')
|
|
7
|
+
var ratSub = require('big-rat/sub')
|
|
8
|
+
var ratSign = require('big-rat/sign')
|
|
9
|
+
var rvSub = require('rat-vec/sub')
|
|
10
|
+
var rvAdd = require('rat-vec/add')
|
|
11
|
+
var rvMuls = require('rat-vec/muls')
|
|
12
|
+
|
|
13
|
+
function ratPerp (a, b) {
|
|
14
|
+
return ratSub(ratMul(a[0], b[1]), ratMul(a[1], b[0]))
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
// Solve for intersection
|
|
18
|
+
// x = a + t (b-a)
|
|
19
|
+
// (x - c) ^ (d-c) = 0
|
|
20
|
+
// (t * (b-a) + (a-c) ) ^ (d-c) = 0
|
|
21
|
+
// t * (b-a)^(d-c) = (d-c)^(a-c)
|
|
22
|
+
// t = (d-c)^(a-c) / (b-a)^(d-c)
|
|
23
|
+
|
|
24
|
+
function solveIntersection (a, b, c, d) {
|
|
25
|
+
var ba = rvSub(b, a)
|
|
26
|
+
var dc = rvSub(d, c)
|
|
27
|
+
|
|
28
|
+
var baXdc = ratPerp(ba, dc)
|
|
29
|
+
|
|
30
|
+
if (ratSign(baXdc) === 0) {
|
|
31
|
+
return null
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
var ac = rvSub(a, c)
|
|
35
|
+
var dcXac = ratPerp(dc, ac)
|
|
36
|
+
|
|
37
|
+
var t = ratDiv(dcXac, baXdc)
|
|
38
|
+
var s = rvMuls(ba, t)
|
|
39
|
+
var r = rvAdd(a, s)
|
|
40
|
+
|
|
41
|
+
return r
|
|
42
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "clean-pslg",
|
|
3
|
+
"version": "1.1.2",
|
|
4
|
+
"description": "",
|
|
5
|
+
"license": "ISC",
|
|
6
|
+
"author": "",
|
|
7
|
+
"type": "commonjs",
|
|
8
|
+
"private": true,
|
|
9
|
+
"main": "clean-pslg.js",
|
|
10
|
+
"scripts": {
|
|
11
|
+
"test": "echo \"Error: no test specified\" && exit 1"
|
|
12
|
+
},
|
|
13
|
+
"dependencies": {
|
|
14
|
+
"big-rat": "^1.0.3",
|
|
15
|
+
"nextafter": "^1.0.0",
|
|
16
|
+
"rat-vec": "^1.1.1",
|
|
17
|
+
"robust-segment-intersect": "^1.0.1",
|
|
18
|
+
"union-find": "^1.0.2",
|
|
19
|
+
"uniq": "^1.0.1"
|
|
20
|
+
},
|
|
21
|
+
"devDependencies": {
|
|
22
|
+
"canvas-fit": "^1.4.0",
|
|
23
|
+
"mouse-change": "^1.2.1",
|
|
24
|
+
"robust-orientation": "^1.1.3",
|
|
25
|
+
"segment2": "^0.3.2",
|
|
26
|
+
"tape": "^5.9.0",
|
|
27
|
+
"vec2": "^1.6.0"
|
|
28
|
+
}
|
|
29
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "poly-to-pslg",
|
|
3
|
+
"version": "1.0.1",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"private": true,
|
|
6
|
+
"description": "",
|
|
7
|
+
"license": "ISC",
|
|
8
|
+
"author": "",
|
|
9
|
+
"main": "poly-to-pslg.js",
|
|
10
|
+
"scripts": {
|
|
11
|
+
"test": "echo \"Error: no test specified\" && exit 1"
|
|
12
|
+
},
|
|
13
|
+
"dependencies": {
|
|
14
|
+
}
|
|
15
|
+
}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import cleanPSLG from 'clean-pslg'
|
|
2
|
+
|
|
3
|
+
//Converts a polygon to a planar straight line graph
|
|
4
|
+
export default function polygonToPSLG (loops, options) {
|
|
5
|
+
if(!Array.isArray(loops)) {
|
|
6
|
+
throw new Error('poly-to-pslg: Error, invalid polygon')
|
|
7
|
+
}
|
|
8
|
+
if(loops.length === 0) {
|
|
9
|
+
return {
|
|
10
|
+
points: [],
|
|
11
|
+
edges: []
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
options = options || {}
|
|
16
|
+
|
|
17
|
+
var nested = true
|
|
18
|
+
if('nested' in options) {
|
|
19
|
+
nested = !!options.nested
|
|
20
|
+
} else if(loops[0].length === 2 && typeof loops[0][0] === 'number') {
|
|
21
|
+
//Hack: If use doesn't pass in a loop, then try to guess if it is nested
|
|
22
|
+
nested = false
|
|
23
|
+
}
|
|
24
|
+
if(!nested) {
|
|
25
|
+
loops = [loops]
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
//First we just unroll all the points in the dumb/obvious way
|
|
29
|
+
var points = []
|
|
30
|
+
var edges = []
|
|
31
|
+
for(var i=0; i<loops.length; ++i) {
|
|
32
|
+
var loop = loops[i]
|
|
33
|
+
var offset = points.length
|
|
34
|
+
for(var j=0; j<loop.length; ++j) {
|
|
35
|
+
points.push(loop[j])
|
|
36
|
+
edges.push([ offset+j, offset+(j+1)%loop.length ])
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
//Then we run snap rounding to clean up self intersections and duplicate verts
|
|
41
|
+
var clean = 'clean' in options ? true : !!options.clean
|
|
42
|
+
if(clean) {
|
|
43
|
+
cleanPSLG(points, edges)
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
//Finally, we return the resulting PSLG
|
|
47
|
+
return {
|
|
48
|
+
points: points,
|
|
49
|
+
edges: edges
|
|
50
|
+
}
|
|
51
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "typedarray-pool",
|
|
3
|
+
"version": "1.2.0",
|
|
4
|
+
"description": "",
|
|
5
|
+
"license": "ISC",
|
|
6
|
+
"author": "",
|
|
7
|
+
"type": "commonjs",
|
|
8
|
+
"private": true,
|
|
9
|
+
"main": "pool.js",
|
|
10
|
+
"scripts": {
|
|
11
|
+
"test": "echo \"Error: no test specified\" && exit 1"
|
|
12
|
+
},
|
|
13
|
+
"dependencies": {
|
|
14
|
+
"bit-twiddle": "^1.0.2",
|
|
15
|
+
"dup": "^1.0.0"
|
|
16
|
+
}
|
|
17
|
+
}
|