plotboilerplate 1.23.3 → 1.25.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.
- package/README.md +19 -1
- package/dist/index.esm.js +1684 -394
- package/dist/index.esm.js.map +1 -1
- package/dist/index.esm.min.js +1 -1
- package/dist/index.esm.min.js.map +1 -1
- package/dist/plotboilerplate.browser.min.js +1 -1
- package/dist/plotboilerplate.browser.min.js.map +1 -1
- package/dist/plotboilerplate.js +12450 -11120
- package/dist/plotboilerplate.min.js +1 -1
- package/package.json +9 -5
- package/src/cjs/BezierPath.d.ts +41 -5
- package/src/cjs/BezierPath.js +52 -2
- package/src/cjs/BezierPath.js.map +1 -1
- package/src/cjs/Bounds.d.ts +67 -3
- package/src/cjs/Bounds.js +101 -3
- package/src/cjs/Bounds.js.map +1 -1
- package/src/cjs/Circle.d.ts +46 -4
- package/src/cjs/Circle.js +82 -3
- package/src/cjs/Circle.js.map +1 -1
- package/src/cjs/CircleSector.d.ts +51 -2
- package/src/cjs/CircleSector.js +112 -3
- package/src/cjs/CircleSector.js.map +1 -1
- package/src/cjs/CubicBezierCurve.d.ts +113 -7
- package/src/cjs/CubicBezierCurve.js +281 -33
- package/src/cjs/CubicBezierCurve.js.map +1 -1
- package/src/cjs/Line.d.ts +38 -3
- package/src/cjs/Line.js +64 -1
- package/src/cjs/Line.js.map +1 -1
- package/src/cjs/PlotBoilerplate.d.ts +37 -6
- package/src/cjs/PlotBoilerplate.js +224 -125
- package/src/cjs/PlotBoilerplate.js.map +1 -1
- package/src/cjs/Polygon.d.ts +68 -5
- package/src/cjs/Polygon.js +143 -22
- package/src/cjs/Polygon.js.map +1 -1
- package/src/cjs/Triangle.d.ts +52 -3
- package/src/cjs/Triangle.js +80 -1
- package/src/cjs/Triangle.js.map +1 -1
- package/src/cjs/VEllipse.d.ts +62 -3
- package/src/cjs/VEllipse.js +181 -17
- package/src/cjs/VEllipse.js.map +1 -1
- package/src/cjs/VEllipseSector.d.ts +86 -2
- package/src/cjs/VEllipseSector.js +148 -4
- package/src/cjs/VEllipseSector.js.map +1 -1
- package/src/cjs/Vector.d.ts +12 -2
- package/src/cjs/Vector.js +15 -2
- package/src/cjs/Vector.js.map +1 -1
- package/src/cjs/VertTuple.d.ts +28 -4
- package/src/cjs/VertTuple.js +36 -3
- package/src/cjs/VertTuple.js.map +1 -1
- package/src/cjs/Vertex.d.ts +31 -4
- package/src/cjs/Vertex.js +35 -1
- package/src/cjs/Vertex.js.map +1 -1
- package/src/cjs/interfaces/core.d.ts +67 -0
- package/src/cjs/interfaces/core.js +4 -0
- package/src/cjs/interfaces/core.js.map +1 -1
- package/src/cjs/utils/algorithms/convexPolygonIncircle.d.ts +2 -1
- package/src/cjs/utils/algorithms/convexPolygonIncircle.js +14 -6
- package/src/cjs/utils/algorithms/convexPolygonIncircle.js.map +1 -1
- package/src/cjs/utils/createRandomizedPolygon.d.ts +14 -0
- package/src/cjs/utils/createRandomizedPolygon.js +32 -0
- package/src/cjs/utils/createRandomizedPolygon.js.map +1 -0
- package/src/cjs/utils/datastructures/Color.d.ts +147 -1
- package/src/cjs/utils/datastructures/Color.js +385 -41
- package/src/cjs/utils/datastructures/Color.js.map +1 -1
- package/src/cjs/utils/datastructures/ColorGradient.d.ts +79 -0
- package/src/cjs/utils/datastructures/ColorGradient.js +171 -0
- package/src/cjs/utils/datastructures/ColorGradient.js.map +1 -0
- package/src/cjs/utils/dom/components/ColorGradientPicker.d.ts +245 -0
- package/src/cjs/utils/dom/components/ColorGradientPicker.js +667 -0
- package/src/cjs/utils/dom/components/ColorGradientPicker.js.map +1 -0
- package/src/cjs/utils/dom/components/ColorGradientPickerJSX.d.ts +129 -0
- package/src/cjs/utils/dom/components/ColorGradientPickerJSX.js +520 -0
- package/src/cjs/utils/dom/components/ColorGradientPickerJSX.js.map +1 -0
- package/src/cjs/utils/dom/components/ColorGradientSelector.d.ts +117 -0
- package/src/cjs/utils/dom/components/ColorGradientSelector.js +325 -0
- package/src/cjs/utils/dom/components/ColorGradientSelector.js.map +1 -0
- package/src/cjs/utils/dom/components/Test.d.ts +7 -0
- package/src/cjs/utils/dom/components/Test.js +30 -0
- package/src/cjs/utils/dom/components/Test.js.map +1 -0
- package/src/cjs/utils/dom/guiSizeToggler.js +1 -1
- package/src/cjs/utils/dom/guiSizeToggler.js.map +1 -1
- package/src/cjs/utils/helpers/BezierPathInteractionHelper.d.ts +16 -8
- package/src/cjs/utils/helpers/BezierPathInteractionHelper.js +49 -28
- package/src/cjs/utils/helpers/BezierPathInteractionHelper.js.map +1 -1
- package/src/cjs/utils/helpers/CircleHelper.d.ts +10 -1
- package/src/cjs/utils/helpers/CircleHelper.js +13 -2
- package/src/cjs/utils/helpers/CircleHelper.js.map +1 -1
- package/src/cjs/utils/helpers/CircleSectorHelper.d.ts +11 -2
- package/src/cjs/utils/helpers/CircleSectorHelper.js +20 -20
- package/src/cjs/utils/helpers/CircleSectorHelper.js.map +1 -1
- package/src/cjs/utils/helpers/TriangleHelper.d.ts +57 -0
- package/src/cjs/utils/helpers/TriangleHelper.js +83 -0
- package/src/cjs/utils/helpers/TriangleHelper.js.map +1 -0
- package/src/cjs/utils/helpers/VEllipseHelper.d.ts +32 -0
- package/src/cjs/utils/helpers/VEllipseHelper.js +88 -0
- package/src/cjs/utils/helpers/VEllipseHelper.js.map +1 -0
- package/src/cjs/utils/helpers/VEllipseSectorHelper.d.ts +44 -4
- package/src/cjs/utils/helpers/VEllipseSectorHelper.js +108 -25
- package/src/cjs/utils/helpers/VEllipseSectorHelper.js.map +1 -1
- package/src/cjs/utils/parsers/LinearColorGradientParser.d.ts +78 -0
- package/src/cjs/utils/parsers/LinearColorGradientParser.js +224 -0
- package/src/cjs/utils/parsers/LinearColorGradientParser.js.map +1 -0
- package/src/createDemoDrawables.js +4 -1
- package/src/esm/BezierPath.d.ts +41 -5
- package/src/esm/BezierPath.js +50 -2
- package/src/esm/BezierPath.js.map +1 -1
- package/src/esm/Bounds.d.ts +67 -3
- package/src/esm/Bounds.js +101 -3
- package/src/esm/Bounds.js.map +1 -1
- package/src/esm/Circle.d.ts +46 -4
- package/src/esm/Circle.js +79 -3
- package/src/esm/Circle.js.map +1 -1
- package/src/esm/CircleSector.d.ts +51 -2
- package/src/esm/CircleSector.js +108 -3
- package/src/esm/CircleSector.js.map +1 -1
- package/src/esm/CubicBezierCurve.d.ts +113 -7
- package/src/esm/CubicBezierCurve.js +277 -33
- package/src/esm/CubicBezierCurve.js.map +1 -1
- package/src/esm/Line.d.ts +38 -3
- package/src/esm/Line.js +62 -1
- package/src/esm/Line.js.map +1 -1
- package/src/esm/PlotBoilerplate.d.ts +37 -6
- package/src/esm/PlotBoilerplate.js +224 -125
- package/src/esm/PlotBoilerplate.js.map +1 -1
- package/src/esm/Polygon.d.ts +68 -5
- package/src/esm/Polygon.js +138 -22
- package/src/esm/Polygon.js.map +1 -1
- package/src/esm/Triangle.d.ts +52 -3
- package/src/esm/Triangle.js +77 -1
- package/src/esm/Triangle.js.map +1 -1
- package/src/esm/VEllipse.d.ts +62 -3
- package/src/esm/VEllipse.js +178 -17
- package/src/esm/VEllipse.js.map +1 -1
- package/src/esm/VEllipseSector.d.ts +86 -2
- package/src/esm/VEllipseSector.js +146 -7
- package/src/esm/VEllipseSector.js.map +1 -1
- package/src/esm/Vector.d.ts +12 -2
- package/src/esm/Vector.js +15 -2
- package/src/esm/Vector.js.map +1 -1
- package/src/esm/VertTuple.d.ts +28 -4
- package/src/esm/VertTuple.js +36 -3
- package/src/esm/VertTuple.js.map +1 -1
- package/src/esm/Vertex.d.ts +31 -4
- package/src/esm/Vertex.js +35 -1
- package/src/esm/Vertex.js.map +1 -1
- package/src/esm/interfaces/core.d.ts +67 -0
- package/src/esm/interfaces/core.js +4 -0
- package/src/esm/interfaces/core.js.map +1 -1
- package/src/esm/utils/algorithms/convexPolygonIncircle.d.ts +2 -1
- package/src/esm/utils/algorithms/convexPolygonIncircle.js +15 -7
- package/src/esm/utils/algorithms/convexPolygonIncircle.js.map +1 -1
- package/src/esm/utils/algorithms/createRandomizedPolygon.d.ts +14 -0
- package/src/esm/utils/algorithms/createRandomizedPolygon.js +28 -0
- package/src/esm/utils/algorithms/createRandomizedPolygon.js.map +1 -0
- package/src/esm/utils/createRandomizedPolygon.d.ts +14 -0
- package/src/esm/utils/createRandomizedPolygon.js +28 -0
- package/src/esm/utils/createRandomizedPolygon.js.map +1 -0
- package/src/esm/utils/datastructures/Color.d.ts +147 -1
- package/src/esm/utils/datastructures/Color.js +386 -42
- package/src/esm/utils/datastructures/Color.js.map +1 -1
- package/src/esm/utils/datastructures/ColorGradient.d.ts +79 -0
- package/src/esm/utils/datastructures/ColorGradient.js +166 -0
- package/src/esm/utils/datastructures/ColorGradient.js.map +1 -0
- package/src/esm/utils/dom/components/ColorGradientPicker.d.ts +245 -0
- package/src/esm/utils/dom/components/ColorGradientPicker.js +732 -0
- package/src/esm/utils/dom/components/ColorGradientPicker.js.map +1 -0
- package/src/esm/utils/dom/components/ColorGradientPickerJSX.d.ts +129 -0
- package/src/esm/utils/dom/components/ColorGradientPickerJSX.js +582 -0
- package/src/esm/utils/dom/components/ColorGradientPickerJSX.js.map +1 -0
- package/src/esm/utils/dom/components/ColorGradientSelector.d.ts +117 -0
- package/src/esm/utils/dom/components/ColorGradientSelector.js +332 -0
- package/src/esm/utils/dom/components/ColorGradientSelector.js.map +1 -0
- package/src/esm/utils/dom/components/Test.d.ts +7 -0
- package/src/esm/utils/dom/components/Test.js +26 -0
- package/src/esm/utils/dom/components/Test.js.map +1 -0
- package/src/esm/utils/dom/guiSizeToggler.js +1 -1
- package/src/esm/utils/dom/guiSizeToggler.js.map +1 -1
- package/src/esm/utils/helpers/BezierPathInteractionHelper.d.ts +16 -8
- package/src/esm/utils/helpers/BezierPathInteractionHelper.js +47 -27
- package/src/esm/utils/helpers/BezierPathInteractionHelper.js.map +1 -1
- package/src/esm/utils/helpers/CircleHelper.d.ts +10 -1
- package/src/esm/utils/helpers/CircleHelper.js +13 -2
- package/src/esm/utils/helpers/CircleHelper.js.map +1 -1
- package/src/esm/utils/helpers/CircleSectorHelper.d.ts +11 -2
- package/src/esm/utils/helpers/CircleSectorHelper.js +20 -20
- package/src/esm/utils/helpers/CircleSectorHelper.js.map +1 -1
- package/src/esm/utils/helpers/TriangleHelper.d.ts +57 -0
- package/src/esm/utils/helpers/TriangleHelper.js +78 -0
- package/src/esm/utils/helpers/TriangleHelper.js.map +1 -0
- package/src/esm/utils/helpers/VEllipseHelper.d.ts +32 -0
- package/src/esm/utils/helpers/VEllipseHelper.js +83 -0
- package/src/esm/utils/helpers/VEllipseHelper.js.map +1 -0
- package/src/esm/utils/helpers/VEllipseSectorHelper.d.ts +44 -4
- package/src/esm/utils/helpers/VEllipseSectorHelper.js +107 -24
- package/src/esm/utils/helpers/VEllipseSectorHelper.js.map +1 -1
- package/src/esm/utils/parsers/LinearColorGradientParser.d.ts +78 -0
- package/src/esm/utils/parsers/LinearColorGradientParser.js +217 -0
- package/src/esm/utils/parsers/LinearColorGradientParser.js.map +1 -0
- package/src/external.d.ts +9 -0
- package/src/ts/BezierPath.ts +58 -5
- package/src/ts/Bounds.ts +110 -6
- package/src/ts/Circle.ts +87 -5
- package/src/ts/CircleSector.ts +115 -5
- package/src/ts/CubicBezierCurve.ts +332 -42
- package/src/ts/Line.ts +66 -3
- package/src/ts/PlotBoilerplate.ts +236 -114
- package/src/ts/Polygon.ts +164 -29
- package/src/ts/Triangle.ts +85 -3
- package/src/ts/VEllipse.ts +214 -19
- package/src/ts/VEllipseSector.ts +154 -8
- package/src/ts/Vector.ts +16 -2
- package/src/ts/VertTuple.ts +39 -4
- package/src/ts/Vertex.ts +40 -4
- package/src/ts/interfaces/core.ts +73 -0
- package/src/ts/utils/algorithms/convexPolygonIncircle.ts +82 -78
- package/src/ts/utils/createRandomizedPolygon.ts +31 -0
- package/src/ts/utils/datastructures/Color.ts +423 -44
- package/src/ts/utils/datastructures/ColorGradient.ts +196 -0
- package/src/ts/utils/dom/components/ColorGradientPicker.tsx +877 -0
- package/src/ts/utils/dom/components/ColorGradientSelector.tsx +445 -0
- package/src/ts/utils/dom/components/Test.tsx +44 -0
- package/src/ts/utils/dom/components/_ColorGradientPicker_raw.ts_ +392 -0
- package/src/ts/utils/dom/guiSizeToggler.ts +1 -1
- package/src/ts/utils/helpers/BezierPathInteractionHelper.ts +61 -35
- package/src/ts/utils/helpers/CircleHelper.ts +17 -3
- package/src/ts/utils/helpers/CircleSectorHelper.ts +118 -126
- package/src/ts/utils/helpers/TriangleHelper.ts +102 -0
- package/src/ts/utils/helpers/VEllipseHelper.ts +115 -0
- package/src/ts/utils/helpers/VEllipseSectorHelper.ts +144 -26
- package/src/ts/utils/parsers/LinearColorGradientParser.ts +297 -0
package/src/ts/VEllipse.ts
CHANGED
|
@@ -15,7 +15,11 @@
|
|
|
15
15
|
* @modified 2021-03-19 Added the `VEllipse.rotate` function.
|
|
16
16
|
* @modified 2022-02-02 Added the `destroy` method.
|
|
17
17
|
* @modified 2022-02-02 Cleared the `VEllipse.toSVGString` function (deprecated). Use `drawutilssvg` instead.
|
|
18
|
-
* @
|
|
18
|
+
* @modified 2025-03-31 ATTENTION: modified the winding direction of the `tangentAt` method to match with the Circle method. This is a breaking change!
|
|
19
|
+
* @modified 2025-03-31 Adding the `VEllipse.move(amount: XYCoords)` method.
|
|
20
|
+
* @modified 2025-04-19 Adding the `VEllipse.getBounds()` method.
|
|
21
|
+
* @modified 2025-04-24 Adding the `VEllipse.getExtremePoints()` method for calculating minima and maxima.
|
|
22
|
+
* @version 1.4.0
|
|
19
23
|
*
|
|
20
24
|
* @file VEllipse
|
|
21
25
|
* @fileoverview Ellipses with a center and an x- and a y-axis (stored as a vertex).
|
|
@@ -25,8 +29,11 @@ import { Line } from "./Line";
|
|
|
25
29
|
import { Vector } from "./Vector";
|
|
26
30
|
import { Vertex } from "./Vertex";
|
|
27
31
|
import { UIDGenerator } from "./UIDGenerator";
|
|
28
|
-
import { SVGSerializable, UID, XYCoords } from "./interfaces";
|
|
32
|
+
import { IBounded, Intersectable, SVGSerializable, UID, XYCoords } from "./interfaces";
|
|
29
33
|
import { CubicBezierCurve } from "./CubicBezierCurve";
|
|
34
|
+
import { VertTuple } from "./VertTuple";
|
|
35
|
+
import { Circle } from "./Circle";
|
|
36
|
+
import { Bounds } from "./Bounds";
|
|
30
37
|
|
|
31
38
|
/**
|
|
32
39
|
* @classdesc An ellipse class based on two vertices [centerX,centerY] and [radiusX,radiusY].
|
|
@@ -36,7 +43,7 @@ import { CubicBezierCurve } from "./CubicBezierCurve";
|
|
|
36
43
|
* @requires UIDGenerator
|
|
37
44
|
* @requires Vertex
|
|
38
45
|
*/
|
|
39
|
-
export class VEllipse implements SVGSerializable {
|
|
46
|
+
export class VEllipse implements IBounded, Intersectable, SVGSerializable {
|
|
40
47
|
/**
|
|
41
48
|
* Required to generate proper CSS classes and other class related IDs.
|
|
42
49
|
**/
|
|
@@ -154,12 +161,119 @@ export class VEllipse implements SVGSerializable {
|
|
|
154
161
|
* @return {number} The signed vertical radius of this ellipse.
|
|
155
162
|
*/
|
|
156
163
|
signedRadiusV(): number {
|
|
157
|
-
// return Math.abs(this.axis.y - this.center.y);
|
|
158
164
|
// Rotate axis back to origin before calculating radius
|
|
159
|
-
// return Math.abs(new Vertex(this.axis).rotate(-this.rotation,this.center).y - this.center.y);
|
|
160
165
|
return new Vertex(this.axis).rotate(-this.rotation, this.center).y - this.center.y;
|
|
161
166
|
}
|
|
162
167
|
|
|
168
|
+
/**
|
|
169
|
+
* Get the the minima and maxima (points) of this (rotated) ellipse.
|
|
170
|
+
*
|
|
171
|
+
* @method getExtremePoints
|
|
172
|
+
* @instance
|
|
173
|
+
* @memberof VEllipse
|
|
174
|
+
* @return {[Vertex, Vertex, Vertex, Vertex]} Get the the minima and maxima (points) of this (rotated) ellipse.
|
|
175
|
+
*/
|
|
176
|
+
getExtremePoints(): [Vertex, Vertex, Vertex, Vertex] {
|
|
177
|
+
const a: number = this.radiusH();
|
|
178
|
+
const b: number = this.radiusV();
|
|
179
|
+
|
|
180
|
+
// Calculate t_x values
|
|
181
|
+
const t_x1: number = Math.atan2(-b * Math.sin(this.rotation), a * Math.cos(this.rotation));
|
|
182
|
+
const t_x2: number = t_x1 + Math.PI;
|
|
183
|
+
|
|
184
|
+
// Calculate x values at t_x
|
|
185
|
+
const x_x1: number =
|
|
186
|
+
this.center.x + a * Math.cos(t_x1) * Math.cos(this.rotation) - b * Math.sin(t_x1) * Math.sin(this.rotation);
|
|
187
|
+
const y_x1: number =
|
|
188
|
+
this.center.y + a * Math.cos(t_x1) * Math.sin(this.rotation) + b * Math.sin(t_x1) * Math.cos(this.rotation);
|
|
189
|
+
const x_x2: number =
|
|
190
|
+
this.center.x + a * Math.cos(t_x2) * Math.cos(this.rotation) - b * Math.sin(t_x2) * Math.sin(this.rotation);
|
|
191
|
+
const y_x2: number =
|
|
192
|
+
this.center.y + a * Math.cos(t_x2) * Math.sin(this.rotation) + b * Math.sin(t_x2) * Math.cos(this.rotation);
|
|
193
|
+
|
|
194
|
+
let x_max: Vertex, x_min: Vertex;
|
|
195
|
+
if (x_x1 > x_x2) {
|
|
196
|
+
x_max = new Vertex(x_x1, y_x1);
|
|
197
|
+
x_min = new Vertex(x_x2, y_x2);
|
|
198
|
+
} else {
|
|
199
|
+
x_max = new Vertex(x_x2, y_x2);
|
|
200
|
+
x_min = new Vertex(x_x1, y_x1);
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
// Calculate t_y values
|
|
204
|
+
const t_y1: number = Math.atan2(b * Math.cos(this.rotation), a * Math.sin(this.rotation));
|
|
205
|
+
const t_y2: number = t_y1 + Math.PI;
|
|
206
|
+
|
|
207
|
+
// Calculate y values at t_y
|
|
208
|
+
const x_y1: number =
|
|
209
|
+
this.center.x + a * Math.cos(t_y1) * Math.cos(this.rotation) - b * Math.sin(t_y1) * Math.sin(this.rotation);
|
|
210
|
+
const y_y1: number =
|
|
211
|
+
this.center.y + a * Math.cos(t_y1) * Math.sin(this.rotation) + b * Math.sin(t_y1) * Math.cos(this.rotation);
|
|
212
|
+
const x_y2: number =
|
|
213
|
+
this.center.x + a * Math.cos(t_y2) * Math.cos(this.rotation) - b * Math.sin(t_y2) * Math.sin(this.rotation);
|
|
214
|
+
const y_y2: number =
|
|
215
|
+
this.center.y + a * Math.cos(t_y2) * Math.sin(this.rotation) + b * Math.sin(t_y2) * Math.cos(this.rotation);
|
|
216
|
+
|
|
217
|
+
let y_max: Vertex, y_min: Vertex;
|
|
218
|
+
if (y_y1 > y_y2) {
|
|
219
|
+
y_max = new Vertex(x_y1, y_y1);
|
|
220
|
+
y_min = new Vertex(x_y2, y_y2);
|
|
221
|
+
} else {
|
|
222
|
+
y_max = new Vertex(x_y2, y_y2);
|
|
223
|
+
y_min = new Vertex(x_y1, y_y1);
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
return [x_max, x_min, y_max, y_min];
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
//--- BEGIN --- Implement interface `IBounded`
|
|
230
|
+
/**
|
|
231
|
+
* Get the bounds of this ellipse.
|
|
232
|
+
*
|
|
233
|
+
* The bounds are approximated by the underlying segment buffer; the more segment there are,
|
|
234
|
+
* the more accurate will be the returned bounds.
|
|
235
|
+
*
|
|
236
|
+
* @method getBounds
|
|
237
|
+
* @instance
|
|
238
|
+
* @memberof VEllipse
|
|
239
|
+
* @return {Bounds} The bounds of this ellipse.
|
|
240
|
+
**/
|
|
241
|
+
getBounds(): Bounds {
|
|
242
|
+
// Thanks to Cuixiping
|
|
243
|
+
// https://stackoverflow.com/questions/87734/how-do-you-calculate-the-axis-aligned-bounding-box-of-an-ellipse
|
|
244
|
+
const r1: number = this.radiusH();
|
|
245
|
+
const r2: number = this.radiusV();
|
|
246
|
+
|
|
247
|
+
const ux: number = r1 * Math.cos(this.rotation);
|
|
248
|
+
const uy: number = r1 * Math.sin(this.rotation);
|
|
249
|
+
const vx: number = r2 * Math.cos(this.rotation + Math.PI / 2);
|
|
250
|
+
const vy: number = r2 * Math.sin(this.rotation + Math.PI / 2);
|
|
251
|
+
|
|
252
|
+
const bbox_halfwidth = Math.sqrt(ux * ux + vx * vx);
|
|
253
|
+
const bbox_halfheight = Math.sqrt(uy * uy + vy * vy);
|
|
254
|
+
|
|
255
|
+
return new Bounds(
|
|
256
|
+
{ x: this.center.x - bbox_halfwidth, y: this.center.y - bbox_halfheight },
|
|
257
|
+
{ x: this.center.x + bbox_halfwidth, y: this.center.y + bbox_halfheight }
|
|
258
|
+
);
|
|
259
|
+
}
|
|
260
|
+
//--- BEGIN --- Implement interface `IBounded`
|
|
261
|
+
|
|
262
|
+
/**
|
|
263
|
+
* Move the ellipse by the given amount. This is equivalent by moving the `center` and `axis` points.
|
|
264
|
+
*
|
|
265
|
+
* @method move
|
|
266
|
+
* @param {XYCoords} amount - The amount to move.
|
|
267
|
+
* @instance
|
|
268
|
+
* @memberof VEllipse
|
|
269
|
+
* @return {VEllipse} this for chaining
|
|
270
|
+
**/
|
|
271
|
+
move(amount: XYCoords): VEllipse {
|
|
272
|
+
this.center.add(amount);
|
|
273
|
+
this.axis.add(amount);
|
|
274
|
+
return this;
|
|
275
|
+
}
|
|
276
|
+
|
|
163
277
|
/**
|
|
164
278
|
* Scale this ellipse by the given factor from the center point. The factor will be applied to both radii.
|
|
165
279
|
*
|
|
@@ -222,9 +336,8 @@ export class VEllipse implements SVGSerializable {
|
|
|
222
336
|
* @param {number} angle - The angle to get the normal vector at.
|
|
223
337
|
* @param {number=1.0} length - [optional, default=1] The length of the returned vector.
|
|
224
338
|
*/
|
|
225
|
-
|
|
226
339
|
normalAt(angle: number, length?: number): Vector {
|
|
227
|
-
const point: Vertex = this.vertAt(angle);
|
|
340
|
+
const point: Vertex = this.vertAt(angle - this.rotation); // HERE IS THE CORRECT BEHAVIOR!
|
|
228
341
|
const foci: [Vertex, Vertex] = this.getFoci();
|
|
229
342
|
// Calculate the angle between [point,focusA] and [point,focusB]
|
|
230
343
|
const angleA: number = new Line(point, foci[0]).angle();
|
|
@@ -236,11 +349,14 @@ export class VEllipse implements SVGSerializable {
|
|
|
236
349
|
.addX(50)
|
|
237
350
|
.clone()
|
|
238
351
|
.rotate(Math.PI + centerAngle, point);
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
352
|
+
const resultVector: Vector =
|
|
353
|
+
this.center.distance(endPointA) < this.center.distance(endPointB)
|
|
354
|
+
? new Vector(point, endPointB)
|
|
355
|
+
: new Vector(point, endPointA);
|
|
356
|
+
if (typeof length === "number") {
|
|
357
|
+
resultVector.setLength(length);
|
|
243
358
|
}
|
|
359
|
+
return resultVector;
|
|
244
360
|
}
|
|
245
361
|
|
|
246
362
|
/**
|
|
@@ -260,9 +376,7 @@ export class VEllipse implements SVGSerializable {
|
|
|
260
376
|
*/
|
|
261
377
|
tangentAt(angle: number, length?: number): Vector {
|
|
262
378
|
const normal: Vector = this.normalAt(angle, length);
|
|
263
|
-
|
|
264
|
-
normal.b.rotate(Math.PI / 2, normal.a);
|
|
265
|
-
return normal;
|
|
379
|
+
return normal.inv().perp();
|
|
266
380
|
}
|
|
267
381
|
|
|
268
382
|
/**
|
|
@@ -315,6 +429,8 @@ export class VEllipse implements SVGSerializable {
|
|
|
315
429
|
/**
|
|
316
430
|
* Get equally distributed points on the outline of this ellipse.
|
|
317
431
|
*
|
|
432
|
+
* @method getEquidistantVertices
|
|
433
|
+
* @instance
|
|
318
434
|
* @param {number} pointCount - The number of points.
|
|
319
435
|
* @returns {Array<Vertex>}
|
|
320
436
|
*/
|
|
@@ -327,6 +443,85 @@ export class VEllipse implements SVGSerializable {
|
|
|
327
443
|
return result;
|
|
328
444
|
}
|
|
329
445
|
|
|
446
|
+
//--- BEGIN --- Implement interface `Intersectable`
|
|
447
|
+
/**
|
|
448
|
+
* Get the line intersections as vectors with this ellipse.
|
|
449
|
+
*
|
|
450
|
+
* @method lineIntersections
|
|
451
|
+
* @instance
|
|
452
|
+
* @param {VertTuple<Vector> ray - The line/ray to intersect this ellipse with.
|
|
453
|
+
* @param {boolean} inVectorBoundsOnly - (default=false) Set to true if only intersections within the vector bounds are of interest.
|
|
454
|
+
* @returns
|
|
455
|
+
*/
|
|
456
|
+
lineIntersections(ray: VertTuple<Vector>, inVectorBoundsOnly: boolean = false): Array<Vertex> {
|
|
457
|
+
// Question: what happens to extreme versions when ellipse is a line (width or height is zero)?
|
|
458
|
+
// This would result in a Division_by_Zero exception!
|
|
459
|
+
|
|
460
|
+
// Step A: create clones for operations (keep originals unchanged)
|
|
461
|
+
const ellipseCopy: VEllipse = this.clone(); // VEllipse
|
|
462
|
+
const rayCopy: VertTuple<Vector> = ray.clone(); // Vector
|
|
463
|
+
|
|
464
|
+
// Step B: move both so ellipse's center is located at (0,0)
|
|
465
|
+
const moveAmount: Vertex = ellipseCopy.center.clone().inv();
|
|
466
|
+
ellipseCopy.move(moveAmount);
|
|
467
|
+
rayCopy.add(moveAmount);
|
|
468
|
+
|
|
469
|
+
// Step C: rotate eclipse backwards it's rotation, so that rotation is zero (0.0).
|
|
470
|
+
// Rotate together with ray!
|
|
471
|
+
const rotationAmount: number = -ellipseCopy.rotation;
|
|
472
|
+
ellipseCopy.rotate(rotationAmount); // Rotation around (0,0) = center of translated ellipse
|
|
473
|
+
rayCopy.a.rotate(rotationAmount, ellipseCopy.center);
|
|
474
|
+
rayCopy.b.rotate(rotationAmount, ellipseCopy.center);
|
|
475
|
+
|
|
476
|
+
// Step D: find x/y factors to use for scaling to transform the ellipse to a circle.
|
|
477
|
+
// Scale together with vector ray.
|
|
478
|
+
const radiusH: number = ellipseCopy.radiusH();
|
|
479
|
+
const radiusV: number = ellipseCopy.radiusV();
|
|
480
|
+
const scalingFactors: XYCoords = radiusH > radiusV ? { x: radiusV / radiusH, y: 1.0 } : { x: 1.0, y: radiusH / radiusV };
|
|
481
|
+
|
|
482
|
+
// Step E: scale ellipse AND ray by calculated factors.
|
|
483
|
+
ellipseCopy.axis.scaleXY(scalingFactors);
|
|
484
|
+
rayCopy.a.scaleXY(scalingFactors);
|
|
485
|
+
rayCopy.b.scaleXY(scalingFactors);
|
|
486
|
+
|
|
487
|
+
// Intermediate result: now the ellipse is transformed to a circle and we can calculate intersections :)
|
|
488
|
+
// Step F: calculate circle+line intersecions
|
|
489
|
+
const tmpCircle: Circle = new Circle(new Vertex(), ellipseCopy.radiusH()); // radiusH() === radiusV()
|
|
490
|
+
const intersections: Vertex[] = tmpCircle.lineIntersections(rayCopy, inVectorBoundsOnly);
|
|
491
|
+
|
|
492
|
+
// Step G: transform intersecions back to original configuration
|
|
493
|
+
intersections.forEach(function (intersectionPoint) {
|
|
494
|
+
// Reverse transformation from above.
|
|
495
|
+
intersectionPoint.scaleXY({ x: 1 / scalingFactors.x, y: 1 / scalingFactors.y }, ellipseCopy.center);
|
|
496
|
+
intersectionPoint.rotate(-rotationAmount, ellipseCopy.center);
|
|
497
|
+
intersectionPoint.sub(moveAmount);
|
|
498
|
+
});
|
|
499
|
+
|
|
500
|
+
return intersections;
|
|
501
|
+
}
|
|
502
|
+
|
|
503
|
+
/**
|
|
504
|
+
* Get all line intersections of this polygon and their tangents along the shape.
|
|
505
|
+
*
|
|
506
|
+
* This method returns all intersection tangents (as vectors) with this shape. The returned array of vectors is in no specific order.
|
|
507
|
+
*
|
|
508
|
+
* @param line
|
|
509
|
+
* @param lineIntersectionTangents
|
|
510
|
+
* @returns
|
|
511
|
+
*/
|
|
512
|
+
lineIntersectionTangents(line: VertTuple<any>, inVectorBoundsOnly: boolean = false): Array<Vector> {
|
|
513
|
+
// Find the intersections of all lines plus their tangents inside the circle bounds
|
|
514
|
+
const interSectionPoints: Array<Vertex> = this.lineIntersections(line, inVectorBoundsOnly);
|
|
515
|
+
return interSectionPoints.map((vert: Vertex) => {
|
|
516
|
+
// Calculate angle
|
|
517
|
+
const lineFromCenter = new Line(this.center, vert);
|
|
518
|
+
const angle: number = lineFromCenter.angle();
|
|
519
|
+
// Calculate tangent at angle
|
|
520
|
+
return this.tangentAt(angle);
|
|
521
|
+
});
|
|
522
|
+
}
|
|
523
|
+
//--- END --- Implement interface `Intersectable`
|
|
524
|
+
|
|
330
525
|
/**
|
|
331
526
|
* Convert this ellipse into cubic Bézier curves.
|
|
332
527
|
*
|
|
@@ -340,7 +535,7 @@ export class VEllipse implements SVGSerializable {
|
|
|
340
535
|
// http://www.spaceroots.org/documents/ellipse/node22.html
|
|
341
536
|
|
|
342
537
|
// Note that ellipses with radiusH=0 or radiusV=0 cannot be represented as Bézier curves.
|
|
343
|
-
// Return a single line here (as a Bézier curve)
|
|
538
|
+
// Return a single line here (as a Bézier curve)?
|
|
344
539
|
// if (Math.abs(this.radiusV()) < 0.00001) {
|
|
345
540
|
// const radiusH = this.radiusH();
|
|
346
541
|
// return [
|
|
@@ -372,10 +567,10 @@ export class VEllipse implements SVGSerializable {
|
|
|
372
567
|
|
|
373
568
|
const curves: Array<CubicBezierCurve> = [];
|
|
374
569
|
const angles: Array<number> = VEllipse.utils.equidistantVertAngles(radiusH, radiusV, segmentCount);
|
|
375
|
-
let curAngle: number = angles[0];
|
|
570
|
+
let curAngle: number = angles[0] + this.rotation;
|
|
376
571
|
let startPoint: Vertex = this.vertAt(curAngle);
|
|
377
572
|
for (var i = 0; i < angles.length; i++) {
|
|
378
|
-
let nextAngle = angles[(i + 1) % angles.length];
|
|
573
|
+
let nextAngle = angles[(i + 1) % angles.length] + this.rotation;
|
|
379
574
|
let endPoint: Vertex = this.vertAt(nextAngle);
|
|
380
575
|
|
|
381
576
|
if (Math.abs(radiusV) < 0.0001 || Math.abs(radiusH) < 0.0001) {
|
|
@@ -389,8 +584,8 @@ export class VEllipse implements SVGSerializable {
|
|
|
389
584
|
);
|
|
390
585
|
curves.push(curve);
|
|
391
586
|
} else {
|
|
392
|
-
let startTangent: Vector = this.tangentAt(curAngle);
|
|
393
|
-
let endTangent: Vector = this.tangentAt(nextAngle);
|
|
587
|
+
let startTangent: Vector = this.tangentAt(curAngle + this.rotation);
|
|
588
|
+
let endTangent: Vector = this.tangentAt(nextAngle + this.rotation);
|
|
394
589
|
|
|
395
590
|
// Find intersection (ignore that the result might be null in some extreme cases)
|
|
396
591
|
let intersection: Vertex = startTangent.intersection(endTangent) as Vertex;
|
package/src/ts/VEllipseSector.ts
CHANGED
|
@@ -6,9 +6,17 @@
|
|
|
6
6
|
* @date 2021-02-26
|
|
7
7
|
* @modified 2022-02-02 Added the `destroy` method.
|
|
8
8
|
* @modified 2022-11-01 Tweaked the `endpointToCenterParameters` function to handle negative values, too, without errors.
|
|
9
|
-
* @
|
|
9
|
+
* @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).
|
|
10
|
+
* @modified 2025-04-02 Adding `VEllipseSector.containsAngle` method.
|
|
11
|
+
* @modified 2025-04-02 Adding `VEllipseSector.lineIntersections` and `VEllipseSector.lineIntersectionTangents` and implementing `Intersectable`.
|
|
12
|
+
* @modified 2025-04-07 Adding value wrapping (0 to TWO_PI) to the `VEllipseSector.containsAngle` method.
|
|
13
|
+
* @modified 2025-04-09 Adding the `VEllipseSector.move` method.
|
|
14
|
+
* @modified 2025-04-19 Added the `VEllipseSector.getStartPoint` and `getEndPoint` methods.
|
|
15
|
+
* @modified 2025-04-23 Added the `VEllipseSector.getBounds` method.
|
|
16
|
+
* @version 1.2.0
|
|
10
17
|
*/
|
|
11
18
|
|
|
19
|
+
import { Bounds } from "./Bounds";
|
|
12
20
|
import { CubicBezierCurve } from "./CubicBezierCurve";
|
|
13
21
|
import { geomutils } from "./geomutils";
|
|
14
22
|
import { SVGPathParams, UID, XYCoords } from "./interfaces";
|
|
@@ -17,6 +25,7 @@ import { UIDGenerator } from "./UIDGenerator";
|
|
|
17
25
|
import { Vector } from "./Vector";
|
|
18
26
|
import { VEllipse } from "./VEllipse";
|
|
19
27
|
import { Vertex } from "./Vertex";
|
|
28
|
+
import { VertTuple } from "./VertTuple";
|
|
20
29
|
|
|
21
30
|
/**
|
|
22
31
|
* @classdesc A class for elliptic sectors.
|
|
@@ -93,6 +102,143 @@ export class VEllipseSector {
|
|
|
93
102
|
this.endAngle = geomutils.wrapMinMax(endAngle, 0, Math.PI * 2);
|
|
94
103
|
}
|
|
95
104
|
|
|
105
|
+
/**
|
|
106
|
+
* Move the ellipse sector by the given amount.
|
|
107
|
+
*
|
|
108
|
+
* @method move
|
|
109
|
+
* @param {XYCoords} amount - The amount to move.
|
|
110
|
+
* @instance
|
|
111
|
+
* @memberof VEllipseSector
|
|
112
|
+
* @return {VEllipseSector} this for chaining
|
|
113
|
+
**/
|
|
114
|
+
move(amount: XYCoords): VEllipseSector {
|
|
115
|
+
this.ellipse.move(amount);
|
|
116
|
+
return this;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
/**
|
|
120
|
+
* Checks wether the given angle (must be inside 0 and PI*2) is contained inside this sector.
|
|
121
|
+
*
|
|
122
|
+
* @param {number} angle - The numeric angle to check.
|
|
123
|
+
* @method containsAngle
|
|
124
|
+
* @instance
|
|
125
|
+
* @memberof VEllipseSectpr
|
|
126
|
+
* @return {boolean} True if (and only if) this sector contains the given angle.
|
|
127
|
+
*/
|
|
128
|
+
containsAngle(angle: number) {
|
|
129
|
+
angle = geomutils.mapAngleTo2PI(angle); // wrapMinMax(angle, 0, Math.PI * 2);
|
|
130
|
+
const sAngle: number = geomutils.mapAngleTo2PI(this.startAngle);
|
|
131
|
+
const eAngle: number = geomutils.mapAngleTo2PI(this.endAngle);
|
|
132
|
+
// TODO: cleanup
|
|
133
|
+
// if (this.startAngle <= this.endAngle) {
|
|
134
|
+
// return angle >= this.startAngle && angle < this.endAngle;
|
|
135
|
+
// } else {
|
|
136
|
+
// // startAngle > endAngle
|
|
137
|
+
// return angle >= this.startAngle || angle < this.endAngle;
|
|
138
|
+
// }
|
|
139
|
+
if (sAngle <= eAngle) {
|
|
140
|
+
return angle >= sAngle && angle < eAngle;
|
|
141
|
+
} else {
|
|
142
|
+
// startAngle > endAngle
|
|
143
|
+
return angle >= sAngle || angle < eAngle;
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
/**
|
|
148
|
+
* Get the sectors starting point (on the underlying ellipse, located at the start angle).
|
|
149
|
+
*
|
|
150
|
+
* @method getStartPoint
|
|
151
|
+
* @instance
|
|
152
|
+
* @memberof VEllipseSector
|
|
153
|
+
* @return {Vertex} The sector's stating point.
|
|
154
|
+
*/
|
|
155
|
+
getStartPoint(): Vertex {
|
|
156
|
+
return this.ellipse.vertAt(this.startAngle);
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
/**
|
|
160
|
+
* Get the sectors ending point (on the underlying ellipse, located at the end angle).
|
|
161
|
+
*
|
|
162
|
+
* @method getEndPoint
|
|
163
|
+
* @instance
|
|
164
|
+
* @memberof VEllipseSector
|
|
165
|
+
* @return {Vertex} The sector's ending point.
|
|
166
|
+
*/
|
|
167
|
+
getEndPoint(): Vertex {
|
|
168
|
+
return this.ellipse.vertAt(this.endAngle);
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
//--- BEGIN --- Implement interface `IBounded`
|
|
172
|
+
/**
|
|
173
|
+
* Get the bounds of this elliptic sector.
|
|
174
|
+
*
|
|
175
|
+
* The bounds are approximated by the underlying segment buffer; the more segment there are,
|
|
176
|
+
* the more accurate will be the returned bounds.
|
|
177
|
+
*
|
|
178
|
+
* @method getBounds
|
|
179
|
+
* @instance
|
|
180
|
+
* @memberof VEllipse
|
|
181
|
+
* @return {Bounds} The bounds of this elliptic sector.
|
|
182
|
+
**/
|
|
183
|
+
getBounds(): Bounds {
|
|
184
|
+
// Calculage angles from east, west, north and south box points and check if they are inside
|
|
185
|
+
const extremes = this.ellipse.getExtremePoints();
|
|
186
|
+
const candidates: Array<Vertex> = extremes.filter(point => {
|
|
187
|
+
const angle: number = new Line(this.ellipse.center, point).angle() - this.ellipse.rotation;
|
|
188
|
+
return this.containsAngle(angle);
|
|
189
|
+
});
|
|
190
|
+
return Bounds.computeFromVertices([this.getStartPoint(), this.getEndPoint()].concat(candidates));
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
//--- BEGIN --- Implement interface `Intersectable`
|
|
194
|
+
/**
|
|
195
|
+
* Get the line intersections as vectors with this ellipse.
|
|
196
|
+
*
|
|
197
|
+
* @method lineIntersections
|
|
198
|
+
* @instance
|
|
199
|
+
* @memberof VEllipseSectpr
|
|
200
|
+
* @param {VertTuple<Vector>} ray - The line/ray to intersect this ellipse with.
|
|
201
|
+
* @param {boolean} inVectorBoundsOnly - (default=false) Set to true if only intersections within the vector bounds are of interest.
|
|
202
|
+
* @returns
|
|
203
|
+
*/
|
|
204
|
+
lineIntersections(ray: VertTuple<Vector>, inVectorBoundsOnly: boolean = false): Array<Vertex> {
|
|
205
|
+
// First get all line intersections from underlying ellipse.
|
|
206
|
+
const ellipseIntersections: Array<Vertex> = this.ellipse.lineIntersections(ray, inVectorBoundsOnly);
|
|
207
|
+
// Drop all intersection points that are not contained in the circle sectors bounds.
|
|
208
|
+
const tmpLine = new Line(this.ellipse.center, new Vertex());
|
|
209
|
+
return ellipseIntersections.filter((intersectionPoint: Vertex) => {
|
|
210
|
+
tmpLine.b.set(intersectionPoint);
|
|
211
|
+
const lineAngle = tmpLine.angle();
|
|
212
|
+
return this.containsAngle(lineAngle - this.ellipse.rotation);
|
|
213
|
+
});
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
/**
|
|
217
|
+
* Get all line intersections of this polygon and their tangents along the shape.
|
|
218
|
+
*
|
|
219
|
+
* This method returns all intersection tangents (as vectors) with this shape. The returned array of vectors is in no specific order.
|
|
220
|
+
*
|
|
221
|
+
* @method lineIntersections
|
|
222
|
+
* @memberof VEllipseSectpr
|
|
223
|
+
* @param line
|
|
224
|
+
* @param lineIntersectionTangents
|
|
225
|
+
* @returns
|
|
226
|
+
*/
|
|
227
|
+
lineIntersectionTangents(line: VertTuple<any>, inVectorBoundsOnly: boolean = false): Array<Vector> {
|
|
228
|
+
// Find the intersections of all lines plus their tangents inside the circle bounds
|
|
229
|
+
const interSectionPoints: Array<Vertex> = this.lineIntersections(line, inVectorBoundsOnly);
|
|
230
|
+
return interSectionPoints.map((vert: Vertex) => {
|
|
231
|
+
// Calculate angle
|
|
232
|
+
const lineFromCenter = new Line(this.ellipse.center, vert);
|
|
233
|
+
const angle: number = lineFromCenter.angle();
|
|
234
|
+
// console.log("angle", (angle / Math.PI) * 180.0);
|
|
235
|
+
// const angle = Math.random() * Math.PI * 2; // TODO
|
|
236
|
+
// Calculate tangent at angle
|
|
237
|
+
return this.ellipse.tangentAt(angle);
|
|
238
|
+
});
|
|
239
|
+
}
|
|
240
|
+
//--- END --- Implement interface `Intersectable`
|
|
241
|
+
|
|
96
242
|
/**
|
|
97
243
|
* Convert this elliptic sector into cubic Bézier curves.
|
|
98
244
|
*
|
|
@@ -125,8 +271,8 @@ export class VEllipseSector {
|
|
|
125
271
|
let nextAngle = angles[(i + 1) % angles.length];
|
|
126
272
|
let endPoint: Vertex = this.ellipse.vertAt(nextAngle);
|
|
127
273
|
|
|
128
|
-
let startTangent: Vector = this.ellipse.tangentAt(curAngle);
|
|
129
|
-
let endTangent: Vector = this.ellipse.tangentAt(nextAngle);
|
|
274
|
+
let startTangent: Vector = this.ellipse.tangentAt(curAngle + this.ellipse.rotation);
|
|
275
|
+
let endTangent: Vector = this.ellipse.tangentAt(nextAngle + this.ellipse.rotation);
|
|
130
276
|
|
|
131
277
|
// Distorted ellipses can only be approximated by linear Bézier segments
|
|
132
278
|
if (Math.abs(radiusV) < 0.0001 || Math.abs(radiusH) < 0.0001) {
|
|
@@ -257,23 +403,23 @@ export class VEllipseSector {
|
|
|
257
403
|
endAngle: number,
|
|
258
404
|
fullEllipsePointCount: number
|
|
259
405
|
): Array<number> => {
|
|
260
|
-
var ellipseAngles = VEllipse.utils.equidistantVertAngles(radiusH, radiusV, fullEllipsePointCount);
|
|
406
|
+
var ellipseAngles: number[] = VEllipse.utils.equidistantVertAngles(radiusH, radiusV, fullEllipsePointCount);
|
|
261
407
|
ellipseAngles = ellipseAngles.map((angle: number) => VEllipseSector.ellipseSectorUtils.normalizeAngle(angle));
|
|
262
408
|
|
|
263
|
-
|
|
409
|
+
const angleIsInRange = (angle: number) => {
|
|
264
410
|
if (startAngle < endAngle) return angle >= startAngle && angle <= endAngle;
|
|
265
411
|
else return angle >= startAngle || (angle <= endAngle && angle >= 0);
|
|
266
412
|
};
|
|
267
413
|
// Drop all angles outside the sector
|
|
268
|
-
|
|
414
|
+
ellipseAngles = ellipseAngles.filter(angleIsInRange);
|
|
269
415
|
|
|
270
416
|
// Now we need to sort the angles to the first one in the array is the closest to startAngle.
|
|
271
417
|
// --> find the angle that is closest to the start angle
|
|
272
|
-
|
|
418
|
+
const startIndex: number = VEllipseSector.ellipseSectorUtils.findClosestToStartAngle(startAngle, endAngle, ellipseAngles);
|
|
273
419
|
|
|
274
420
|
// Bring all angles into the correct order
|
|
275
421
|
// Idea: use splice or slice here?
|
|
276
|
-
|
|
422
|
+
const angles: Array<number> = [];
|
|
277
423
|
for (var i = 0; i < ellipseAngles.length; i++) {
|
|
278
424
|
angles.push(ellipseAngles[(startIndex + i) % ellipseAngles.length]);
|
|
279
425
|
}
|
package/src/ts/Vector.ts
CHANGED
|
@@ -12,7 +12,8 @@
|
|
|
12
12
|
* @modified 2022-02-02 Added the `destroy` method.
|
|
13
13
|
* @modified 2022-02-02 Cleared the `Vector.toSVGString` function (deprecated). Use `drawutilssvg` instead.
|
|
14
14
|
* @modified 2022-10-25 Added the `getOrthogonal` method.
|
|
15
|
-
* @
|
|
15
|
+
* @modified 2025-04-14 Added the `Vector.rotate(number)` method.
|
|
16
|
+
* @version 1.6.0
|
|
16
17
|
*
|
|
17
18
|
* @file Vector
|
|
18
19
|
* @public
|
|
@@ -53,7 +54,6 @@ export class Vector extends VertTuple<Vector> implements SVGSerializable {
|
|
|
53
54
|
/**
|
|
54
55
|
* Get the perpendicular of this vector which is located at a.
|
|
55
56
|
*
|
|
56
|
-
* @param {Number} t The position on the vector.
|
|
57
57
|
* @return {Vector} A new vector being the perpendicular of this vector sitting on a.
|
|
58
58
|
**/
|
|
59
59
|
perp(): Vector {
|
|
@@ -136,6 +136,20 @@ export class Vector extends VertTuple<Vector> implements SVGSerializable {
|
|
|
136
136
|
return new Vector(linePoint, startPoint.add(this.a));
|
|
137
137
|
}
|
|
138
138
|
|
|
139
|
+
/**
|
|
140
|
+
* Rotate this vector by the given angle around the first point `a`.
|
|
141
|
+
*
|
|
142
|
+
* @name rotate
|
|
143
|
+
* @method rotate
|
|
144
|
+
* @return {Vector} this - for chaining.
|
|
145
|
+
* @instance
|
|
146
|
+
* @memberof Vector
|
|
147
|
+
*/
|
|
148
|
+
rotate(angle: number): Vector {
|
|
149
|
+
this.b.rotate(angle, this.a);
|
|
150
|
+
return this;
|
|
151
|
+
}
|
|
152
|
+
|
|
139
153
|
static utils = {
|
|
140
154
|
/**
|
|
141
155
|
* Generate a four-point arrow head, starting at the vector end minus the
|
package/src/ts/VertTuple.ts
CHANGED
|
@@ -13,7 +13,10 @@
|
|
|
13
13
|
* @modified 2024-09-10 Chaging the first param of `pointDistance` from `Vertex` to less strict type `XYCoords`. This should not break anything.
|
|
14
14
|
* @modified 2024-09-10 Adding the optional `epsilon` param to the `hasPoint` method.
|
|
15
15
|
* @modified 2024-12-02 Added the `epsilon` param to the `colinear` method. Default is 1.0e-6.
|
|
16
|
-
* @
|
|
16
|
+
* @modified 2025-03-31 Added the `VertTuple.revert` method.
|
|
17
|
+
* @modified 2025-04-15 Changed param of `VertTuple.moveTo` method from `Vertex` to `XYCoords`.
|
|
18
|
+
* @modified 2025-04-15 Added method `VertTuple.move` method.
|
|
19
|
+
* @version 1.4.0
|
|
17
20
|
*/
|
|
18
21
|
|
|
19
22
|
import { Vertex } from "./Vertex";
|
|
@@ -124,9 +127,9 @@ export class VertTuple<T extends VertTuple<T>> {
|
|
|
124
127
|
*
|
|
125
128
|
* @method add
|
|
126
129
|
* @param {XYCoords} amount The amount (x,y) to add.
|
|
127
|
-
* @return {Line} this
|
|
128
130
|
* @instance
|
|
129
131
|
* @memberof VertTuple
|
|
132
|
+
* @return {VertTuple<T>} this
|
|
130
133
|
**/
|
|
131
134
|
add(amount: XYCoords): VertTuple<T> {
|
|
132
135
|
this.a.add(amount);
|
|
@@ -134,6 +137,23 @@ export class VertTuple<T extends VertTuple<T>> {
|
|
|
134
137
|
return this;
|
|
135
138
|
}
|
|
136
139
|
|
|
140
|
+
/**
|
|
141
|
+
* Reverse this vertex tuple: a becomes b, and b becomes a.
|
|
142
|
+
* This operation is in-place.
|
|
143
|
+
*
|
|
144
|
+
* @method add
|
|
145
|
+
* @param {XYCoords} amount The amount (x,y) to add.
|
|
146
|
+
* @instance
|
|
147
|
+
* @memberof VertTuple
|
|
148
|
+
* @return {VertTuple<T>} this
|
|
149
|
+
*/
|
|
150
|
+
revert(): VertTuple<T> {
|
|
151
|
+
const tmp: Vertex = this.a;
|
|
152
|
+
this.a = this.b;
|
|
153
|
+
this.b = tmp;
|
|
154
|
+
return this;
|
|
155
|
+
}
|
|
156
|
+
|
|
137
157
|
/**
|
|
138
158
|
* Normalize this line (set to length 1).
|
|
139
159
|
*
|
|
@@ -165,18 +185,33 @@ export class VertTuple<T extends VertTuple<T>> {
|
|
|
165
185
|
* Move this line to a new location.
|
|
166
186
|
*
|
|
167
187
|
* @method moveTo
|
|
168
|
-
* @param {
|
|
188
|
+
* @param {XYCoords} newA - The new desired location of 'a'. Vertex 'b' will be moved, too.
|
|
169
189
|
* @return {VertTuple} this
|
|
170
190
|
* @instance
|
|
171
191
|
* @memberof VertTuple
|
|
172
192
|
**/
|
|
173
|
-
moveTo(newA:
|
|
193
|
+
moveTo(newA: XYCoords): VertTuple<T> {
|
|
174
194
|
let diff = this.a.difference(newA);
|
|
175
195
|
this.a.add(diff);
|
|
176
196
|
this.b.add(diff);
|
|
177
197
|
return this;
|
|
178
198
|
}
|
|
179
199
|
|
|
200
|
+
/**
|
|
201
|
+
* Move this line by the given amount
|
|
202
|
+
*
|
|
203
|
+
* @method move
|
|
204
|
+
* @param {XYCoords} amount - The amount to move both point of this tuple.
|
|
205
|
+
* @return {VertTuple} this
|
|
206
|
+
* @instance
|
|
207
|
+
* @memberof VertTuple
|
|
208
|
+
**/
|
|
209
|
+
move(amount: XYCoords): VertTuple<T> {
|
|
210
|
+
this.a.add(amount);
|
|
211
|
+
this.b.add(amount);
|
|
212
|
+
return this;
|
|
213
|
+
}
|
|
214
|
+
|
|
180
215
|
/**
|
|
181
216
|
* Get the angle between this and the passed line (in radians).
|
|
182
217
|
*
|