@aethervtt/shard-text 0.0.1

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/dist/msdf.js ADDED
@@ -0,0 +1,1147 @@
1
+ import {
2
+ colorEdgesSimple,
3
+ contourWinding,
4
+ EdgeColor,
5
+ edgeDirection,
6
+ normalizeShape,
7
+ reverseContour,
8
+ shapeBounds
9
+ } from "./shape.js";
10
+ const MAX = Number.MAX_VALUE;
11
+ const DELTA_FACTOR = 1.001;
12
+ const CUBIC_SEARCH_STARTS = 4;
13
+ const CUBIC_SEARCH_STEPS = 4;
14
+ let edgeCap = 0;
15
+ let P = new Float64Array(0);
16
+ let KIND = new Uint8Array(0);
17
+ let COLOR = new Uint8Array(0);
18
+ let PREV = new Int32Array(0);
19
+ let NEXT = new Int32Array(0);
20
+ let D0 = new Float64Array(0);
21
+ let D1 = new Float64Array(0);
22
+ let R0 = new Float64Array(0);
23
+ let R1 = new Float64Array(0);
24
+ let Z0 = new Float64Array(0);
25
+ let Z1 = new Float64Array(0);
26
+ let BA = new Float64Array(0);
27
+ let BB = new Float64Array(0);
28
+ let CPX = new Float64Array(0);
29
+ let CPY = new Float64Array(0);
30
+ let CABS = new Float64Array(0);
31
+ let CAD = new Float64Array(0);
32
+ let CBD = new Float64Array(0);
33
+ let CAP = new Float64Array(0);
34
+ let CBP = new Float64Array(0);
35
+ let contourCap = 0;
36
+ let CSTART = new Int32Array(0);
37
+ let CEND = new Int32Array(0);
38
+ let WINDING = new Int8Array(0);
39
+ let STD = new Float64Array(0);
40
+ let STDOT = new Float64Array(0);
41
+ let SNE = new Int32Array(0);
42
+ let SNP = new Float64Array(0);
43
+ let SNEG = new Float64Array(0);
44
+ let SPOS = new Float64Array(0);
45
+ let SPX = new Float64Array(0);
46
+ let SPY = new Float64Array(0);
47
+ let CD = new Float64Array(0);
48
+ let edgeCount = 0;
49
+ let contourCount = 0;
50
+ const MTD = new Float64Array(9);
51
+ const MTDOT = new Float64Array(9);
52
+ const MNE = new Int32Array(9);
53
+ const MNP = new Float64Array(9);
54
+ const MNEG = new Float64Array(9);
55
+ const MPOS = new Float64Array(9);
56
+ const MD = new Float64Array(12);
57
+ const SD = new Float64Array(3);
58
+ const ROOTS = new Float64Array(3);
59
+ const V = [0, 0];
60
+ function ensureEdges(n) {
61
+ if (n <= edgeCap) return;
62
+ edgeCap = Math.max(n, edgeCap * 2, 64);
63
+ P = new Float64Array(edgeCap * 8);
64
+ KIND = new Uint8Array(edgeCap);
65
+ COLOR = new Uint8Array(edgeCap);
66
+ PREV = new Int32Array(edgeCap);
67
+ NEXT = new Int32Array(edgeCap);
68
+ D0 = new Float64Array(edgeCap * 2);
69
+ D1 = new Float64Array(edgeCap * 2);
70
+ R0 = new Float64Array(edgeCap * 2);
71
+ R1 = new Float64Array(edgeCap * 2);
72
+ Z0 = new Float64Array(edgeCap * 2);
73
+ Z1 = new Float64Array(edgeCap * 2);
74
+ BA = new Float64Array(edgeCap * 2);
75
+ BB = new Float64Array(edgeCap * 2);
76
+ CPX = new Float64Array(edgeCap);
77
+ CPY = new Float64Array(edgeCap);
78
+ CABS = new Float64Array(edgeCap);
79
+ CAD = new Float64Array(edgeCap);
80
+ CBD = new Float64Array(edgeCap);
81
+ CAP = new Float64Array(edgeCap);
82
+ CBP = new Float64Array(edgeCap);
83
+ }
84
+ function ensureContours(n) {
85
+ if (n <= contourCap) return;
86
+ contourCap = Math.max(n, contourCap * 2, 16);
87
+ CSTART = new Int32Array(contourCap);
88
+ CEND = new Int32Array(contourCap);
89
+ WINDING = new Int8Array(contourCap);
90
+ STD = new Float64Array(contourCap * 3);
91
+ STDOT = new Float64Array(contourCap * 3);
92
+ SNE = new Int32Array(contourCap * 3);
93
+ SNP = new Float64Array(contourCap * 3);
94
+ SNEG = new Float64Array(contourCap * 3);
95
+ SPOS = new Float64Array(contourCap * 3);
96
+ SPX = new Float64Array(contourCap);
97
+ SPY = new Float64Array(contourCap);
98
+ CD = new Float64Array(contourCap * 3);
99
+ }
100
+ function normalized(out, o, x, y, allowZero) {
101
+ const len = Math.sqrt(x * x + y * y);
102
+ if (len === 0) {
103
+ out[o] = 0;
104
+ out[o + 1] = allowZero ? 0 : 1;
105
+ } else {
106
+ out[o] = x / len;
107
+ out[o + 1] = y / len;
108
+ }
109
+ }
110
+ function flatten(shape) {
111
+ let n = 0;
112
+ for (const c of shape.contours) n += c.edges.length;
113
+ ensureEdges(n);
114
+ ensureContours(shape.contours.length);
115
+ edgeCount = n;
116
+ contourCount = shape.contours.length;
117
+ let e = 0;
118
+ for (let ci = 0; ci < shape.contours.length; ci++) {
119
+ const contour = shape.contours[ci];
120
+ CSTART[ci] = e;
121
+ WINDING[ci] = contourWinding(contour);
122
+ const m = contour.edges.length;
123
+ for (let k = 0; k < m; k++) {
124
+ const edge = contour.edges[k];
125
+ const o = e * 8;
126
+ const p = edge.p;
127
+ for (let j = 0; j < 8; j++) P[o + j] = 0;
128
+ for (let j = 0; j < p.length; j++) P[o + j] = p[j];
129
+ if (edge.kind === 1) {
130
+ P[o + 6] = p[2];
131
+ P[o + 7] = p[3];
132
+ } else if (edge.kind === 2) {
133
+ P[o + 6] = p[4];
134
+ P[o + 7] = p[5];
135
+ }
136
+ KIND[e] = edge.kind;
137
+ COLOR[e] = edge.color;
138
+ PREV[e] = CSTART[ci] + (k + m - 1) % m;
139
+ NEXT[e] = CSTART[ci] + (k + 1) % m;
140
+ edgeDirection(edge, 0, V);
141
+ R0[e * 2] = V[0];
142
+ R0[e * 2 + 1] = V[1];
143
+ normalized(D0, e * 2, V[0], V[1], false);
144
+ normalized(Z0, e * 2, V[0], V[1], true);
145
+ edgeDirection(edge, 1, V);
146
+ R1[e * 2] = V[0];
147
+ R1[e * 2 + 1] = V[1];
148
+ normalized(D1, e * 2, V[0], V[1], false);
149
+ normalized(Z1, e * 2, V[0], V[1], true);
150
+ e++;
151
+ }
152
+ CEND[ci] = e;
153
+ }
154
+ for (let i = 0; i < edgeCount; i++) {
155
+ const pv = PREV[i];
156
+ const nx = NEXT[i];
157
+ normalized(BA, i * 2, Z1[pv * 2] + Z0[i * 2], Z1[pv * 2 + 1] + Z0[i * 2 + 1], true);
158
+ normalized(BB, i * 2, Z1[i * 2] + Z0[nx * 2], Z1[i * 2 + 1] + Z0[nx * 2 + 1], true);
159
+ }
160
+ }
161
+ const endX = (i) => P[i * 8 + 6];
162
+ const endY = (i) => P[i * 8 + 7];
163
+ function solveQuadratic(a, b, c) {
164
+ if (a === 0 || Math.abs(b) > 1e12 * Math.abs(a)) {
165
+ if (b === 0) return c === 0 ? -1 : 0;
166
+ ROOTS[0] = -c / b;
167
+ return 1;
168
+ }
169
+ let dscr = b * b - 4 * a * c;
170
+ if (dscr > 0) {
171
+ dscr = Math.sqrt(dscr);
172
+ ROOTS[0] = (-b + dscr) / (2 * a);
173
+ ROOTS[1] = (-b - dscr) / (2 * a);
174
+ return 2;
175
+ }
176
+ if (dscr === 0) {
177
+ ROOTS[0] = -b / (2 * a);
178
+ return 1;
179
+ }
180
+ return 0;
181
+ }
182
+ function solveCubicNormed(a, b, c) {
183
+ const a2 = a * a;
184
+ let q = 1 / 9 * (a2 - 3 * b);
185
+ const r = 1 / 54 * (a * (2 * a2 - 9 * b) + 27 * c);
186
+ const r2 = r * r;
187
+ const q3 = q * q * q;
188
+ const a3 = a / 3;
189
+ if (r2 < q3) {
190
+ let t = r / Math.sqrt(q3);
191
+ if (t < -1) t = -1;
192
+ if (t > 1) t = 1;
193
+ t = Math.acos(t);
194
+ q = -2 * Math.sqrt(q);
195
+ ROOTS[0] = q * Math.cos(t / 3) - a3;
196
+ ROOTS[1] = q * Math.cos((t + 2 * Math.PI) / 3) - a3;
197
+ ROOTS[2] = q * Math.cos((t - 2 * Math.PI) / 3) - a3;
198
+ return 3;
199
+ }
200
+ const u = (r < 0 ? 1 : -1) * Math.cbrt(Math.abs(r) + Math.sqrt(r2 - q3));
201
+ const v = u === 0 ? 0 : q / u;
202
+ ROOTS[0] = u + v - a3;
203
+ if (u === v || Math.abs(u - v) < 1e-12 * Math.abs(u + v)) {
204
+ ROOTS[1] = -0.5 * (u + v) - a3;
205
+ return 2;
206
+ }
207
+ return 1;
208
+ }
209
+ function solveCubic(a, b, c, d) {
210
+ if (a !== 0) {
211
+ const bn = b / a;
212
+ if (Math.abs(bn) < 1e6) return solveCubicNormed(bn, c / a, d / a);
213
+ }
214
+ return solveQuadratic(b, c, d);
215
+ }
216
+ function edgeSignedDistance(i, px, py) {
217
+ const o = i * 8;
218
+ const kind = KIND[i];
219
+ const x0 = P[o];
220
+ const y0 = P[o + 1];
221
+ if (kind === 1) {
222
+ const x12 = P[o + 2];
223
+ const y12 = P[o + 3];
224
+ const aqx = px - x0;
225
+ const aqy = py - y0;
226
+ const abx2 = x12 - x0;
227
+ const aby2 = y12 - y0;
228
+ const abLen2 = abx2 * abx2 + aby2 * aby2;
229
+ const param2 = (aqx * abx2 + aqy * aby2) / abLen2;
230
+ const eqx = (param2 > 0.5 ? x12 : x0) - px;
231
+ const eqy = (param2 > 0.5 ? y12 : y0) - py;
232
+ const endpointDistance = Math.sqrt(eqx * eqx + eqy * eqy);
233
+ const abLen = Math.sqrt(abLen2);
234
+ SD[2] = param2;
235
+ if (param2 > 0 && param2 < 1) {
236
+ const ortho = (aby2 * aqx - abx2 * aqy) / abLen;
237
+ if (Math.abs(ortho) < endpointDistance) {
238
+ SD[0] = ortho;
239
+ SD[1] = 0;
240
+ return;
241
+ }
242
+ }
243
+ SD[0] = (aqx * aby2 - aqy * abx2 > 0 ? 1 : -1) * endpointDistance;
244
+ const eqLen = endpointDistance;
245
+ const dot = eqLen === 0 ? aby2 / abLen : (abx2 * eqx + aby2 * eqy) / (abLen * eqLen);
246
+ SD[1] = Math.abs(dot);
247
+ return;
248
+ }
249
+ if (kind === 2) {
250
+ const x12 = P[o + 2];
251
+ const y12 = P[o + 3];
252
+ const x22 = P[o + 4];
253
+ const y22 = P[o + 5];
254
+ const qax2 = x0 - px;
255
+ const qay2 = y0 - py;
256
+ const abx2 = x12 - x0;
257
+ const aby2 = y12 - y0;
258
+ const brx2 = x22 - x12 - abx2;
259
+ const bry2 = y22 - y12 - aby2;
260
+ const a = brx2 * brx2 + bry2 * bry2;
261
+ const b = 3 * (abx2 * brx2 + aby2 * bry2);
262
+ const c = 2 * (abx2 * abx2 + aby2 * aby2) + (qax2 * brx2 + qay2 * bry2);
263
+ const d = qax2 * abx2 + qay2 * aby2;
264
+ let ex2 = R0[i * 2];
265
+ let ey2 = R0[i * 2 + 1];
266
+ let minDistance2 = (ex2 * qay2 - ey2 * qax2 > 0 ? 1 : -1) * Math.sqrt(qax2 * qax2 + qay2 * qay2);
267
+ let param2 = -(qax2 * ex2 + qay2 * ey2) / (ex2 * ex2 + ey2 * ey2);
268
+ const bqx2 = x22 - px;
269
+ const bqy2 = y22 - py;
270
+ const distB2 = Math.sqrt(bqx2 * bqx2 + bqy2 * bqy2);
271
+ if (distB2 < Math.abs(minDistance2)) {
272
+ ex2 = R1[i * 2];
273
+ ey2 = R1[i * 2 + 1];
274
+ minDistance2 = (ex2 * bqy2 - ey2 * bqx2 > 0 ? 1 : -1) * distB2;
275
+ param2 = ((px - x12) * ex2 + (py - y12) * ey2) / (ex2 * ex2 + ey2 * ey2);
276
+ }
277
+ const bx0 = x0 < x12 ? x0 < x22 ? x0 : x22 : x12 < x22 ? x12 : x22;
278
+ const bx1 = x0 > x12 ? x0 > x22 ? x0 : x22 : x12 > x22 ? x12 : x22;
279
+ const by0 = y0 < y12 ? y0 < y22 ? y0 : y22 : y12 < y22 ? y12 : y22;
280
+ const by1 = y0 > y12 ? y0 > y22 ? y0 : y22 : y12 > y22 ? y12 : y22;
281
+ const ox = px < bx0 ? bx0 - px : px > bx1 ? px - bx1 : 0;
282
+ const oy = py < by0 ? by0 - py : py > by1 ? py - by1 : 0;
283
+ const solutions = ox * ox + oy * oy > minDistance2 * minDistance2 ? 0 : solveCubic(a, b, c, d);
284
+ for (let s = 0; s < solutions; s++) {
285
+ const t = ROOTS[s];
286
+ if (t > 0 && t < 1) {
287
+ const qex = qax2 + 2 * t * abx2 + t * t * brx2;
288
+ const qey = qay2 + 2 * t * aby2 + t * t * bry2;
289
+ const distance = Math.sqrt(qex * qex + qey * qey);
290
+ if (distance <= Math.abs(minDistance2)) {
291
+ const dx = abx2 + t * brx2;
292
+ const dy = aby2 + t * bry2;
293
+ minDistance2 = (dx * qey - dy * qex > 0 ? 1 : -1) * distance;
294
+ param2 = t;
295
+ }
296
+ }
297
+ }
298
+ SD[0] = minDistance2;
299
+ SD[2] = param2;
300
+ if (param2 >= 0 && param2 <= 1) SD[1] = 0;
301
+ else if (param2 < 0.5) SD[1] = endpointDot(i, true, qax2, qay2);
302
+ else SD[1] = endpointDot(i, false, bqx2, bqy2);
303
+ return;
304
+ }
305
+ const x1 = P[o + 2];
306
+ const y1 = P[o + 3];
307
+ const x2 = P[o + 4];
308
+ const y2 = P[o + 5];
309
+ const x3 = P[o + 6];
310
+ const y3 = P[o + 7];
311
+ const qax = x0 - px;
312
+ const qay = y0 - py;
313
+ const abx = x1 - x0;
314
+ const aby = y1 - y0;
315
+ const brx = x2 - x1 - abx;
316
+ const bry = y2 - y1 - aby;
317
+ const asx = x3 - x2 - (x2 - x1) - brx;
318
+ const asy = y3 - y2 - (y2 - y1) - bry;
319
+ let ex = R0[i * 2];
320
+ let ey = R0[i * 2 + 1];
321
+ let minDistance = (ex * qay - ey * qax > 0 ? 1 : -1) * Math.sqrt(qax * qax + qay * qay);
322
+ let param = -(qax * ex + qay * ey) / (ex * ex + ey * ey);
323
+ const bqx = x3 - px;
324
+ const bqy = y3 - py;
325
+ const distB = Math.sqrt(bqx * bqx + bqy * bqy);
326
+ if (distB < Math.abs(minDistance)) {
327
+ ex = R1[i * 2];
328
+ ey = R1[i * 2 + 1];
329
+ minDistance = (ex * bqy - ey * bqx > 0 ? 1 : -1) * distB;
330
+ param = ((ex - bqx) * ex + (ey - bqy) * ey) / (ex * ex + ey * ey);
331
+ }
332
+ for (let s = 0; s <= CUBIC_SEARCH_STARTS; s++) {
333
+ let t = s / CUBIC_SEARCH_STARTS;
334
+ let qex = qax + 3 * t * abx + 3 * t * t * brx + t * t * t * asx;
335
+ let qey = qay + 3 * t * aby + 3 * t * t * bry + t * t * t * asy;
336
+ let d1x = 3 * abx + 6 * t * brx + 3 * t * t * asx;
337
+ let d1y = 3 * aby + 6 * t * bry + 3 * t * t * asy;
338
+ let d2x = 6 * brx + 6 * t * asx;
339
+ let d2y = 6 * bry + 6 * t * asy;
340
+ let improved = t - (qex * d1x + qey * d1y) / (d1x * d1x + d1y * d1y + qex * d2x + qey * d2y);
341
+ if (improved > 0 && improved < 1) {
342
+ let remaining = CUBIC_SEARCH_STEPS;
343
+ do {
344
+ t = improved;
345
+ qex = qax + 3 * t * abx + 3 * t * t * brx + t * t * t * asx;
346
+ qey = qay + 3 * t * aby + 3 * t * t * bry + t * t * t * asy;
347
+ d1x = 3 * abx + 6 * t * brx + 3 * t * t * asx;
348
+ d1y = 3 * aby + 6 * t * bry + 3 * t * t * asy;
349
+ if (--remaining === 0) break;
350
+ d2x = 6 * brx + 6 * t * asx;
351
+ d2y = 6 * bry + 6 * t * asy;
352
+ improved = t - (qex * d1x + qey * d1y) / (d1x * d1x + d1y * d1y + qex * d2x + qey * d2y);
353
+ } while (improved > 0 && improved < 1);
354
+ const distance = Math.sqrt(qex * qex + qey * qey);
355
+ if (distance < Math.abs(minDistance)) {
356
+ minDistance = (d1x * qey - d1y * qex > 0 ? 1 : -1) * distance;
357
+ param = t;
358
+ }
359
+ }
360
+ }
361
+ SD[0] = minDistance;
362
+ SD[2] = param;
363
+ if (param >= 0 && param <= 1) SD[1] = 0;
364
+ else if (param < 0.5) SD[1] = endpointDot(i, true, qax, qay);
365
+ else SD[1] = endpointDot(i, false, bqx, bqy);
366
+ }
367
+ function endpointDot(i, start, qx, qy) {
368
+ const dx = start ? D0[i * 2] : D1[i * 2];
369
+ const dy = start ? D0[i * 2 + 1] : D1[i * 2 + 1];
370
+ const len = Math.sqrt(qx * qx + qy * qy);
371
+ if (len === 0) return Math.abs(dy);
372
+ return Math.abs((dx * qx + dy * qy) / len);
373
+ }
374
+ function perpendicular(i, distance, px, py, param) {
375
+ if (param < 0) {
376
+ const dx = D0[i * 2];
377
+ const dy = D0[i * 2 + 1];
378
+ const aqx = px - P[i * 8];
379
+ const aqy = py - P[i * 8 + 1];
380
+ if (aqx * dx + aqy * dy < 0) {
381
+ const perp = aqx * dy - aqy * dx;
382
+ if (Math.abs(perp) <= Math.abs(distance)) return perp;
383
+ }
384
+ } else if (param > 1) {
385
+ const dx = D1[i * 2];
386
+ const dy = D1[i * 2 + 1];
387
+ const bqx = px - endX(i);
388
+ const bqy = py - endY(i);
389
+ if (bqx * dx + bqy * dy > 0) {
390
+ const perp = bqx * dy - bqy * dx;
391
+ if (Math.abs(perp) <= Math.abs(distance)) return perp;
392
+ }
393
+ }
394
+ return distance;
395
+ }
396
+ function resetSelectors(px, py) {
397
+ for (let c = 0; c < contourCount; c++) {
398
+ const dx = px - SPX[c];
399
+ const dy = py - SPY[c];
400
+ const delta = DELTA_FACTOR * Math.sqrt(dx * dx + dy * dy);
401
+ SPX[c] = px;
402
+ SPY[c] = py;
403
+ for (let ch = 0; ch < 3; ch++) {
404
+ const s = c * 3 + ch;
405
+ const td = STD[s] + (STD[s] > 0 ? 1 : -1) * delta;
406
+ STD[s] = td;
407
+ SNEG[s] = -Math.abs(td);
408
+ SPOS[s] = Math.abs(td);
409
+ SNE[s] = -1;
410
+ SNP[s] = 0;
411
+ }
412
+ }
413
+ }
414
+ function isEdgeRelevant(s, e, delta) {
415
+ const ad = CAD[e];
416
+ const bd = CBD[e];
417
+ if (CABS[e] - delta <= Math.abs(STD[s]) || Math.abs(ad) < delta || Math.abs(bd) < delta) {
418
+ return true;
419
+ }
420
+ if (ad > 0) {
421
+ const ap = CAP[e];
422
+ if (ap < 0 ? ap + delta >= SNEG[s] : ap - delta <= SPOS[s]) return true;
423
+ }
424
+ if (bd > 0) {
425
+ const bp = CBP[e];
426
+ if (bp < 0 ? bp + delta >= SNEG[s] : bp - delta <= SPOS[s]) return true;
427
+ }
428
+ return false;
429
+ }
430
+ function addTrue(s, e, d, dot, param) {
431
+ const ad = Math.abs(d);
432
+ const at = Math.abs(STD[s]);
433
+ if (ad < at || ad === at && dot < STDOT[s]) {
434
+ STD[s] = d;
435
+ STDOT[s] = dot;
436
+ SNE[s] = e;
437
+ SNP[s] = param;
438
+ }
439
+ }
440
+ function addPerpendicular(s, d) {
441
+ if (d <= 0 && d > SNEG[s]) SNEG[s] = d;
442
+ if (d >= 0 && d < SPOS[s]) SPOS[s] = d;
443
+ }
444
+ function addEdge(c, e, px, py) {
445
+ const color = COLOR[e];
446
+ const cdx = px - CPX[e];
447
+ const cdy = py - CPY[e];
448
+ const delta = DELTA_FACTOR * Math.sqrt(cdx * cdx + cdy * cdy);
449
+ const base = c * 3;
450
+ if (!(color & EdgeColor.red && isEdgeRelevant(base, e, delta) || color & EdgeColor.green && isEdgeRelevant(base + 1, e, delta) || color & EdgeColor.blue && isEdgeRelevant(base + 2, e, delta))) {
451
+ return;
452
+ }
453
+ edgeSignedDistance(e, px, py);
454
+ const d = SD[0];
455
+ const dot = SD[1];
456
+ const param = SD[2];
457
+ if (color & EdgeColor.red) addTrue(base, e, d, dot, param);
458
+ if (color & EdgeColor.green) addTrue(base + 1, e, d, dot, param);
459
+ if (color & EdgeColor.blue) addTrue(base + 2, e, d, dot, param);
460
+ CPX[e] = px;
461
+ CPY[e] = py;
462
+ CABS[e] = Math.abs(d);
463
+ const o = e * 8;
464
+ const apx = px - P[o];
465
+ const apy = py - P[o + 1];
466
+ const bpx = px - endX(e);
467
+ const bpy = py - endY(e);
468
+ const add = apx * BA[e * 2] + apy * BA[e * 2 + 1];
469
+ const bdd = -(bpx * BB[e * 2] + bpy * BB[e * 2 + 1]);
470
+ if (add > 0) {
471
+ let pd = d;
472
+ const dirx = -Z0[e * 2];
473
+ const diry = -Z0[e * 2 + 1];
474
+ if (apx * dirx + apy * diry > 0) {
475
+ const perp = apx * diry - apy * dirx;
476
+ if (Math.abs(perp) < Math.abs(pd)) {
477
+ pd = -perp;
478
+ if (color & EdgeColor.red) addPerpendicular(base, pd);
479
+ if (color & EdgeColor.green) addPerpendicular(base + 1, pd);
480
+ if (color & EdgeColor.blue) addPerpendicular(base + 2, pd);
481
+ }
482
+ }
483
+ CAP[e] = pd;
484
+ }
485
+ if (bdd > 0) {
486
+ let pd = d;
487
+ const dirx = Z1[e * 2];
488
+ const diry = Z1[e * 2 + 1];
489
+ if (bpx * dirx + bpy * diry > 0) {
490
+ const perp = bpx * diry - bpy * dirx;
491
+ if (Math.abs(perp) < Math.abs(pd)) {
492
+ pd = perp;
493
+ if (color & EdgeColor.red) addPerpendicular(base, pd);
494
+ if (color & EdgeColor.green) addPerpendicular(base + 1, pd);
495
+ if (color & EdgeColor.blue) addPerpendicular(base + 2, pd);
496
+ }
497
+ }
498
+ CBP[e] = pd;
499
+ }
500
+ CAD[e] = add;
501
+ CBD[e] = bdd;
502
+ }
503
+ function selectorDistance(td, ne, np, neg, pos, px, py) {
504
+ let minDistance = td < 0 ? neg : pos;
505
+ if (ne >= 0) {
506
+ const d = perpendicular(ne, td, px, py, np);
507
+ if (Math.abs(d) < Math.abs(minDistance)) minDistance = d;
508
+ }
509
+ return minDistance;
510
+ }
511
+ function median(a, b, c) {
512
+ return Math.max(Math.min(a, b), Math.min(Math.max(a, b), c));
513
+ }
514
+ function resetMerged(m) {
515
+ for (let ch = 0; ch < 3; ch++) {
516
+ const k = m * 3 + ch;
517
+ MTD[k] = -MAX;
518
+ MTDOT[k] = 0;
519
+ MNE[k] = -1;
520
+ MNP[k] = 0;
521
+ MNEG[k] = -MAX;
522
+ MPOS[k] = MAX;
523
+ }
524
+ }
525
+ function merge(m, c) {
526
+ for (let ch = 0; ch < 3; ch++) {
527
+ const k = m * 3 + ch;
528
+ const s = c * 3 + ch;
529
+ const a = Math.abs(STD[s]);
530
+ const b = Math.abs(MTD[k]);
531
+ if (a < b || a === b && STDOT[s] < MTDOT[k]) {
532
+ MTD[k] = STD[s];
533
+ MTDOT[k] = STDOT[s];
534
+ MNE[k] = SNE[s];
535
+ MNP[k] = SNP[s];
536
+ }
537
+ if (SNEG[s] > MNEG[k]) MNEG[k] = SNEG[s];
538
+ if (SPOS[s] < MPOS[k]) MPOS[k] = SPOS[s];
539
+ }
540
+ }
541
+ function mergedDistance(m, px, py) {
542
+ for (let ch = 0; ch < 3; ch++) {
543
+ const k = m * 3 + ch;
544
+ MD[k] = selectorDistance(MTD[k], MNE[k], MNP[k], MNEG[k], MPOS[k], px, py);
545
+ }
546
+ }
547
+ const cdMedian = (c) => median(CD[c * 3], CD[c * 3 + 1], CD[c * 3 + 2]);
548
+ const mdMedian = (m) => median(MD[m * 3], MD[m * 3 + 1], MD[m * 3 + 2]);
549
+ function setResultFromContour(c) {
550
+ MD[9] = CD[c * 3];
551
+ MD[10] = CD[c * 3 + 1];
552
+ MD[11] = CD[c * 3 + 2];
553
+ }
554
+ function setResultFromMerged(m) {
555
+ MD[9] = MD[m * 3];
556
+ MD[10] = MD[m * 3 + 1];
557
+ MD[11] = MD[m * 3 + 2];
558
+ }
559
+ function distanceAt(px, py) {
560
+ resetSelectors(px, py);
561
+ for (let c = 0; c < contourCount; c++) {
562
+ const end = CEND[c];
563
+ for (let e = CSTART[c]; e < end; e++) addEdge(c, e, px, py);
564
+ }
565
+ for (let c = 0; c < contourCount; c++) {
566
+ for (let ch = 0; ch < 3; ch++) {
567
+ const s = c * 3 + ch;
568
+ CD[s] = selectorDistance(STD[s], SNE[s], SNP[s], SNEG[s], SPOS[s], px, py);
569
+ }
570
+ }
571
+ resetMerged(0);
572
+ resetMerged(1);
573
+ resetMerged(2);
574
+ for (let c = 0; c < contourCount; c++) {
575
+ const m = cdMedian(c);
576
+ merge(0, c);
577
+ if (WINDING[c] > 0 && m >= 0) merge(1, c);
578
+ if (WINDING[c] < 0 && m <= 0) merge(2, c);
579
+ }
580
+ mergedDistance(0, px, py);
581
+ mergedDistance(1, px, py);
582
+ mergedDistance(2, px, py);
583
+ const inner = mdMedian(1);
584
+ const outer = mdMedian(2);
585
+ let winding = 0;
586
+ if (inner >= 0 && Math.abs(inner) <= Math.abs(outer)) {
587
+ setResultFromMerged(1);
588
+ winding = 1;
589
+ for (let c = 0; c < contourCount; c++) {
590
+ if (WINDING[c] > 0) {
591
+ const cm = cdMedian(c);
592
+ if (Math.abs(cm) < Math.abs(outer) && cm > median(MD[9], MD[10], MD[11])) {
593
+ setResultFromContour(c);
594
+ }
595
+ }
596
+ }
597
+ } else if (outer <= 0 && Math.abs(outer) < Math.abs(inner)) {
598
+ setResultFromMerged(2);
599
+ winding = -1;
600
+ for (let c = 0; c < contourCount; c++) {
601
+ if (WINDING[c] < 0) {
602
+ const cm = cdMedian(c);
603
+ if (Math.abs(cm) < Math.abs(inner) && cm < median(MD[9], MD[10], MD[11])) {
604
+ setResultFromContour(c);
605
+ }
606
+ }
607
+ }
608
+ } else {
609
+ setResultFromMerged(0);
610
+ return;
611
+ }
612
+ for (let c = 0; c < contourCount; c++) {
613
+ if (WINDING[c] !== winding) {
614
+ const cm = cdMedian(c);
615
+ const rm = median(MD[9], MD[10], MD[11]);
616
+ if (cm * rm >= 0 && Math.abs(cm) < Math.abs(rm)) setResultFromContour(c);
617
+ }
618
+ }
619
+ if (median(MD[9], MD[10], MD[11]) === mdMedian(0)) setResultFromMerged(0);
620
+ }
621
+ function resetCaches() {
622
+ for (let e = 0; e < edgeCount; e++) {
623
+ CPX[e] = 0;
624
+ CPY[e] = 0;
625
+ CABS[e] = 0;
626
+ CAD[e] = 0;
627
+ CBD[e] = 0;
628
+ CAP[e] = 0;
629
+ CBP[e] = 0;
630
+ }
631
+ for (let s = 0; s < contourCount * 3; s++) {
632
+ STD[s] = -MAX;
633
+ STDOT[s] = 0;
634
+ SNE[s] = -1;
635
+ }
636
+ for (let c = 0; c < contourCount; c++) {
637
+ SPX[c] = 0;
638
+ SPY[c] = 0;
639
+ }
640
+ }
641
+ function trueDistance(px, py) {
642
+ let best = -MAX;
643
+ let bestDot = 0;
644
+ for (let e = 0; e < edgeCount; e++) {
645
+ edgeSignedDistance(e, px, py);
646
+ const a = Math.abs(SD[0]);
647
+ const b = Math.abs(best);
648
+ if (a < b || a === b && SD[1] < bestDot) {
649
+ best = SD[0];
650
+ bestDot = SD[1];
651
+ }
652
+ }
653
+ return best;
654
+ }
655
+ let pieceCap = 0;
656
+ let PE = new Int32Array(0);
657
+ let PT = new Float64Array(0);
658
+ let pieceCount = 0;
659
+ let hitCap = 0;
660
+ let HX = new Float64Array(0);
661
+ let HD = new Int8Array(0);
662
+ function ensurePieces(n) {
663
+ if (n <= pieceCap) return;
664
+ pieceCap = Math.max(n, pieceCap * 2, 64);
665
+ const pe = new Int32Array(pieceCap);
666
+ const pt = new Float64Array(pieceCap * 4);
667
+ pe.set(PE);
668
+ pt.set(PT);
669
+ PE = pe;
670
+ PT = pt;
671
+ }
672
+ function ensureHits(n) {
673
+ if (n <= hitCap) return;
674
+ hitCap = Math.max(n, hitCap * 2, 64);
675
+ HX = new Float64Array(hitCap);
676
+ HD = new Int8Array(hitCap);
677
+ }
678
+ function pointX(e, t) {
679
+ const o = e * 8;
680
+ const k = KIND[e];
681
+ const s = 1 - t;
682
+ if (k === 1) return s * P[o] + t * P[o + 2];
683
+ if (k === 2) return s * s * P[o] + 2 * s * t * P[o + 2] + t * t * P[o + 4];
684
+ return s * s * s * P[o] + 3 * s * s * t * P[o + 2] + 3 * s * t * t * P[o + 4] + t * t * t * P[o + 6];
685
+ }
686
+ function pointY(e, t) {
687
+ const o = e * 8 + 1;
688
+ const k = KIND[e];
689
+ const s = 1 - t;
690
+ if (k === 1) return s * P[o] + t * P[o + 2];
691
+ if (k === 2) return s * s * P[o] + 2 * s * t * P[o + 2] + t * t * P[o + 4];
692
+ return s * s * s * P[o] + 3 * s * s * t * P[o + 2] + 3 * s * t * t * P[o + 4] + t * t * t * P[o + 6];
693
+ }
694
+ function addPiece(e, t0, t1) {
695
+ if (t1 <= t0) return;
696
+ ensurePieces(pieceCount + 1);
697
+ const y0 = pointY(e, t0);
698
+ const y1 = pointY(e, t1);
699
+ if (y0 === y1) return;
700
+ PE[pieceCount] = e;
701
+ PT[pieceCount * 4] = t0;
702
+ PT[pieceCount * 4 + 1] = t1;
703
+ PT[pieceCount * 4 + 2] = y0;
704
+ PT[pieceCount * 4 + 3] = y1;
705
+ pieceCount++;
706
+ }
707
+ function buildPieces() {
708
+ pieceCount = 0;
709
+ for (let e = 0; e < edgeCount; e++) {
710
+ const o = e * 8 + 1;
711
+ const k = KIND[e];
712
+ let n = 0;
713
+ if (k === 2) {
714
+ const den = P[o] - 2 * P[o + 2] + P[o + 4];
715
+ if (den !== 0) {
716
+ ROOTS[0] = (P[o] - P[o + 2]) / den;
717
+ n = 1;
718
+ }
719
+ } else if (k === 3) {
720
+ const p0 = P[o];
721
+ const p1 = P[o + 2];
722
+ const p2 = P[o + 4];
723
+ const p3 = P[o + 6];
724
+ n = solveQuadratic(-p0 + 3 * p1 - 3 * p2 + p3, 2 * (p0 - 2 * p1 + p2), p1 - p0);
725
+ if (n < 0) n = 0;
726
+ if (n === 2 && ROOTS[0] > ROOTS[1]) {
727
+ const tmp = ROOTS[0];
728
+ ROOTS[0] = ROOTS[1];
729
+ ROOTS[1] = tmp;
730
+ }
731
+ }
732
+ let t = 0;
733
+ for (let r = 0; r < n; r++) {
734
+ const root = ROOTS[r];
735
+ if (root > t && root < 1) {
736
+ addPiece(e, t, root);
737
+ t = root;
738
+ }
739
+ }
740
+ addPiece(e, t, 1);
741
+ }
742
+ }
743
+ function scanline(y) {
744
+ let n = 0;
745
+ ensureHits(pieceCount);
746
+ for (let i = 0; i < pieceCount; i++) {
747
+ const y0 = PT[i * 4 + 2];
748
+ const y1 = PT[i * 4 + 3];
749
+ const lo = y0 < y1 ? y0 : y1;
750
+ const hi = y0 < y1 ? y1 : y0;
751
+ if (y < lo || y >= hi) continue;
752
+ const e = PE[i];
753
+ let t0 = PT[i * 4];
754
+ let t1 = PT[i * 4 + 1];
755
+ let x;
756
+ if (KIND[e] === 1) {
757
+ const o = e * 8;
758
+ const t = (y - P[o + 1]) / (P[o + 3] - P[o + 1]);
759
+ x = P[o] + (P[o + 2] - P[o]) * t;
760
+ } else {
761
+ const up = y1 > y0;
762
+ for (let it = 0; it < 40; it++) {
763
+ const tm = 0.5 * (t0 + t1);
764
+ const ym = pointY(e, tm);
765
+ if (ym < y === up) t0 = tm;
766
+ else t1 = tm;
767
+ }
768
+ x = pointX(e, 0.5 * (t0 + t1));
769
+ }
770
+ let j = n;
771
+ while (j > 0 && HX[j - 1] > x) {
772
+ HX[j] = HX[j - 1];
773
+ HD[j] = HD[j - 1];
774
+ j--;
775
+ }
776
+ HX[j] = x;
777
+ HD[j] = y1 > y0 ? 1 : -1;
778
+ n++;
779
+ }
780
+ return n;
781
+ }
782
+ const ERROR = 1;
783
+ const PROTECTED = 2;
784
+ const ARTIFACT_T_EPSILON = 0.01;
785
+ const PROTECTION_RADIUS_TOLERANCE = 1.001;
786
+ const MIN_DEVIATION_RATIO = 10 / 9;
787
+ let stencilCap = 0;
788
+ let STENCIL = new Uint8Array(0);
789
+ const T2 = new Float64Array(2);
790
+ const LQ = new Float64Array(6);
791
+ function interpolatedMedian(sdf, a, b, t) {
792
+ return median(
793
+ sdf[a] + (sdf[b] - sdf[a]) * t,
794
+ sdf[a + 1] + (sdf[b + 1] - sdf[a + 1]) * t,
795
+ sdf[a + 2] + (sdf[b + 2] - sdf[a + 2]) * t
796
+ );
797
+ }
798
+ function interpolatedMedianQ(sdf, a, t) {
799
+ return median(
800
+ t * (t * LQ[3] + LQ[0]) + sdf[a],
801
+ t * (t * LQ[4] + LQ[1]) + sdf[a + 1],
802
+ t * (t * LQ[5] + LQ[2]) + sdf[a + 2]
803
+ );
804
+ }
805
+ const CANDIDATE = 1;
806
+ const ARTIFACT = 2;
807
+ function rangeTest(span, isProtected, at, bt, xt, am, bm, xm) {
808
+ if (am > 0.5 && bm > 0.5 && xm <= 0.5 || am < 0.5 && bm < 0.5 && xm >= 0.5 || !isProtected && median(am, bm, xm) !== xm) {
809
+ const axSpan = (xt - at) * span;
810
+ const bxSpan = (bt - xt) * span;
811
+ if (!(xm >= am - axSpan && xm <= am + axSpan && xm >= bm - bxSpan && xm <= bm + bxSpan)) {
812
+ return CANDIDATE | ARTIFACT;
813
+ }
814
+ return CANDIDATE;
815
+ }
816
+ return 0;
817
+ }
818
+ function linearArtifactInner(sdf, span, isProtected, am, bm, a, b, dA, dB) {
819
+ const t = dA / (dA - dB);
820
+ if (t > ARTIFACT_T_EPSILON && t < 1 - ARTIFACT_T_EPSILON) {
821
+ const xm = interpolatedMedian(sdf, a, b, t);
822
+ return (rangeTest(span, isProtected, 0, 1, t, am, bm, xm) & ARTIFACT) !== 0;
823
+ }
824
+ return false;
825
+ }
826
+ function hasLinearArtifact(sdf, span, isProtected, am, a, b) {
827
+ const bm = median(sdf[b], sdf[b + 1], sdf[b + 2]);
828
+ return Math.abs(am - 0.5) >= Math.abs(bm - 0.5) && (linearArtifactInner(
829
+ sdf,
830
+ span,
831
+ isProtected,
832
+ am,
833
+ bm,
834
+ a,
835
+ b,
836
+ sdf[a + 1] - sdf[a],
837
+ sdf[b + 1] - sdf[b]
838
+ ) || linearArtifactInner(
839
+ sdf,
840
+ span,
841
+ isProtected,
842
+ am,
843
+ bm,
844
+ a,
845
+ b,
846
+ sdf[a + 2] - sdf[a + 1],
847
+ sdf[b + 2] - sdf[b + 1]
848
+ ) || linearArtifactInner(
849
+ sdf,
850
+ span,
851
+ isProtected,
852
+ am,
853
+ bm,
854
+ a,
855
+ b,
856
+ sdf[a] - sdf[a + 2],
857
+ sdf[b] - sdf[b + 2]
858
+ ));
859
+ }
860
+ function diagonalArtifactInner(sdf, span, isProtected, am, dm, a, dA, dBC, dD, tEx0, tEx1) {
861
+ const n = solveQuadratic(dD - dBC + dA, dBC - dA - dA, dA);
862
+ if (n <= 0) return false;
863
+ T2[0] = ROOTS[0];
864
+ T2[1] = ROOTS[1];
865
+ for (let i = 0; i < n; i++) {
866
+ const t = T2[i];
867
+ if (t > ARTIFACT_T_EPSILON && t < 1 - ARTIFACT_T_EPSILON) {
868
+ const xm = interpolatedMedianQ(sdf, a, t);
869
+ let flags = rangeTest(span, isProtected, 0, 1, t, am, dm, xm);
870
+ if (tEx0 > 0 && tEx0 < 1) {
871
+ const em = interpolatedMedianQ(sdf, a, tEx0);
872
+ flags |= tEx0 > t ? rangeTest(span, isProtected, 0, tEx0, t, am, em, xm) : rangeTest(span, isProtected, tEx0, 1, t, em, dm, xm);
873
+ }
874
+ if (tEx1 > 0 && tEx1 < 1) {
875
+ const em = interpolatedMedianQ(sdf, a, tEx1);
876
+ flags |= tEx1 > t ? rangeTest(span, isProtected, 0, tEx1, t, am, em, xm) : rangeTest(span, isProtected, tEx1, 1, t, em, dm, xm);
877
+ }
878
+ if (flags & ARTIFACT) return true;
879
+ }
880
+ }
881
+ return false;
882
+ }
883
+ function hasDiagonalArtifact(sdf, span, isProtected, am, a, b, c, d) {
884
+ const dm = median(sdf[d], sdf[d + 1], sdf[d + 2]);
885
+ if (Math.abs(am - 0.5) < Math.abs(dm - 0.5)) return false;
886
+ for (let ch = 0; ch < 3; ch++) {
887
+ const abc = sdf[a + ch] - sdf[b + ch] - sdf[c + ch];
888
+ LQ[ch] = -sdf[a + ch] - abc;
889
+ LQ[3 + ch] = sdf[d + ch] + abc;
890
+ }
891
+ const tEx0 = -0.5 * LQ[0] / LQ[3];
892
+ const tEx1 = -0.5 * LQ[1] / LQ[4];
893
+ const tEx2 = -0.5 * LQ[2] / LQ[5];
894
+ for (let k = 0; k < 3; k++) {
895
+ const hi = k === 2 ? 0 : k + 1;
896
+ const lo = k;
897
+ const dA = sdf[a + hi] - sdf[a + lo];
898
+ const dBC = sdf[b + hi] - sdf[b + lo] + sdf[c + hi] - sdf[c + lo];
899
+ const dD = sdf[d + hi] - sdf[d + lo];
900
+ const e0 = k === 0 ? tEx0 : k === 1 ? tEx1 : tEx2;
901
+ const e1 = k === 0 ? tEx1 : k === 1 ? tEx2 : tEx0;
902
+ if (diagonalArtifactInner(sdf, span, isProtected, am, dm, a, dA, dBC, dD, e0, e1)) return true;
903
+ }
904
+ return false;
905
+ }
906
+ function edgeBetweenTexels(sdf, a, b) {
907
+ let mask = 0;
908
+ for (let ch = 0; ch < 3; ch++) {
909
+ const t = (sdf[a + ch] - 0.5) / (sdf[a + ch] - sdf[b + ch]);
910
+ if (t > 0 && t < 1) {
911
+ const c0 = sdf[a] + (sdf[b] - sdf[a]) * t;
912
+ const c1 = sdf[a + 1] + (sdf[b + 1] - sdf[a + 1]) * t;
913
+ const c2 = sdf[a + 2] + (sdf[b + 2] - sdf[a + 2]) * t;
914
+ const cc = ch === 0 ? c0 : ch === 1 ? c1 : c2;
915
+ if (median(c0, c1, c2) === cc) mask |= 1 << ch;
916
+ }
917
+ }
918
+ return mask;
919
+ }
920
+ function protectExtremeChannels(sdf, texel, m, mask) {
921
+ const i = texel * 3;
922
+ if (mask & 1 && sdf[i] !== m || mask & 2 && sdf[i + 1] !== m || mask & 4 && sdf[i + 2] !== m) {
923
+ STENCIL[texel] = STENCIL[texel] | PROTECTED;
924
+ }
925
+ }
926
+ function protectCorners(shape, w, h, scale, tx, ty) {
927
+ for (const contour of shape.contours) {
928
+ const edges = contour.edges;
929
+ if (edges.length === 0) continue;
930
+ let prev = edges[edges.length - 1];
931
+ for (const edge of edges) {
932
+ const common = prev.color & edge.color;
933
+ if (!(common & common - 1)) {
934
+ const px = scale * (edge.p[0] + tx);
935
+ const py = scale * (edge.p[1] + ty);
936
+ const l = Math.floor(px - 0.5);
937
+ const b = Math.floor(py - 0.5);
938
+ const r = l + 1;
939
+ const t = b + 1;
940
+ if (l < w && b < h && r >= 0 && t >= 0) {
941
+ if (l >= 0 && b >= 0) STENCIL[b * w + l] = STENCIL[b * w + l] | PROTECTED;
942
+ if (r < w && b >= 0) STENCIL[b * w + r] = STENCIL[b * w + r] | PROTECTED;
943
+ if (l >= 0 && t < h) STENCIL[t * w + l] = STENCIL[t * w + l] | PROTECTED;
944
+ if (r < w && t < h) STENCIL[t * w + r] = STENCIL[t * w + r] | PROTECTED;
945
+ }
946
+ }
947
+ prev = edge;
948
+ }
949
+ }
950
+ }
951
+ const med3 = (sdf, i) => median(sdf[i], sdf[i + 1], sdf[i + 2]);
952
+ function protectEdges(sdf, w, h, rangePx) {
953
+ let radius = PROTECTION_RADIUS_TOLERANCE / rangePx;
954
+ for (let y = 0; y < h; y++) {
955
+ for (let x = 0; x < w - 1; x++) {
956
+ const a = y * w + x;
957
+ const lm = med3(sdf, a * 3);
958
+ const rm = med3(sdf, (a + 1) * 3);
959
+ if (Math.abs(lm - 0.5) + Math.abs(rm - 0.5) < radius) {
960
+ const mask = edgeBetweenTexels(sdf, a * 3, (a + 1) * 3);
961
+ protectExtremeChannels(sdf, a, lm, mask);
962
+ protectExtremeChannels(sdf, a + 1, rm, mask);
963
+ }
964
+ }
965
+ }
966
+ for (let y = 0; y < h - 1; y++) {
967
+ for (let x = 0; x < w; x++) {
968
+ const a = y * w + x;
969
+ const bm = med3(sdf, a * 3);
970
+ const tm = med3(sdf, (a + w) * 3);
971
+ if (Math.abs(bm - 0.5) + Math.abs(tm - 0.5) < radius) {
972
+ const mask = edgeBetweenTexels(sdf, a * 3, (a + w) * 3);
973
+ protectExtremeChannels(sdf, a, bm, mask);
974
+ protectExtremeChannels(sdf, a + w, tm, mask);
975
+ }
976
+ }
977
+ }
978
+ radius = PROTECTION_RADIUS_TOLERANCE * Math.SQRT2 / rangePx;
979
+ for (let y = 0; y < h - 1; y++) {
980
+ for (let x = 0; x < w - 1; x++) {
981
+ const lb = y * w + x;
982
+ const rb = lb + 1;
983
+ const lt = lb + w;
984
+ const rt = lt + 1;
985
+ const mlb = med3(sdf, lb * 3);
986
+ const mrb = med3(sdf, rb * 3);
987
+ const mlt = med3(sdf, lt * 3);
988
+ const mrt = med3(sdf, rt * 3);
989
+ if (Math.abs(mlb - 0.5) + Math.abs(mrt - 0.5) < radius) {
990
+ const mask = edgeBetweenTexels(sdf, lb * 3, rt * 3);
991
+ protectExtremeChannels(sdf, lb, mlb, mask);
992
+ protectExtremeChannels(sdf, rt, mrt, mask);
993
+ }
994
+ if (Math.abs(mrb - 0.5) + Math.abs(mlt - 0.5) < radius) {
995
+ const mask = edgeBetweenTexels(sdf, rb * 3, lt * 3);
996
+ protectExtremeChannels(sdf, rb, mrb, mask);
997
+ protectExtremeChannels(sdf, lt, mlt, mask);
998
+ }
999
+ }
1000
+ }
1001
+ }
1002
+ function findErrors(sdf, w, h, rangePx) {
1003
+ const hSpan = MIN_DEVIATION_RATIO / rangePx;
1004
+ const dSpan = MIN_DEVIATION_RATIO * Math.SQRT2 / rangePx;
1005
+ for (let y = 0; y < h; y++) {
1006
+ for (let x = 0; x < w; x++) {
1007
+ const i = y * w + x;
1008
+ const c = i * 3;
1009
+ const cm = med3(sdf, c);
1010
+ const prot = (STENCIL[i] & PROTECTED) !== 0;
1011
+ const l = (i - 1) * 3;
1012
+ const r = (i + 1) * 3;
1013
+ const b = (i - w) * 3;
1014
+ const t = (i + w) * 3;
1015
+ const error = x > 0 && hasLinearArtifact(sdf, hSpan, prot, cm, c, l) || y > 0 && hasLinearArtifact(sdf, hSpan, prot, cm, c, b) || x < w - 1 && hasLinearArtifact(sdf, hSpan, prot, cm, c, r) || y < h - 1 && hasLinearArtifact(sdf, hSpan, prot, cm, c, t) || x > 0 && y > 0 && hasDiagonalArtifact(sdf, dSpan, prot, cm, c, l, b, b - 3) || x < w - 1 && y > 0 && hasDiagonalArtifact(sdf, dSpan, prot, cm, c, r, b, b + 3) || x > 0 && y < h - 1 && hasDiagonalArtifact(sdf, dSpan, prot, cm, c, l, t, t - 3) || x < w - 1 && y < h - 1 && hasDiagonalArtifact(sdf, dSpan, prot, cm, c, r, t, t + 3);
1016
+ if (error) STENCIL[i] = STENCIL[i] | ERROR;
1017
+ }
1018
+ }
1019
+ }
1020
+ function msdfBox(bounds, scale, range) {
1021
+ const pad = 0.5 * range / scale;
1022
+ const l = bounds[0] - pad;
1023
+ const b = bounds[1] - pad;
1024
+ const r = bounds[2] + pad;
1025
+ const t = bounds[3] + pad;
1026
+ const w = scale * (r - l);
1027
+ const h = scale * (t - b);
1028
+ const width = Math.ceil(w) + 1;
1029
+ const height = Math.ceil(h) + 1;
1030
+ const tx = -l + 0.5 * (width - w) / scale;
1031
+ const ty = -b + 0.5 * (height - h) / scale;
1032
+ return {
1033
+ width,
1034
+ height,
1035
+ tx,
1036
+ ty,
1037
+ plane: [
1038
+ -tx + 0.5 / scale,
1039
+ -ty + 0.5 / scale,
1040
+ -tx + (width - 0.5) / scale,
1041
+ -ty + (height - 0.5) / scale
1042
+ ]
1043
+ };
1044
+ }
1045
+ function prepareShape(shape, angleThreshold = 3) {
1046
+ normalizeShape(shape);
1047
+ const bounds = shapeBounds(shape);
1048
+ if (!bounds) return;
1049
+ flatten(shape);
1050
+ const px = bounds[0] - (bounds[2] - bounds[0]) - 1;
1051
+ const py = bounds[1] - (bounds[3] - bounds[1]) - 1;
1052
+ if (trueDistance(px, py) > 0) for (const c of shape.contours) reverseContour(c);
1053
+ colorEdgesSimple(shape, angleThreshold);
1054
+ }
1055
+ let floatCap = 0;
1056
+ let FLOATS = new Float32Array(0);
1057
+ function generateMsdf(shape, box, options) {
1058
+ const { width: w, height: h, tx, ty } = box;
1059
+ const scale = options.scale;
1060
+ const rangeUnits = options.range / scale;
1061
+ const n = w * h;
1062
+ if (n * 3 > floatCap) {
1063
+ floatCap = Math.max(n * 3, floatCap * 2);
1064
+ FLOATS = new Float32Array(floatCap);
1065
+ }
1066
+ if (n > stencilCap) {
1067
+ stencilCap = Math.max(n, stencilCap * 2);
1068
+ STENCIL = new Uint8Array(stencilCap);
1069
+ }
1070
+ const sdf = FLOATS;
1071
+ flatten(shape);
1072
+ if (edgeCount === 0) {
1073
+ sdf.fill(0, 0, n * 3);
1074
+ return sdf;
1075
+ }
1076
+ resetCaches();
1077
+ const invRange = 1 / rangeUnits;
1078
+ for (let y = 0; y < h; y++) {
1079
+ const py = (y + 0.5) / scale - ty;
1080
+ const leftToRight = (y & 1) === 0;
1081
+ for (let k = 0; k < w; k++) {
1082
+ const x = leftToRight ? k : w - 1 - k;
1083
+ const px = (x + 0.5) / scale - tx;
1084
+ distanceAt(px, py);
1085
+ const o = (y * w + x) * 3;
1086
+ sdf[o] = MD[9] * invRange + 0.5;
1087
+ sdf[o + 1] = MD[10] * invRange + 0.5;
1088
+ sdf[o + 2] = MD[11] * invRange + 0.5;
1089
+ }
1090
+ }
1091
+ if (options.scanline !== false) {
1092
+ buildPieces();
1093
+ for (let y = 0; y < h; y++) {
1094
+ const hits = scanline((y + 0.5) / scale - ty);
1095
+ let hit = 0;
1096
+ let winding = 0;
1097
+ for (let x = 0; x < w; x++) {
1098
+ const px = (x + 0.5) / scale - tx;
1099
+ while (hit < hits && HX[hit] < px) winding += HD[hit++];
1100
+ const fill = winding !== 0;
1101
+ const o = (y * w + x) * 3;
1102
+ const m = med3(sdf, o);
1103
+ if (m !== 0.5 && m > 0.5 !== fill) {
1104
+ sdf[o] = 1 - sdf[o];
1105
+ sdf[o + 1] = 1 - sdf[o + 1];
1106
+ sdf[o + 2] = 1 - sdf[o + 2];
1107
+ }
1108
+ }
1109
+ }
1110
+ }
1111
+ if (options.errorCorrection !== false) {
1112
+ STENCIL.fill(0, 0, n);
1113
+ protectCorners(shape, w, h, scale, tx, ty);
1114
+ protectEdges(sdf, w, h, options.range);
1115
+ findErrors(sdf, w, h, options.range);
1116
+ for (let i = 0; i < n; i++) {
1117
+ if (STENCIL[i] & ERROR) {
1118
+ const m = med3(sdf, i * 3);
1119
+ sdf[i * 3] = m;
1120
+ sdf[i * 3 + 1] = m;
1121
+ sdf[i * 3 + 2] = m;
1122
+ }
1123
+ }
1124
+ }
1125
+ return sdf;
1126
+ }
1127
+ function blitMsdf(sdf, w, h, out, outWidth, x, y) {
1128
+ for (let row = 0; row < h; row++) {
1129
+ const src = (h - 1 - row) * w * 3;
1130
+ let dst = ((y + row) * outWidth + x) * 4;
1131
+ for (let col = 0; col < w; col++) {
1132
+ const s = src + col * 3;
1133
+ for (let ch = 0; ch < 3; ch++) {
1134
+ const v = sdf[s + ch];
1135
+ out[dst + ch] = v <= 0 ? 0 : v >= 1 ? 255 : Math.round(v * 255);
1136
+ }
1137
+ out[dst + 3] = 255;
1138
+ dst += 4;
1139
+ }
1140
+ }
1141
+ }
1142
+ export {
1143
+ blitMsdf,
1144
+ generateMsdf,
1145
+ msdfBox,
1146
+ prepareShape
1147
+ };