@weasel-js/core 1.4.4 → 1.5.1

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.
Files changed (58) hide show
  1. package/CHANGELOG.md +1295 -2197
  2. package/README.md +118 -75
  3. package/dist/autoPoseDescriptor-Dr6CwNZK.d.ts +26 -0
  4. package/dist/{chunk-WPM42WJP.js → chunk-3LPQ2XZG.js} +196 -406
  5. package/dist/chunk-3LPQ2XZG.js.map +1 -0
  6. package/dist/{chunk-R3AWPTLZ.js → chunk-GREL4MVO.js} +7593 -8533
  7. package/dist/chunk-GREL4MVO.js.map +1 -0
  8. package/dist/chunk-HAGOFNP5.js +162 -0
  9. package/dist/chunk-HAGOFNP5.js.map +1 -0
  10. package/dist/chunk-LXJDWBEL.js +318 -0
  11. package/dist/chunk-LXJDWBEL.js.map +1 -0
  12. package/dist/{chunk-2VXGHUVL.js → chunk-P6MGECVO.js} +4 -22
  13. package/dist/chunk-P6MGECVO.js.map +1 -0
  14. package/dist/{chunk-PRGBGMH3.js → chunk-XXQ6FLCJ.js} +3 -3
  15. package/dist/chunk-XXQ6FLCJ.js.map +1 -0
  16. package/dist/clipboard.d.ts +2 -3
  17. package/dist/clone.d.ts +3 -2
  18. package/dist/depSchema-BubKMv-2.d.ts +3479 -0
  19. package/dist/{grid-0Pbn5B2C.d.ts → grid-Z_Af3vTl.d.ts} +7 -10
  20. package/dist/index.d.ts +2588 -1556
  21. package/dist/index.js +6 -5
  22. package/dist/insert.d.ts +4 -4
  23. package/dist/insert.js +2 -1
  24. package/dist/insert.js.map +1 -1
  25. package/dist/math-E3rZn4bR.d.ts +282 -0
  26. package/dist/math.d.ts +5 -0
  27. package/dist/math.js +4 -0
  28. package/dist/math.js.map +1 -0
  29. package/dist/move.d.ts +5 -6
  30. package/dist/move.js +4 -6
  31. package/dist/move.js.map +1 -1
  32. package/dist/{options-DbYLImvq.d.ts → options-BPcmwYk7.d.ts} +3 -2
  33. package/dist/{autoPoseDescriptor-DF1SnnSx.d.ts → pointSnapToGrid-CgcK2R_I.d.ts} +11 -32
  34. package/dist/poseDescriptor-PgfVKfa0.d.ts +134 -0
  35. package/dist/renderer.d.ts +9 -4
  36. package/dist/renderer.js +6 -5
  37. package/dist/resize.d.ts +11 -12
  38. package/dist/resize.js +3 -2
  39. package/dist/routing.d.ts +1 -142
  40. package/dist/routing.js +1 -1
  41. package/dist/routing.js.map +1 -1
  42. package/dist/{types-ei3UMl9R.d.ts → types-BHGdrOcu.d.ts} +12 -41
  43. package/dist/{types-DEALFt5F.d.ts → types-BdaK9PcP.d.ts} +10 -4
  44. package/package.json +17 -10
  45. package/dist/DrawCommand-CD-ug3d9.d.ts +0 -332
  46. package/dist/builtins-BXFBXegF.d.ts +0 -840
  47. package/dist/chunk-2VXGHUVL.js.map +0 -1
  48. package/dist/chunk-BL65SHCX.js +0 -573
  49. package/dist/chunk-BL65SHCX.js.map +0 -1
  50. package/dist/chunk-PRGBGMH3.js.map +0 -1
  51. package/dist/chunk-R3AWPTLZ.js.map +0 -1
  52. package/dist/chunk-WPM42WJP.js.map +0 -1
  53. package/dist/geometry-6fCNhAux.d.ts +0 -114
  54. package/dist/path-JEV2c5If.d.ts +0 -48
  55. package/dist/registry-BY-wI9gm.d.ts +0 -4003
  56. package/dist/types-BHK2dkMu.d.ts +0 -172
  57. package/dist/types-bcc7jcUy.d.ts +0 -594
  58. package/dist/view-DSQgxBJB.d.ts +0 -63
@@ -1,52 +1,7 @@
1
- import { PATH_Z, PATH_Q, elevateQuadraticToCubic, cubicBounds, PATH_C, PATH_L, PATH_M, pointSegmentDist2, transformCoords, forEachSegment, pathCommandCoordCount, boxToBox } from '@weasel-js/geom';
2
- export { PATH_C, PATH_CMD_LENGTHS, PATH_L, PATH_M, PATH_Q, PATH_Z, pathCommandCoordCount } from '@weasel-js/geom';
1
+ import { forEachSegment, PATH_Z, PATH_Q, elevateQuadraticToCubic, cubicBounds, PATH_C, PATH_L, PATH_M, DEFAULT_FLATTEN_TOLERANCE, flattenQuadratic, flattenCubic, pointSegmentDist2, transformCoords, pathCommandCoordCount, boxToBox } from '@weasel-js/geom';
2
+ export { DEFAULT_FLATTEN_TOLERANCE, PATH_C, PATH_CMD_LENGTHS, PATH_L, PATH_M, PATH_Q, PATH_Z, flattenCubic, flattenCubicWithArcLen, flattenQuadratic, flattenQuadraticWithArcLen, pathCommandCoordCount } from '@weasel-js/geom';
3
3
 
4
- // src/core/units.ts
5
- function resolveUnit(v, unitSystem) {
6
- if (typeof v === "number") return v;
7
- if (!unitSystem) {
8
- throw new Error(
9
- `resolveUnit: tagged value { value: ${v.value}, unit: '${v.unit}' } requires a UnitSystem`
10
- );
11
- }
12
- const factor = unitSystem.units[v.unit];
13
- if (factor === void 0) {
14
- const known = Object.keys(unitSystem.units).join(", ") || "(none)";
15
- throw new Error(
16
- `resolveUnit: unknown unit '${v.unit}' (system base: '${unitSystem.base}', known units: ${known})`
17
- );
18
- }
19
- return v.value * factor;
20
- }
21
- function formatUnit(baseValue, displayUnit, unitSystem, opts) {
22
- const factor = unitSystem.units[displayUnit];
23
- if (factor === void 0) {
24
- const known = Object.keys(unitSystem.units).join(", ") || "(none)";
25
- throw new Error(
26
- `formatUnit: unknown unit '${displayUnit}' (system base: '${unitSystem.base}', known units: ${known})`
27
- );
28
- }
29
- const precision = opts?.precision ?? 2;
30
- const suffix = opts?.suffix ?? true;
31
- const display = baseValue / factor;
32
- let s = display.toFixed(precision);
33
- if (s.includes(".")) {
34
- s = s.replace(/0+$/, "").replace(/\.$/, "");
35
- }
36
- return suffix ? `${s}${displayUnit}` : s;
37
- }
38
- var IMPERIAL_INCHES = {
39
- base: "in",
40
- units: { in: 1, ft: 12, yd: 36, mi: 63360 }
41
- };
42
- var METRIC_MM = {
43
- base: "mm",
44
- units: { mm: 1, cm: 10, m: 1e3, km: 1e6 }
45
- };
46
- var PIXELS = {
47
- base: "px",
48
- units: { px: 1 }
49
- };
4
+ // src/core/geometry/path.ts
50
5
  function boundsOfPath(path) {
51
6
  if (path.kind === "rect") return path;
52
7
  const { commands, coords } = path;
@@ -54,9 +9,7 @@ function boundsOfPath(path) {
54
9
  return { kind: "rect", x: 0, y: 0, width: 0, height: 0 };
55
10
  }
56
11
  let minX = Infinity, minY = Infinity, maxX = -Infinity, maxY = -Infinity;
57
- let ci = 0;
58
12
  let seen = false;
59
- let px = 0, py = 0;
60
13
  const include = (x, y) => {
61
14
  if (x < minX) minX = x;
62
15
  if (x > maxX) maxX = x;
@@ -64,40 +17,34 @@ function boundsOfPath(path) {
64
17
  if (y > maxY) maxY = y;
65
18
  seen = true;
66
19
  };
67
- for (let i = 0; i < commands.length; i++) {
68
- const cmd = commands[i];
20
+ forEachSegment(commands, coords, (cmd, ci, px, py) => {
69
21
  switch (cmd) {
70
22
  case PATH_M:
71
23
  case PATH_L: {
72
- const x = coords[ci], y = coords[ci + 1];
73
- include(x, y);
74
- px = x;
75
- py = y;
76
- ci += 2;
24
+ include(coords[ci], coords[ci + 1]);
77
25
  break;
78
26
  }
79
27
  case PATH_C: {
80
- const x1 = coords[ci], y1 = coords[ci + 1];
81
- const x2 = coords[ci + 2], y2 = coords[ci + 3];
82
- const x3 = coords[ci + 4], y3 = coords[ci + 5];
83
- const [bMinX, bMinY, bMaxX, bMaxY] = cubicBounds(px, py, x1, y1, x2, y2, x3, y3);
28
+ const [bMinX, bMinY, bMaxX, bMaxY] = cubicBounds(
29
+ px,
30
+ py,
31
+ coords[ci],
32
+ coords[ci + 1],
33
+ coords[ci + 2],
34
+ coords[ci + 3],
35
+ coords[ci + 4],
36
+ coords[ci + 5]
37
+ );
84
38
  include(bMinX, bMinY);
85
39
  include(bMaxX, bMaxY);
86
- px = x3;
87
- py = y3;
88
- ci += 6;
89
40
  break;
90
41
  }
91
42
  case PATH_Q: {
92
- const qx1 = coords[ci], qy1 = coords[ci + 1];
93
43
  const qx2 = coords[ci + 2], qy2 = coords[ci + 3];
94
- const [c1x, c1y, c2x, c2y] = elevateQuadraticToCubic(px, py, qx1, qy1, qx2, qy2);
44
+ const [c1x, c1y, c2x, c2y] = elevateQuadraticToCubic(px, py, coords[ci], coords[ci + 1], qx2, qy2);
95
45
  const [bMinX, bMinY, bMaxX, bMaxY] = cubicBounds(px, py, c1x, c1y, c2x, c2y, qx2, qy2);
96
46
  include(bMinX, bMinY);
97
47
  include(bMaxX, bMaxY);
98
- px = qx2;
99
- py = qy2;
100
- ci += 4;
101
48
  break;
102
49
  }
103
50
  case PATH_Z:
@@ -105,133 +52,10 @@ function boundsOfPath(path) {
105
52
  default:
106
53
  throw new Error(`boundsOfPath: unknown command ${cmd}`);
107
54
  }
108
- }
55
+ });
109
56
  if (!seen) return { kind: "rect", x: 0, y: 0, width: 0, height: 0 };
110
57
  return { kind: "rect", x: minX, y: minY, width: maxX - minX, height: maxY - minY };
111
58
  }
112
-
113
- // src/features/paths/flatten.ts
114
- var DEFAULT_FLATTEN_TOLERANCE = 0.5;
115
- var MIN_FLATTEN_TOLERANCE = 1e-6;
116
- function usableTolerance(tolerance) {
117
- return tolerance > 0 ? tolerance : MIN_FLATTEN_TOLERANCE;
118
- }
119
- function finite6(a, b, c, d, e, f) {
120
- return Number.isFinite(a) && Number.isFinite(b) && Number.isFinite(c) && Number.isFinite(d) && Number.isFinite(e) && Number.isFinite(f);
121
- }
122
- function finite8(a, b, c, d, e, f, g, h) {
123
- return finite6(a, b, c, d, e, f) && Number.isFinite(g) && Number.isFinite(h);
124
- }
125
- function distPointToLine(px, py, ax, ay, bx, by) {
126
- const dx = bx - ax;
127
- const dy = by - ay;
128
- const len2 = dx * dx + dy * dy;
129
- if (len2 === 0) {
130
- const ex = px - ax;
131
- const ey = py - ay;
132
- return Math.sqrt(ex * ex + ey * ey);
133
- }
134
- const cross = (px - ax) * dy - (py - ay) * dx;
135
- return Math.abs(cross) / Math.sqrt(len2);
136
- }
137
- function flattenCubic(x0, y0, x1, y1, x2, y2, x3, y3, tolerance, out) {
138
- if (!finite8(x0, y0, x1, y1, x2, y2, x3, y3)) {
139
- out.push(x3, y3);
140
- return;
141
- }
142
- flattenCubicRec(x0, y0, x1, y1, x2, y2, x3, y3, usableTolerance(tolerance), out);
143
- }
144
- function flattenCubicRec(x0, y0, x1, y1, x2, y2, x3, y3, tolerance, out) {
145
- const d1 = distPointToLine(x1, y1, x0, y0, x3, y3);
146
- const d2 = distPointToLine(x2, y2, x0, y0, x3, y3);
147
- if (Math.max(d1, d2) <= tolerance) {
148
- out.push(x3, y3);
149
- return;
150
- }
151
- const x01 = (x0 + x1) * 0.5, y01 = (y0 + y1) * 0.5;
152
- const x12 = (x1 + x2) * 0.5, y12 = (y1 + y2) * 0.5;
153
- const x23 = (x2 + x3) * 0.5, y23 = (y2 + y3) * 0.5;
154
- const x012 = (x01 + x12) * 0.5, y012 = (y01 + y12) * 0.5;
155
- const x123 = (x12 + x23) * 0.5, y123 = (y12 + y23) * 0.5;
156
- const x0123 = (x012 + x123) * 0.5, y0123 = (y012 + y123) * 0.5;
157
- flattenCubicRec(x0, y0, x01, y01, x012, y012, x0123, y0123, tolerance, out);
158
- flattenCubicRec(x0123, y0123, x123, y123, x23, y23, x3, y3, tolerance, out);
159
- }
160
- function flattenQuadratic(x0, y0, x1, y1, x2, y2, tolerance, out) {
161
- if (!finite6(x0, y0, x1, y1, x2, y2)) {
162
- out.push(x2, y2);
163
- return;
164
- }
165
- flattenQuadraticRec(x0, y0, x1, y1, x2, y2, usableTolerance(tolerance), out);
166
- }
167
- function flattenQuadraticRec(x0, y0, x1, y1, x2, y2, tolerance, out) {
168
- const d = distPointToLine(x1, y1, x0, y0, x2, y2);
169
- if (d <= tolerance) {
170
- out.push(x2, y2);
171
- return;
172
- }
173
- const x01 = (x0 + x1) * 0.5, y01 = (y0 + y1) * 0.5;
174
- const x12 = (x1 + x2) * 0.5, y12 = (y1 + y2) * 0.5;
175
- const x012 = (x01 + x12) * 0.5, y012 = (y01 + y12) * 0.5;
176
- flattenQuadraticRec(x0, y0, x01, y01, x012, y012, tolerance, out);
177
- flattenQuadraticRec(x012, y012, x12, y12, x2, y2, tolerance, out);
178
- }
179
- function flattenCubicWithArcLen(x0, y0, x1, y1, x2, y2, x3, y3, tolerance, out, arcOut) {
180
- if (!finite8(x0, y0, x1, y1, x2, y2, x3, y3)) {
181
- out.push(x3, y3);
182
- arcOut.push(0);
183
- return 0;
184
- }
185
- return flattenCubicArcRec(x0, y0, x1, y1, x2, y2, x3, y3, usableTolerance(tolerance), out, arcOut, 0);
186
- }
187
- function flattenCubicArcRec(x0, y0, x1, y1, x2, y2, x3, y3, tolerance, out, arcOut, accum) {
188
- const d1 = distPointToLine(x1, y1, x0, y0, x3, y3);
189
- const d2 = distPointToLine(x2, y2, x0, y0, x3, y3);
190
- if (Math.max(d1, d2) <= tolerance) {
191
- const lastX = out.length >= 2 ? out[out.length - 2] : x0;
192
- const lastY = out.length >= 2 ? out[out.length - 1] : y0;
193
- const seg = Math.hypot(x3 - lastX, y3 - lastY);
194
- accum += seg;
195
- out.push(x3, y3);
196
- arcOut.push(accum);
197
- return accum;
198
- }
199
- const x01 = (x0 + x1) * 0.5, y01 = (y0 + y1) * 0.5;
200
- const x12 = (x1 + x2) * 0.5, y12 = (y1 + y2) * 0.5;
201
- const x23 = (x2 + x3) * 0.5, y23 = (y2 + y3) * 0.5;
202
- const x012 = (x01 + x12) * 0.5, y012 = (y01 + y12) * 0.5;
203
- const x123 = (x12 + x23) * 0.5, y123 = (y12 + y23) * 0.5;
204
- const x0123 = (x012 + x123) * 0.5, y0123 = (y012 + y123) * 0.5;
205
- accum = flattenCubicArcRec(x0, y0, x01, y01, x012, y012, x0123, y0123, tolerance, out, arcOut, accum);
206
- accum = flattenCubicArcRec(x0123, y0123, x123, y123, x23, y23, x3, y3, tolerance, out, arcOut, accum);
207
- return accum;
208
- }
209
- function flattenQuadraticWithArcLen(x0, y0, x1, y1, x2, y2, tolerance, out, arcOut) {
210
- if (!finite6(x0, y0, x1, y1, x2, y2)) {
211
- out.push(x2, y2);
212
- arcOut.push(0);
213
- return 0;
214
- }
215
- return flattenQuadraticArcRec(x0, y0, x1, y1, x2, y2, usableTolerance(tolerance), out, arcOut, 0);
216
- }
217
- function flattenQuadraticArcRec(x0, y0, x1, y1, x2, y2, tolerance, out, arcOut, accum) {
218
- const d = distPointToLine(x1, y1, x0, y0, x2, y2);
219
- if (d <= tolerance) {
220
- const lastX = out.length >= 2 ? out[out.length - 2] : x0;
221
- const lastY = out.length >= 2 ? out[out.length - 1] : y0;
222
- const seg = Math.hypot(x2 - lastX, y2 - lastY);
223
- accum += seg;
224
- out.push(x2, y2);
225
- arcOut.push(accum);
226
- return accum;
227
- }
228
- const x01 = (x0 + x1) * 0.5, y01 = (y0 + y1) * 0.5;
229
- const x12 = (x1 + x2) * 0.5, y12 = (y1 + y2) * 0.5;
230
- const x012 = (x01 + x12) * 0.5, y012 = (y01 + y12) * 0.5;
231
- accum = flattenQuadraticArcRec(x0, y0, x01, y01, x012, y012, tolerance, out, arcOut, accum);
232
- accum = flattenQuadraticArcRec(x012, y012, x12, y12, x2, y2, tolerance, out, arcOut, accum);
233
- return accum;
234
- }
235
59
  function pointInPath(path, x, y, opts = {}) {
236
60
  if (path.kind === "rect") {
237
61
  return x >= path.x && x <= path.x + path.width && y >= path.y && y <= path.y + path.height;
@@ -244,7 +68,6 @@ function pointInPolygonPath(path, x, y, tolerance) {
244
68
  let crossings = 0;
245
69
  let winding = 0;
246
70
  let subStartX = 0, subStartY = 0;
247
- let curX = 0, curY = 0;
248
71
  let subVerts = [];
249
72
  let subOpen = false;
250
73
  const flushSubpath = (closed) => {
@@ -263,57 +86,52 @@ function pointInPolygonPath(path, x, y, tolerance) {
263
86
  subVerts = [];
264
87
  subOpen = false;
265
88
  };
266
- let ci = 0;
267
- for (let i = 0; i < commands.length; i++) {
268
- const cmd = commands[i];
89
+ forEachSegment(commands, coords, (cmd, ci, curX, curY) => {
269
90
  switch (cmd) {
270
91
  case PATH_M: {
271
92
  if (subOpen) flushSubpath(false);
272
93
  subStartX = coords[ci];
273
94
  subStartY = coords[ci + 1];
274
- curX = subStartX;
275
- curY = subStartY;
276
- subVerts.push(curX, curY);
95
+ subVerts.push(subStartX, subStartY);
277
96
  subOpen = true;
278
- ci += 2;
279
97
  break;
280
98
  }
281
- case PATH_L: {
282
- curX = coords[ci];
283
- curY = coords[ci + 1];
284
- subVerts.push(curX, curY);
285
- ci += 2;
99
+ case PATH_L:
100
+ subVerts.push(coords[ci], coords[ci + 1]);
286
101
  break;
287
- }
288
- case PATH_C: {
289
- const x1 = coords[ci], y1 = coords[ci + 1];
290
- const x2 = coords[ci + 2], y2 = coords[ci + 3];
291
- const x3 = coords[ci + 4], y3 = coords[ci + 5];
292
- flattenCubic(curX, curY, x1, y1, x2, y2, x3, y3, tolerance, subVerts);
293
- curX = x3;
294
- curY = y3;
295
- ci += 6;
102
+ case PATH_C:
103
+ flattenCubic(
104
+ curX,
105
+ curY,
106
+ coords[ci],
107
+ coords[ci + 1],
108
+ coords[ci + 2],
109
+ coords[ci + 3],
110
+ coords[ci + 4],
111
+ coords[ci + 5],
112
+ tolerance,
113
+ subVerts
114
+ );
296
115
  break;
297
- }
298
- case PATH_Q: {
299
- const x1 = coords[ci], y1 = coords[ci + 1];
300
- const x2 = coords[ci + 2], y2 = coords[ci + 3];
301
- flattenQuadratic(curX, curY, x1, y1, x2, y2, tolerance, subVerts);
302
- curX = x2;
303
- curY = y2;
304
- ci += 4;
116
+ case PATH_Q:
117
+ flattenQuadratic(
118
+ curX,
119
+ curY,
120
+ coords[ci],
121
+ coords[ci + 1],
122
+ coords[ci + 2],
123
+ coords[ci + 3],
124
+ tolerance,
125
+ subVerts
126
+ );
305
127
  break;
306
- }
307
- case PATH_Z: {
128
+ case PATH_Z:
308
129
  flushSubpath(true);
309
- curX = subStartX;
310
- curY = subStartY;
311
130
  break;
312
- }
313
131
  default:
314
132
  throw new Error(`pointInPath: unknown command ${cmd}`);
315
133
  }
316
- }
134
+ });
317
135
  if (subOpen) flushSubpath(false);
318
136
  return fillRule === "evenodd" ? (crossings & 1) === 1 : winding !== 0;
319
137
  }
@@ -334,7 +152,6 @@ function polylineWithinThreshold(path, px, py, t2, tolerance) {
334
152
  const { commands, coords } = path;
335
153
  if (commands.length === 0) return false;
336
154
  let subStartX = 0, subStartY = 0;
337
- let curX = 0, curY = 0;
338
155
  let subVerts = [];
339
156
  let subOpen = false;
340
157
  const checkSegments = (closed) => {
@@ -346,62 +163,66 @@ function polylineWithinThreshold(path, px, py, t2, tolerance) {
346
163
  }
347
164
  return false;
348
165
  };
349
- let ci = 0;
350
- for (let i = 0; i < commands.length; i++) {
351
- const cmd = commands[i];
166
+ let hit = false;
167
+ forEachSegment(commands, coords, (cmd, ci, curX, curY) => {
352
168
  switch (cmd) {
353
169
  case PATH_M: {
354
170
  if (subOpen) {
355
- if (checkSegments(false)) return true;
171
+ if (checkSegments(false)) {
172
+ hit = true;
173
+ return false;
174
+ }
356
175
  subVerts = [];
357
176
  }
358
177
  subStartX = coords[ci];
359
178
  subStartY = coords[ci + 1];
360
- curX = subStartX;
361
- curY = subStartY;
362
- subVerts.push(curX, curY);
179
+ subVerts.push(subStartX, subStartY);
363
180
  subOpen = true;
364
- ci += 2;
365
181
  break;
366
182
  }
367
- case PATH_L: {
368
- curX = coords[ci];
369
- curY = coords[ci + 1];
370
- subVerts.push(curX, curY);
371
- ci += 2;
183
+ case PATH_L:
184
+ subVerts.push(coords[ci], coords[ci + 1]);
372
185
  break;
373
- }
374
- case PATH_C: {
375
- const x1 = coords[ci], y1 = coords[ci + 1];
376
- const x2 = coords[ci + 2], y2 = coords[ci + 3];
377
- const x3 = coords[ci + 4], y3 = coords[ci + 5];
378
- flattenCubic(curX, curY, x1, y1, x2, y2, x3, y3, tolerance, subVerts);
379
- curX = x3;
380
- curY = y3;
381
- ci += 6;
186
+ case PATH_C:
187
+ flattenCubic(
188
+ curX,
189
+ curY,
190
+ coords[ci],
191
+ coords[ci + 1],
192
+ coords[ci + 2],
193
+ coords[ci + 3],
194
+ coords[ci + 4],
195
+ coords[ci + 5],
196
+ tolerance,
197
+ subVerts
198
+ );
382
199
  break;
383
- }
384
- case PATH_Q: {
385
- const x1 = coords[ci], y1 = coords[ci + 1];
386
- const x2 = coords[ci + 2], y2 = coords[ci + 3];
387
- flattenQuadratic(curX, curY, x1, y1, x2, y2, tolerance, subVerts);
388
- curX = x2;
389
- curY = y2;
390
- ci += 4;
200
+ case PATH_Q:
201
+ flattenQuadratic(
202
+ curX,
203
+ curY,
204
+ coords[ci],
205
+ coords[ci + 1],
206
+ coords[ci + 2],
207
+ coords[ci + 3],
208
+ tolerance,
209
+ subVerts
210
+ );
391
211
  break;
392
- }
393
- case PATH_Z: {
394
- if (checkSegments(true)) return true;
212
+ case PATH_Z:
213
+ if (checkSegments(true)) {
214
+ hit = true;
215
+ return false;
216
+ }
395
217
  subVerts = [];
396
218
  subOpen = false;
397
- curX = subStartX;
398
- curY = subStartY;
399
219
  break;
400
- }
401
220
  default:
402
221
  throw new Error(`strokeHitTest: unknown command ${cmd}`);
403
222
  }
404
- }
223
+ return true;
224
+ });
225
+ if (hit) return true;
405
226
  if (subOpen && checkSegments(false)) return true;
406
227
  return false;
407
228
  }
@@ -609,7 +430,81 @@ function scalePolygon(path, src, dst) {
609
430
  return transformPath(path, m);
610
431
  }
611
432
 
612
- // src/interactions/actions/resize/geometry.ts
433
+ // src/core/geometry/unionBounds.ts
434
+ function unionBounds(poses) {
435
+ let minX = Infinity;
436
+ let minY = Infinity;
437
+ let maxX = -Infinity;
438
+ let maxY = -Infinity;
439
+ let any = false;
440
+ for (const p of poses) {
441
+ any = true;
442
+ if (p.x < minX) minX = p.x;
443
+ if (p.y < minY) minY = p.y;
444
+ const right = p.x + p.width;
445
+ const bottom = p.y + p.height;
446
+ if (right > maxX) maxX = right;
447
+ if (bottom > maxY) maxY = bottom;
448
+ }
449
+ if (!any) return null;
450
+ return { x: minX, y: minY, width: maxX - minX, height: maxY - minY };
451
+ }
452
+ function axisAlignedBounds(b) {
453
+ const rotation = b.rotation;
454
+ if (!rotation) {
455
+ return { x: b.x, y: b.y, width: b.width, height: b.height };
456
+ }
457
+ const cos = Math.cos(rotation);
458
+ const sin = Math.sin(rotation);
459
+ const cx = b.x + b.width / 2;
460
+ const cy = b.y + b.height / 2;
461
+ let minX = Infinity;
462
+ let minY = Infinity;
463
+ let maxX = -Infinity;
464
+ let maxY = -Infinity;
465
+ const corners = [
466
+ [b.x, b.y],
467
+ [b.x + b.width, b.y],
468
+ [b.x + b.width, b.y + b.height],
469
+ [b.x, b.y + b.height]
470
+ ];
471
+ for (const [px, py] of corners) {
472
+ const dx = px - cx;
473
+ const dy = py - cy;
474
+ const rx = cx + dx * cos - dy * sin;
475
+ const ry = cy + dx * sin + dy * cos;
476
+ if (rx < minX) minX = rx;
477
+ if (rx > maxX) maxX = rx;
478
+ if (ry < minY) minY = ry;
479
+ if (ry > maxY) maxY = ry;
480
+ }
481
+ return { x: minX, y: minY, width: maxX - minX, height: maxY - minY };
482
+ }
483
+ function unionAABB(parts) {
484
+ let minX = Infinity;
485
+ let minY = Infinity;
486
+ let maxX = -Infinity;
487
+ let maxY = -Infinity;
488
+ let any = false;
489
+ for (const part of parts) {
490
+ if (!part) continue;
491
+ const b = axisAlignedBounds(part);
492
+ any = true;
493
+ if (b.x < minX) minX = b.x;
494
+ if (b.y < minY) minY = b.y;
495
+ const right = b.x + b.width;
496
+ const bottom = b.y + b.height;
497
+ if (right > maxX) maxX = right;
498
+ if (bottom > maxY) maxY = bottom;
499
+ }
500
+ if (!any) return null;
501
+ return { x: minX, y: minY, width: maxX - minX, height: maxY - minY };
502
+ }
503
+
504
+ // src/core/geometry/poseDescriptor.ts
505
+ function poseDescriptorForNode(descriptor, node) {
506
+ return descriptor.forNode?.(node) ?? descriptor;
507
+ }
613
508
  function aabbIntersectsRect(b, r) {
614
509
  return b.x < r.x + r.width && b.x + b.width > r.x && b.y < r.y + r.height && b.y + b.height > r.y;
615
510
  }
@@ -626,6 +521,7 @@ var RECT_POSE_DESCRIPTOR = {
626
521
  height: p.height * sy
627
522
  };
628
523
  },
524
+ fromBounds: (b) => ({ x: b.x, y: b.y, width: b.width, height: b.height }),
629
525
  translate: (p, dx, dy) => ({ ...p, x: p.x + dx, y: p.y + dy }),
630
526
  intersectsRect: (p, r) => aabbIntersectsRect(p, r),
631
527
  lerp: (a, b, t) => ({
@@ -634,7 +530,8 @@ var RECT_POSE_DESCRIPTOR = {
634
530
  y: a.y + (b.y - a.y) * t,
635
531
  width: a.width + (b.width - a.width) * t,
636
532
  height: a.height + (b.height - a.height) * t
637
- })
533
+ }),
534
+ withRotation: (p, rotation) => ({ ...p, rotation })
638
535
  };
639
536
  var ROTATED_POSE_DESCRIPTOR = {
640
537
  getBounds: RECT_POSE_DESCRIPTOR.getBounds,
@@ -642,7 +539,9 @@ var ROTATED_POSE_DESCRIPTOR = {
642
539
  translate: RECT_POSE_DESCRIPTOR.translate,
643
540
  intersectsRect: RECT_POSE_DESCRIPTOR.intersectsRect,
644
541
  lerp: RECT_POSE_DESCRIPTOR.lerp,
645
- getRotation: (p) => p.rotation
542
+ fromBounds: (b) => ({ x: b.x, y: b.y, width: b.width, height: b.height, rotation: 0 }),
543
+ getRotation: (p) => p.rotation,
544
+ withRotation: (p, rotation) => ({ ...p, rotation })
646
545
  };
647
546
  function remapRotatedLeaf(pose, src, dst) {
648
547
  const sx = src.width === 0 ? 1 : dst.width / src.width;
@@ -666,22 +565,24 @@ function remapRotatedLeaf(pose, src, dst) {
666
565
  rotation
667
566
  };
668
567
  }
568
+ function visualBoundsViaDescriptor(pose, geometry) {
569
+ const b = geometry.getBounds(pose);
570
+ const rotation = geometry.getRotation?.(pose) ?? b.rotation ?? 0;
571
+ return axisAlignedBounds({ x: b.x, y: b.y, width: b.width, height: b.height, rotation });
572
+ }
573
+ function translatePoseViaDescriptor(pose, dx, dy, geometry) {
574
+ if (geometry.translate) return geometry.translate(pose, dx, dy);
575
+ const src = geometry.getBounds(pose);
576
+ const dst = { x: src.x + dx, y: src.y + dy, width: src.width, height: src.height };
577
+ return geometry.remapBounds(pose, src, dst);
578
+ }
669
579
  var pathPoseDescriptor = {
670
580
  getBounds: (path) => boundsOfPath(path),
671
- remapBounds: (path, src, dst) => {
672
- const sx = src.width === 0 ? 0 : dst.width / src.width;
673
- const sy = src.height === 0 ? 0 : dst.height / src.height;
674
- if (path.kind === "rect") {
675
- return {
676
- kind: "rect",
677
- x: dst.x + (path.x - src.x) * sx,
678
- y: dst.y + (path.y - src.y) * sy,
679
- width: path.width * sx,
680
- height: path.height * sy
681
- };
682
- }
683
- return remapPolygon(path, src, dst, sx, sy);
684
- },
581
+ remapBounds: (path, src, dst) => transformPath(
582
+ path,
583
+ boxToBox(src.x, src.y, src.width, src.height, dst.x, dst.y, dst.width, dst.height)
584
+ ),
585
+ fromBounds: (b) => ({ kind: "rect", x: b.x, y: b.y, width: b.width, height: b.height }),
685
586
  translate: (path, dx, dy) => translatePath(path, dx, dy),
686
587
  // WHY: AABB pre-test is cheap; only fall through to per-corner pointInPath
687
588
  // when the rect is fully inside the AABB (silhouette test).
@@ -718,25 +619,20 @@ var pathPoseDescriptor = {
718
619
  // so the rotate cursor doesn't appear without a working interaction.
719
620
  supportsRotation: () => false
720
621
  };
721
- function remapPolygon(path, src, dst, sx, sy) {
722
- const next = new Float32Array(path.coords.length);
723
- const { commands, coords } = path;
724
- forEachSegment(commands, coords, (cmd, ci) => {
725
- for (let k = 0, len = pathCommandCoordCount(cmd); k < len; k += 2) {
726
- next[ci + k] = dst.x + (coords[ci + k] - src.x) * sx;
727
- next[ci + k + 1] = dst.y + (coords[ci + k + 1] - src.y) * sy;
728
- }
729
- });
730
- return { kind: "polygon", commands: path.commands, coords: next, fillRule: path.fillRule };
731
- }
732
622
 
733
623
  // src/interactions/actions/resize/autoPoseDescriptor.ts
734
624
  function isPathLike(p) {
735
625
  return !!p && typeof p === "object" && "kind" in p && (p.kind === "polygon" || p.kind === "rect");
736
626
  }
627
+ function isRectPose(p) {
628
+ if (!p || typeof p !== "object") return false;
629
+ const r = p;
630
+ return typeof r.x === "number" && typeof r.y === "number" && typeof r.width === "number" && typeof r.height === "number";
631
+ }
737
632
  var AUTO_POSE_DESCRIPTOR = {
738
633
  getBounds: (p) => isPathLike(p) ? pathPoseDescriptor.getBounds(p) : RECT_POSE_DESCRIPTOR.getBounds(p),
739
634
  remapBounds: (p, src, dst) => isPathLike(p) ? pathPoseDescriptor.remapBounds(p, src, dst) : RECT_POSE_DESCRIPTOR.remapBounds(p, src, dst),
635
+ fromBounds: (b, template) => isPathLike(template) ? pathPoseDescriptor.fromBounds(b, template) : RECT_POSE_DESCRIPTOR.fromBounds(b, template),
740
636
  translate: (p, dx, dy) => isPathLike(p) ? pathPoseDescriptor.translate(p, dx, dy) : RECT_POSE_DESCRIPTOR.translate(p, dx, dy),
741
637
  intersectsRect: (p, rect) => isPathLike(p) ? pathPoseDescriptor.intersectsRect(p, rect) : RECT_POSE_DESCRIPTOR.intersectsRect(p, rect),
742
638
  getRotation: (p) => {
@@ -748,116 +644,10 @@ var AUTO_POSE_DESCRIPTOR = {
748
644
  // Everything else flows through `wrapWithPoseRotation`'s x/y/w/h gate at
749
645
  // paint time, so report `true` and let the wrapper no-op for poses
750
646
  // missing AABB fields.
751
- supportsRotation: (p) => !isPathLike(p)
752
- };
753
-
754
- // src/interactions/gestures/shared/strategies/grid.ts
755
- var RECT_ORIGIN_PROJECTION = {
756
- getOrigin: (p) => ({ x: p.x, y: p.y }),
757
- translate: (p, dx, dy) => ({ ...p, x: p.x + dx, y: p.y + dy })
758
- };
759
- var AUTO_ORIGIN_PROJECTION = {
760
- getOrigin: (p) => {
761
- if (isPathLike(p)) {
762
- const b = boundsOfPath(p);
763
- return { x: b.x, y: b.y };
764
- }
765
- const r = p;
766
- return { x: r.x, y: r.y };
767
- },
768
- translate: (p, dx, dy) => {
769
- if (isPathLike(p)) return translatePath(p, dx, dy);
770
- const r = p;
771
- return { ...r, x: r.x + dx, y: r.y + dy };
772
- }
647
+ supportsRotation: (p) => !isPathLike(p),
648
+ withRotation: (p, rotation) => isPathLike(p) ? p : { ...p, rotation }
773
649
  };
774
- function gridSnapStrategy(spacing, arg) {
775
- const isOpts = typeof arg === "object" && arg !== null && ("origin" in arg || "debug" in arg || "unitSystem" in arg) && !("base" in arg);
776
- const optsArg = isOpts ? arg : null;
777
- const unitSystem = optsArg ? optsArg.unitSystem : arg;
778
- const proj = optsArg && optsArg.origin ? optsArg.origin : AUTO_ORIGIN_PROJECTION;
779
- const debug = optsArg ? optsArg.debug : void 0;
780
- const c = resolveUnit(spacing, unitSystem);
781
- return {
782
- snap(pose) {
783
- const o = proj.getOrigin(pose);
784
- const sx = Math.round(o.x / c) * c;
785
- const sy = Math.round(o.y / c) * c;
786
- debug?.recordSnapCandidate({ x: sx, y: sy }, true);
787
- return proj.translate(pose, sx - o.x, sy - o.y);
788
- }
789
- };
790
- }
791
- function pointToGridCell(point, spacing, unitSystem, origin = { x: 0, y: 0 }) {
792
- const s = resolveUnit(spacing, unitSystem);
793
- return {
794
- col: Math.floor((point.x - origin.x) / s),
795
- row: Math.floor((point.y - origin.y) / s)
796
- };
797
- }
798
-
799
- // src/core/viewport/pxExtent.ts
800
- var MIN_SCALE = 1e-9;
801
- function pxExtent(px, scale) {
802
- return {
803
- x: px / Math.max(MIN_SCALE, Math.abs(scale.x)),
804
- y: px / Math.max(MIN_SCALE, Math.abs(scale.y))
805
- };
806
- }
807
- function scaleDelta(dx, dy, scale) {
808
- return { x: dx * scale.x, y: dy * scale.y };
809
- }
810
- function withinPxBox(dx, dy, px, scale) {
811
- const s = scaleDelta(dx, dy, scale);
812
- return Math.abs(s.x) <= px && Math.abs(s.y) <= px;
813
- }
814
- function withinPxRadius(dx, dy, px, scale) {
815
- const s = scaleDelta(dx, dy, scale);
816
- return s.x * s.x + s.y * s.y <= px * px;
817
- }
818
-
819
- // src/interactions/gestures/shared/strategies/guides.ts
820
- var DEFAULT_GUIDE_TOLERANCE_PX = 6;
821
- function guideSnapStrategy(getGuides, options = {}) {
822
- const tolerance = options.tolerance ?? DEFAULT_GUIDE_TOLERANCE_PX;
823
- const getView = options.getView;
824
- const proj = options.origin ?? RECT_ORIGIN_PROJECTION;
825
- return {
826
- snap(pose) {
827
- const guides = getGuides();
828
- if (guides.length === 0) return null;
829
- const tol = getView ? pxExtent(tolerance, getView().scale) : { x: tolerance, y: tolerance };
830
- const o = proj.getOrigin(pose);
831
- let bestDx = 0;
832
- let bestAbsDx = Infinity;
833
- let bestDy = 0;
834
- let bestAbsDy = Infinity;
835
- for (const g of guides) {
836
- if (g.axis === "x") {
837
- const d = g.offset - o.x;
838
- const ad = Math.abs(d);
839
- if (ad <= tol.x && ad < bestAbsDx) {
840
- bestAbsDx = ad;
841
- bestDx = d;
842
- }
843
- } else {
844
- const d = g.offset - o.y;
845
- const ad = Math.abs(d);
846
- if (ad <= tol.y && ad < bestAbsDy) {
847
- bestAbsDy = ad;
848
- bestDy = d;
849
- }
850
- }
851
- }
852
- if (bestAbsDx === Infinity && bestAbsDy === Infinity) return null;
853
- const dx = bestAbsDx === Infinity ? 0 : bestDx;
854
- const dy = bestAbsDy === Infinity ? 0 : bestDy;
855
- if (dx === 0 && dy === 0) return null;
856
- return proj.translate(pose, dx, dy);
857
- }
858
- };
859
- }
860
650
 
861
- export { AUTO_POSE_DESCRIPTOR, DEFAULT_FLATTEN_TOLERANCE, DEFAULT_GUIDE_TOLERANCE_PX, IMPERIAL_INCHES, METRIC_MM, PIXELS, PathBuilder, RECT_ORIGIN_PROJECTION, RECT_POSE_DESCRIPTOR, ROTATED_POSE_DESCRIPTOR, boundsOfPath, ellipsePath, flattenCubic, flattenCubicWithArcLen, flattenQuadratic, flattenQuadraticWithArcLen, formatUnit, gridSnapStrategy, guideSnapStrategy, isPathLike, linePath, pathPoseDescriptor, pointInPath, pointToGridCell, polygonFromPoints, polylineFromPoints, pxExtent, rectPath, regularPolygonPath, remapRotatedLeaf, resolveUnit, scaleDelta, scalePathToBounds, starPath, strokeHitTest, transformPath, translatePath, translatePolygonInPlace, withinPxBox, withinPxRadius };
862
- //# sourceMappingURL=chunk-WPM42WJP.js.map
863
- //# sourceMappingURL=chunk-WPM42WJP.js.map
651
+ export { AUTO_POSE_DESCRIPTOR, PathBuilder, RECT_POSE_DESCRIPTOR, ROTATED_POSE_DESCRIPTOR, aabbIntersectsRect, axisAlignedBounds, boundsOfPath, ellipsePath, isPathLike, isRectPose, linePath, pathPoseDescriptor, pointInPath, polygonFromPoints, polylineFromPoints, poseDescriptorForNode, rectPath, regularPolygonPath, remapRotatedLeaf, scalePathToBounds, starPath, strokeHitTest, transformPath, translatePath, translatePolygonInPlace, translatePoseViaDescriptor, unionAABB, unionBounds, visualBoundsViaDescriptor };
652
+ //# sourceMappingURL=chunk-3LPQ2XZG.js.map
653
+ //# sourceMappingURL=chunk-3LPQ2XZG.js.map