plotboilerplate 1.29.0 → 1.31.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 (80) hide show
  1. package/README.md +26 -13
  2. package/dist/index.esm.js +310 -57
  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 +266 -36
  9. package/dist/plotboilerplate.min.js +1 -1
  10. package/package.json +1 -1
  11. package/src/cjs/Circle.d.ts +17 -1
  12. package/src/cjs/Circle.js +21 -1
  13. package/src/cjs/Circle.js.map +1 -1
  14. package/src/cjs/CubicBezierCurve.d.ts +34 -3
  15. package/src/cjs/CubicBezierCurve.js +79 -12
  16. package/src/cjs/CubicBezierCurve.js.map +1 -1
  17. package/src/cjs/Line.d.ts +46 -1
  18. package/src/cjs/Line.js +80 -1
  19. package/src/cjs/Line.js.map +1 -1
  20. package/src/cjs/Polygon.d.ts +18 -4
  21. package/src/cjs/Polygon.js +56 -18
  22. package/src/cjs/Polygon.js.map +1 -1
  23. package/src/cjs/VertTuple.d.ts +24 -2
  24. package/src/cjs/VertTuple.js +28 -2
  25. package/src/cjs/VertTuple.js.map +1 -1
  26. package/src/cjs/Vertex.d.ts +2 -2
  27. package/src/cjs/Vertex.js +2 -2
  28. package/src/cjs/utils/algorithms/delaunay2voronoi.d.ts +2 -1
  29. package/src/cjs/utils/algorithms/delaunay2voronoi.js +8 -10
  30. package/src/cjs/utils/algorithms/delaunay2voronoi.js.map +1 -1
  31. package/src/cjs/utils/datastructures/PointSet.d.ts +63 -0
  32. package/src/cjs/utils/datastructures/PointSet.js +126 -0
  33. package/src/cjs/utils/datastructures/PointSet.js.map +1 -0
  34. package/src/cjs/utils/datastructures/VoronoiCell.d.ts +19 -2
  35. package/src/cjs/utils/datastructures/VoronoiCell.js +39 -12
  36. package/src/cjs/utils/datastructures/VoronoiCell.js.map +1 -1
  37. package/src/cjs/utils/renderers/VoronoiRenderer.d.ts +99 -0
  38. package/src/cjs/utils/renderers/VoronoiRenderer.js +147 -0
  39. package/src/cjs/utils/renderers/VoronoiRenderer.js.map +1 -0
  40. package/src/esm/Circle.d.ts +17 -1
  41. package/src/esm/Circle.js +21 -1
  42. package/src/esm/Circle.js.map +1 -1
  43. package/src/esm/CubicBezierCurve.d.ts +34 -3
  44. package/src/esm/CubicBezierCurve.js +79 -12
  45. package/src/esm/CubicBezierCurve.js.map +1 -1
  46. package/src/esm/Line.d.ts +46 -1
  47. package/src/esm/Line.js +80 -1
  48. package/src/esm/Line.js.map +1 -1
  49. package/src/esm/Polygon.d.ts +18 -4
  50. package/src/esm/Polygon.js +56 -18
  51. package/src/esm/Polygon.js.map +1 -1
  52. package/src/esm/VertTuple.d.ts +24 -2
  53. package/src/esm/VertTuple.js +28 -2
  54. package/src/esm/VertTuple.js.map +1 -1
  55. package/src/esm/Vertex.d.ts +2 -2
  56. package/src/esm/Vertex.js +2 -2
  57. package/src/esm/utils/algorithms/delaunay2voronoi.d.ts +2 -1
  58. package/src/esm/utils/algorithms/delaunay2voronoi.js +8 -10
  59. package/src/esm/utils/algorithms/delaunay2voronoi.js.map +1 -1
  60. package/src/esm/utils/datastructures/PointSet.d.ts +63 -0
  61. package/src/esm/utils/datastructures/PointSet.js +115 -0
  62. package/src/esm/utils/datastructures/PointSet.js.map +1 -0
  63. package/src/esm/utils/datastructures/VoronoiCell.d.ts +19 -2
  64. package/src/esm/utils/datastructures/VoronoiCell.js +39 -12
  65. package/src/esm/utils/datastructures/VoronoiCell.js.map +1 -1
  66. package/src/esm/utils/renderers/VoronoiRenderer.d.ts +99 -0
  67. package/src/esm/utils/renderers/VoronoiRenderer.js +142 -0
  68. package/src/esm/utils/renderers/VoronoiRenderer.js.map +1 -0
  69. package/src/index-gl.js +1 -2
  70. package/src/ts/Circle.ts +23 -1
  71. package/src/ts/CubicBezierCurve.ts +133 -48
  72. package/src/ts/Line.ts +84 -1
  73. package/src/ts/Polygon.ts +58 -18
  74. package/src/ts/VertTuple.ts +30 -2
  75. package/src/ts/Vertex.ts +2 -2
  76. package/src/ts/utils/_AppContext.ts_ +22 -0
  77. package/src/ts/utils/algorithms/delaunay2voronoi.ts +81 -88
  78. package/src/ts/utils/datastructures/PointSet.ts +135 -0
  79. package/src/ts/utils/datastructures/VoronoiCell.ts +198 -169
  80. package/src/ts/utils/renderers/VoronoiRenderer.ts +200 -0
package/dist/index.esm.js CHANGED
@@ -356,7 +356,8 @@ class VertexListeners {
356
356
  * @modified 2026-07-08 Adding the `Circle.setRadius` method (for chaining).
357
357
  * @mofified 2026-07-31 Adding the `radicalAxis(Circle)` method. Added the `Circle.circleUtils.createRadicalAxisHelperCircle` and `.circleDistance` helper methods.
358
358
  * @modified 2026-08-03 Adding `Circle.tangentsFromPoint`.
359
- * @version 1.7.0
359
+ * @modified 2026-08-16 Adding the `Circle.sectorAngleByArcLength` method and the `Circle.circleUtils.sectorAngleByArcLength` helper method.
360
+ * @version 1.8.0
360
361
  **/
361
362
  /**
362
363
  * @classdesc A simple circle: center point and radius.
@@ -731,6 +732,15 @@ class Circle {
731
732
  }
732
733
  return [new Vector(intersection.a, vert), new Vector(intersection.b, vert)];
733
734
  }
735
+ /**
736
+ * Calculate inner sector angle for this circle and a given circle arc length.
737
+ *
738
+ * @param {number} sectorArcLength - The desired arc length (in units).
739
+ * @returns The sector's inner angle (in radians).
740
+ */
741
+ sectorAngleByArcLength(sectorArcLength) {
742
+ return Circle.circleUtils.sectorAngleByArcLength(sectorArcLength, this.radius);
743
+ }
734
744
  /**
735
745
  * Create a deep copy of this circle.
736
746
  *
@@ -809,6 +819,16 @@ Circle.circleUtils = {
809
819
  */
810
820
  circleDistance: (circleA, circleB) => {
811
821
  return circleA.center.distance(circleB.center) - circleA.radius - circleB.radius;
822
+ },
823
+ /**
824
+ * Calculate the inner sector angle for a given circle arc length and radius.
825
+ *
826
+ * @param {number} sectorArcLength - The desired arc length.
827
+ * @param {number} circleRadius - The circle's radius.
828
+ * @returns The sector angle in radians.
829
+ */
830
+ sectorAngleByArcLength: (sectorArcLength, circleRadius) => {
831
+ return sectorArcLength / circleRadius;
812
832
  }
813
833
  };
814
834
 
@@ -1548,7 +1568,7 @@ const geomutils = {
1548
1568
  * @modified 2025-04-13 Adding the `Vertex.move(amount: XYCoords)` method (does the same as `add`, added by naming convention).
1549
1569
  * @modified 2025-05-07 Class `Vertex` is now implementing interface `IBounded` (to meet convention).
1550
1570
  * @modified 2026-06-10 Adding methods `Vertex.findClosestPoint` and `Vertex.findFarestPoint`.
1551
- * @version 2.12.0
1571
+ * @version 2.12.1
1552
1572
  *
1553
1573
  * @file Vertex
1554
1574
  * @public
@@ -2019,7 +2039,7 @@ class Vertex$1 {
2019
2039
  * around given center.
2020
2040
  *
2021
2041
  * @method rotate
2022
- * @param {number} angle - The angle to 'rotate' this vertex; 0.0 means no change.
2042
+ * @param {number} angle - The angle in radians to 'rotate' this vertex; 0.0 means no change.
2023
2043
  * @param {XYCoords=} center - The center of rotation; default is (0,0).
2024
2044
  * @return {Vertex} this
2025
2045
  * @instance
@@ -2263,7 +2283,9 @@ Vertex$1.utils = {
2263
2283
  * @modified 2025-04-15 Changed param of `VertTuple.moveTo` method from `Vertex` to `XYCoords`.
2264
2284
  * @modified 2025-04-15 Added method `VertTuple.move` method.
2265
2285
  * @modified 2026-06-10 Adding helper function `VertTuple.utils.calcCircumcircle`.
2266
- * @version 1.5.0
2286
+ * @modified 2026-06-17 Adding method `VertTuple.asLine` for converting TertTuples to Line instances.
2287
+ * @modified 2026-09-21 Adding method `VertTuple.asVector` for converting TertTuples to Vector instances.
2288
+ * @version 1.7.0
2267
2289
  */
2268
2290
  /**
2269
2291
  * @classdesc An abstract base classes for vertex tuple constructs, like Lines or Vectors.
@@ -2547,7 +2569,7 @@ class VertTuple {
2547
2569
  /**
2548
2570
  * Create a deep clone of this instance.
2549
2571
  *
2550
- * @method cloneLine
2572
+ * @method clone
2551
2573
  * @return {T} A type safe clone if this instance.
2552
2574
  * @instance
2553
2575
  * @memberof VertTuple
@@ -2555,6 +2577,28 @@ class VertTuple {
2555
2577
  clone() {
2556
2578
  return this.factory(this.a.clone(), this.b.clone());
2557
2579
  }
2580
+ /**
2581
+ * Converts this `VertTuple` to a `Line` (segment).
2582
+ *
2583
+ * @method asLine
2584
+ * @return {Line} This tuple as `Line` instance.
2585
+ * @instance
2586
+ * @memberof VertTuple
2587
+ **/
2588
+ asLine() {
2589
+ return new Line(this.a, this.b);
2590
+ }
2591
+ /**
2592
+ * Converts this `VertTuple` to a `Vector` (arrow).
2593
+ *
2594
+ * @method asVector
2595
+ * @return {Line} This tuple as `Vector` instance.
2596
+ * @instance
2597
+ * @memberof VertTuple
2598
+ **/
2599
+ asVector() {
2600
+ return new Vector(this.a, this.b);
2601
+ }
2558
2602
  /**
2559
2603
  * Create a string representation of this line.
2560
2604
  *
@@ -2785,7 +2829,8 @@ Vector.utils = {
2785
2829
  * @modified 2023-09-25 Changed param type of `intersection()` from Line to VertTuple.
2786
2830
  * @modified 2025-04-15 Class `Line` now implements interface `Intersectable`.
2787
2831
  * @modified 2025-04-16 Class `Line` now implements interface `IBounded`.
2788
- * @version 2.4.0
2832
+ * @modified 2026-08-16 Adding methods `Line.trimStart` and `Line.trimEnd`. Adding methods `Line.trimStartAt` and `Line.trimEndAt`.
2833
+ * @version 2.5.0
2789
2834
  *
2790
2835
  * @file Line
2791
2836
  * @public
@@ -2912,6 +2957,84 @@ class Line extends VertTuple {
2912
2957
  return this;
2913
2958
  }
2914
2959
  //--- END Implement PathSegment ---
2960
+ /**
2961
+ * Trim this line segment from the start point by the given amount.
2962
+ * The amount must be positive and should be withing the segment's length. If the amount exceeds the segment's length
2963
+ * then the length of the resulting line will be zero (0.0).
2964
+ *
2965
+ * @method trimStart
2966
+ * @memberof Line
2967
+ * @param {number} amount - The positive amount to trim the line from the start point `a`.
2968
+ * @returns {Line} This for chaining, with updated point `a`.
2969
+ */
2970
+ trimStart(amount) {
2971
+ // Calculate the relative position `t` on this line.
2972
+ var t = amount / this.length();
2973
+ // `t` should be inside 0..1 – otherwise the amount was too large or negative.
2974
+ if (t < 0.0) {
2975
+ return this;
2976
+ }
2977
+ if (t > 1.0) {
2978
+ // Set the line to length zero (endpoint only)
2979
+ this.a = this.b.clone();
2980
+ return this;
2981
+ }
2982
+ this.a = this.vertAt(t);
2983
+ return this;
2984
+ }
2985
+ /**
2986
+ * Trim this line segment from the start point by the given relative amount.
2987
+ * The amount must be positive and should be within 0.0 and 1.0. If the amount exceeds the segment's length
2988
+ * then the length of the resulting line will be zero (0.0).
2989
+ *
2990
+ * @method trimStartAt
2991
+ * @memberof Line
2992
+ * @param {number} amount - The positive amount to trim the line from the start point `a`.
2993
+ * @returns {Line} This for chaining, with updated point `a`.
2994
+ */
2995
+ trimStartAt(relativeAmount) {
2996
+ // Calculate the relative position `t` on this line.
2997
+ return this.trimStart(relativeAmount * this.length());
2998
+ }
2999
+ /**
3000
+ * Trim this line segment from the end point by the given amount.
3001
+ * The amount must be positive and should be withing the segment's length. If the amount exceeds the segment's length
3002
+ * then the length of the resulting line will be zero (0.0).
3003
+ *
3004
+ * @method trimEnd
3005
+ * @memberof Line
3006
+ * @param {number} amount - The positive amount to trim the line from the end point `b`.
3007
+ * @returns {Line} This for chaining, with updated point `b`.
3008
+ */
3009
+ trimEnd(amount) {
3010
+ // Calculate the relative position `t` on this line.
3011
+ var t = 1.0 - amount / this.length();
3012
+ // `t` should be inside 0..1 – otherwise the amount was too large or negative.
3013
+ if (t < 0.0) {
3014
+ return this;
3015
+ }
3016
+ if (t > 1.0) {
3017
+ // Set the line to length zero (endpoint only)
3018
+ this.b = this.a.clone();
3019
+ return this;
3020
+ }
3021
+ this.b = this.vertAt(t);
3022
+ return this;
3023
+ }
3024
+ /**
3025
+ * Trim this line segment from the end point by the given relative amount.
3026
+ * The amount must be positive and should be within 0.0 and 1.0. If the amount exceeds the segment's length
3027
+ * then the length of the resulting line will be zero (0.0).
3028
+ *
3029
+ * @method trimEndAt
3030
+ * @memberof Line
3031
+ * @param {number} amount - The positive amount to trim the line from the start point `a`.
3032
+ * @returns {Line} This for chaining, with updated point `a`.
3033
+ */
3034
+ trimEndAt(relativeAmount) {
3035
+ // Calculate the relative position `t` on this line.
3036
+ return this.trimEnd(relativeAmount * this.length());
3037
+ }
2915
3038
  //--- BEGIN --- Implement interface `Intersectable`
2916
3039
  /**
2917
3040
  * Get all line intersections with this polygon.
@@ -2997,7 +3120,9 @@ class Line extends VertTuple {
2997
3120
  * @modified 2025-05-16 Class `Polygon` now implements `IBounded`.
2998
3121
  * @modified 2025-05-20 Tweaking `Polygon.getInnerAngleAt` and `Polygo.isAngleAcute` to handle indices out of array bounds as well.
2999
3122
  * @modified 2025-06-07 Adding `Polygon.closestLineIntersectionIndex` to determine line intersections plus detected edge index.
3000
- * @version 1.16.0
3123
+ * @modified 2026-09-16 Adding a `forceClockwise` parameter to the `Polygon.getCentroid()` method.
3124
+ * @modified 2026-09-21 Adding `Polygon.revert` method to change the winding order.
3125
+ * @version 1.17.0
3001
3126
  *
3002
3127
  * @file Polygon
3003
3128
  * @public
@@ -3291,6 +3416,20 @@ class Polygon {
3291
3416
  // return Polygon.utils.signedArea(this.vertices) < 0;
3292
3417
  return Polygon.utils.isClockwise(this.vertices);
3293
3418
  }
3419
+ /**
3420
+ * Revert the order of this polygon's vertices to change the winding order.
3421
+ * This operation is in-place.
3422
+ *
3423
+ * @method revert
3424
+ * @instance
3425
+ * @memberof Polygon
3426
+ * @return {Polygon} This for chaining.
3427
+ */
3428
+ revert() {
3429
+ // this.vertices.slice().reverse(); // Copy?
3430
+ this.vertices.reverse();
3431
+ return this;
3432
+ }
3294
3433
  /**
3295
3434
  * Get the perimeter of this polygon.
3296
3435
  * The perimeter is the absolute length of the outline.
@@ -3372,35 +3511,37 @@ class Polygon {
3372
3511
  }
3373
3512
  /**
3374
3513
  * Get centroid.
3375
- * Centroids define the barycenter of any non self-intersecting convex polygon.
3514
+ * Centroids define the barycenter of any non self-intersecting convex clockwise polygon.
3376
3515
  *
3377
- * If the polygon is self intersecting or non konvex then the barycenter is not well defined.
3516
+ * If the polygon is self intersecting or non convex or not clockwise then the barycenter is not well defined.
3378
3517
  *
3379
3518
  * https://mathworld.wolfram.com/PolygonCentroid.html
3380
3519
  *
3381
3520
  * @method getCentroid
3382
3521
  * @instance
3522
+ * @param {boolean} forceClockwise - [optiona] If set to true then the centroid will be calculated for the clockwise polygon.
3383
3523
  * @memberof Polygon
3384
3524
  * @returns {Vertex|null}
3385
3525
  */
3386
- getCentroid() {
3526
+ getCentroid(forceClockwise) {
3387
3527
  if (this.vertices.length === 0) {
3388
3528
  return null;
3389
3529
  }
3390
- const center = new Vertex$1(0.0, 0.0);
3391
- const n = this.vertices.length;
3392
- for (var i = 0; i < n; i++) {
3393
- // center.add(this.vertices[i]);
3394
- const cur = this.vertices[i];
3395
- const next = this.vertices[(i + 1) % n];
3396
- var factor = cur.x * next.y - next.x * cur.y;
3397
- center.x += (cur.x + next.x) * factor;
3398
- center.y += (cur.y + next.y) * factor;
3399
- }
3400
- const area = this.area();
3401
- center.x *= 1 / (6 * area);
3402
- center.y *= 1 / (6 * area);
3403
- return center;
3530
+ // const centroid: Vertex = new Vertex(0.0, 0.0);
3531
+ // const n = this.vertices.length;
3532
+ // for (var i = 0; i < n; i++) {
3533
+ // // center.add(this.vertices[i]);
3534
+ // const cur: Vertex = this.vertices[i];
3535
+ // const next: Vertex = this.vertices[(i + 1) % n];
3536
+ // var factor: number = cur.x * next.y - next.x * cur.y;
3537
+ // centroid.x += (cur.x + next.x) * factor;
3538
+ // centroid.y += (cur.y + next.y) * factor;
3539
+ // }
3540
+ // const area = this.area();
3541
+ // centroid.x *= 1 / (6 * area);
3542
+ // centroid.y *= 1 / (6 * area);
3543
+ // return centroid;
3544
+ return Polygon.utils.calculateCentroid(this.vertices, forceClockwise);
3404
3545
  }
3405
3546
  //--- BEGIN --- Implement interface `Intersectable`
3406
3547
  /**
@@ -3825,6 +3966,26 @@ Polygon.utils = {
3825
3966
  isClockwise(vertices) {
3826
3967
  return Polygon.utils.signedArea(vertices) < 0;
3827
3968
  },
3969
+ calculateCentroid(vertices, forceClockwise) {
3970
+ const centroid = new Vertex$1(0.0, 0.0);
3971
+ const n = vertices.length;
3972
+ if (forceClockwise && !Polygon.utils.isClockwise(vertices)) {
3973
+ return Polygon.utils.calculateCentroid(vertices.slice().reverse());
3974
+ }
3975
+ for (var i = 0; i < n; i++) {
3976
+ // center.add(this.vertices[i]);
3977
+ const cur = vertices[i];
3978
+ const next = vertices[(i + 1) % n];
3979
+ var factor = cur.x * next.y - next.x * cur.y;
3980
+ centroid.x += (cur.x + next.x) * factor;
3981
+ centroid.y += (cur.y + next.y) * factor;
3982
+ }
3983
+ // const area = this.area();
3984
+ const area = Polygon.utils.area(vertices);
3985
+ centroid.x *= 1 / (6 * area);
3986
+ centroid.y *= 1 / (6 * area);
3987
+ return centroid;
3988
+ },
3828
3989
  /**
3829
3990
  * Calulate the signed polyon area by interpreting the polygon as a matrix
3830
3991
  * and calculating its determinant.
@@ -4214,8 +4375,9 @@ class Bounds {
4214
4375
  * @modified 2025-04-18 Added evaluation method for cubic Bézier curves `CubicBezierCurve.utils.evaluateT`.
4215
4376
  * @modified 2025-04-18 Refactored method `CubicBezierCurve.getPointAt` to use `evaluateT`.
4216
4377
  * @modified 2025-04-18 Fixed the `CubicBezierCurve.getBounds` method: now returning the real bounding box. Before it was an approximated one.
4217
- * @modified 2025-ß4-18 Added helper methods for bounding box calculation `CubucBezierCurve.util.cubicPolyMinMax` and `cubicPoly`.
4218
- * @version 2.9.0
4378
+ * @modified 2025-04-18 Added helper methods for bounding box calculation `CubucBezierCurve.util.cubicPolyMinMax` and `cubicPoly`.
4379
+ * @modified 2026-09-09 Adding methods `CubicBezierCurve.trimStartEnd` and `CubicBezierCurve.trimStartEndAt`.
4380
+ * @version 2.10.0
4219
4381
  *
4220
4382
  * @file CubicBezierCurve
4221
4383
  * @public
@@ -4664,6 +4826,7 @@ class CubicBezierCurve {
4664
4826
  this.endControlPoint.set(subCurbePoints[3]);
4665
4827
  this.updateArcLengths();
4666
4828
  return this;
4829
+ // return this.trimStartEndAt(t, null);
4667
4830
  }
4668
4831
  /**
4669
4832
  * Trim off the end of this curve. The position parameter `uValue` is the absolute position on the
@@ -4699,7 +4862,79 @@ class CubicBezierCurve {
4699
4862
  this.endControlPoint.set(subCurbePoints[3]);
4700
4863
  this.updateArcLengths();
4701
4864
  return this;
4865
+ // return this.trimStartEndAt(null, t);
4702
4866
  }
4867
+ /**
4868
+ * Trim off a start and end section of this curve. The position parameters `uStart` and `uEnd` are the absolute positions in [0..arcLength].
4869
+ * The remaining curve will be the one in the bounds `[uStart,uEnd]` (so `[0.0,uStart]` and `[uEnd,1.0]` are cut off).
4870
+ *
4871
+ * Parameters out of bounds (< 0.0 or > arcLength) are ignored.
4872
+ * If `uEnd` is smaller than `uStart` then a curve with length zero (0) at `uStart` is returned.
4873
+ *
4874
+ * @method trimStartEndAt
4875
+ * @instance
4876
+ * @memberof CubicBezierCurve
4877
+ * @param {number} tStart - The relative position parameter where to cut off the head curve.
4878
+ * @param {number} tEnd - The relative position parameter where to cut off the tail curve.
4879
+ * @returns {CubicBezierCurve} `this` for chanining.
4880
+ */
4881
+ trimStartEnd(uStart, uEnd) {
4882
+ return this.trimStartEndAt(this.convertU2T(uStart), this.convertU2T(uEnd));
4883
+ }
4884
+ /**
4885
+ * Trim off a start and end section of this curve. The position parameters `tStart` and `tEnd` are the relative positions in [0..1].
4886
+ * The remaining curve will be the one in the bounds `[tStart,tEnd]` (so `[0.0,tStart]` and `[tEnd,1.0]` are cut off).
4887
+ *
4888
+ * Parameters out of bounds (< 0.0 or > 1.0) are ignored.
4889
+ * If `tEnd` is smaller than `tStart` then a curve with length zero (0) at `tStart` is returned.
4890
+ *
4891
+ * @method trimStartEndAt
4892
+ * @instance
4893
+ * @memberof CubicBezierCurve
4894
+ * @param {number} tStart - The relative position parameter where to cut off the head curve.
4895
+ * @param {number} tEnd - The relative position parameter where to cut off the tail curve.
4896
+ * @returns {CubicBezierCurve} `this` for chanining.
4897
+ */
4898
+ trimStartEndAt(tStart, tEnd) {
4899
+ const cleanTrimStart = Math.min(Math.max(0.0, tStart), 1.0);
4900
+ const cleanTrimEnd = Math.min(Math.max(cleanTrimStart, tEnd), 1.0);
4901
+ this.trimStartAt(cleanTrimStart);
4902
+ const relativeTrimEnd = (cleanTrimEnd - cleanTrimStart) / (1.0 - cleanTrimStart);
4903
+ this.trimEndAt(relativeTrimEnd);
4904
+ return this;
4905
+ }
4906
+ // __trimStartEndAt(tStart: number, tEnd: number): CubicBezierCurve {
4907
+ // var finalCurvePoints = [
4908
+ // this.startPoint.clone(),
4909
+ // this.endPoint.clone(),
4910
+ // this.startControlPoint.clone(),
4911
+ // this.endControlPoint.clone()
4912
+ // ];
4913
+ // if (typeof tStart === "number" && !Number.isNaN(tStart)) {
4914
+ // const subCurvePointsStart = CubicBezierCurve.utils.getSubCurvePointsAt(this, tStart, 1.0);
4915
+ // finalCurvePoints[0].set(subCurvePointsStart[0]);
4916
+ // finalCurvePoints[2].set(subCurvePointsStart[2]);
4917
+ // // this.startPoint.set(subCurvePointsStart[0]);
4918
+ // // this.startControlPoint.set(subCurvePointsStart[2]);
4919
+ // // this.endPoint.set(subCurvePointsStart[1]);
4920
+ // // this.endControlPoint.set(subCurvePointsStart[3]);
4921
+ // }
4922
+ // if (typeof tEnd === "number" && !Number.isNaN(tEnd)) {
4923
+ // const subCurvePointsEnd = CubicBezierCurve.utils.getSubCurvePointsAt(this, 0.0, tEnd);
4924
+ // // this.startPoint.set(subCurvePointsEnd[0]);
4925
+ // // this.startControlPoint.set(subCurvePointsEnd[2]);
4926
+ // // this.endPoint.set(subCurvePointsEnd[1]);
4927
+ // // this.endControlPoint.set(subCurvePointsEnd[3]);
4928
+ // finalCurvePoints[1].set(subCurvePointsEnd[1]);
4929
+ // finalCurvePoints[3].set(subCurvePointsEnd[3]);
4930
+ // }
4931
+ // this.startPoint.set(finalCurvePoints[0]);
4932
+ // this.endPoint.set(finalCurvePoints[1]);
4933
+ // this.startControlPoint.set(finalCurvePoints[2]);
4934
+ // this.endControlPoint.set(finalCurvePoints[3]);
4935
+ // this.updateArcLengths();
4936
+ // return this;
4937
+ // }
4703
4938
  /**
4704
4939
  * Get a sub curve at the given start end end positions (values on the curve's length, between 0 and curve.arcLength).
4705
4940
  *
@@ -5051,10 +5286,7 @@ CubicBezierCurve.END_POINT = 3;
5051
5286
  */
5052
5287
  CubicBezierCurve.utils = {
5053
5288
  evaluateT: (p0, p1, p2, p3, t) => {
5054
- return p0 * Math.pow(1.0 - t, 3) +
5055
- p1 * 3 * t * Math.pow(1.0 - t, 2) +
5056
- p2 * 3 * Math.pow(t, 2) * (1.0 - t) +
5057
- p3 * Math.pow(t, 3);
5289
+ return (p0 * Math.pow(1.0 - t, 3) + p1 * 3 * t * Math.pow(1.0 - t, 2) + p2 * 3 * Math.pow(t, 2) * (1.0 - t) + p3 * Math.pow(t, 3));
5058
5290
  },
5059
5291
  cubicPolyMinMax: (p0, p1, p2, p3) => {
5060
5292
  // var polyX = CubicBezierCurve.utils.cubicPoly2(
@@ -5126,7 +5358,7 @@ CubicBezierCurve.utils = {
5126
5358
  * @param {number} tEnd – The end offset if the desired cub curve (must be in [0..1]).
5127
5359
  * @instance
5128
5360
  * @memberof CubicBezierCurve
5129
- * @return {CubicBezierCurve} The sub curve as a new curve.
5361
+ * @return {[Vertex, Vertex, Vertex, Vertex]} The sub curve as curve vertices.
5130
5362
  **/
5131
5363
  getSubCurvePointsAt: (curve, tStart, tEnd) => {
5132
5364
  const startVec = new Vector(curve.getPointAt(tStart), curve.getTangentAt(tStart));
@@ -5215,11 +5447,7 @@ CubicBezierCurve.utils = {
5215
5447
  * @returns {[number,number,number]}
5216
5448
  */
5217
5449
  cubicPoly: (p0, p1, p2, p3) => {
5218
- return [
5219
- 3 * p3 - 9 * p2 + 9 * p1 - 3 * p0,
5220
- 6 * p0 - 12 * p1 + 6 * p2,
5221
- 3 * p1 - 3 * p0
5222
- ];
5450
+ return [3 * p3 - 9 * p2 + 9 * p1 - 3 * p0, 6 * p0 - 12 * p1 + 6 * p2, 3 * p1 - 3 * p0];
5223
5451
  },
5224
5452
  /**
5225
5453
  * sign of number, but is division safe: no zero returned :)
@@ -19184,7 +19412,8 @@ class Delaunay {
19184
19412
  * @modified 2020-08-12 Ported this class from vanilla JS to TypeScript.
19185
19413
  * @modified 2020-08-17 Added some missing type declarations.
19186
19414
  * @modified 2021-01-20 Members `triangles` and `sharedVertex` are now public.
19187
- * @version 1.1.3
19415
+ * @modified 2026-09-15 Added the `VoronoiCell.sharedVertexIndex` attribute.
19416
+ * @version 1.2.0
19188
19417
  *
19189
19418
  * @file VoronoiCell
19190
19419
  * @public
@@ -19200,15 +19429,15 @@ class VoronoiCell {
19200
19429
  * @param {Vertex} sharedVertex This is the 'center' of the voronoi cell; all triangles must share
19201
19430
  * that vertex.
19202
19431
  **/
19203
- constructor(triangles, sharedVertex) {
19204
- if (typeof triangles === 'undefined')
19432
+ constructor(triangles, sharedVertex, sharedVertexIndex) {
19433
+ if (typeof triangles === "undefined")
19205
19434
  triangles = [];
19206
- if (typeof sharedVertex === 'undefined')
19435
+ if (typeof sharedVertex === "undefined")
19207
19436
  sharedVertex = new Vertex$1(0, 0);
19208
19437
  this.triangles = triangles;
19209
19438
  this.sharedVertex = sharedVertex;
19439
+ this.sharedVertexIndex = sharedVertexIndex;
19210
19440
  }
19211
- ;
19212
19441
  /**
19213
19442
  * Check if the first and the last triangle in the path are NOT connected.
19214
19443
  *
@@ -19221,7 +19450,6 @@ class VoronoiCell {
19221
19450
  // There must be at least three triangles
19222
19451
  return this.triangles.length < 3 || !this.triangles[0].isAdjacent(this.triangles[this.triangles.length - 1]);
19223
19452
  }
19224
- ;
19225
19453
  /**
19226
19454
  * Convert this Voronoi cell to a path polygon, consisting of all Voronoi cell corner points.
19227
19455
  *
@@ -19236,7 +19464,32 @@ class VoronoiCell {
19236
19464
  toPolygon() {
19237
19465
  return new Polygon(this.toPathArray(), this.isOpen());
19238
19466
  }
19239
- ;
19467
+ /**
19468
+ * Get all 'umbrella' triangles for this Voronoi cell.
19469
+ *
19470
+ * The 'umbrella' is that sequence of triangles that covers the whole Voronoi cell and
19471
+ * meet in the cell's centroid.
19472
+ *
19473
+ * @method getUmbrellaTriangles
19474
+ * @instance
19475
+ * @memberof VoronoiCell
19476
+ * @return {Array<Triangle>}
19477
+ **/
19478
+ getUmbrellaTriangles() {
19479
+ var tris = [];
19480
+ // for (var i = 0; i < this.triangles.length; i++) {
19481
+ // var delaunayTri = this.triangles[i];
19482
+ // var tri = new Triangle(this.sharedVertex, delaunayTri.b, delaunayTri.c);
19483
+ // tris.push(tri);
19484
+ // }
19485
+ var vertices = this.toPathArray();
19486
+ var n = vertices.length;
19487
+ for (var i = 0; i < n; i++) {
19488
+ var tri = new Triangle(this.sharedVertex, vertices[i], vertices[(i + 1) % n]);
19489
+ tris.push(tri);
19490
+ }
19491
+ return tris;
19492
+ }
19240
19493
  /**
19241
19494
  * Convert the voronoi cell path data to an SVG polygon data string.
19242
19495
  *
@@ -19251,9 +19504,12 @@ class VoronoiCell {
19251
19504
  if (this.triangles.length == 0)
19252
19505
  return "";
19253
19506
  const arr = this.toPathArray();
19254
- return arr.map((vert) => { return '' + vert.x + ',' + vert.y; }).join(' ');
19507
+ return arr
19508
+ .map((vert) => {
19509
+ return "" + vert.x + "," + vert.y;
19510
+ })
19511
+ .join(" ");
19255
19512
  }
19256
- ;
19257
19513
  /**
19258
19514
  * Convert the voronoi cell path data to an array.
19259
19515
  *
@@ -19305,7 +19561,6 @@ class VoronoiCell {
19305
19561
  const openEdgePoint = new Vertex$1(perpendicular.x + (center.x - perpendicular.x) * 1000, perpendicular.y + (center.y - perpendicular.y) * 1000);
19306
19562
  return openEdgePoint;
19307
19563
  }
19308
- ;
19309
19564
  /**
19310
19565
  * A helper function.
19311
19566
  *
@@ -19329,13 +19584,12 @@ class VoronoiCell {
19329
19584
  return tri.a;
19330
19585
  }
19331
19586
  // Here:
19332
- // tri.c.equals(sharedVertex)
19587
+ // tri.c.equals(sharedVertex)
19333
19588
  if (neighbour.a.equals(tri.a) || neighbour.b.equals(tri.a) || neighbour.c.equals(tri.a))
19334
19589
  return tri.b;
19335
19590
  else
19336
19591
  return tri.a;
19337
19592
  }
19338
- ;
19339
19593
  }
19340
19594
 
19341
19595
  /**
@@ -19343,7 +19597,8 @@ class VoronoiCell {
19343
19597
  * @date 2018-04-07
19344
19598
  * @modified 2018-04-11 Using VoronoiCells now (was array before).
19345
19599
  * @modified 2020-08-15 Ported from vanilla JS to TypeScript.
19346
- * @version 1.0.2
19600
+ * @modified 2026-09-15 Added the `sharedVertexIndex` attribute to each Voronoi cell.
19601
+ * @version 1.1.0
19347
19602
  **/
19348
19603
  /**
19349
19604
  * @classdesc Create the voronoi diagram from the given delaunay triangulation (they are dual graphs).
@@ -19358,13 +19613,12 @@ class delaunay2voronoi {
19358
19613
  this.pointList = pointList;
19359
19614
  this.triangles = triangles;
19360
19615
  }
19361
- ;
19362
19616
  // +---------------------------------------------------------------------------------
19363
19617
  // | Convert the triangle set to the Voronoi diagram.
19364
19618
  // +-------------------------------
19365
19619
  build() {
19366
19620
  const voronoiDiagram = [];
19367
- for (var p in this.pointList) {
19621
+ for (var p = 0; p < this.pointList.length; p++) {
19368
19622
  var point = this.pointList[p];
19369
19623
  // Find adjacent triangles for first point
19370
19624
  var adjacentSubset = [];
@@ -19373,12 +19627,12 @@ class delaunay2voronoi {
19373
19627
  adjacentSubset.push(this.triangles[t]);
19374
19628
  }
19375
19629
  var path = this.subsetToPath(adjacentSubset);
19376
- if (path) // There may be errors
19377
- voronoiDiagram.push(new VoronoiCell(path, point));
19630
+ if (path)
19631
+ // There may be errors
19632
+ voronoiDiagram.push(new VoronoiCell(path, point, p));
19378
19633
  }
19379
19634
  return voronoiDiagram;
19380
19635
  }
19381
- ;
19382
19636
  // +---------------------------------------------------------------------------------
19383
19637
  // | Re-order a tiangle subset so the triangle define a single path.
19384
19638
  // |
@@ -19391,7 +19645,7 @@ class delaunay2voronoi {
19391
19645
  subsetToPath(triangleSet, startPosition, tryOnce) {
19392
19646
  if (triangleSet.length == 0)
19393
19647
  return [];
19394
- if (typeof startPosition === 'undefined')
19648
+ if (typeof startPosition === "undefined")
19395
19649
  startPosition = 0;
19396
19650
  let t = startPosition;
19397
19651
  const result = [triangleSet[t]];
@@ -19432,8 +19686,7 @@ class delaunay2voronoi {
19432
19686
  return result;
19433
19687
  }
19434
19688
  }
19435
- ;
19436
- }
19689
+ } // END delaunay2voronoi
19437
19690
 
19438
19691
  /**
19439
19692
  * @requires Line