modern-path2d 1.3.1 → 1.3.3

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/index.mjs CHANGED
@@ -1029,7 +1029,7 @@ function cubicBezier(t, p0, p1, p2, p3) {
1029
1029
  return cubicBezierP0(t, p0) + cubicBezierP1(t, p1) + cubicBezierP2(t, p2) + cubicBezierP3(t, p3);
1030
1030
  }
1031
1031
 
1032
- function fillTriangulate(points, options = {}) {
1032
+ function fillTriangulate(pointArray, options = {}) {
1033
1033
  let {
1034
1034
  vertices = [],
1035
1035
  indices = [],
@@ -1038,17 +1038,17 @@ function fillTriangulate(points, options = {}) {
1038
1038
  verticesOffset = vertices.length / verticesStride,
1039
1039
  indicesOffset = indices.length
1040
1040
  } = options;
1041
- const triangles = earcut(points, holes, 2);
1042
- if (triangles) {
1041
+ const triangles = earcut(pointArray, holes, 2);
1042
+ if (triangles.length) {
1043
1043
  for (let i = 0; i < triangles.length; i += 3) {
1044
1044
  indices[indicesOffset++] = triangles[i] + verticesOffset;
1045
1045
  indices[indicesOffset++] = triangles[i + 1] + verticesOffset;
1046
1046
  indices[indicesOffset++] = triangles[i + 2] + verticesOffset;
1047
1047
  }
1048
1048
  let index = verticesOffset * verticesStride;
1049
- for (let i = 0; i < points.length; i += 2) {
1050
- vertices[index] = points[i];
1051
- vertices[index + 1] = points[i + 1];
1049
+ for (let i = 0; i < pointArray.length; i += 2) {
1050
+ vertices[index] = pointArray[i];
1051
+ vertices[index + 1] = pointArray[i + 1];
1052
1052
  index += verticesStride;
1053
1053
  }
1054
1054
  }
@@ -1175,6 +1175,35 @@ function recursive(points, x1, y1, x2, y2, x3, y3, distanceTolerance, level) {
1175
1175
  recursive(points, x123, y123, x23, y23, x3, y3, distanceTolerance, level + 1);
1176
1176
  }
1177
1177
 
1178
+ function getDirectedArea(vertices) {
1179
+ let area = 0;
1180
+ const n = vertices.length;
1181
+ for (let i = 0; i < n; i += 2) {
1182
+ const x0 = vertices[i];
1183
+ const y0 = vertices[i + 1];
1184
+ const x1 = vertices[(i + 2) % (n - 1)];
1185
+ const y1 = vertices[(i + 3) % n];
1186
+ area += x0 * y1 - x1 * y0;
1187
+ }
1188
+ return area / 2;
1189
+ }
1190
+
1191
+ function pointInPolygon(point, polygon) {
1192
+ let inside = false;
1193
+ const [x, y] = point;
1194
+ const len = polygon.length / 2;
1195
+ for (let i = 0, j = len - 1; i < len; j = i++) {
1196
+ const xi = polygon[i * 2];
1197
+ const yi = polygon[i * 2 + 1];
1198
+ const xj = polygon[j * 2];
1199
+ const yj = polygon[j * 2 + 1];
1200
+ if (yi > y !== yj > y && x < (xj - xi) * (y - yi) / (yj - yi) + xi) {
1201
+ inside = !inside;
1202
+ }
1203
+ }
1204
+ return inside;
1205
+ }
1206
+
1178
1207
  function quadraticBezierP0(t, p) {
1179
1208
  const k = 1 - t;
1180
1209
  return k * k * p;
@@ -1603,7 +1632,7 @@ class Curve {
1603
1632
  });
1604
1633
  return this;
1605
1634
  }
1606
- getUnevenPointArray(count = 5, output = []) {
1635
+ getUnevenVertices(count = 5, output = []) {
1607
1636
  const p = new Vector2();
1608
1637
  for (let i = 0, len = Math.max(1, count) - 1; i <= len; i++) {
1609
1638
  this.getPoint(i / len, p);
@@ -1611,7 +1640,7 @@ class Curve {
1611
1640
  }
1612
1641
  return output;
1613
1642
  }
1614
- getSpacedPointArray(count = 5, output = []) {
1643
+ getSpacedVertices(count = 5, output = []) {
1615
1644
  const p = new Vector2();
1616
1645
  for (let i = 0, len = Math.max(1, count) - 1; i <= len; i++) {
1617
1646
  this.getPointAt(i / len, p);
@@ -1619,40 +1648,40 @@ class Curve {
1619
1648
  }
1620
1649
  return output;
1621
1650
  }
1622
- getAdaptivePointArray(output = []) {
1623
- return this.getUnevenPointArray(5, output);
1651
+ getAdaptiveVertices(output = []) {
1652
+ return this.getUnevenVertices(5, output);
1624
1653
  }
1625
- _pointArrayToPoint(array, output = []) {
1626
- for (let i = 0, len = array.length; i < len; i += 2) {
1627
- const x = array[i];
1628
- const y = array[i + 1];
1654
+ _verticesToPoints(vertices, output = []) {
1655
+ for (let i = 0, len = vertices.length; i < len; i += 2) {
1656
+ const x = vertices[i];
1657
+ const y = vertices[i + 1];
1629
1658
  output.push(new Vector2(x, y));
1630
1659
  }
1631
1660
  return output;
1632
1661
  }
1633
1662
  getSpacedPoints(count, output = []) {
1634
- const array = this.getSpacedPointArray(count);
1635
- this._pointArrayToPoint(array, output);
1663
+ const array = this.getSpacedVertices(count);
1664
+ this._verticesToPoints(array, output);
1636
1665
  return output;
1637
1666
  }
1638
1667
  getUnevenPoints(count, output = []) {
1639
- const array = this.getUnevenPointArray(count);
1640
- this._pointArrayToPoint(array, output);
1668
+ const array = this.getUnevenVertices(count);
1669
+ this._verticesToPoints(array, output);
1641
1670
  return output;
1642
1671
  }
1643
1672
  getAdaptivePoints(output = []) {
1644
- const array = this.getAdaptivePointArray();
1645
- this._pointArrayToPoint(array, output);
1673
+ const array = this.getAdaptiveVertices();
1674
+ this._verticesToPoints(array, output);
1646
1675
  return output;
1647
1676
  }
1648
1677
  getPoints(count, output = []) {
1649
1678
  let array;
1650
1679
  if (count) {
1651
- array = this.getUnevenPointArray(count);
1680
+ array = this.getUnevenVertices(count);
1652
1681
  } else {
1653
- array = this.getAdaptivePointArray();
1682
+ array = this.getAdaptiveVertices();
1654
1683
  }
1655
- this._pointArrayToPoint(array, output);
1684
+ this._verticesToPoints(array, output);
1656
1685
  return output;
1657
1686
  }
1658
1687
  getLength() {
@@ -1757,44 +1786,21 @@ class Curve {
1757
1786
  const { min, max } = this.getMinMax();
1758
1787
  return new BoundingBox(min.x, min.y, max.x - min.x, max.y - min.y);
1759
1788
  }
1789
+ getFillVertices(_options) {
1790
+ return this.getAdaptiveVertices();
1791
+ }
1760
1792
  fillTriangulate(options) {
1761
1793
  return fillTriangulate(
1762
- this.getAdaptivePointArray(),
1794
+ this.getFillVertices(options),
1763
1795
  options
1764
1796
  );
1765
1797
  }
1766
1798
  strokeTriangulate(options) {
1767
1799
  return strokeTriangulate(
1768
- this.getAdaptivePointArray(),
1800
+ this.getAdaptiveVertices(),
1769
1801
  options
1770
1802
  );
1771
1803
  }
1772
- toTriangulatedSVGString(result = this.fillTriangulate(), padding = 0) {
1773
- const { vertices, indices } = result;
1774
- const min = { x: -padding, y: -padding };
1775
- const max = { x: padding, y: padding };
1776
- const getPoint = (indice) => {
1777
- const x = vertices[indice * 2];
1778
- const y = vertices[indice * 2 + 1];
1779
- min.x = Math.min(min.x, x + padding);
1780
- max.x = Math.max(max.x, x + padding);
1781
- min.y = Math.min(min.y, y + padding);
1782
- max.y = Math.max(max.y, y + padding);
1783
- return [x, y];
1784
- };
1785
- let polygonStr = "";
1786
- for (let i = 0, len = indices.length; i < len; i += 3) {
1787
- const p1 = getPoint(indices[i]);
1788
- const p2 = getPoint(indices[i + 1]);
1789
- const p3 = getPoint(indices[i + 2]);
1790
- polygonStr += `<polygon points="${p1.join(",")} ${p2.join(",")} ${p3.join(",")}" fill="none" stroke="black" stroke-width="0.5" stroke-linecap="round" stroke-linejoin="round" />`;
1791
- }
1792
- const viewBox = [min.x, min.y, max.x - min.x, max.y - min.y];
1793
- return `<svg width="${viewBox[2]}" height="${viewBox[3]}" viewBox="${viewBox.join(" ")}" xmlns="http://www.w3.org/2000/svg">${polygonStr}</svg>`;
1794
- }
1795
- toTriangulatedSVG(result, padding) {
1796
- return new DOMParser().parseFromString(this.toTriangulatedSVGString(result, padding), "image/svg+xml").documentElement;
1797
- }
1798
1804
  toCommands() {
1799
1805
  const comds = [];
1800
1806
  const potins = this.getPoints();
@@ -1969,69 +1975,114 @@ class RoundCurve extends Curve {
1969
1975
  getControlPointRefs() {
1970
1976
  return [this._center];
1971
1977
  }
1972
- getAdaptivePointArray(output = []) {
1973
- const { cx, cy, rx, ry, startAngle, endAngle, clockwise } = this;
1974
- if (!(rx >= 0 && ry >= 0)) {
1978
+ _getAdaptiveVerticesByArc(output = []) {
1979
+ const { cx, cy, rx, ry, dx, dy, startAngle, endAngle, clockwise: _clockwise } = this;
1980
+ const clockwise = !_clockwise;
1981
+ const x = cx;
1982
+ const y = cy;
1983
+ const start = startAngle;
1984
+ const end = endAngle;
1985
+ let dist = Math.abs(start - end);
1986
+ if (!clockwise && start > end) {
1987
+ dist = 2 * Math.PI - dist;
1988
+ } else if (clockwise && end > start) {
1989
+ dist = 2 * Math.PI - dist;
1990
+ }
1991
+ let steps = Math.max(6, Math.floor(6 * rx ** (1 / 3) * (dist / Math.PI)));
1992
+ steps = Math.max(steps, 3);
1993
+ let f = dist / steps;
1994
+ let t = start;
1995
+ f *= clockwise ? -1 : 1;
1996
+ for (let i = 0; i < steps + 1; i++) {
1997
+ const cs = Math.cos(t);
1998
+ const sn = Math.sin(t);
1999
+ const nx = x + dx + cs * rx;
2000
+ const ny = y + dy + sn * ry;
2001
+ output.push(nx, ny);
2002
+ t += f;
2003
+ }
2004
+ return output;
2005
+ }
2006
+ _getAdaptiveVerticesByCircle(output = []) {
2007
+ const { cx, cy, rx, ry, dx, dy } = this;
2008
+ if (!(rx >= 0 && ry >= 0 && dx >= 0 && dy >= 0)) {
2009
+ return output;
2010
+ }
2011
+ const n = Math.ceil(2.3 * Math.sqrt(rx + ry));
2012
+ const x = cx;
2013
+ const y = cy;
2014
+ const m = n * 8 + (dx ? 4 : 0) + (dy ? 4 : 0);
2015
+ if (m === 0) {
2016
+ return output;
2017
+ }
2018
+ const start = output.length;
2019
+ if (n === 0) {
2020
+ output[start] = output[start + 6] = x + dx;
2021
+ output[start + 1] = output[start + 3] = y + dy;
2022
+ output[start + 2] = output[start + 4] = x - dx;
2023
+ output[start + 5] = output[start + 7] = y - dy;
1975
2024
  return output;
1976
2025
  }
1977
- let deltaAngle = endAngle - startAngle;
1978
- if (!clockwise && deltaAngle > 0) {
1979
- deltaAngle -= 2 * Math.PI;
1980
- } else if (clockwise && deltaAngle < 0) {
1981
- deltaAngle += 2 * Math.PI;
1982
- }
1983
- const arcLength = Math.abs(deltaAngle);
1984
- const n = Math.max(1, Math.ceil(arcLength / (Math.PI / 16)));
1985
- for (let i = 0; i <= n; i++) {
1986
- const t = i / n;
1987
- const angle = startAngle + deltaAngle * t;
1988
- const x = cx + Math.cos(angle) * rx;
1989
- const y = cy + Math.sin(angle) * ry;
1990
- output.push(x, y);
2026
+ let j1 = start;
2027
+ let j2 = start + n * 4 + (dx ? 2 : 0) + 2;
2028
+ let j3 = j2;
2029
+ let j4 = m;
2030
+ let x0 = dx + rx;
2031
+ let y0 = dy;
2032
+ let x1 = x + x0;
2033
+ let x2 = x - x0;
2034
+ let y1 = y + y0;
2035
+ output[j1++] = x1;
2036
+ output[j1++] = y1;
2037
+ output[--j2] = y1;
2038
+ output[--j2] = x2;
2039
+ if (dy) {
2040
+ const y22 = y - y0;
2041
+ output[j3++] = x2;
2042
+ output[j3++] = y22;
2043
+ output[--j4] = y22;
2044
+ output[--j4] = x1;
2045
+ }
2046
+ for (let i = 1; i < n; i++) {
2047
+ const a = Math.PI / 2 * (i / n);
2048
+ const x02 = dx + Math.cos(a) * rx;
2049
+ const y02 = dy + Math.sin(a) * ry;
2050
+ const x12 = x + x02;
2051
+ const x22 = x - x02;
2052
+ const y12 = y + y02;
2053
+ const y22 = y - y02;
2054
+ output[j1++] = x12;
2055
+ output[j1++] = y12;
2056
+ output[--j2] = y12;
2057
+ output[--j2] = x22;
2058
+ output[j3++] = x22;
2059
+ output[j3++] = y22;
2060
+ output[--j4] = y22;
2061
+ output[--j4] = x12;
2062
+ }
2063
+ x0 = dx;
2064
+ y0 = dy + ry;
2065
+ x1 = x + x0;
2066
+ x2 = x - x0;
2067
+ y1 = y + y0;
2068
+ const y2 = y - y0;
2069
+ output[j1++] = x1;
2070
+ output[j1++] = y1;
2071
+ output[--j4] = y2;
2072
+ output[--j4] = x1;
2073
+ if (dx) {
2074
+ output[j1++] = x2;
2075
+ output[j1++] = y1;
2076
+ output[--j4] = y2;
2077
+ output[--j4] = x2;
1991
2078
  }
1992
2079
  return output;
1993
2080
  }
1994
- fillTriangulate(options = {}) {
1995
- let {
1996
- vertices = [],
1997
- indices = [],
1998
- verticesStride = 2,
1999
- verticesOffset = vertices.length / verticesStride,
2000
- indicesOffset = indices.length
2001
- } = options;
2002
- const points = this.getAdaptivePointArray();
2003
- if (points.length === 0) {
2004
- return { vertices, indices };
2005
- }
2006
- let centerX = 0;
2007
- let centerY = 0;
2008
- for (let i = 0; i < points.length; i += 2) {
2009
- centerX += points[i];
2010
- centerY += points[i + 1];
2011
- }
2012
- centerX /= points.length / 2;
2013
- centerY /= points.length / 2;
2014
- let count = verticesOffset;
2015
- vertices[count * verticesStride] = centerX;
2016
- vertices[count * verticesStride + 1] = centerY;
2017
- const centerIndex = count++;
2018
- for (let i = 0; i < points.length; i += 2) {
2019
- vertices[count * verticesStride] = points[i];
2020
- vertices[count * verticesStride + 1] = points[i + 1];
2021
- if (i > 0) {
2022
- indices[indicesOffset++] = count;
2023
- indices[indicesOffset++] = centerIndex;
2024
- indices[indicesOffset++] = count - 1;
2025
- }
2026
- count++;
2027
- }
2028
- indices[indicesOffset++] = centerIndex + 1;
2029
- indices[indicesOffset++] = centerIndex;
2030
- indices[indicesOffset++] = count - 1;
2031
- return {
2032
- vertices,
2033
- indices
2034
- };
2081
+ getAdaptiveVertices(output = []) {
2082
+ if (this.startAngle === 0 && this.endAngle === Math.PI * 2) {
2083
+ return this._getAdaptiveVerticesByCircle(output);
2084
+ }
2085
+ return this._getAdaptiveVerticesByArc(output);
2035
2086
  }
2036
2087
  getMinMax(min = Vector2.MAX, max = Vector2.MIN) {
2037
2088
  const { cx, cy, rx, ry, rotate } = this;
@@ -2228,7 +2279,7 @@ class ArcCurve extends RoundCurve {
2228
2279
  );
2229
2280
  return this;
2230
2281
  }
2231
- getAdaptivePointArray(output = []) {
2282
+ getAdaptiveVertices(output = []) {
2232
2283
  const { cx, cy, rx, startAngle, endAngle, clockwise } = this;
2233
2284
  let dist = Math.abs(startAngle - endAngle);
2234
2285
  if (!clockwise && startAngle > endAngle) {
@@ -2253,6 +2304,96 @@ class ArcCurve extends RoundCurve {
2253
2304
  }
2254
2305
  }
2255
2306
 
2307
+ class LineCurve extends Curve {
2308
+ constructor(p1 = new Vector2(), p2 = new Vector2()) {
2309
+ super();
2310
+ this.p1 = p1;
2311
+ this.p2 = p2;
2312
+ }
2313
+ static from(p1x, p1y, p2x, p2y) {
2314
+ return new LineCurve(
2315
+ new Vector2(p1x, p1y),
2316
+ new Vector2(p2x, p2y)
2317
+ );
2318
+ }
2319
+ getPoint(t, output = new Vector2()) {
2320
+ if (t === 1) {
2321
+ output.copy(this.p2);
2322
+ } else {
2323
+ output.copy(this.p2).sub(this.p1).scale(t).add(this.p1);
2324
+ }
2325
+ return output;
2326
+ }
2327
+ getPointAt(u, output = new Vector2()) {
2328
+ return this.getPoint(u, output);
2329
+ }
2330
+ getTangent(_t, output = new Vector2()) {
2331
+ return output.subVectors(this.p2, this.p1).normalize();
2332
+ }
2333
+ getTangentAt(u, output = new Vector2()) {
2334
+ return this.getTangent(u, output);
2335
+ }
2336
+ getControlPointRefs() {
2337
+ return [this.p1, this.p2];
2338
+ }
2339
+ getAdaptiveVertices(output = []) {
2340
+ output.push(
2341
+ this.p1.x,
2342
+ this.p1.y,
2343
+ this.p2.x,
2344
+ this.p2.y
2345
+ );
2346
+ return output;
2347
+ }
2348
+ getMinMax(min = Vector2.MAX, max = Vector2.MIN) {
2349
+ const { p1, p2 } = this;
2350
+ min.x = Math.min(min.x, p1.x, p2.x);
2351
+ min.y = Math.min(min.y, p1.y, p2.y);
2352
+ max.x = Math.max(max.x, p1.x, p2.x);
2353
+ max.y = Math.max(max.y, p1.y, p2.y);
2354
+ return { min: min.finite(), max: max.finite() };
2355
+ }
2356
+ toCommands() {
2357
+ const { p1, p2 } = this;
2358
+ return [
2359
+ { type: "M", x: p1.x, y: p1.y },
2360
+ { type: "L", x: p2.x, y: p2.y }
2361
+ ];
2362
+ }
2363
+ getFillVertices(options = {}) {
2364
+ const minX = Math.min(this.p1.x, this.p2.x);
2365
+ const maxX = Math.max(this.p1.x, this.p2.x);
2366
+ const minY = Math.min(this.p1.y, this.p2.y);
2367
+ const maxY = Math.max(this.p1.y, this.p2.y);
2368
+ const x = minX;
2369
+ const y = minY;
2370
+ const width = maxX - minX || options.style?.strokeWidth || 0;
2371
+ const height = maxY - minY || options.style?.strokeWidth || 0;
2372
+ return [
2373
+ x,
2374
+ y,
2375
+ x + width,
2376
+ y,
2377
+ x + width,
2378
+ y + height,
2379
+ x,
2380
+ y + height
2381
+ ];
2382
+ }
2383
+ drawTo(ctx) {
2384
+ const { p1, p2 } = this;
2385
+ ctx.lineTo(p1.x, p1.y);
2386
+ ctx.lineTo(p2.x, p2.y);
2387
+ return this;
2388
+ }
2389
+ copy(source) {
2390
+ super.copy(source);
2391
+ this.p1.copy(source.p1);
2392
+ this.p2.copy(source.p2);
2393
+ return this;
2394
+ }
2395
+ }
2396
+
2256
2397
  class CompositeCurve extends Curve {
2257
2398
  constructor(curves = []) {
2258
2399
  super();
@@ -2300,15 +2441,17 @@ class CompositeCurve extends Curve {
2300
2441
  return this.curves.flatMap((curve) => curve.getControlPointRefs());
2301
2442
  }
2302
2443
  _removeNextPointIfEqualPrevPoint(output, offset) {
2303
- if (output[offset - 1] === output[offset + 1] && output[offset] === output[offset + 2]) {
2444
+ const p1 = [output[offset - 1], output[offset]];
2445
+ const p2 = [output[offset + 1], output[offset + 2]];
2446
+ if (p1[0] === p2[0] && p1[1] === p2[1]) {
2304
2447
  output.splice(offset + 1, 2);
2305
2448
  }
2306
2449
  return output;
2307
2450
  }
2308
- getSpacedPointArray(count = 5, output = []) {
2451
+ getSpacedVertices(count = 5, output = []) {
2309
2452
  let offset;
2310
2453
  this.curves.forEach((curve) => {
2311
- curve.getSpacedPointArray(count, output);
2454
+ curve.getSpacedVertices(count, output);
2312
2455
  if (offset) {
2313
2456
  this._removeNextPointIfEqualPrevPoint(output, offset);
2314
2457
  }
@@ -2316,10 +2459,10 @@ class CompositeCurve extends Curve {
2316
2459
  });
2317
2460
  return output;
2318
2461
  }
2319
- getAdaptivePointArray(output = []) {
2462
+ getAdaptiveVertices(output = []) {
2320
2463
  let offset;
2321
2464
  this.curves.forEach((curve) => {
2322
- curve.getAdaptivePointArray(output);
2465
+ curve.getAdaptiveVertices(output);
2323
2466
  if (offset) {
2324
2467
  this._removeNextPointIfEqualPrevPoint(output, offset);
2325
2468
  }
@@ -2327,17 +2470,34 @@ class CompositeCurve extends Curve {
2327
2470
  });
2328
2471
  return output;
2329
2472
  }
2330
- fillTriangulate(options) {
2331
- const indices = options?.indices ?? [];
2332
- const vertices = options?.vertices ?? [];
2333
- this.curves.forEach((curve) => {
2334
- curve.fillTriangulate({
2335
- ...options,
2336
- indices,
2337
- vertices
2473
+ strokeTriangulate(options) {
2474
+ if (this.curves.length === 1) {
2475
+ return this.curves[0].strokeTriangulate(options);
2476
+ } else {
2477
+ return super.strokeTriangulate(options);
2478
+ }
2479
+ }
2480
+ getFillVertices(options) {
2481
+ if (this.curves.length === 1) {
2482
+ return this.curves[0].getFillVertices(options);
2483
+ } else {
2484
+ const output = [];
2485
+ let offset;
2486
+ this.curves.forEach((curve) => {
2487
+ let arr;
2488
+ if (curve instanceof LineCurve) {
2489
+ arr = curve.getAdaptiveVertices();
2490
+ } else {
2491
+ arr = curve.getFillVertices(options);
2492
+ }
2493
+ output.push(...arr);
2494
+ if (offset) {
2495
+ this._removeNextPointIfEqualPrevPoint(output, offset);
2496
+ }
2497
+ offset = output.length - 1;
2338
2498
  });
2339
- });
2340
- return { indices, vertices };
2499
+ return output;
2500
+ }
2341
2501
  }
2342
2502
  applyTransform(transform) {
2343
2503
  this.curves.forEach((curve) => curve.applyTransform(transform));
@@ -2392,7 +2552,7 @@ class CubicBezierCurve extends Curve {
2392
2552
  cubicBezier(t, p1.y, cp1.y, cp2.y, p2.y)
2393
2553
  );
2394
2554
  }
2395
- getAdaptivePointArray(output = []) {
2555
+ getAdaptiveVertices(output = []) {
2396
2556
  return getAdaptiveCubicBezierCurvePoints(
2397
2557
  this.p1.x,
2398
2558
  this.p1.y,
@@ -2497,125 +2657,6 @@ class EllipseCurve extends RoundCurve {
2497
2657
  }
2498
2658
  }
2499
2659
 
2500
- class LineCurve extends Curve {
2501
- constructor(p1 = new Vector2(), p2 = new Vector2()) {
2502
- super();
2503
- this.p1 = p1;
2504
- this.p2 = p2;
2505
- }
2506
- static from(p1x, p1y, p2x, p2y) {
2507
- return new LineCurve(
2508
- new Vector2(p1x, p1y),
2509
- new Vector2(p2x, p2y)
2510
- );
2511
- }
2512
- getPoint(t, output = new Vector2()) {
2513
- if (t === 1) {
2514
- output.copy(this.p2);
2515
- } else {
2516
- output.copy(this.p2).sub(this.p1).scale(t).add(this.p1);
2517
- }
2518
- return output;
2519
- }
2520
- getPointAt(u, output = new Vector2()) {
2521
- return this.getPoint(u, output);
2522
- }
2523
- getTangent(_t, output = new Vector2()) {
2524
- return output.subVectors(this.p2, this.p1).normalize();
2525
- }
2526
- getTangentAt(u, output = new Vector2()) {
2527
- return this.getTangent(u, output);
2528
- }
2529
- getControlPointRefs() {
2530
- return [this.p1, this.p2];
2531
- }
2532
- getAdaptivePointArray(output = []) {
2533
- output.push(
2534
- this.p1.x,
2535
- this.p1.y,
2536
- this.p2.x,
2537
- this.p2.y
2538
- );
2539
- return output;
2540
- }
2541
- getMinMax(min = Vector2.MAX, max = Vector2.MIN) {
2542
- const { p1, p2 } = this;
2543
- min.x = Math.min(min.x, p1.x, p2.x);
2544
- min.y = Math.min(min.y, p1.y, p2.y);
2545
- max.x = Math.max(max.x, p1.x, p2.x);
2546
- max.y = Math.max(max.y, p1.y, p2.y);
2547
- return { min: min.finite(), max: max.finite() };
2548
- }
2549
- toCommands() {
2550
- const { p1, p2 } = this;
2551
- return [
2552
- { type: "M", x: p1.x, y: p1.y },
2553
- { type: "L", x: p2.x, y: p2.y }
2554
- ];
2555
- }
2556
- fillTriangulate(options = {}) {
2557
- let {
2558
- vertices = [],
2559
- indices = [],
2560
- verticesStride = 2,
2561
- verticesOffset = vertices.length / verticesStride,
2562
- indicesOffset = indices.length
2563
- } = options;
2564
- const minX = Math.min(this.p1.x, this.p2.x);
2565
- const maxX = Math.max(this.p1.x, this.p2.x);
2566
- const minY = Math.min(this.p1.y, this.p2.y);
2567
- const maxY = Math.max(this.p1.y, this.p2.y);
2568
- const x = minX;
2569
- const y = minY;
2570
- const width = maxX - minX;
2571
- const height = maxY - minY;
2572
- const points = [
2573
- x,
2574
- y,
2575
- x + width,
2576
- y,
2577
- x + width,
2578
- y + height,
2579
- x,
2580
- y + height
2581
- ];
2582
- let count = 0;
2583
- verticesOffset *= verticesStride;
2584
- vertices[verticesOffset + count] = points[0];
2585
- vertices[verticesOffset + count + 1] = points[1];
2586
- count += verticesStride;
2587
- vertices[verticesOffset + count] = points[2];
2588
- vertices[verticesOffset + count + 1] = points[3];
2589
- count += verticesStride;
2590
- vertices[verticesOffset + count] = points[6];
2591
- vertices[verticesOffset + count + 1] = points[7];
2592
- count += verticesStride;
2593
- vertices[verticesOffset + count] = points[4];
2594
- vertices[verticesOffset + count + 1] = points[5];
2595
- count += verticesStride;
2596
- const verticesIndex = verticesOffset / verticesStride;
2597
- indices[indicesOffset++] = verticesIndex;
2598
- indices[indicesOffset++] = verticesIndex + 1;
2599
- indices[indicesOffset++] = verticesIndex + 2;
2600
- indices[indicesOffset++] = verticesIndex + 1;
2601
- indices[indicesOffset++] = verticesIndex + 3;
2602
- indices[indicesOffset++] = verticesIndex + 2;
2603
- return { vertices, indices };
2604
- }
2605
- drawTo(ctx) {
2606
- const { p1, p2 } = this;
2607
- ctx.lineTo(p1.x, p1.y);
2608
- ctx.lineTo(p2.x, p2.y);
2609
- return this;
2610
- }
2611
- copy(source) {
2612
- super.copy(source);
2613
- this.p1.copy(source.p1);
2614
- this.p2.copy(source.p2);
2615
- return this;
2616
- }
2617
- }
2618
-
2619
2660
  class PloygonCurve extends CompositeCurve {
2620
2661
  //
2621
2662
  }
@@ -2689,7 +2730,7 @@ class QuadraticBezierCurve extends Curve {
2689
2730
  getControlPointRefs() {
2690
2731
  return [this.p1, this.cp, this.p2];
2691
2732
  }
2692
- getAdaptivePointArray(output = []) {
2733
+ getAdaptiveVertices(output = []) {
2693
2734
  return getAdaptiveQuadraticBezierCurvePoints(
2694
2735
  this.p1.x,
2695
2736
  this.p1.y,
@@ -2764,16 +2805,9 @@ class RectangleCurve extends PloygonCurve {
2764
2805
  ctx.rect(this.x, this.y, this.width, this.height);
2765
2806
  return this;
2766
2807
  }
2767
- fillTriangulate(options = {}) {
2768
- let {
2769
- vertices = [],
2770
- indices = [],
2771
- verticesStride = 2,
2772
- verticesOffset = vertices.length / verticesStride,
2773
- indicesOffset = indices.length
2774
- } = options;
2808
+ getFillVertices(_options = {}) {
2775
2809
  const { x, y, width, height } = this;
2776
- const points = [
2810
+ return [
2777
2811
  x,
2778
2812
  y,
2779
2813
  x + width,
@@ -2783,28 +2817,6 @@ class RectangleCurve extends PloygonCurve {
2783
2817
  x,
2784
2818
  y + height
2785
2819
  ];
2786
- let count = 0;
2787
- verticesOffset *= verticesStride;
2788
- vertices[verticesOffset + count] = points[0];
2789
- vertices[verticesOffset + count + 1] = points[1];
2790
- count += verticesStride;
2791
- vertices[verticesOffset + count] = points[2];
2792
- vertices[verticesOffset + count + 1] = points[3];
2793
- count += verticesStride;
2794
- vertices[verticesOffset + count] = points[6];
2795
- vertices[verticesOffset + count + 1] = points[7];
2796
- count += verticesStride;
2797
- vertices[verticesOffset + count] = points[4];
2798
- vertices[verticesOffset + count + 1] = points[5];
2799
- count += verticesStride;
2800
- const verticesIndex = verticesOffset / verticesStride;
2801
- indices[indicesOffset++] = verticesIndex;
2802
- indices[indicesOffset++] = verticesIndex + 1;
2803
- indices[indicesOffset++] = verticesIndex + 2;
2804
- indices[indicesOffset++] = verticesIndex + 1;
2805
- indices[indicesOffset++] = verticesIndex + 3;
2806
- indices[indicesOffset++] = verticesIndex + 2;
2807
- return { vertices, indices };
2808
2820
  }
2809
2821
  copy(source) {
2810
2822
  super.copy(source);
@@ -2916,25 +2928,30 @@ class CurvePath extends CompositeCurve {
2916
2928
  this.addCommands(svgPathDataToCommands(data));
2917
2929
  return this;
2918
2930
  }
2919
- _closePointArray(output) {
2931
+ _closeVertices(output) {
2920
2932
  if (this.autoClose && output.length >= 4 && (output[0] !== output[output.length - 2] && output[1] !== output[output.length - 1])) {
2921
2933
  output.push(output[0], output[1]);
2922
2934
  }
2923
2935
  return output;
2924
2936
  }
2925
- getUnevenPointArray(count = 40, output = []) {
2926
- return this._closePointArray(
2927
- super.getUnevenPointArray(count, output)
2937
+ getUnevenVertices(count = 40, output = []) {
2938
+ return this._closeVertices(
2939
+ super.getUnevenVertices(count, output)
2928
2940
  );
2929
2941
  }
2930
- getSpacedPointArray(count = 40, output = []) {
2931
- return this._closePointArray(
2932
- super.getSpacedPointArray(count, output)
2942
+ getSpacedVertices(count = 40, output = []) {
2943
+ return this._closeVertices(
2944
+ super.getSpacedVertices(count, output)
2933
2945
  );
2934
2946
  }
2935
- getAdaptivePointArray(output = []) {
2936
- return this._closePointArray(
2937
- super.getAdaptivePointArray(output)
2947
+ getAdaptiveVertices(output = []) {
2948
+ return this._closeVertices(
2949
+ super.getAdaptiveVertices(output)
2950
+ );
2951
+ }
2952
+ getFillVertices(options) {
2953
+ return this._closeVertices(
2954
+ super.getFillVertices(options)
2938
2955
  );
2939
2956
  }
2940
2957
  _setCurrentPoint(point) {
@@ -3362,11 +3379,78 @@ class Path2D extends CompositeCurve {
3362
3379
  curve.strokeTriangulate({
3363
3380
  ...options,
3364
3381
  indices,
3365
- vertices
3382
+ vertices,
3383
+ style: { ...this.style }
3366
3384
  });
3367
3385
  });
3368
3386
  return { indices, vertices };
3369
3387
  }
3388
+ fillTriangulate(options) {
3389
+ const _options = {
3390
+ ...options,
3391
+ style: {
3392
+ ...this.style,
3393
+ ...options?.style
3394
+ }
3395
+ };
3396
+ const indices = _options.indices ?? [];
3397
+ const vertices = _options.vertices ?? [];
3398
+ const fillRule = _options.style.fillRule ?? "nonzero";
3399
+ if (fillRule === "nonzero") {
3400
+ const pointArrays = this.curves.map((curve) => curve.getFillVertices(_options));
3401
+ const parentMap = /* @__PURE__ */ new Map();
3402
+ const parentd = /* @__PURE__ */ new Set();
3403
+ for (let i = 0; i < pointArrays.length; i++) {
3404
+ const parents = [];
3405
+ for (let j = 0; j < pointArrays.length; j++) {
3406
+ if (i === j)
3407
+ continue;
3408
+ if (pointInPolygon([pointArrays[i][0], pointArrays[i][1]], pointArrays[j])) {
3409
+ parents.push(j);
3410
+ }
3411
+ }
3412
+ if (parents.length) {
3413
+ parents.forEach((pi) => {
3414
+ let set = parentMap.get(pi);
3415
+ if (!set) {
3416
+ set = /* @__PURE__ */ new Set();
3417
+ parentMap.set(pi, set);
3418
+ }
3419
+ set.add(i);
3420
+ });
3421
+ parentd.add(i);
3422
+ }
3423
+ }
3424
+ pointArrays.forEach((pointArray, i) => {
3425
+ if (parentd.has(i) || !pointArray.length) {
3426
+ return;
3427
+ }
3428
+ const _pointArray = pointArray.slice();
3429
+ const holes = [];
3430
+ parentMap.get(i)?.forEach((ci) => {
3431
+ holes.push(_pointArray.length / 2);
3432
+ _pointArray.push(...pointArrays[ci]);
3433
+ });
3434
+ fillTriangulate(_pointArray, {
3435
+ ...options,
3436
+ indices,
3437
+ vertices,
3438
+ holes,
3439
+ style: { ...this.style }
3440
+ });
3441
+ });
3442
+ } else {
3443
+ this.curves.forEach((curve) => {
3444
+ curve.fillTriangulate({
3445
+ ...options,
3446
+ indices,
3447
+ vertices,
3448
+ style: { ...this.style }
3449
+ });
3450
+ });
3451
+ }
3452
+ return { indices, vertices };
3453
+ }
3370
3454
  getBoundingBox(withStyle = true) {
3371
3455
  const { min, max } = this.getMinMax(undefined, undefined, withStyle);
3372
3456
  return new BoundingBox(min.x, min.y, max.x - min.x, max.y - min.y);
@@ -3458,6 +3542,34 @@ class Path2DSet {
3458
3542
  this.paths.forEach((path) => path.getMinMax(min, max, withStyle));
3459
3543
  return new BoundingBox(min.x, min.y, max.x - min.x, max.y - min.y);
3460
3544
  }
3545
+ toTriangulatedSVGString(result = this.paths.map((p) => p.fillTriangulate()), padding = 0) {
3546
+ let polygonStr = "";
3547
+ const min = { x: -padding, y: -padding };
3548
+ const max = { x: padding, y: padding };
3549
+ const results = Array.isArray(result) ? result : [result];
3550
+ results.forEach(({ vertices, indices }) => {
3551
+ const getPoint = (indice) => {
3552
+ const x = vertices[indice * 2];
3553
+ const y = vertices[indice * 2 + 1];
3554
+ min.x = Math.min(min.x, x + padding);
3555
+ max.x = Math.max(max.x, x + padding);
3556
+ min.y = Math.min(min.y, y + padding);
3557
+ max.y = Math.max(max.y, y + padding);
3558
+ return [x, y];
3559
+ };
3560
+ for (let i = 0, len = indices.length; i < len; i += 3) {
3561
+ const p1 = getPoint(indices[i]);
3562
+ const p2 = getPoint(indices[i + 1]);
3563
+ const p3 = getPoint(indices[i + 2]);
3564
+ polygonStr += `<polygon points="${p1.join(",")} ${p2.join(",")} ${p3.join(",")}" fill="black" />`;
3565
+ }
3566
+ });
3567
+ const viewBox = [min.x, min.y, max.x - min.x, max.y - min.y];
3568
+ return `<svg width="${viewBox[2]}" height="${viewBox[3]}" viewBox="${viewBox.join(" ")}" xmlns="http://www.w3.org/2000/svg">${polygonStr}</svg>`;
3569
+ }
3570
+ toTriangulatedSVG(result, padding) {
3571
+ return new DOMParser().parseFromString(this.toTriangulatedSVGString(result, padding), "image/svg+xml").documentElement;
3572
+ }
3461
3573
  toSVGString() {
3462
3574
  const { x, y, width, height } = this.getBoundingBox();
3463
3575
  const content = this.paths.map((path) => path.toSVGPathString()).join("");
@@ -4073,4 +4185,4 @@ function svgToPath2DSet(svg) {
4073
4185
  );
4074
4186
  }
4075
4187
 
4076
- export { ArcCurve, BoundingBox, CompositeCurve, CubicBezierCurve, Curve, CurvePath, EllipseCurve, EquilateralPloygonCurve, FFDControlGrid, LineCurve, Matrix3, Path2D, Path2DSet, PloygonCurve, QuadraticBezierCurve, RectangleCurve, RoundRectangleCurve, SplineCurve, Vector2, applyFFD, catmullRom, cubicBezier, drawPoint, fillTriangulate, getAdaptiveCubicBezierCurvePoints, getAdaptiveQuadraticBezierCurvePoints, parseArcCommand, parsePathDataArgs, quadraticBezier, setCanvasContext, strokeTriangulate, svgPathCommandsAddToPath2D, svgPathCommandsToData, svgPathDataToCommands, svgToDOM, svgToPath2DSet };
4188
+ export { ArcCurve, BoundingBox, CompositeCurve, CubicBezierCurve, Curve, CurvePath, EllipseCurve, EquilateralPloygonCurve, FFDControlGrid, LineCurve, Matrix3, Path2D, Path2DSet, PloygonCurve, QuadraticBezierCurve, RectangleCurve, RoundRectangleCurve, SplineCurve, Vector2, applyFFD, catmullRom, cubicBezier, drawPoint, fillTriangulate, getAdaptiveCubicBezierCurvePoints, getAdaptiveQuadraticBezierCurvePoints, getDirectedArea, parseArcCommand, parsePathDataArgs, pointInPolygon, quadraticBezier, setCanvasContext, strokeTriangulate, svgPathCommandsAddToPath2D, svgPathCommandsToData, svgPathDataToCommands, svgToDOM, svgToPath2DSet };