@weasel-js/geom 1.15.1 → 1.15.2
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/3d/index.d.ts +3 -1
- package/dist/3d/index.js +7 -10
- package/dist/3d/index.js.map +1 -1
- package/dist/booleans/index.js +4 -5
- package/dist/booleans/index.js.map +1 -1
- package/dist/{chunk-B3D6KWW3.js → chunk-346XYYMX.js} +154 -3
- package/dist/chunk-346XYYMX.js.map +1 -0
- package/dist/chunk-DNX24KBT.js +82 -0
- package/dist/chunk-DNX24KBT.js.map +1 -0
- package/dist/{chunk-EURWZUNY.js → chunk-GA5R5KWD.js} +59 -65
- package/dist/chunk-GA5R5KWD.js.map +1 -0
- package/dist/{chunk-3HQJGI63.js → chunk-HTT5AQIU.js} +3 -4
- package/dist/chunk-HTT5AQIU.js.map +1 -0
- package/dist/{chunk-FROQPADA.js → chunk-IDSKOHA4.js} +4 -4
- package/dist/{chunk-FROQPADA.js.map → chunk-IDSKOHA4.js.map} +1 -1
- package/dist/{chunk-HMGGJZTM.js → chunk-MIKP4V2C.js} +7 -21
- package/dist/chunk-MIKP4V2C.js.map +1 -0
- package/dist/{chunk-HNLJO3E7.js → chunk-MOCSUHEI.js} +22 -8
- package/dist/chunk-MOCSUHEI.js.map +1 -0
- package/dist/{chunk-3YH5XU3H.js → chunk-OQP5M5VD.js} +14 -23
- package/dist/chunk-OQP5M5VD.js.map +1 -0
- package/dist/{chunk-ZOMUTU7J.js → chunk-STYO7J4Y.js} +5 -11
- package/dist/chunk-STYO7J4Y.js.map +1 -0
- package/dist/{curvature-CDOI32hv.d.ts → curvature-DKPO4Qeh.d.ts} +0 -27
- package/dist/curves/index.d.ts +1 -1
- package/dist/curves/index.js +4 -4
- package/dist/index.d.ts +108 -3
- package/dist/index.js +159 -162
- package/dist/index.js.map +1 -1
- package/dist/nd/index.d.ts +28 -1
- package/dist/nd/index.js +2 -5
- package/dist/nd/index.js.map +1 -1
- package/dist/tessellate/index.js +5 -5
- package/dist/warp/index.js +8 -15
- package/dist/warp/index.js.map +1 -1
- package/package.json +1 -1
- package/dist/chunk-2N6OWA7E.js +0 -104
- package/dist/chunk-2N6OWA7E.js.map +0 -1
- package/dist/chunk-3HQJGI63.js.map +0 -1
- package/dist/chunk-3YH5XU3H.js.map +0 -1
- package/dist/chunk-755Y4YZS.js +0 -32
- package/dist/chunk-755Y4YZS.js.map +0 -1
- package/dist/chunk-B3D6KWW3.js.map +0 -1
- package/dist/chunk-EURWZUNY.js.map +0 -1
- package/dist/chunk-HMGGJZTM.js.map +0 -1
- package/dist/chunk-HNLJO3E7.js.map +0 -1
- package/dist/chunk-ZOMUTU7J.js.map +0 -1
package/dist/index.js
CHANGED
|
@@ -1,29 +1,45 @@
|
|
|
1
|
-
import { carryCorners, parseSubpaths, intersectSegments, evalSeg, keepCorners, anchorRange, subSeg, writePath, derivSeg } from './chunk-
|
|
2
|
-
export { CORNER_RESTORE_TOLERANCE, cornerTraces, intersectSegments, keepCorners, restoreCorners } from './chunk-
|
|
1
|
+
import { carryCorners, parseSubpaths, intersectSegments, evalSeg, keepCorners, anchorRange, subSeg, writePath, derivSeg } from './chunk-OQP5M5VD.js';
|
|
2
|
+
export { CORNER_RESTORE_TOLERANCE, cornerTraces, intersectSegments, keepCorners, restoreCorners } from './chunk-OQP5M5VD.js';
|
|
3
3
|
import { createBvh } from './chunk-XXNK4N7Z.js';
|
|
4
4
|
import { PORT_REACH, portControls, portCurvePoints } from './chunk-YQADYJJ7.js';
|
|
5
5
|
export { PORT_REACH } from './chunk-YQADYJJ7.js';
|
|
6
|
-
import { eulerAngleAt, eulerSegmentCubic, eulerCubicError, integrateEuler, eulerPointAt, eulerCurvatureAt, cubicDerivativeAt, cubicCurvatureAt } from './chunk-
|
|
7
|
-
export { SPIRO_KINDS, combTeeth, cubicCurvatureAt, cubicCurvatureSource, cubicDerivativeAt, curvatureComb, eulerAngleAt, eulerCurvatureAt, eulerCurvatureDerivativesAt, eulerPointAt, fitEulerSegment, isSpiroKind, placeEulerSegment, solveSpiro, spiroContoursFromControl, spiroContoursOf, spiroControlPath, spiroToPath } from './chunk-
|
|
8
|
-
import { extractPolylines } from './chunk-
|
|
9
|
-
import { boundsOfPath, fitPointRun, keepCorner } from './chunk-
|
|
10
|
-
export { boundsOfPath } from './chunk-
|
|
11
|
-
import { countPathAnchors, pathToAnchors, anchorsToPath, isAnchorSmooth, segmentEnds, isStraightSegment, nearestSegmentT } from './chunk-
|
|
12
|
-
export { anchorsToPath, countPathAnchors, isAnchorSmooth, isStraightSegment, nearestSegmentT, pathToAnchors, segmentEnds } from './chunk-
|
|
13
|
-
import {
|
|
14
|
-
export {
|
|
15
|
-
import {
|
|
16
|
-
export {
|
|
17
|
-
import { SINGULAR_RATIO, clamp } from './chunk-
|
|
18
|
-
export { EPS, approxEq, clamp, cross, dot, len2, sign, sub } from './chunk-
|
|
19
|
-
import { worldCoords, PATH_M, PATH_L, PATH_C, PATH_Q, PATH_Z, PathBuilder, withCorner, scaleCorners, originFor, coordsFrom, forEachSegment, pathCommandCoordCount, withoutCorners, elevateQuadraticToCubic, cubicEvalAt, cubicPointAt, splitCubicAtT, cubicAxisExtremaTs, rectToContour, splitCubicAt } from './chunk-B3D6KWW3.js';
|
|
20
|
-
export { ORIGIN_THRESHOLD, PATH_C, PATH_CMD_LENGTHS, PATH_COMMANDS, PATH_L, PATH_M, PATH_Q, PATH_Z, PathBuilder, addOrigin, asPolygonPath, boundsOfCoords, boxContainsBox, boxContainsPoint, compactCorners, coordsFrom, cornerAt, cornerSpecAt, cubicAxisExtremaTs, cubicBounds, cubicEvalAt, cubicPointAt, elevateQuadraticToCubic, ellipsePath, forEachSegment, hasCorners, joinPaths, lerpCorners, linePath, originFor, originOf, pathCommandCoordCount, pathPoint, polygonFromPoints, polylineFromPoints, quadraticEvalAt, rectPath, rectToContour, regularPolygonPath, scaleCorners, splitCubicAt, splitCubicAtT, splitLineAt, splitQuadraticAt, starPath, unionBox, withCorner, withoutCorners, worldCoords } from './chunk-B3D6KWW3.js';
|
|
6
|
+
import { wrapPositive, eulerAngleAt, eulerSegmentCubic, eulerCubicError, integrateEuler, eulerPointAt, eulerCurvatureAt, DEG_TO_RAD, cubicDerivativeAt, cubicCurvatureAt } from './chunk-MOCSUHEI.js';
|
|
7
|
+
export { DEG_TO_RAD, RAD_TO_DEG, SPIRO_KINDS, combTeeth, cubicCurvatureAt, cubicCurvatureSource, cubicDerivativeAt, curvatureComb, eulerAngleAt, eulerCurvatureAt, eulerCurvatureDerivativesAt, eulerPointAt, fitEulerSegment, isSpiroKind, placeEulerSegment, solveSpiro, spiroContoursFromControl, spiroContoursOf, spiroControlPath, spiroToPath, wrapAngle, wrapPositive } from './chunk-MOCSUHEI.js';
|
|
8
|
+
import { extractPolylines } from './chunk-IDSKOHA4.js';
|
|
9
|
+
import { boundsOfPath, fitPointRun, keepCorner } from './chunk-STYO7J4Y.js';
|
|
10
|
+
export { boundsOfPath } from './chunk-STYO7J4Y.js';
|
|
11
|
+
import { countPathAnchors, pathToAnchors, anchorsToPath, isAnchorSmooth, segmentEnds, isStraightSegment, nearestSegmentT } from './chunk-HTT5AQIU.js';
|
|
12
|
+
export { anchorsToPath, countPathAnchors, isAnchorSmooth, isStraightSegment, nearestSegmentT, pathToAnchors, segmentEnds } from './chunk-HTT5AQIU.js';
|
|
13
|
+
import { resolveCorners, pointInPolygon, cornerCuts, fillsOpenSubpaths, schneiderFit, fitCubicWithTangents, flattenCubic, flattenQuadratic, DEFAULT_FLATTEN_TOLERANCE, segmentsCross, tangentAt } from './chunk-GA5R5KWD.js';
|
|
14
|
+
export { CORNER_FIT_TOLERANCE, CORNER_KEYWORDS, DEFAULT_FLATTEN_TOLERANCE, cornerCenter, cornerCuts, cornerFrameAt, cornerFrames, cornerKeywordOf, cornerShapeK, cornerShapePieces, cornerShapePoint, defaultOpenFill, fillsOpenSubpaths, fitCubicWithTangents, flattenCubic, flattenCubicWithArcLen, flattenQuadratic, flattenQuadraticWithArcLen, isCornerShape, nextCornerShape, pointInPolygon, remapPerAnchor, resolveCorners, resolveCornersWithSources, ringSignedArea, schneiderFit, segmentsCross, setDefaultOpenFill } from './chunk-GA5R5KWD.js';
|
|
15
|
+
import { nearestOnLine, worldCoords, PATH_M, PATH_L, PATH_C, PATH_Q, PATH_Z, PathBuilder, withCorner, scaleCorners, originFor, coordsFrom, forEachSegment, pathCommandCoordCount, withoutCorners, elevateQuadraticToCubic, cubicEvalAt, nearestOnPath, cubicPointAt, splitCubicAtT, nearestOnCubic, cubicAxisExtremaTs, rectToContour, pointSegmentDist2, lerpPoint, distance, splitCubicAt, nearestOnQuadratic, boxesIntersect } from './chunk-346XYYMX.js';
|
|
16
|
+
export { ORIGIN_THRESHOLD, PATH_C, PATH_CMD_LENGTHS, PATH_COMMANDS, PATH_L, PATH_M, PATH_Q, PATH_Z, PathBuilder, addOrigin, asPolygonPath, boundsOfCoords, boxContainsBox, boxContainsPoint, boxesIntersect, compactCorners, coordsFrom, cornerAt, cornerSpecAt, cubicAxisExtremaTs, cubicBounds, cubicEvalAt, cubicPointAt, distance, distance2, elevateQuadraticToCubic, ellipsePath, forEachSegment, hasCorners, joinPaths, lerpCorners, lerpPoint, linePath, nearestOnCubic, nearestOnLine, nearestOnPath, nearestOnQuadratic, originFor, originOf, pathCommandCoordCount, pathPoint, pointSegmentDist, pointSegmentDist2, polygonFromPoints, polylineFromPoints, quadraticEvalAt, rectContainsPoint, rectContainsPointHalfOpen, rectPath, rectToContour, rectsIntersect, rectsOverlap, regularPolygonPath, scaleCorners, segmentT, splitCubicAt, splitCubicAtT, splitLineAt, splitQuadraticAt, starPath, unionBox, unionRects, withCorner, withoutCorners, worldCoords } from './chunk-346XYYMX.js';
|
|
17
|
+
import { SINGULAR_RATIO, clamp } from './chunk-DNX24KBT.js';
|
|
18
|
+
export { EPS, approxEq, clamp, clamp01, cross, dot, len2, lerp, sign, sub } from './chunk-DNX24KBT.js';
|
|
21
19
|
|
|
22
20
|
// src/view.ts
|
|
23
21
|
var ZOOM_FLOOR = 1e-9;
|
|
24
22
|
function normalizeZoom(zoom) {
|
|
25
23
|
return zoom >= ZOOM_FLOOR && zoom < Infinity ? zoom : ZOOM_FLOOR;
|
|
26
24
|
}
|
|
25
|
+
function viewWorldToScreen(view, p) {
|
|
26
|
+
return { x: (p.x - view.x) * view.scale.x, y: (p.y - view.y) * view.scale.y };
|
|
27
|
+
}
|
|
28
|
+
function viewScreenToWorld(view, p) {
|
|
29
|
+
return { x: p.x / view.scale.x + view.x, y: p.y / view.scale.y + view.y };
|
|
30
|
+
}
|
|
31
|
+
function viewRectToScreen(view, r) {
|
|
32
|
+
const x0 = (r.x - view.x) * view.scale.x;
|
|
33
|
+
const y0 = (r.y - view.y) * view.scale.y;
|
|
34
|
+
const w = r.width * view.scale.x;
|
|
35
|
+
const h = r.height * view.scale.y;
|
|
36
|
+
return {
|
|
37
|
+
x: w < 0 ? x0 + w : x0,
|
|
38
|
+
y: h < 0 ? y0 + h : y0,
|
|
39
|
+
width: Math.abs(w),
|
|
40
|
+
height: Math.abs(h)
|
|
41
|
+
};
|
|
42
|
+
}
|
|
27
43
|
|
|
28
44
|
// src/affine.ts
|
|
29
45
|
function identity() {
|
|
@@ -87,12 +103,12 @@ function transformCoords(coords, m) {
|
|
|
87
103
|
function lineShape(from, to) {
|
|
88
104
|
const dx2 = to.x - from.x;
|
|
89
105
|
const dy2 = to.y - from.y;
|
|
90
|
-
const
|
|
91
|
-
const tangent =
|
|
106
|
+
const length = Math.hypot(dx2, dy2);
|
|
107
|
+
const tangent = length === 0 ? { x: 1, y: 0 } : { x: dx2 / length, y: dy2 / length };
|
|
92
108
|
const normal2 = { x: tangent.y, y: -tangent.x };
|
|
93
109
|
return {
|
|
94
110
|
kind: "line",
|
|
95
|
-
length
|
|
111
|
+
length,
|
|
96
112
|
closed: false,
|
|
97
113
|
at(f, options) {
|
|
98
114
|
const t = options?.open ? f : clamp(f, 0, 1);
|
|
@@ -104,25 +120,23 @@ function lineShape(from, to) {
|
|
|
104
120
|
},
|
|
105
121
|
nearest(p, options) {
|
|
106
122
|
const n = nearestOnLine(p.x, p.y, from.x, from.y, to.x, to.y);
|
|
107
|
-
if (!options?.open ||
|
|
108
|
-
const f = ((p.x - from.x) * dx2 + (p.y - from.y) * dy2) / (
|
|
123
|
+
if (!options?.open || length === 0) return { f: n.t, dist: n.dist };
|
|
124
|
+
const f = ((p.x - from.x) * dx2 + (p.y - from.y) * dy2) / (length * length);
|
|
109
125
|
return { f, dist: n.dist };
|
|
110
126
|
}
|
|
111
127
|
};
|
|
112
128
|
}
|
|
113
129
|
|
|
114
130
|
// src/track/arc.ts
|
|
115
|
-
var RAD = Math.PI / 180;
|
|
116
|
-
var mod360 = (a) => (a % 360 + 360) % 360;
|
|
117
131
|
function arcShape(spec) {
|
|
118
132
|
const { center, radius, start } = spec;
|
|
119
133
|
const sign2 = spec.direction === "ccw" ? -1 : 1;
|
|
120
|
-
const raw =
|
|
134
|
+
const raw = wrapPositive(sign2 * (spec.end - start), 360);
|
|
121
135
|
const sweep = raw === 0 ? 360 : raw;
|
|
122
|
-
const
|
|
136
|
+
const length = radius * sweep * DEG_TO_RAD;
|
|
123
137
|
const at2 = (f, options) => {
|
|
124
138
|
const t = options?.open ? f : clamp(f, 0, 1);
|
|
125
|
-
const theta = (start + sign2 * t * sweep) *
|
|
139
|
+
const theta = (start + sign2 * t * sweep) * DEG_TO_RAD;
|
|
126
140
|
const s = Math.sin(theta);
|
|
127
141
|
const c = Math.cos(theta);
|
|
128
142
|
return {
|
|
@@ -133,14 +147,14 @@ function arcShape(spec) {
|
|
|
133
147
|
};
|
|
134
148
|
const shape = {
|
|
135
149
|
kind: "arc",
|
|
136
|
-
length
|
|
150
|
+
length,
|
|
137
151
|
closed: raw === 0,
|
|
138
152
|
at: at2,
|
|
139
153
|
nearest(p, options) {
|
|
140
154
|
const dx2 = p.x - center.x;
|
|
141
155
|
const dy2 = p.y - center.y;
|
|
142
|
-
const angle = dx2 === 0 && dy2 === 0 ? 0 : Math.atan2(dx2, -dy2) /
|
|
143
|
-
const offset2 =
|
|
156
|
+
const angle = dx2 === 0 && dy2 === 0 ? 0 : Math.atan2(dx2, -dy2) / DEG_TO_RAD;
|
|
157
|
+
const offset2 = wrapPositive(sign2 * (angle - start), 360);
|
|
144
158
|
let f;
|
|
145
159
|
if (offset2 <= sweep) f = offset2 / sweep;
|
|
146
160
|
else f = 360 - offset2 < offset2 - sweep ? 0 : 1;
|
|
@@ -148,7 +162,7 @@ function arcShape(spec) {
|
|
|
148
162
|
const dist = Math.hypot(p.x - q.x, p.y - q.y);
|
|
149
163
|
if (!options?.open) return { f, dist };
|
|
150
164
|
const mid = (options.about ?? 0.5) * sweep;
|
|
151
|
-
const unwrapped = mid +
|
|
165
|
+
const unwrapped = mid + wrapPositive(offset2 - mid + 180, 360) - 180;
|
|
152
166
|
return { f: unwrapped / sweep, dist };
|
|
153
167
|
}
|
|
154
168
|
};
|
|
@@ -157,18 +171,16 @@ function arcShape(spec) {
|
|
|
157
171
|
}
|
|
158
172
|
|
|
159
173
|
// src/track/ellipse.ts
|
|
160
|
-
var RAD2 = Math.PI / 180;
|
|
161
|
-
var mod3602 = (a) => (a % 360 + 360) % 360;
|
|
162
174
|
var PIECES = 128;
|
|
163
175
|
var PANELS = 4;
|
|
164
176
|
var RING = 256;
|
|
165
177
|
var pointAt = ({ center, a, b, t0, sign: sign2 }, u) => {
|
|
166
|
-
const t = (t0 + sign2 * u) *
|
|
178
|
+
const t = (t0 + sign2 * u) * DEG_TO_RAD;
|
|
167
179
|
return { x: center.x + a * Math.sin(t), y: center.y - b * Math.cos(t) };
|
|
168
180
|
};
|
|
169
181
|
var speed = ({ a, b, t0, sign: sign2 }, u) => {
|
|
170
|
-
const t = (t0 + sign2 * u) *
|
|
171
|
-
return Math.hypot(a * Math.cos(t), b * Math.sin(t)) *
|
|
182
|
+
const t = (t0 + sign2 * u) * DEG_TO_RAD;
|
|
183
|
+
return Math.hypot(a * Math.cos(t), b * Math.sin(t)) * DEG_TO_RAD;
|
|
172
184
|
};
|
|
173
185
|
function lengthTable(e, sweep) {
|
|
174
186
|
const simpson = (u0, u1) => {
|
|
@@ -180,7 +192,7 @@ function lengthTable(e, sweep) {
|
|
|
180
192
|
const du = sweep / PIECES;
|
|
181
193
|
const table = [0];
|
|
182
194
|
for (let i = 0; i < PIECES; i++) table.push(table[i] + simpson(i * du, (i + 1) * du));
|
|
183
|
-
const
|
|
195
|
+
const length = table[PIECES];
|
|
184
196
|
const lengthTo = (u) => {
|
|
185
197
|
if (u >= 0 && u <= sweep) {
|
|
186
198
|
const i = Math.min(PIECES - 1, Math.floor(u / du));
|
|
@@ -192,8 +204,8 @@ function lengthTable(e, sweep) {
|
|
|
192
204
|
return s;
|
|
193
205
|
};
|
|
194
206
|
const offsetAt = (f) => {
|
|
195
|
-
if (
|
|
196
|
-
const s = f *
|
|
207
|
+
if (length === 0) return f * sweep;
|
|
208
|
+
const s = f * length;
|
|
197
209
|
let lo = 0;
|
|
198
210
|
let hi = PIECES;
|
|
199
211
|
while (hi - lo > 1) {
|
|
@@ -210,7 +222,7 @@ function lengthTable(e, sweep) {
|
|
|
210
222
|
}
|
|
211
223
|
return u;
|
|
212
224
|
};
|
|
213
|
-
return { length
|
|
225
|
+
return { length, lengthTo, offsetAt };
|
|
214
226
|
}
|
|
215
227
|
var dist2 = (e, p, u) => {
|
|
216
228
|
const q = pointAt(e, u);
|
|
@@ -230,13 +242,13 @@ function footBetween(e, p, lo, hi, n, late) {
|
|
|
230
242
|
const dy2 = p.y - e.center.y;
|
|
231
243
|
let u = best;
|
|
232
244
|
for (let i = 0; i < 12; i++) {
|
|
233
|
-
const t = (t0 + sign2 * u) *
|
|
245
|
+
const t = (t0 + sign2 * u) * DEG_TO_RAD;
|
|
234
246
|
const s = Math.sin(t);
|
|
235
247
|
const c = Math.cos(t);
|
|
236
248
|
const g = (a * a - b * b) * s * c - dx2 * a * c - dy2 * b * s;
|
|
237
249
|
const g1 = (a * a - b * b) * (c * c - s * s) + dx2 * a * s - dy2 * b * c;
|
|
238
250
|
if (!(g1 > 0)) break;
|
|
239
|
-
const next = clamp(u - sign2 * g / g1 /
|
|
251
|
+
const next = clamp(u - sign2 * g / g1 / DEG_TO_RAD, Math.max(lo, best - step), Math.min(hi, best + step));
|
|
240
252
|
if (Math.abs(next - u) < 1e-12) break;
|
|
241
253
|
u = next;
|
|
242
254
|
}
|
|
@@ -245,24 +257,24 @@ function footBetween(e, p, lo, hi, n, late) {
|
|
|
245
257
|
function ellipseShape(spec) {
|
|
246
258
|
const { center, radiusX: a, radiusY: b } = spec;
|
|
247
259
|
const sign2 = spec.direction === "ccw" ? -1 : 1;
|
|
248
|
-
const param = (seenDeg) => Math.atan2(b * Math.sin(seenDeg *
|
|
260
|
+
const param = (seenDeg) => Math.atan2(b * Math.sin(seenDeg * DEG_TO_RAD), a * Math.cos(seenDeg * DEG_TO_RAD)) / DEG_TO_RAD;
|
|
249
261
|
const e = { center, a, b, t0: param(spec.start), sign: sign2 };
|
|
250
|
-
const raw =
|
|
262
|
+
const raw = wrapPositive(sign2 * (param(spec.end) - e.t0), 360);
|
|
251
263
|
const sweep = raw === 0 ? 360 : raw;
|
|
252
|
-
const { length
|
|
264
|
+
const { length, lengthTo, offsetAt } = lengthTable(e, sweep);
|
|
253
265
|
const offsetPast = (f) => {
|
|
254
266
|
if (raw === 0) return offsetAt((f % 1 + 1) % 1);
|
|
255
267
|
let u = f * sweep;
|
|
256
268
|
for (let i = 0; i < 8; i++) {
|
|
257
269
|
const v = speed(e, u);
|
|
258
270
|
if (!(v > 0)) break;
|
|
259
|
-
u -= (lengthTo(u) - f *
|
|
271
|
+
u -= (lengthTo(u) - f * length) / v;
|
|
260
272
|
}
|
|
261
273
|
return u;
|
|
262
274
|
};
|
|
263
275
|
const at2 = (f, options) => {
|
|
264
276
|
const u = options?.open && (f < 0 || f > 1) ? offsetPast(f) : offsetAt(clamp(f, 0, 1));
|
|
265
|
-
const t = (e.t0 + sign2 * u) *
|
|
277
|
+
const t = (e.t0 + sign2 * u) * DEG_TO_RAD;
|
|
266
278
|
const s = Math.sin(t);
|
|
267
279
|
const c = Math.cos(t);
|
|
268
280
|
const k = Math.hypot(a * c, b * s);
|
|
@@ -272,16 +284,16 @@ function ellipseShape(spec) {
|
|
|
272
284
|
};
|
|
273
285
|
const shape = {
|
|
274
286
|
kind: "ellipse",
|
|
275
|
-
length
|
|
287
|
+
length,
|
|
276
288
|
closed: raw === 0,
|
|
277
289
|
at: at2,
|
|
278
290
|
nearest(p, options) {
|
|
279
291
|
const u = footBetween(e, p, 0, sweep, PIECES, true);
|
|
280
|
-
const f =
|
|
292
|
+
const f = length === 0 ? 0 : clamp(lengthTo(u) / length, 0, 1);
|
|
281
293
|
const dist = Math.sqrt(dist2(e, p, u));
|
|
282
|
-
if (!options?.open ||
|
|
294
|
+
if (!options?.open || length === 0) return { f, dist };
|
|
283
295
|
const mid = offsetAt(options.about ?? 0.5);
|
|
284
|
-
return { f: lengthTo(footBetween(e, p, mid - 180, mid + 180, RING, false)) /
|
|
296
|
+
return { f: lengthTo(footBetween(e, p, mid - 180, mid + 180, RING, false)) / length, dist };
|
|
285
297
|
}
|
|
286
298
|
};
|
|
287
299
|
Object.defineProperty(shape, "ellipse", { value: spec, enumerable: false });
|
|
@@ -413,22 +425,22 @@ function segmentAt(segments, s) {
|
|
|
413
425
|
function pathShape(path, options = {}) {
|
|
414
426
|
const measure2 = measurePath(path, { ...options, keepCorners: true });
|
|
415
427
|
if (!measure2) return null;
|
|
416
|
-
const { length
|
|
428
|
+
const { length, closed } = measure2;
|
|
417
429
|
const shape = {
|
|
418
430
|
kind: "path",
|
|
419
|
-
length
|
|
431
|
+
length,
|
|
420
432
|
closed,
|
|
421
433
|
at(f, options2) {
|
|
422
434
|
const open = options2?.open === true && (f < 0 || f > 1);
|
|
423
435
|
const g = open && closed ? (f % 1 + 1) % 1 : clamp(f, 0, 1);
|
|
424
|
-
const { point, tangent } = measure2.at(g *
|
|
425
|
-
const past = open && !closed ? (f - g) *
|
|
436
|
+
const { point, tangent } = measure2.at(g * length, true);
|
|
437
|
+
const past = open && !closed ? (f - g) * length : 0;
|
|
426
438
|
return { point: { x: point.x + past * tangent.x, y: point.y + past * tangent.y }, tangent, normal: { x: tangent.y, y: -tangent.x } };
|
|
427
439
|
},
|
|
428
440
|
nearest(p, opts) {
|
|
429
441
|
const n = measure2.nearest(p);
|
|
430
|
-
const f =
|
|
431
|
-
if (!opts?.open || !closed ||
|
|
442
|
+
const f = length === 0 ? 0 : n.s / length;
|
|
443
|
+
if (!opts?.open || !closed || length === 0) return { f, dist: n.dist };
|
|
432
444
|
const about = opts.about ?? 0.5;
|
|
433
445
|
const unwrapped = [f - 1, f + 1].reduce((best, g) => Math.abs(g - about) < Math.abs(best - about) ? g : best, f);
|
|
434
446
|
return { f: unwrapped, dist: n.dist };
|
|
@@ -556,7 +568,7 @@ function trackShapeD(shape, from = 0, to = 1) {
|
|
|
556
568
|
const param = (p) => Math.atan2((p.x - center.x) / radiusX, (center.y - p.y) / radiusY);
|
|
557
569
|
const sign2 = direction === "ccw" ? -1 : 1;
|
|
558
570
|
const whole = (shape.ellipse.start - shape.ellipse.end) % 360 === 0 && Math.abs(to - from) >= 1 - 1e-12;
|
|
559
|
-
const raw = (sign2 * Math.sign(to - from) * (param(b) - param(a))
|
|
571
|
+
const raw = wrapPositive(sign2 * Math.sign(to - from) * (param(b) - param(a)));
|
|
560
572
|
return arcsD(a, b, m, radiusX, radiusY, whole ? 2 * Math.PI : raw, direction === "ccw" === to < from ? 1 : 0);
|
|
561
573
|
}
|
|
562
574
|
let d = `M ${pt(a)}`;
|
|
@@ -591,15 +603,15 @@ function shiftTrack(shape, shift) {
|
|
|
591
603
|
table[i] = table[i - 1] + Math.hypot(step.x, step.y);
|
|
592
604
|
prev = next;
|
|
593
605
|
}
|
|
594
|
-
const
|
|
606
|
+
const length = table[SAMPLES2];
|
|
595
607
|
const per = shape.length / SAMPLES2;
|
|
596
608
|
const startRatio = table[1] > 0 ? per / table[1] : 1;
|
|
597
609
|
const endRatio = table[SAMPLES2] - table[SAMPLES2 - 1] > 0 ? per / (table[SAMPLES2] - table[SAMPLES2 - 1]) : 1;
|
|
598
610
|
const toBase = (f) => {
|
|
599
|
-
const d = f *
|
|
600
|
-
if (
|
|
611
|
+
const d = f * length;
|
|
612
|
+
if (length <= 0 || shape.length <= 0) return f;
|
|
601
613
|
if (d < 0) return d * startRatio / shape.length;
|
|
602
|
-
if (d >
|
|
614
|
+
if (d > length) return 1 + (d - length) * endRatio / shape.length;
|
|
603
615
|
let lo = 0;
|
|
604
616
|
let hi = SAMPLES2;
|
|
605
617
|
while (hi - lo > 1) {
|
|
@@ -611,17 +623,17 @@ function shiftTrack(shape, shift) {
|
|
|
611
623
|
return (lo + (span > 0 ? (d - table[lo]) / span : 0)) / SAMPLES2;
|
|
612
624
|
};
|
|
613
625
|
const fromBase = (g) => {
|
|
614
|
-
if (
|
|
615
|
-
if (g < 0) return g * shape.length / startRatio /
|
|
616
|
-
if (g > 1) return (
|
|
626
|
+
if (length <= 0 || shape.length <= 0) return g;
|
|
627
|
+
if (g < 0) return g * shape.length / startRatio / length;
|
|
628
|
+
if (g > 1) return (length + (g - 1) * shape.length / endRatio) / length;
|
|
617
629
|
const x = g * SAMPLES2;
|
|
618
630
|
const i = Math.min(SAMPLES2 - 1, Math.floor(x));
|
|
619
|
-
return (table[i] + (x - i) * (table[i + 1] - table[i])) /
|
|
631
|
+
return (table[i] + (x - i) * (table[i + 1] - table[i])) / length;
|
|
620
632
|
};
|
|
621
633
|
const at2 = (f, options) => moved2(shape.at(toBase(options?.open ? f : clamp(f, 0, 1)), options));
|
|
622
634
|
return {
|
|
623
635
|
kind: shape.kind,
|
|
624
|
-
length
|
|
636
|
+
length,
|
|
625
637
|
closed: shape.closed,
|
|
626
638
|
at: at2,
|
|
627
639
|
nearest(p, options) {
|
|
@@ -634,8 +646,7 @@ function shiftTrack(shape, shift) {
|
|
|
634
646
|
}
|
|
635
647
|
|
|
636
648
|
// src/track/slice.ts
|
|
637
|
-
var
|
|
638
|
-
var seen = (c, p) => Math.atan2(p.x - c.x, c.y - p.y) / RAD3;
|
|
649
|
+
var seen = (c, p) => Math.atan2(p.x - c.x, c.y - p.y) / DEG_TO_RAD;
|
|
639
650
|
function trackSlice(shape, from, to) {
|
|
640
651
|
const lo = clamp(Math.min(from, to), 0, 1);
|
|
641
652
|
const hi = clamp(Math.max(from, to), 0, 1);
|
|
@@ -675,25 +686,25 @@ function runPlaces(lengths, gap, room, align, offset2, at2) {
|
|
|
675
686
|
const fits = at2 === void 0 && total <= room;
|
|
676
687
|
const lead = align === "start" ? 0 : align === "end" ? total : total / 2;
|
|
677
688
|
let lo = at2 !== void 0 ? at2 - offset2 - lead : !fits ? -offset2 : align === "start" ? 0 : align === "end" ? room - total : (room - total) / 2;
|
|
678
|
-
return lengths.map((
|
|
689
|
+
return lengths.map((length) => {
|
|
679
690
|
const start = lo;
|
|
680
|
-
const hi = start +
|
|
691
|
+
const hi = start + length;
|
|
681
692
|
lo = hi + gap;
|
|
682
|
-
return { center: start +
|
|
693
|
+
return { center: start + length / 2, clipped: fits ? "none" : clipOf(start, hi, 0, room) };
|
|
683
694
|
});
|
|
684
695
|
}
|
|
685
696
|
function runLength(lengths, gap) {
|
|
686
|
-
return lengths.reduce((sum,
|
|
697
|
+
return lengths.reduce((sum, length, i) => sum + length + (i > 0 ? gap : 0), 0);
|
|
687
698
|
}
|
|
688
|
-
function runStationAt(run2,
|
|
689
|
-
const { length
|
|
690
|
-
if (past === "follow" &&
|
|
691
|
-
const place2 = run2.at(
|
|
699
|
+
function runStationAt(run2, distance3, shift = 0, past = "extend") {
|
|
700
|
+
const { length } = run2;
|
|
701
|
+
if (past === "follow" && length > 0) {
|
|
702
|
+
const place2 = run2.at(distance3 / length, { open: true });
|
|
692
703
|
const { point: point2, normal: normal3 } = place2;
|
|
693
704
|
return { ...place2, point: { x: point2.x + shift * normal3.x, y: point2.y + shift * normal3.y } };
|
|
694
705
|
}
|
|
695
|
-
const place = run2.at(
|
|
696
|
-
const beyond =
|
|
706
|
+
const place = run2.at(length === 0 ? 0 : distance3 / length);
|
|
707
|
+
const beyond = distance3 < 0 ? distance3 : distance3 > length ? distance3 - length : 0;
|
|
697
708
|
const { point, tangent, normal: normal2 } = place;
|
|
698
709
|
return {
|
|
699
710
|
...place,
|
|
@@ -702,22 +713,22 @@ function runStationAt(run2, distance, shift = 0, past = "extend") {
|
|
|
702
713
|
}
|
|
703
714
|
function placeAlongRun(run2, lengths, options = {}) {
|
|
704
715
|
const { gap = 0, align = "center", offset: offset2 = 0, at: at2, shift = 0, wrap = false, past = "extend", order = "reading" } = options;
|
|
705
|
-
const { length
|
|
716
|
+
const { length } = run2;
|
|
706
717
|
const mirror = order === "track" && run2.reversed;
|
|
707
|
-
const spots = runPlaces(lengths, gap,
|
|
708
|
-
const lap = wrap && run2.closed && spots.length > 0 ? wrapWindow(spots[0], lengths[0],
|
|
718
|
+
const spots = runPlaces(lengths, gap, length, align, offset2, at2);
|
|
719
|
+
const lap = wrap && run2.closed && spots.length > 0 ? wrapWindow(spots[0], lengths[0], length) : null;
|
|
709
720
|
return spots.map((spot, i) => {
|
|
710
721
|
const half = lengths[i] / 2;
|
|
711
722
|
const clipped = lap ? clipOf(spot.center - half, spot.center + half, lap.start, lap.end, lap.hair) : spot.clipped;
|
|
712
|
-
let
|
|
713
|
-
if (past === "hold" && clipped === "past")
|
|
714
|
-
if (lap &&
|
|
715
|
-
return { ...runStationAt(run2, mirror ?
|
|
723
|
+
let distance3 = spot.center;
|
|
724
|
+
if (past === "hold" && clipped === "past") distance3 = clamp(distance3, lap?.start ?? 0, lap?.end ?? length);
|
|
725
|
+
if (lap && length > 0) distance3 = (distance3 % length + length) % length;
|
|
726
|
+
return { ...runStationAt(run2, mirror ? length - distance3 : distance3, shift, past === "extend" ? "extend" : "follow"), center: spot.center, clipped };
|
|
716
727
|
});
|
|
717
728
|
}
|
|
718
|
-
function wrapWindow(first, firstLength,
|
|
729
|
+
function wrapWindow(first, firstLength, length) {
|
|
719
730
|
const start = first.center - firstLength / 2;
|
|
720
|
-
return { start, end: start +
|
|
731
|
+
return { start, end: start + length, hair: 1e-9 * Math.max(1, length) };
|
|
721
732
|
}
|
|
722
733
|
|
|
723
734
|
// src/portCurve2.ts
|
|
@@ -1128,8 +1139,8 @@ function polygonIntersectsPath(polygon, path, opts = {}) {
|
|
|
1128
1139
|
}
|
|
1129
1140
|
|
|
1130
1141
|
// src/paths/cornerOffset.ts
|
|
1131
|
-
function offsetCornerTraces(path,
|
|
1132
|
-
if (path.kind !== "polygon" ||
|
|
1142
|
+
function offsetCornerTraces(path, distance3) {
|
|
1143
|
+
if (path.kind !== "polygon" || distance3 === 0) return [];
|
|
1133
1144
|
const drawn = resolveCorners(path);
|
|
1134
1145
|
const out = [];
|
|
1135
1146
|
for (const cut of cornerCuts(path)) {
|
|
@@ -1146,9 +1157,9 @@ function offsetCornerTraces(path, distance) {
|
|
|
1146
1157
|
const half = Math.acos(Math.max(-1, Math.min(1, din.x * b.x + din.y * b.y)));
|
|
1147
1158
|
const probe = Math.min(inLen, outLen) * 0.01;
|
|
1148
1159
|
const sign2 = pointInPath(drawn, v.x + b.x * probe, v.y + b.y * probe) ? -1 : 1;
|
|
1149
|
-
const radius = spec.radius + sign2 *
|
|
1160
|
+
const radius = spec.radius + sign2 * distance3 / Math.tan(half);
|
|
1150
1161
|
if (!(radius > 0)) continue;
|
|
1151
|
-
const at2 = { x: v.x - b.x * sign2 *
|
|
1162
|
+
const at2 = { x: v.x - b.x * sign2 * distance3 / Math.sin(half), y: v.y - b.y * sign2 * distance3 / Math.sin(half) };
|
|
1152
1163
|
const reach = radius * 2 + 1;
|
|
1153
1164
|
const wedge = new PathBuilder().moveTo(at2.x + din.x * reach, at2.y + din.y * reach).lineTo(at2.x, at2.y).lineTo(at2.x + dout.x * reach, at2.y + dout.y * reach).build();
|
|
1154
1165
|
const [moved2] = cornerCuts(withCorner(wedge, 1, { shape: spec.shape, radius }));
|
|
@@ -2341,14 +2352,14 @@ function segmentLength(s, a = 0, b = 1) {
|
|
|
2341
2352
|
}
|
|
2342
2353
|
return sum * h / 2;
|
|
2343
2354
|
}
|
|
2344
|
-
function segmentTAtLength(s,
|
|
2355
|
+
function segmentTAtLength(s, length) {
|
|
2345
2356
|
const total = segmentLength(s);
|
|
2346
|
-
if (
|
|
2347
|
-
if (
|
|
2348
|
-
if (s.length === 2) return
|
|
2349
|
-
let lo = 0, hi = 1, t =
|
|
2357
|
+
if (length <= 0 || !(total > 0)) return 0;
|
|
2358
|
+
if (length >= total) return 1;
|
|
2359
|
+
if (s.length === 2) return length / total;
|
|
2360
|
+
let lo = 0, hi = 1, t = length / total;
|
|
2350
2361
|
for (let i = 0; i < 30; i++) {
|
|
2351
|
-
const err = segmentLength(s, 0, t) -
|
|
2362
|
+
const err = segmentLength(s, 0, t) - length;
|
|
2352
2363
|
if (Math.abs(err) < 1e-10 * Math.max(1, total)) break;
|
|
2353
2364
|
if (err > 0) hi = t;
|
|
2354
2365
|
else lo = t;
|
|
@@ -2559,8 +2570,8 @@ function findPathSnaps(index, probe, query) {
|
|
|
2559
2570
|
const skip = query.skip ?? (() => false);
|
|
2560
2571
|
const hits = [];
|
|
2561
2572
|
const offer = (kind, x, y, paths) => {
|
|
2562
|
-
const
|
|
2563
|
-
if (
|
|
2573
|
+
const distance3 = metric(x - probe.x, y - probe.y);
|
|
2574
|
+
if (distance3 <= r) hits.push({ kind, x, y, distance: distance3, paths });
|
|
2564
2575
|
};
|
|
2565
2576
|
const rx = sx > 0 ? r / sx : Infinity, ry = sy > 0 ? r / sy : Infinity;
|
|
2566
2577
|
const box = [probe.x - rx, probe.y - ry, probe.x + rx, probe.y + ry];
|
|
@@ -3142,12 +3153,12 @@ var FULL = 2 * Math.PI;
|
|
|
3142
3153
|
var FIT_SHARE = 1e-4;
|
|
3143
3154
|
var FIT_FLOOR = 1e-3;
|
|
3144
3155
|
var MAX_SPLITS = 6;
|
|
3145
|
-
function extensionPieces(frame,
|
|
3146
|
-
if (!(
|
|
3147
|
-
const bends = Math.abs(frame.curvature) *
|
|
3148
|
-
if (mode === "curvature" && bends) return arcPieces(frame,
|
|
3149
|
-
if (mode === "eased" && bends) return easedPieces(frame,
|
|
3150
|
-
return [line(frame.point, frame.tangent,
|
|
3156
|
+
function extensionPieces(frame, distance3, mode, opts = {}) {
|
|
3157
|
+
if (!(distance3 > 0)) return [];
|
|
3158
|
+
const bends = Math.abs(frame.curvature) * distance3 > STRAIGHT_TURN;
|
|
3159
|
+
if (mode === "curvature" && bends) return arcPieces(frame, distance3);
|
|
3160
|
+
if (mode === "eased" && bends) return easedPieces(frame, distance3, easeTurnOf(opts));
|
|
3161
|
+
return [line(frame.point, frame.tangent, distance3)];
|
|
3151
3162
|
}
|
|
3152
3163
|
function easeLength(frame, opts = {}) {
|
|
3153
3164
|
const k = Math.abs(frame.curvature);
|
|
@@ -3157,16 +3168,16 @@ function easeTurnOf(opts) {
|
|
|
3157
3168
|
const turn = opts.easeTurn;
|
|
3158
3169
|
return turn !== void 0 && Number.isFinite(turn) && turn > 0 ? Math.min(turn, QUARTER) : DEFAULT_EASE_TURN;
|
|
3159
3170
|
}
|
|
3160
|
-
function line(from, dir,
|
|
3161
|
-
return { pts: [from, { x: from.x + dir.x *
|
|
3171
|
+
function line(from, dir, length) {
|
|
3172
|
+
return { pts: [from, { x: from.x + dir.x * length, y: from.y + dir.y * length }], length };
|
|
3162
3173
|
}
|
|
3163
3174
|
function arcCenter({ point, tangent, curvature }) {
|
|
3164
3175
|
return { x: point.x - tangent.y / curvature, y: point.y + tangent.x / curvature };
|
|
3165
3176
|
}
|
|
3166
|
-
function arcPieces(frame,
|
|
3177
|
+
function arcPieces(frame, distance3) {
|
|
3167
3178
|
const s = Math.sign(frame.curvature);
|
|
3168
3179
|
const r = 1 / Math.abs(frame.curvature);
|
|
3169
|
-
const sweep = Math.min(
|
|
3180
|
+
const sweep = Math.min(distance3 / r, FULL);
|
|
3170
3181
|
const count = Math.max(1, Math.ceil(sweep / QUARTER - 1e-9));
|
|
3171
3182
|
const step = sweep / count;
|
|
3172
3183
|
const reach = 4 / 3 * Math.tan(step / 4) * r;
|
|
@@ -3197,7 +3208,7 @@ function arcPieces(frame, distance) {
|
|
|
3197
3208
|
}
|
|
3198
3209
|
return out;
|
|
3199
3210
|
}
|
|
3200
|
-
function easeSpiral(frame,
|
|
3211
|
+
function easeSpiral(frame, length, turn) {
|
|
3201
3212
|
const sign2 = Math.sign(frame.curvature);
|
|
3202
3213
|
const k0 = sign2 * turn;
|
|
3203
3214
|
const k1 = -2 * sign2 * turn;
|
|
@@ -3212,19 +3223,19 @@ function easeSpiral(frame, length2, turn) {
|
|
|
3212
3223
|
chordAngle: Math.atan2(c.y, c.x),
|
|
3213
3224
|
p0: frame.point,
|
|
3214
3225
|
p1: frame.point,
|
|
3215
|
-
length
|
|
3226
|
+
length,
|
|
3216
3227
|
rotation
|
|
3217
3228
|
};
|
|
3218
3229
|
return { ...seg, p1: eulerPointAt(seg, 1) };
|
|
3219
3230
|
}
|
|
3220
|
-
function easedPieces(frame,
|
|
3231
|
+
function easedPieces(frame, distance3, turn) {
|
|
3221
3232
|
const ease = 2 * turn / Math.abs(frame.curvature);
|
|
3222
3233
|
const spiral = easeSpiral(frame, ease, turn);
|
|
3223
|
-
const drawn =
|
|
3234
|
+
const drawn = distance3 < ease ? spiralPiece(spiral, 0, distance3 / ease) : spiral;
|
|
3224
3235
|
const out = fitSpiral(drawn, Math.max(FIT_FLOOR, FIT_SHARE * ease), 0);
|
|
3225
|
-
if (
|
|
3236
|
+
if (distance3 > ease) {
|
|
3226
3237
|
const a = eulerAngleAt(spiral, 1);
|
|
3227
|
-
out.push(line(spiral.p1, { x: Math.cos(a), y: Math.sin(a) },
|
|
3238
|
+
out.push(line(spiral.p1, { x: Math.cos(a), y: Math.sin(a) }, distance3 - ease));
|
|
3228
3239
|
}
|
|
3229
3240
|
return out;
|
|
3230
3241
|
}
|
|
@@ -3315,9 +3326,9 @@ function pathEndAnchorIndex(set, end) {
|
|
|
3315
3326
|
function pathEndFrame(set, end) {
|
|
3316
3327
|
return atTail(set, end, tailFrame) ?? null;
|
|
3317
3328
|
}
|
|
3318
|
-
function lengthenPathEnd(set, end,
|
|
3319
|
-
if (!(
|
|
3320
|
-
return atTail(set, end, (sub3) =>
|
|
3329
|
+
function lengthenPathEnd(set, end, distance3, mode, opts = {}) {
|
|
3330
|
+
if (!(distance3 !== 0 && Number.isFinite(distance3))) return false;
|
|
3331
|
+
return atTail(set, end, (sub3) => distance3 < 0 ? trimTail(sub3, -distance3) : growTail(sub3, distance3, mode, opts)) ?? false;
|
|
3321
3332
|
}
|
|
3322
3333
|
function lengthToward(set, end, mode, point, near2 = 0, opts = {}) {
|
|
3323
3334
|
const frame = pathEndFrame(set, end);
|
|
@@ -3393,10 +3404,10 @@ function lengthAlongEased(frame, point, opts) {
|
|
|
3393
3404
|
}
|
|
3394
3405
|
return best.length;
|
|
3395
3406
|
}
|
|
3396
|
-
function growTail(sub3,
|
|
3407
|
+
function growTail(sub3, distance3, mode, opts) {
|
|
3397
3408
|
const frame = tailFrame(sub3);
|
|
3398
3409
|
if (!frame) return false;
|
|
3399
|
-
const pieces = extensionPieces(frame,
|
|
3410
|
+
const pieces = extensionPieces(frame, distance3, mode, opts);
|
|
3400
3411
|
const end = sub3[sub3.length - 1];
|
|
3401
3412
|
const first = pieces[0];
|
|
3402
3413
|
if (pieces.length === 1 && first.pts.length === 2 && isStraightSegment(sub3[sub3.length - 2], end)) {
|
|
@@ -3479,9 +3490,9 @@ function segmentsBesideEnd(path, end) {
|
|
|
3479
3490
|
return s === end.sub ? segs.filter((g) => g.index !== (end.end === "last" ? g.count - 1 : 0)) : segs;
|
|
3480
3491
|
});
|
|
3481
3492
|
}
|
|
3482
|
-
function lengthenOpenEnd(path, end,
|
|
3483
|
-
if (!(
|
|
3484
|
-
return editAnchorSetTracked(path, (set) => lengthenPathEnd(set, end,
|
|
3493
|
+
function lengthenOpenEnd(path, end, distance3, mode = "tangent", opts = {}) {
|
|
3494
|
+
if (!(distance3 > 0) || path.kind !== "polygon") return null;
|
|
3495
|
+
return editAnchorSetTracked(path, (set) => lengthenPathEnd(set, end, distance3, mode, opts))?.path ?? null;
|
|
3485
3496
|
}
|
|
3486
3497
|
function extendToMeet(path, boundaries, end, opts = {}) {
|
|
3487
3498
|
if (path.kind !== "polygon") return null;
|
|
@@ -3649,12 +3660,12 @@ function unit(p) {
|
|
|
3649
3660
|
// src/paths/growRegion.ts
|
|
3650
3661
|
var MAX_DEPTH = 6;
|
|
3651
3662
|
var SAMPLES3 = [0.2, 0.35, 0.5, 0.65, 0.8];
|
|
3652
|
-
function growRegion(path,
|
|
3663
|
+
function growRegion(path, distance3, opts = {}) {
|
|
3653
3664
|
const b = new PathBuilder();
|
|
3654
|
-
if (!(
|
|
3665
|
+
if (!(distance3 > 0)) return b.build();
|
|
3655
3666
|
const sigma = pathSignedArea(path) < 0 ? -1 : 1;
|
|
3656
3667
|
const ctx = {
|
|
3657
|
-
d:
|
|
3668
|
+
d: distance3,
|
|
3658
3669
|
sigma,
|
|
3659
3670
|
tol: opts.tolerance ?? 0.1,
|
|
3660
3671
|
join: opts.join ?? "miter",
|
|
@@ -3887,7 +3898,7 @@ function segmentCrossings(segs) {
|
|
|
3887
3898
|
const out = [];
|
|
3888
3899
|
for (let a = 0; a < segs.length; a++) {
|
|
3889
3900
|
for (let b = a + 1; b < segs.length; b++) {
|
|
3890
|
-
if (!
|
|
3901
|
+
if (!boxesIntersect(boxes[a], boxes[b])) continue;
|
|
3891
3902
|
const pa = flat[a], pb = flat[b];
|
|
3892
3903
|
for (let i = 0; i + 1 < pa.length; i++) {
|
|
3893
3904
|
for (let j = 0; j + 1 < pb.length; j++) {
|
|
@@ -3921,7 +3932,6 @@ function boxOf(pts) {
|
|
|
3921
3932
|
}
|
|
3922
3933
|
return b;
|
|
3923
3934
|
}
|
|
3924
|
-
var overlaps = (p, q) => p[0] <= q[2] && q[0] <= p[2] && p[1] <= q[3] && q[1] <= p[3];
|
|
3925
3935
|
function linesCross(a, b, c, d) {
|
|
3926
3936
|
const rx = b[0] - a[0], ry = b[1] - a[1], sx = d[0] - c[0], sy = d[1] - c[1];
|
|
3927
3937
|
const den = rx * sy - ry * sx;
|
|
@@ -4221,21 +4231,21 @@ function paramAt(seg, d) {
|
|
|
4221
4231
|
function arcRun(sub3, from, to) {
|
|
4222
4232
|
const n = sub3.length;
|
|
4223
4233
|
const segs = [];
|
|
4224
|
-
let
|
|
4234
|
+
let length = 0;
|
|
4225
4235
|
for (let i = from; i < to; i++) {
|
|
4226
|
-
const seg = measure(sub3[i % n], sub3[(i + 1) % n],
|
|
4236
|
+
const seg = measure(sub3[i % n], sub3[(i + 1) % n], length);
|
|
4227
4237
|
segs.push(seg);
|
|
4228
|
-
|
|
4238
|
+
length += seg.len;
|
|
4229
4239
|
}
|
|
4230
4240
|
const locate = (s, arriving) => {
|
|
4231
|
-
const d = Math.min(Math.max(s, 0),
|
|
4241
|
+
const d = Math.min(Math.max(s, 0), length);
|
|
4232
4242
|
let k = 0;
|
|
4233
4243
|
while (k < segs.length - 1 && (arriving ? segs[k].from + segs[k].len < d : segs[k].from + segs[k].len <= d)) k++;
|
|
4234
4244
|
return { seg: segs[k], t: paramAt(segs[k], d - segs[k].from) };
|
|
4235
4245
|
};
|
|
4236
4246
|
const start = { x: sub3[from % n].x, y: sub3[from % n].y };
|
|
4237
4247
|
return {
|
|
4238
|
-
length
|
|
4248
|
+
length,
|
|
4239
4249
|
pointAt(s) {
|
|
4240
4250
|
if (segs.length === 0) return start;
|
|
4241
4251
|
const { seg, t } = locate(s, false);
|
|
@@ -5189,17 +5199,13 @@ function pathThroughPoseFrame(path, pose) {
|
|
|
5189
5199
|
function anchorsUnderBrush(set, from, to, opts) {
|
|
5190
5200
|
const scale3 = opts.scale ?? { x: 1, y: 1 };
|
|
5191
5201
|
const ax = from.x * scale3.x, ay = from.y * scale3.y;
|
|
5192
|
-
const
|
|
5193
|
-
const len22 = dx2 * dx2 + dy2 * dy2;
|
|
5202
|
+
const bx = to.x * scale3.x, by = to.y * scale3.y;
|
|
5194
5203
|
const r2 = opts.radiusPx * opts.radiusPx;
|
|
5195
5204
|
const hits = [];
|
|
5196
5205
|
let flat = 0;
|
|
5197
5206
|
for (const sub3 of set.anchors) {
|
|
5198
5207
|
for (const a of sub3) {
|
|
5199
|
-
|
|
5200
|
-
const t = len22 === 0 ? 0 : Math.max(0, Math.min(1, (px * dx2 + py * dy2) / len22));
|
|
5201
|
-
const ex = px - t * dx2, ey = py - t * dy2;
|
|
5202
|
-
if (ex * ex + ey * ey <= r2) hits.push(flat);
|
|
5208
|
+
if (pointSegmentDist2(a.x * scale3.x, a.y * scale3.y, ax, ay, bx, by) <= r2) hits.push(flat);
|
|
5203
5209
|
flat++;
|
|
5204
5210
|
}
|
|
5205
5211
|
}
|
|
@@ -5321,8 +5327,8 @@ function bendSegment(set, grip, dx2, dy2) {
|
|
|
5321
5327
|
const aSmooth = isAnchorSmooth(a);
|
|
5322
5328
|
const bSmooth = isAnchorSmooth(b);
|
|
5323
5329
|
const straight = isStraightSegment(a, b);
|
|
5324
|
-
const p1 = a.outHandle ?? (straight ?
|
|
5325
|
-
const p2 = b.inHandle ?? (straight ?
|
|
5330
|
+
const p1 = a.outHandle ?? (straight ? lerpPoint(a, b, 1 / 3) : { x: a.x, y: a.y });
|
|
5331
|
+
const p2 = b.inHandle ?? (straight ? lerpPoint(a, b, 2 / 3) : { x: b.x, y: b.y });
|
|
5326
5332
|
const t = Math.min(1 - T_MARGIN, Math.max(T_MARGIN, grip.t));
|
|
5327
5333
|
const u = 1 - t;
|
|
5328
5334
|
const k = 1 / (3 * t * u * (u * u + t * t));
|
|
@@ -5332,9 +5338,6 @@ function bendSegment(set, grip, dx2, dy2) {
|
|
|
5332
5338
|
if (bSmooth) b.outHandle = alignedOpposite(b, b.inHandle, b.outHandle);
|
|
5333
5339
|
return true;
|
|
5334
5340
|
}
|
|
5335
|
-
function lerp(a, b, f) {
|
|
5336
|
-
return { x: a.x + (b.x - a.x) * f, y: a.y + (b.y - a.y) * f };
|
|
5337
|
-
}
|
|
5338
5341
|
function alignedOpposite(anchor, moved2, other2) {
|
|
5339
5342
|
const mx = moved2.x - anchor.x;
|
|
5340
5343
|
const my = moved2.y - anchor.y;
|
|
@@ -5483,10 +5486,10 @@ function same2(p, q) {
|
|
|
5483
5486
|
}
|
|
5484
5487
|
|
|
5485
5488
|
// src/paths/softSelection.ts
|
|
5486
|
-
function softFalloff(falloff,
|
|
5487
|
-
if (!(radius > 0) ||
|
|
5488
|
-
if (
|
|
5489
|
-
const u =
|
|
5489
|
+
function softFalloff(falloff, distance3, radius) {
|
|
5490
|
+
if (!(radius > 0) || distance3 >= radius) return 0;
|
|
5491
|
+
if (distance3 <= 0) return 1;
|
|
5492
|
+
const u = distance3 / radius;
|
|
5490
5493
|
switch (falloff) {
|
|
5491
5494
|
case "linear":
|
|
5492
5495
|
return 1 - u;
|
|
@@ -5581,7 +5584,7 @@ function softSelectionBand(measure2, set, selected, radius) {
|
|
|
5581
5584
|
sub3.segments.forEach((seg, i) => {
|
|
5582
5585
|
const c = segmentControls2(anchors, sub3.closed, i);
|
|
5583
5586
|
if (!c) return;
|
|
5584
|
-
const at2 = (t) => isStraight(c) ?
|
|
5587
|
+
const at2 = (t) => isStraight(c) ? lerpPoint(c[0], c[3], t) : cubicPointAt(c[0], c[1], c[2], c[3], t);
|
|
5585
5588
|
const steps = seg.lengths.length - 1;
|
|
5586
5589
|
for (let k = 0; k <= steps; k++) {
|
|
5587
5590
|
const len = seg.lengths[k];
|
|
@@ -5631,9 +5634,6 @@ function crossing2(a, b, aIn, inside) {
|
|
|
5631
5634
|
}
|
|
5632
5635
|
return (lo + hi) / 2;
|
|
5633
5636
|
}
|
|
5634
|
-
function lerp2(a, b, t) {
|
|
5635
|
-
return { x: a.x + (b.x - a.x) * t, y: a.y + (b.y - a.y) * t };
|
|
5636
|
-
}
|
|
5637
5637
|
|
|
5638
5638
|
// src/paths/balanceHandles.ts
|
|
5639
5639
|
function handleBalances(set) {
|
|
@@ -5661,7 +5661,7 @@ function segmentHandles(set, sub3, segIdx) {
|
|
|
5661
5661
|
if (!ends || isStraightSegment(ends.a, ends.b)) return null;
|
|
5662
5662
|
const { a, b } = ends;
|
|
5663
5663
|
if (!a.outHandle || !b.inHandle) return null;
|
|
5664
|
-
if (
|
|
5664
|
+
if (distance(a, a.outHandle) === 0 || distance(b, b.inHandle) === 0) return null;
|
|
5665
5665
|
return { a, b, from: a.outHandle, to: b.inHandle };
|
|
5666
5666
|
}
|
|
5667
5667
|
function scaleSegmentHandles(set, sub3, segIdx, factor, syms = []) {
|
|
@@ -5691,8 +5691,8 @@ function equalizeSegmentHandles(set, sub3, segIdx) {
|
|
|
5691
5691
|
const handles = segmentHandles(set, sub3, segIdx);
|
|
5692
5692
|
if (!handles) return false;
|
|
5693
5693
|
const { a, b, from, to } = handles;
|
|
5694
|
-
const lenA =
|
|
5695
|
-
const lenB =
|
|
5694
|
+
const lenA = distance(a, from);
|
|
5695
|
+
const lenB = distance(b, to);
|
|
5696
5696
|
const ua = { x: (from.x - a.x) / lenA, y: (from.y - a.y) / lenA };
|
|
5697
5697
|
const ub = { x: (to.x - b.x) / lenB, y: (to.y - b.y) / lenB };
|
|
5698
5698
|
const corner = rayCrossing(a, ua, b, ub);
|
|
@@ -5719,9 +5719,6 @@ function rayCrossing(p, u, q, v) {
|
|
|
5719
5719
|
const tb = (dx2 * u.y - dy2 * u.x) / den;
|
|
5720
5720
|
return ta > 0 && tb > 0 ? { ta, tb } : null;
|
|
5721
5721
|
}
|
|
5722
|
-
function length(a, b) {
|
|
5723
|
-
return Math.hypot(b.x - a.x, b.y - a.y);
|
|
5724
|
-
}
|
|
5725
5722
|
function scaledFrom(anchor, handle, k) {
|
|
5726
5723
|
return { x: anchor.x + (handle.x - anchor.x) * k, y: anchor.y + (handle.y - anchor.y) * k };
|
|
5727
5724
|
}
|
|
@@ -6917,10 +6914,10 @@ function handleOf(a, side) {
|
|
|
6917
6914
|
function handleTarget(a, h, part, entry) {
|
|
6918
6915
|
if (part === "X") return { x: apply2(h.x, entry), y: h.y };
|
|
6919
6916
|
if (part === "Y") return { x: h.x, y: apply2(h.y, entry) };
|
|
6920
|
-
const
|
|
6917
|
+
const length = Math.hypot(h.x - a.x, h.y - a.y);
|
|
6921
6918
|
const angle = angleOf(a, h);
|
|
6922
6919
|
const nextAngle = part === "Angle" ? apply2(angle, entry) : angle;
|
|
6923
|
-
const nextLength = part === "Length" ? Math.max(0, apply2(
|
|
6920
|
+
const nextLength = part === "Length" ? Math.max(0, apply2(length, entry)) : length;
|
|
6924
6921
|
const rad = nextAngle * Math.PI / 180;
|
|
6925
6922
|
return { x: a.x + Math.cos(rad) * nextLength, y: a.y - Math.sin(rad) * nextLength };
|
|
6926
6923
|
}
|
|
@@ -7020,6 +7017,6 @@ function typedArrayReplacer(_key, value) {
|
|
|
7020
7017
|
return tagTypedArray(value) ?? value;
|
|
7021
7018
|
}
|
|
7022
7019
|
|
|
7023
|
-
export { ANCHOR_FIELDS, CONSTRAINT_TOLERANCE, EASINGS, PATH_SNAP_KINDS, SPRING_PRESETS, TYPED_ARRAY_CONSTRUCTORS, ZOOM_FLOOR, addExtremaAnchors, anchorAt, anchorCount, anchorOriginsOf, anchorSymmetries, anchorSymmetry, anchorsBefore, anchorsInRect, anchorsUnderBrush, anchorsWhere, applyToPoint, arcShape, averageAnchorsAt, balanceFactorToward, bendAlongPath, bendSegment, bendSide, blendPaths, boxFrameOf, boxToBox, circlePath, clampRectWithin, closestOpenEnds, composePath, conflictingConstraints, constrainPathEdit, constrainPathsEdit, constraintAnchors, constraintApplies, constraintFits, convertSegments, cornerAnchors, createPathSnapIndex, cubicBezierEasing, cubicContoursToPath, decomposePath, deleteAnchorsAt, directionMarks, easeIn, easeInBack, easeInBounce, easeInCirc, easeInCubic, easeInElastic, easeInExpo, easeInOut, easeInOutBack, easeInOutBounce, easeInOutCirc, easeInOutCubic, easeInOutElastic, easeInOutExpo, easeInOutQuad, easeInOutQuart, easeInOutQuint, easeInOutSine, easeInQuad, easeInQuart, easeInQuint, easeInSine, easeLength, easeOut, easeOutBack, easeOutBounce, easeOutCirc, easeOutCubic, easeOutElastic, easeOutExpo, easeOutQuad, easeOutQuart, easeOutQuint, easeOutSine, editAnchorSet, editAnchorSetTracked, ellipseShape, equalizeSegmentHandles, everyNthAnchor, extendToMeet, extensionPieces, findPathSnap, findPathSnaps, fitAffine, fitCubicThroughDeletion, flatAnchorIndex, flatIndexesAfterReverse, growAnchorSelection, growRegion, handleAlongItsAngle, handleAtItsLength, handleBalances, harmonizeAnchors, hasOpenSubpath, identity, insertAnchorOnSegment, invert, invertAnchorSelection, isSegmentStraight, joinAnchorsAt, joinSubpathEnds, lengthToward, lengthenOpenEnd, lengthenPathEnd, lineShape, linear, locateAnchor, makeHandlesSymmetric, mapConstraintAnchors, mat3, meanScale, measureAnchorPath, measurePath, mergeRegion, moveHandleSymmetric, moveHandleTo, multiply, nearestPathAnchor, normalizeZoom, offsetCornerTraces, openEndAt, openEndRay, openPathEnds, openSubpathAt, pathAnchorPoints, pathAwayFromAnchors, pathContainsPoint, pathContainsPolygon, pathContainsRect, pathCrossings, pathDistanceToPoint, pathEndAnchorIndex, pathEndFrame, pathFromD, pathInPoseFrame, pathInWorld, pathIntersectsPolygon, pathIntersectsRect, pathSegments, pathShape, pathSignedArea, pathThroughPoseFrame, pathToCubicContours, pathToD, placeAlongRun, placeRect, pointAlongPath, pointInPath, polygonContainsPath, polygonIntersectsPath, portControls2 as portControls, portCurvePoints2 as portCurvePoints, poseFrameInverseOf, poseFrameOf, poseLinearOf, poseRotationOf, prepareBlend, puckerBloatPath, pxExtent, pxExtentInFrame, readAnchorFields, rectMarkerPath, remapAnchorValues, remapConstraints, remapPointValues, repeatAlongPath, resamplePath, resolveEasing, retractHandles, reverseAnchors, reversePath, reverseSubpaths, reviveTypedArrays, rotate, rotateAboutPoint, rotatePathAround, roughenPath, roundRectPath, runLength, runPlaces, runStationAt, scale, scaleDelta, scalePathToBounds, scaleSegmentHandles, screenAngleOf, segmentAt2 as segmentAt, segmentBetween, segmentExtremaTs, segmentsBetweenAnchors, setSubpathStart, shiftTrack, shrinkAnchorSelection, simplifyAnchorsAt, simplifyPath, simplifySpan, simplifySubpath, smoothAnchors, smudgePath, softFalloff, softSelectionBand, softSelectionWeights, solveConstraints, solvePathConstraints, splitByClosure, splitSubpaths, squarePath, standoff, stationsAlongPath, strokeHitTest, subpathEndAt, subpathsOfAnchors, tagTypedArray, tagTypedArrays, trackRun, trackShapeD, trackSlice, transformCoords, transformPath, translate, translateAnchorBy, translateAnchorsSymmetric, translatePath, trimPathAt, typedArrayReplacer, unionBoundsPath, unsatisfiedConstraints, untagTypedArray, viewToMat3, withAnchorPoints, withinPxBox, withinPxRadius, worldEditToStorage, writeAnchorField, zigzagPath };
|
|
7020
|
+
export { ANCHOR_FIELDS, CONSTRAINT_TOLERANCE, EASINGS, PATH_SNAP_KINDS, SPRING_PRESETS, TYPED_ARRAY_CONSTRUCTORS, ZOOM_FLOOR, addExtremaAnchors, anchorAt, anchorCount, anchorOriginsOf, anchorSymmetries, anchorSymmetry, anchorsBefore, anchorsInRect, anchorsUnderBrush, anchorsWhere, applyToPoint, arcShape, averageAnchorsAt, balanceFactorToward, bendAlongPath, bendSegment, bendSide, blendPaths, boxFrameOf, boxToBox, circlePath, clampRectWithin, closestOpenEnds, composePath, conflictingConstraints, constrainPathEdit, constrainPathsEdit, constraintAnchors, constraintApplies, constraintFits, convertSegments, cornerAnchors, createPathSnapIndex, cubicBezierEasing, cubicContoursToPath, decomposePath, deleteAnchorsAt, directionMarks, easeIn, easeInBack, easeInBounce, easeInCirc, easeInCubic, easeInElastic, easeInExpo, easeInOut, easeInOutBack, easeInOutBounce, easeInOutCirc, easeInOutCubic, easeInOutElastic, easeInOutExpo, easeInOutQuad, easeInOutQuart, easeInOutQuint, easeInOutSine, easeInQuad, easeInQuart, easeInQuint, easeInSine, easeLength, easeOut, easeOutBack, easeOutBounce, easeOutCirc, easeOutCubic, easeOutElastic, easeOutExpo, easeOutQuad, easeOutQuart, easeOutQuint, easeOutSine, editAnchorSet, editAnchorSetTracked, ellipseShape, equalizeSegmentHandles, everyNthAnchor, extendToMeet, extensionPieces, findPathSnap, findPathSnaps, fitAffine, fitCubicThroughDeletion, flatAnchorIndex, flatIndexesAfterReverse, growAnchorSelection, growRegion, handleAlongItsAngle, handleAtItsLength, handleBalances, harmonizeAnchors, hasOpenSubpath, identity, insertAnchorOnSegment, invert, invertAnchorSelection, isSegmentStraight, joinAnchorsAt, joinSubpathEnds, lengthToward, lengthenOpenEnd, lengthenPathEnd, lineShape, linear, locateAnchor, makeHandlesSymmetric, mapConstraintAnchors, mat3, meanScale, measureAnchorPath, measurePath, mergeRegion, moveHandleSymmetric, moveHandleTo, multiply, nearestPathAnchor, normalizeZoom, offsetCornerTraces, openEndAt, openEndRay, openPathEnds, openSubpathAt, pathAnchorPoints, pathAwayFromAnchors, pathContainsPoint, pathContainsPolygon, pathContainsRect, pathCrossings, pathDistanceToPoint, pathEndAnchorIndex, pathEndFrame, pathFromD, pathInPoseFrame, pathInWorld, pathIntersectsPolygon, pathIntersectsRect, pathSegments, pathShape, pathSignedArea, pathThroughPoseFrame, pathToCubicContours, pathToD, placeAlongRun, placeRect, pointAlongPath, pointInPath, polygonContainsPath, polygonIntersectsPath, portControls2 as portControls, portCurvePoints2 as portCurvePoints, poseFrameInverseOf, poseFrameOf, poseLinearOf, poseRotationOf, prepareBlend, puckerBloatPath, pxExtent, pxExtentInFrame, readAnchorFields, rectMarkerPath, remapAnchorValues, remapConstraints, remapPointValues, repeatAlongPath, resamplePath, resolveEasing, retractHandles, reverseAnchors, reversePath, reverseSubpaths, reviveTypedArrays, rotate, rotateAboutPoint, rotatePathAround, roughenPath, roundRectPath, runLength, runPlaces, runStationAt, scale, scaleDelta, scalePathToBounds, scaleSegmentHandles, screenAngleOf, segmentAt2 as segmentAt, segmentBetween, segmentExtremaTs, segmentsBetweenAnchors, setSubpathStart, shiftTrack, shrinkAnchorSelection, simplifyAnchorsAt, simplifyPath, simplifySpan, simplifySubpath, smoothAnchors, smudgePath, softFalloff, softSelectionBand, softSelectionWeights, solveConstraints, solvePathConstraints, splitByClosure, splitSubpaths, squarePath, standoff, stationsAlongPath, strokeHitTest, subpathEndAt, subpathsOfAnchors, tagTypedArray, tagTypedArrays, trackRun, trackShapeD, trackSlice, transformCoords, transformPath, translate, translateAnchorBy, translateAnchorsSymmetric, translatePath, trimPathAt, typedArrayReplacer, unionBoundsPath, unsatisfiedConstraints, untagTypedArray, viewRectToScreen, viewScreenToWorld, viewToMat3, viewWorldToScreen, withAnchorPoints, withinPxBox, withinPxRadius, worldEditToStorage, writeAnchorField, zigzagPath };
|
|
7024
7021
|
//# sourceMappingURL=index.js.map
|
|
7025
7022
|
//# sourceMappingURL=index.js.map
|