@thi.ng/geom-tessellate 2.1.131 → 3.0.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.
@@ -0,0 +1,415 @@
1
+ import { bounds2 } from "@thi.ng/geom-poly-utils/bounds";
2
+ import { sign } from "@thi.ng/math/abs";
3
+ import { mux2 } from "@thi.ng/morton/mux";
4
+ const earCutComplex = (holeIDs = [], hashThreshold = 80) => (tess, faces, pids) => {
5
+ let points = tess.pointsForIDs(pids);
6
+ const hasHoles = !!holeIDs.length;
7
+ const outerLen = hasHoles ? holeIDs[0] : points.length;
8
+ let scale = 0;
9
+ if (points.length >= hashThreshold) {
10
+ const [[minX, minY], [maxX, maxY]] = bounds2(points, 0, outerLen);
11
+ scale = Math.max(maxX - minX, maxY - minY);
12
+ if (scale > 0) {
13
+ scale = 65535 / scale;
14
+ points = points.map((p) => [
15
+ (p[0] - minX) * scale,
16
+ (p[1] - minY) * scale
17
+ ]);
18
+ }
19
+ }
20
+ let outerNode = __buildVertexList(points, pids, 0, outerLen, true);
21
+ if (!outerNode || outerNode.n === outerNode.p) return faces;
22
+ if (hasHoles) {
23
+ outerNode = __eliminateHoles(points, pids, holeIDs, outerNode);
24
+ } else {
25
+ outerNode = __removeColinear(outerNode);
26
+ }
27
+ __earcutLinked(outerNode, faces, scale > 0 ? __isEarHashed : __isEar);
28
+ return faces;
29
+ };
30
+ const earCutComplexPrepare = (boundary, holes) => {
31
+ let points = boundary;
32
+ const holeIDs = [];
33
+ for (let hole of holes) {
34
+ holeIDs.push(points.length);
35
+ points = points.concat(hole);
36
+ }
37
+ return [points, holeIDs];
38
+ };
39
+ class Vertex {
40
+ i;
41
+ x;
42
+ y;
43
+ p = null;
44
+ n = null;
45
+ pz = null;
46
+ nz = null;
47
+ z = -1;
48
+ s = false;
49
+ constructor(i, x, y) {
50
+ this.i = i;
51
+ this.x = x;
52
+ this.y = y;
53
+ }
54
+ }
55
+ const __buildVertexList = (points, pids, start, end, clockwise) => {
56
+ let last;
57
+ if (clockwise === __signedArea(points, start, end) > 0) {
58
+ for (let i = start; i < end; i++)
59
+ last = __insertVertex(pids[i], points[i], last);
60
+ } else {
61
+ for (let i = end - 1; i >= start; i--)
62
+ last = __insertVertex(pids[i], points[i], last);
63
+ }
64
+ if (last && __equals(last, last.n)) {
65
+ __removeVertex(last);
66
+ last = last.n;
67
+ }
68
+ return last;
69
+ };
70
+ const __insertVertex = (i, [x, y], last) => {
71
+ const v = new Vertex(i, x, y);
72
+ if (!last) {
73
+ v.p = v.n = v;
74
+ } else {
75
+ v.n = last.n;
76
+ v.p = last;
77
+ last.n = last.n.p = v;
78
+ }
79
+ return v;
80
+ };
81
+ const __removeVertex = (v) => {
82
+ v.n.p = v.p;
83
+ v.p.n = v.n;
84
+ if (v.pz) v.pz.nz = v.nz;
85
+ if (v.nz) v.nz.pz = v.pz;
86
+ };
87
+ const __earcutLinked = (ear, triangles, pred, pass = 0) => {
88
+ if (!ear) return;
89
+ if (!pass && pred === __isEarHashed) __indexZCurve(ear);
90
+ let stop = ear;
91
+ while (ear.p !== ear.n) {
92
+ const { p: prev, n: next } = ear;
93
+ if (pred(ear)) {
94
+ triangles.push([prev.i, ear.i, next.i]);
95
+ __removeVertex(ear);
96
+ ear = stop = next.n;
97
+ continue;
98
+ }
99
+ ear = next;
100
+ if (ear === stop) {
101
+ if (pass === 0) {
102
+ __earcutLinked(__removeColinear(ear), triangles, pred, 1);
103
+ } else if (pass === 1) {
104
+ ear = __cureLocalIntersections(
105
+ __removeColinear(ear),
106
+ triangles
107
+ );
108
+ __earcutLinked(ear, triangles, pred, 2);
109
+ } else if (pass === 2) {
110
+ __splitEarcut(ear, triangles, pred);
111
+ }
112
+ break;
113
+ }
114
+ }
115
+ };
116
+ const __splitEarcut = (start, triangles, pred) => {
117
+ let a = start;
118
+ do {
119
+ let b = a.n.n;
120
+ while (b !== a.p) {
121
+ if (a.i !== b.i && __isValidDiagonal(a, b)) {
122
+ let c = __splitPolygon(a, b);
123
+ a = __removeColinear(a, a.n);
124
+ c = __removeColinear(c, c.n);
125
+ __earcutLinked(a, triangles, pred, 0);
126
+ __earcutLinked(c, triangles, pred, 0);
127
+ return;
128
+ }
129
+ b = b.n;
130
+ }
131
+ a = a.n;
132
+ } while (a !== start);
133
+ };
134
+ const __splitPolygon = (a, b) => {
135
+ const a2 = new Vertex(a.i, a.x, a.y);
136
+ const b2 = new Vertex(b.i, b.x, b.y);
137
+ const an = a.n;
138
+ const bp = b.p;
139
+ a.n = b;
140
+ b.p = a;
141
+ a2.n = an;
142
+ an.p = a2;
143
+ b2.n = a2;
144
+ a2.p = b2;
145
+ bp.n = b2;
146
+ b2.p = bp;
147
+ return b2;
148
+ };
149
+ const __isEdgeCentroidInside = (a, b) => {
150
+ const mx = (a.x + b.x) * 0.5;
151
+ const my = (a.y + b.y) * 0.5;
152
+ let v = a;
153
+ let inside = false;
154
+ do {
155
+ const { x: px, y: py, n: vn } = v;
156
+ if (vn.y !== py && py > my !== vn.y > my && mx < (vn.x - px) * (my - py) / (vn.y - py) + px)
157
+ inside = !inside;
158
+ v = vn;
159
+ } while (v !== a);
160
+ return inside;
161
+ };
162
+ const __isLocallyInside = (a, b) => __area(a.p, a, a.n) < 0 ? __area(a, b, a.n) >= 0 && __area(a, a.p, b) >= 0 : __area(a, b, a.p) < 0 || __area(a, a.n, b) < 0;
163
+ const __intersectsPolygon = (a, b) => {
164
+ let v = a;
165
+ const ai = a.i;
166
+ const bi = b.i;
167
+ do {
168
+ if (v.i !== ai && v.i !== bi && v.n.i !== ai && v.n.i !== bi && __intersects(v, v.n, a, b))
169
+ return true;
170
+ v = v.n;
171
+ } while (v !== a);
172
+ return false;
173
+ };
174
+ const __intersects = (p1, q1, p2, q2) => {
175
+ const o1 = sign(__area(p1, q1, p2));
176
+ const o2 = sign(__area(p1, q1, q2));
177
+ const o3 = sign(__area(p2, q2, p1));
178
+ const o4 = sign(__area(p2, q2, q1));
179
+ if (o1 !== o2 && o3 !== o4) return true;
180
+ if (o1 === 0 && __onSegment(p1, p2, q1)) return true;
181
+ if (o2 === 0 && __onSegment(p1, q2, q1)) return true;
182
+ if (o3 === 0 && __onSegment(p2, p1, q2)) return true;
183
+ if (o4 === 0 && __onSegment(p2, q1, q2)) return true;
184
+ return false;
185
+ };
186
+ const __onSegment = ({ x: px, y: py }, { x: qx, y: qy }, { x: rx, y: ry }) => qx <= Math.max(px, rx) && qx >= Math.min(px, rx) && qy <= Math.max(py, ry) && qy >= Math.min(py, ry);
187
+ const __isValidDiagonal = (a, b) => a.n.i !== b.i && a.p.i !== b.i && !__intersectsPolygon(a, b) && (__isLocallyInside(a, b) && __isLocallyInside(b, a) && // locally visible
188
+ __isEdgeCentroidInside(a, b) && // does not create opposite-facing sectors
189
+ (__area(a.p, a, b.p) || __area(a, b.p, b)) || // special zero-length case
190
+ __equals(a, b) && __area(a.p, a, a.n) > 0 && __area(b.p, b, b.n) > 0);
191
+ const __isPointInTriangle = ({ x, y }, ax, ay, bx, by, cx, cy) => (cx - x) * (ay - y) >= (ax - x) * (cy - y) && (ax - x) * (by - y) >= (bx - x) * (ay - y) && (bx - x) * (cy - y) >= (cx - x) * (by - y);
192
+ const __isPointInRect = ({ x, y }, x0, y0, x1, y1) => x >= x0 && x <= x1 && y >= y0 && y <= y1;
193
+ const __findLeftmost = (start) => {
194
+ let left = start;
195
+ let v = start;
196
+ do {
197
+ if (v.x < left.x || v.x === left.x && v.y < left.y) left = v;
198
+ v = v.n;
199
+ } while (v !== start);
200
+ return left;
201
+ };
202
+ const __sortLinked = (list) => {
203
+ let numMerges;
204
+ let inSize = 1;
205
+ do {
206
+ let p = list;
207
+ let tail = list = null;
208
+ let q, e;
209
+ numMerges = 0;
210
+ while (p) {
211
+ numMerges++;
212
+ q = p;
213
+ let pSize = 0;
214
+ for (let i = 0; i < inSize; i++) {
215
+ pSize++;
216
+ q = q.nz;
217
+ if (!q) break;
218
+ }
219
+ let qSize = inSize;
220
+ while (pSize > 0 || qSize > 0 && q) {
221
+ if (pSize !== 0 && (qSize === 0 || !q || p.z <= q.z)) {
222
+ e = p;
223
+ p = p.nz;
224
+ pSize--;
225
+ } else {
226
+ e = q;
227
+ q = q.nz;
228
+ qSize--;
229
+ }
230
+ if (tail) tail.nz = e;
231
+ else list = e;
232
+ e.pz = tail;
233
+ tail = e;
234
+ }
235
+ p = q;
236
+ }
237
+ tail.nz = null;
238
+ inSize *= 2;
239
+ } while (numMerges > 1);
240
+ return list;
241
+ };
242
+ const __indexZCurve = (start) => {
243
+ let v = start;
244
+ do {
245
+ if (v.z < 0) v.z = mux2(v.x, v.y);
246
+ v.pz = v.p;
247
+ v = v.nz = v.n;
248
+ } while (v !== start);
249
+ v.pz.nz = v.pz = null;
250
+ __sortLinked(v);
251
+ };
252
+ const __sectorContainsSector = (m, p) => __area(m.p, m, p.p) < 0 && __area(p.n, m, m.n) < 0;
253
+ const __findHoleBridge = (hole, outer) => {
254
+ const { x: hx, y: hy } = hole;
255
+ let v = outer;
256
+ let qx = -Infinity;
257
+ let px, py;
258
+ let pnx, pny;
259
+ let m;
260
+ do {
261
+ ({ x: px, y: py } = v);
262
+ ({ x: pnx, y: pny } = v.n);
263
+ if (hy <= py && hy >= pny && pny !== py) {
264
+ const x = px + (hy - py) * (pnx - px) / (pny - py);
265
+ if (x <= hx && x > qx) {
266
+ qx = x;
267
+ m = px < pnx ? v : v.n;
268
+ if (x === hx) return m;
269
+ }
270
+ }
271
+ v = v.n;
272
+ } while (v !== outer);
273
+ if (!m) return null;
274
+ const stop = m;
275
+ const { x: mx, y: my } = m;
276
+ let tanMin = Infinity;
277
+ let tan;
278
+ v = m;
279
+ do {
280
+ ({ x: px, y: py } = v);
281
+ if (hx >= px && px >= mx && hx !== px && __isPointInTriangle(
282
+ v,
283
+ hy < my ? hx : qx,
284
+ hy,
285
+ mx,
286
+ my,
287
+ hy < my ? qx : hx,
288
+ hy
289
+ )) {
290
+ tan = Math.abs(hy - py) / (hx - px);
291
+ if (__isLocallyInside(v, hole) && (tan < tanMin || tan === tanMin && (px > m.x || px === m.x && __sectorContainsSector(m, v)))) {
292
+ m = v;
293
+ tanMin = tan;
294
+ }
295
+ }
296
+ v = v.n;
297
+ } while (v !== stop);
298
+ return m;
299
+ };
300
+ const __eliminateHole = (hole, outerNode) => {
301
+ const bridge = __findHoleBridge(hole, outerNode);
302
+ if (!bridge) return outerNode;
303
+ const bridgeReverse = __splitPolygon(bridge, hole);
304
+ __removeColinear(bridgeReverse, bridgeReverse.n);
305
+ return __removeColinear(bridge, bridge.n);
306
+ };
307
+ const __eliminateHoles = (points, pids, holeIndices, outerNode) => {
308
+ const queue = [];
309
+ for (let i = 0, num = holeIndices.length - 1; i <= num; i++) {
310
+ const start = holeIndices[i];
311
+ const end = i < num ? holeIndices[i + 1] : points.length;
312
+ const list = __buildVertexList(points, pids, start, end, false);
313
+ if (list === list.n) list.s = true;
314
+ queue.push(__findLeftmost(list));
315
+ }
316
+ queue.sort((a, b) => a.x - b.x);
317
+ for (let i = 0, n = queue.length; i < n; i++) {
318
+ outerNode = __eliminateHole(queue[i], outerNode);
319
+ }
320
+ return outerNode;
321
+ };
322
+ const __cureLocalIntersections = (start, triangles) => {
323
+ let v = start;
324
+ do {
325
+ const a = v.p;
326
+ const b = v.n.n;
327
+ if (!__equals(a, b) && __isLocallyInside(a, b) && __isLocallyInside(b, a) && __intersects(a, v, v.n, b)) {
328
+ triangles.push([a.i, v.i, b.i]);
329
+ __removeVertex(v);
330
+ __removeVertex(v.n);
331
+ v = start = b;
332
+ }
333
+ v = v.n;
334
+ } while (v !== start);
335
+ return __removeColinear(v);
336
+ };
337
+ const __isEar = (ear) => {
338
+ const { p: a, n: c } = ear;
339
+ const b = ear;
340
+ if (__area(a, b, c) >= 0) return false;
341
+ const { x: ax, y: ay } = a, { x: bx, y: by } = b, { x: cx, y: cy } = c;
342
+ const [x0, y0, x1, y1] = __triBounds(ax, ay, bx, by, cx, cy);
343
+ let v = c.n;
344
+ while (v !== a) {
345
+ if (__isPointInRect(v, x0, y0, x1, y1) && __isPointInTriangle(v, ax, ay, bx, by, cx, cy) && __area(v.p, v, v.n) >= 0)
346
+ return false;
347
+ v = v.n;
348
+ }
349
+ return true;
350
+ };
351
+ const __isEarHashed = (ear) => {
352
+ const { p: a, n: c } = ear;
353
+ const b = ear;
354
+ if (__area(a, b, c) >= 0) return false;
355
+ const { x: ax, y: ay } = a;
356
+ const { x: bx, y: by } = b;
357
+ const { x: cx, y: cy } = c;
358
+ const [x0, y0, x1, y1] = __triBounds(ax, ay, bx, by, cx, cy);
359
+ const minZ = mux2(x0, y0);
360
+ const maxZ = mux2(x1, y1);
361
+ const check = (v) => v !== a && v !== c && __isPointInRect(v, x0, y0, x1, y1) && __isPointInTriangle(v, ax, ay, bx, by, cx, cy) && __area(v.p, v, v.n) >= 0;
362
+ let { pz: p, nz: n } = ear;
363
+ while (p && p.z >= minZ && n && n.z <= maxZ) {
364
+ if (check(p) || check(n)) return false;
365
+ p = p.pz;
366
+ n = n.nz;
367
+ }
368
+ while (p && p.z >= minZ) {
369
+ if (check(p)) return false;
370
+ p = p.pz;
371
+ }
372
+ while (n && n.z <= maxZ) {
373
+ if (check(n)) return false;
374
+ n = n.nz;
375
+ }
376
+ return true;
377
+ };
378
+ const __removeColinear = (start, end = start) => {
379
+ if (!start) return start;
380
+ let v = start;
381
+ let repeat;
382
+ do {
383
+ repeat = false;
384
+ if (!v.s && (__equals(v, v.n) || sign(__area(v.p, v, v.n)) === 0)) {
385
+ __removeVertex(v);
386
+ v = end = v.p;
387
+ if (v === v.n) break;
388
+ repeat = true;
389
+ } else {
390
+ v = v.n;
391
+ }
392
+ } while (repeat || v !== end);
393
+ return end;
394
+ };
395
+ const __area = (a, { x: bx, y: by }, c) => (by - a.y) * (c.x - bx) - (bx - a.x) * (c.y - by);
396
+ const __signedArea = (points, start, end) => {
397
+ let sum = 0;
398
+ for (let i = start, j = end - 1; i < end; j = i, i++) {
399
+ const a = points[j];
400
+ const b = points[i];
401
+ sum += (a[0] - b[0]) * (a[1] + b[1]);
402
+ }
403
+ return sum;
404
+ };
405
+ const __triBounds = (ax, ay, bx, by, cx, cy) => [
406
+ ax < bx ? ax < cx ? ax : cx : bx < cx ? bx : cx,
407
+ ay < by ? ay < cy ? ay : cy : by < cy ? by : cy,
408
+ ax > bx ? ax > cx ? ax : cx : bx > cx ? bx : cx,
409
+ ay > by ? ay > cy ? ay : cy : by > cy ? by : cy
410
+ ];
411
+ const __equals = (pa, b) => pa.x === b.x && pa.y === b.y;
412
+ export {
413
+ earCutComplex,
414
+ earCutComplexPrepare
415
+ };
package/earcut.d.ts CHANGED
@@ -1,8 +1,3 @@
1
- import type { Tessellator } from "@thi.ng/geom-api";
2
- /**
3
- * Tessellator for simple 2D polygons.
4
- *
5
- * @param points - polygon vertices
6
- */
7
- export declare const earCut2: Tessellator;
1
+ import type { Tessellator } from "./api.js";
2
+ export declare const earCut: Tessellator;
8
3
  //# sourceMappingURL=earcut.d.ts.map
package/earcut.js CHANGED
@@ -2,45 +2,47 @@ import { pointInTriangle2 } from "@thi.ng/geom-isec/point";
2
2
  import { polyArea2 } from "@thi.ng/geom-poly-utils/area";
3
3
  import { range } from "@thi.ng/transducers/range";
4
4
  import { signedArea2 } from "@thi.ng/vectors/signed-area";
5
- const snip = (points, u, v, w, n, ids) => {
6
- const a = points[ids[u]];
7
- const b = points[ids[v]];
8
- const c = points[ids[w]];
9
- if (signedArea2(a, b, c) > 0) {
10
- for (let i = 0; i < n; i++) {
11
- if (i !== u && i !== v && i !== w) {
12
- if (pointInTriangle2(points[ids[i]], a, b, c)) {
13
- return;
14
- }
15
- }
16
- }
17
- return [a, b, c];
18
- }
19
- };
20
- const earCut2 = (points) => {
21
- const tris = [];
22
- let n = points.length;
23
- const ids = [...polyArea2(points) > 0 ? range(n) : range(n - 1, -1, -1)];
5
+ const earCut = (tess, faces, pids) => {
6
+ let n = pids.length;
7
+ const points = tess.pointsForIDs(pids);
8
+ const order = [
9
+ ...polyArea2(points) > 0 ? range(n) : range(n - 1, -1, -1)
10
+ ];
24
11
  let count = 2 * n - 1;
25
- let v = n - 1, u, w, t;
12
+ let v = n - 1, u, w;
26
13
  while (count > 0 && n > 2) {
27
14
  u = n <= v ? 0 : v;
28
15
  v = u + 1;
29
16
  v = n <= v ? 0 : v;
30
17
  w = v + 1;
31
18
  w = n <= w ? 0 : w;
32
- t = snip(points, u, v, w, n, ids);
33
- if (t !== void 0) {
34
- tris.push(t);
35
- ids.splice(v, 1);
19
+ if (__snip(points, u, v, w, n, order)) {
20
+ faces.push([pids[order[u]], pids[order[v]], pids[order[w]]]);
21
+ order.splice(v, 1);
36
22
  n--;
37
23
  count = 2 * n;
38
24
  } else {
39
25
  count--;
40
26
  }
41
27
  }
42
- return tris;
28
+ return faces;
29
+ };
30
+ const __snip = (points, u, v, w, n, ids) => {
31
+ const a = points[ids[u]];
32
+ const b = points[ids[v]];
33
+ const c = points[ids[w]];
34
+ if (signedArea2(a, b, c) > 0) {
35
+ for (let i = 0; i < n; i++) {
36
+ if (i !== u && i !== v && i !== w) {
37
+ if (pointInTriangle2(points[ids[i]], a, b, c)) {
38
+ return false;
39
+ }
40
+ }
41
+ }
42
+ return true;
43
+ }
44
+ return false;
43
45
  };
44
46
  export {
45
- earCut2
47
+ earCut
46
48
  };
package/edge-split.d.ts CHANGED
@@ -1,3 +1,10 @@
1
- import type { Tessellator } from "@thi.ng/geom-api";
1
+ import type { Tessellator } from "./api.js";
2
+ /**
3
+ * Tessellates a polygon into sequence of triangles by splitting each boundary
4
+ * edge and constructing 2 triangles: `amc`, `mbc`, where `a` and `b` are edge
5
+ * endpoints, `m` is the edge centroid and `c` the face centroid.
6
+ *
7
+ * @param points
8
+ */
2
9
  export declare const edgeSplit: Tessellator;
3
10
  //# sourceMappingURL=edge-split.d.ts.map
package/edge-split.js CHANGED
@@ -1,27 +1,15 @@
1
1
  import { centroid } from "@thi.ng/geom-poly-utils/centroid";
2
- import { comp } from "@thi.ng/transducers/comp";
3
- import { mapcat } from "@thi.ng/transducers/mapcat";
4
- import { partition } from "@thi.ng/transducers/partition";
5
- import { push } from "@thi.ng/transducers/push";
6
- import { transduce } from "@thi.ng/transducers/transduce";
7
- import { wrapSides } from "@thi.ng/transducers/wrap-sides";
8
- import { mixN } from "@thi.ng/vectors/mixn";
9
- const edgeSplit = (points) => {
10
- const c = centroid(points);
11
- return transduce(
12
- comp(
13
- partition(2, 1),
14
- mapcat(([a, b]) => {
15
- const m = mixN([], a, b, 0.5);
16
- return [
17
- [a, m, c],
18
- [m, b, c]
19
- ];
20
- })
21
- ),
22
- push(),
23
- wrapSides(points, 0, 1)
24
- );
2
+ import { addmN } from "@thi.ng/vectors/addmn";
3
+ const edgeSplit = (tess, faces, pids) => {
4
+ const points = tess.pointsForIDs(pids);
5
+ const c = tess.addPoint(centroid(points));
6
+ const n = pids.length - 1;
7
+ for (let i = 0; i <= n; i++) {
8
+ const j = i < n ? i + 1 : 0;
9
+ const m = tess.addPoint(addmN([], points[i], points[j], 0.5));
10
+ faces.push([c, pids[i], m], [c, m, pids[j]]);
11
+ }
12
+ return faces;
25
13
  };
26
14
  export {
27
15
  edgeSplit
package/index.d.ts CHANGED
@@ -1,8 +1,13 @@
1
+ export * from "./api.js";
1
2
  export * from "./tessellate.js";
3
+ export * from "./tessellation.js";
2
4
  export * from "./earcut.js";
5
+ export * from "./earcut-complex.js";
3
6
  export * from "./edge-split.js";
4
7
  export * from "./inset.js";
5
8
  export * from "./quad-fan.js";
6
9
  export * from "./rim-tris.js";
7
10
  export * from "./tri-fan.js";
11
+ export * from "./tri-fan-boundary.js";
12
+ export * from "./tri-fan-split.js";
8
13
  //# sourceMappingURL=index.d.ts.map
package/index.js CHANGED
@@ -1,7 +1,12 @@
1
+ export * from "./api.js";
1
2
  export * from "./tessellate.js";
3
+ export * from "./tessellation.js";
2
4
  export * from "./earcut.js";
5
+ export * from "./earcut-complex.js";
3
6
  export * from "./edge-split.js";
4
7
  export * from "./inset.js";
5
8
  export * from "./quad-fan.js";
6
9
  export * from "./rim-tris.js";
7
10
  export * from "./tri-fan.js";
11
+ export * from "./tri-fan-boundary.js";
12
+ export * from "./tri-fan-split.js";
package/inset.d.ts CHANGED
@@ -1,3 +1,3 @@
1
- import type { Tessellator } from "@thi.ng/geom-api";
2
- export declare const tesselInset: (inset?: number, keepInterior?: boolean) => Tessellator;
1
+ import type { Tessellator } from "./api.js";
2
+ export declare const inset: (inset?: number, keepInterior?: boolean) => Tessellator;
3
3
  //# sourceMappingURL=inset.d.ts.map
package/inset.js CHANGED
@@ -1,25 +1,17 @@
1
1
  import { centroid } from "@thi.ng/geom-poly-utils/centroid";
2
- import { comp } from "@thi.ng/transducers/comp";
3
- import { map } from "@thi.ng/transducers/map";
4
- import { partition } from "@thi.ng/transducers/partition";
5
- import { push } from "@thi.ng/transducers/push";
6
- import { transduce } from "@thi.ng/transducers/transduce";
7
- import { wrapSides } from "@thi.ng/transducers/wrap-sides";
8
- import { zip } from "@thi.ng/transducers/zip";
9
2
  import { mixN } from "@thi.ng/vectors/mixn";
10
- const tesselInset = (inset = 0.5, keepInterior = false) => (points) => {
3
+ const inset = (inset2 = 0.5, keepInterior = false) => (tess, faces, pids) => {
4
+ const points = tess.pointsForIDs(pids);
11
5
  const c = centroid(points);
12
- const inner = points.map((p) => mixN([], p, c, inset));
13
- return transduce(
14
- comp(
15
- partition(2, 1),
16
- map(([[a, b], [c2, d]]) => [a, b, d, c2])
17
- ),
18
- push(),
19
- keepInterior ? [inner] : [],
20
- wrapSides([...zip(points, inner)], 0, 1)
21
- );
6
+ const insets = tess.addPoints(points.map((p) => mixN([], p, c, inset2)));
7
+ const n = pids.length - 1;
8
+ for (let i = 0; i <= n; i++) {
9
+ const j = i < n ? i + 1 : 0;
10
+ faces.push([pids[i], pids[j], insets[j], insets[i]]);
11
+ }
12
+ if (keepInterior) faces.push(insets);
13
+ return faces;
22
14
  };
23
15
  export {
24
- tesselInset
16
+ inset
25
17
  };