plotboilerplate 1.28.1 → 1.30.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 +8 -0
- package/dist/index.esm.js +527 -53
- 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 +528 -51
- package/dist/plotboilerplate.min.js +1 -1
- package/package.json +1 -1
- package/src/cjs/Circle.d.ts +86 -3
- package/src/cjs/Circle.js +179 -4
- package/src/cjs/Circle.js.map +1 -1
- package/src/cjs/CubicBezierCurve.d.ts +34 -3
- package/src/cjs/CubicBezierCurve.js +79 -12
- package/src/cjs/CubicBezierCurve.js.map +1 -1
- package/src/cjs/Line.d.ts +46 -1
- package/src/cjs/Line.js +80 -1
- package/src/cjs/Line.js.map +1 -1
- package/src/cjs/Triangle.d.ts +40 -4
- package/src/cjs/Triangle.js +127 -31
- package/src/cjs/Triangle.js.map +1 -1
- package/src/cjs/VertTuple.d.ts +16 -2
- package/src/cjs/VertTuple.js +20 -2
- package/src/cjs/VertTuple.js.map +1 -1
- package/src/cjs/Vertex.d.ts +25 -2
- package/src/cjs/Vertex.js +43 -1
- package/src/cjs/Vertex.js.map +1 -1
- package/src/cjs/utils/algorithms/minimalContainingCircleFromPoints.d.ts +21 -0
- package/src/cjs/utils/algorithms/minimalContainingCircleFromPoints.js +73 -0
- package/src/cjs/utils/algorithms/minimalContainingCircleFromPoints.js.map +1 -0
- package/src/cjs/utils/algorithms/minimalEnclosingCircleFromPoints.d.ts +21 -0
- package/src/cjs/utils/algorithms/minimalEnclosingCircleFromPoints.js +73 -0
- package/src/cjs/utils/algorithms/minimalEnclosingCircleFromPoints.js.map +1 -0
- package/src/cjs/utils/algorithms/pointsMinimalContainingCircle.d.ts +21 -0
- package/src/cjs/utils/algorithms/pointsMinimalContainingCircle.js +73 -0
- package/src/cjs/utils/algorithms/pointsMinimalContainingCircle.js.map +1 -0
- package/src/cjs/utils/algorithms/solveApollonius3.d.ts +69 -0
- package/src/cjs/utils/algorithms/solveApollonius3.js +118 -0
- package/src/cjs/utils/algorithms/solveApollonius3.js.map +1 -0
- package/src/esm/Circle.d.ts +86 -3
- package/src/esm/Circle.js +179 -4
- package/src/esm/Circle.js.map +1 -1
- package/src/esm/CubicBezierCurve.d.ts +34 -3
- package/src/esm/CubicBezierCurve.js +79 -12
- package/src/esm/CubicBezierCurve.js.map +1 -1
- package/src/esm/Line.d.ts +46 -1
- package/src/esm/Line.js +80 -1
- package/src/esm/Line.js.map +1 -1
- package/src/esm/Triangle.d.ts +40 -4
- package/src/esm/Triangle.js +128 -32
- package/src/esm/Triangle.js.map +1 -1
- package/src/esm/VertTuple.d.ts +16 -2
- package/src/esm/VertTuple.js +20 -2
- package/src/esm/VertTuple.js.map +1 -1
- package/src/esm/Vertex.d.ts +25 -2
- package/src/esm/Vertex.js +44 -2
- package/src/esm/Vertex.js.map +1 -1
- package/src/esm/utils/algorithms/minimalContainingCircleFromPoints.d.ts +21 -0
- package/src/esm/utils/algorithms/minimalContainingCircleFromPoints.js +69 -0
- package/src/esm/utils/algorithms/minimalContainingCircleFromPoints.js.map +1 -0
- package/src/esm/utils/algorithms/minimalEnclosingCircleFromPoints.d.ts +21 -0
- package/src/esm/utils/algorithms/minimalEnclosingCircleFromPoints.js +69 -0
- package/src/esm/utils/algorithms/minimalEnclosingCircleFromPoints.js.map +1 -0
- package/src/esm/utils/algorithms/pointsMinimalContainingCircle.d.ts +21 -0
- package/src/esm/utils/algorithms/pointsMinimalContainingCircle.js +69 -0
- package/src/esm/utils/algorithms/pointsMinimalContainingCircle.js.map +1 -0
- package/src/esm/utils/algorithms/solveApollonius3.d.ts +69 -0
- package/src/esm/utils/algorithms/solveApollonius3.js +114 -0
- package/src/esm/utils/algorithms/solveApollonius3.js.map +1 -0
- package/src/index-gl.js +6 -4
- package/src/index.js +25 -17
- package/src/ts/Circle.ts +200 -5
- package/src/ts/CubicBezierCurve.ts +133 -48
- package/src/ts/Line.ts +84 -1
- package/src/ts/Triangle.ts +148 -41
- package/src/ts/VertTuple.ts +29 -2
- package/src/ts/Vertex.ts +44 -2
- package/src/ts/utils/algorithms/minimalEnclosingCircleFromPoints.ts +69 -0
- package/src/ts/utils/algorithms/solveApollonius3.ts +132 -0
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Calculate the minimal containing circle from a set of points.
|
|
4
|
+
*
|
|
5
|
+
* The number of points must be at least 2. Otherwise the function returns null.
|
|
6
|
+
*
|
|
7
|
+
* Inspired by https://github.com/rowanwins/smallest-enclosing-circle.
|
|
8
|
+
*
|
|
9
|
+
* @param {XYCoords[]} points
|
|
10
|
+
* @returns
|
|
11
|
+
*/
|
|
12
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
13
|
+
exports.pointsMinimalContainingCircle = void 0;
|
|
14
|
+
var Circle_1 = require("../../Circle");
|
|
15
|
+
var Triangle_1 = require("../../Triangle");
|
|
16
|
+
var VertTuple_1 = require("../../VertTuple");
|
|
17
|
+
var Vertex_1 = require("../../Vertex");
|
|
18
|
+
/**
|
|
19
|
+
* Calculate the minimal containing circle from a set of points.
|
|
20
|
+
*
|
|
21
|
+
* The number of points must be at least 2. Otherwise the function returns null.
|
|
22
|
+
*
|
|
23
|
+
* @param {XYCoords[]} points
|
|
24
|
+
* @returns {Circle | null} The minimal containing circle or null if the point count is lower than 2.
|
|
25
|
+
*/
|
|
26
|
+
var pointsMinimalContainingCircle = function (points) {
|
|
27
|
+
if (points.length <= 1) {
|
|
28
|
+
return null;
|
|
29
|
+
}
|
|
30
|
+
var circleObject = wetzlsAlgorithm(points);
|
|
31
|
+
return new Circle_1.Circle(new Vertex_1.Vertex(circleObject.center.x, circleObject.center.y), circleObject.radius);
|
|
32
|
+
};
|
|
33
|
+
exports.pointsMinimalContainingCircle = pointsMinimalContainingCircle;
|
|
34
|
+
/**
|
|
35
|
+
* This initiates the actual algorithm but return a shallow circle representation.
|
|
36
|
+
*
|
|
37
|
+
* @param points
|
|
38
|
+
* @returns
|
|
39
|
+
*/
|
|
40
|
+
var wetzlsAlgorithm = function (points) {
|
|
41
|
+
return minimumContainingCircle(points, points.length, [], 0);
|
|
42
|
+
};
|
|
43
|
+
/**
|
|
44
|
+
* Pre: points.length >= 2
|
|
45
|
+
* @param {Vertex[]} points
|
|
46
|
+
* @param n
|
|
47
|
+
* @param boundary
|
|
48
|
+
* @param boundaryLength
|
|
49
|
+
* @returns
|
|
50
|
+
*/
|
|
51
|
+
var minimumContainingCircle = function (points, n, boundary, boundaryLength) {
|
|
52
|
+
if (boundaryLength === 3) {
|
|
53
|
+
return Triangle_1.Triangle.utils.calcCircumcircle(boundary[0], boundary[1], boundary[2]);
|
|
54
|
+
}
|
|
55
|
+
else if (n === 1 && boundaryLength === 0) {
|
|
56
|
+
return { center: { x: points[0].x, y: points[0].y }, radius: 0 };
|
|
57
|
+
}
|
|
58
|
+
else if (n === 0 && boundaryLength === 2) {
|
|
59
|
+
return VertTuple_1.VertTuple.vtutils.calcCircumcircle(boundary[0], boundary[1]);
|
|
60
|
+
}
|
|
61
|
+
else if (n === 1 && boundaryLength === 1) {
|
|
62
|
+
return VertTuple_1.VertTuple.vtutils.calcCircumcircle(boundary[0], points[0]);
|
|
63
|
+
}
|
|
64
|
+
else {
|
|
65
|
+
var localCircle = minimumContainingCircle(points, n - 1, boundary, boundaryLength);
|
|
66
|
+
if (!Circle_1.Circle.circleUtils.containsPoint(points[n - 1], localCircle)) {
|
|
67
|
+
boundary[boundaryLength++] = points[n - 1];
|
|
68
|
+
return minimumContainingCircle(points, n - 1, boundary, boundaryLength);
|
|
69
|
+
}
|
|
70
|
+
return localCircle;
|
|
71
|
+
}
|
|
72
|
+
};
|
|
73
|
+
//# sourceMappingURL=pointsMinimalContainingCircle.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pointsMinimalContainingCircle.js","sourceRoot":"","sources":["../../../ts/utils/algorithms/pointsMinimalContainingCircle.ts"],"names":[],"mappings":";AAAA;;;;;;;;;GASG;;;AAEH,uCAA+C;AAC/C,2CAA0C;AAC1C,6CAA4C;AAC5C,uCAAsC;AAGtC;;;;;;;GAOG;AACI,IAAM,6BAA6B,GAAG,UAAC,MAAkB;IAC9D,IAAI,MAAM,CAAC,MAAM,IAAI,CAAC,EAAE,CAAC;QACvB,OAAO,IAAI,CAAC;IACd,CAAC;IACD,IAAM,YAAY,GAAG,eAAe,CAAC,MAAM,CAAC,CAAC;IAC7C,OAAO,IAAI,eAAM,CAAC,IAAI,eAAM,CAAC,YAAY,CAAC,MAAM,CAAC,CAAC,EAAE,YAAY,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,YAAY,CAAC,MAAM,CAAC,CAAC;AACnG,CAAC,CAAC;AANW,QAAA,6BAA6B,iCAMxC;AAEF;;;;;GAKG;AACH,IAAM,eAAe,GAAG,UAAC,MAAkB;IACzC,OAAO,uBAAuB,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,EAAE,EAAE,CAAC,CAAC,CAAC;AAC/D,CAAC,CAAC;AAEF;;;;;;;GAOG;AACH,IAAM,uBAAuB,GAAG,UAAC,MAAkB,EAAE,CAAS,EAAE,QAAoB,EAAE,cAAsB;IAC1G,IAAI,cAAc,KAAK,CAAC,EAAE,CAAC;QACzB,OAAO,mBAAQ,CAAC,KAAK,CAAC,gBAAgB,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,QAAQ,CAAC,CAAC,CAAC,EAAE,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC;IAChF,CAAC;SAAM,IAAI,CAAC,KAAK,CAAC,IAAI,cAAc,KAAK,CAAC,EAAE,CAAC;QAC3C,OAAO,EAAE,MAAM,EAAE,EAAE,CAAC,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,EAAE,MAAM,EAAE,CAAC,EAAE,CAAC;IACnE,CAAC;SAAM,IAAI,CAAC,KAAK,CAAC,IAAI,cAAc,KAAK,CAAC,EAAE,CAAC;QAC3C,OAAO,qBAAS,CAAC,OAAO,CAAC,gBAAgB,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC;IACtE,CAAC;SAAM,IAAI,CAAC,KAAK,CAAC,IAAI,cAAc,KAAK,CAAC,EAAE,CAAC;QAC3C,OAAO,qBAAS,CAAC,OAAO,CAAC,gBAAgB,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC;IACpE,CAAC;SAAM,CAAC;QACN,IAAM,WAAW,GAAY,uBAAuB,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,EAAE,QAAQ,EAAE,cAAc,CAAC,CAAC;QAC9F,IAAI,CAAC,eAAM,CAAC,WAAW,CAAC,aAAa,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,CAAC,EAAE,WAAW,CAAC,EAAE,CAAC;YAClE,QAAQ,CAAC,cAAc,EAAE,CAAC,GAAG,MAAM,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;YAC3C,OAAO,uBAAuB,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,EAAE,QAAQ,EAAE,cAAc,CAAC,CAAC;QAC1E,CAAC;QACD,OAAO,WAAW,CAAC;IACrB,CAAC;AACH,CAAC,CAAC"}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A solver for the Apollonian circle problem:
|
|
3
|
+
* find the circle that touches three other circles in extactly one point (each).
|
|
4
|
+
* The solution is not necesarily unique.
|
|
5
|
+
*
|
|
6
|
+
* For each of the three circles a boolean attribute can be passed that determines if the
|
|
7
|
+
* resultint circle should touch the input circle should be touched on the inside or outside.
|
|
8
|
+
*
|
|
9
|
+
* Not that there can be condition when the circle cannot be calculated (e.g. all circles
|
|
10
|
+
* have the same size and are colinear).
|
|
11
|
+
*
|
|
12
|
+
* Found at
|
|
13
|
+
* https://stackoverflow.com/questions/79281573/algorithm-for-finding-enclosing-circles-for-3-other-circles
|
|
14
|
+
*
|
|
15
|
+
* solveApollonius(Coord c1, Coord c2, Coord c3, int s1, int s2, int s3) {
|
|
16
|
+
// https://github.com/DIKU-Steiner/ProGAL/blob/master/src/ProGAL/geom2d/ApolloniusSolver.java
|
|
17
|
+
|
|
18
|
+
var x1 = c1.x;
|
|
19
|
+
var y1 = c1.y;
|
|
20
|
+
var r1 = c1.z;
|
|
21
|
+
var x2 = c2.x;
|
|
22
|
+
var y2 = c2.y;
|
|
23
|
+
var r2 = c2.z;
|
|
24
|
+
var x3 = c3.x;
|
|
25
|
+
var y3 = c3.y;
|
|
26
|
+
var r3 = c3.z;
|
|
27
|
+
|
|
28
|
+
// Currently optimized for fewest multiplications.
|
|
29
|
+
var v11 = 2 * x2 - 2 * x1;
|
|
30
|
+
var v12 = 2 * y2 - 2 * y1;
|
|
31
|
+
var v13 = x1 * x1 - x2 * x2 + y1 * y1 - y2 * y2 - r1 * r1 + r2 * r2;
|
|
32
|
+
var v14 = 2 * s2 * r2 - 2 * s1 * r1;
|
|
33
|
+
|
|
34
|
+
var v21 = 2 * x3 - 2 * x2;
|
|
35
|
+
var v22 = 2 * y3 - 2 * y2;
|
|
36
|
+
var v23 = x2 * x2 - x3 * x3 + y2 * y2 - y3 * y3 - r2 * r2 + r3 * r3;
|
|
37
|
+
var v24 = 2 * s3 * r3 - 2 * s2 * r2;
|
|
38
|
+
|
|
39
|
+
var w12 = v12 / v11;
|
|
40
|
+
var w13 = v13 / v11;
|
|
41
|
+
var w14 = v14 / v11;
|
|
42
|
+
|
|
43
|
+
var w22 = v22 / v21 - w12;
|
|
44
|
+
var w23 = v23 / v21 - w13;
|
|
45
|
+
var w24 = v24 / v21 - w14;
|
|
46
|
+
|
|
47
|
+
var P = -w23 / w22;
|
|
48
|
+
var Q = w24 / w22;
|
|
49
|
+
var M = -w12 * P - w13;
|
|
50
|
+
var N = w14 - w12 * Q;
|
|
51
|
+
|
|
52
|
+
var a = N * N + Q * Q - 1;
|
|
53
|
+
var b = 2 * M * N - 2 * N * x1 + 2 * P * Q - 2 * Q * y1 + 2 * s1 * r1;
|
|
54
|
+
var c = x1 * x1 + M * M - 2 * M * x1 + P * P + y1 * y1 - 2 * P * y1 - r1 * r1;
|
|
55
|
+
|
|
56
|
+
// Find a root of a quadratic equation. This requires the circle centers not
|
|
57
|
+
// to be e.g. colinear
|
|
58
|
+
var D = b * b - 4 * a * c;
|
|
59
|
+
var rs = (-b - Math.sqrt(D)) / (2 * a);
|
|
60
|
+
var xs = M + N * rs;
|
|
61
|
+
var ys = P + Q * rs;
|
|
62
|
+
|
|
63
|
+
return (xs, ys, rs);
|
|
64
|
+
}
|
|
65
|
+
*
|
|
66
|
+
* @date 2026-07-03
|
|
67
|
+
*/
|
|
68
|
+
import { Circle, ICircle } from "../../Circle";
|
|
69
|
+
export declare const solveApollonius3: (c1: ICircle, c2: ICircle, c3: ICircle, circle1Inside?: boolean, circle2Inside?: boolean, circle3Inside?: boolean) => Circle;
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* A solver for the Apollonian circle problem:
|
|
4
|
+
* find the circle that touches three other circles in extactly one point (each).
|
|
5
|
+
* The solution is not necesarily unique.
|
|
6
|
+
*
|
|
7
|
+
* For each of the three circles a boolean attribute can be passed that determines if the
|
|
8
|
+
* resultint circle should touch the input circle should be touched on the inside or outside.
|
|
9
|
+
*
|
|
10
|
+
* Not that there can be condition when the circle cannot be calculated (e.g. all circles
|
|
11
|
+
* have the same size and are colinear).
|
|
12
|
+
*
|
|
13
|
+
* Found at
|
|
14
|
+
* https://stackoverflow.com/questions/79281573/algorithm-for-finding-enclosing-circles-for-3-other-circles
|
|
15
|
+
*
|
|
16
|
+
* solveApollonius(Coord c1, Coord c2, Coord c3, int s1, int s2, int s3) {
|
|
17
|
+
// https://github.com/DIKU-Steiner/ProGAL/blob/master/src/ProGAL/geom2d/ApolloniusSolver.java
|
|
18
|
+
|
|
19
|
+
var x1 = c1.x;
|
|
20
|
+
var y1 = c1.y;
|
|
21
|
+
var r1 = c1.z;
|
|
22
|
+
var x2 = c2.x;
|
|
23
|
+
var y2 = c2.y;
|
|
24
|
+
var r2 = c2.z;
|
|
25
|
+
var x3 = c3.x;
|
|
26
|
+
var y3 = c3.y;
|
|
27
|
+
var r3 = c3.z;
|
|
28
|
+
|
|
29
|
+
// Currently optimized for fewest multiplications.
|
|
30
|
+
var v11 = 2 * x2 - 2 * x1;
|
|
31
|
+
var v12 = 2 * y2 - 2 * y1;
|
|
32
|
+
var v13 = x1 * x1 - x2 * x2 + y1 * y1 - y2 * y2 - r1 * r1 + r2 * r2;
|
|
33
|
+
var v14 = 2 * s2 * r2 - 2 * s1 * r1;
|
|
34
|
+
|
|
35
|
+
var v21 = 2 * x3 - 2 * x2;
|
|
36
|
+
var v22 = 2 * y3 - 2 * y2;
|
|
37
|
+
var v23 = x2 * x2 - x3 * x3 + y2 * y2 - y3 * y3 - r2 * r2 + r3 * r3;
|
|
38
|
+
var v24 = 2 * s3 * r3 - 2 * s2 * r2;
|
|
39
|
+
|
|
40
|
+
var w12 = v12 / v11;
|
|
41
|
+
var w13 = v13 / v11;
|
|
42
|
+
var w14 = v14 / v11;
|
|
43
|
+
|
|
44
|
+
var w22 = v22 / v21 - w12;
|
|
45
|
+
var w23 = v23 / v21 - w13;
|
|
46
|
+
var w24 = v24 / v21 - w14;
|
|
47
|
+
|
|
48
|
+
var P = -w23 / w22;
|
|
49
|
+
var Q = w24 / w22;
|
|
50
|
+
var M = -w12 * P - w13;
|
|
51
|
+
var N = w14 - w12 * Q;
|
|
52
|
+
|
|
53
|
+
var a = N * N + Q * Q - 1;
|
|
54
|
+
var b = 2 * M * N - 2 * N * x1 + 2 * P * Q - 2 * Q * y1 + 2 * s1 * r1;
|
|
55
|
+
var c = x1 * x1 + M * M - 2 * M * x1 + P * P + y1 * y1 - 2 * P * y1 - r1 * r1;
|
|
56
|
+
|
|
57
|
+
// Find a root of a quadratic equation. This requires the circle centers not
|
|
58
|
+
// to be e.g. colinear
|
|
59
|
+
var D = b * b - 4 * a * c;
|
|
60
|
+
var rs = (-b - Math.sqrt(D)) / (2 * a);
|
|
61
|
+
var xs = M + N * rs;
|
|
62
|
+
var ys = P + Q * rs;
|
|
63
|
+
|
|
64
|
+
return (xs, ys, rs);
|
|
65
|
+
}
|
|
66
|
+
*
|
|
67
|
+
* @date 2026-07-03
|
|
68
|
+
*/
|
|
69
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
70
|
+
exports.solveApollonius3 = void 0;
|
|
71
|
+
var Circle_1 = require("../../Circle");
|
|
72
|
+
var Vertex_1 = require("../../Vertex");
|
|
73
|
+
var solveApollonius3 = function (c1, c2, c3, circle1Inside, circle2Inside, circle3Inside) {
|
|
74
|
+
// https://github.com/DIKU-Steiner/ProGAL/blob/master/src/ProGAL/geom2d/ApolloniusSolver.java
|
|
75
|
+
var x1 = c1.center.x;
|
|
76
|
+
var y1 = c1.center.y;
|
|
77
|
+
var r1 = c1.radius;
|
|
78
|
+
var x2 = c2.center.x;
|
|
79
|
+
var y2 = c2.center.y;
|
|
80
|
+
var r2 = c2.radius;
|
|
81
|
+
var x3 = c3.center.x;
|
|
82
|
+
var y3 = c3.center.y;
|
|
83
|
+
var r3 = c3.radius;
|
|
84
|
+
var s1 = Boolean(circle1Inside) ? 1 : -1;
|
|
85
|
+
var s2 = Boolean(circle2Inside) ? 1 : -1;
|
|
86
|
+
var s3 = Boolean(circle3Inside) ? 1 : -1;
|
|
87
|
+
// Currently optimized for fewest multiplications.
|
|
88
|
+
var v11 = 2 * x2 - 2 * x1;
|
|
89
|
+
var v12 = 2 * y2 - 2 * y1;
|
|
90
|
+
var v13 = x1 * x1 - x2 * x2 + y1 * y1 - y2 * y2 - r1 * r1 + r2 * r2;
|
|
91
|
+
var v14 = 2 * s2 * r2 - 2 * s1 * r1;
|
|
92
|
+
var v21 = 2 * x3 - 2 * x2;
|
|
93
|
+
var v22 = 2 * y3 - 2 * y2;
|
|
94
|
+
var v23 = x2 * x2 - x3 * x3 + y2 * y2 - y3 * y3 - r2 * r2 + r3 * r3;
|
|
95
|
+
var v24 = 2 * s3 * r3 - 2 * s2 * r2;
|
|
96
|
+
var w12 = v12 / v11;
|
|
97
|
+
var w13 = v13 / v11;
|
|
98
|
+
var w14 = v14 / v11;
|
|
99
|
+
var w22 = v22 / v21 - w12;
|
|
100
|
+
var w23 = v23 / v21 - w13;
|
|
101
|
+
var w24 = v24 / v21 - w14;
|
|
102
|
+
var P = -w23 / w22;
|
|
103
|
+
var Q = w24 / w22;
|
|
104
|
+
var M = -w12 * P - w13;
|
|
105
|
+
var N = w14 - w12 * Q;
|
|
106
|
+
var a = N * N + Q * Q - 1;
|
|
107
|
+
var b = 2 * M * N - 2 * N * x1 + 2 * P * Q - 2 * Q * y1 + 2 * s1 * r1;
|
|
108
|
+
var c = x1 * x1 + M * M - 2 * M * x1 + P * P + y1 * y1 - 2 * P * y1 - r1 * r1;
|
|
109
|
+
// Find a root of a quadratic equation. This requires the circle centers not
|
|
110
|
+
// to be e.g. colinear
|
|
111
|
+
var D = b * b - 4 * a * c;
|
|
112
|
+
var rs = (-b - Math.sqrt(D)) / (2 * a);
|
|
113
|
+
var xs = M + N * rs;
|
|
114
|
+
var ys = P + Q * rs;
|
|
115
|
+
return new Circle_1.Circle(new Vertex_1.Vertex(xs, ys), Math.abs(rs));
|
|
116
|
+
};
|
|
117
|
+
exports.solveApollonius3 = solveApollonius3;
|
|
118
|
+
//# sourceMappingURL=solveApollonius3.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"solveApollonius3.js","sourceRoot":"","sources":["../../../ts/utils/algorithms/solveApollonius3.ts"],"names":[],"mappings":"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"}
|
package/src/esm/Circle.d.ts
CHANGED
|
@@ -14,7 +14,16 @@
|
|
|
14
14
|
* @modified 2022-08-23 Added the `closestPoint` function.
|
|
15
15
|
* @modified 2025-04-09 Added the `Circle.move(amount: XYCoords)` method.
|
|
16
16
|
* @modified 2025-04-16 Class `Circle` now implements interface `Intersectable`.
|
|
17
|
-
* @
|
|
17
|
+
* @modified 2026-06-10 Adding the utility function `Circle.circleUtils.containsPoint`.
|
|
18
|
+
* @modified 2026-06-10 Adding the `Circle.clone` method.
|
|
19
|
+
* @modified 2026-01-13 Adding helper function `Circle.circleUtils.containsPoint` and refactored the member method `containsPoint`.
|
|
20
|
+
* @modified 2026-07-03 Adding the optional `epsilon` parameter to the `Circle.containsCircle` method.
|
|
21
|
+
* @modified 2026-07-03 Fixing the `Circle.clone` method; the center had not been cloned at all, this was fixed.
|
|
22
|
+
* @modified 2026-07-08 Adding the `Circle.setRadius` method (for chaining).
|
|
23
|
+
* @mofified 2026-07-31 Adding the `radicalAxis(Circle)` method. Added the `Circle.circleUtils.createRadicalAxisHelperCircle` and `.circleDistance` helper methods.
|
|
24
|
+
* @modified 2026-08-03 Adding `Circle.tangentsFromPoint`.
|
|
25
|
+
* @modified 2026-08-16 Adding the `Circle.sectorAngleByArcLength` method and the `Circle.circleUtils.sectorAngleByArcLength` helper method.
|
|
26
|
+
* @version 1.8.0
|
|
18
27
|
**/
|
|
19
28
|
import { Bounds } from "./Bounds";
|
|
20
29
|
import { Line } from "./Line";
|
|
@@ -22,6 +31,11 @@ import { Vector } from "./Vector";
|
|
|
22
31
|
import { VertTuple } from "./VertTuple";
|
|
23
32
|
import { Vertex } from "./Vertex";
|
|
24
33
|
import { IBounded, Intersectable, SVGSerializable, UID, XYCoords } from "./interfaces";
|
|
34
|
+
export interface ICircle {
|
|
35
|
+
center: XYCoords;
|
|
36
|
+
radius: number;
|
|
37
|
+
radius_squared?: number;
|
|
38
|
+
}
|
|
25
39
|
/**
|
|
26
40
|
* @classdesc A simple circle: center point and radius.
|
|
27
41
|
*
|
|
@@ -33,7 +47,7 @@ import { IBounded, Intersectable, SVGSerializable, UID, XYCoords } from "./inter
|
|
|
33
47
|
* @requires UID
|
|
34
48
|
* @requires UIDGenerator
|
|
35
49
|
**/
|
|
36
|
-
export declare class Circle implements IBounded, Intersectable, SVGSerializable {
|
|
50
|
+
export declare class Circle implements IBounded, ICircle, Intersectable, SVGSerializable {
|
|
37
51
|
/**
|
|
38
52
|
* Required to generate proper CSS classes and other class related IDs.
|
|
39
53
|
**/
|
|
@@ -75,6 +89,17 @@ export declare class Circle implements IBounded, Intersectable, SVGSerializable
|
|
|
75
89
|
* @param {number} radius - The radius of the circle.
|
|
76
90
|
*/
|
|
77
91
|
constructor(center: Vertex, radius: number);
|
|
92
|
+
/**
|
|
93
|
+
* Set the radius of this circle.
|
|
94
|
+
* The method is meant for chaining, you may also alter the `radius` attribute directly.
|
|
95
|
+
*
|
|
96
|
+
* @method setRadius
|
|
97
|
+
* @param {number} radius - The amount to move.
|
|
98
|
+
* @instance
|
|
99
|
+
* @memberof Circle
|
|
100
|
+
* @return {Circle} this for chaining
|
|
101
|
+
**/
|
|
102
|
+
setRadius(radius: number): Circle;
|
|
78
103
|
/**
|
|
79
104
|
* Move the circle by the given amount.
|
|
80
105
|
*
|
|
@@ -104,7 +129,7 @@ export declare class Circle implements IBounded, Intersectable, SVGSerializable
|
|
|
104
129
|
* @memberof Circle
|
|
105
130
|
* @return {boolean} `true` if any only if the given circle is completely inside this circle.
|
|
106
131
|
*/
|
|
107
|
-
containsCircle(circle: Circle): boolean;
|
|
132
|
+
containsCircle(circle: Circle, epsilon?: number): boolean;
|
|
108
133
|
/**
|
|
109
134
|
* Calculate the distance from this circle to the given line.
|
|
110
135
|
*
|
|
@@ -192,6 +217,20 @@ export declare class Circle implements IBounded, Intersectable, SVGSerializable
|
|
|
192
217
|
* @returns
|
|
193
218
|
*/
|
|
194
219
|
lineIntersectionTangents(line: VertTuple<any>, inVectorBoundsOnly?: boolean): Array<Vector>;
|
|
220
|
+
/**
|
|
221
|
+
* Calculate the radical axis of this and a different circle.
|
|
222
|
+
* The two circles must not be co-centric.
|
|
223
|
+
*
|
|
224
|
+
* See this article for details:
|
|
225
|
+
* https://www.cut-the-knot.org/Curriculum/Geometry/GeoGebra/RadicalAxes.shtml
|
|
226
|
+
*
|
|
227
|
+
* @method radicalAxis
|
|
228
|
+
* @instance
|
|
229
|
+
* @memberof Circle
|
|
230
|
+
* @param {Circle} circleB - The second circle to calculated the radical axis for.
|
|
231
|
+
* @return {Line} A line defining the radical axis of the two circles.
|
|
232
|
+
**/
|
|
233
|
+
radicalAxis(circleB: Circle): Line;
|
|
195
234
|
/**
|
|
196
235
|
* Calculate the closest point on the outline of this circle to the given point.
|
|
197
236
|
*
|
|
@@ -202,6 +241,34 @@ export declare class Circle implements IBounded, Intersectable, SVGSerializable
|
|
|
202
241
|
* @return {Vertex} The closest point on this circle.
|
|
203
242
|
**/
|
|
204
243
|
closestPoint(vert: XYCoords): Vertex;
|
|
244
|
+
/**
|
|
245
|
+
* Get the two tangent vectors for the given point.
|
|
246
|
+
* If the point is on or in the circle then null is returned.
|
|
247
|
+
*
|
|
248
|
+
* @method tangentsFromPoint
|
|
249
|
+
* @instance
|
|
250
|
+
* @memberof Circle
|
|
251
|
+
* @param {Vertex} vert - The point to find the two tangents for.
|
|
252
|
+
* @return {[Vector,Vector]} The two tangent vector
|
|
253
|
+
**/
|
|
254
|
+
tangentsFromPoint(vert: Vertex): [Vector, Vector];
|
|
255
|
+
/**
|
|
256
|
+
* Calculate inner sector angle for this circle and a given circle arc length.
|
|
257
|
+
*
|
|
258
|
+
* @param {number} sectorArcLength - The desired arc length (in units).
|
|
259
|
+
* @returns The sector's inner angle (in radians).
|
|
260
|
+
*/
|
|
261
|
+
sectorAngleByArcLength(sectorArcLength: number): number;
|
|
262
|
+
/**
|
|
263
|
+
* Create a deep copy of this circle.
|
|
264
|
+
*
|
|
265
|
+
* @method clone
|
|
266
|
+
* @return {Circle} A new circle, an exact copy of this one.
|
|
267
|
+
* @instance
|
|
268
|
+
* @memberof Circle
|
|
269
|
+
**/
|
|
270
|
+
clone(): Circle;
|
|
271
|
+
static fromICircle(obj: ICircle): Circle;
|
|
205
272
|
/**
|
|
206
273
|
* This function should invalidate any installed listeners and invalidate this object.
|
|
207
274
|
* After calling this function the object might not hold valid data any more and
|
|
@@ -210,5 +277,21 @@ export declare class Circle implements IBounded, Intersectable, SVGSerializable
|
|
|
210
277
|
destroy(): void;
|
|
211
278
|
static circleUtils: {
|
|
212
279
|
vertAt: (angle: number, radius: number) => Vertex;
|
|
280
|
+
containsPoint: (circleCenter: XYCoords, circleRadius: number, point: XYCoords) => boolean;
|
|
281
|
+
createRadicalAxisHelperCircle: (circleA: Circle, circleB: Circle) => Circle;
|
|
282
|
+
/**
|
|
283
|
+
* Calculate the outer distance between two circles. If the circles touch then the
|
|
284
|
+
* distance is 0.0.
|
|
285
|
+
* If the circles intersect then the distance in negative.
|
|
286
|
+
*/
|
|
287
|
+
circleDistance: (circleA: Circle, circleB: Circle) => number;
|
|
288
|
+
/**
|
|
289
|
+
* Calculate the inner sector angle for a given circle arc length and radius.
|
|
290
|
+
*
|
|
291
|
+
* @param {number} sectorArcLength - The desired arc length.
|
|
292
|
+
* @param {number} circleRadius - The circle's radius.
|
|
293
|
+
* @returns The sector angle in radians.
|
|
294
|
+
*/
|
|
295
|
+
sectorAngleByArcLength: (sectorArcLength: number, circleRadius: number) => number;
|
|
213
296
|
};
|
|
214
297
|
}
|
package/src/esm/Circle.js
CHANGED
|
@@ -14,13 +14,23 @@
|
|
|
14
14
|
* @modified 2022-08-23 Added the `closestPoint` function.
|
|
15
15
|
* @modified 2025-04-09 Added the `Circle.move(amount: XYCoords)` method.
|
|
16
16
|
* @modified 2025-04-16 Class `Circle` now implements interface `Intersectable`.
|
|
17
|
-
* @
|
|
17
|
+
* @modified 2026-06-10 Adding the utility function `Circle.circleUtils.containsPoint`.
|
|
18
|
+
* @modified 2026-06-10 Adding the `Circle.clone` method.
|
|
19
|
+
* @modified 2026-01-13 Adding helper function `Circle.circleUtils.containsPoint` and refactored the member method `containsPoint`.
|
|
20
|
+
* @modified 2026-07-03 Adding the optional `epsilon` parameter to the `Circle.containsCircle` method.
|
|
21
|
+
* @modified 2026-07-03 Fixing the `Circle.clone` method; the center had not been cloned at all, this was fixed.
|
|
22
|
+
* @modified 2026-07-08 Adding the `Circle.setRadius` method (for chaining).
|
|
23
|
+
* @mofified 2026-07-31 Adding the `radicalAxis(Circle)` method. Added the `Circle.circleUtils.createRadicalAxisHelperCircle` and `.circleDistance` helper methods.
|
|
24
|
+
* @modified 2026-08-03 Adding `Circle.tangentsFromPoint`.
|
|
25
|
+
* @modified 2026-08-16 Adding the `Circle.sectorAngleByArcLength` method and the `Circle.circleUtils.sectorAngleByArcLength` helper method.
|
|
26
|
+
* @version 1.8.0
|
|
18
27
|
**/
|
|
19
28
|
import { Bounds } from "./Bounds";
|
|
20
29
|
import { Line } from "./Line";
|
|
21
30
|
import { UIDGenerator } from "./UIDGenerator";
|
|
22
31
|
import { Vector } from "./Vector";
|
|
23
32
|
import { Vertex } from "./Vertex";
|
|
33
|
+
import { geomutils } from "./geomutils";
|
|
24
34
|
/**
|
|
25
35
|
* @classdesc A simple circle: center point and radius.
|
|
26
36
|
*
|
|
@@ -50,6 +60,20 @@ export class Circle {
|
|
|
50
60
|
this.center = center;
|
|
51
61
|
this.radius = radius;
|
|
52
62
|
}
|
|
63
|
+
/**
|
|
64
|
+
* Set the radius of this circle.
|
|
65
|
+
* The method is meant for chaining, you may also alter the `radius` attribute directly.
|
|
66
|
+
*
|
|
67
|
+
* @method setRadius
|
|
68
|
+
* @param {number} radius - The amount to move.
|
|
69
|
+
* @instance
|
|
70
|
+
* @memberof Circle
|
|
71
|
+
* @return {Circle} this for chaining
|
|
72
|
+
**/
|
|
73
|
+
setRadius(radius) {
|
|
74
|
+
this.radius = radius;
|
|
75
|
+
return this;
|
|
76
|
+
}
|
|
53
77
|
/**
|
|
54
78
|
* Move the circle by the given amount.
|
|
55
79
|
*
|
|
@@ -73,7 +97,8 @@ export class Circle {
|
|
|
73
97
|
* @return {boolean} `true` if the given point is inside this circle.
|
|
74
98
|
*/
|
|
75
99
|
containsPoint(point) {
|
|
76
|
-
return this.center.distance(point) < this.radius
|
|
100
|
+
// return this.center.distance(point) < this.radius;//
|
|
101
|
+
return Circle.circleUtils.containsPoint(this.center, this.radius, point);
|
|
77
102
|
}
|
|
78
103
|
/**
|
|
79
104
|
* Check if the given circle is fully contained inside this circle.
|
|
@@ -84,8 +109,13 @@ export class Circle {
|
|
|
84
109
|
* @memberof Circle
|
|
85
110
|
* @return {boolean} `true` if any only if the given circle is completely inside this circle.
|
|
86
111
|
*/
|
|
87
|
-
containsCircle(circle) {
|
|
88
|
-
|
|
112
|
+
containsCircle(circle, epsilon) {
|
|
113
|
+
if (typeof epsilon === "undefined" || Number.isNaN(epsilon)) {
|
|
114
|
+
return this.center.distance(circle.center) + circle.radius < this.radius;
|
|
115
|
+
}
|
|
116
|
+
else {
|
|
117
|
+
return this.center.distance(circle.center) + circle.radius < this.radius + Math.abs(epsilon);
|
|
118
|
+
}
|
|
89
119
|
}
|
|
90
120
|
/**
|
|
91
121
|
* Calculate the distance from this circle to the given line.
|
|
@@ -288,6 +318,40 @@ export class Circle {
|
|
|
288
318
|
});
|
|
289
319
|
}
|
|
290
320
|
//--- END --- Implement interface `Intersectable`
|
|
321
|
+
/**
|
|
322
|
+
* Calculate the radical axis of this and a different circle.
|
|
323
|
+
* The two circles must not be co-centric.
|
|
324
|
+
*
|
|
325
|
+
* See this article for details:
|
|
326
|
+
* https://www.cut-the-knot.org/Curriculum/Geometry/GeoGebra/RadicalAxes.shtml
|
|
327
|
+
*
|
|
328
|
+
* @method radicalAxis
|
|
329
|
+
* @instance
|
|
330
|
+
* @memberof Circle
|
|
331
|
+
* @param {Circle} circleB - The second circle to calculated the radical axis for.
|
|
332
|
+
* @return {Line} A line defining the radical axis of the two circles.
|
|
333
|
+
**/
|
|
334
|
+
radicalAxis(circleB) {
|
|
335
|
+
var helperCircle = Circle.circleUtils.createRadicalAxisHelperCircle(this, circleB);
|
|
336
|
+
var intersectionLineA = this.circleIntersection(helperCircle);
|
|
337
|
+
var intersectionLineB = circleB.circleIntersection(helperCircle);
|
|
338
|
+
var intersection = this.circleIntersection(circleB);
|
|
339
|
+
if (!intersectionLineA || !intersectionLineB) {
|
|
340
|
+
console.error("Critical error: none of the two intersections must be null.");
|
|
341
|
+
return intersection; // Fallback
|
|
342
|
+
}
|
|
343
|
+
var lineA = new Line(intersectionLineA.a, intersectionLineA.b);
|
|
344
|
+
var lineB = new Line(intersectionLineB.a, intersectionLineB.b);
|
|
345
|
+
var firstRadicalAxisPoint = lineA.intersection(lineB);
|
|
346
|
+
var centerConnectLine = new Line(this.center, circleB.center);
|
|
347
|
+
var secondRadicalAxisPoint = centerConnectLine.getClosestPoint(firstRadicalAxisPoint);
|
|
348
|
+
// Create a mirrored version of the second radical axis point so both are located
|
|
349
|
+
// symmetrical from the circle connect point.
|
|
350
|
+
// (currently the second point is located ON the connect line)
|
|
351
|
+
var secondRadicalAxisPoint_mirrored = secondRadicalAxisPoint.clone().scale(2.0, firstRadicalAxisPoint);
|
|
352
|
+
var radicalAxis = new Line(firstRadicalAxisPoint, secondRadicalAxisPoint_mirrored);
|
|
353
|
+
return intersection && intersection.length() > radicalAxis.length() ? intersection : radicalAxis;
|
|
354
|
+
}
|
|
291
355
|
/**
|
|
292
356
|
* Calculate the closest point on the outline of this circle to the given point.
|
|
293
357
|
*
|
|
@@ -311,6 +375,80 @@ export class Circle {
|
|
|
311
375
|
return lineIntersection.b;
|
|
312
376
|
}
|
|
313
377
|
}
|
|
378
|
+
/**
|
|
379
|
+
* Get the two tangent vectors for the given point.
|
|
380
|
+
* If the point is on or in the circle then null is returned.
|
|
381
|
+
*
|
|
382
|
+
* @method tangentsFromPoint
|
|
383
|
+
* @instance
|
|
384
|
+
* @memberof Circle
|
|
385
|
+
* @param {Vertex} vert - The point to find the two tangents for.
|
|
386
|
+
* @return {[Vector,Vector]} The two tangent vector
|
|
387
|
+
**/
|
|
388
|
+
tangentsFromPoint(vert) {
|
|
389
|
+
// Inspired by
|
|
390
|
+
// https://www.omnicalculator.com/math/tangent-circle
|
|
391
|
+
const centerDistance = this.center.distance(vert);
|
|
392
|
+
const tangentLength = Math.sqrt(centerDistance * centerDistance - this.radius * this.radius);
|
|
393
|
+
// console.log("this.radius ", this.radius, "centerDistance", centerDistance, "tangentLength", tangentLength);
|
|
394
|
+
if (Number.isNaN(tangentLength)) {
|
|
395
|
+
// vertex is inside circle
|
|
396
|
+
console.log("tangentLength is NaN", tangentLength);
|
|
397
|
+
return null;
|
|
398
|
+
}
|
|
399
|
+
const helperCircle = new Circle(vert, tangentLength);
|
|
400
|
+
const intersection = this.circleIntersection(helperCircle);
|
|
401
|
+
if (!intersection) {
|
|
402
|
+
// No intersection (vertex is inside circle)
|
|
403
|
+
return null;
|
|
404
|
+
}
|
|
405
|
+
return [new Vector(intersection.a, vert), new Vector(intersection.b, vert)];
|
|
406
|
+
}
|
|
407
|
+
/**
|
|
408
|
+
* Calculate inner sector angle for this circle and a given circle arc length.
|
|
409
|
+
*
|
|
410
|
+
* @param {number} sectorArcLength - The desired arc length (in units).
|
|
411
|
+
* @returns The sector's inner angle (in radians).
|
|
412
|
+
*/
|
|
413
|
+
sectorAngleByArcLength(sectorArcLength) {
|
|
414
|
+
return Circle.circleUtils.sectorAngleByArcLength(sectorArcLength, this.radius);
|
|
415
|
+
}
|
|
416
|
+
/**
|
|
417
|
+
* Create a deep copy of this circle.
|
|
418
|
+
*
|
|
419
|
+
* @method clone
|
|
420
|
+
* @return {Circle} A new circle, an exact copy of this one.
|
|
421
|
+
* @instance
|
|
422
|
+
* @memberof Circle
|
|
423
|
+
**/
|
|
424
|
+
clone() {
|
|
425
|
+
return new Circle(this.center.clone(), this.radius);
|
|
426
|
+
}
|
|
427
|
+
static fromICircle(obj) {
|
|
428
|
+
return new Circle(new Vertex(obj.center), obj.radius);
|
|
429
|
+
}
|
|
430
|
+
// static fromObject(obj: object): Circle {
|
|
431
|
+
// if (!obj) {
|
|
432
|
+
// return null;
|
|
433
|
+
// }
|
|
434
|
+
// if (typeof obj !== "object") {
|
|
435
|
+
// return null;
|
|
436
|
+
// }
|
|
437
|
+
// if (!obj.hasOwnProperty("center") || typeof (obj as any).center != "object") {
|
|
438
|
+
// return null;
|
|
439
|
+
// }
|
|
440
|
+
// if (!obj.hasOwnProperty("radius") || typeof !(obj as any).radius != "number") {
|
|
441
|
+
// return null;
|
|
442
|
+
// }
|
|
443
|
+
// var center = (obj as any).center;
|
|
444
|
+
// if (!center.hasOwnProperty("x") || typeof (center as any).x != "number") {
|
|
445
|
+
// return null;
|
|
446
|
+
// }
|
|
447
|
+
// if (!center.hasOwnProperty("y") || typeof (center as any).y != "number") {
|
|
448
|
+
// return null;
|
|
449
|
+
// }
|
|
450
|
+
// return new Circle(new Vertex(center), (obj as any).radius);
|
|
451
|
+
// }
|
|
314
452
|
/**
|
|
315
453
|
* This function should invalidate any installed listeners and invalidate this object.
|
|
316
454
|
* After calling this function the object might not hold valid data any more and
|
|
@@ -326,6 +464,43 @@ Circle.circleUtils = {
|
|
|
326
464
|
/* return new Vertex( Math.sin(angle) * radius,
|
|
327
465
|
Math.cos(angle) * radius ); */
|
|
328
466
|
return new Vertex(Math.cos(angle) * radius, Math.sin(angle) * radius);
|
|
467
|
+
},
|
|
468
|
+
containsPoint: (circleCenter, circleRadius, point) => {
|
|
469
|
+
// TODO: cleanup
|
|
470
|
+
// return (
|
|
471
|
+
// (circle.center.x - point.x) * (circle.center.x - point.x) + (circle.center.y - point.y) * (circle.center.y - point.y) <=
|
|
472
|
+
// circle.radius * circle.radius
|
|
473
|
+
// );
|
|
474
|
+
return geomutils.dist4(point.x, point.y, circleCenter.x, circleCenter.y) < circleRadius;
|
|
475
|
+
},
|
|
476
|
+
createRadicalAxisHelperCircle: (circleA, circleB) => {
|
|
477
|
+
// We need to create a helper circle that intersects BOTH other circles,
|
|
478
|
+
// each in TWO points.
|
|
479
|
+
var circleConnectLine = new Vector(circleA.center.clone(), circleB.center);
|
|
480
|
+
circleConnectLine.a.set(circleConnectLine.vertAt(0.5));
|
|
481
|
+
// Get the perpendicular by half the circle distance.
|
|
482
|
+
var bisector = circleConnectLine.perp();
|
|
483
|
+
var bisectorLength = Math.max(circleA.radius, circleB.radius, bisector.length());
|
|
484
|
+
bisector.setLength(bisectorLength);
|
|
485
|
+
return new Circle(bisector.b, bisector.b.distance(circleA.center));
|
|
486
|
+
},
|
|
487
|
+
/**
|
|
488
|
+
* Calculate the outer distance between two circles. If the circles touch then the
|
|
489
|
+
* distance is 0.0.
|
|
490
|
+
* If the circles intersect then the distance in negative.
|
|
491
|
+
*/
|
|
492
|
+
circleDistance: (circleA, circleB) => {
|
|
493
|
+
return circleA.center.distance(circleB.center) - circleA.radius - circleB.radius;
|
|
494
|
+
},
|
|
495
|
+
/**
|
|
496
|
+
* Calculate the inner sector angle for a given circle arc length and radius.
|
|
497
|
+
*
|
|
498
|
+
* @param {number} sectorArcLength - The desired arc length.
|
|
499
|
+
* @param {number} circleRadius - The circle's radius.
|
|
500
|
+
* @returns The sector angle in radians.
|
|
501
|
+
*/
|
|
502
|
+
sectorAngleByArcLength: (sectorArcLength, circleRadius) => {
|
|
503
|
+
return sectorArcLength / circleRadius;
|
|
329
504
|
}
|
|
330
505
|
};
|
|
331
506
|
//# sourceMappingURL=Circle.js.map
|