plotboilerplate 1.23.2 → 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 (218) hide show
  1. package/README.md +6 -0
  2. package/dist/index.esm.js +8351 -6928
  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 +1590 -123
  9. package/dist/plotboilerplate.min.js +1 -1
  10. package/package.json +4 -2
  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.d.ts +4 -2
  30. package/src/cjs/PlotBoilerplate.js +9 -12
  31. package/src/cjs/PlotBoilerplate.js.map +1 -1
  32. package/src/cjs/Polygon.d.ts +153 -6
  33. package/src/cjs/Polygon.js +304 -23
  34. package/src/cjs/Polygon.js.map +1 -1
  35. package/src/cjs/Triangle.d.ts +73 -4
  36. package/src/cjs/Triangle.js +94 -2
  37. package/src/cjs/Triangle.js.map +1 -1
  38. package/src/cjs/VEllipse.d.ts +62 -3
  39. package/src/cjs/VEllipse.js +181 -17
  40. package/src/cjs/VEllipse.js.map +1 -1
  41. package/src/cjs/VEllipseSector.d.ts +86 -2
  42. package/src/cjs/VEllipseSector.js +148 -4
  43. package/src/cjs/VEllipseSector.js.map +1 -1
  44. package/src/cjs/Vector.d.ts +12 -2
  45. package/src/cjs/Vector.js +15 -2
  46. package/src/cjs/Vector.js.map +1 -1
  47. package/src/cjs/VertTuple.d.ts +39 -10
  48. package/src/cjs/VertTuple.js +49 -11
  49. package/src/cjs/VertTuple.js.map +1 -1
  50. package/src/cjs/Vertex.d.ts +18 -2
  51. package/src/cjs/Vertex.js +22 -2
  52. package/src/cjs/Vertex.js.map +1 -1
  53. package/src/cjs/draw.d.ts +1 -0
  54. package/src/cjs/draw.js +2 -1
  55. package/src/cjs/draw.js.map +1 -1
  56. package/src/cjs/drawutilssvg.js +24 -0
  57. package/src/cjs/drawutilssvg.js.map +1 -1
  58. package/src/cjs/geomutils.d.ts +32 -1
  59. package/src/cjs/geomutils.js +47 -1
  60. package/src/cjs/geomutils.js.map +1 -1
  61. package/src/cjs/interfaces/core.d.ts +39 -0
  62. package/src/cjs/interfaces/core.js +2 -0
  63. package/src/cjs/interfaces/core.js.map +1 -1
  64. package/src/cjs/utils/algorithms/PolygonInset.d.ts +184 -0
  65. package/src/cjs/utils/algorithms/PolygonInset.js +431 -0
  66. package/src/cjs/utils/algorithms/PolygonInset.js.map +1 -0
  67. package/src/cjs/utils/algorithms/clearDuplicateVertices.d.ts +5 -4
  68. package/src/cjs/utils/algorithms/clearDuplicateVertices.js +6 -3
  69. package/src/cjs/utils/algorithms/clearDuplicateVertices.js.map +1 -1
  70. package/src/cjs/utils/algorithms/convexPolygonIncircle.d.ts +2 -1
  71. package/src/cjs/utils/algorithms/convexPolygonIncircle.js +14 -6
  72. package/src/cjs/utils/algorithms/convexPolygonIncircle.js.map +1 -1
  73. package/src/cjs/utils/algorithms/findPolygonSelfIntersections.d.ts +2 -1
  74. package/src/cjs/utils/algorithms/findPolygonSelfIntersections.js +3 -3
  75. package/src/cjs/utils/algorithms/findPolygonSelfIntersections.js.map +1 -1
  76. package/src/cjs/utils/algorithms/splitPolygonToNonIntersecting.d.ts +3 -2
  77. package/src/cjs/utils/algorithms/splitPolygonToNonIntersecting.js +11 -9
  78. package/src/cjs/utils/algorithms/splitPolygonToNonIntersecting.js.map +1 -1
  79. package/src/cjs/utils/createRandomizedPolygon.d.ts +14 -0
  80. package/src/cjs/utils/createRandomizedPolygon.js +32 -0
  81. package/src/cjs/utils/createRandomizedPolygon.js.map +1 -0
  82. package/src/cjs/utils/detectDarkMode.js.map +1 -1
  83. package/src/cjs/utils/dom/guiSizeToggler.d.ts +2 -1
  84. package/src/cjs/utils/dom/guiSizeToggler.js +5 -3
  85. package/src/cjs/utils/dom/guiSizeToggler.js.map +1 -1
  86. package/src/cjs/utils/helpers/BezierPathInteractionHelper.d.ts +9 -7
  87. package/src/cjs/utils/helpers/BezierPathInteractionHelper.js +37 -23
  88. package/src/cjs/utils/helpers/BezierPathInteractionHelper.js.map +1 -1
  89. package/src/cjs/utils/helpers/CircleSectorHelper.d.ts +10 -1
  90. package/src/cjs/utils/helpers/CircleSectorHelper.js +19 -20
  91. package/src/cjs/utils/helpers/CircleSectorHelper.js.map +1 -1
  92. package/src/cjs/utils/helpers/VEllipseHelper.d.ts +30 -0
  93. package/src/cjs/utils/helpers/VEllipseHelper.js +86 -0
  94. package/src/cjs/utils/helpers/VEllipseHelper.js.map +1 -0
  95. package/src/cjs/utils/helpers/VEllipseSectorHelper.d.ts +42 -3
  96. package/src/cjs/utils/helpers/VEllipseSectorHelper.js +107 -25
  97. package/src/cjs/utils/helpers/VEllipseSectorHelper.js.map +1 -1
  98. package/src/createDemoDrawables.js +3 -1
  99. package/src/esm/BezierPath.d.ts +41 -5
  100. package/src/esm/BezierPath.js +50 -2
  101. package/src/esm/BezierPath.js.map +1 -1
  102. package/src/esm/Bounds.d.ts +67 -3
  103. package/src/esm/Bounds.js +101 -3
  104. package/src/esm/Bounds.js.map +1 -1
  105. package/src/esm/Circle.d.ts +46 -4
  106. package/src/esm/Circle.js +79 -3
  107. package/src/esm/Circle.js.map +1 -1
  108. package/src/esm/CircleSector.d.ts +51 -2
  109. package/src/esm/CircleSector.js +108 -3
  110. package/src/esm/CircleSector.js.map +1 -1
  111. package/src/esm/CubicBezierCurve.d.ts +113 -7
  112. package/src/esm/CubicBezierCurve.js +277 -33
  113. package/src/esm/CubicBezierCurve.js.map +1 -1
  114. package/src/esm/Line.d.ts +38 -3
  115. package/src/esm/Line.js +62 -1
  116. package/src/esm/Line.js.map +1 -1
  117. package/src/esm/PlotBoilerplate.d.ts +4 -2
  118. package/src/esm/PlotBoilerplate.js +9 -12
  119. package/src/esm/PlotBoilerplate.js.map +1 -1
  120. package/src/esm/Polygon.d.ts +153 -6
  121. package/src/esm/Polygon.js +301 -23
  122. package/src/esm/Polygon.js.map +1 -1
  123. package/src/esm/Triangle.d.ts +73 -4
  124. package/src/esm/Triangle.js +91 -2
  125. package/src/esm/Triangle.js.map +1 -1
  126. package/src/esm/VEllipse.d.ts +62 -3
  127. package/src/esm/VEllipse.js +178 -17
  128. package/src/esm/VEllipse.js.map +1 -1
  129. package/src/esm/VEllipseSector.d.ts +86 -2
  130. package/src/esm/VEllipseSector.js +146 -7
  131. package/src/esm/VEllipseSector.js.map +1 -1
  132. package/src/esm/Vector.d.ts +12 -2
  133. package/src/esm/Vector.js +15 -2
  134. package/src/esm/Vector.js.map +1 -1
  135. package/src/esm/VertTuple.d.ts +39 -10
  136. package/src/esm/VertTuple.js +49 -11
  137. package/src/esm/VertTuple.js.map +1 -1
  138. package/src/esm/Vertex.d.ts +18 -2
  139. package/src/esm/Vertex.js +22 -2
  140. package/src/esm/Vertex.js.map +1 -1
  141. package/src/esm/draw.d.ts +1 -0
  142. package/src/esm/draw.js +2 -1
  143. package/src/esm/draw.js.map +1 -1
  144. package/src/esm/drawutilssvg.js +24 -0
  145. package/src/esm/drawutilssvg.js.map +1 -1
  146. package/src/esm/geomutils.d.ts +32 -1
  147. package/src/esm/geomutils.js +47 -1
  148. package/src/esm/geomutils.js.map +1 -1
  149. package/src/esm/interfaces/core.d.ts +39 -0
  150. package/src/esm/interfaces/core.js +2 -0
  151. package/src/esm/interfaces/core.js.map +1 -1
  152. package/src/esm/utils/algorithms/PolygonInset.d.ts +184 -0
  153. package/src/esm/utils/algorithms/PolygonInset.js +424 -0
  154. package/src/esm/utils/algorithms/PolygonInset.js.map +1 -0
  155. package/src/esm/utils/algorithms/clearDuplicateVertices.d.ts +5 -4
  156. package/src/esm/utils/algorithms/clearDuplicateVertices.js +6 -3
  157. package/src/esm/utils/algorithms/clearDuplicateVertices.js.map +1 -1
  158. package/src/esm/utils/algorithms/convexPolygonIncircle.d.ts +2 -1
  159. package/src/esm/utils/algorithms/convexPolygonIncircle.js +15 -7
  160. package/src/esm/utils/algorithms/convexPolygonIncircle.js.map +1 -1
  161. package/src/esm/utils/algorithms/createRandomizedPolygon.d.ts +14 -0
  162. package/src/esm/utils/algorithms/createRandomizedPolygon.js +28 -0
  163. package/src/esm/utils/algorithms/createRandomizedPolygon.js.map +1 -0
  164. package/src/esm/utils/algorithms/findPolygonSelfIntersections.d.ts +2 -1
  165. package/src/esm/utils/algorithms/findPolygonSelfIntersections.js +3 -3
  166. package/src/esm/utils/algorithms/findPolygonSelfIntersections.js.map +1 -1
  167. package/src/esm/utils/algorithms/splitPolygonToNonIntersecting.d.ts +3 -2
  168. package/src/esm/utils/algorithms/splitPolygonToNonIntersecting.js +11 -9
  169. package/src/esm/utils/algorithms/splitPolygonToNonIntersecting.js.map +1 -1
  170. package/src/esm/utils/createRandomizedPolygon.d.ts +14 -0
  171. package/src/esm/utils/createRandomizedPolygon.js +28 -0
  172. package/src/esm/utils/createRandomizedPolygon.js.map +1 -0
  173. package/src/esm/utils/detectDarkMode.js.map +1 -1
  174. package/src/esm/utils/dom/guiSizeToggler.d.ts +2 -1
  175. package/src/esm/utils/dom/guiSizeToggler.js +4 -2
  176. package/src/esm/utils/dom/guiSizeToggler.js.map +1 -1
  177. package/src/esm/utils/helpers/BezierPathInteractionHelper.d.ts +9 -7
  178. package/src/esm/utils/helpers/BezierPathInteractionHelper.js +35 -22
  179. package/src/esm/utils/helpers/BezierPathInteractionHelper.js.map +1 -1
  180. package/src/esm/utils/helpers/CircleSectorHelper.d.ts +10 -1
  181. package/src/esm/utils/helpers/CircleSectorHelper.js +19 -20
  182. package/src/esm/utils/helpers/CircleSectorHelper.js.map +1 -1
  183. package/src/esm/utils/helpers/VEllipseHelper.d.ts +30 -0
  184. package/src/esm/utils/helpers/VEllipseHelper.js +81 -0
  185. package/src/esm/utils/helpers/VEllipseHelper.js.map +1 -0
  186. package/src/esm/utils/helpers/VEllipseSectorHelper.d.ts +42 -3
  187. package/src/esm/utils/helpers/VEllipseSectorHelper.js +106 -24
  188. package/src/esm/utils/helpers/VEllipseSectorHelper.js.map +1 -1
  189. package/src/ts/BezierPath.ts +58 -5
  190. package/src/ts/Bounds.ts +110 -6
  191. package/src/ts/Circle.ts +87 -5
  192. package/src/ts/CircleSector.ts +115 -5
  193. package/src/ts/CubicBezierCurve.ts +332 -42
  194. package/src/ts/Line.ts +66 -3
  195. package/src/ts/PlotBoilerplate.ts +10 -12
  196. package/src/ts/Polygon.ts +329 -27
  197. package/src/ts/Triangle.ts +101 -5
  198. package/src/ts/VEllipse.ts +214 -19
  199. package/src/ts/VEllipseSector.ts +154 -8
  200. package/src/ts/Vector.ts +16 -2
  201. package/src/ts/VertTuple.ts +53 -13
  202. package/src/ts/Vertex.ts +24 -3
  203. package/src/ts/draw.ts +2 -1
  204. package/src/ts/drawutilssvg.ts +29 -0
  205. package/src/ts/geomutils.ts +49 -1
  206. package/src/ts/interfaces/core.ts +42 -0
  207. package/src/ts/utils/algorithms/PolygonInset.ts +529 -0
  208. package/src/ts/utils/algorithms/clearDuplicateVertices.ts +11 -8
  209. package/src/ts/utils/algorithms/convexPolygonIncircle.ts +82 -78
  210. package/src/ts/utils/algorithms/findPolygonSelfIntersections.ts +25 -26
  211. package/src/ts/utils/algorithms/splitPolygonToNonIntersecting.ts +92 -99
  212. package/src/ts/utils/createRandomizedPolygon.ts +31 -0
  213. package/src/ts/utils/detectDarkMode.ts +1 -3
  214. package/src/ts/utils/dom/guiSizeToggler.ts +4 -2
  215. package/src/ts/utils/helpers/BezierPathInteractionHelper.ts +45 -29
  216. package/src/ts/utils/helpers/CircleSectorHelper.ts +115 -125
  217. package/src/ts/utils/helpers/VEllipseHelper.ts +113 -0
  218. 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;
1785
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)));
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);
1879
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
+ }
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;
@@ -4333,8 +4980,9 @@ exports.PBText = PBText;
4333
4980
  * @modified 2023-09-29 Adding proper dicionary key and value types to the params of `PlotBoilerplate.utils.safeMergeByKeys` (was `object` before).
4334
4981
  * @modified 2024-07-08 Adding `PlotBoilerplate.getGUI()` to retrieve the GUI instance.
4335
4982
  * @modified 2024-08-25 Extending main class `PlotBoilerplate` optional param `isBackdropFiltersEnabled`.
4983
+ * @modified 2024-12-02 Adding the `triggerRedraw` to the `removeAll` method.
4336
4984
  *
4337
- * @version 1.19.0
4985
+ * @version 1.20.0
4338
4986
  *
4339
4987
  * @file PlotBoilerplate
4340
4988
  * @fileoverview The main class.
@@ -5094,16 +5742,19 @@ var PlotBoilerplate = /** @class */ (function () {
5094
5742
  *
5095
5743
  * @method removeAll
5096
5744
  * @param {boolean=false} keepVertices
5745
+ * @param {boolean=true} triggerRedraw - By default this method triggers the redraw routine; passing `false` will suppress redrawing.
5097
5746
  * @instance
5098
5747
  * @memberof PlotBoilerplate
5099
5748
  * @return {void}
5100
5749
  */
5101
- PlotBoilerplate.prototype.removeAll = function (keepVertices) {
5750
+ PlotBoilerplate.prototype.removeAll = function (keepVertices, triggerRedraw) {
5102
5751
  this.drawables = [];
5103
5752
  if (!Boolean(keepVertices)) {
5104
5753
  this.vertices = [];
5105
5754
  }
5106
- this.redraw();
5755
+ if (triggerRedraw || typeof triggerRedraw === "undefined") {
5756
+ this.redraw();
5757
+ }
5107
5758
  };
5108
5759
  /**
5109
5760
  * Find the vertex near the given position.
@@ -5308,18 +5959,17 @@ var PlotBoilerplate = /** @class */ (function () {
5308
5959
  }
5309
5960
  else if (d instanceof Triangle_1.Triangle) {
5310
5961
  draw.polyline([d.a, d.b, d.c], false, this.drawConfig.triangle.color, this.drawConfig.triangle.lineWidth);
5311
- if (!this.drawConfig.drawHandlePoints)
5962
+ if (!this.drawConfig.drawHandlePoints) {
5312
5963
  d.a.attr.renderTime = d.b.attr.renderTime = d.c.attr.renderTime = renderTime;
5964
+ }
5313
5965
  }
5314
5966
  else if (d instanceof VEllipse_1.VEllipse) {
5315
5967
  if (this.drawConfig.drawHandleLines) {
5316
5968
  draw.setCurrentId("".concat(d.uid, "_e0"));
5317
5969
  draw.setCurrentClassName("".concat(d.className, "-v-line"));
5318
- // draw.line( d.center.clone().add(0,d.axis.y-d.center.y), d.axis, '#c8c8c8' );
5319
5970
  draw.handleLine(d.center.clone().add(0, d.signedRadiusV()).rotate(d.rotation, d.center), d.axis); // , "#c8c8c8");
5320
5971
  draw.setCurrentId("".concat(d.uid, "_e1"));
5321
5972
  draw.setCurrentClassName("".concat(d.className, "-h-line"));
5322
- // draw.line( d.center.clone().add(d.axis.x-d.center.x,0), d.axis, '#c8c8c8' );
5323
5973
  draw.handleLine(d.center.clone().add(d.signedRadiusH(), 0).rotate(d.rotation, d.center), d.axis); // , "#c8c8c8");
5324
5974
  }
5325
5975
  draw.setCurrentId(d.uid);
@@ -5335,12 +5985,6 @@ var PlotBoilerplate = /** @class */ (function () {
5335
5985
  else if (d instanceof VEllipseSector_1.VEllipseSector) {
5336
5986
  draw.setCurrentId(d.uid);
5337
5987
  draw.setCurrentClassName("".concat(d.className));
5338
- /* draw.ellipse( d.center,
5339
- // Math.abs(d.axis.x-d.center.x), Math.abs(d.axis.y-d.center.y),
5340
- d.radiusH(), d.radiusV(),
5341
- this.drawConfig.ellipse.color,
5342
- this.drawConfig.ellipse.lineWidth,
5343
- d.rotation ); */
5344
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 });
5345
5989
  draw.path(data, this.drawConfig.ellipseSector.color, this.drawConfig.ellipseSector.lineWidth);
5346
5990
  }
@@ -6526,7 +7170,15 @@ exports["default"] = PlotBoilerplate;
6526
7170
  * @modified 2023-09-25 Added the `Polygon.lineIntersections(Line,boolean)` function.
6527
7171
  * @modified 2023-09-29 Added the `Polygon.closestLineIntersection(Line,boolean)` function.
6528
7172
  * @modified 2023-11-24 Added the `Polygon.containsPolygon(Polygon)' function.
6529
- * @version 1.12.0
7173
+ * @modified 2024-10-12 Added the `getEdgeAt` method.
7174
+ * @modified 2024-10-30 Added the `getEdges` method.
7175
+ * @modified 2024-12-02 Added the `elimitateColinearEdges` method.
7176
+ * @modified 2025-02-12 Added the `containsVerts` method to test multiple vertices for containment.
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
6530
7182
  *
6531
7183
  * @file Polygon
6532
7184
  * @public
@@ -6536,8 +7188,11 @@ exports.Polygon = void 0;
6536
7188
  var BezierPath_1 = __webpack_require__(733);
6537
7189
  var Bounds_1 = __webpack_require__(76);
6538
7190
  var Line_1 = __webpack_require__(939);
7191
+ var Triangle_1 = __webpack_require__(737);
6539
7192
  var UIDGenerator_1 = __webpack_require__(938);
7193
+ var Vector_1 = __webpack_require__(30);
6540
7194
  var Vertex_1 = __webpack_require__(787);
7195
+ var geomutils_1 = __webpack_require__(328);
6541
7196
  /**
6542
7197
  * @classdesc A polygon class. Any polygon consists of an array of vertices; polygons can be open or closed.
6543
7198
  *
@@ -6564,15 +7219,16 @@ var Polygon = /** @class */ (function () {
6564
7219
  **/
6565
7220
  this.className = "Polygon";
6566
7221
  this.uid = UIDGenerator_1.UIDGenerator.next();
6567
- if (typeof vertices == "undefined")
7222
+ if (typeof vertices == "undefined") {
6568
7223
  vertices = [];
7224
+ }
6569
7225
  this.vertices = vertices;
6570
7226
  this.isOpen = isOpen || false;
6571
7227
  }
6572
7228
  /**
6573
7229
  * Add a vertex to the end of the `vertices` array.
6574
7230
  *
6575
- * @method addVert
7231
+ * @method addVertex
6576
7232
  * @param {Vertex} vert - The vertex to add.
6577
7233
  * @instance
6578
7234
  * @memberof Polygon
@@ -6580,6 +7236,108 @@ var Polygon = /** @class */ (function () {
6580
7236
  Polygon.prototype.addVertex = function (vert) {
6581
7237
  this.vertices.push(vert);
6582
7238
  };
7239
+ /**
7240
+ * Add a vertex at a particular position of the `vertices` array.
7241
+ *
7242
+ * @method addVertexAt
7243
+ * @param {Vertex} vert - The vertex to add.
7244
+ * @param {number} index - The position to add the vertex at. Will be handled modulo.
7245
+ * @instance
7246
+ * @memberof Polygon
7247
+ **/
7248
+ Polygon.prototype.addVertexAt = function (vert, index) {
7249
+ // var moduloIndex = index % (this.vertices.length + 1);
7250
+ this.vertices.splice(index, 0, vert);
7251
+ };
7252
+ /**
7253
+ * Get a new instance of the line at the given start index. The returned line will consist
7254
+ * of the vertex at `vertIndex` and `vertIndex+1` (will be handled modulo).
7255
+ *
7256
+ * @method getEdgeAt
7257
+ * @param {number} vertIndex - The vertex index of the line to start.
7258
+ * @instance
7259
+ * @memberof Polygon
7260
+ * @return {Line}
7261
+ **/
7262
+ Polygon.prototype.getEdgeAt = function (vertIndex) {
7263
+ return new Line_1.Line(this.getVertexAt(vertIndex), this.getVertexAt(vertIndex + 1));
7264
+ };
7265
+ /**
7266
+ * Converts this polygon into a sequence of lines. Please note that each time
7267
+ * this method is called new lines are created. The underlying line vertices are no clones
7268
+ * (instances).
7269
+ *
7270
+ * @method getEdges
7271
+ * @instance
7272
+ * @memberof Polygon
7273
+ * @return {Array<Line>}
7274
+ */
7275
+ Polygon.prototype.getEdges = function () {
7276
+ var lines = [];
7277
+ for (var i = 0; i + 1 < this.vertices.length; i++) {
7278
+ // var line = this.getLineAt(i).clone();
7279
+ lines.push(this.getEdgeAt(i));
7280
+ }
7281
+ if (!this.isOpen && this.vertices.length > 0) {
7282
+ lines.push(this.getEdgeAt(this.vertices.length - 1));
7283
+ }
7284
+ return lines;
7285
+ };
7286
+ /**
7287
+ * Checks if the angle at the given polygon vertex (index) is acute. Please not that this is
7288
+ * only working for clockwise polygons. If this polygon is not clockwise please use the
7289
+ * `isClockwise` method and reverse polygon vertices if needed.
7290
+ *
7291
+ * @method isAngleAcute
7292
+ * @instance
7293
+ * @memberof Polygon
7294
+ * @param {number} vertIndex - The index of the polygon vertex to check.
7295
+ * @returns {boolean} `true` is angle is acute, `false` is obtuse.
7296
+ */
7297
+ Polygon.prototype.getInnerAngleAt = function (vertIndex) {
7298
+ var p2 = this.vertices[vertIndex];
7299
+ var p1 = this.vertices[(vertIndex + this.vertices.length - 1) % this.vertices.length].clone();
7300
+ var p3 = this.vertices[(vertIndex + 1) % this.vertices.length].clone();
7301
+ // See
7302
+ // https://math.stackexchange.com/questions/149959/how-to-find-the-interior-angle-of-an-irregular-pentagon-or-polygon
7303
+ // π−arccos((P2−P1)⋅(P3−P2)|P2−P1||P3−P2|)
7304
+ // Check if triangle is acute (will be used later)
7305
+ // Acute angles and obtuse angles need to be handled differently.
7306
+ var isAcute = this.isAngleAcute(vertIndex);
7307
+ // Differences
7308
+ var zero = new Vertex_1.Vertex(0, 0);
7309
+ var p2mp1 = new Vertex_1.Vertex(p2.x - p1.x, p2.y - p1.y);
7310
+ var p3mp2 = new Vertex_1.Vertex(p3.x - p2.x, p3.y - p2.y);
7311
+ var p2mp1_len = zero.distance(p2mp1);
7312
+ var p3mp2_len = zero.distance(p3mp2);
7313
+ // Dot products
7314
+ var dotProduct = geomutils_1.geomutils.dotProduct(p2mp1, p3mp2);
7315
+ var lengthProduct = p2mp1_len * p3mp2_len;
7316
+ if (isAcute) {
7317
+ return Math.PI - Math.acos(dotProduct / lengthProduct);
7318
+ }
7319
+ else {
7320
+ return Math.PI + Math.acos(dotProduct / lengthProduct);
7321
+ }
7322
+ };
7323
+ /**
7324
+ * Checks if the angle at the given polygon vertex (index) is acute.
7325
+ *
7326
+ * @method isAngleAcute
7327
+ * @instance
7328
+ * @memberof Polygon
7329
+ * @param {number} vertIndex - The index of the polygon vertex to check.
7330
+ * @returns {boolean} `true` is angle is acute, `false` is obtuse.
7331
+ */
7332
+ Polygon.prototype.isAngleAcute = function (vertIndex) {
7333
+ var A = this.vertices[(vertIndex + this.vertices.length - 1) % this.vertices.length].clone();
7334
+ var B = this.vertices[vertIndex];
7335
+ var C = this.vertices[(vertIndex + 1) % this.vertices.length].clone();
7336
+ // Find local winding number for triangle A B C
7337
+ var windingNumber = Triangle_1.Triangle.utils.determinant(A, B, C);
7338
+ // console.log("vertIndex", vertIndex, "windingNumber", windingNumber);
7339
+ return windingNumber < 0;
7340
+ };
6583
7341
  /**
6584
7342
  * Get the polygon vertex at the given position (index).
6585
7343
  *
@@ -6590,17 +7348,19 @@ var Polygon = /** @class */ (function () {
6590
7348
  * - getVertexAt( vertices.length + k ) == getVertexAt( k )
6591
7349
  * - getVertexAt( -k ) == getVertexAt( vertices.length -k )
6592
7350
  *
6593
- * @metho getVertexAt
7351
+ * @method getVertexAt
6594
7352
  * @param {number} index - The index of the desired vertex.
6595
7353
  * @instance
6596
7354
  * @memberof Polygon
6597
7355
  * @return {Vertex} At the given index.
6598
7356
  **/
6599
7357
  Polygon.prototype.getVertexAt = function (index) {
6600
- if (index < 0)
7358
+ if (index < 0) {
6601
7359
  return this.vertices[this.vertices.length - (Math.abs(index) % this.vertices.length)];
6602
- else
7360
+ }
7361
+ else {
6603
7362
  return this.vertices[index % this.vertices.length];
7363
+ }
6604
7364
  };
6605
7365
  /**
6606
7366
  * Move the polygon's vertices by the given amount.
@@ -6624,7 +7384,7 @@ var Polygon = /** @class */ (function () {
6624
7384
  * https://stackoverflow.com/questions/22521982/check-if-point-inside-a-polygon
6625
7385
  *
6626
7386
  * @method containsVert
6627
- * @param {XYCoords} vert - The vertex to check. The new x-component.
7387
+ * @param {XYCoords} vert - The vertex to check.
6628
7388
  * @return {boolean} True if the passed vertex is inside this polygon. The polygon is considered closed.
6629
7389
  * @instance
6630
7390
  * @memberof Polygon
@@ -6642,6 +7402,21 @@ var Polygon = /** @class */ (function () {
6642
7402
  }
6643
7403
  return inside;
6644
7404
  };
7405
+ /**
7406
+ * Check if all given vertices are inside this polygon.<br>
7407
+ * <br>
7408
+ * This method just uses the `Polygon.containsVert` method.
7409
+ *
7410
+ * @method containsVerts
7411
+ * @param {XYCoords[]} verts - The vertices to check.
7412
+ * @return {boolean} True if all passed vertices are inside this polygon. The polygon is considered closed.
7413
+ * @instance
7414
+ * @memberof Polygon
7415
+ **/
7416
+ Polygon.prototype.containsVerts = function (verts) {
7417
+ var _this = this;
7418
+ return verts.every(function (vert) { return _this.containsVert(vert); });
7419
+ };
6645
7420
  /**
6646
7421
  * Check if the passed polygon is completly contained inside this polygon.
6647
7422
  *
@@ -6704,7 +7479,8 @@ var Polygon = /** @class */ (function () {
6704
7479
  * @return {boolean}
6705
7480
  */
6706
7481
  Polygon.prototype.isClockwise = function () {
6707
- return Polygon.utils.signedArea(this.vertices) < 0;
7482
+ // return Polygon.utils.signedArea(this.vertices) < 0;
7483
+ return Polygon.utils.isClockwise(this.vertices);
6708
7484
  };
6709
7485
  /**
6710
7486
  * Get the perimeter of this polygon.
@@ -6763,9 +7539,66 @@ var Polygon = /** @class */ (function () {
6763
7539
  }
6764
7540
  return this;
6765
7541
  };
7542
+ /**
7543
+ * Get the mean `center` of this polygon by calculating the mean value of all vertices.
7544
+ *
7545
+ * Mean: (v[0] + v[1] + ... v[n-1]) / n
7546
+ *
7547
+ * @method getMeanCenter
7548
+ * @instance
7549
+ * @memberof Polygon
7550
+ * @return {Vertex|null} `null` is no vertices are available.
7551
+ */
7552
+ Polygon.prototype.getMeanCenter = function () {
7553
+ if (this.vertices.length === 0) {
7554
+ return null;
7555
+ }
7556
+ var center = this.vertices[0].clone();
7557
+ for (var i = 1; i < this.vertices.length; i++) {
7558
+ center.add(this.vertices[i]);
7559
+ }
7560
+ center.x /= this.vertices.length;
7561
+ center.y /= this.vertices.length;
7562
+ return center;
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`
6766
7597
  /**
6767
7598
  * Get all line intersections with this polygon.
6768
7599
  *
7600
+ * This method returns all intersections (as vertices) with this shape. The returned array of vertices is in no specific order.
7601
+ *
6769
7602
  * See demo `47-closest-vector-projection-on-polygon` for how it works.
6770
7603
  *
6771
7604
  * @param {VertTuple} line - The line to find intersections with.
@@ -6775,21 +7608,29 @@ var Polygon = /** @class */ (function () {
6775
7608
  Polygon.prototype.lineIntersections = function (line, inVectorBoundsOnly) {
6776
7609
  if (inVectorBoundsOnly === void 0) { inVectorBoundsOnly = false; }
6777
7610
  // Find the intersections of all lines inside the edge bounds
6778
- var intersectionPoints = [];
6779
- for (var i = 0; i < this.vertices.length; i++) {
6780
- var polyLine = new Line_1.Line(this.vertices[i], this.vertices[(i + 1) % this.vertices.length]);
6781
- var intersection = polyLine.intersection(line);
6782
- // true => only inside bounds
6783
- // ignore last edge if open
6784
- if ((!this.isOpen || i + 1 !== this.vertices.length) &&
6785
- intersection !== null &&
6786
- polyLine.hasPoint(intersection, true) &&
6787
- (!inVectorBoundsOnly || line.hasPoint(intersection, inVectorBoundsOnly))) {
6788
- intersectionPoints.push(intersection);
6789
- }
6790
- }
6791
- 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
+ });
6792
7632
  };
7633
+ //--- END --- Implement interface `Intersectable`
6793
7634
  /**
6794
7635
  * Get the closest line-polygon-intersection point (closest the line point A).
6795
7636
  *
@@ -6891,6 +7732,7 @@ var Polygon = /** @class */ (function () {
6891
7732
  }
6892
7733
  return result;
6893
7734
  };
7735
+ //--- BEGIN --- Implement interface `IBounded`
6894
7736
  /**
6895
7737
  * Get the bounding box (bounds) of this polygon.
6896
7738
  *
@@ -6902,13 +7744,66 @@ var Polygon = /** @class */ (function () {
6902
7744
  Polygon.prototype.getBounds = function () {
6903
7745
  return Bounds_1.Bounds.computeFromVertices(this.vertices);
6904
7746
  };
7747
+ //--- END --- Implement interface `IBounded`
6905
7748
  /**
6906
7749
  * Create a deep copy of this polygon.
6907
7750
  *
7751
+ * @method clone
7752
+ * @instance
7753
+ * @memberof Polygon
6908
7754
  * @return {Polygon} The cloned polygon.
6909
7755
  */
6910
- Polygon.prototype.clone = function () {
6911
- return new Polygon(this.vertices.map(function (vert) { return vert.clone(); }), this.isOpen);
7756
+ Polygon.prototype.clone = function () {
7757
+ return new Polygon(this.vertices.map(function (vert) { return vert.clone(); }), this.isOpen);
7758
+ };
7759
+ /**
7760
+ * Create a new polygon without colinear adjacent edges. This method does not midify the current polygon
7761
+ * but creates a new one.
7762
+ *
7763
+ * Please note that this method does NOT create deep clones of the vertices. Use Polygon.clone() if you need to.
7764
+ *
7765
+ * Please also note that the `tolerance` may become really large here, as the denominator of two closely
7766
+ * parallel lines is usually pretty large. See the demo `57-eliminate-colinear-polygon-edges` to get
7767
+ * an impression of how denominators work.
7768
+ *
7769
+ * @method elimitateColinearEdges
7770
+ * @instance
7771
+ * @memberof Polygon
7772
+ * @param {number?} tolerance - (default is 1.0) The epsilon to detect co-linear edges.
7773
+ * @return {Polygon} A new polygon without co-linear adjacent edges – respective the given epsilon.
7774
+ */
7775
+ Polygon.prototype.elimitateColinearEdges = function (tolerance) {
7776
+ var eps = typeof tolerance === "undefined" ? 1.0 : tolerance;
7777
+ var verts = this.vertices.slice(); // Creates a shallow copy
7778
+ var i = 0;
7779
+ var lineA = new Line_1.Line(new Vertex_1.Vertex(), new Vertex_1.Vertex());
7780
+ var lineB = new Line_1.Line(new Vertex_1.Vertex(), new Vertex_1.Vertex());
7781
+ while (i + 1 < verts.length && verts.length > 2) {
7782
+ var vertA = verts[i];
7783
+ var vertB = verts[(i + 1) % verts.length];
7784
+ lineA.a = vertA;
7785
+ lineA.b = vertB;
7786
+ lineB.a = vertB;
7787
+ var areColinear = false;
7788
+ var j = i + 2;
7789
+ do {
7790
+ var vertC = verts[j % verts.length];
7791
+ lineB.b = vertC;
7792
+ areColinear = lineA.colinear(lineB, eps);
7793
+ // console.log("are colinear?", i, i + 1, j, areColinear);
7794
+ if (areColinear) {
7795
+ j++;
7796
+ }
7797
+ } while (areColinear);
7798
+ // Now j points to the first vertex that's NOT colinear to the current lineA
7799
+ // -> delete all vertices in between
7800
+ if (j - i > 2) {
7801
+ // Means: there have been 'colinear vertices' in between
7802
+ verts.splice(i + 1, j - i - 2);
7803
+ }
7804
+ i++;
7805
+ }
7806
+ return new Polygon(verts, this.isOpen);
6912
7807
  };
6913
7808
  /**
6914
7809
  * Convert this polygon to a sequence of quadratic Bézier curves.<br>
@@ -7009,8 +7904,9 @@ var Polygon = /** @class */ (function () {
7009
7904
  **/
7010
7905
  Polygon.prototype.toCubicBezierSVGString = function (threshold) {
7011
7906
  var qdata = this.toCubicBezierData(threshold);
7012
- if (qdata.length == 0)
7907
+ if (qdata.length == 0) {
7013
7908
  return "";
7909
+ }
7014
7910
  var buffer = ["M " + qdata[0].x + " " + qdata[0].y];
7015
7911
  for (var i = 1; i < qdata.length; i += 3) {
7016
7912
  buffer.push("C " +
@@ -7080,6 +7976,9 @@ var Polygon = /** @class */ (function () {
7080
7976
  }
7081
7977
  return Math.abs(total);
7082
7978
  },
7979
+ isClockwise: function (vertices) {
7980
+ return Polygon.utils.signedArea(vertices) < 0;
7981
+ },
7083
7982
  /**
7084
7983
  * Calulate the signed polyon area by interpreting the polygon as a matrix
7085
7984
  * and calculating its determinant.
@@ -7095,6 +7994,32 @@ var Polygon = /** @class */ (function () {
7095
7994
  sum += (vertices[j].x - vertices[i].x) * (vertices[i].y + vertices[j].y);
7096
7995
  }
7097
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;
7098
8023
  }
7099
8024
  };
7100
8025
  return Polygon;
@@ -7131,7 +8056,13 @@ exports.Polygon = Polygon;
7131
8056
  * @modified 2021-01-22 Always updating circumcircle when retieving it.
7132
8057
  * @modified 2022-02-02 Added the `destroy` method.
7133
8058
  * @modified 2022-02-02 Cleared the `Triangle.toSVGString` function (deprecated). Use `drawutilssvg` instead.
7134
- * @version 2.6.0
8059
+ * @modified 2024-11-22 Added static utility function Triangle.utils.determinant; adapted method `determinant`.
8060
+ * @modified 2024-11-22 Changing visibility of `Triangle.utils` from `private` to `public`.
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
7135
8066
  *
7136
8067
  * @file Triangle
7137
8068
  * @fileoverview A simple triangle class: three vertices.
@@ -7144,6 +8075,7 @@ var Circle_1 = __webpack_require__(118);
7144
8075
  var Line_1 = __webpack_require__(939);
7145
8076
  var Polygon_1 = __webpack_require__(687);
7146
8077
  var UIDGenerator_1 = __webpack_require__(938);
8078
+ var Vector_1 = __webpack_require__(30);
7147
8079
  var Vertex_1 = __webpack_require__(787);
7148
8080
  var geomutils_1 = __webpack_require__(328);
7149
8081
  /**
@@ -7245,6 +8177,35 @@ var Triangle = /** @class */ (function () {
7245
8177
  this.c.scale(factor, centroid);
7246
8178
  return this;
7247
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
+ };
7248
8209
  /**
7249
8210
  * Get the circumcircle of this triangle.
7250
8211
  *
@@ -7370,6 +8331,51 @@ var Triangle = /** @class */ (function () {
7370
8331
  Triangle.prototype.bounds = function () {
7371
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)));
7372
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
+ };
7373
8379
  /**
7374
8380
  * Convert this triangle to a polygon instance.
7375
8381
  *
@@ -7393,7 +8399,8 @@ var Triangle = /** @class */ (function () {
7393
8399
  */
7394
8400
  Triangle.prototype.determinant = function () {
7395
8401
  // (b.y - a.y)*(c.x - b.x) - (c.y - b.y)*(b.x - a.x);
7396
- return (this.b.y - this.a.y) * (this.c.x - this.b.x) - (this.c.y - this.b.y) * (this.b.x - this.a.x);
8402
+ // return (this.b.y - this.a.y) * (this.c.x - this.b.x) - (this.c.y - this.b.y) * (this.b.x - this.a.x);
8403
+ return Triangle.utils.determinant(this.a, this.b, this.c);
7397
8404
  };
7398
8405
  /**
7399
8406
  * Checks if the passed vertex (p) is inside this triangle.
@@ -7506,6 +8513,16 @@ var Triangle = /** @class */ (function () {
7506
8513
  var s = (1 / (2 * area)) * (p0y * p2x - p0x * p2y + (p2y - p0y) * px + (p0x - p2x) * py);
7507
8514
  var t = (1 / (2 * area)) * (p0x * p1y - p0y * p1x + (p0y - p1y) * px + (p1x - p0x) * py);
7508
8515
  return s > 0 && t > 0 && 1 - s - t > 0;
8516
+ },
8517
+ /**
8518
+ * Calculate the determinant of the three vertices a, b and c (in this order).
8519
+ * @param {XYCords} a - The first vertex.
8520
+ * @param {XYCords} b - The first vertex.
8521
+ * @param {XYCords} c - The first vertex.
8522
+ * @returns {nmber}
8523
+ */
8524
+ determinant: function (a, b, c) {
8525
+ return (b.y - a.y) * (c.x - b.x) - (c.y - b.y) * (b.x - a.x);
7509
8526
  }
7510
8527
  };
7511
8528
  return Triangle;
@@ -7563,7 +8580,11 @@ exports.UIDGenerator = UIDGenerator;
7563
8580
  * @modified 2021-03-19 Added the `VEllipse.rotate` function.
7564
8581
  * @modified 2022-02-02 Added the `destroy` method.
7565
8582
  * @modified 2022-02-02 Cleared the `VEllipse.toSVGString` function (deprecated). Use `drawutilssvg` instead.
7566
- * @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
7567
8588
  *
7568
8589
  * @file VEllipse
7569
8590
  * @fileoverview Ellipses with a center and an x- and a y-axis (stored as a vertex).
@@ -7575,6 +8596,8 @@ var Vector_1 = __webpack_require__(30);
7575
8596
  var Vertex_1 = __webpack_require__(787);
7576
8597
  var UIDGenerator_1 = __webpack_require__(938);
7577
8598
  var CubicBezierCurve_1 = __webpack_require__(973);
8599
+ var Circle_1 = __webpack_require__(118);
8600
+ var Bounds_1 = __webpack_require__(76);
7578
8601
  /**
7579
8602
  * @classdesc An ellipse class based on two vertices [centerX,centerY] and [radiusX,radiusY].
7580
8603
  *
@@ -7656,11 +8679,96 @@ var VEllipse = /** @class */ (function () {
7656
8679
  * @return {number} The signed vertical radius of this ellipse.
7657
8680
  */
7658
8681
  VEllipse.prototype.signedRadiusV = function () {
7659
- // return Math.abs(this.axis.y - this.center.y);
7660
8682
  // Rotate axis back to origin before calculating radius
7661
- // return Math.abs(new Vertex(this.axis).rotate(-this.rotation,this.center).y - this.center.y);
7662
8683
  return new Vertex_1.Vertex(this.axis).rotate(-this.rotation, this.center).y - this.center.y;
7663
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
+ };
7664
8772
  /**
7665
8773
  * Scale this ellipse by the given factor from the center point. The factor will be applied to both radii.
7666
8774
  *
@@ -7718,7 +8826,7 @@ var VEllipse = /** @class */ (function () {
7718
8826
  * @param {number=1.0} length - [optional, default=1] The length of the returned vector.
7719
8827
  */
7720
8828
  VEllipse.prototype.normalAt = function (angle, length) {
7721
- var point = this.vertAt(angle);
8829
+ var point = this.vertAt(angle - this.rotation); // HERE IS THE CORRECT BEHAVIOR!
7722
8830
  var foci = this.getFoci();
7723
8831
  // Calculate the angle between [point,focusA] and [point,focusB]
7724
8832
  var angleA = new Line_1.Line(point, foci[0]).angle();
@@ -7730,12 +8838,13 @@ var VEllipse = /** @class */ (function () {
7730
8838
  .addX(50)
7731
8839
  .clone()
7732
8840
  .rotate(Math.PI + centerAngle, point);
7733
- if (this.center.distance(endPointA) < this.center.distance(endPointB)) {
7734
- return new Vector_1.Vector(point, endPointB);
7735
- }
7736
- else {
7737
- 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);
7738
8846
  }
8847
+ return resultVector;
7739
8848
  };
7740
8849
  /**
7741
8850
  * Get the tangent vector at the given angle.
@@ -7754,9 +8863,7 @@ var VEllipse = /** @class */ (function () {
7754
8863
  */
7755
8864
  VEllipse.prototype.tangentAt = function (angle, length) {
7756
8865
  var normal = this.normalAt(angle, length);
7757
- // Rotate the normal by 90 degrees, then it is the tangent.
7758
- normal.b.rotate(Math.PI / 2, normal.a);
7759
- return normal;
8866
+ return normal.inv().perp();
7760
8867
  };
7761
8868
  /**
7762
8869
  * Get the perimeter of this ellipse.
@@ -7807,6 +8914,8 @@ var VEllipse = /** @class */ (function () {
7807
8914
  /**
7808
8915
  * Get equally distributed points on the outline of this ellipse.
7809
8916
  *
8917
+ * @method getEquidistantVertices
8918
+ * @instance
7810
8919
  * @param {number} pointCount - The number of points.
7811
8920
  * @returns {Array<Vertex>}
7812
8921
  */
@@ -7818,6 +8927,78 @@ var VEllipse = /** @class */ (function () {
7818
8927
  }
7819
8928
  return result;
7820
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`
7821
9002
  /**
7822
9003
  * Convert this ellipse into cubic Bézier curves.
7823
9004
  *
@@ -7830,7 +9011,7 @@ var VEllipse = /** @class */ (function () {
7830
9011
  // Math by Luc Maisonobe
7831
9012
  // http://www.spaceroots.org/documents/ellipse/node22.html
7832
9013
  // Note that ellipses with radiusH=0 or radiusV=0 cannot be represented as Bézier curves.
7833
- // Return a single line here (as a Bézier curve)
9014
+ // Return a single line here (as a Bézier curve)?
7834
9015
  // if (Math.abs(this.radiusV()) < 0.00001) {
7835
9016
  // const radiusH = this.radiusH();
7836
9017
  // return [
@@ -7860,10 +9041,10 @@ var VEllipse = /** @class */ (function () {
7860
9041
  var radiusV = this.radiusV();
7861
9042
  var curves = [];
7862
9043
  var angles = VEllipse.utils.equidistantVertAngles(radiusH, radiusV, segmentCount);
7863
- var curAngle = angles[0];
9044
+ var curAngle = angles[0] + this.rotation;
7864
9045
  var startPoint = this.vertAt(curAngle);
7865
9046
  for (var i = 0; i < angles.length; i++) {
7866
- var nextAngle = angles[(i + 1) % angles.length];
9047
+ var nextAngle = angles[(i + 1) % angles.length] + this.rotation;
7867
9048
  var endPoint = this.vertAt(nextAngle);
7868
9049
  if (Math.abs(radiusV) < 0.0001 || Math.abs(radiusH) < 0.0001) {
7869
9050
  // Distorted ellipses can only be approximated by linear Bézier segments
@@ -7872,8 +9053,8 @@ var VEllipse = /** @class */ (function () {
7872
9053
  curves.push(curve);
7873
9054
  }
7874
9055
  else {
7875
- var startTangent = this.tangentAt(curAngle);
7876
- var endTangent = this.tangentAt(nextAngle);
9056
+ var startTangent = this.tangentAt(curAngle + this.rotation);
9057
+ var endTangent = this.tangentAt(nextAngle + this.rotation);
7877
9058
  // Find intersection (ignore that the result might be null in some extreme cases)
7878
9059
  var intersection = startTangent.intersection(endTangent);
7879
9060
  // What if intersection is undefined?
@@ -7974,10 +9155,18 @@ exports.VEllipse = VEllipse;
7974
9155
  * @date 2021-02-26
7975
9156
  * @modified 2022-02-02 Added the `destroy` method.
7976
9157
  * @modified 2022-11-01 Tweaked the `endpointToCenterParameters` function to handle negative values, too, without errors.
7977
- * @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
7978
9166
  */
7979
9167
  Object.defineProperty(exports, "__esModule", ({ value: true }));
7980
9168
  exports.VEllipseSector = void 0;
9169
+ var Bounds_1 = __webpack_require__(76);
7981
9170
  var CubicBezierCurve_1 = __webpack_require__(973);
7982
9171
  var geomutils_1 = __webpack_require__(328);
7983
9172
  var Line_1 = __webpack_require__(939);
@@ -8018,6 +9207,142 @@ var VEllipseSector = /** @class */ (function () {
8018
9207
  this.startAngle = geomutils_1.geomutils.wrapMinMax(startAngle, 0, Math.PI * 2);
8019
9208
  this.endAngle = geomutils_1.geomutils.wrapMinMax(endAngle, 0, Math.PI * 2);
8020
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`
8021
9346
  /**
8022
9347
  * Convert this elliptic sector into cubic Bézier curves.
8023
9348
  *
@@ -8045,8 +9370,8 @@ var VEllipseSector = /** @class */ (function () {
8045
9370
  for (var i = 0; i + 1 < angles.length; i++) {
8046
9371
  var nextAngle = angles[(i + 1) % angles.length];
8047
9372
  var endPoint = this.ellipse.vertAt(nextAngle);
8048
- var startTangent = this.ellipse.tangentAt(curAngle);
8049
- 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);
8050
9375
  // Distorted ellipses can only be approximated by linear Bézier segments
8051
9376
  if (Math.abs(radiusV) < 0.0001 || Math.abs(radiusH) < 0.0001) {
8052
9377
  var diff = startPoint.difference(endPoint);
@@ -8156,7 +9481,7 @@ var VEllipseSector = /** @class */ (function () {
8156
9481
  return angle >= startAngle || (angle <= endAngle && angle >= 0);
8157
9482
  };
8158
9483
  // Drop all angles outside the sector
8159
- var ellipseAngles = ellipseAngles.filter(angleIsInRange);
9484
+ ellipseAngles = ellipseAngles.filter(angleIsInRange);
8160
9485
  // Now we need to sort the angles to the first one in the array is the closest to startAngle.
8161
9486
  // --> find the angle that is closest to the start angle
8162
9487
  var startIndex = VEllipseSector.ellipseSectorUtils.findClosestToStartAngle(startAngle, endAngle, ellipseAngles);
@@ -8270,7 +9595,8 @@ exports.VEllipseSector = VEllipseSector;
8270
9595
  * @modified 2022-02-02 Added the `destroy` method.
8271
9596
  * @modified 2022-02-02 Cleared the `Vector.toSVGString` function (deprecated). Use `drawutilssvg` instead.
8272
9597
  * @modified 2022-10-25 Added the `getOrthogonal` method.
8273
- * @version 1.5.0
9598
+ * @modified 2025-04-14 Added the `Vector.rotate(number)` method.
9599
+ * @version 1.6.0
8274
9600
  *
8275
9601
  * @file Vector
8276
9602
  * @public
@@ -8325,7 +9651,6 @@ var Vector = /** @class */ (function (_super) {
8325
9651
  /**
8326
9652
  * Get the perpendicular of this vector which is located at a.
8327
9653
  *
8328
- * @param {Number} t The position on the vector.
8329
9654
  * @return {Vector} A new vector being the perpendicular of this vector sitting on a.
8330
9655
  **/
8331
9656
  Vector.prototype.perp = function () {
@@ -8401,6 +9726,19 @@ var Vector = /** @class */ (function (_super) {
8401
9726
  startPoint.y = tmp;
8402
9727
  return new Vector(linePoint, startPoint.add(this.a));
8403
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
+ };
8404
9742
  Vector.utils = {
8405
9743
  /**
8406
9744
  * Generate a four-point arrow head, starting at the vector end minus the
@@ -8460,7 +9798,13 @@ exports.Vector = Vector;
8460
9798
  * @modified 2021-01-20 Added UID.
8461
9799
  * @modified 2022-02-02 Added the `destroy` method.
8462
9800
  * @modified 2023-09-29 Fixed a calculation error in the VertTuple.hasPoint() function; distance measure was broken!
8463
- * @version 1.2.1
9801
+ * @modified 2024-09-10 Chaging the first param of `pointDistance` from `Vertex` to less strict type `XYCoords`. This should not break anything.
9802
+ * @modified 2024-09-10 Adding the optional `epsilon` param to the `hasPoint` method.
9803
+ * @modified 2024-12-02 Added the `epsilon` param to the `colinear` method. Default is 1.0e-6.
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
8464
9808
  */
8465
9809
  Object.defineProperty(exports, "__esModule", ({ value: true }));
8466
9810
  exports.VertTuple = void 0;
@@ -8529,15 +9873,31 @@ var VertTuple = /** @class */ (function () {
8529
9873
  *
8530
9874
  * @method add
8531
9875
  * @param {XYCoords} amount The amount (x,y) to add.
8532
- * @return {Line} this
8533
9876
  * @instance
8534
9877
  * @memberof VertTuple
9878
+ * @return {VertTuple<T>} this
8535
9879
  **/
8536
9880
  VertTuple.prototype.add = function (amount) {
8537
9881
  this.a.add(amount);
8538
9882
  this.b.add(amount);
8539
9883
  return this;
8540
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
+ };
8541
9901
  /**
8542
9902
  * Normalize this line (set to length 1).
8543
9903
  *
@@ -8567,7 +9927,7 @@ var VertTuple = /** @class */ (function () {
8567
9927
  * Move this line to a new location.
8568
9928
  *
8569
9929
  * @method moveTo
8570
- * @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.
8571
9931
  * @return {VertTuple} this
8572
9932
  * @instance
8573
9933
  * @memberof VertTuple
@@ -8578,6 +9938,20 @@ var VertTuple = /** @class */ (function () {
8578
9938
  this.b.add(diff);
8579
9939
  return this;
8580
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
+ };
8581
9955
  /**
8582
9956
  * Get the angle between this and the passed line (in radians).
8583
9957
  *
@@ -8635,12 +10009,13 @@ var VertTuple = /** @class */ (function () {
8635
10009
  *
8636
10010
  * @method colinear
8637
10011
  * @param {VertTuple} line
10012
+ * @param {epsilon?=1.0e-6} epsilon - The epsilon to use (default is 1.0e-6).
8638
10013
  * @instance
8639
10014
  * @memberof VertTuple
8640
10015
  * @return true if both lines are co-linear.
8641
10016
  */
8642
- VertTuple.prototype.colinear = function (line) {
8643
- return Math.abs(this.denominator(line)) < Vertex_1.Vertex.EPSILON;
10017
+ VertTuple.prototype.colinear = function (line, epsilon) {
10018
+ return Math.abs(this.denominator(line)) < (typeof epsilon === "undefined" ? Vertex_1.Vertex.EPSILON : epsilon);
8644
10019
  };
8645
10020
  /**
8646
10021
  * Get the closest position T from this line to the specified point.
@@ -8669,21 +10044,22 @@ var VertTuple = /** @class */ (function () {
8669
10044
  * that point is located between point `a` and `b`.
8670
10045
  *
8671
10046
  * @method hasPoint
8672
- * @param {Vertex} point The point to check.
8673
- * @param {boolean=} insideBoundsOnly If set to to true (default=false) the point must be between start and end point of the line.
10047
+ * @param {Vertex} point - The point to check.
10048
+ * @param {boolean=} insideBoundsOnly - [optional] If set to to true (default=false) the point must be between start and end point of the line.
10049
+ * @param {number=Vertex.EPSILON} epsilon - [optional] A tolerance.
8674
10050
  * @return {boolean} True if the given point is on this line.
8675
10051
  * @instance
8676
10052
  * @memberof VertTuple
8677
10053
  */
8678
- VertTuple.prototype.hasPoint = function (point, insideBoundsOnly) {
10054
+ VertTuple.prototype.hasPoint = function (point, insideBoundsOnly, epsilon) {
8679
10055
  var t = this.getClosestT(point);
8680
10056
  // Compare to pointDistance?
8681
10057
  var distance = Math.sqrt(VertTuple.vtutils.dist2(point, this.vertAt(t)));
8682
10058
  if (typeof insideBoundsOnly !== "undefined" && insideBoundsOnly) {
8683
- return distance < Vertex_1.Vertex.EPSILON && t >= 0 && t <= 1;
10059
+ return distance < (epsilon !== null && epsilon !== void 0 ? epsilon : Vertex_1.Vertex.EPSILON) && t >= 0 && t <= 1;
8684
10060
  }
8685
10061
  else {
8686
- return distance < Vertex_1.Vertex.EPSILON; // t >= 0 && t <= 1;
10062
+ return distance < (epsilon !== null && epsilon !== void 0 ? epsilon : Vertex_1.Vertex.EPSILON); // t >= 0 && t <= 1;
8687
10063
  }
8688
10064
  };
8689
10065
  /**
@@ -8703,7 +10079,7 @@ var VertTuple = /** @class */ (function () {
8703
10079
  * The the minimal distance between this line and the specified point.
8704
10080
  *
8705
10081
  * @method pointDistance
8706
- * @param {Vertex} p The point (vertex) to measre the distance to.
10082
+ * @param {XYCoords} p The point (vertex) to measre the distance to.
8707
10083
  * @return {number} The absolute minimal distance.
8708
10084
  * @instance
8709
10085
  * @memberof VertTuple
@@ -8798,7 +10174,10 @@ exports.VertTuple = VertTuple;
8798
10174
  * @modified 2023-09-29 Downgraded types for the `Vertex.utils.buildArrowHead` function (replacing Vertex params by more generic XYCoords type).
8799
10175
  * @modified 2023-09-29 Added the `Vertex.abs()` method as it seems useful.
8800
10176
  * @modified 2024-03-08 Added the optional `precision` param to the `toString` method.
8801
- * @version 2.9.0
10177
+ * @modified 2024-12-17 Outsourced the euclidean distance calculation of `Vertex.distance` to `geomutils.dist4`.
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
8802
10181
  *
8803
10182
  * @file Vertex
8804
10183
  * @public
@@ -8808,6 +10187,7 @@ exports.Vertex = void 0;
8808
10187
  var VertexAttr_1 = __webpack_require__(476);
8809
10188
  var UIDGenerator_1 = __webpack_require__(938);
8810
10189
  var VertexListeners_1 = __webpack_require__(934);
10190
+ var geomutils_1 = __webpack_require__(328);
8811
10191
  /**
8812
10192
  * @classdesc A vertex is a pair of two numbers.<br>
8813
10193
  * <br>
@@ -8994,6 +10374,21 @@ var Vertex = /** @class */ (function () {
8994
10374
  }
8995
10375
  return this;
8996
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
+ };
8997
10392
  /**
8998
10393
  * Add the passed amounts to the x- and y- components of this vertex.
8999
10394
  *
@@ -9151,7 +10546,8 @@ var Vertex = /** @class */ (function () {
9151
10546
  * @memberof Vertex
9152
10547
  **/
9153
10548
  Vertex.prototype.distance = function (vert) {
9154
- return Math.sqrt(Math.pow(vert.x - this.x, 2) + Math.pow(vert.y - this.y, 2));
10549
+ // return Math.sqrt(Math.pow(vert.x - this.x, 2) + Math.pow(vert.y - this.y, 2));
10550
+ return geomutils_1.geomutils.dist4(this.x, this.y, vert.x, vert.y);
9155
10551
  };
9156
10552
  /**
9157
10553
  * Get the angle of this point (relative to (0,0) or to the given other origin point).
@@ -9832,6 +11228,7 @@ exports.VertexListeners = VertexListeners;
9832
11228
  * @modified 2023-09-29 Added the `lineDashes` attribute.
9833
11229
  * @modified 2023-09-30 Adding `strokeOptions` param to these draw function: line, arrow, cubicBezierArrow, cubicBezier, cubicBezierPath, circle, circleArc, ellipse, square, rect, polygon, polyline.
9834
11230
  * @modified 2023-10-07 Adding the optional `arrowHeadBasePositionBuffer` param to the arrowHead(...) method.
11231
+ * @modified 2024-09-13 Remoed the scaling of `lineWidth` in the `polygon` and `polyline` methods. This makes no sense here and doesn't match up with the behavior of other line functions.
9835
11232
  * @version 1.13.0
9836
11233
  **/
9837
11234
  Object.defineProperty(exports, "__esModule", ({ value: true }));
@@ -10762,7 +12159,7 @@ var drawutils = /** @class */ (function () {
10762
12159
  this.ctx.save();
10763
12160
  this.applyStrokeOpts(strokeOptions);
10764
12161
  this.ctx.beginPath();
10765
- this.ctx.lineWidth = (lineWidth || 1.0) * this.scale.x;
12162
+ this.ctx.lineWidth = lineWidth || 1.0;
10766
12163
  this.ctx.moveTo(this.offset.x + vertices[0].x * this.scale.x, this.offset.y + vertices[0].y * this.scale.y);
10767
12164
  for (var i = 0; i < vertices.length; i++) {
10768
12165
  this.ctx.lineTo(this.offset.x + vertices[i].x * this.scale.x, this.offset.y + vertices[i].y * this.scale.y);
@@ -12690,6 +14087,30 @@ var drawutilssvg = /** @class */ (function () {
12690
14087
  * @memberof drawutilssvg
12691
14088
  */
12692
14089
  drawutilssvg.prototype.grid = function (center, width, height, sizeX, sizeY, color) {
14090
+ // console.log("grid");
14091
+ // const node: SVGElement = this.makeNode("pattern");
14092
+ // var patternId = "pattern_id_" + Math.floor(Math.random() * 65365);
14093
+ // node.setAttribute("id", patternId);
14094
+ // node.setAttribute("viewBox", `0,0,${sizeX},${sizeY}`);
14095
+ // node.setAttribute("width", `${sizeX}`);
14096
+ // node.setAttribute("height", `${sizeX}`);
14097
+ // var pattern: SVGElement = this.makeNode("path");
14098
+ // const d: SVGPathParams = [];
14099
+ // d.push("M", sizeX / 2.0, 0);
14100
+ // d.push("L", sizeX / 2.0, sizeY);
14101
+ // d.push("M", 0, sizeY / 2.0);
14102
+ // d.push("L", sizeX, sizeY / 2.0);
14103
+ // node.setAttribute("d", d.join(" "));
14104
+ // this.bufferedNodeDefs.append(pattern);
14105
+ // const fillNode: SVGElement = this.makeNode("rect");
14106
+ // // For some strange reason SVG rotation transforms use degrees instead of radians
14107
+ // // Note that the background does not scale with the zoom level (always covers full element)
14108
+ // fillNode.setAttribute("x", "0");
14109
+ // fillNode.setAttribute("y", "0");
14110
+ // fillNode.setAttribute("width", `${this.canvasSize.width}`);
14111
+ // fillNode.setAttribute("height", `${this.canvasSize.height}`);
14112
+ // fillNode.setAttribute("fill", `url(#${patternId})`);
14113
+ // return this._bindFillDraw(fillNode, "grid", "red", 1);
12693
14114
  var node = this.makeNode("path");
12694
14115
  var d = [];
12695
14116
  var yMin = -Math.ceil((height * 0.5) / sizeY) * sizeY;
@@ -13415,7 +14836,10 @@ exports.drawutilssvg = drawutilssvg;
13415
14836
  * @author Ikaros Kappler
13416
14837
  * @date 2019-02-03
13417
14838
  * @modified 2021-03-01 Added `wrapMax` function.
13418
- * @version 1.1.0
14839
+ * @modified 2024-11-15 Adding helper function `geomutils.mapAngleTo2PI(number)` for mapping any value into the interval [0,2*PI).
14840
+ * @modified 2024-11-22 Adding helper function `geomutils.dotProduct(number)` for calculating the dot product of two vertices (as vectors).
14841
+ *
14842
+ * @version 1.2.0
13419
14843
  **/
13420
14844
  Object.defineProperty(exports, "__esModule", ({ value: true }));
13421
14845
  exports.geomutils = void 0;
@@ -13427,6 +14851,49 @@ var Triangle_1 = __webpack_require__(737);
13427
14851
  * @global
13428
14852
  **/
13429
14853
  exports.geomutils = {
14854
+ /**
14855
+ * Map any angle (any numeric value) to [0, Math.PI).
14856
+ *
14857
+ * @param {number} angle - The numeric value to map.
14858
+ * @return {number} The mapped angle inside [0,PI*2].
14859
+ **/
14860
+ mapAngleTo2PI: function (angle) {
14861
+ // Source: https://forums.codeguru.com/showthread.php?384172-get-angle-into-range-0-2*pi
14862
+ var new_angle = Math.asin(Math.sin(angle));
14863
+ if (Math.cos(angle) < 0) {
14864
+ return Math.PI - new_angle;
14865
+ }
14866
+ else if (new_angle < 0) {
14867
+ return new_angle + 2 * Math.PI;
14868
+ }
14869
+ else {
14870
+ return new_angle;
14871
+ }
14872
+ },
14873
+ /**
14874
+ * Calculate the euclidean distance between two points given by four coordinates (two coordinates each).
14875
+ *
14876
+ * @param {number} x1
14877
+ * @param {number} y1
14878
+ * @param {number} x2
14879
+ * @param {number} y2
14880
+ * @returns {number}
14881
+ */
14882
+ dist4: function (x1, y1, x2, y2) {
14883
+ return Math.sqrt(Math.pow(x2 - x1, 2) + Math.pow(y1 - y2, 2));
14884
+ },
14885
+ /**
14886
+ * Map any angle (any numeric value) to [0, Math.PI).
14887
+ *
14888
+ * A × B := (A.x * B.x) + (A.y * B.y)
14889
+ *
14890
+ * @param {XYCoords} vertA - The first vertex.
14891
+ * @param {XYCoords} vertB - The second vertex.
14892
+ * @return {number} The dot product of the two vertices.
14893
+ **/
14894
+ dotProduct: function (vertA, vertB) {
14895
+ return vertA.x * vertB.x + vertA.y * vertB.y;
14896
+ },
13430
14897
  /**
13431
14898
  * Compute the n-section of the angle – described as a triangle (A,B,C) – in point A.
13432
14899
  *