curvy 2.0.0-alpha.17 → 2.0.0-alpha.18

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 (74) hide show
  1. package/dist/arc/arc.d.ts +277 -0
  2. package/dist/arc/arc.internal.d.ts +2 -0
  3. package/dist/arc/index.d.ts +2 -0
  4. package/dist/arc/index.mjs +165 -0
  5. package/dist/arc/index.mjs.map +1 -0
  6. package/dist/characteristic/index.mjs +1 -1
  7. package/dist/coordinates/coordinateSystem.d.ts +686 -0
  8. package/dist/coordinates/coordinateSystem.internal.d.ts +2 -0
  9. package/dist/coordinates/dimension.d.ts +346 -0
  10. package/dist/coordinates/dimension.internal.d.ts +2 -0
  11. package/dist/coordinates/index.d.ts +6 -0
  12. package/dist/coordinates/index.mjs +656 -0
  13. package/dist/coordinates/index.mjs.map +1 -0
  14. package/dist/curve/cubic2d.d.ts +31 -0
  15. package/dist/curve/index.mjs +2 -2
  16. package/dist/interval/index.mjs +1 -1
  17. package/dist/matrix/index.mjs +2 -2
  18. package/dist/number.d.ts +140 -1
  19. package/dist/number.mjs +154 -2
  20. package/dist/number.mjs.map +1 -1
  21. package/dist/path/cubic2d.d.ts +44 -0
  22. package/dist/path/index.mjs +4 -3
  23. package/dist/path/rationalCubic2d.d.ts +10 -6
  24. package/dist/piecewise/index.mjs +8 -7
  25. package/dist/piecewise/index.mjs.map +1 -1
  26. package/dist/polynomial/index.mjs +2 -2
  27. package/dist/shared/{affine2d-CFfmB3LQ.mjs → affine2d-DUqbI9RP.mjs} +3 -3
  28. package/dist/shared/{affine2d-CFfmB3LQ.mjs.map → affine2d-DUqbI9RP.mjs.map} +1 -1
  29. package/dist/shared/arc.internal-DBLPlj56.mjs +138 -0
  30. package/dist/shared/arc.internal-DBLPlj56.mjs.map +1 -0
  31. package/dist/shared/{characteristic-CL3bnjgJ.mjs → characteristic-OjEkAZBA.mjs} +3 -3
  32. package/dist/shared/{characteristic-CL3bnjgJ.mjs.map → characteristic-OjEkAZBA.mjs.map} +1 -1
  33. package/dist/shared/{cubic-EPyClIq0.mjs → cubic-CddsJ7ek.mjs} +2 -2
  34. package/dist/shared/{cubic-EPyClIq0.mjs.map → cubic-CddsJ7ek.mjs.map} +1 -1
  35. package/dist/shared/{cubic2d-q1HU0uM9.mjs → cubic2d-B6OVwHqs.mjs} +67 -330
  36. package/dist/shared/cubic2d-B6OVwHqs.mjs.map +1 -0
  37. package/dist/shared/{cubic2d-CI82mN9o.mjs → cubic2d-CnREttj6.mjs} +42 -7
  38. package/dist/shared/cubic2d-CnREttj6.mjs.map +1 -0
  39. package/dist/shared/{interval2d-CVS66YmV.mjs → interval2d-BCabpCmV.mjs} +2 -2
  40. package/dist/shared/{interval2d-CVS66YmV.mjs.map → interval2d-BCabpCmV.mjs.map} +1 -1
  41. package/dist/shared/linear2d-B01Cuo06.mjs +326 -0
  42. package/dist/shared/linear2d-B01Cuo06.mjs.map +1 -0
  43. package/dist/shared/{matrix3x3.internal-eK-9vsoI.mjs → matrix3x3.internal-BW6BMirB.mjs} +3 -3
  44. package/dist/shared/{matrix3x3.internal-eK-9vsoI.mjs.map → matrix3x3.internal-BW6BMirB.mjs.map} +1 -1
  45. package/dist/shared/{matrix4x4-DCRpqQsP.mjs → matrix4x4-Cq_UJZNO.mjs} +2 -2
  46. package/dist/shared/{matrix4x4-DCRpqQsP.mjs.map → matrix4x4-Cq_UJZNO.mjs.map} +1 -1
  47. package/dist/shared/{quadratic-DY3a1MVJ.mjs → quadratic-CvvVVM5r.mjs} +2 -2
  48. package/dist/shared/{quadratic-DY3a1MVJ.mjs.map → quadratic-CvvVVM5r.mjs.map} +1 -1
  49. package/dist/shared/{quadratic2d-CXlMyyCs.mjs → quadratic2d-CdwZ28Rg.mjs} +3 -3
  50. package/dist/shared/{quadratic2d-CXlMyyCs.mjs.map → quadratic2d-CdwZ28Rg.mjs.map} +1 -1
  51. package/dist/shared/{rationalCubic2d-CGU2mYjs.mjs → rationalCubic2d-A7ZkG9_r.mjs} +5 -5
  52. package/dist/shared/{rationalCubic2d-CGU2mYjs.mjs.map → rationalCubic2d-A7ZkG9_r.mjs.map} +1 -1
  53. package/dist/shared/{rationalCubic2d-aT1o6oCm.mjs → rationalCubic2d-CXTogOPX.mjs} +12 -9
  54. package/dist/shared/rationalCubic2d-CXTogOPX.mjs.map +1 -0
  55. package/dist/shared/{vector2-CrUOYb3v.mjs → vector2-BzDphAEw.mjs} +9 -7
  56. package/dist/shared/vector2-BzDphAEw.mjs.map +1 -0
  57. package/dist/shared/{vector2.internal-rPnW0RCx.mjs → vector2.internal-B42hdbQr.mjs} +2 -2
  58. package/dist/shared/{vector2.internal-rPnW0RCx.mjs.map → vector2.internal-B42hdbQr.mjs.map} +1 -1
  59. package/dist/shared/{vector3-CFL7Yx16.mjs → vector3--DNTuqZ-.mjs} +7 -5
  60. package/dist/shared/vector3--DNTuqZ-.mjs.map +1 -0
  61. package/dist/shared/{vector3.internal-CfWHl9SG.mjs → vector3.internal-DRO121Di.mjs} +2 -2
  62. package/dist/shared/{vector3.internal-CfWHl9SG.mjs.map → vector3.internal-DRO121Di.mjs.map} +1 -1
  63. package/dist/splines/index.mjs +10 -9
  64. package/dist/splines/index.mjs.map +1 -1
  65. package/dist/transform/index.mjs +1 -1
  66. package/dist/vector/index.mjs +2 -2
  67. package/dist/vector/vector2.d.ts +7 -5
  68. package/dist/vector/vector3.d.ts +6 -4
  69. package/package.json +9 -1
  70. package/dist/shared/cubic2d-CI82mN9o.mjs.map +0 -1
  71. package/dist/shared/cubic2d-q1HU0uM9.mjs.map +0 -1
  72. package/dist/shared/rationalCubic2d-aT1o6oCm.mjs.map +0 -1
  73. package/dist/shared/vector2-CrUOYb3v.mjs.map +0 -1
  74. package/dist/shared/vector3-CFL7Yx16.mjs.map +0 -1
@@ -0,0 +1,277 @@
1
+ import type { Closed } from '../interval/interval.ts';
2
+ import type { Interval2d } from '../interval/interval2d.ts';
3
+ import type { RationalCubicPath2d } from '../path/rationalCubic2d.ts';
4
+ import type { Pipeable } from '../utils.ts';
5
+ import type { Vector2 } from '../vector/vector2.ts';
6
+ import type { ArcTypeId } from './arc.internal.ts';
7
+ /**
8
+ * A circular arc: the points `center + radius * (cos(a), sin(a))` for `a`
9
+ * running from `startAngle` to `startAngle + sweep`.
10
+ *
11
+ * An authoring representation, like the spline modules: describe the arc
12
+ * here, query its closed-form geometry (`solve`, `length`, `boundingBox`),
13
+ * and lower it with `toPath` for curve math or `toPathData` for SVG. The
14
+ * description keeps answers the lowered form loses — arc length and
15
+ * point-at-parameter are exact one-liners here and numeric iterations
16
+ * there.
17
+ *
18
+ * Angles are in radians, measured from the `+x` direction, positive
19
+ * rotating `+x` toward `+y` — clockwise in an SVG viewport's y-down
20
+ * coordinates. Direction and multiplicity live in the sweep's sign and
21
+ * magnitude: a negative sweep runs the other way, and a magnitude past
22
+ * `2 * pi` keeps going around the circle.
23
+ *
24
+ * All fields are readonly. No operation mutates an arc.
25
+ *
26
+ * @since 2.0.0
27
+ */
28
+ export interface Circular extends Pipeable {
29
+ readonly [ArcTypeId]: ArcTypeId;
30
+ readonly kind: 'circular';
31
+ /**
32
+ * The cartesian center of the circle the arc lies on.
33
+ */
34
+ readonly center: Vector2;
35
+ /**
36
+ * The circle's radius. Non-negative; `0` is a valid degenerate arc that
37
+ * never leaves `center`.
38
+ */
39
+ readonly radius: number;
40
+ /**
41
+ * The angle where the arc starts, in radians from the `+x` direction,
42
+ * positive rotating `+x` toward `+y`.
43
+ */
44
+ readonly startAngle: number;
45
+ /**
46
+ * The signed angular extent, in radians. Positive rotates `+x` toward
47
+ * `+y`; a magnitude past `2 * pi` traces the circle more than once.
48
+ */
49
+ readonly sweep: number;
50
+ }
51
+ /**
52
+ * Configuration for `circular`. Only `radius` is required; the defaults
53
+ * give a full circle around the origin.
54
+ *
55
+ * @since 2.0.0
56
+ */
57
+ export interface CircularConfig {
58
+ /**
59
+ * The cartesian center of the circle. Defaults to the origin.
60
+ */
61
+ readonly center?: Vector2;
62
+ /**
63
+ * The circle's radius. Must be finite and non-negative.
64
+ */
65
+ readonly radius: number;
66
+ /**
67
+ * The angle where the arc starts, in radians from the `+x` direction,
68
+ * positive rotating `+x` toward `+y`. Defaults to `0` (3 o'clock on
69
+ * screen).
70
+ */
71
+ readonly startAngle?: number;
72
+ /**
73
+ * The signed angular extent, in radians. Defaults to `2 * pi`, a full
74
+ * circle.
75
+ */
76
+ readonly sweep?: number;
77
+ }
78
+ /**
79
+ * Checks if a value is a `Circular` arc.
80
+ *
81
+ * @param v - The value to check.
82
+ * @returns `true` if the value is a `Circular` arc, `false` otherwise.
83
+ * @since 2.0.0
84
+ */
85
+ export declare const isCircular: (v: unknown) => v is Circular;
86
+ /**
87
+ * Creates a `Circular` arc.
88
+ *
89
+ * @param config - Center, radius, start angle, and sweep. Only `radius` is
90
+ * required; see `CircularConfig` for the defaults.
91
+ * @returns A new `Circular` arc.
92
+ * @throws `Error` when `radius` is negative, or when `radius`,
93
+ * `startAngle`, or `sweep` is not finite.
94
+ * @since 2.0.0
95
+ * @example
96
+ * ```ts
97
+ * // A quarter circle of radius 100 from 3 o'clock to 6 o'clock:
98
+ * const quarter = Arc.circular({ radius: 100, sweep: Math.PI / 2 })
99
+ *
100
+ * // Omitting sweep gives the full circle:
101
+ * const dial = Arc.circular({ center: Vector2.make(200, 200), radius: 80 })
102
+ * ```
103
+ */
104
+ export declare const circular: (config: CircularConfig) => Circular;
105
+ export declare const equals: {
106
+ /**
107
+ * Checks two `Circular` arcs for equality, field by field. Numeric
108
+ * fields compare within the tolerance of `coincident` from
109
+ * `curvy/number`.
110
+ *
111
+ * Comparison is structural, not geometric: two arcs tracing the same
112
+ * points from different descriptions — a start angle shifted by
113
+ * `2 * pi`, or the reverse direction — compare unequal.
114
+ *
115
+ * @param a - The first arc.
116
+ * @param b - The second arc.
117
+ * @returns `true` if the arcs are equal, `false` otherwise.
118
+ * @since 2.0.0
119
+ */
120
+ (a: Circular, b: Circular): boolean;
121
+ /**
122
+ * Checks two `Circular` arcs for equality.
123
+ *
124
+ * @param b - The arc to compare against.
125
+ * @returns A function that takes an arc and returns whether the two are
126
+ * equal.
127
+ * @since 2.0.0
128
+ */
129
+ (b: Circular): (a: Circular) => boolean;
130
+ };
131
+ /**
132
+ * Computes the point where the arc starts,
133
+ * `center + radius * (cos(startAngle), sin(startAngle))`.
134
+ *
135
+ * @param a - The arc.
136
+ * @returns The arc's first point.
137
+ * @since 2.0.0
138
+ */
139
+ export declare const startPoint: (a: Circular) => Vector2;
140
+ /**
141
+ * Computes the point where the arc ends, evaluated at
142
+ * `startAngle + sweep`.
143
+ *
144
+ * On a full-turn arc the result lands within rounding of `startPoint`,
145
+ * not bitwise on it — the trig re-evaluates a full period away. `toPathData`
146
+ * closes full circles on the exact starting coordinates instead.
147
+ *
148
+ * @param a - The arc.
149
+ * @returns The arc's last point.
150
+ * @since 2.0.0
151
+ */
152
+ export declare const endPoint: (a: Circular) => Vector2;
153
+ export declare const solve: {
154
+ /**
155
+ * Evaluates the arc at parameter `t`, the point at angle
156
+ * `startAngle + t * sweep`.
157
+ *
158
+ * The uniform parameter is also the arc-length parameter: equal steps
159
+ * in `t` cover equal distance along the arc, a property polynomial
160
+ * curves lack. `t` is not clamped — values outside `[0, 1]` continue
161
+ * around the circle.
162
+ *
163
+ * @param a - The arc to evaluate.
164
+ * @param t - The parameter. `0` is the start of the arc, `1` the end.
165
+ * @returns The point on the arc at parameter `t`.
166
+ * @since 2.0.0
167
+ * @example
168
+ * ```ts
169
+ * // The midpoint of a quarter arc sits at 45 degrees:
170
+ * Arc.solve(Arc.circular({ radius: 1, sweep: Math.PI / 2 }), 0.5)
171
+ * // (cos(pi / 4), sin(pi / 4))
172
+ * ```
173
+ */
174
+ (a: Circular, t: number): Vector2;
175
+ /**
176
+ * Evaluates the arc at parameter `t`.
177
+ *
178
+ * @param t - The parameter. `0` is the start of the arc, `1` the end.
179
+ * @returns A function that takes an arc and returns the point at `t`.
180
+ * @since 2.0.0
181
+ */
182
+ (t: number): (a: Circular) => Vector2;
183
+ };
184
+ /**
185
+ * Computes the arc's length, `radius * abs(sweep)`. Exact, in closed form
186
+ * — no tolerance parameter and no iteration, unlike arc length on a
187
+ * lowered path. A sweep past one full turn counts every traversal.
188
+ *
189
+ * @param a - The arc.
190
+ * @returns The length of the arc.
191
+ * @since 2.0.0
192
+ */
193
+ export declare const length: (a: Circular) => number;
194
+ /**
195
+ * Reverses the arc's direction: the same points traced the other way.
196
+ * The start angle moves to the far end and the sweep negates, so
197
+ * `solve(reverse(a), t)` is `solve(a, 1 - t)`.
198
+ *
199
+ * @param a - The arc.
200
+ * @returns A new `Circular` arc tracing the input backward.
201
+ * @since 2.0.0
202
+ */
203
+ export declare const reverse: (a: Circular) => Circular;
204
+ /**
205
+ * Computes the exact axis-aligned bounding box of the arc.
206
+ *
207
+ * Extremes occur only at the endpoints or where the arc crosses an axis
208
+ * direction (a multiple of `pi / 2`), so every side is evaluated in
209
+ * closed form — exact up to IEEE 754 rounding, with no tolerance
210
+ * parameter. Contrast `RationalCubicPath2d.boundingBox`, which is tight
211
+ * only to a tolerance you choose. A zero-radius arc's box collapses to
212
+ * `center`.
213
+ *
214
+ * @param a - The arc.
215
+ * @returns A closed `Interval2d` enclosing exactly the arc's points.
216
+ * @since 2.0.0
217
+ */
218
+ export declare const boundingBox: (a: Circular) => Interval2d<Closed, Closed>;
219
+ /**
220
+ * Constructs the arc as a `RationalCubicPath2d`, exact up to IEEE 754
221
+ * rounding — the same construction `CoordinateSystem.arc` uses: rational
222
+ * cubic segments of at most a quarter turn each, uniform in angle, with a
223
+ * sweep past one full turn tracing the circle more than once.
224
+ *
225
+ * The path is the form to transform: circles are not closed under affine
226
+ * maps, but rational cubics are, so lower first and apply
227
+ * `RationalCubicPath2d.transform` to the result.
228
+ *
229
+ * @param a - The arc.
230
+ * @returns The arc as a `RationalCubicPath2d`.
231
+ * @since 2.0.0
232
+ * @example
233
+ * ```ts
234
+ * // A quarter-turn fillet of radius 8 as one exact rational segment:
235
+ * const path = Arc.toPath(
236
+ * Arc.circular({
237
+ * center: Vector2.make(50, 50),
238
+ * radius: 8,
239
+ * startAngle: -Math.PI / 2,
240
+ * sweep: Math.PI / 2,
241
+ * }),
242
+ * )
243
+ * ```
244
+ */
245
+ export declare const toPath: (a: Circular) => RationalCubicPath2d;
246
+ /**
247
+ * Emits exact SVG path data for the arc, using `A` commands computed from
248
+ * the arc's description rather than recovered from curve coefficients.
249
+ * Pieces stay at or under a half turn, so the large-arc flag is always
250
+ * `0`; the sweep flag is `1` for a positive sweep, which renders
251
+ * clockwise in an SVG viewport's y-down coordinates.
252
+ *
253
+ * Degenerate contracts:
254
+ * - zero sweep, or radius `0`: an `M` command alone, which renders
255
+ * nothing
256
+ * - a full-turn sweep: the circle as two half-turn `A` commands, closing
257
+ * on the exact starting coordinates
258
+ * - a sweep past one full turn: clamped to one circle, where `toPath`
259
+ * keeps going around — SVG path data cannot express multiple laps
260
+ *
261
+ * @param a - The arc.
262
+ * @returns The SVG path data string.
263
+ * @since 2.0.0
264
+ * @example
265
+ * ```ts
266
+ * // d attribute for a gauge tick at 12 o'clock, ready for <path d={...}>:
267
+ * const d = Arc.toPathData(
268
+ * Arc.circular({
269
+ * center: Vector2.make(200, 200),
270
+ * radius: 120,
271
+ * startAngle: -Math.PI / 2,
272
+ * sweep: Math.PI / 6,
273
+ * }),
274
+ * )
275
+ * ```
276
+ */
277
+ export declare const toPathData: (a: Circular) => string;
@@ -0,0 +1,2 @@
1
+ export declare const ArcTypeId: unique symbol;
2
+ export type ArcTypeId = typeof ArcTypeId;
@@ -0,0 +1,2 @@
1
+ import * as ArcNs from './arc.ts';
2
+ export { ArcNs as Arc };
@@ -0,0 +1,165 @@
1
+ import { t as __exportAll } from "../shared/chunk-25Hzd3z8.mjs";
2
+ import { _ as toPathData$1, c as equals$1, d as length$1, g as toPath$1, h as startPoint$1, i as circular$1, l as isCircular$1, m as solve$1, p as reverse$1, r as boundingBox$1, s as endPoint$1 } from "../shared/arc.internal-DBLPlj56.mjs";
3
+ //#region src/arc/arc.ts
4
+ var arc_exports = /* @__PURE__ */ __exportAll({
5
+ boundingBox: () => boundingBox,
6
+ circular: () => circular,
7
+ endPoint: () => endPoint,
8
+ equals: () => equals,
9
+ isCircular: () => isCircular,
10
+ length: () => length,
11
+ reverse: () => reverse,
12
+ solve: () => solve,
13
+ startPoint: () => startPoint,
14
+ toPath: () => toPath,
15
+ toPathData: () => toPathData
16
+ });
17
+ /**
18
+ * Checks if a value is a `Circular` arc.
19
+ *
20
+ * @param v - The value to check.
21
+ * @returns `true` if the value is a `Circular` arc, `false` otherwise.
22
+ * @since 2.0.0
23
+ */
24
+ const isCircular = isCircular$1;
25
+ /**
26
+ * Creates a `Circular` arc.
27
+ *
28
+ * @param config - Center, radius, start angle, and sweep. Only `radius` is
29
+ * required; see `CircularConfig` for the defaults.
30
+ * @returns A new `Circular` arc.
31
+ * @throws `Error` when `radius` is negative, or when `radius`,
32
+ * `startAngle`, or `sweep` is not finite.
33
+ * @since 2.0.0
34
+ * @example
35
+ * ```ts
36
+ * // A quarter circle of radius 100 from 3 o'clock to 6 o'clock:
37
+ * const quarter = Arc.circular({ radius: 100, sweep: Math.PI / 2 })
38
+ *
39
+ * // Omitting sweep gives the full circle:
40
+ * const dial = Arc.circular({ center: Vector2.make(200, 200), radius: 80 })
41
+ * ```
42
+ */
43
+ const circular = circular$1;
44
+ const equals = equals$1;
45
+ /**
46
+ * Computes the point where the arc starts,
47
+ * `center + radius * (cos(startAngle), sin(startAngle))`.
48
+ *
49
+ * @param a - The arc.
50
+ * @returns The arc's first point.
51
+ * @since 2.0.0
52
+ */
53
+ const startPoint = startPoint$1;
54
+ /**
55
+ * Computes the point where the arc ends, evaluated at
56
+ * `startAngle + sweep`.
57
+ *
58
+ * On a full-turn arc the result lands within rounding of `startPoint`,
59
+ * not bitwise on it — the trig re-evaluates a full period away. `toPathData`
60
+ * closes full circles on the exact starting coordinates instead.
61
+ *
62
+ * @param a - The arc.
63
+ * @returns The arc's last point.
64
+ * @since 2.0.0
65
+ */
66
+ const endPoint = endPoint$1;
67
+ const solve = solve$1;
68
+ /**
69
+ * Computes the arc's length, `radius * abs(sweep)`. Exact, in closed form
70
+ * — no tolerance parameter and no iteration, unlike arc length on a
71
+ * lowered path. A sweep past one full turn counts every traversal.
72
+ *
73
+ * @param a - The arc.
74
+ * @returns The length of the arc.
75
+ * @since 2.0.0
76
+ */
77
+ const length = length$1;
78
+ /**
79
+ * Reverses the arc's direction: the same points traced the other way.
80
+ * The start angle moves to the far end and the sweep negates, so
81
+ * `solve(reverse(a), t)` is `solve(a, 1 - t)`.
82
+ *
83
+ * @param a - The arc.
84
+ * @returns A new `Circular` arc tracing the input backward.
85
+ * @since 2.0.0
86
+ */
87
+ const reverse = reverse$1;
88
+ /**
89
+ * Computes the exact axis-aligned bounding box of the arc.
90
+ *
91
+ * Extremes occur only at the endpoints or where the arc crosses an axis
92
+ * direction (a multiple of `pi / 2`), so every side is evaluated in
93
+ * closed form — exact up to IEEE 754 rounding, with no tolerance
94
+ * parameter. Contrast `RationalCubicPath2d.boundingBox`, which is tight
95
+ * only to a tolerance you choose. A zero-radius arc's box collapses to
96
+ * `center`.
97
+ *
98
+ * @param a - The arc.
99
+ * @returns A closed `Interval2d` enclosing exactly the arc's points.
100
+ * @since 2.0.0
101
+ */
102
+ const boundingBox = boundingBox$1;
103
+ /**
104
+ * Constructs the arc as a `RationalCubicPath2d`, exact up to IEEE 754
105
+ * rounding — the same construction `CoordinateSystem.arc` uses: rational
106
+ * cubic segments of at most a quarter turn each, uniform in angle, with a
107
+ * sweep past one full turn tracing the circle more than once.
108
+ *
109
+ * The path is the form to transform: circles are not closed under affine
110
+ * maps, but rational cubics are, so lower first and apply
111
+ * `RationalCubicPath2d.transform` to the result.
112
+ *
113
+ * @param a - The arc.
114
+ * @returns The arc as a `RationalCubicPath2d`.
115
+ * @since 2.0.0
116
+ * @example
117
+ * ```ts
118
+ * // A quarter-turn fillet of radius 8 as one exact rational segment:
119
+ * const path = Arc.toPath(
120
+ * Arc.circular({
121
+ * center: Vector2.make(50, 50),
122
+ * radius: 8,
123
+ * startAngle: -Math.PI / 2,
124
+ * sweep: Math.PI / 2,
125
+ * }),
126
+ * )
127
+ * ```
128
+ */
129
+ const toPath = toPath$1;
130
+ /**
131
+ * Emits exact SVG path data for the arc, using `A` commands computed from
132
+ * the arc's description rather than recovered from curve coefficients.
133
+ * Pieces stay at or under a half turn, so the large-arc flag is always
134
+ * `0`; the sweep flag is `1` for a positive sweep, which renders
135
+ * clockwise in an SVG viewport's y-down coordinates.
136
+ *
137
+ * Degenerate contracts:
138
+ * - zero sweep, or radius `0`: an `M` command alone, which renders
139
+ * nothing
140
+ * - a full-turn sweep: the circle as two half-turn `A` commands, closing
141
+ * on the exact starting coordinates
142
+ * - a sweep past one full turn: clamped to one circle, where `toPath`
143
+ * keeps going around — SVG path data cannot express multiple laps
144
+ *
145
+ * @param a - The arc.
146
+ * @returns The SVG path data string.
147
+ * @since 2.0.0
148
+ * @example
149
+ * ```ts
150
+ * // d attribute for a gauge tick at 12 o'clock, ready for <path d={...}>:
151
+ * const d = Arc.toPathData(
152
+ * Arc.circular({
153
+ * center: Vector2.make(200, 200),
154
+ * radius: 120,
155
+ * startAngle: -Math.PI / 2,
156
+ * sweep: Math.PI / 6,
157
+ * }),
158
+ * )
159
+ * ```
160
+ */
161
+ const toPathData = toPathData$1;
162
+ //#endregion
163
+ export { arc_exports as Arc };
164
+
165
+ //# sourceMappingURL=index.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.mjs","names":["internal.isCircular","internal.circular","internal.equals","internal.startPoint","internal.endPoint","internal.solve","internal.length","internal.reverse","internal.boundingBox","internal.toPath","internal.toPathData"],"sources":["../../src/arc/arc.ts"],"sourcesContent":["import type { Closed } from '../interval/interval.ts'\nimport type { Interval2d } from '../interval/interval2d.ts'\nimport type { RationalCubicPath2d } from '../path/rationalCubic2d.ts'\nimport type { Pipeable } from '../utils.ts'\nimport type { Vector2 } from '../vector/vector2.ts'\nimport type { ArcTypeId } from './arc.internal.ts'\nimport * as internal from './arc.internal.ts'\n\n/**\n * A circular arc: the points `center + radius * (cos(a), sin(a))` for `a`\n * running from `startAngle` to `startAngle + sweep`.\n *\n * An authoring representation, like the spline modules: describe the arc\n * here, query its closed-form geometry (`solve`, `length`, `boundingBox`),\n * and lower it with `toPath` for curve math or `toPathData` for SVG. The\n * description keeps answers the lowered form loses — arc length and\n * point-at-parameter are exact one-liners here and numeric iterations\n * there.\n *\n * Angles are in radians, measured from the `+x` direction, positive\n * rotating `+x` toward `+y` — clockwise in an SVG viewport's y-down\n * coordinates. Direction and multiplicity live in the sweep's sign and\n * magnitude: a negative sweep runs the other way, and a magnitude past\n * `2 * pi` keeps going around the circle.\n *\n * All fields are readonly. No operation mutates an arc.\n *\n * @since 2.0.0\n */\nexport interface Circular extends Pipeable {\n readonly [ArcTypeId]: ArcTypeId\n readonly kind: 'circular'\n /**\n * The cartesian center of the circle the arc lies on.\n */\n readonly center: Vector2\n /**\n * The circle's radius. Non-negative; `0` is a valid degenerate arc that\n * never leaves `center`.\n */\n readonly radius: number\n /**\n * The angle where the arc starts, in radians from the `+x` direction,\n * positive rotating `+x` toward `+y`.\n */\n readonly startAngle: number\n /**\n * The signed angular extent, in radians. Positive rotates `+x` toward\n * `+y`; a magnitude past `2 * pi` traces the circle more than once.\n */\n readonly sweep: number\n}\n\n/**\n * Configuration for `circular`. Only `radius` is required; the defaults\n * give a full circle around the origin.\n *\n * @since 2.0.0\n */\nexport interface CircularConfig {\n /**\n * The cartesian center of the circle. Defaults to the origin.\n */\n readonly center?: Vector2\n /**\n * The circle's radius. Must be finite and non-negative.\n */\n readonly radius: number\n /**\n * The angle where the arc starts, in radians from the `+x` direction,\n * positive rotating `+x` toward `+y`. Defaults to `0` (3 o'clock on\n * screen).\n */\n readonly startAngle?: number\n /**\n * The signed angular extent, in radians. Defaults to `2 * pi`, a full\n * circle.\n */\n readonly sweep?: number\n}\n\n/**\n * Checks if a value is a `Circular` arc.\n *\n * @param v - The value to check.\n * @returns `true` if the value is a `Circular` arc, `false` otherwise.\n * @since 2.0.0\n */\nexport const isCircular: (v: unknown) => v is Circular = internal.isCircular\n\n/**\n * Creates a `Circular` arc.\n *\n * @param config - Center, radius, start angle, and sweep. Only `radius` is\n * required; see `CircularConfig` for the defaults.\n * @returns A new `Circular` arc.\n * @throws `Error` when `radius` is negative, or when `radius`,\n * `startAngle`, or `sweep` is not finite.\n * @since 2.0.0\n * @example\n * ```ts\n * // A quarter circle of radius 100 from 3 o'clock to 6 o'clock:\n * const quarter = Arc.circular({ radius: 100, sweep: Math.PI / 2 })\n *\n * // Omitting sweep gives the full circle:\n * const dial = Arc.circular({ center: Vector2.make(200, 200), radius: 80 })\n * ```\n */\nexport const circular: (config: CircularConfig) => Circular = internal.circular\n\nexport const equals: {\n /**\n * Checks two `Circular` arcs for equality, field by field. Numeric\n * fields compare within the tolerance of `coincident` from\n * `curvy/number`.\n *\n * Comparison is structural, not geometric: two arcs tracing the same\n * points from different descriptions — a start angle shifted by\n * `2 * pi`, or the reverse direction — compare unequal.\n *\n * @param a - The first arc.\n * @param b - The second arc.\n * @returns `true` if the arcs are equal, `false` otherwise.\n * @since 2.0.0\n */\n (a: Circular, b: Circular): boolean\n /**\n * Checks two `Circular` arcs for equality.\n *\n * @param b - The arc to compare against.\n * @returns A function that takes an arc and returns whether the two are\n * equal.\n * @since 2.0.0\n */\n (b: Circular): (a: Circular) => boolean\n} = internal.equals\n\n/**\n * Computes the point where the arc starts,\n * `center + radius * (cos(startAngle), sin(startAngle))`.\n *\n * @param a - The arc.\n * @returns The arc's first point.\n * @since 2.0.0\n */\nexport const startPoint: (a: Circular) => Vector2 = internal.startPoint\n\n/**\n * Computes the point where the arc ends, evaluated at\n * `startAngle + sweep`.\n *\n * On a full-turn arc the result lands within rounding of `startPoint`,\n * not bitwise on it — the trig re-evaluates a full period away. `toPathData`\n * closes full circles on the exact starting coordinates instead.\n *\n * @param a - The arc.\n * @returns The arc's last point.\n * @since 2.0.0\n */\nexport const endPoint: (a: Circular) => Vector2 = internal.endPoint\n\nexport const solve: {\n /**\n * Evaluates the arc at parameter `t`, the point at angle\n * `startAngle + t * sweep`.\n *\n * The uniform parameter is also the arc-length parameter: equal steps\n * in `t` cover equal distance along the arc, a property polynomial\n * curves lack. `t` is not clamped — values outside `[0, 1]` continue\n * around the circle.\n *\n * @param a - The arc to evaluate.\n * @param t - The parameter. `0` is the start of the arc, `1` the end.\n * @returns The point on the arc at parameter `t`.\n * @since 2.0.0\n * @example\n * ```ts\n * // The midpoint of a quarter arc sits at 45 degrees:\n * Arc.solve(Arc.circular({ radius: 1, sweep: Math.PI / 2 }), 0.5)\n * // (cos(pi / 4), sin(pi / 4))\n * ```\n */\n (a: Circular, t: number): Vector2\n /**\n * Evaluates the arc at parameter `t`.\n *\n * @param t - The parameter. `0` is the start of the arc, `1` the end.\n * @returns A function that takes an arc and returns the point at `t`.\n * @since 2.0.0\n */\n (t: number): (a: Circular) => Vector2\n} = internal.solve\n\n/**\n * Computes the arc's length, `radius * abs(sweep)`. Exact, in closed form\n * — no tolerance parameter and no iteration, unlike arc length on a\n * lowered path. A sweep past one full turn counts every traversal.\n *\n * @param a - The arc.\n * @returns The length of the arc.\n * @since 2.0.0\n */\nexport const length: (a: Circular) => number = internal.length\n\n/**\n * Reverses the arc's direction: the same points traced the other way.\n * The start angle moves to the far end and the sweep negates, so\n * `solve(reverse(a), t)` is `solve(a, 1 - t)`.\n *\n * @param a - The arc.\n * @returns A new `Circular` arc tracing the input backward.\n * @since 2.0.0\n */\nexport const reverse: (a: Circular) => Circular = internal.reverse\n\n/**\n * Computes the exact axis-aligned bounding box of the arc.\n *\n * Extremes occur only at the endpoints or where the arc crosses an axis\n * direction (a multiple of `pi / 2`), so every side is evaluated in\n * closed form — exact up to IEEE 754 rounding, with no tolerance\n * parameter. Contrast `RationalCubicPath2d.boundingBox`, which is tight\n * only to a tolerance you choose. A zero-radius arc's box collapses to\n * `center`.\n *\n * @param a - The arc.\n * @returns A closed `Interval2d` enclosing exactly the arc's points.\n * @since 2.0.0\n */\nexport const boundingBox: (a: Circular) => Interval2d<Closed, Closed> = internal.boundingBox\n\n/**\n * Constructs the arc as a `RationalCubicPath2d`, exact up to IEEE 754\n * rounding — the same construction `CoordinateSystem.arc` uses: rational\n * cubic segments of at most a quarter turn each, uniform in angle, with a\n * sweep past one full turn tracing the circle more than once.\n *\n * The path is the form to transform: circles are not closed under affine\n * maps, but rational cubics are, so lower first and apply\n * `RationalCubicPath2d.transform` to the result.\n *\n * @param a - The arc.\n * @returns The arc as a `RationalCubicPath2d`.\n * @since 2.0.0\n * @example\n * ```ts\n * // A quarter-turn fillet of radius 8 as one exact rational segment:\n * const path = Arc.toPath(\n * Arc.circular({\n * center: Vector2.make(50, 50),\n * radius: 8,\n * startAngle: -Math.PI / 2,\n * sweep: Math.PI / 2,\n * }),\n * )\n * ```\n */\nexport const toPath: (a: Circular) => RationalCubicPath2d = internal.toPath\n\n/**\n * Emits exact SVG path data for the arc, using `A` commands computed from\n * the arc's description rather than recovered from curve coefficients.\n * Pieces stay at or under a half turn, so the large-arc flag is always\n * `0`; the sweep flag is `1` for a positive sweep, which renders\n * clockwise in an SVG viewport's y-down coordinates.\n *\n * Degenerate contracts:\n * - zero sweep, or radius `0`: an `M` command alone, which renders\n * nothing\n * - a full-turn sweep: the circle as two half-turn `A` commands, closing\n * on the exact starting coordinates\n * - a sweep past one full turn: clamped to one circle, where `toPath`\n * keeps going around — SVG path data cannot express multiple laps\n *\n * @param a - The arc.\n * @returns The SVG path data string.\n * @since 2.0.0\n * @example\n * ```ts\n * // d attribute for a gauge tick at 12 o'clock, ready for <path d={...}>:\n * const d = Arc.toPathData(\n * Arc.circular({\n * center: Vector2.make(200, 200),\n * radius: 120,\n * startAngle: -Math.PI / 2,\n * sweep: Math.PI / 6,\n * }),\n * )\n * ```\n */\nexport const toPathData: (a: Circular) => string = internal.toPathData\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;AAwFA,MAAa,aAA4CA;;;;;;;;;;;;;;;;;;;AAoBzD,MAAa,WAAiDC;AAE9D,MAAa,SAyBTC;;;;;;;;;AAUJ,MAAa,aAAuCC;;;;;;;;;;;;;AAcpD,MAAa,WAAqCC;AAElD,MAAa,QA8BTC;;;;;;;;;;AAWJ,MAAa,SAAkCC;;;;;;;;;;AAW/C,MAAa,UAAqCC;;;;;;;;;;;;;;;AAgBlD,MAAa,cAA2DC;;;;;;;;;;;;;;;;;;;;;;;;;;;AA4BxE,MAAa,SAA+CC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAiC5D,MAAa,aAAsCC"}
@@ -1,2 +1,2 @@
1
- import { n as characteristic_exports } from "../shared/characteristic-CL3bnjgJ.mjs";
1
+ import { n as characteristic_exports } from "../shared/characteristic-OjEkAZBA.mjs";
2
2
  export { characteristic_exports as Characteristic };