plotboilerplate 1.23.3 → 1.24.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (159) hide show
  1. package/README.md +6 -0
  2. package/dist/index.esm.js +1390 -265
  3. package/dist/index.esm.js.map +1 -1
  4. package/dist/index.esm.min.js +1 -1
  5. package/dist/index.esm.min.js.map +1 -1
  6. package/dist/plotboilerplate.browser.min.js +1 -1
  7. package/dist/plotboilerplate.browser.min.js.map +1 -1
  8. package/dist/plotboilerplate.js +1264 -99
  9. package/dist/plotboilerplate.min.js +1 -1
  10. package/package.json +1 -1
  11. package/src/cjs/BezierPath.d.ts +41 -5
  12. package/src/cjs/BezierPath.js +52 -2
  13. package/src/cjs/BezierPath.js.map +1 -1
  14. package/src/cjs/Bounds.d.ts +67 -3
  15. package/src/cjs/Bounds.js +101 -3
  16. package/src/cjs/Bounds.js.map +1 -1
  17. package/src/cjs/Circle.d.ts +46 -4
  18. package/src/cjs/Circle.js +82 -3
  19. package/src/cjs/Circle.js.map +1 -1
  20. package/src/cjs/CircleSector.d.ts +51 -2
  21. package/src/cjs/CircleSector.js +112 -3
  22. package/src/cjs/CircleSector.js.map +1 -1
  23. package/src/cjs/CubicBezierCurve.d.ts +113 -7
  24. package/src/cjs/CubicBezierCurve.js +281 -33
  25. package/src/cjs/CubicBezierCurve.js.map +1 -1
  26. package/src/cjs/Line.d.ts +38 -3
  27. package/src/cjs/Line.js +64 -1
  28. package/src/cjs/Line.js.map +1 -1
  29. package/src/cjs/PlotBoilerplate.js +2 -9
  30. package/src/cjs/PlotBoilerplate.js.map +1 -1
  31. package/src/cjs/Polygon.d.ts +48 -4
  32. package/src/cjs/Polygon.js +91 -16
  33. package/src/cjs/Polygon.js.map +1 -1
  34. package/src/cjs/Triangle.d.ts +52 -3
  35. package/src/cjs/Triangle.js +80 -1
  36. package/src/cjs/Triangle.js.map +1 -1
  37. package/src/cjs/VEllipse.d.ts +62 -3
  38. package/src/cjs/VEllipse.js +181 -17
  39. package/src/cjs/VEllipse.js.map +1 -1
  40. package/src/cjs/VEllipseSector.d.ts +86 -2
  41. package/src/cjs/VEllipseSector.js +148 -4
  42. package/src/cjs/VEllipseSector.js.map +1 -1
  43. package/src/cjs/Vector.d.ts +12 -2
  44. package/src/cjs/Vector.js +15 -2
  45. package/src/cjs/Vector.js.map +1 -1
  46. package/src/cjs/VertTuple.d.ts +28 -4
  47. package/src/cjs/VertTuple.js +36 -3
  48. package/src/cjs/VertTuple.js.map +1 -1
  49. package/src/cjs/Vertex.d.ts +17 -2
  50. package/src/cjs/Vertex.js +18 -1
  51. package/src/cjs/Vertex.js.map +1 -1
  52. package/src/cjs/interfaces/core.d.ts +39 -0
  53. package/src/cjs/interfaces/core.js +2 -0
  54. package/src/cjs/interfaces/core.js.map +1 -1
  55. package/src/cjs/utils/algorithms/convexPolygonIncircle.d.ts +2 -1
  56. package/src/cjs/utils/algorithms/convexPolygonIncircle.js +14 -6
  57. package/src/cjs/utils/algorithms/convexPolygonIncircle.js.map +1 -1
  58. package/src/cjs/utils/createRandomizedPolygon.d.ts +14 -0
  59. package/src/cjs/utils/createRandomizedPolygon.js +32 -0
  60. package/src/cjs/utils/createRandomizedPolygon.js.map +1 -0
  61. package/src/cjs/utils/helpers/BezierPathInteractionHelper.d.ts +9 -7
  62. package/src/cjs/utils/helpers/BezierPathInteractionHelper.js +37 -23
  63. package/src/cjs/utils/helpers/BezierPathInteractionHelper.js.map +1 -1
  64. package/src/cjs/utils/helpers/CircleSectorHelper.d.ts +10 -1
  65. package/src/cjs/utils/helpers/CircleSectorHelper.js +19 -20
  66. package/src/cjs/utils/helpers/CircleSectorHelper.js.map +1 -1
  67. package/src/cjs/utils/helpers/VEllipseHelper.d.ts +30 -0
  68. package/src/cjs/utils/helpers/VEllipseHelper.js +86 -0
  69. package/src/cjs/utils/helpers/VEllipseHelper.js.map +1 -0
  70. package/src/cjs/utils/helpers/VEllipseSectorHelper.d.ts +42 -3
  71. package/src/cjs/utils/helpers/VEllipseSectorHelper.js +107 -25
  72. package/src/cjs/utils/helpers/VEllipseSectorHelper.js.map +1 -1
  73. package/src/createDemoDrawables.js +3 -1
  74. package/src/esm/BezierPath.d.ts +41 -5
  75. package/src/esm/BezierPath.js +50 -2
  76. package/src/esm/BezierPath.js.map +1 -1
  77. package/src/esm/Bounds.d.ts +67 -3
  78. package/src/esm/Bounds.js +101 -3
  79. package/src/esm/Bounds.js.map +1 -1
  80. package/src/esm/Circle.d.ts +46 -4
  81. package/src/esm/Circle.js +79 -3
  82. package/src/esm/Circle.js.map +1 -1
  83. package/src/esm/CircleSector.d.ts +51 -2
  84. package/src/esm/CircleSector.js +108 -3
  85. package/src/esm/CircleSector.js.map +1 -1
  86. package/src/esm/CubicBezierCurve.d.ts +113 -7
  87. package/src/esm/CubicBezierCurve.js +277 -33
  88. package/src/esm/CubicBezierCurve.js.map +1 -1
  89. package/src/esm/Line.d.ts +38 -3
  90. package/src/esm/Line.js +62 -1
  91. package/src/esm/Line.js.map +1 -1
  92. package/src/esm/PlotBoilerplate.js +2 -9
  93. package/src/esm/PlotBoilerplate.js.map +1 -1
  94. package/src/esm/Polygon.d.ts +48 -4
  95. package/src/esm/Polygon.js +89 -16
  96. package/src/esm/Polygon.js.map +1 -1
  97. package/src/esm/Triangle.d.ts +52 -3
  98. package/src/esm/Triangle.js +77 -1
  99. package/src/esm/Triangle.js.map +1 -1
  100. package/src/esm/VEllipse.d.ts +62 -3
  101. package/src/esm/VEllipse.js +178 -17
  102. package/src/esm/VEllipse.js.map +1 -1
  103. package/src/esm/VEllipseSector.d.ts +86 -2
  104. package/src/esm/VEllipseSector.js +146 -7
  105. package/src/esm/VEllipseSector.js.map +1 -1
  106. package/src/esm/Vector.d.ts +12 -2
  107. package/src/esm/Vector.js +15 -2
  108. package/src/esm/Vector.js.map +1 -1
  109. package/src/esm/VertTuple.d.ts +28 -4
  110. package/src/esm/VertTuple.js +36 -3
  111. package/src/esm/VertTuple.js.map +1 -1
  112. package/src/esm/Vertex.d.ts +17 -2
  113. package/src/esm/Vertex.js +18 -1
  114. package/src/esm/Vertex.js.map +1 -1
  115. package/src/esm/interfaces/core.d.ts +39 -0
  116. package/src/esm/interfaces/core.js +2 -0
  117. package/src/esm/interfaces/core.js.map +1 -1
  118. package/src/esm/utils/algorithms/convexPolygonIncircle.d.ts +2 -1
  119. package/src/esm/utils/algorithms/convexPolygonIncircle.js +15 -7
  120. package/src/esm/utils/algorithms/convexPolygonIncircle.js.map +1 -1
  121. package/src/esm/utils/algorithms/createRandomizedPolygon.d.ts +14 -0
  122. package/src/esm/utils/algorithms/createRandomizedPolygon.js +28 -0
  123. package/src/esm/utils/algorithms/createRandomizedPolygon.js.map +1 -0
  124. package/src/esm/utils/createRandomizedPolygon.d.ts +14 -0
  125. package/src/esm/utils/createRandomizedPolygon.js +28 -0
  126. package/src/esm/utils/createRandomizedPolygon.js.map +1 -0
  127. package/src/esm/utils/helpers/BezierPathInteractionHelper.d.ts +9 -7
  128. package/src/esm/utils/helpers/BezierPathInteractionHelper.js +35 -22
  129. package/src/esm/utils/helpers/BezierPathInteractionHelper.js.map +1 -1
  130. package/src/esm/utils/helpers/CircleSectorHelper.d.ts +10 -1
  131. package/src/esm/utils/helpers/CircleSectorHelper.js +19 -20
  132. package/src/esm/utils/helpers/CircleSectorHelper.js.map +1 -1
  133. package/src/esm/utils/helpers/VEllipseHelper.d.ts +30 -0
  134. package/src/esm/utils/helpers/VEllipseHelper.js +81 -0
  135. package/src/esm/utils/helpers/VEllipseHelper.js.map +1 -0
  136. package/src/esm/utils/helpers/VEllipseSectorHelper.d.ts +42 -3
  137. package/src/esm/utils/helpers/VEllipseSectorHelper.js +106 -24
  138. package/src/esm/utils/helpers/VEllipseSectorHelper.js.map +1 -1
  139. package/src/ts/BezierPath.ts +58 -5
  140. package/src/ts/Bounds.ts +110 -6
  141. package/src/ts/Circle.ts +87 -5
  142. package/src/ts/CircleSector.ts +115 -5
  143. package/src/ts/CubicBezierCurve.ts +332 -42
  144. package/src/ts/Line.ts +66 -3
  145. package/src/ts/PlotBoilerplate.ts +3 -9
  146. package/src/ts/Polygon.ts +103 -22
  147. package/src/ts/Triangle.ts +85 -3
  148. package/src/ts/VEllipse.ts +214 -19
  149. package/src/ts/VEllipseSector.ts +154 -8
  150. package/src/ts/Vector.ts +16 -2
  151. package/src/ts/VertTuple.ts +39 -4
  152. package/src/ts/Vertex.ts +20 -2
  153. package/src/ts/interfaces/core.ts +42 -0
  154. package/src/ts/utils/algorithms/convexPolygonIncircle.ts +82 -78
  155. package/src/ts/utils/createRandomizedPolygon.ts +31 -0
  156. package/src/ts/utils/helpers/BezierPathInteractionHelper.ts +45 -29
  157. package/src/ts/utils/helpers/CircleSectorHelper.ts +115 -125
  158. package/src/ts/utils/helpers/VEllipseHelper.ts +113 -0
  159. package/src/ts/utils/helpers/VEllipseSectorHelper.ts +142 -25
@@ -450,7 +450,10 @@ class AlloyFinger {
450
450
  * @modified 2022-02-02 Cleared the `toSVGString` function (deprecated). Use `drawutilssvg` instead.
451
451
  * @modified 2023-10-06 Adding the `BezierPath.toPathPoints()` method.
452
452
  * @modified 2023-10-07 Adding the `BezierPath.fromCurve(CubicBezierCurve)` static function.
453
- * @version 2.6.0
453
+ * @modified 2025-04-09 Added the `BezierPath.move` method to match the convention – which just calls `translate`.
454
+ * @modified 2025-04-09 Modified the `BezierPath.translate` method: chaning parameter `Vertex` to more generalized `XYCoords`.
455
+ * @modified 2025-04-14 Class `BezierPath` is now implementing interface `Intersectable`.
456
+ * @version 2.7.0
454
457
  *
455
458
  * @file BezierPath
456
459
  * @public
@@ -661,7 +664,7 @@ var BezierPath = /** @class */ (function () {
661
664
  * Move the whole bezier path by the given (x,y)-amount.
662
665
  *
663
666
  * @method translate
664
- * @param {Vertex} amount - The amount to be added (amount.x and amount.y)
667
+ * @param {XYCoords} amount - The amount to be added (amount.x and amount.y)
665
668
  * to each vertex of the curve.
666
669
  * @instance
667
670
  * @memberof BezierPath
@@ -680,6 +683,19 @@ var BezierPath = /** @class */ (function () {
680
683
  this.updateArcLengths();
681
684
  return this;
682
685
  };
686
+ /**
687
+ * Move the whole bezier path by the given (x,y)-amount.
688
+ *
689
+ * @method move
690
+ * @param {XYCoords} amount - The amount to be added (amount.x and amount.y)
691
+ * to each vertex of the curve.
692
+ * @instance
693
+ * @memberof BezierPath
694
+ * @return {BezierPath} this for chaining
695
+ **/
696
+ BezierPath.prototype.move = function (amount) {
697
+ return this.translate(amount);
698
+ };
683
699
  /**
684
700
  * Scale the whole bezier path by the given uniform factor.
685
701
  *
@@ -890,6 +906,38 @@ var BezierPath = /** @class */ (function () {
890
906
  var relativeU = u - uResult.uPart;
891
907
  return bCurve.getPerpendicular(relativeU);
892
908
  };
909
+ //--- BEGIN --- Implement interface `Intersectable`
910
+ /**
911
+ * Get all line intersections with this shape.
912
+ *
913
+ * This method returns all intersections (as vertices) with this shape. The returned array of vertices is in no specific order.
914
+ *
915
+ * @param {VertTuple} line - The line to find intersections with.
916
+ * @param {boolean} inVectorBoundsOnly - If set to true only intersecion points on the passed vector are returned (located strictly between start and end vertex).
917
+ * @returns {Array<Vertex>} - An array of all intersections with the shape's outline.
918
+ */
919
+ BezierPath.prototype.lineIntersections = function (line, inVectorBoundsOnly) {
920
+ if (inVectorBoundsOnly === void 0) { inVectorBoundsOnly = false; }
921
+ return this.bezierCurves.reduce(function (accu, curCurve) {
922
+ return accu.concat(curCurve.lineIntersections(line, inVectorBoundsOnly));
923
+ }, []);
924
+ };
925
+ /**
926
+ * Get all line intersections of this polygon and their tangents along the shape.
927
+ *
928
+ * This method returns all intersection tangents (as vectors) with this shape. The returned array of vectors is in no specific order.
929
+ *
930
+ * @param line
931
+ * @param lineIntersectionTangents
932
+ * @returns
933
+ */
934
+ BezierPath.prototype.lineIntersectionTangents = function (line, inVectorBoundsOnly) {
935
+ if (inVectorBoundsOnly === void 0) { inVectorBoundsOnly = false; }
936
+ return this.bezierCurves.reduce(function (accu, curCurve) {
937
+ return accu.concat(curCurve.lineIntersectionTangents(line, inVectorBoundsOnly));
938
+ }, []);
939
+ };
940
+ //--- END --- Implement interface `Intersectable`
893
941
  /**
894
942
  * This is a helper function to locate the curve index for a given
895
943
  * absolute path position u.
@@ -1103,6 +1151,7 @@ var BezierPath = /** @class */ (function () {
1103
1151
  }
1104
1152
  neighbourCurve.updateArcLengths();
1105
1153
  };
1154
+ //--- BEGIN --- Implement interface `IBounded`
1106
1155
  /**
1107
1156
  * Get the bounds of this Bézier path.
1108
1157
  *
@@ -1124,6 +1173,7 @@ var BezierPath = /** @class */ (function () {
1124
1173
  }
1125
1174
  return new Bounds_1.Bounds(min, max);
1126
1175
  };
1176
+ //--- END --- Implement interface `IBounded`
1127
1177
  /**
1128
1178
  * Get n 'equally' distributed vertices along this Bézier path.
1129
1179
  *
@@ -1517,7 +1567,11 @@ exports.BezierPath = BezierPath;
1517
1567
  * @modified 2022-10-09 Added the `fromDimension` function.
1518
1568
  * @modified 2022-11-28 Added the `clone` method.
1519
1569
  * @modified 2023-09-29 Added the `randomPoint` method.
1520
- * @version 1.7.0
1570
+ * @modified 2025-03-23 Added the `getMinDimension` and `getMaxDimension` methods.
1571
+ * @modified 2025-04-18 Change parameter type in `Bounds.computeFromVertices` from `Vertex` to more general `XYCoords`.
1572
+ * @modified 2025-04-19 Added methods to `Bounds` class: `getNorthPoint`, `getSouthPoint`, `getEastPoint` and `getWestPoint`.
1573
+ * @modified 2025-04-26 Added static method `Bounds.computeFromBoundsSet` to calculate containing bounds for a set of bounding boxes.
1574
+ * @version 1.8.0
1521
1575
  **/
1522
1576
  Object.defineProperty(exports, "__esModule", ({ value: true }));
1523
1577
  exports.Bounds = void 0;
@@ -1545,6 +1599,54 @@ var Bounds = /** @class */ (function () {
1545
1599
  this.width = max.x - min.x;
1546
1600
  this.height = max.y - min.y;
1547
1601
  }
1602
+ /**
1603
+ * Get the center point of the north bound.
1604
+ *
1605
+ * @method getNorthPoint
1606
+ * @instance
1607
+ * @memberof Bounds
1608
+ * @return {Vertex} The "northmost" centered point of this bounding box.
1609
+ */
1610
+ Bounds.prototype.getNorthPoint = function () {
1611
+ return new Vertex_1.Vertex(this.min.x + this.width / 2.0, this.min.y);
1612
+ };
1613
+ ;
1614
+ /**
1615
+ * Get the center point of the south bound.
1616
+ *
1617
+ * @method getNorthPoint
1618
+ * @instance
1619
+ * @memberof Bounds
1620
+ * @return {Vertex} The "southhmost" centered point of this bounding box.
1621
+ */
1622
+ Bounds.prototype.getSouthPoint = function () {
1623
+ return new Vertex_1.Vertex(this.min.x + this.width / 2.0, this.max.y);
1624
+ };
1625
+ ;
1626
+ /**
1627
+ * Get the center point of the west bound.
1628
+ *
1629
+ * @method getWestPoint
1630
+ * @instance
1631
+ * @memberof Bounds
1632
+ * @return {Vertex} The "westhmost" centered point of this bounding box.
1633
+ */
1634
+ Bounds.prototype.getWestPoint = function () {
1635
+ return new Vertex_1.Vertex(this.min.x, this.min.y + this.height / 2.0);
1636
+ };
1637
+ ;
1638
+ /**
1639
+ * Get the center point of the east bound.
1640
+ *
1641
+ * @method getEastPoint
1642
+ * @instance
1643
+ * @memberof Bounds
1644
+ * @return {Vertex} The "easthmost" centered point of this bounding box.
1645
+ */
1646
+ Bounds.prototype.getEastPoint = function () {
1647
+ return new Vertex_1.Vertex(this.max.x, this.min.y + this.height / 2.0);
1648
+ };
1649
+ ;
1548
1650
  /**
1549
1651
  * Convert this rectangular bounding box to a polygon with four vertices.
1550
1652
  *
@@ -1567,6 +1669,22 @@ var Bounds = /** @class */ (function () {
1567
1669
  Bounds.prototype.getCenter = function () {
1568
1670
  return new Vertex_1.Vertex(this.min.x + (this.max.x - this.min.x) / 2.0, this.min.y + (this.max.y - this.min.y) / 2);
1569
1671
  };
1672
+ /**
1673
+ * Get the minimum of `width` and `height`.
1674
+ *
1675
+ * @returns {number} The value of Math.min( this.width, this.height )
1676
+ */
1677
+ Bounds.prototype.getMinDimension = function () {
1678
+ return Math.min(this.width, this.height);
1679
+ };
1680
+ /**
1681
+ * Get the minimum of `width` and `height`.
1682
+ *
1683
+ * @returns {number} The value of Math.min( this.width, this.height )
1684
+ */
1685
+ Bounds.prototype.getMaxDimension = function () {
1686
+ return Math.max(this.width, this.height);
1687
+ };
1570
1688
  /**
1571
1689
  * Generate a random point inside this bounds object. Safe areas at the border to avoid
1572
1690
  * included.
@@ -1619,12 +1737,13 @@ var Bounds = /** @class */ (function () {
1619
1737
  * @static
1620
1738
  * @method computeFromVertices
1621
1739
  * @memberof Bounds
1622
- * @param {Array<Vertex>} vertices - The set of vertices you want to get the bounding box for.
1740
+ * @param {Array<XYCoords>} vertices - The set of vertices you want to get the bounding box for.
1623
1741
  * @return The minimal Bounds for the given vertices.
1624
1742
  **/
1625
1743
  Bounds.computeFromVertices = function (vertices) {
1626
- if (vertices.length == 0)
1744
+ if (vertices.length == 0) {
1627
1745
  return new Bounds(new Vertex_1.Vertex(0, 0), new Vertex_1.Vertex(0, 0));
1746
+ }
1628
1747
  var xMin = vertices[0].x;
1629
1748
  var xMax = vertices[0].x;
1630
1749
  var yMin = vertices[0].y;
@@ -1639,6 +1758,35 @@ var Bounds = /** @class */ (function () {
1639
1758
  }
1640
1759
  return new Bounds(new Vertex_1.Vertex(xMin, yMin), new Vertex_1.Vertex(xMax, yMax));
1641
1760
  };
1761
+ /**
1762
+ * Compute the minimal bounding box for a given set of existing bounding boxes.
1763
+ *
1764
+ * An empty vertex array will return an empty bounding box located at (0,0).
1765
+ *
1766
+ * @static
1767
+ * @method computeFromBoundsSet
1768
+ * @memberof Bounds
1769
+ * @param {Array<IBounds>} boundingBoxes - The set of existing bounding boxes to get the containing bounding box for.
1770
+ * @return The minimal Bounds for the given bounds instances.
1771
+ **/
1772
+ Bounds.computeFromBoundsSet = function (boundingBoxes) {
1773
+ if (boundingBoxes.length == 0) {
1774
+ return new Bounds(new Vertex_1.Vertex(0, 0), new Vertex_1.Vertex(0, 0));
1775
+ }
1776
+ var xMin = boundingBoxes[0].min.x;
1777
+ var xMax = boundingBoxes[0].max.x;
1778
+ var yMin = boundingBoxes[0].min.y;
1779
+ var yMax = boundingBoxes[0].min.y;
1780
+ var bounds;
1781
+ for (var i in boundingBoxes) {
1782
+ bounds = boundingBoxes[i];
1783
+ xMin = Math.min(xMin, bounds.min.x);
1784
+ xMax = Math.max(xMax, bounds.max.x);
1785
+ yMin = Math.min(yMin, bounds.min.y);
1786
+ yMax = Math.max(yMax, bounds.min.y);
1787
+ }
1788
+ return new Bounds(new Vertex_1.Vertex(xMin, yMin), new Vertex_1.Vertex(xMax, yMax));
1789
+ };
1642
1790
  /**
1643
1791
  * Create a new `Bounds` instance just from `width` and `height`, located at (0,0) or the optionally given origin.
1644
1792
  *
@@ -1675,10 +1823,13 @@ exports.Bounds = Bounds;
1675
1823
  * @modified 2022-08-15 Added the `containsPoint` function.
1676
1824
  * @modified 2022-08-23 Added the `lineIntersection` function.
1677
1825
  * @modified 2022-08-23 Added the `closestPoint` function.
1678
- * @version 1.4.0
1826
+ * @modified 2025-04-09 Added the `Circle.move(amount: XYCoords)` method.
1827
+ * @modified 2025-04-16 Class `Circle` now implements interface `Intersectable`.
1828
+ * @version 1.5.0
1679
1829
  **/
1680
1830
  Object.defineProperty(exports, "__esModule", ({ value: true }));
1681
1831
  exports.Circle = void 0;
1832
+ var Bounds_1 = __webpack_require__(76);
1682
1833
  var Line_1 = __webpack_require__(939);
1683
1834
  var UIDGenerator_1 = __webpack_require__(938);
1684
1835
  var Vector_1 = __webpack_require__(30);
@@ -1712,6 +1863,19 @@ var Circle = /** @class */ (function () {
1712
1863
  this.center = center;
1713
1864
  this.radius = radius;
1714
1865
  }
1866
+ /**
1867
+ * Move the circle by the given amount.
1868
+ *
1869
+ * @method move
1870
+ * @param {XYCoords} amount - The amount to move.
1871
+ * @instance
1872
+ * @memberof Circle
1873
+ * @return {Circle} this for chaining
1874
+ **/
1875
+ Circle.prototype.move = function (amount) {
1876
+ this.center.add(amount);
1877
+ return this;
1878
+ };
1715
1879
  /**
1716
1880
  * Check if the given circle is fully contained inside this circle.
1717
1881
  *
@@ -1782,7 +1946,21 @@ var Circle = /** @class */ (function () {
1782
1946
  var pointA = Circle.circleUtils.vertAt(angle, this.radius);
1783
1947
  // Construct the perpendicular of the line in point a. Then move relative to center.
1784
1948
  return new Vector_1.Vector(pointA, new Vertex_1.Vertex(0, 0)).add(this.center).perp();
1949
+ // return (new Vector(this.center.clone(), pointA).add(pointA) as Vector).perp() as Vector;
1950
+ };
1951
+ //--- BEGIN --- Implement interface `Intersectable`
1952
+ /**
1953
+ * Get the bounding box (bounds) of this Circle.
1954
+ *
1955
+ * @method getBounds
1956
+ * @instance
1957
+ * @memberof Circle
1958
+ * @return {Bounds} The rectangular bounds of this Circle.
1959
+ **/
1960
+ Circle.prototype.getBounds = function () {
1961
+ return new Bounds_1.Bounds(this.center.clone().subXY(Math.abs(this.radius), Math.abs(this.radius)), this.center.clone().addXY(Math.abs(this.radius), Math.abs(this.radius)));
1785
1962
  };
1963
+ //--- END --- Implement interface `Intersectable`
1786
1964
  /**
1787
1965
  * Calculate the intersection points (if exists) with the given circle.
1788
1966
  *
@@ -1842,7 +2020,7 @@ var Circle = /** @class */ (function () {
1842
2020
  * @instance
1843
2021
  * @memberof Circle
1844
2022
  * @param {Vertex} a- The first of the two points defining the line.
1845
- * @param {Vertex} b - The second of the two points defining the line.
2023
+ * @param {XYCoords} b - The second of the two points defining the line.
1846
2024
  * @return {Line|null} The intersection points (as a line) or null if this circle does not intersect the line given.
1847
2025
  **/
1848
2026
  Circle.prototype.lineIntersection = function (a, b) {
@@ -1875,8 +2053,57 @@ var Circle = /** @class */ (function () {
1875
2053
  interA.y = (-det * diff.x + Math.abs(diff.y) * sqrt) / distSquared;
1876
2054
  interB.y = (-det * diff.x - Math.abs(diff.y) * sqrt) / distSquared;
1877
2055
  return new Line_1.Line(interA.add(this.center), interB.add(this.center));
1878
- // return new Line(interA, interB);
2056
+ };
2057
+ //--- BEGIN --- Implement interface `Intersectable`
2058
+ /**
2059
+ * Get all line intersections with this circle.
2060
+ *
2061
+ * This method returns all intersections (as vertices) with this shape. The returned array of vertices is in no specific order.
2062
+ *
2063
+ * @param {VertTuple} line - The line to find intersections with.
2064
+ * @param {boolean} inVectorBoundsOnly - If set to true only intersecion points on the passed vector are returned (located strictly between start and end vertex).
2065
+ * @returns {Array<Vertex>} - An array of all intersections with the circle outline.
2066
+ */
2067
+ Circle.prototype.lineIntersections = function (line, inVectorBoundsOnly) {
2068
+ if (inVectorBoundsOnly === void 0) { inVectorBoundsOnly = false; }
2069
+ // Find the intersections of all lines inside the edge bounds
2070
+ var intersectioLine = this.lineIntersection(line.a, line.b);
2071
+ if (!intersectioLine) {
2072
+ return [];
2073
+ }
2074
+ if (inVectorBoundsOnly) {
2075
+ // const maxDist = line.length();
2076
+ return [intersectioLine.a, intersectioLine.b].filter(function (vert) { return line.hasPoint(vert, true); });
2077
+ }
2078
+ else {
2079
+ return [intersectioLine.a, intersectioLine.b];
2080
+ }
1879
2081
  };
2082
+ /**
2083
+ * Get all line intersections of this polygon and their tangents along the shape.
2084
+ *
2085
+ * This method returns all intersection tangents (as vectors) with this shape. The returned array of vectors is in no specific order.
2086
+ *
2087
+ * @param line
2088
+ * @param lineIntersectionTangents
2089
+ * @returns
2090
+ */
2091
+ Circle.prototype.lineIntersectionTangents = function (line, inVectorBoundsOnly) {
2092
+ var _this = this;
2093
+ if (inVectorBoundsOnly === void 0) { inVectorBoundsOnly = false; }
2094
+ // Find the intersections of all lines plus their tangents inside the circle bounds
2095
+ var interSectionPoints = this.lineIntersections(line, inVectorBoundsOnly);
2096
+ return interSectionPoints.map(function (vert) {
2097
+ // Calculate angle
2098
+ var lineFromCenter = new Line_1.Line(_this.center, vert);
2099
+ var angle = lineFromCenter.angle();
2100
+ // console.log("angle", (angle / Math.PI) * 180.0);
2101
+ // const angle = Math.random() * Math.PI * 2; // TODO
2102
+ // Calculate tangent at angle
2103
+ return _this.tangentAt(angle);
2104
+ });
2105
+ };
2106
+ //--- END --- Implement interface `Intersectable`
1880
2107
  /**
1881
2108
  * Calculate the closest point on the outline of this circle to the given point.
1882
2109
  *
@@ -1937,12 +2164,20 @@ exports.Circle = Circle;
1937
2164
  * @modified 2024-03-08 Added the `containsAngle` method.
1938
2165
  * @modified 2024-03-09 Added the `circleSectorIntersection` method to find coherent sector intersections..
1939
2166
  * @modified 2024-03-09 Added the `angleAt` method to determine any angle at some ratio.
2167
+ * @modified 2025-04-02 Adding the `CircleSector.lineIntersections` and `CircleSector.lineIntersectionTangents` and implementing `Intersectable`.
2168
+ * @modified 2025-04-09 Adding the `CircleSector.move()` method.
2169
+ * @modified 2025-04-19 Tweaking the `CircleSector.containsAngle` method: all values (input angle, start- and end- angle) are wrapped into [0,2*PI) now.
2170
+ * @modified 2025-04-19 Class `CircleSector` implements interface `Bounded` now (method `getBounds` added).
1940
2171
  * @version 1.2.0
1941
2172
  **/
1942
2173
  Object.defineProperty(exports, "__esModule", ({ value: true }));
1943
2174
  exports.CircleSector = void 0;
2175
+ var Bounds_1 = __webpack_require__(76);
1944
2176
  var Circle_1 = __webpack_require__(118);
2177
+ var Line_1 = __webpack_require__(939);
1945
2178
  var UIDGenerator_1 = __webpack_require__(938);
2179
+ var Vertex_1 = __webpack_require__(787);
2180
+ var geomutils_1 = __webpack_require__(328);
1946
2181
  /**
1947
2182
  * @classdesc A simple circle sector: circle, start- and end-angle.
1948
2183
  *
@@ -1972,6 +2207,49 @@ var CircleSector = /** @class */ (function () {
1972
2207
  this.startAngle = startAngle;
1973
2208
  this.endAngle = endAngle;
1974
2209
  }
2210
+ //--- BEGIN --- Implement interface `IBounded`
2211
+ /**
2212
+ * Get the bounds of this ellipse.
2213
+ *
2214
+ * The bounds are approximated by the underlying segment buffer; the more segment there are,
2215
+ * the more accurate will be the returned bounds.
2216
+ *
2217
+ * @method getBounds
2218
+ * @instance
2219
+ * @memberof VEllipse
2220
+ * @return {Bounds} The bounds of this curve.
2221
+ **/
2222
+ CircleSector.prototype.getBounds = function () {
2223
+ var _self = this;
2224
+ var circleBounds = this.circle.getBounds();
2225
+ // Calculage angles from east, west, north and south box points and check if they are inside
2226
+ var candidates = [
2227
+ circleBounds.getNorthPoint(),
2228
+ circleBounds.getSouthPoint(),
2229
+ circleBounds.getWestPoint(),
2230
+ circleBounds.getEastPoint()
2231
+ ].filter(function (point) {
2232
+ // Check for each candidate points if they are contained in this sector. Drop if not.
2233
+ var angle = new Line_1.Line(_self.circle.center, point).angle();
2234
+ return _self.containsAngle(angle);
2235
+ });
2236
+ // Compute bounds and inlcude start end end point (they are definitely part of the bounds)
2237
+ return Bounds_1.Bounds.computeFromVertices(candidates.concat([this.getStartPoint(), this.getEndPoint()]));
2238
+ };
2239
+ //--- BEGIN --- Implement interface `IBounded`
2240
+ /**
2241
+ * Move the circle sector by the given amount.
2242
+ *
2243
+ * @method move
2244
+ * @param {XYCoords} amount - The amount to move.
2245
+ * @instance
2246
+ * @memberof CircleSector
2247
+ * @return {CircleSector} this for chaining
2248
+ **/
2249
+ CircleSector.prototype.move = function (amount) {
2250
+ this.circle.move(amount);
2251
+ return this;
2252
+ };
1975
2253
  /**
1976
2254
  * Checks wether the given angle (must be inside 0 and PI*2) is contained inside this sector.
1977
2255
  *
@@ -1982,12 +2260,22 @@ var CircleSector = /** @class */ (function () {
1982
2260
  * @return {boolean} True if (and only if) this sector contains the given angle.
1983
2261
  */
1984
2262
  CircleSector.prototype.containsAngle = function (angle) {
1985
- if (this.startAngle <= this.endAngle) {
1986
- return angle >= this.startAngle && angle < this.endAngle;
2263
+ var wrappedAngle = geomutils_1.geomutils.mapAngleTo2PI(angle);
2264
+ var wrappedStart = geomutils_1.geomutils.mapAngleTo2PI(this.startAngle);
2265
+ var wrappedEnd = geomutils_1.geomutils.mapAngleTo2PI(this.endAngle);
2266
+ // TODO: cleanup
2267
+ // if (this.startAngle <= this.endAngle) {
2268
+ // return angle >= this.startAngle && angle < this.endAngle;
2269
+ // } else {
2270
+ // // startAngle > endAngle
2271
+ // return angle >= this.startAngle || angle < this.endAngle;
2272
+ // }
2273
+ if (wrappedStart <= wrappedEnd) {
2274
+ return wrappedAngle >= wrappedStart && wrappedAngle < wrappedEnd;
1987
2275
  }
1988
2276
  else {
1989
2277
  // startAngle > endAngle
1990
- return angle >= this.startAngle || angle < this.endAngle;
2278
+ return wrappedAngle >= wrappedStart || wrappedAngle < wrappedEnd;
1991
2279
  }
1992
2280
  };
1993
2281
  /**
@@ -2081,6 +2369,54 @@ var CircleSector = /** @class */ (function () {
2081
2369
  }
2082
2370
  return resultSector;
2083
2371
  };
2372
+ //--- BEGIN --- Implement interface `Intersectable`
2373
+ /**
2374
+ * Get the line intersections as vectors with this ellipse.
2375
+ *
2376
+ * @method lineIntersections
2377
+ * @instance
2378
+ * @param {VertTuple<Vector> ray - The line/ray to intersect this ellipse with.
2379
+ * @param {boolean} inVectorBoundsOnly - (default=false) Set to true if only intersections within the vector bounds are of interest.
2380
+ * @returns
2381
+ */
2382
+ CircleSector.prototype.lineIntersections = function (ray, inVectorBoundsOnly) {
2383
+ var _this = this;
2384
+ if (inVectorBoundsOnly === void 0) { inVectorBoundsOnly = false; }
2385
+ // First get all line intersections from underlying ellipse.
2386
+ var ellipseIntersections = this.circle.lineIntersections(ray, inVectorBoundsOnly);
2387
+ // Drop all intersection points that are not contained in the circle sectors bounds.
2388
+ var tmpLine = new Line_1.Line(this.circle.center, new Vertex_1.Vertex());
2389
+ return ellipseIntersections.filter(function (intersectionPoint) {
2390
+ tmpLine.b.set(intersectionPoint);
2391
+ var lineAngle = tmpLine.angle();
2392
+ return _this.containsAngle(geomutils_1.geomutils.wrapMinMax(lineAngle, 0, Math.PI * 2));
2393
+ });
2394
+ };
2395
+ /**
2396
+ * Get all line intersections of this polygon and their tangents along the shape.
2397
+ *
2398
+ * This method returns all intersection tangents (as vectors) with this shape. The returned array of vectors is in no specific order.
2399
+ *
2400
+ * @param line
2401
+ * @param lineIntersectionTangents
2402
+ * @returns
2403
+ */
2404
+ CircleSector.prototype.lineIntersectionTangents = function (line, inVectorBoundsOnly) {
2405
+ var _this = this;
2406
+ if (inVectorBoundsOnly === void 0) { inVectorBoundsOnly = false; }
2407
+ // Find the intersections of all lines plus their tangents inside the circle bounds
2408
+ var interSectionPoints = this.lineIntersections(line, inVectorBoundsOnly);
2409
+ return interSectionPoints.map(function (vert) {
2410
+ // Calculate angle
2411
+ var lineFromCenter = new Line_1.Line(_this.circle.center, vert);
2412
+ var angle = lineFromCenter.angle();
2413
+ // console.log("angle", (angle / Math.PI) * 180.0);
2414
+ // const angle = Math.random() * Math.PI * 2; // TODO
2415
+ // Calculate tangent at angle
2416
+ return _this.circle.tangentAt(angle);
2417
+ });
2418
+ };
2419
+ //--- END --- Implement interface `Intersectable`
2084
2420
  /**
2085
2421
  * This function should invalidate any installed listeners and invalidate this object.
2086
2422
  * After calling this function the object might not hold valid data any more and
@@ -2186,7 +2522,17 @@ exports.CircleSector = CircleSector;
2186
2522
  * @modified 2022-10-17 The `CubicBezierCurve` class now implements the new `PathSegment` interface.
2187
2523
  * @modified 2023-09-30 Added the function `CubicbezierCurve.getSubCurve(number,number)` – similar to `getSubCurveAt(...)` but with absolute position parameters.
2188
2524
  * @modified 2023-10-07 Added the `trimEnd`, `trimEndAt`, `trimStart`, `trimStartAt` methods.
2189
- * @version 2.8.0
2525
+ * @modified 2025-04-09 Added the `CubicBezierCurve.move` method to match the convention – which just calls `translate`.
2526
+ * @modified 2025-04-09 Modified the `CubicBezierCurve.translate` method: chaning parameter `Vertex` to more generalized `XYCoords`.
2527
+ * @modified 2025-04-13 Changed visibility of `CubicBezierCurve.utils` from 'private' to 'public'.
2528
+ * @modified 2025-04-13 Added helper function `CubicBezierCurve.utils.bezierCoeffs`.
2529
+ * @modified 2025-04-13 Added helper functopn `CubicBezierCurve.utils.sgn(number)` for division safe sign calculation.
2530
+ * @modified 2025-03-13 Class `CubicBezierCurve` is now implementing interface `Intersectable`.
2531
+ * @modified 2025-04-18 Added evaluation method for cubic Bézier curves `CubicBezierCurve.utils.evaluateT`.
2532
+ * @modified 2025-04-18 Refactored method `CubicBezierCurve.getPointAt` to use `evaluateT`.
2533
+ * @modified 2025-04-18 Fixed the `CubicBezierCurve.getBounds` method: now returning the real bounding box. Before it was an approximated one.
2534
+ * @modified 2025-ß4-18 Added helper methods for bounding box calculation `CubucBezierCurve.util.cubicPolyMinMax` and `cubicPoly`.
2535
+ * @version 2.9.0
2190
2536
  *
2191
2537
  * @file CubicBezierCurve
2192
2538
  * @public
@@ -2281,7 +2627,7 @@ var CubicBezierCurve = /** @class */ (function () {
2281
2627
  * Translate the whole curve by the given {x,y} amount: moves all four points.
2282
2628
  *
2283
2629
  * @method translate
2284
- * @param {Vertex} amount - The amount to translate this curve by.
2630
+ * @param {XYCoords} amount - The amount to translate this curve by.
2285
2631
  * @instance
2286
2632
  * @memberof CubicBezierCurve
2287
2633
  * @return {CubicBezierCurve} this (for chaining).
@@ -2293,6 +2639,18 @@ var CubicBezierCurve = /** @class */ (function () {
2293
2639
  this.endPoint.add(amount);
2294
2640
  return this;
2295
2641
  };
2642
+ /**
2643
+ * Translate the whole curve by the given {x,y} amount: moves all four points.
2644
+ *
2645
+ * @method translate
2646
+ * @param {XYCoords} amount - The amount to translate this curve by.
2647
+ * @instance
2648
+ * @memberof CubicBezierCurve
2649
+ * @return {CubicBezierCurve} this (for chaining).
2650
+ **/
2651
+ CubicBezierCurve.prototype.move = function (amount) {
2652
+ return this.translate(amount);
2653
+ };
2296
2654
  /**
2297
2655
  * Reverse this curve, means swapping start- and end-point and swapping
2298
2656
  * start-control- and end-control-point.
@@ -2373,6 +2731,9 @@ var CubicBezierCurve = /** @class */ (function () {
2373
2731
  *
2374
2732
  * This function uses a recursive approach by cutting the curve into several linear segments.
2375
2733
  *
2734
+ * @method getClosestT
2735
+ * @instance
2736
+ * @memberof CubicBezierCurve
2376
2737
  * @param {Vertex} p - The point to find the closest position ('t' on the curve).
2377
2738
  * @return {number}
2378
2739
  **/
@@ -2422,27 +2783,35 @@ var CubicBezierCurve = /** @class */ (function () {
2422
2783
  tNext: tStart + tDiff * (Math.min(stepCount, minIndex + 1) / stepCount)
2423
2784
  };
2424
2785
  };
2786
+ //--- BEGIN --- Implement interface `IBounded`
2425
2787
  /**
2426
2788
  * Get the bounds of this bezier curve.
2427
2789
  *
2428
2790
  * The bounds are approximated by the underlying segment buffer; the more segment there are,
2429
2791
  * the more accurate will be the returned bounds.
2430
2792
  *
2431
- * @return {Bounds} The bounds of this curve.
2793
+ * @method getClosestT
2794
+ * @instance
2795
+ * @memberof CubicBezierCurve
2796
+ * @return {Bounds} The bounds of this ellipse.
2432
2797
  **/
2433
2798
  CubicBezierCurve.prototype.getBounds = function () {
2434
- var min = new Vertex_1.Vertex(Number.POSITIVE_INFINITY, Number.POSITIVE_INFINITY);
2435
- var max = new Vertex_1.Vertex(Number.NEGATIVE_INFINITY, Number.NEGATIVE_INFINITY);
2436
- var v;
2437
- for (var i = 0; i < this.segmentCache.length; i++) {
2438
- v = this.segmentCache[i];
2439
- min.x = Math.min(min.x, v.x);
2440
- min.y = Math.min(min.y, v.y);
2441
- max.x = Math.max(max.x, v.x);
2442
- max.y = Math.max(max.y, v.y);
2443
- }
2444
- return new Bounds_1.Bounds(min, max);
2445
- };
2799
+ // Thanks to Richard "RM" for the Bézier bounds calculatin
2800
+ // https://jsfiddle.net/SalixAlba/QQnvm/4/
2801
+ var xMinMax = CubicBezierCurve.utils.cubicPolyMinMax(this.startPoint.x, this.startControlPoint.x, this.endControlPoint.x, this.endPoint.x);
2802
+ var xl = xMinMax.min;
2803
+ var xh = xMinMax.max;
2804
+ var yMinMax = CubicBezierCurve.utils.cubicPolyMinMax(this.startPoint.y, this.startControlPoint.y, this.endControlPoint.y, this.endPoint.y);
2805
+ var yl = yMinMax.min;
2806
+ var yh = yMinMax.max;
2807
+ return Bounds_1.Bounds.computeFromVertices([
2808
+ { x: xl, y: yl },
2809
+ { x: xl, y: yh },
2810
+ { x: xh, y: yh },
2811
+ { x: xh, y: yl }
2812
+ ]);
2813
+ };
2814
+ //--- END --- Implement interface `IBounded`
2446
2815
  /**
2447
2816
  * Get the start point of the curve.<br>
2448
2817
  * <br>
@@ -2529,14 +2898,19 @@ var CubicBezierCurve = /** @class */ (function () {
2529
2898
  **/
2530
2899
  CubicBezierCurve.prototype.getPointAt = function (t) {
2531
2900
  // Perform some powerful math magic
2532
- var x = this.startPoint.x * Math.pow(1.0 - t, 3) +
2533
- this.startControlPoint.x * 3 * t * Math.pow(1.0 - t, 2) +
2534
- this.endControlPoint.x * 3 * Math.pow(t, 2) * (1.0 - t) +
2535
- this.endPoint.x * Math.pow(t, 3);
2536
- var y = this.startPoint.y * Math.pow(1.0 - t, 3) +
2537
- this.startControlPoint.y * 3 * t * Math.pow(1.0 - t, 2) +
2538
- this.endControlPoint.y * 3 * Math.pow(t, 2) * (1.0 - t) +
2539
- this.endPoint.y * Math.pow(t, 3);
2901
+ // TODO: cleanup
2902
+ // const x: number =
2903
+ // this.startPoint.x * Math.pow(1.0 - t, 3) +
2904
+ // this.startControlPoint.x * 3 * t * Math.pow(1.0 - t, 2) +
2905
+ // this.endControlPoint.x * 3 * Math.pow(t, 2) * (1.0 - t) +
2906
+ // this.endPoint.x * Math.pow(t, 3);
2907
+ // const y: number =
2908
+ // this.startPoint.y * Math.pow(1.0 - t, 3) +
2909
+ // this.startControlPoint.y * 3 * t * Math.pow(1.0 - t, 2) +
2910
+ // this.endControlPoint.y * 3 * Math.pow(t, 2) * (1.0 - t) +
2911
+ // this.endPoint.y * Math.pow(t, 3);
2912
+ var x = CubicBezierCurve.utils.evaluateT(this.startPoint.x, this.startControlPoint.x, this.endControlPoint.x, this.endPoint.x, t);
2913
+ var y = CubicBezierCurve.utils.evaluateT(this.startPoint.y, this.startControlPoint.y, this.endControlPoint.y, this.endPoint.y, t);
2540
2914
  return new Vertex_1.Vertex(x, y);
2541
2915
  };
2542
2916
  /**
@@ -2677,17 +3051,7 @@ var CubicBezierCurve = /** @class */ (function () {
2677
3051
  * @return {CubicBezierCurve} The sub curve as a new curve.
2678
3052
  **/
2679
3053
  CubicBezierCurve.prototype.getSubCurveAt = function (tStart, tEnd) {
2680
- // const startVec: Vector = new Vector(this.getPointAt(tStart), this.getTangentAt(tStart));
2681
- // const endVec: Vector = new Vector(this.getPointAt(tEnd), this.getTangentAt(tEnd).inv());
2682
- // // Tangents are relative. Make absolute.
2683
- // startVec.b.add(startVec.a);
2684
- // endVec.b.add(endVec.a);
2685
- // // This 'splits' the curve at the given point at t.
2686
- // startVec.scale(0.33333333 * (tEnd - tStart));
2687
- // endVec.scale(0.33333333 * (tEnd - tStart));
2688
- // // Draw the bezier curve
2689
- // // pb.draw.cubicBezier( startVec.a, endVec.a, startVec.b, endVec.b, '#8800ff', 2 );
2690
- // return new CubicBezierCurve(startVec.a, endVec.a, startVec.b, endVec.b);
3054
+ // This 'splits' the curve at the given point at t.
2691
3055
  var subCurbePoints = CubicBezierCurve.utils.getSubCurvePointsAt(this, tStart, tEnd);
2692
3056
  return new CubicBezierCurve(subCurbePoints[0], subCurbePoints[1], subCurbePoints[2], subCurbePoints[3]);
2693
3057
  };
@@ -2779,6 +3143,73 @@ var CubicBezierCurve = /** @class */ (function () {
2779
3143
  return this.endControlPoint;
2780
3144
  };
2781
3145
  //---END PathSegment-------------------------
3146
+ //--- BEGIN --- Implement interface `Intersectable`
3147
+ /**
3148
+ * Get all line intersections with this shape.
3149
+ *
3150
+ * This method returns all intersections (as vertices) with this shape. The returned array of vertices is in no specific order.
3151
+ *
3152
+ * @param {VertTuple} line - The line to find intersections with.
3153
+ * @param {boolean} inVectorBoundsOnly - If set to true only intersecion points on the passed vector are returned (located strictly between start and end vertex).
3154
+ * @returns {Array<Vertex>} - An array of all intersections with the shape outline.
3155
+ */
3156
+ CubicBezierCurve.prototype.lineIntersections = function (line, inVectorBoundsOnly) {
3157
+ var _this = this;
3158
+ if (inVectorBoundsOnly === void 0) { inVectorBoundsOnly = false; }
3159
+ var intersectionTs = this.lineIntersectionTs(line);
3160
+ var intersectionPoints = intersectionTs.map(function (t) {
3161
+ return _this.getPointAt(t);
3162
+ });
3163
+ if (inVectorBoundsOnly) {
3164
+ // const maxDist = line.length();
3165
+ return intersectionPoints.filter(function (vert) { return line.hasPoint(vert, true); });
3166
+ }
3167
+ else {
3168
+ return intersectionPoints;
3169
+ }
3170
+ };
3171
+ /**
3172
+ * Get all line intersections of this polygon and their tangents along the shape.
3173
+ *
3174
+ * This method returns all intersection tangents (as vectors) with this shape. The returned array of vectors is in no specific order.
3175
+ *
3176
+ * @param line
3177
+ * @param lineIntersectionTangents
3178
+ * @returns
3179
+ */
3180
+ CubicBezierCurve.prototype.lineIntersectionTangents = function (line, inVectorBoundsOnly) {
3181
+ var _this = this;
3182
+ if (inVectorBoundsOnly === void 0) { inVectorBoundsOnly = false; }
3183
+ var intersectionTs = this.lineIntersectionTs(line);
3184
+ var intersectionTangents = intersectionTs.map(function (t) {
3185
+ var startPoint = _this.getPointAt(t);
3186
+ var endPoint = _this.getTangentAt(t);
3187
+ return new Vector_1.Vector(startPoint, endPoint.add(startPoint));
3188
+ });
3189
+ if (inVectorBoundsOnly) {
3190
+ return intersectionTangents.filter(function (vec) { return line.hasPoint(vec.a, true); });
3191
+ }
3192
+ else {
3193
+ return intersectionTangents;
3194
+ }
3195
+ };
3196
+ //--- END --- Implement interface `Intersectable`
3197
+ CubicBezierCurve.prototype.lineIntersectionTs = function (line) {
3198
+ var A = line.b.y - line.a.y; // A=y2-y1
3199
+ var B = line.a.x - line.b.x; // B=x1-x2
3200
+ var C = line.a.x * (line.a.y - line.b.y) + line.a.y * (line.b.x - line.a.x); //C=x1*(y1-y2)+y1*(x2-x1)
3201
+ // var bx = bezierCoeffs(px[0], px[1], px[2], px[3]);
3202
+ // var by = bezierCoeffs(py[0], py[1], py[2], py[3]);
3203
+ var bx = CubicBezierCurve.utils.bezierCoeffs(this.startPoint.x, this.startControlPoint.x, this.endControlPoint.x, this.endPoint.x);
3204
+ var by = CubicBezierCurve.utils.bezierCoeffs(this.startPoint.y, this.startControlPoint.y, this.endControlPoint.y, this.endPoint.y);
3205
+ var poly = Array(4);
3206
+ poly[0] = A * bx[0] + B * by[0]; /*t^3*/
3207
+ poly[1] = A * bx[1] + B * by[1]; /*t^2*/
3208
+ poly[2] = A * bx[2] + B * by[2]; /*t*/
3209
+ poly[3] = A * bx[3] + B * by[3] + C; /*1*/
3210
+ var roots = CubicBezierCurve.utils.cubicRoots(poly);
3211
+ return roots.filter(function (root) { return root != -1; });
3212
+ };
2782
3213
  /**
2783
3214
  * Check if this and the specified curve are equal.<br>
2784
3215
  * <br>
@@ -2945,6 +3376,71 @@ var CubicBezierCurve = /** @class */ (function () {
2945
3376
  * Helper utils.
2946
3377
  */
2947
3378
  CubicBezierCurve.utils = {
3379
+ evaluateT: function (p0, p1, p2, p3, t) {
3380
+ return p0 * Math.pow(1.0 - t, 3) +
3381
+ p1 * 3 * t * Math.pow(1.0 - t, 2) +
3382
+ p2 * 3 * Math.pow(t, 2) * (1.0 - t) +
3383
+ p3 * Math.pow(t, 3);
3384
+ },
3385
+ cubicPolyMinMax: function (p0, p1, p2, p3) {
3386
+ // var polyX = CubicBezierCurve.utils.cubicPoly2(
3387
+ // p0, // P[0].X, // bezierCurve.startPoint.x,
3388
+ // p1, // P[1].X, // bezierCurve.startControlPoint.x,
3389
+ // p2, // P[2].X, // bezierCurve.endControlPoint.x,
3390
+ // p3 // P[3].X // bezierCurve.endPoint.x
3391
+ // );
3392
+ // var a = polyX.a;
3393
+ // var b = polyX.b;
3394
+ // var c = polyX.c;
3395
+ // var disc = polyX.b * polyX.b - 4 * polyX.a * polyX.c;
3396
+ var polyX = CubicBezierCurve.utils.cubicPoly(p0, // P[0].X, // bezierCurve.startPoint.x,
3397
+ p1, // P[1].X, // bezierCurve.startControlPoint.x,
3398
+ p2, // P[2].X, // bezierCurve.endControlPoint.x,
3399
+ p3 // P[3].X // bezierCurve.endPoint.x
3400
+ );
3401
+ var a = polyX[0]; // .a;
3402
+ var b = polyX[1]; // .b;
3403
+ var c = polyX[2]; // .c;
3404
+ //alert("a "+a+" "+b+" "+c);
3405
+ // var disc = b * b - 4 * a * c;
3406
+ var disc = polyX[1] * polyX[1] - 4 * polyX[0] * polyX[2];
3407
+ // var polyX = CubicBezierCurve.utils.bezierCoeffs(p3,p2,p1,p0);
3408
+ // var a = polyX[0]; //polyX.a;
3409
+ // var b = polyX[1]; // .b;
3410
+ // var c = polyX[2]; //.c;
3411
+ // var disc = polyX[1] * polyX[1] - 4 * polyX[0] * polyX[2];
3412
+ // var xl = Math.min(bCurve.endPoint.x, bCurve.startPoint.x); // P[0].X;
3413
+ // var xh = Math.max(bCurve.endPoint.x, bCurve.startPoint.x); // P[0].X;
3414
+ var xl = Math.min(p3, p0); // P[0].X;
3415
+ var xh = Math.max(p3, p0); // P[0].X;
3416
+ // if (P[3].X < xl) xl = P[3].X;
3417
+ // if (P[3].X > xh) xh = P[3].X;
3418
+ if (disc >= 0) {
3419
+ var t1 = (-b + Math.sqrt(disc)) / (2 * a);
3420
+ // alert("t1 " + t1);
3421
+ if (t1 > 0 && t1 < 1) {
3422
+ // var x1 = evalBez(PX, t1);
3423
+ // var x1 = bCurve.getPointAt(t1).x;
3424
+ var x1 = CubicBezierCurve.utils.evaluateT(p0, p1, p2, p3, t1); // bCurve.getPointAt(t1).x;
3425
+ if (x1 < xl)
3426
+ xl = x1;
3427
+ if (x1 > xh)
3428
+ xh = x1;
3429
+ }
3430
+ var t2 = (-b - Math.sqrt(disc)) / (2 * a);
3431
+ // alert("t2 " + t2);
3432
+ if (t2 > 0 && t2 < 1) {
3433
+ // var x2 = evalBez(PX, t2);
3434
+ // var x2 = bCurve.getPointAt(t2).x;
3435
+ var x2 = CubicBezierCurve.utils.evaluateT(p0, p1, p2, p3, t2); //
3436
+ if (x2 < xl)
3437
+ xl = x2;
3438
+ if (x2 > xh)
3439
+ xh = x2;
3440
+ }
3441
+ }
3442
+ return { min: xl, max: xh };
3443
+ },
2948
3444
  /**
2949
3445
  * Get the points of a sub curve at the given start end end offsets (values between 0.0 and 1.0).
2950
3446
  *
@@ -2968,6 +3464,94 @@ var CubicBezierCurve = /** @class */ (function () {
2968
3464
  startVec.scale(0.33333333 * (tEnd - tStart));
2969
3465
  endVec.scale(0.33333333 * (tEnd - tStart));
2970
3466
  return [startVec.a, endVec.a, startVec.b, endVec.b];
3467
+ },
3468
+ /**
3469
+ * Compute the cubic roots for the given cubic polynomial coefficients.
3470
+ *
3471
+ * Based on
3472
+ * http://mysite.verizon.net/res148h4j/javascript/script_exact_cubic.html#the%20source%20code
3473
+ * Inspired by
3474
+ * https://www.particleincell.com/2013/cubic-line-intersection/
3475
+ * Thanks to Stephan Schmitt and Particle-In-Cell!
3476
+ *
3477
+ * @param poly
3478
+ * @returns
3479
+ */
3480
+ cubicRoots: function (poly) {
3481
+ var a = poly[0];
3482
+ var b = poly[1];
3483
+ var c = poly[2];
3484
+ var d = poly[3];
3485
+ var A = b / a;
3486
+ var B = c / a;
3487
+ var C = d / a;
3488
+ var S, T, Im;
3489
+ var Q = (3 * B - Math.pow(A, 2)) / 9;
3490
+ var R = (9 * A * B - 27 * C - 2 * Math.pow(A, 3)) / 54;
3491
+ var D = Math.pow(Q, 3) + Math.pow(R, 2); // polynomial discriminant
3492
+ var ts = []; // Array();
3493
+ if (D >= 0) {
3494
+ // complex or duplicate roots
3495
+ S = CubicBezierCurve.utils.sgn(R + Math.sqrt(D)) * Math.pow(Math.abs(R + Math.sqrt(D)), 1 / 3);
3496
+ T = CubicBezierCurve.utils.sgn(R - Math.sqrt(D)) * Math.pow(Math.abs(R - Math.sqrt(D)), 1 / 3);
3497
+ ts[0] = -A / 3 + (S + T); // real root
3498
+ ts[1] = -A / 3 - (S + T) / 2; // real part of complex root
3499
+ ts[2] = -A / 3 - (S + T) / 2; // real part of complex root
3500
+ Im = Math.abs((Math.sqrt(3) * (S - T)) / 2); // complex part of root pair
3501
+ // Mark complex roots to be discarded
3502
+ if (Im != 0) {
3503
+ ts[1] = -1;
3504
+ ts[2] = -1;
3505
+ }
3506
+ } // distinct real roots
3507
+ else {
3508
+ var th = Math.acos(R / Math.sqrt(-Math.pow(Q, 3)));
3509
+ ts[0] = 2 * Math.sqrt(-Q) * Math.cos(th / 3) - A / 3;
3510
+ ts[1] = 2 * Math.sqrt(-Q) * Math.cos((th + 2 * Math.PI) / 3) - A / 3;
3511
+ ts[2] = 2 * Math.sqrt(-Q) * Math.cos((th + 4 * Math.PI) / 3) - A / 3;
3512
+ Im = 0.0;
3513
+ }
3514
+ // Discard all t's out of spec and sort the rest
3515
+ return ts.filter(function (t) { return t >= 0 && t <= 1.0; }).sort();
3516
+ },
3517
+ /**
3518
+ * Compute the Bézier coefficients from the given Bézier point coordinates.
3519
+ *
3520
+ * @param {number} p0 - The start point coordinate.
3521
+ * @param {number} p1 - The start control point coordinate.
3522
+ * @param {number} p2 - The end control point coordinate.
3523
+ * @param {number} p3 - The end point coordinate.
3524
+ * @returns {[number,number,number,number]}
3525
+ */
3526
+ bezierCoeffs: function (p0, p1, p2, p3) {
3527
+ var coeffs = [NaN, NaN, NaN, NaN]; //Array(4);
3528
+ coeffs[0] = -p0 + 3 * p1 + -3 * p2 + p3;
3529
+ coeffs[1] = 3 * p0 - 6 * p1 + 3 * p2;
3530
+ coeffs[2] = -3 * p0 + 3 * p1;
3531
+ coeffs[3] = p0;
3532
+ return coeffs;
3533
+ },
3534
+ /**
3535
+ * Calculate the cubic polynomial coefficients used to find the bounding box.
3536
+ *
3537
+ * @param {number} p0 - The start point coordinate.
3538
+ * @param {number} p1 - The start control point coordinate.
3539
+ * @param {number} p2 - The end control point coordinate.
3540
+ * @param {number} p3 - The end point coordinate.
3541
+ * @returns {[number,number,number]}
3542
+ */
3543
+ cubicPoly: function (p0, p1, p2, p3) {
3544
+ return [
3545
+ 3 * p3 - 9 * p2 + 9 * p1 - 3 * p0,
3546
+ 6 * p0 - 12 * p1 + 6 * p2,
3547
+ 3 * p1 - 3 * p0
3548
+ ];
3549
+ },
3550
+ /**
3551
+ * sign of number, but is division safe: no zero returned :)
3552
+ */
3553
+ sgn: function (x) {
3554
+ return x < 0.0 ? -1 : 1;
2971
3555
  }
2972
3556
  };
2973
3557
  return CubicBezierCurve;
@@ -3536,7 +4120,9 @@ exports.KeyHandler = KeyHandler;
3536
4120
  * @modified 2022-10-09 Changed the actual return value of the `intersection` function to null (was undefined before).
3537
4121
  * @modified 2022-10-17 Adding these methods from the `PathSegment` interface: getStartPoint, getEndPoint, revert.
3538
4122
  * @modified 2023-09-25 Changed param type of `intersection()` from Line to VertTuple.
3539
- * @version 2.3.0
4123
+ * @modified 2025-04-15 Class `Line` now implements interface `Intersectable`.
4124
+ * @modified 2025-04-16 Class `Line` now implements interface `IBounded`.
4125
+ * @version 2.4.0
3540
4126
  *
3541
4127
  * @file Line
3542
4128
  * @public
@@ -3558,6 +4144,8 @@ var __extends = (this && this.__extends) || (function () {
3558
4144
  })();
3559
4145
  Object.defineProperty(exports, "__esModule", ({ value: true }));
3560
4146
  exports.Line = void 0;
4147
+ var Bounds_1 = __webpack_require__(76);
4148
+ var Vector_1 = __webpack_require__(30);
3561
4149
  var VertTuple_1 = __webpack_require__(590);
3562
4150
  var Vertex_1 = __webpack_require__(787);
3563
4151
  /**
@@ -3616,6 +4204,19 @@ var Line = /** @class */ (function (_super) {
3616
4204
  // if we cast these lines infinitely in both directions, they intersect here:
3617
4205
  return new Vertex_1.Vertex(x, y);
3618
4206
  };
4207
+ //--- BEGIN --- Implement interface `IBounded`
4208
+ /**
4209
+ * Get the bounding box (bounds) of this Line.
4210
+ *
4211
+ * @method getBounds
4212
+ * @instance
4213
+ * @memberof Line
4214
+ * @return {Bounds} The rectangular bounds of this Line.
4215
+ **/
4216
+ Line.prototype.getBounds = function () {
4217
+ return Bounds_1.Bounds.computeFromVertices([this.a, this.b]);
4218
+ };
4219
+ //--- END --- Implement interface `IBounded`
3619
4220
  //--- Implement PathSegment ---
3620
4221
  /**
3621
4222
  * Get the start point of this path segment.
@@ -3670,6 +4271,52 @@ var Line = /** @class */ (function (_super) {
3670
4271
  this.b = tmp;
3671
4272
  return this;
3672
4273
  };
4274
+ //--- END Implement PathSegment ---
4275
+ //--- BEGIN --- Implement interface `Intersectable`
4276
+ /**
4277
+ * Get all line intersections with this polygon.
4278
+ *
4279
+ * This method returns all intersections (as vertices) with this shape. The returned array of vertices is in no specific order.
4280
+ *
4281
+ * See demo `47-closest-vector-projection-on-polygon` for how it works.
4282
+ *
4283
+ * @param {VertTuple} line - The line to find intersections with.
4284
+ * @param {boolean} inVectorBoundsOnly - If set to true only intersecion points on the passed vector are returned (located strictly between start and end vertex).
4285
+ * @returns {Array<Vertex>} - An array of all intersections within the polygon bounds.
4286
+ */
4287
+ Line.prototype.lineIntersections = function (line, inVectorBoundsOnly) {
4288
+ if (inVectorBoundsOnly === void 0) { inVectorBoundsOnly = false; }
4289
+ // Find the intersections of all lines inside the edge bounds
4290
+ var intersection = this.intersection(line);
4291
+ if (!intersection) {
4292
+ return []; // Both lines parallel
4293
+ }
4294
+ if (this.hasPoint(intersection, true) && (!inVectorBoundsOnly || line.hasPoint(intersection, inVectorBoundsOnly))) {
4295
+ return [intersection];
4296
+ }
4297
+ else {
4298
+ return [];
4299
+ }
4300
+ };
4301
+ /**
4302
+ * Get all line intersections of this polygon and their tangents along the shape.
4303
+ *
4304
+ * This method returns all intersection tangents (as vectors) with this shape. The returned array of vectors is in no specific order.
4305
+ *
4306
+ * @param line
4307
+ * @param inVectorBoundsOnly
4308
+ * @returns
4309
+ */
4310
+ Line.prototype.lineIntersectionTangents = function (line, inVectorBoundsOnly) {
4311
+ if (inVectorBoundsOnly === void 0) { inVectorBoundsOnly = false; }
4312
+ // Find the intersection tangents of all lines inside the edge bounds
4313
+ var intersections = this.lineIntersections(line, inVectorBoundsOnly);
4314
+ if (intersections.length === 0) {
4315
+ return [];
4316
+ }
4317
+ var intrsctn = intersections[0];
4318
+ return [new Vector_1.Vector(this.a.clone(), this.b.clone()).moveTo(intrsctn)];
4319
+ };
3673
4320
  return Line;
3674
4321
  }(VertTuple_1.VertTuple));
3675
4322
  exports.Line = Line;
@@ -5312,18 +5959,17 @@ var PlotBoilerplate = /** @class */ (function () {
5312
5959
  }
5313
5960
  else if (d instanceof Triangle_1.Triangle) {
5314
5961
  draw.polyline([d.a, d.b, d.c], false, this.drawConfig.triangle.color, this.drawConfig.triangle.lineWidth);
5315
- if (!this.drawConfig.drawHandlePoints)
5962
+ if (!this.drawConfig.drawHandlePoints) {
5316
5963
  d.a.attr.renderTime = d.b.attr.renderTime = d.c.attr.renderTime = renderTime;
5964
+ }
5317
5965
  }
5318
5966
  else if (d instanceof VEllipse_1.VEllipse) {
5319
5967
  if (this.drawConfig.drawHandleLines) {
5320
5968
  draw.setCurrentId("".concat(d.uid, "_e0"));
5321
5969
  draw.setCurrentClassName("".concat(d.className, "-v-line"));
5322
- // draw.line( d.center.clone().add(0,d.axis.y-d.center.y), d.axis, '#c8c8c8' );
5323
5970
  draw.handleLine(d.center.clone().add(0, d.signedRadiusV()).rotate(d.rotation, d.center), d.axis); // , "#c8c8c8");
5324
5971
  draw.setCurrentId("".concat(d.uid, "_e1"));
5325
5972
  draw.setCurrentClassName("".concat(d.className, "-h-line"));
5326
- // draw.line( d.center.clone().add(d.axis.x-d.center.x,0), d.axis, '#c8c8c8' );
5327
5973
  draw.handleLine(d.center.clone().add(d.signedRadiusH(), 0).rotate(d.rotation, d.center), d.axis); // , "#c8c8c8");
5328
5974
  }
5329
5975
  draw.setCurrentId(d.uid);
@@ -5339,12 +5985,6 @@ var PlotBoilerplate = /** @class */ (function () {
5339
5985
  else if (d instanceof VEllipseSector_1.VEllipseSector) {
5340
5986
  draw.setCurrentId(d.uid);
5341
5987
  draw.setCurrentClassName("".concat(d.className));
5342
- /* draw.ellipse( d.center,
5343
- // Math.abs(d.axis.x-d.center.x), Math.abs(d.axis.y-d.center.y),
5344
- d.radiusH(), d.radiusV(),
5345
- this.drawConfig.ellipse.color,
5346
- this.drawConfig.ellipse.lineWidth,
5347
- d.rotation ); */
5348
5988
  var data = VEllipseSector_1.VEllipseSector.ellipseSectorUtils.describeSVGArc(d.ellipse.center.x, d.ellipse.center.y, d.ellipse.radiusH(), d.ellipse.radiusV(), d.startAngle, d.endAngle, d.ellipse.rotation, { moveToStart: true });
5349
5989
  draw.path(data, this.drawConfig.ellipseSector.color, this.drawConfig.ellipseSector.lineWidth);
5350
5990
  }
@@ -6534,7 +7174,11 @@ exports["default"] = PlotBoilerplate;
6534
7174
  * @modified 2024-10-30 Added the `getEdges` method.
6535
7175
  * @modified 2024-12-02 Added the `elimitateColinearEdges` method.
6536
7176
  * @modified 2025-02-12 Added the `containsVerts` method to test multiple vertices for containment.
6537
- * @version 1.14.0
7177
+ * @modified 2025-03-28 Added the `Polygon.utils.locateLineIntersecion` static helper method.
7178
+ * @modified 2025-03-28 Added the `Polygon.lineIntersectionTangents` method.
7179
+ * @modified 2025-04-09 Added the `Polygon.getCentroid` method.
7180
+ * @modified 2025-05-16 Class `Polygon` now implements `IBounded`.
7181
+ * @version 1.15.0
6538
7182
  *
6539
7183
  * @file Polygon
6540
7184
  * @public
@@ -6546,6 +7190,7 @@ var Bounds_1 = __webpack_require__(76);
6546
7190
  var Line_1 = __webpack_require__(939);
6547
7191
  var Triangle_1 = __webpack_require__(737);
6548
7192
  var UIDGenerator_1 = __webpack_require__(938);
7193
+ var Vector_1 = __webpack_require__(30);
6549
7194
  var Vertex_1 = __webpack_require__(787);
6550
7195
  var geomutils_1 = __webpack_require__(328);
6551
7196
  /**
@@ -6916,9 +7561,44 @@ var Polygon = /** @class */ (function () {
6916
7561
  center.y /= this.vertices.length;
6917
7562
  return center;
6918
7563
  };
7564
+ /**
7565
+ * Get centroid.
7566
+ * Centroids define the barycenter of any non self-intersecting convex polygon.
7567
+ *
7568
+ * If the polygon is self intersecting or non konvex then the barycenter is not well defined.
7569
+ *
7570
+ * https://mathworld.wolfram.com/PolygonCentroid.html
7571
+ *
7572
+ * @method getCentroid
7573
+ * @instance
7574
+ * @memberof Polygon
7575
+ * @returns {Vertex|null}
7576
+ */
7577
+ Polygon.prototype.getCentroid = function () {
7578
+ if (this.vertices.length === 0) {
7579
+ return null;
7580
+ }
7581
+ var center = new Vertex_1.Vertex(0.0, 0.0);
7582
+ var n = this.vertices.length;
7583
+ for (var i = 0; i < n; i++) {
7584
+ // center.add(this.vertices[i]);
7585
+ var cur = this.vertices[i];
7586
+ var next = this.vertices[(i + 1) % n];
7587
+ var factor = cur.x * next.y - next.x * cur.y;
7588
+ center.x += (cur.x + next.x) * factor;
7589
+ center.y += (cur.y + next.y) * factor;
7590
+ }
7591
+ var area = this.area();
7592
+ center.x *= 1 / (6 * area);
7593
+ center.y *= 1 / (6 * area);
7594
+ return center;
7595
+ };
7596
+ //--- BEGIN --- Implement interface `Intersectable`
6919
7597
  /**
6920
7598
  * Get all line intersections with this polygon.
6921
7599
  *
7600
+ * This method returns all intersections (as vertices) with this shape. The returned array of vertices is in no specific order.
7601
+ *
6922
7602
  * See demo `47-closest-vector-projection-on-polygon` for how it works.
6923
7603
  *
6924
7604
  * @param {VertTuple} line - The line to find intersections with.
@@ -6928,21 +7608,29 @@ var Polygon = /** @class */ (function () {
6928
7608
  Polygon.prototype.lineIntersections = function (line, inVectorBoundsOnly) {
6929
7609
  if (inVectorBoundsOnly === void 0) { inVectorBoundsOnly = false; }
6930
7610
  // Find the intersections of all lines inside the edge bounds
6931
- var intersectionPoints = [];
6932
- for (var i = 0; i < this.vertices.length; i++) {
6933
- var polyLine = new Line_1.Line(this.vertices[i], this.vertices[(i + 1) % this.vertices.length]);
6934
- var intersection = polyLine.intersection(line);
6935
- // true => only inside bounds
6936
- // ignore last edge if open
6937
- if ((!this.isOpen || i + 1 !== this.vertices.length) &&
6938
- intersection !== null &&
6939
- polyLine.hasPoint(intersection, true) &&
6940
- (!inVectorBoundsOnly || line.hasPoint(intersection, inVectorBoundsOnly))) {
6941
- intersectionPoints.push(intersection);
6942
- }
6943
- }
6944
- return intersectionPoints;
7611
+ return Polygon.utils
7612
+ .locateLineIntersecion(line, this.vertices, this.isOpen, inVectorBoundsOnly)
7613
+ .map(function (intersectionTuple) { return intersectionTuple.intersectionPoint; });
7614
+ };
7615
+ /**
7616
+ * Get all line intersections of this polygon and their tangents along the shape.
7617
+ *
7618
+ * This method returns all intersection tangents (as vectors) with this shape. The returned array of vectors is in no specific order.
7619
+ *
7620
+ * @param line
7621
+ * @param inVectorBoundsOnly
7622
+ * @returns
7623
+ */
7624
+ Polygon.prototype.lineIntersectionTangents = function (line, inVectorBoundsOnly) {
7625
+ var _this = this;
7626
+ if (inVectorBoundsOnly === void 0) { inVectorBoundsOnly = false; }
7627
+ // Find the intersection tangents of all lines inside the edge bounds
7628
+ return Polygon.utils.locateLineIntersecion(line, this.vertices, this.isOpen, inVectorBoundsOnly).map(function (intersectionTuple) {
7629
+ var polyLine = _this.getEdgeAt(intersectionTuple.edgeIndex);
7630
+ return new Vector_1.Vector(polyLine.a.clone(), polyLine.b.clone()).moveTo(intersectionTuple.intersectionPoint);
7631
+ });
6945
7632
  };
7633
+ //--- END --- Implement interface `Intersectable`
6946
7634
  /**
6947
7635
  * Get the closest line-polygon-intersection point (closest the line point A).
6948
7636
  *
@@ -7044,6 +7732,7 @@ var Polygon = /** @class */ (function () {
7044
7732
  }
7045
7733
  return result;
7046
7734
  };
7735
+ //--- BEGIN --- Implement interface `IBounded`
7047
7736
  /**
7048
7737
  * Get the bounding box (bounds) of this polygon.
7049
7738
  *
@@ -7055,6 +7744,7 @@ var Polygon = /** @class */ (function () {
7055
7744
  Polygon.prototype.getBounds = function () {
7056
7745
  return Bounds_1.Bounds.computeFromVertices(this.vertices);
7057
7746
  };
7747
+ //--- END --- Implement interface `IBounded`
7058
7748
  /**
7059
7749
  * Create a deep copy of this polygon.
7060
7750
  *
@@ -7109,7 +7799,6 @@ var Polygon = /** @class */ (function () {
7109
7799
  // -> delete all vertices in between
7110
7800
  if (j - i > 2) {
7111
7801
  // Means: there have been 'colinear vertices' in between
7112
- // console.log("Splice", "i", i, "j", j, i + 1, j - i - 1);
7113
7802
  verts.splice(i + 1, j - i - 2);
7114
7803
  }
7115
7804
  i++;
@@ -7305,6 +7994,32 @@ var Polygon = /** @class */ (function () {
7305
7994
  sum += (vertices[j].x - vertices[i].x) * (vertices[i].y + vertices[j].y);
7306
7995
  }
7307
7996
  return sum;
7997
+ },
7998
+ /**
7999
+ * Find intersections of a line with a polygon (vertices).
8000
+ *
8001
+ * @param {VertTuple<any>} line - The line to find intersections with.
8002
+ * @param {Array<Vertex>} vertices - The polygon's vertices.
8003
+ * @param {boolean} isOpen - True if the polygon is open, false otherwise.
8004
+ * @param {boolean} inVectorBoundsOnly - If only intersections in strict vector bounds should be returned.
8005
+ * @returns
8006
+ */
8007
+ locateLineIntersecion: function (line, vertices, isOpen, inVectorBoundsOnly) {
8008
+ // Find the intersections of all lines inside the edge bounds
8009
+ var intersectionPoints = [];
8010
+ var n = isOpen ? vertices.length - 1 : vertices.length;
8011
+ for (var i = 0; i < n; i++) {
8012
+ var polyLine = new Line_1.Line(vertices[i % n], vertices[(i + 1) % n]);
8013
+ var intersection = polyLine.intersection(line);
8014
+ // true => only inside bounds
8015
+ // ignore last edge if open
8016
+ if (intersection !== null &&
8017
+ polyLine.hasPoint(intersection, true) &&
8018
+ (!inVectorBoundsOnly || line.hasPoint(intersection, inVectorBoundsOnly))) {
8019
+ intersectionPoints.push({ edgeIndex: i, intersectionPoint: intersection });
8020
+ }
8021
+ }
8022
+ return intersectionPoints;
7308
8023
  }
7309
8024
  };
7310
8025
  return Polygon;
@@ -7343,7 +8058,11 @@ exports.Polygon = Polygon;
7343
8058
  * @modified 2022-02-02 Cleared the `Triangle.toSVGString` function (deprecated). Use `drawutilssvg` instead.
7344
8059
  * @modified 2024-11-22 Added static utility function Triangle.utils.determinant; adapted method `determinant`.
7345
8060
  * @modified 2024-11-22 Changing visibility of `Triangle.utils` from `private` to `public`.
7346
- * @version 2.8.0
8061
+ * @modified 2025-14-16 Class `Triangle` now implements interface `Intersectable`.
8062
+ * @modified 2025-14-16 Class `Triangle` now implements interface `IBounded`.
8063
+ * @modified 2025-14-16 Class `Triangle` now implements interface `Intersectable`.
8064
+ * @modified 2025-14-16 Added method `Triangle.move`.
8065
+ * @version 2.10.0
7347
8066
  *
7348
8067
  * @file Triangle
7349
8068
  * @fileoverview A simple triangle class: three vertices.
@@ -7356,6 +8075,7 @@ var Circle_1 = __webpack_require__(118);
7356
8075
  var Line_1 = __webpack_require__(939);
7357
8076
  var Polygon_1 = __webpack_require__(687);
7358
8077
  var UIDGenerator_1 = __webpack_require__(938);
8078
+ var Vector_1 = __webpack_require__(30);
7359
8079
  var Vertex_1 = __webpack_require__(787);
7360
8080
  var geomutils_1 = __webpack_require__(328);
7361
8081
  /**
@@ -7457,6 +8177,35 @@ var Triangle = /** @class */ (function () {
7457
8177
  this.c.scale(factor, centroid);
7458
8178
  return this;
7459
8179
  };
8180
+ //--- BEGIN --- Implement interface `IBounded`
8181
+ /**
8182
+ * Get the bounding box (bounds) of this Triangle.
8183
+ *
8184
+ * @method getBounds
8185
+ * @instance
8186
+ * @memberof Triangle
8187
+ * @return {Bounds} The rectangular bounds of this Triangle.
8188
+ **/
8189
+ Triangle.prototype.getBounds = function () {
8190
+ // return Bounds.computeFromVertices([this.a, this.b, this.c]);
8191
+ return this.bounds();
8192
+ };
8193
+ //--- END --- Implement interface `IBounded`
8194
+ /**
8195
+ * Move the Triangle's vertices by the given amount.
8196
+ *
8197
+ * @method move
8198
+ * @param {XYCoords} amount - The amount to move.
8199
+ * @instance
8200
+ * @memberof Triangle
8201
+ * @return {Triangle} this for chaining
8202
+ **/
8203
+ Triangle.prototype.move = function (amount) {
8204
+ this.a.add(amount);
8205
+ this.b.add(amount);
8206
+ this.c.add(amount);
8207
+ return this;
8208
+ };
7460
8209
  /**
7461
8210
  * Get the circumcircle of this triangle.
7462
8211
  *
@@ -7582,6 +8331,51 @@ var Triangle = /** @class */ (function () {
7582
8331
  Triangle.prototype.bounds = function () {
7583
8332
  return new Bounds_1.Bounds(new Vertex_1.Vertex(Triangle.utils.min3(this.a.x, this.b.x, this.c.x), Triangle.utils.min3(this.a.y, this.b.y, this.c.y)), new Vertex_1.Vertex(Triangle.utils.max3(this.a.x, this.b.x, this.c.x), Triangle.utils.max3(this.a.y, this.b.y, this.c.y)));
7584
8333
  };
8334
+ //--- BEGIN --- Implement interface `Intersectable`
8335
+ /**
8336
+ * Get all line intersections with this polygon.
8337
+ *
8338
+ * This method returns all intersections (as vertices) with this shape. The returned array of vertices is in no specific order.
8339
+ *
8340
+ * See demo `47-closest-vector-projection-on-polygon` for how it works.
8341
+ *
8342
+ * @param {VertTuple} line - The line to find intersections with.
8343
+ * @param {boolean} inVectorBoundsOnly - If set to true only intersecion points on the passed vector are returned (located strictly between start and end vertex).
8344
+ * @returns {Array<Vertex>} - An array of all intersections within the polygon bounds.
8345
+ */
8346
+ Triangle.prototype.lineIntersections = function (line, inVectorBoundsOnly) {
8347
+ if (inVectorBoundsOnly === void 0) { inVectorBoundsOnly = false; }
8348
+ // Find the intersections of all lines inside the edge bounds
8349
+ return Polygon_1.Polygon.utils
8350
+ .locateLineIntersecion(line, [this.a, this.b, this.c], false, inVectorBoundsOnly)
8351
+ .map(function (intersectionTuple) { return intersectionTuple.intersectionPoint; });
8352
+ };
8353
+ /**
8354
+ * Get all line intersections of this polygon and their tangents along the shape.
8355
+ *
8356
+ * This method returns all intersection tangents (as vectors) with this shape. The returned array of vectors is in no specific order.
8357
+ *
8358
+ * @param line
8359
+ * @param inVectorBoundsOnly
8360
+ * @returns
8361
+ */
8362
+ Triangle.prototype.lineIntersectionTangents = function (line, inVectorBoundsOnly) {
8363
+ var _this = this;
8364
+ if (inVectorBoundsOnly === void 0) { inVectorBoundsOnly = false; }
8365
+ // Find the intersection tangents of all lines inside the edge bounds
8366
+ return Polygon_1.Polygon.utils
8367
+ .locateLineIntersecion(line, [this.a, this.b, this.c], false, inVectorBoundsOnly)
8368
+ .map(function (intersectionTuple) {
8369
+ // const polyLine = this.getEdgeAt(intersectionTuple.edgeIndex);
8370
+ var polyLine = _this.getEdgeAt(intersectionTuple.edgeIndex);
8371
+ return new Vector_1.Vector(polyLine.a.clone(), polyLine.b.clone()).moveTo(intersectionTuple.intersectionPoint);
8372
+ });
8373
+ };
8374
+ //--- END --- Implement interface `Intersectable`
8375
+ Triangle.prototype.getEdgeAt = function (edgeIndex) {
8376
+ var modIndex = edgeIndex % 3;
8377
+ return modIndex === 0 ? new Line_1.Line(this.a, this.b) : modIndex === 1 ? new Line_1.Line(this.b, this.c) : new Line_1.Line(this.c, this.a);
8378
+ };
7585
8379
  /**
7586
8380
  * Convert this triangle to a polygon instance.
7587
8381
  *
@@ -7786,7 +8580,11 @@ exports.UIDGenerator = UIDGenerator;
7786
8580
  * @modified 2021-03-19 Added the `VEllipse.rotate` function.
7787
8581
  * @modified 2022-02-02 Added the `destroy` method.
7788
8582
  * @modified 2022-02-02 Cleared the `VEllipse.toSVGString` function (deprecated). Use `drawutilssvg` instead.
7789
- * @version 1.3.0
8583
+ * @modified 2025-03-31 ATTENTION: modified the winding direction of the `tangentAt` method to match with the Circle method. This is a breaking change!
8584
+ * @modified 2025-03-31 Adding the `VEllipse.move(amount: XYCoords)` method.
8585
+ * @modified 2025-04-19 Adding the `VEllipse.getBounds()` method.
8586
+ * @modified 2025-04-24 Adding the `VEllipse.getExtremePoints()` method for calculating minima and maxima.
8587
+ * @version 1.4.0
7790
8588
  *
7791
8589
  * @file VEllipse
7792
8590
  * @fileoverview Ellipses with a center and an x- and a y-axis (stored as a vertex).
@@ -7798,6 +8596,8 @@ var Vector_1 = __webpack_require__(30);
7798
8596
  var Vertex_1 = __webpack_require__(787);
7799
8597
  var UIDGenerator_1 = __webpack_require__(938);
7800
8598
  var CubicBezierCurve_1 = __webpack_require__(973);
8599
+ var Circle_1 = __webpack_require__(118);
8600
+ var Bounds_1 = __webpack_require__(76);
7801
8601
  /**
7802
8602
  * @classdesc An ellipse class based on two vertices [centerX,centerY] and [radiusX,radiusY].
7803
8603
  *
@@ -7879,11 +8679,96 @@ var VEllipse = /** @class */ (function () {
7879
8679
  * @return {number} The signed vertical radius of this ellipse.
7880
8680
  */
7881
8681
  VEllipse.prototype.signedRadiusV = function () {
7882
- // return Math.abs(this.axis.y - this.center.y);
7883
8682
  // Rotate axis back to origin before calculating radius
7884
- // return Math.abs(new Vertex(this.axis).rotate(-this.rotation,this.center).y - this.center.y);
7885
8683
  return new Vertex_1.Vertex(this.axis).rotate(-this.rotation, this.center).y - this.center.y;
7886
8684
  };
8685
+ /**
8686
+ * Get the the minima and maxima (points) of this (rotated) ellipse.
8687
+ *
8688
+ * @method getExtremePoints
8689
+ * @instance
8690
+ * @memberof VEllipse
8691
+ * @return {[Vertex, Vertex, Vertex, Vertex]} Get the the minima and maxima (points) of this (rotated) ellipse.
8692
+ */
8693
+ VEllipse.prototype.getExtremePoints = function () {
8694
+ var a = this.radiusH();
8695
+ var b = this.radiusV();
8696
+ // Calculate t_x values
8697
+ var t_x1 = Math.atan2(-b * Math.sin(this.rotation), a * Math.cos(this.rotation));
8698
+ var t_x2 = t_x1 + Math.PI;
8699
+ // Calculate x values at t_x
8700
+ var x_x1 = this.center.x + a * Math.cos(t_x1) * Math.cos(this.rotation) - b * Math.sin(t_x1) * Math.sin(this.rotation);
8701
+ var y_x1 = this.center.y + a * Math.cos(t_x1) * Math.sin(this.rotation) + b * Math.sin(t_x1) * Math.cos(this.rotation);
8702
+ var x_x2 = this.center.x + a * Math.cos(t_x2) * Math.cos(this.rotation) - b * Math.sin(t_x2) * Math.sin(this.rotation);
8703
+ var y_x2 = this.center.y + a * Math.cos(t_x2) * Math.sin(this.rotation) + b * Math.sin(t_x2) * Math.cos(this.rotation);
8704
+ var x_max, x_min;
8705
+ if (x_x1 > x_x2) {
8706
+ x_max = new Vertex_1.Vertex(x_x1, y_x1);
8707
+ x_min = new Vertex_1.Vertex(x_x2, y_x2);
8708
+ }
8709
+ else {
8710
+ x_max = new Vertex_1.Vertex(x_x2, y_x2);
8711
+ x_min = new Vertex_1.Vertex(x_x1, y_x1);
8712
+ }
8713
+ // Calculate t_y values
8714
+ var t_y1 = Math.atan2(b * Math.cos(this.rotation), a * Math.sin(this.rotation));
8715
+ var t_y2 = t_y1 + Math.PI;
8716
+ // Calculate y values at t_y
8717
+ var x_y1 = this.center.x + a * Math.cos(t_y1) * Math.cos(this.rotation) - b * Math.sin(t_y1) * Math.sin(this.rotation);
8718
+ var y_y1 = this.center.y + a * Math.cos(t_y1) * Math.sin(this.rotation) + b * Math.sin(t_y1) * Math.cos(this.rotation);
8719
+ var x_y2 = this.center.x + a * Math.cos(t_y2) * Math.cos(this.rotation) - b * Math.sin(t_y2) * Math.sin(this.rotation);
8720
+ var y_y2 = this.center.y + a * Math.cos(t_y2) * Math.sin(this.rotation) + b * Math.sin(t_y2) * Math.cos(this.rotation);
8721
+ var y_max, y_min;
8722
+ if (y_y1 > y_y2) {
8723
+ y_max = new Vertex_1.Vertex(x_y1, y_y1);
8724
+ y_min = new Vertex_1.Vertex(x_y2, y_y2);
8725
+ }
8726
+ else {
8727
+ y_max = new Vertex_1.Vertex(x_y2, y_y2);
8728
+ y_min = new Vertex_1.Vertex(x_y1, y_y1);
8729
+ }
8730
+ return [x_max, x_min, y_max, y_min];
8731
+ };
8732
+ //--- BEGIN --- Implement interface `IBounded`
8733
+ /**
8734
+ * Get the bounds of this ellipse.
8735
+ *
8736
+ * The bounds are approximated by the underlying segment buffer; the more segment there are,
8737
+ * the more accurate will be the returned bounds.
8738
+ *
8739
+ * @method getBounds
8740
+ * @instance
8741
+ * @memberof VEllipse
8742
+ * @return {Bounds} The bounds of this ellipse.
8743
+ **/
8744
+ VEllipse.prototype.getBounds = function () {
8745
+ // Thanks to Cuixiping
8746
+ // https://stackoverflow.com/questions/87734/how-do-you-calculate-the-axis-aligned-bounding-box-of-an-ellipse
8747
+ var r1 = this.radiusH();
8748
+ var r2 = this.radiusV();
8749
+ var ux = r1 * Math.cos(this.rotation);
8750
+ var uy = r1 * Math.sin(this.rotation);
8751
+ var vx = r2 * Math.cos(this.rotation + Math.PI / 2);
8752
+ var vy = r2 * Math.sin(this.rotation + Math.PI / 2);
8753
+ var bbox_halfwidth = Math.sqrt(ux * ux + vx * vx);
8754
+ var bbox_halfheight = Math.sqrt(uy * uy + vy * vy);
8755
+ return new Bounds_1.Bounds({ x: this.center.x - bbox_halfwidth, y: this.center.y - bbox_halfheight }, { x: this.center.x + bbox_halfwidth, y: this.center.y + bbox_halfheight });
8756
+ };
8757
+ //--- BEGIN --- Implement interface `IBounded`
8758
+ /**
8759
+ * Move the ellipse by the given amount. This is equivalent by moving the `center` and `axis` points.
8760
+ *
8761
+ * @method move
8762
+ * @param {XYCoords} amount - The amount to move.
8763
+ * @instance
8764
+ * @memberof VEllipse
8765
+ * @return {VEllipse} this for chaining
8766
+ **/
8767
+ VEllipse.prototype.move = function (amount) {
8768
+ this.center.add(amount);
8769
+ this.axis.add(amount);
8770
+ return this;
8771
+ };
7887
8772
  /**
7888
8773
  * Scale this ellipse by the given factor from the center point. The factor will be applied to both radii.
7889
8774
  *
@@ -7941,7 +8826,7 @@ var VEllipse = /** @class */ (function () {
7941
8826
  * @param {number=1.0} length - [optional, default=1] The length of the returned vector.
7942
8827
  */
7943
8828
  VEllipse.prototype.normalAt = function (angle, length) {
7944
- var point = this.vertAt(angle);
8829
+ var point = this.vertAt(angle - this.rotation); // HERE IS THE CORRECT BEHAVIOR!
7945
8830
  var foci = this.getFoci();
7946
8831
  // Calculate the angle between [point,focusA] and [point,focusB]
7947
8832
  var angleA = new Line_1.Line(point, foci[0]).angle();
@@ -7953,12 +8838,13 @@ var VEllipse = /** @class */ (function () {
7953
8838
  .addX(50)
7954
8839
  .clone()
7955
8840
  .rotate(Math.PI + centerAngle, point);
7956
- if (this.center.distance(endPointA) < this.center.distance(endPointB)) {
7957
- return new Vector_1.Vector(point, endPointB);
7958
- }
7959
- else {
7960
- return new Vector_1.Vector(point, endPointA);
8841
+ var resultVector = this.center.distance(endPointA) < this.center.distance(endPointB)
8842
+ ? new Vector_1.Vector(point, endPointB)
8843
+ : new Vector_1.Vector(point, endPointA);
8844
+ if (typeof length === "number") {
8845
+ resultVector.setLength(length);
7961
8846
  }
8847
+ return resultVector;
7962
8848
  };
7963
8849
  /**
7964
8850
  * Get the tangent vector at the given angle.
@@ -7977,9 +8863,7 @@ var VEllipse = /** @class */ (function () {
7977
8863
  */
7978
8864
  VEllipse.prototype.tangentAt = function (angle, length) {
7979
8865
  var normal = this.normalAt(angle, length);
7980
- // Rotate the normal by 90 degrees, then it is the tangent.
7981
- normal.b.rotate(Math.PI / 2, normal.a);
7982
- return normal;
8866
+ return normal.inv().perp();
7983
8867
  };
7984
8868
  /**
7985
8869
  * Get the perimeter of this ellipse.
@@ -8030,6 +8914,8 @@ var VEllipse = /** @class */ (function () {
8030
8914
  /**
8031
8915
  * Get equally distributed points on the outline of this ellipse.
8032
8916
  *
8917
+ * @method getEquidistantVertices
8918
+ * @instance
8033
8919
  * @param {number} pointCount - The number of points.
8034
8920
  * @returns {Array<Vertex>}
8035
8921
  */
@@ -8041,6 +8927,78 @@ var VEllipse = /** @class */ (function () {
8041
8927
  }
8042
8928
  return result;
8043
8929
  };
8930
+ //--- BEGIN --- Implement interface `Intersectable`
8931
+ /**
8932
+ * Get the line intersections as vectors with this ellipse.
8933
+ *
8934
+ * @method lineIntersections
8935
+ * @instance
8936
+ * @param {VertTuple<Vector> ray - The line/ray to intersect this ellipse with.
8937
+ * @param {boolean} inVectorBoundsOnly - (default=false) Set to true if only intersections within the vector bounds are of interest.
8938
+ * @returns
8939
+ */
8940
+ VEllipse.prototype.lineIntersections = function (ray, inVectorBoundsOnly) {
8941
+ // Question: what happens to extreme versions when ellipse is a line (width or height is zero)?
8942
+ // This would result in a Division_by_Zero exception!
8943
+ if (inVectorBoundsOnly === void 0) { inVectorBoundsOnly = false; }
8944
+ // Step A: create clones for operations (keep originals unchanged)
8945
+ var ellipseCopy = this.clone(); // VEllipse
8946
+ var rayCopy = ray.clone(); // Vector
8947
+ // Step B: move both so ellipse's center is located at (0,0)
8948
+ var moveAmount = ellipseCopy.center.clone().inv();
8949
+ ellipseCopy.move(moveAmount);
8950
+ rayCopy.add(moveAmount);
8951
+ // Step C: rotate eclipse backwards it's rotation, so that rotation is zero (0.0).
8952
+ // Rotate together with ray!
8953
+ var rotationAmount = -ellipseCopy.rotation;
8954
+ ellipseCopy.rotate(rotationAmount); // Rotation around (0,0) = center of translated ellipse
8955
+ rayCopy.a.rotate(rotationAmount, ellipseCopy.center);
8956
+ rayCopy.b.rotate(rotationAmount, ellipseCopy.center);
8957
+ // Step D: find x/y factors to use for scaling to transform the ellipse to a circle.
8958
+ // Scale together with vector ray.
8959
+ var radiusH = ellipseCopy.radiusH();
8960
+ var radiusV = ellipseCopy.radiusV();
8961
+ var scalingFactors = radiusH > radiusV ? { x: radiusV / radiusH, y: 1.0 } : { x: 1.0, y: radiusH / radiusV };
8962
+ // Step E: scale ellipse AND ray by calculated factors.
8963
+ ellipseCopy.axis.scaleXY(scalingFactors);
8964
+ rayCopy.a.scaleXY(scalingFactors);
8965
+ rayCopy.b.scaleXY(scalingFactors);
8966
+ // Intermediate result: now the ellipse is transformed to a circle and we can calculate intersections :)
8967
+ // Step F: calculate circle+line intersecions
8968
+ var tmpCircle = new Circle_1.Circle(new Vertex_1.Vertex(), ellipseCopy.radiusH()); // radiusH() === radiusV()
8969
+ var intersections = tmpCircle.lineIntersections(rayCopy, inVectorBoundsOnly);
8970
+ // Step G: transform intersecions back to original configuration
8971
+ intersections.forEach(function (intersectionPoint) {
8972
+ // Reverse transformation from above.
8973
+ intersectionPoint.scaleXY({ x: 1 / scalingFactors.x, y: 1 / scalingFactors.y }, ellipseCopy.center);
8974
+ intersectionPoint.rotate(-rotationAmount, ellipseCopy.center);
8975
+ intersectionPoint.sub(moveAmount);
8976
+ });
8977
+ return intersections;
8978
+ };
8979
+ /**
8980
+ * Get all line intersections of this polygon and their tangents along the shape.
8981
+ *
8982
+ * This method returns all intersection tangents (as vectors) with this shape. The returned array of vectors is in no specific order.
8983
+ *
8984
+ * @param line
8985
+ * @param lineIntersectionTangents
8986
+ * @returns
8987
+ */
8988
+ VEllipse.prototype.lineIntersectionTangents = function (line, inVectorBoundsOnly) {
8989
+ var _this = this;
8990
+ if (inVectorBoundsOnly === void 0) { inVectorBoundsOnly = false; }
8991
+ // Find the intersections of all lines plus their tangents inside the circle bounds
8992
+ var interSectionPoints = this.lineIntersections(line, inVectorBoundsOnly);
8993
+ return interSectionPoints.map(function (vert) {
8994
+ // Calculate angle
8995
+ var lineFromCenter = new Line_1.Line(_this.center, vert);
8996
+ var angle = lineFromCenter.angle();
8997
+ // Calculate tangent at angle
8998
+ return _this.tangentAt(angle);
8999
+ });
9000
+ };
9001
+ //--- END --- Implement interface `Intersectable`
8044
9002
  /**
8045
9003
  * Convert this ellipse into cubic Bézier curves.
8046
9004
  *
@@ -8053,7 +9011,7 @@ var VEllipse = /** @class */ (function () {
8053
9011
  // Math by Luc Maisonobe
8054
9012
  // http://www.spaceroots.org/documents/ellipse/node22.html
8055
9013
  // Note that ellipses with radiusH=0 or radiusV=0 cannot be represented as Bézier curves.
8056
- // Return a single line here (as a Bézier curve)
9014
+ // Return a single line here (as a Bézier curve)?
8057
9015
  // if (Math.abs(this.radiusV()) < 0.00001) {
8058
9016
  // const radiusH = this.radiusH();
8059
9017
  // return [
@@ -8083,10 +9041,10 @@ var VEllipse = /** @class */ (function () {
8083
9041
  var radiusV = this.radiusV();
8084
9042
  var curves = [];
8085
9043
  var angles = VEllipse.utils.equidistantVertAngles(radiusH, radiusV, segmentCount);
8086
- var curAngle = angles[0];
9044
+ var curAngle = angles[0] + this.rotation;
8087
9045
  var startPoint = this.vertAt(curAngle);
8088
9046
  for (var i = 0; i < angles.length; i++) {
8089
- var nextAngle = angles[(i + 1) % angles.length];
9047
+ var nextAngle = angles[(i + 1) % angles.length] + this.rotation;
8090
9048
  var endPoint = this.vertAt(nextAngle);
8091
9049
  if (Math.abs(radiusV) < 0.0001 || Math.abs(radiusH) < 0.0001) {
8092
9050
  // Distorted ellipses can only be approximated by linear Bézier segments
@@ -8095,8 +9053,8 @@ var VEllipse = /** @class */ (function () {
8095
9053
  curves.push(curve);
8096
9054
  }
8097
9055
  else {
8098
- var startTangent = this.tangentAt(curAngle);
8099
- var endTangent = this.tangentAt(nextAngle);
9056
+ var startTangent = this.tangentAt(curAngle + this.rotation);
9057
+ var endTangent = this.tangentAt(nextAngle + this.rotation);
8100
9058
  // Find intersection (ignore that the result might be null in some extreme cases)
8101
9059
  var intersection = startTangent.intersection(endTangent);
8102
9060
  // What if intersection is undefined?
@@ -8197,10 +9155,18 @@ exports.VEllipse = VEllipse;
8197
9155
  * @date 2021-02-26
8198
9156
  * @modified 2022-02-02 Added the `destroy` method.
8199
9157
  * @modified 2022-11-01 Tweaked the `endpointToCenterParameters` function to handle negative values, too, without errors.
8200
- * @version 1.1.1
9158
+ * @modified 2025-04-01 Adapting a the `toCubicBezier` calculation to match an underlying change in the vertAt and tangentAt calculation of ellipses (was required to hamonize both methods with circles).
9159
+ * @modified 2025-04-02 Adding `VEllipseSector.containsAngle` method.
9160
+ * @modified 2025-04-02 Adding `VEllipseSector.lineIntersections` and `VEllipseSector.lineIntersectionTangents` and implementing `Intersectable`.
9161
+ * @modified 2025-04-07 Adding value wrapping (0 to TWO_PI) to the `VEllipseSector.containsAngle` method.
9162
+ * @modified 2025-04-09 Adding the `VEllipseSector.move` method.
9163
+ * @modified 2025-04-19 Added the `VEllipseSector.getStartPoint` and `getEndPoint` methods.
9164
+ * @modified 2025-04-23 Added the `VEllipseSector.getBounds` method.
9165
+ * @version 1.2.0
8201
9166
  */
8202
9167
  Object.defineProperty(exports, "__esModule", ({ value: true }));
8203
9168
  exports.VEllipseSector = void 0;
9169
+ var Bounds_1 = __webpack_require__(76);
8204
9170
  var CubicBezierCurve_1 = __webpack_require__(973);
8205
9171
  var geomutils_1 = __webpack_require__(328);
8206
9172
  var Line_1 = __webpack_require__(939);
@@ -8241,6 +9207,142 @@ var VEllipseSector = /** @class */ (function () {
8241
9207
  this.startAngle = geomutils_1.geomutils.wrapMinMax(startAngle, 0, Math.PI * 2);
8242
9208
  this.endAngle = geomutils_1.geomutils.wrapMinMax(endAngle, 0, Math.PI * 2);
8243
9209
  }
9210
+ /**
9211
+ * Move the ellipse sector by the given amount.
9212
+ *
9213
+ * @method move
9214
+ * @param {XYCoords} amount - The amount to move.
9215
+ * @instance
9216
+ * @memberof VEllipseSector
9217
+ * @return {VEllipseSector} this for chaining
9218
+ **/
9219
+ VEllipseSector.prototype.move = function (amount) {
9220
+ this.ellipse.move(amount);
9221
+ return this;
9222
+ };
9223
+ /**
9224
+ * Checks wether the given angle (must be inside 0 and PI*2) is contained inside this sector.
9225
+ *
9226
+ * @param {number} angle - The numeric angle to check.
9227
+ * @method containsAngle
9228
+ * @instance
9229
+ * @memberof VEllipseSectpr
9230
+ * @return {boolean} True if (and only if) this sector contains the given angle.
9231
+ */
9232
+ VEllipseSector.prototype.containsAngle = function (angle) {
9233
+ angle = geomutils_1.geomutils.mapAngleTo2PI(angle); // wrapMinMax(angle, 0, Math.PI * 2);
9234
+ var sAngle = geomutils_1.geomutils.mapAngleTo2PI(this.startAngle);
9235
+ var eAngle = geomutils_1.geomutils.mapAngleTo2PI(this.endAngle);
9236
+ // TODO: cleanup
9237
+ // if (this.startAngle <= this.endAngle) {
9238
+ // return angle >= this.startAngle && angle < this.endAngle;
9239
+ // } else {
9240
+ // // startAngle > endAngle
9241
+ // return angle >= this.startAngle || angle < this.endAngle;
9242
+ // }
9243
+ if (sAngle <= eAngle) {
9244
+ return angle >= sAngle && angle < eAngle;
9245
+ }
9246
+ else {
9247
+ // startAngle > endAngle
9248
+ return angle >= sAngle || angle < eAngle;
9249
+ }
9250
+ };
9251
+ /**
9252
+ * Get the sectors starting point (on the underlying ellipse, located at the start angle).
9253
+ *
9254
+ * @method getStartPoint
9255
+ * @instance
9256
+ * @memberof VEllipseSector
9257
+ * @return {Vertex} The sector's stating point.
9258
+ */
9259
+ VEllipseSector.prototype.getStartPoint = function () {
9260
+ return this.ellipse.vertAt(this.startAngle);
9261
+ };
9262
+ /**
9263
+ * Get the sectors ending point (on the underlying ellipse, located at the end angle).
9264
+ *
9265
+ * @method getEndPoint
9266
+ * @instance
9267
+ * @memberof VEllipseSector
9268
+ * @return {Vertex} The sector's ending point.
9269
+ */
9270
+ VEllipseSector.prototype.getEndPoint = function () {
9271
+ return this.ellipse.vertAt(this.endAngle);
9272
+ };
9273
+ //--- BEGIN --- Implement interface `IBounded`
9274
+ /**
9275
+ * Get the bounds of this elliptic sector.
9276
+ *
9277
+ * The bounds are approximated by the underlying segment buffer; the more segment there are,
9278
+ * the more accurate will be the returned bounds.
9279
+ *
9280
+ * @method getBounds
9281
+ * @instance
9282
+ * @memberof VEllipse
9283
+ * @return {Bounds} The bounds of this elliptic sector.
9284
+ **/
9285
+ VEllipseSector.prototype.getBounds = function () {
9286
+ var _this = this;
9287
+ // Calculage angles from east, west, north and south box points and check if they are inside
9288
+ var extremes = this.ellipse.getExtremePoints();
9289
+ var candidates = extremes.filter(function (point) {
9290
+ var angle = new Line_1.Line(_this.ellipse.center, point).angle() - _this.ellipse.rotation;
9291
+ return _this.containsAngle(angle);
9292
+ });
9293
+ return Bounds_1.Bounds.computeFromVertices([this.getStartPoint(), this.getEndPoint()].concat(candidates));
9294
+ };
9295
+ //--- BEGIN --- Implement interface `Intersectable`
9296
+ /**
9297
+ * Get the line intersections as vectors with this ellipse.
9298
+ *
9299
+ * @method lineIntersections
9300
+ * @instance
9301
+ * @memberof VEllipseSectpr
9302
+ * @param {VertTuple<Vector>} ray - The line/ray to intersect this ellipse with.
9303
+ * @param {boolean} inVectorBoundsOnly - (default=false) Set to true if only intersections within the vector bounds are of interest.
9304
+ * @returns
9305
+ */
9306
+ VEllipseSector.prototype.lineIntersections = function (ray, inVectorBoundsOnly) {
9307
+ var _this = this;
9308
+ if (inVectorBoundsOnly === void 0) { inVectorBoundsOnly = false; }
9309
+ // First get all line intersections from underlying ellipse.
9310
+ var ellipseIntersections = this.ellipse.lineIntersections(ray, inVectorBoundsOnly);
9311
+ // Drop all intersection points that are not contained in the circle sectors bounds.
9312
+ var tmpLine = new Line_1.Line(this.ellipse.center, new Vertex_1.Vertex());
9313
+ return ellipseIntersections.filter(function (intersectionPoint) {
9314
+ tmpLine.b.set(intersectionPoint);
9315
+ var lineAngle = tmpLine.angle();
9316
+ return _this.containsAngle(lineAngle - _this.ellipse.rotation);
9317
+ });
9318
+ };
9319
+ /**
9320
+ * Get all line intersections of this polygon and their tangents along the shape.
9321
+ *
9322
+ * This method returns all intersection tangents (as vectors) with this shape. The returned array of vectors is in no specific order.
9323
+ *
9324
+ * @method lineIntersections
9325
+ * @memberof VEllipseSectpr
9326
+ * @param line
9327
+ * @param lineIntersectionTangents
9328
+ * @returns
9329
+ */
9330
+ VEllipseSector.prototype.lineIntersectionTangents = function (line, inVectorBoundsOnly) {
9331
+ var _this = this;
9332
+ if (inVectorBoundsOnly === void 0) { inVectorBoundsOnly = false; }
9333
+ // Find the intersections of all lines plus their tangents inside the circle bounds
9334
+ var interSectionPoints = this.lineIntersections(line, inVectorBoundsOnly);
9335
+ return interSectionPoints.map(function (vert) {
9336
+ // Calculate angle
9337
+ var lineFromCenter = new Line_1.Line(_this.ellipse.center, vert);
9338
+ var angle = lineFromCenter.angle();
9339
+ // console.log("angle", (angle / Math.PI) * 180.0);
9340
+ // const angle = Math.random() * Math.PI * 2; // TODO
9341
+ // Calculate tangent at angle
9342
+ return _this.ellipse.tangentAt(angle);
9343
+ });
9344
+ };
9345
+ //--- END --- Implement interface `Intersectable`
8244
9346
  /**
8245
9347
  * Convert this elliptic sector into cubic Bézier curves.
8246
9348
  *
@@ -8268,8 +9370,8 @@ var VEllipseSector = /** @class */ (function () {
8268
9370
  for (var i = 0; i + 1 < angles.length; i++) {
8269
9371
  var nextAngle = angles[(i + 1) % angles.length];
8270
9372
  var endPoint = this.ellipse.vertAt(nextAngle);
8271
- var startTangent = this.ellipse.tangentAt(curAngle);
8272
- var endTangent = this.ellipse.tangentAt(nextAngle);
9373
+ var startTangent = this.ellipse.tangentAt(curAngle + this.ellipse.rotation);
9374
+ var endTangent = this.ellipse.tangentAt(nextAngle + this.ellipse.rotation);
8273
9375
  // Distorted ellipses can only be approximated by linear Bézier segments
8274
9376
  if (Math.abs(radiusV) < 0.0001 || Math.abs(radiusH) < 0.0001) {
8275
9377
  var diff = startPoint.difference(endPoint);
@@ -8379,7 +9481,7 @@ var VEllipseSector = /** @class */ (function () {
8379
9481
  return angle >= startAngle || (angle <= endAngle && angle >= 0);
8380
9482
  };
8381
9483
  // Drop all angles outside the sector
8382
- var ellipseAngles = ellipseAngles.filter(angleIsInRange);
9484
+ ellipseAngles = ellipseAngles.filter(angleIsInRange);
8383
9485
  // Now we need to sort the angles to the first one in the array is the closest to startAngle.
8384
9486
  // --> find the angle that is closest to the start angle
8385
9487
  var startIndex = VEllipseSector.ellipseSectorUtils.findClosestToStartAngle(startAngle, endAngle, ellipseAngles);
@@ -8493,7 +9595,8 @@ exports.VEllipseSector = VEllipseSector;
8493
9595
  * @modified 2022-02-02 Added the `destroy` method.
8494
9596
  * @modified 2022-02-02 Cleared the `Vector.toSVGString` function (deprecated). Use `drawutilssvg` instead.
8495
9597
  * @modified 2022-10-25 Added the `getOrthogonal` method.
8496
- * @version 1.5.0
9598
+ * @modified 2025-04-14 Added the `Vector.rotate(number)` method.
9599
+ * @version 1.6.0
8497
9600
  *
8498
9601
  * @file Vector
8499
9602
  * @public
@@ -8548,7 +9651,6 @@ var Vector = /** @class */ (function (_super) {
8548
9651
  /**
8549
9652
  * Get the perpendicular of this vector which is located at a.
8550
9653
  *
8551
- * @param {Number} t The position on the vector.
8552
9654
  * @return {Vector} A new vector being the perpendicular of this vector sitting on a.
8553
9655
  **/
8554
9656
  Vector.prototype.perp = function () {
@@ -8624,6 +9726,19 @@ var Vector = /** @class */ (function (_super) {
8624
9726
  startPoint.y = tmp;
8625
9727
  return new Vector(linePoint, startPoint.add(this.a));
8626
9728
  };
9729
+ /**
9730
+ * Rotate this vector by the given angle around the first point `a`.
9731
+ *
9732
+ * @name rotate
9733
+ * @method rotate
9734
+ * @return {Vector} this - for chaining.
9735
+ * @instance
9736
+ * @memberof Vector
9737
+ */
9738
+ Vector.prototype.rotate = function (angle) {
9739
+ this.b.rotate(angle, this.a);
9740
+ return this;
9741
+ };
8627
9742
  Vector.utils = {
8628
9743
  /**
8629
9744
  * Generate a four-point arrow head, starting at the vector end minus the
@@ -8686,7 +9801,10 @@ exports.Vector = Vector;
8686
9801
  * @modified 2024-09-10 Chaging the first param of `pointDistance` from `Vertex` to less strict type `XYCoords`. This should not break anything.
8687
9802
  * @modified 2024-09-10 Adding the optional `epsilon` param to the `hasPoint` method.
8688
9803
  * @modified 2024-12-02 Added the `epsilon` param to the `colinear` method. Default is 1.0e-6.
8689
- * @version 1.3.0
9804
+ * @modified 2025-03-31 Added the `VertTuple.revert` method.
9805
+ * @modified 2025-04-15 Changed param of `VertTuple.moveTo` method from `Vertex` to `XYCoords`.
9806
+ * @modified 2025-04-15 Added method `VertTuple.move` method.
9807
+ * @version 1.4.0
8690
9808
  */
8691
9809
  Object.defineProperty(exports, "__esModule", ({ value: true }));
8692
9810
  exports.VertTuple = void 0;
@@ -8755,15 +9873,31 @@ var VertTuple = /** @class */ (function () {
8755
9873
  *
8756
9874
  * @method add
8757
9875
  * @param {XYCoords} amount The amount (x,y) to add.
8758
- * @return {Line} this
8759
9876
  * @instance
8760
9877
  * @memberof VertTuple
9878
+ * @return {VertTuple<T>} this
8761
9879
  **/
8762
9880
  VertTuple.prototype.add = function (amount) {
8763
9881
  this.a.add(amount);
8764
9882
  this.b.add(amount);
8765
9883
  return this;
8766
9884
  };
9885
+ /**
9886
+ * Reverse this vertex tuple: a becomes b, and b becomes a.
9887
+ * This operation is in-place.
9888
+ *
9889
+ * @method add
9890
+ * @param {XYCoords} amount The amount (x,y) to add.
9891
+ * @instance
9892
+ * @memberof VertTuple
9893
+ * @return {VertTuple<T>} this
9894
+ */
9895
+ VertTuple.prototype.revert = function () {
9896
+ var tmp = this.a;
9897
+ this.a = this.b;
9898
+ this.b = tmp;
9899
+ return this;
9900
+ };
8767
9901
  /**
8768
9902
  * Normalize this line (set to length 1).
8769
9903
  *
@@ -8793,7 +9927,7 @@ var VertTuple = /** @class */ (function () {
8793
9927
  * Move this line to a new location.
8794
9928
  *
8795
9929
  * @method moveTo
8796
- * @param {Vertex} newA - The new desired location of 'a'. Vertex 'b' will be moved, too.
9930
+ * @param {XYCoords} newA - The new desired location of 'a'. Vertex 'b' will be moved, too.
8797
9931
  * @return {VertTuple} this
8798
9932
  * @instance
8799
9933
  * @memberof VertTuple
@@ -8804,6 +9938,20 @@ var VertTuple = /** @class */ (function () {
8804
9938
  this.b.add(diff);
8805
9939
  return this;
8806
9940
  };
9941
+ /**
9942
+ * Move this line by the given amount
9943
+ *
9944
+ * @method move
9945
+ * @param {XYCoords} amount - The amount to move both point of this tuple.
9946
+ * @return {VertTuple} this
9947
+ * @instance
9948
+ * @memberof VertTuple
9949
+ **/
9950
+ VertTuple.prototype.move = function (amount) {
9951
+ this.a.add(amount);
9952
+ this.b.add(amount);
9953
+ return this;
9954
+ };
8807
9955
  /**
8808
9956
  * Get the angle between this and the passed line (in radians).
8809
9957
  *
@@ -9027,7 +10175,9 @@ exports.VertTuple = VertTuple;
9027
10175
  * @modified 2023-09-29 Added the `Vertex.abs()` method as it seems useful.
9028
10176
  * @modified 2024-03-08 Added the optional `precision` param to the `toString` method.
9029
10177
  * @modified 2024-12-17 Outsourced the euclidean distance calculation of `Vertex.distance` to `geomutils.dist4`.
9030
- * @version 2.9.1
10178
+ * @modified 2025-03-24 Making the second parameter `center` of the `Vertex.rotate` method optional.
10179
+ * @modified 2025-04-13 Adding the `Vertex.move(amount: XYCoords)` method (does the same as `add`, added by naming convention).
10180
+ * @version 2.10.0
9031
10181
  *
9032
10182
  * @file Vertex
9033
10183
  * @public
@@ -9224,6 +10374,21 @@ var Vertex = /** @class */ (function () {
9224
10374
  }
9225
10375
  return this;
9226
10376
  };
10377
+ /**
10378
+ * Move this point by the given amount.
10379
+ *
10380
+ * This method just calls `add(amount).
10381
+ *
10382
+ *
10383
+ * @method move
10384
+ * @param {Vertex} amount - The amount to move this vertex.
10385
+ * @return {Vertex} this - For chaining.
10386
+ * @instance
10387
+ * @memberof Vertex
10388
+ */
10389
+ Vertex.prototype.move = function (amount) {
10390
+ return this.add(amount);
10391
+ };
9227
10392
  /**
9228
10393
  * Add the passed amounts to the x- and y- components of this vertex.
9229
10394
  *