UNPKG

6 kBJavaScriptView Raw
1"use strict";
2Object.defineProperty(exports, "__esModule", { value: true });
3exports.segmentArcFactory = void 0;
4var segment_line_factory_1 = require("./segment-line-factory");
5var distance_square_root_1 = require("./distance-square-root");
6function angleBetween(v0, v1) {
7 var v0x = v0.x, v0y = v0.y;
8 var v1x = v1.x, v1y = v1.y;
9 var p = v0x * v1x + v0y * v1y;
10 var n = Math.sqrt((Math.pow(v0x, 2) + Math.pow(v0y, 2)) * (Math.pow(v1x, 2) + Math.pow(v1y, 2)));
11 var sign = v0x * v1y - v0y * v1x < 0 ? -1 : 1;
12 var angle = sign * Math.acos(p / n);
13 return angle;
14}
15/**
16 * Returns a {x,y} point at a given length, the total length and
17 * the minimum and maximum {x,y} coordinates of a C (cubic-bezier) segment.
18 * @see https://github.com/MadLittleMods/svg-curve-lib/blob/master/src/js/svg-curve-lib.js
19 */
20function getPointAtArcSegmentLength(x1, y1, RX, RY, angle, LAF, SF, x, y, t) {
21 var abs = Math.abs, sin = Math.sin, cos = Math.cos, sqrt = Math.sqrt, PI = Math.PI;
22 var rx = abs(RX);
23 var ry = abs(RY);
24 var xRot = ((angle % 360) + 360) % 360;
25 var xRotRad = xRot * (PI / 180);
26 if (x1 === x && y1 === y) {
27 return { x: x1, y: y1 };
28 }
29 if (rx === 0 || ry === 0) {
30 return (0, segment_line_factory_1.segmentLineFactory)(x1, y1, x, y, t).point;
31 }
32 var dx = (x1 - x) / 2;
33 var dy = (y1 - y) / 2;
34 var transformedPoint = {
35 x: cos(xRotRad) * dx + sin(xRotRad) * dy,
36 y: -sin(xRotRad) * dx + cos(xRotRad) * dy,
37 };
38 var radiiCheck = Math.pow(transformedPoint.x, 2) / Math.pow(rx, 2) + Math.pow(transformedPoint.y, 2) / Math.pow(ry, 2);
39 if (radiiCheck > 1) {
40 rx *= sqrt(radiiCheck);
41 ry *= sqrt(radiiCheck);
42 }
43 var cSquareNumerator = Math.pow(rx, 2) * Math.pow(ry, 2) - Math.pow(rx, 2) * Math.pow(transformedPoint.y, 2) - Math.pow(ry, 2) * Math.pow(transformedPoint.x, 2);
44 var cSquareRootDenom = Math.pow(rx, 2) * Math.pow(transformedPoint.y, 2) + Math.pow(ry, 2) * Math.pow(transformedPoint.x, 2);
45 var cRadicand = cSquareNumerator / cSquareRootDenom;
46 cRadicand = cRadicand < 0 ? 0 : cRadicand;
47 var cCoef = (LAF !== SF ? 1 : -1) * sqrt(cRadicand);
48 var transformedCenter = {
49 x: cCoef * ((rx * transformedPoint.y) / ry),
50 y: cCoef * (-(ry * transformedPoint.x) / rx),
51 };
52 var center = {
53 x: cos(xRotRad) * transformedCenter.x - sin(xRotRad) * transformedCenter.y + (x1 + x) / 2,
54 y: sin(xRotRad) * transformedCenter.x + cos(xRotRad) * transformedCenter.y + (y1 + y) / 2,
55 };
56 var startVector = {
57 x: (transformedPoint.x - transformedCenter.x) / rx,
58 y: (transformedPoint.y - transformedCenter.y) / ry,
59 };
60 var startAngle = angleBetween({ x: 1, y: 0 }, startVector);
61 var endVector = {
62 x: (-transformedPoint.x - transformedCenter.x) / rx,
63 y: (-transformedPoint.y - transformedCenter.y) / ry,
64 };
65 var sweepAngle = angleBetween(startVector, endVector);
66 if (!SF && sweepAngle > 0) {
67 sweepAngle -= 2 * PI;
68 }
69 else if (SF && sweepAngle < 0) {
70 sweepAngle += 2 * PI;
71 }
72 sweepAngle %= 2 * PI;
73 var alpha = startAngle + sweepAngle * t;
74 var ellipseComponentX = rx * cos(alpha);
75 var ellipseComponentY = ry * sin(alpha);
76 var point = {
77 x: cos(xRotRad) * ellipseComponentX - sin(xRotRad) * ellipseComponentY + center.x,
78 y: sin(xRotRad) * ellipseComponentX + cos(xRotRad) * ellipseComponentY + center.y,
79 };
80 // to be used later
81 // point.ellipticalArcStartAngle = startAngle;
82 // point.ellipticalArcEndAngle = startAngle + sweepAngle;
83 // point.ellipticalArcAngle = alpha;
84 // point.ellipticalArcCenter = center;
85 // point.resultantRx = rx;
86 // point.resultantRy = ry;
87 return point;
88}
89/**
90 * Returns a {x,y} point at a given length, the total length and
91 * the shape minimum and maximum {x,y} coordinates of an A (arc-to) segment.
92 *
93 * For better performance, it can skip calculate bbox or length in some scenario.
94 */
95function segmentArcFactory(X1, Y1, RX, RY, angle, LAF, SF, X2, Y2, distance, options) {
96 var _a;
97 var _b = options.bbox, bbox = _b === void 0 ? true : _b, _c = options.length, length = _c === void 0 ? true : _c, _d = options.sampleSize, sampleSize = _d === void 0 ? 30 : _d;
98 var distanceIsNumber = typeof distance === 'number';
99 var x = X1;
100 var y = Y1;
101 var LENGTH = 0;
102 var prev = [x, y, LENGTH];
103 var cur = [x, y];
104 var t = 0;
105 var POINT = { x: 0, y: 0 };
106 var POINTS = [{ x: x, y: y }];
107 if (distanceIsNumber && distance <= 0) {
108 POINT = { x: x, y: y };
109 }
110 // bad perf when size > 100
111 for (var j = 0; j <= sampleSize; j += 1) {
112 t = j / sampleSize;
113 (_a = getPointAtArcSegmentLength(X1, Y1, RX, RY, angle, LAF, SF, X2, Y2, t), x = _a.x, y = _a.y);
114 if (bbox) {
115 POINTS.push({ x: x, y: y });
116 }
117 if (length) {
118 LENGTH += (0, distance_square_root_1.distanceSquareRoot)(cur, [x, y]);
119 }
120 cur = [x, y];
121 if (distanceIsNumber && LENGTH >= distance && distance > prev[2]) {
122 var dv = (LENGTH - distance) / (LENGTH - prev[2]);
123 POINT = {
124 x: cur[0] * (1 - dv) + prev[0] * dv,
125 y: cur[1] * (1 - dv) + prev[1] * dv,
126 };
127 }
128 prev = [x, y, LENGTH];
129 }
130 if (distanceIsNumber && distance >= LENGTH) {
131 POINT = { x: X2, y: Y2 };
132 }
133 return {
134 length: LENGTH,
135 point: POINT,
136 min: {
137 x: Math.min.apply(null, POINTS.map(function (n) { return n.x; })),
138 y: Math.min.apply(null, POINTS.map(function (n) { return n.y; })),
139 },
140 max: {
141 x: Math.max.apply(null, POINTS.map(function (n) { return n.x; })),
142 y: Math.max.apply(null, POINTS.map(function (n) { return n.y; })),
143 },
144 };
145}
146exports.segmentArcFactory = segmentArcFactory;
147//# sourceMappingURL=segment-arc-factory.js.map
\No newline at end of file