@flighthq/path 0.1.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/dist/containsPathPoint.d.ts +13 -0
- package/dist/containsPathPoint.d.ts.map +1 -0
- package/dist/containsPathPoint.js +194 -0
- package/dist/containsPathPoint.js.map +1 -0
- package/dist/copyPath.d.ts +4 -0
- package/dist/copyPath.d.ts.map +1 -0
- package/dist/copyPath.js +28 -0
- package/dist/copyPath.js.map +1 -0
- package/dist/dashPath.d.ts +3 -0
- package/dist/dashPath.d.ts.map +1 -0
- package/dist/dashPath.js +105 -0
- package/dist/dashPath.js.map +1 -0
- package/dist/fitPathCurves.d.ts +3 -0
- package/dist/fitPathCurves.d.ts.map +1 -0
- package/dist/fitPathCurves.js +222 -0
- package/dist/fitPathCurves.js.map +1 -0
- package/dist/flattenPath.d.ts +3 -0
- package/dist/flattenPath.d.ts.map +1 -0
- package/dist/flattenPath.js +145 -0
- package/dist/flattenPath.js.map +1 -0
- package/dist/forEachPathSegment.d.ts +3 -0
- package/dist/forEachPathSegment.d.ts.map +1 -0
- package/dist/forEachPathSegment.js +66 -0
- package/dist/forEachPathSegment.js.map +1 -0
- package/dist/getPathBounds.d.ts +3 -0
- package/dist/getPathBounds.d.ts.map +1 -0
- package/dist/getPathBounds.js +167 -0
- package/dist/getPathBounds.js.map +1 -0
- package/dist/getPathContourLengths.d.ts +3 -0
- package/dist/getPathContourLengths.d.ts.map +1 -0
- package/dist/getPathContourLengths.js +21 -0
- package/dist/getPathContourLengths.js.map +1 -0
- package/dist/getPathLength.d.ts +3 -0
- package/dist/getPathLength.d.ts.map +1 -0
- package/dist/getPathLength.js +23 -0
- package/dist/getPathLength.js.map +1 -0
- package/dist/getPathNearestPoint.d.ts +3 -0
- package/dist/getPathNearestPoint.d.ts.map +1 -0
- package/dist/getPathNearestPoint.js +47 -0
- package/dist/getPathNearestPoint.js.map +1 -0
- package/dist/getPathPointAtDistance.d.ts +5 -0
- package/dist/getPathPointAtDistance.d.ts.map +1 -0
- package/dist/getPathPointAtDistance.js +100 -0
- package/dist/getPathPointAtDistance.js.map +1 -0
- package/dist/getPathSegmentAtParameter.d.ts +8 -0
- package/dist/getPathSegmentAtParameter.d.ts.map +1 -0
- package/dist/getPathSegmentAtParameter.js +163 -0
- package/dist/getPathSegmentAtParameter.js.map +1 -0
- package/dist/getPathSignedArea.d.ts +4 -0
- package/dist/getPathSignedArea.d.ts.map +1 -0
- package/dist/getPathSignedArea.js +43 -0
- package/dist/getPathSignedArea.js.map +1 -0
- package/dist/index.d.ts +23 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +23 -0
- package/dist/index.js.map +1 -0
- package/dist/offsetPath.d.ts +3 -0
- package/dist/offsetPath.d.ts.map +1 -0
- package/dist/offsetPath.js +146 -0
- package/dist/offsetPath.js.map +1 -0
- package/dist/path.d.ts +17 -0
- package/dist/path.d.ts.map +1 -0
- package/dist/path.js +293 -0
- package/dist/path.js.map +1 -0
- package/dist/pathMeshPool.d.ts +6 -0
- package/dist/pathMeshPool.d.ts.map +1 -0
- package/dist/pathMeshPool.js +58 -0
- package/dist/pathMeshPool.js.map +1 -0
- package/dist/reversePath.d.ts +3 -0
- package/dist/reversePath.d.ts.map +1 -0
- package/dist/reversePath.js +95 -0
- package/dist/reversePath.js.map +1 -0
- package/dist/simplifyPath.d.ts +3 -0
- package/dist/simplifyPath.d.ts.map +1 -0
- package/dist/simplifyPath.js +78 -0
- package/dist/simplifyPath.js.map +1 -0
- package/dist/strokePath.d.ts +4 -0
- package/dist/strokePath.d.ts.map +1 -0
- package/dist/strokePath.js +458 -0
- package/dist/strokePath.js.map +1 -0
- package/dist/tessellatePath.d.ts +3 -0
- package/dist/tessellatePath.d.ts.map +1 -0
- package/dist/tessellatePath.js +107 -0
- package/dist/tessellatePath.js.map +1 -0
- package/dist/tessellatePathTyped.d.ts +3 -0
- package/dist/tessellatePathTyped.d.ts.map +1 -0
- package/dist/tessellatePathTyped.js +12 -0
- package/dist/tessellatePathTyped.js.map +1 -0
- package/dist/transformPath.d.ts +4 -0
- package/dist/transformPath.d.ts.map +1 -0
- package/dist/transformPath.js +62 -0
- package/dist/transformPath.js.map +1 -0
- package/package.json +37 -0
- package/src/containsPathPoint.test.ts +125 -0
- package/src/copyPath.test.ts +56 -0
- package/src/dashPath.test.ts +76 -0
- package/src/fitPathCurves.test.ts +65 -0
- package/src/flattenPath.test.ts +87 -0
- package/src/forEachPathSegment.test.ts +82 -0
- package/src/getPathBounds.test.ts +84 -0
- package/src/getPathContourLengths.test.ts +51 -0
- package/src/getPathLength.test.ts +33 -0
- package/src/getPathNearestPoint.test.ts +64 -0
- package/src/getPathPointAtDistance.test.ts +94 -0
- package/src/getPathSegmentAtParameter.test.ts +178 -0
- package/src/getPathSignedArea.test.ts +45 -0
- package/src/offsetPath.test.ts +78 -0
- package/src/path.test.ts +376 -0
- package/src/pathMeshPool.test.ts +78 -0
- package/src/reversePath.test.ts +51 -0
- package/src/simplifyPath.test.ts +69 -0
- package/src/strokePath.test.ts +150 -0
- package/src/tessellatePath.test.ts +62 -0
- package/src/tessellatePathTyped.test.ts +26 -0
- package/src/transformPath.test.ts +79 -0
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { Path } from '@flighthq/types';
|
|
2
|
+
/**
|
|
3
|
+
* Tests whether point (px, py) lies inside the path using the path's winding rule
|
|
4
|
+
* ('evenOdd' or 'nonZero'). Curves are adaptively flattened before the winding
|
|
5
|
+
* number test; the tolerance is in path units.
|
|
6
|
+
*
|
|
7
|
+
* The algorithm casts a ray rightward from (px, py) and counts crossings per
|
|
8
|
+
* contour. For 'nonZero' it accumulates signed winding; for 'evenOdd' it tests
|
|
9
|
+
* parity. Uses the standard convention: points on the boundary are not guaranteed
|
|
10
|
+
* to return true.
|
|
11
|
+
*/
|
|
12
|
+
export declare function containsPathPoint(path: Readonly<Path>, px: number, py: number, tolerance?: number): boolean;
|
|
13
|
+
//# sourceMappingURL=containsPathPoint.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"containsPathPoint.d.ts","sourceRoot":"","sources":["../src/containsPathPoint.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,iBAAiB,CAAC;AAG5C;;;;;;;;;GASG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,QAAQ,CAAC,IAAI,CAAC,EAAE,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,SAAS,SAAO,GAAG,OAAO,CAIzG"}
|
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
import { PathCommand } from '@flighthq/types';
|
|
2
|
+
/**
|
|
3
|
+
* Tests whether point (px, py) lies inside the path using the path's winding rule
|
|
4
|
+
* ('evenOdd' or 'nonZero'). Curves are adaptively flattened before the winding
|
|
5
|
+
* number test; the tolerance is in path units.
|
|
6
|
+
*
|
|
7
|
+
* The algorithm casts a ray rightward from (px, py) and counts crossings per
|
|
8
|
+
* contour. For 'nonZero' it accumulates signed winding; for 'evenOdd' it tests
|
|
9
|
+
* parity. Uses the standard convention: points on the boundary are not guaranteed
|
|
10
|
+
* to return true.
|
|
11
|
+
*/
|
|
12
|
+
export function containsPathPoint(path, px, py, tolerance = 0.25) {
|
|
13
|
+
const winding = computePathWindingNumber(path, px, py, tolerance);
|
|
14
|
+
if (path.winding === 'evenOdd')
|
|
15
|
+
return (winding & 1) !== 0;
|
|
16
|
+
return winding !== 0;
|
|
17
|
+
}
|
|
18
|
+
// Squared perpendicular distance from (px,py) to chord (x0,y0)-(x1,y1).
|
|
19
|
+
function chordDistSq(px, py, x0, y0, x1, y1) {
|
|
20
|
+
const dx = x1 - x0;
|
|
21
|
+
const dy = y1 - y0;
|
|
22
|
+
const lenSq = dx * dx + dy * dy;
|
|
23
|
+
if (lenSq === 0) {
|
|
24
|
+
const ax = px - x0;
|
|
25
|
+
const ay = py - y0;
|
|
26
|
+
return ax * ax + ay * ay;
|
|
27
|
+
}
|
|
28
|
+
const cross = dx * (y0 - py) - dy * (x0 - px);
|
|
29
|
+
return (cross * cross) / lenSq;
|
|
30
|
+
}
|
|
31
|
+
// Computes the winding number of (px, py) relative to the path by flattening each
|
|
32
|
+
// contour to line segments and accumulating signed crossings.
|
|
33
|
+
function computePathWindingNumber(path, px, py, tolerance) {
|
|
34
|
+
const commands = path.commands;
|
|
35
|
+
const data = path.data;
|
|
36
|
+
const toleranceSq = tolerance * tolerance;
|
|
37
|
+
let windingNumber = 0;
|
|
38
|
+
let x = 0;
|
|
39
|
+
let y = 0;
|
|
40
|
+
let contourStartX = 0;
|
|
41
|
+
let contourStartY = 0;
|
|
42
|
+
let hasContour = false;
|
|
43
|
+
let lastX = 0;
|
|
44
|
+
let lastY = 0;
|
|
45
|
+
let di = 0;
|
|
46
|
+
const flushContour = () => {
|
|
47
|
+
if (hasContour) {
|
|
48
|
+
windingNumber += countSegmentCrossings(px, py, lastX, lastY, contourStartX, contourStartY);
|
|
49
|
+
}
|
|
50
|
+
};
|
|
51
|
+
for (let ci = 0; ci < commands.length; ci++) {
|
|
52
|
+
const command = commands[ci];
|
|
53
|
+
if (command === PathCommand.MOVE_TO) {
|
|
54
|
+
flushContour();
|
|
55
|
+
x = data[di];
|
|
56
|
+
y = data[di + 1];
|
|
57
|
+
di += 2;
|
|
58
|
+
contourStartX = x;
|
|
59
|
+
contourStartY = y;
|
|
60
|
+
lastX = x;
|
|
61
|
+
lastY = y;
|
|
62
|
+
hasContour = true;
|
|
63
|
+
}
|
|
64
|
+
else if (command === PathCommand.WIDE_MOVE_TO) {
|
|
65
|
+
flushContour();
|
|
66
|
+
x = data[di + 2];
|
|
67
|
+
y = data[di + 3];
|
|
68
|
+
di += 4;
|
|
69
|
+
contourStartX = x;
|
|
70
|
+
contourStartY = y;
|
|
71
|
+
lastX = x;
|
|
72
|
+
lastY = y;
|
|
73
|
+
hasContour = true;
|
|
74
|
+
}
|
|
75
|
+
else if (command === PathCommand.LINE_TO) {
|
|
76
|
+
const nx = data[di];
|
|
77
|
+
const ny = data[di + 1];
|
|
78
|
+
di += 2;
|
|
79
|
+
if (hasContour) {
|
|
80
|
+
windingNumber += countSegmentCrossings(px, py, lastX, lastY, nx, ny);
|
|
81
|
+
}
|
|
82
|
+
lastX = nx;
|
|
83
|
+
lastY = ny;
|
|
84
|
+
x = nx;
|
|
85
|
+
y = ny;
|
|
86
|
+
}
|
|
87
|
+
else if (command === PathCommand.WIDE_LINE_TO) {
|
|
88
|
+
const nx = data[di + 2];
|
|
89
|
+
const ny = data[di + 3];
|
|
90
|
+
di += 4;
|
|
91
|
+
if (hasContour) {
|
|
92
|
+
windingNumber += countSegmentCrossings(px, py, lastX, lastY, nx, ny);
|
|
93
|
+
}
|
|
94
|
+
lastX = nx;
|
|
95
|
+
lastY = ny;
|
|
96
|
+
x = nx;
|
|
97
|
+
y = ny;
|
|
98
|
+
}
|
|
99
|
+
else if (command === PathCommand.CURVE_TO) {
|
|
100
|
+
const cx = data[di];
|
|
101
|
+
const cy = data[di + 1];
|
|
102
|
+
const ax = data[di + 2];
|
|
103
|
+
const ay = data[di + 3];
|
|
104
|
+
di += 4;
|
|
105
|
+
if (hasContour) {
|
|
106
|
+
windingNumber += flattenQuadraticWindingNumber(px, py, lastX, lastY, cx, cy, ax, ay, toleranceSq, 0);
|
|
107
|
+
}
|
|
108
|
+
lastX = ax;
|
|
109
|
+
lastY = ay;
|
|
110
|
+
x = ax;
|
|
111
|
+
y = ay;
|
|
112
|
+
}
|
|
113
|
+
else if (command === PathCommand.CUBIC_CURVE_TO) {
|
|
114
|
+
const c1x = data[di];
|
|
115
|
+
const c1y = data[di + 1];
|
|
116
|
+
const c2x = data[di + 2];
|
|
117
|
+
const c2y = data[di + 3];
|
|
118
|
+
const ax = data[di + 4];
|
|
119
|
+
const ay = data[di + 5];
|
|
120
|
+
di += 6;
|
|
121
|
+
if (hasContour) {
|
|
122
|
+
windingNumber += flattenCubicWindingNumber(px, py, lastX, lastY, c1x, c1y, c2x, c2y, ax, ay, toleranceSq, 0);
|
|
123
|
+
}
|
|
124
|
+
lastX = ax;
|
|
125
|
+
lastY = ay;
|
|
126
|
+
x = ax;
|
|
127
|
+
y = ay;
|
|
128
|
+
}
|
|
129
|
+
else if (command === PathCommand.CLOSE) {
|
|
130
|
+
// Explicit close: emit a segment back to the contour start and reset.
|
|
131
|
+
if (hasContour) {
|
|
132
|
+
windingNumber += countSegmentCrossings(px, py, lastX, lastY, contourStartX, contourStartY);
|
|
133
|
+
lastX = contourStartX;
|
|
134
|
+
lastY = contourStartY;
|
|
135
|
+
x = contourStartX;
|
|
136
|
+
y = contourStartY;
|
|
137
|
+
hasContour = false;
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
// NO_OP and unrecognized verbs consume no data.
|
|
141
|
+
}
|
|
142
|
+
// Close the final open contour.
|
|
143
|
+
flushContour();
|
|
144
|
+
return Math.abs(windingNumber);
|
|
145
|
+
}
|
|
146
|
+
// Returns the signed crossing count contribution of segment (x0,y0)→(x1,y1) for
|
|
147
|
+
// the rightward ray from (px, py). +1 for upward crossings, -1 for downward.
|
|
148
|
+
function countSegmentCrossings(px, py, x0, y0, x1, y1) {
|
|
149
|
+
// Only segments that cross the horizontal ray (py) contribute.
|
|
150
|
+
if ((y0 <= py && y1 > py) || (y1 <= py && y0 > py)) {
|
|
151
|
+
// x coordinate of the crossing — only count if the segment crosses to the right.
|
|
152
|
+
const crossX = x0 + ((py - y0) * (x1 - x0)) / (y1 - y0);
|
|
153
|
+
if (px < crossX) {
|
|
154
|
+
return y1 > y0 ? 1 : -1;
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
return 0;
|
|
158
|
+
}
|
|
159
|
+
function flattenCubicWindingNumber(px, py, x0, y0, c1x, c1y, c2x, c2y, x1, y1, toleranceSq, depth) {
|
|
160
|
+
const d1 = chordDistSq(c1x, c1y, x0, y0, x1, y1);
|
|
161
|
+
const d2 = chordDistSq(c2x, c2y, x0, y0, x1, y1);
|
|
162
|
+
if (depth >= MAX_SUBDIVISION_DEPTH || (d1 <= toleranceSq && d2 <= toleranceSq)) {
|
|
163
|
+
return countSegmentCrossings(px, py, x0, y0, x1, y1);
|
|
164
|
+
}
|
|
165
|
+
const x01 = (x0 + c1x) / 2;
|
|
166
|
+
const y01 = (y0 + c1y) / 2;
|
|
167
|
+
const x12 = (c1x + c2x) / 2;
|
|
168
|
+
const y12 = (c1y + c2y) / 2;
|
|
169
|
+
const x23 = (c2x + x1) / 2;
|
|
170
|
+
const y23 = (c2y + y1) / 2;
|
|
171
|
+
const x012 = (x01 + x12) / 2;
|
|
172
|
+
const y012 = (y01 + y12) / 2;
|
|
173
|
+
const x123 = (x12 + x23) / 2;
|
|
174
|
+
const y123 = (y12 + y23) / 2;
|
|
175
|
+
const xm = (x012 + x123) / 2;
|
|
176
|
+
const ym = (y012 + y123) / 2;
|
|
177
|
+
return (flattenCubicWindingNumber(px, py, x0, y0, x01, y01, x012, y012, xm, ym, toleranceSq, depth + 1) +
|
|
178
|
+
flattenCubicWindingNumber(px, py, xm, ym, x123, y123, x23, y23, x1, y1, toleranceSq, depth + 1));
|
|
179
|
+
}
|
|
180
|
+
function flattenQuadraticWindingNumber(px, py, x0, y0, cx, cy, x1, y1, toleranceSq, depth) {
|
|
181
|
+
if (depth >= MAX_SUBDIVISION_DEPTH || chordDistSq(cx, cy, x0, y0, x1, y1) <= toleranceSq) {
|
|
182
|
+
return countSegmentCrossings(px, py, x0, y0, x1, y1);
|
|
183
|
+
}
|
|
184
|
+
const mx01 = (x0 + cx) / 2;
|
|
185
|
+
const my01 = (y0 + cy) / 2;
|
|
186
|
+
const mx12 = (cx + x1) / 2;
|
|
187
|
+
const my12 = (cy + y1) / 2;
|
|
188
|
+
const mx = (mx01 + mx12) / 2;
|
|
189
|
+
const my = (my01 + my12) / 2;
|
|
190
|
+
return (flattenQuadraticWindingNumber(px, py, x0, y0, mx01, my01, mx, my, toleranceSq, depth + 1) +
|
|
191
|
+
flattenQuadraticWindingNumber(px, py, mx, my, mx12, my12, x1, y1, toleranceSq, depth + 1));
|
|
192
|
+
}
|
|
193
|
+
const MAX_SUBDIVISION_DEPTH = 16;
|
|
194
|
+
//# sourceMappingURL=containsPathPoint.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"containsPathPoint.js","sourceRoot":"","sources":["../src/containsPathPoint.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"copyPath.d.ts","sourceRoot":"","sources":["../src/copyPath.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,iBAAiB,CAAC;AAI5C,wBAAgB,SAAS,CAAC,MAAM,EAAE,QAAQ,CAAC,IAAI,CAAC,GAAG,IAAI,CAEtD;AAKD,wBAAgB,QAAQ,CAAC,MAAM,EAAE,QAAQ,CAAC,IAAI,CAAC,EAAE,GAAG,CAAC,EAAE,IAAI,GAAG,IAAI,CAgBjE"}
|
package/dist/copyPath.js
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
// Allocates a new `Path` that is a deep copy of `source`.
|
|
2
|
+
// Use `copyPath(source, out)` to write into an existing path without allocating.
|
|
3
|
+
export function clonePath(source) {
|
|
4
|
+
return copyPath(source);
|
|
5
|
+
}
|
|
6
|
+
// Copies all commands, data, and the winding rule from `source` into `out`. If `out` is omitted,
|
|
7
|
+
// allocates and returns a new `Path`. Alias-safe: if `out` is the same object as `source`, the call
|
|
8
|
+
// is a no-op (the path is already in place). Use `clonePath` when you always want a new allocation.
|
|
9
|
+
export function copyPath(source, out) {
|
|
10
|
+
if (out === undefined) {
|
|
11
|
+
return {
|
|
12
|
+
commands: source.commands.slice(),
|
|
13
|
+
data: source.data.slice(),
|
|
14
|
+
winding: source.winding,
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
if (out !== source) {
|
|
18
|
+
out.commands.length = 0;
|
|
19
|
+
for (let i = 0; i < source.commands.length; i++)
|
|
20
|
+
out.commands.push(source.commands[i]);
|
|
21
|
+
out.data.length = 0;
|
|
22
|
+
for (let i = 0; i < source.data.length; i++)
|
|
23
|
+
out.data.push(source.data[i]);
|
|
24
|
+
out.winding = source.winding;
|
|
25
|
+
}
|
|
26
|
+
return out;
|
|
27
|
+
}
|
|
28
|
+
//# sourceMappingURL=copyPath.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"copyPath.js","sourceRoot":"","sources":["../src/copyPath.ts"],"names":[],"mappings":"AAEA,0DAA0D;AAC1D,iFAAiF;AACjF,MAAM,UAAU,SAAS,CAAC,MAAsB;IAC9C,OAAO,QAAQ,CAAC,MAAM,CAAC,CAAC;AAC1B,CAAC;AAED,iGAAiG;AACjG,oGAAoG;AACpG,oGAAoG;AACpG,MAAM,UAAU,QAAQ,CAAC,MAAsB,EAAE,GAAU;IACzD,IAAI,GAAG,KAAK,SAAS,EAAE,CAAC;QACtB,OAAO;YACL,QAAQ,EAAE,MAAM,CAAC,QAAQ,CAAC,KAAK,EAAE;YACjC,IAAI,EAAE,MAAM,CAAC,IAAI,CAAC,KAAK,EAAE;YACzB,OAAO,EAAE,MAAM,CAAC,OAAO;SACxB,CAAC;IACJ,CAAC;IACD,IAAI,GAAG,KAAK,MAAM,EAAE,CAAC;QACnB,GAAG,CAAC,QAAQ,CAAC,MAAM,GAAG,CAAC,CAAC;QACxB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,MAAM,CAAC,QAAQ,CAAC,MAAM,EAAE,CAAC,EAAE;YAAE,GAAG,CAAC,QAAQ,CAAC,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC;QACvF,GAAG,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC;QACpB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,MAAM,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC,EAAE;YAAE,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC;QAC3E,GAAG,CAAC,OAAO,GAAG,MAAM,CAAC,OAAO,CAAC;IAC/B,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dashPath.d.ts","sourceRoot":"","sources":["../src/dashPath.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,iBAAiB,CAAC;AAU5C,wBAAgB,QAAQ,CACtB,MAAM,EAAE,QAAQ,CAAC,IAAI,CAAC,EACtB,IAAI,EAAE,QAAQ,CAAC,MAAM,EAAE,CAAC,EACxB,UAAU,EAAE,MAAM,EAClB,GAAG,EAAE,IAAI,EACT,SAAS,SAAO,GACf,IAAI,CAeN"}
|
package/dist/dashPath.js
ADDED
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
import { PathCommand } from '@flighthq/types';
|
|
2
|
+
import { flattenPath } from './flattenPath';
|
|
3
|
+
// Splits `source` into dashed sub-paths according to the given dash pattern and offset. Each
|
|
4
|
+
// dash-on segment becomes an open sub-path (MOVE_TO + LINE_TOs) in `out`. The dash pattern is
|
|
5
|
+
// a repeating [on, off, on, off, ...] length sequence; `dashOffset` shifts the pattern start.
|
|
6
|
+
//
|
|
7
|
+
// An empty or all-zero dash array copies the source unchanged (solid stroke). Alias-safe.
|
|
8
|
+
export function dashPath(source, dash, dashOffset, out, tolerance = 0.25) {
|
|
9
|
+
out.commands.length = 0;
|
|
10
|
+
out.data.length = 0;
|
|
11
|
+
out.winding = source.winding;
|
|
12
|
+
const totalDashLength = dashTotal(dash);
|
|
13
|
+
if (totalDashLength <= 0) {
|
|
14
|
+
copyCommands(source, out);
|
|
15
|
+
return;
|
|
16
|
+
}
|
|
17
|
+
const contours = flattenPath(source, tolerance);
|
|
18
|
+
for (const contour of contours) {
|
|
19
|
+
applyDashToContour(contour, dash, dashOffset, totalDashLength, out);
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
function applyDashToContour(pts, dash, dashOffset, totalDashLength, out) {
|
|
23
|
+
const n = pts.length >> 1;
|
|
24
|
+
if (n < 2)
|
|
25
|
+
return;
|
|
26
|
+
const offset = ((dashOffset % totalDashLength) + totalDashLength) % totalDashLength;
|
|
27
|
+
let dashIndex = 0;
|
|
28
|
+
let remaining = 0;
|
|
29
|
+
let isOn = true;
|
|
30
|
+
{
|
|
31
|
+
let acc = 0;
|
|
32
|
+
for (let i = 0; i < dash.length; i++) {
|
|
33
|
+
if (acc + dash[i] > offset) {
|
|
34
|
+
dashIndex = i;
|
|
35
|
+
remaining = dash[i] - (offset - acc);
|
|
36
|
+
isOn = i % 2 === 0;
|
|
37
|
+
break;
|
|
38
|
+
}
|
|
39
|
+
acc += dash[i];
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
let segStarted = false;
|
|
43
|
+
for (let i = 0; i < n - 1; i++) {
|
|
44
|
+
const x0 = pts[i * 2];
|
|
45
|
+
const y0 = pts[i * 2 + 1];
|
|
46
|
+
const x1 = pts[(i + 1) * 2];
|
|
47
|
+
const y1 = pts[(i + 1) * 2 + 1];
|
|
48
|
+
const dx = x1 - x0;
|
|
49
|
+
const dy = y1 - y0;
|
|
50
|
+
const segLen = Math.sqrt(dx * dx + dy * dy);
|
|
51
|
+
if (isOn && !segStarted) {
|
|
52
|
+
out.commands.push(PathCommand.MOVE_TO);
|
|
53
|
+
out.data.push(x0, y0);
|
|
54
|
+
segStarted = true;
|
|
55
|
+
}
|
|
56
|
+
let consumed = 0;
|
|
57
|
+
while (consumed < segLen) {
|
|
58
|
+
const step = Math.min(remaining, segLen - consumed);
|
|
59
|
+
const t = segLen > 0 ? (consumed + step) / segLen : 0;
|
|
60
|
+
const ix = x0 + t * dx;
|
|
61
|
+
const iy = y0 + t * dy;
|
|
62
|
+
if (isOn) {
|
|
63
|
+
if (!segStarted) {
|
|
64
|
+
const tStart = segLen > 0 ? consumed / segLen : 0;
|
|
65
|
+
out.commands.push(PathCommand.MOVE_TO);
|
|
66
|
+
out.data.push(x0 + tStart * dx, y0 + tStart * dy);
|
|
67
|
+
segStarted = true;
|
|
68
|
+
}
|
|
69
|
+
out.commands.push(PathCommand.LINE_TO);
|
|
70
|
+
out.data.push(ix, iy);
|
|
71
|
+
}
|
|
72
|
+
consumed += step;
|
|
73
|
+
remaining -= step;
|
|
74
|
+
if (remaining <= 1e-10) {
|
|
75
|
+
dashIndex = (dashIndex + 1) % dash.length;
|
|
76
|
+
remaining = dash[dashIndex];
|
|
77
|
+
const wasOn = isOn;
|
|
78
|
+
isOn = dashIndex % 2 === 0;
|
|
79
|
+
if (wasOn && !isOn) {
|
|
80
|
+
segStarted = false;
|
|
81
|
+
}
|
|
82
|
+
if (!wasOn && isOn) {
|
|
83
|
+
out.commands.push(PathCommand.MOVE_TO);
|
|
84
|
+
out.data.push(ix, iy);
|
|
85
|
+
segStarted = true;
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
function copyCommands(source, out) {
|
|
92
|
+
for (let i = 0; i < source.commands.length; i++) {
|
|
93
|
+
out.commands.push(source.commands[i]);
|
|
94
|
+
}
|
|
95
|
+
for (let i = 0; i < source.data.length; i++) {
|
|
96
|
+
out.data.push(source.data[i]);
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
function dashTotal(dash) {
|
|
100
|
+
let total = 0;
|
|
101
|
+
for (let i = 0; i < dash.length; i++)
|
|
102
|
+
total += dash[i];
|
|
103
|
+
return total;
|
|
104
|
+
}
|
|
105
|
+
//# sourceMappingURL=dashPath.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dashPath.js","sourceRoot":"","sources":["../src/dashPath.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fitPathCurves.d.ts","sourceRoot":"","sources":["../src/fitPathCurves.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,iBAAiB,CAAC;AAU5C,wBAAgB,aAAa,CAAC,MAAM,EAAE,QAAQ,CAAC,IAAI,CAAC,EAAE,SAAS,EAAE,MAAM,EAAE,GAAG,EAAE,IAAI,EAAE,gBAAgB,SAAO,GAAG,IAAI,CA4CjH"}
|
|
@@ -0,0 +1,222 @@
|
|
|
1
|
+
import { PathCommand } from '@flighthq/types';
|
|
2
|
+
import { flattenPath } from './flattenPath';
|
|
3
|
+
// Re-curves a polyline (or any flattened path) into smooth cubic bezier segments using
|
|
4
|
+
// Schneider's algorithm. The input path is first flattened, then partitioned at corners
|
|
5
|
+
// (points where the tangent direction changes by more than ~60°), and each span is fit with
|
|
6
|
+
// cubic beziers via least-squares. If the fit error exceeds `tolerance`, the span is split at
|
|
7
|
+
// the point of maximum error and each half is fit recursively. Alias-safe.
|
|
8
|
+
export function fitPathCurves(source, tolerance, out, flattenTolerance = 0.25) {
|
|
9
|
+
const contours = flattenPath(source, flattenTolerance);
|
|
10
|
+
out.commands.length = 0;
|
|
11
|
+
out.data.length = 0;
|
|
12
|
+
out.winding = source.winding;
|
|
13
|
+
const toleranceSq = tolerance * tolerance;
|
|
14
|
+
for (const contour of contours) {
|
|
15
|
+
const n = contour.length >> 1;
|
|
16
|
+
if (n < 2)
|
|
17
|
+
continue;
|
|
18
|
+
const closed = n >= 3 && contour[0] === contour[contour.length - 2] && contour[1] === contour[contour.length - 1];
|
|
19
|
+
const pts = closed ? contour.slice(0, (n - 1) * 2) : contour;
|
|
20
|
+
const pn = pts.length >> 1;
|
|
21
|
+
if (pn < 2)
|
|
22
|
+
continue;
|
|
23
|
+
if (pn === 2) {
|
|
24
|
+
out.commands.push(PathCommand.MOVE_TO);
|
|
25
|
+
out.data.push(pts[0], pts[1]);
|
|
26
|
+
out.commands.push(PathCommand.LINE_TO);
|
|
27
|
+
out.data.push(pts[2], pts[3]);
|
|
28
|
+
if (closed)
|
|
29
|
+
out.commands.push(PathCommand.CLOSE);
|
|
30
|
+
continue;
|
|
31
|
+
}
|
|
32
|
+
const corners = findCorners(pts, pn);
|
|
33
|
+
out.commands.push(PathCommand.MOVE_TO);
|
|
34
|
+
out.data.push(pts[0], pts[1]);
|
|
35
|
+
for (let ci = 0; ci < corners.length - 1; ci++) {
|
|
36
|
+
const first = corners[ci];
|
|
37
|
+
const last = corners[ci + 1];
|
|
38
|
+
if (last - first < 2) {
|
|
39
|
+
out.commands.push(PathCommand.LINE_TO);
|
|
40
|
+
out.data.push(pts[last * 2], pts[last * 2 + 1]);
|
|
41
|
+
continue;
|
|
42
|
+
}
|
|
43
|
+
const tHat1 = computeLeftTangent(pts, first);
|
|
44
|
+
const tHat2 = computeRightTangent(pts, last);
|
|
45
|
+
fitCubic(pts, first, last, tHat1, tHat2, toleranceSq, out);
|
|
46
|
+
}
|
|
47
|
+
if (closed)
|
|
48
|
+
out.commands.push(PathCommand.CLOSE);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
function findCorners(pts, n) {
|
|
52
|
+
const corners = [0];
|
|
53
|
+
for (let i = 1; i < n - 1; i++) {
|
|
54
|
+
const dx0 = pts[i * 2] - pts[(i - 1) * 2];
|
|
55
|
+
const dy0 = pts[i * 2 + 1] - pts[(i - 1) * 2 + 1];
|
|
56
|
+
const dx1 = pts[(i + 1) * 2] - pts[i * 2];
|
|
57
|
+
const dy1 = pts[(i + 1) * 2 + 1] - pts[i * 2 + 1];
|
|
58
|
+
const len0 = Math.sqrt(dx0 * dx0 + dy0 * dy0);
|
|
59
|
+
const len1 = Math.sqrt(dx1 * dx1 + dy1 * dy1);
|
|
60
|
+
if (len0 === 0 || len1 === 0)
|
|
61
|
+
continue;
|
|
62
|
+
const dot = (dx0 * dx1 + dy0 * dy1) / (len0 * len1);
|
|
63
|
+
if (dot < 0.5)
|
|
64
|
+
corners.push(i);
|
|
65
|
+
}
|
|
66
|
+
corners.push(n - 1);
|
|
67
|
+
return corners;
|
|
68
|
+
}
|
|
69
|
+
function computeLeftTangent(pts, idx) {
|
|
70
|
+
const dx = pts[(idx + 1) * 2] - pts[idx * 2];
|
|
71
|
+
const dy = pts[(idx + 1) * 2 + 1] - pts[idx * 2 + 1];
|
|
72
|
+
const len = Math.sqrt(dx * dx + dy * dy);
|
|
73
|
+
return len > 0 ? [dx / len, dy / len] : [1, 0];
|
|
74
|
+
}
|
|
75
|
+
function computeRightTangent(pts, idx) {
|
|
76
|
+
const dx = pts[(idx - 1) * 2] - pts[idx * 2];
|
|
77
|
+
const dy = pts[(idx - 1) * 2 + 1] - pts[idx * 2 + 1];
|
|
78
|
+
const len = Math.sqrt(dx * dx + dy * dy);
|
|
79
|
+
return len > 0 ? [dx / len, dy / len] : [-1, 0];
|
|
80
|
+
}
|
|
81
|
+
function chordLengthParameterize(pts, first, last) {
|
|
82
|
+
const u = [0];
|
|
83
|
+
for (let i = first + 1; i <= last; i++) {
|
|
84
|
+
const dx = pts[i * 2] - pts[(i - 1) * 2];
|
|
85
|
+
const dy = pts[i * 2 + 1] - pts[(i - 1) * 2 + 1];
|
|
86
|
+
u.push(u[u.length - 1] + Math.sqrt(dx * dx + dy * dy));
|
|
87
|
+
}
|
|
88
|
+
const total = u[u.length - 1];
|
|
89
|
+
if (total > 0) {
|
|
90
|
+
for (let i = 1; i < u.length; i++)
|
|
91
|
+
u[i] /= total;
|
|
92
|
+
}
|
|
93
|
+
return u;
|
|
94
|
+
}
|
|
95
|
+
function fitCubic(pts, first, last, tHat1, tHat2, toleranceSq, out) {
|
|
96
|
+
const nPts = last - first + 1;
|
|
97
|
+
if (nPts === 2) {
|
|
98
|
+
const dist = Math.sqrt((pts[last * 2] - pts[first * 2]) ** 2 + (pts[last * 2 + 1] - pts[first * 2 + 1]) ** 2);
|
|
99
|
+
const d = dist / 3;
|
|
100
|
+
out.commands.push(PathCommand.CUBIC_CURVE_TO);
|
|
101
|
+
out.data.push(pts[first * 2] + tHat1[0] * d, pts[first * 2 + 1] + tHat1[1] * d, pts[last * 2] + tHat2[0] * d, pts[last * 2 + 1] + tHat2[1] * d, pts[last * 2], pts[last * 2 + 1]);
|
|
102
|
+
return;
|
|
103
|
+
}
|
|
104
|
+
let u = chordLengthParameterize(pts, first, last);
|
|
105
|
+
const MAX_ITERATIONS = 4;
|
|
106
|
+
for (let iter = 0; iter <= MAX_ITERATIONS; iter++) {
|
|
107
|
+
const bezier = generateBezier(pts, first, last, u, tHat1, tHat2);
|
|
108
|
+
const [maxErr, splitPoint] = computeMaxError(pts, first, last, bezier, u);
|
|
109
|
+
if (maxErr < toleranceSq) {
|
|
110
|
+
out.commands.push(PathCommand.CUBIC_CURVE_TO);
|
|
111
|
+
out.data.push(bezier[2], bezier[3], bezier[4], bezier[5], bezier[6], bezier[7]);
|
|
112
|
+
return;
|
|
113
|
+
}
|
|
114
|
+
if (iter < MAX_ITERATIONS) {
|
|
115
|
+
u = reparameterize(pts, first, last, u, bezier);
|
|
116
|
+
}
|
|
117
|
+
else {
|
|
118
|
+
const tHatCenter = computeCenterTangent(pts, splitPoint);
|
|
119
|
+
fitCubic(pts, first, splitPoint, tHat1, [-tHatCenter[0], -tHatCenter[1]], toleranceSq, out);
|
|
120
|
+
fitCubic(pts, splitPoint, last, tHatCenter, tHat2, toleranceSq, out);
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
function generateBezier(pts, first, last, u, tHat1, tHat2) {
|
|
125
|
+
const nPts = last - first + 1;
|
|
126
|
+
let c00 = 0;
|
|
127
|
+
let c01 = 0;
|
|
128
|
+
let c11 = 0;
|
|
129
|
+
let x0 = 0;
|
|
130
|
+
let x1 = 0;
|
|
131
|
+
for (let i = 0; i < nPts; i++) {
|
|
132
|
+
const t = u[i];
|
|
133
|
+
const b1 = 3 * t * (1 - t) * (1 - t);
|
|
134
|
+
const b2 = 3 * t * t * (1 - t);
|
|
135
|
+
const a1x = tHat1[0] * b1;
|
|
136
|
+
const a1y = tHat1[1] * b1;
|
|
137
|
+
const a2x = tHat2[0] * b2;
|
|
138
|
+
const a2y = tHat2[1] * b2;
|
|
139
|
+
c00 += a1x * a1x + a1y * a1y;
|
|
140
|
+
c01 += a1x * a2x + a1y * a2y;
|
|
141
|
+
c11 += a2x * a2x + a2y * a2y;
|
|
142
|
+
const b0 = (1 - t) * (1 - t) * (1 - t);
|
|
143
|
+
const b3 = t * t * t;
|
|
144
|
+
const tmpx = pts[(first + i) * 2] - (pts[first * 2] * b0 + pts[first * 2] * b1 + pts[last * 2] * b2 + pts[last * 2] * b3);
|
|
145
|
+
const tmpy = pts[(first + i) * 2 + 1] -
|
|
146
|
+
(pts[first * 2 + 1] * b0 + pts[first * 2 + 1] * b1 + pts[last * 2 + 1] * b2 + pts[last * 2 + 1] * b3);
|
|
147
|
+
x0 += a1x * tmpx + a1y * tmpy;
|
|
148
|
+
x1 += a2x * tmpx + a2y * tmpy;
|
|
149
|
+
}
|
|
150
|
+
const det = c00 * c11 - c01 * c01;
|
|
151
|
+
let alpha1;
|
|
152
|
+
let alpha2;
|
|
153
|
+
if (Math.abs(det) < 1e-12) {
|
|
154
|
+
const dist = Math.sqrt((pts[last * 2] - pts[first * 2]) ** 2 + (pts[last * 2 + 1] - pts[first * 2 + 1]) ** 2);
|
|
155
|
+
alpha1 = alpha2 = dist / 3;
|
|
156
|
+
}
|
|
157
|
+
else {
|
|
158
|
+
alpha1 = (c11 * x0 - c01 * x1) / det;
|
|
159
|
+
alpha2 = (c00 * x1 - c01 * x0) / det;
|
|
160
|
+
}
|
|
161
|
+
const segLength = Math.sqrt((pts[last * 2] - pts[first * 2]) ** 2 + (pts[last * 2 + 1] - pts[first * 2 + 1]) ** 2);
|
|
162
|
+
const epsilon = 1e-6 * segLength;
|
|
163
|
+
if (alpha1 < epsilon || alpha2 < epsilon) {
|
|
164
|
+
alpha1 = alpha2 = segLength / 3;
|
|
165
|
+
}
|
|
166
|
+
return [
|
|
167
|
+
pts[first * 2],
|
|
168
|
+
pts[first * 2 + 1],
|
|
169
|
+
pts[first * 2] + tHat1[0] * alpha1,
|
|
170
|
+
pts[first * 2 + 1] + tHat1[1] * alpha1,
|
|
171
|
+
pts[last * 2] + tHat2[0] * alpha2,
|
|
172
|
+
pts[last * 2 + 1] + tHat2[1] * alpha2,
|
|
173
|
+
pts[last * 2],
|
|
174
|
+
pts[last * 2 + 1],
|
|
175
|
+
];
|
|
176
|
+
}
|
|
177
|
+
function computeMaxError(pts, first, last, bezier, u) {
|
|
178
|
+
let maxDist = 0;
|
|
179
|
+
let splitPoint = (last - first + 1) >> 1;
|
|
180
|
+
for (let i = 1; i < last - first; i++) {
|
|
181
|
+
const t = u[i];
|
|
182
|
+
const mt = 1 - t;
|
|
183
|
+
const bx = mt * mt * mt * bezier[0] + 3 * mt * mt * t * bezier[2] + 3 * mt * t * t * bezier[4] + t * t * t * bezier[6];
|
|
184
|
+
const by = mt * mt * mt * bezier[1] + 3 * mt * mt * t * bezier[3] + 3 * mt * t * t * bezier[5] + t * t * t * bezier[7];
|
|
185
|
+
const dx = pts[(first + i) * 2] - bx;
|
|
186
|
+
const dy = pts[(first + i) * 2 + 1] - by;
|
|
187
|
+
const distSq = dx * dx + dy * dy;
|
|
188
|
+
if (distSq >= maxDist) {
|
|
189
|
+
maxDist = distSq;
|
|
190
|
+
splitPoint = first + i;
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
return [maxDist, splitPoint];
|
|
194
|
+
}
|
|
195
|
+
function reparameterize(pts, first, last, u, bezier) {
|
|
196
|
+
const uPrime = [];
|
|
197
|
+
for (let i = 0; i <= last - first; i++) {
|
|
198
|
+
uPrime.push(newtonRaphsonRootFind(bezier, pts[(first + i) * 2], pts[(first + i) * 2 + 1], u[i]));
|
|
199
|
+
}
|
|
200
|
+
return uPrime;
|
|
201
|
+
}
|
|
202
|
+
function newtonRaphsonRootFind(bezier, px, py, u) {
|
|
203
|
+
const mt = 1 - u;
|
|
204
|
+
const qx = mt * mt * mt * bezier[0] + 3 * mt * mt * u * bezier[2] + 3 * mt * u * u * bezier[4] + u * u * u * bezier[6];
|
|
205
|
+
const qy = mt * mt * mt * bezier[1] + 3 * mt * mt * u * bezier[3] + 3 * mt * u * u * bezier[5] + u * u * u * bezier[7];
|
|
206
|
+
const q1x = 3 * mt * mt * (bezier[2] - bezier[0]) + 6 * mt * u * (bezier[4] - bezier[2]) + 3 * u * u * (bezier[6] - bezier[4]);
|
|
207
|
+
const q1y = 3 * mt * mt * (bezier[3] - bezier[1]) + 6 * mt * u * (bezier[5] - bezier[3]) + 3 * u * u * (bezier[7] - bezier[5]);
|
|
208
|
+
const num = (qx - px) * q1x + (qy - py) * q1y;
|
|
209
|
+
const q2x = 6 * mt * (bezier[4] - 2 * bezier[2] + bezier[0]) + 6 * u * (bezier[6] - 2 * bezier[4] + bezier[2]);
|
|
210
|
+
const q2y = 6 * mt * (bezier[5] - 2 * bezier[3] + bezier[1]) + 6 * u * (bezier[7] - 2 * bezier[5] + bezier[3]);
|
|
211
|
+
const den = q1x * q1x + q1y * q1y + (qx - px) * q2x + (qy - py) * q2y;
|
|
212
|
+
if (Math.abs(den) < 1e-12)
|
|
213
|
+
return u;
|
|
214
|
+
return Math.max(0, Math.min(1, u - num / den));
|
|
215
|
+
}
|
|
216
|
+
function computeCenterTangent(pts, idx) {
|
|
217
|
+
const dx = pts[(idx - 1) * 2] - pts[(idx + 1) * 2];
|
|
218
|
+
const dy = pts[(idx - 1) * 2 + 1] - pts[(idx + 1) * 2 + 1];
|
|
219
|
+
const len = Math.sqrt(dx * dx + dy * dy);
|
|
220
|
+
return len > 0 ? [dx / len, dy / len] : [1, 0];
|
|
221
|
+
}
|
|
222
|
+
//# sourceMappingURL=fitPathCurves.js.map
|