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.
- package/dist/arc/arc.d.ts +277 -0
- package/dist/arc/arc.internal.d.ts +2 -0
- package/dist/arc/index.d.ts +2 -0
- package/dist/arc/index.mjs +165 -0
- package/dist/arc/index.mjs.map +1 -0
- package/dist/characteristic/index.mjs +1 -1
- package/dist/coordinates/coordinateSystem.d.ts +686 -0
- package/dist/coordinates/coordinateSystem.internal.d.ts +2 -0
- package/dist/coordinates/dimension.d.ts +346 -0
- package/dist/coordinates/dimension.internal.d.ts +2 -0
- package/dist/coordinates/index.d.ts +6 -0
- package/dist/coordinates/index.mjs +656 -0
- package/dist/coordinates/index.mjs.map +1 -0
- package/dist/curve/cubic2d.d.ts +31 -0
- package/dist/curve/index.mjs +2 -2
- package/dist/interval/index.mjs +1 -1
- package/dist/matrix/index.mjs +2 -2
- package/dist/number.d.ts +140 -1
- package/dist/number.mjs +154 -2
- package/dist/number.mjs.map +1 -1
- package/dist/path/cubic2d.d.ts +44 -0
- package/dist/path/index.mjs +4 -3
- package/dist/path/rationalCubic2d.d.ts +10 -6
- package/dist/piecewise/index.mjs +8 -7
- package/dist/piecewise/index.mjs.map +1 -1
- package/dist/polynomial/index.mjs +2 -2
- package/dist/shared/{affine2d-CFfmB3LQ.mjs → affine2d-DUqbI9RP.mjs} +3 -3
- package/dist/shared/{affine2d-CFfmB3LQ.mjs.map → affine2d-DUqbI9RP.mjs.map} +1 -1
- package/dist/shared/arc.internal-DBLPlj56.mjs +138 -0
- package/dist/shared/arc.internal-DBLPlj56.mjs.map +1 -0
- package/dist/shared/{characteristic-CL3bnjgJ.mjs → characteristic-OjEkAZBA.mjs} +3 -3
- package/dist/shared/{characteristic-CL3bnjgJ.mjs.map → characteristic-OjEkAZBA.mjs.map} +1 -1
- package/dist/shared/{cubic-EPyClIq0.mjs → cubic-CddsJ7ek.mjs} +2 -2
- package/dist/shared/{cubic-EPyClIq0.mjs.map → cubic-CddsJ7ek.mjs.map} +1 -1
- package/dist/shared/{cubic2d-q1HU0uM9.mjs → cubic2d-B6OVwHqs.mjs} +67 -330
- package/dist/shared/cubic2d-B6OVwHqs.mjs.map +1 -0
- package/dist/shared/{cubic2d-CI82mN9o.mjs → cubic2d-CnREttj6.mjs} +42 -7
- package/dist/shared/cubic2d-CnREttj6.mjs.map +1 -0
- package/dist/shared/{interval2d-CVS66YmV.mjs → interval2d-BCabpCmV.mjs} +2 -2
- package/dist/shared/{interval2d-CVS66YmV.mjs.map → interval2d-BCabpCmV.mjs.map} +1 -1
- package/dist/shared/linear2d-B01Cuo06.mjs +326 -0
- package/dist/shared/linear2d-B01Cuo06.mjs.map +1 -0
- package/dist/shared/{matrix3x3.internal-eK-9vsoI.mjs → matrix3x3.internal-BW6BMirB.mjs} +3 -3
- package/dist/shared/{matrix3x3.internal-eK-9vsoI.mjs.map → matrix3x3.internal-BW6BMirB.mjs.map} +1 -1
- package/dist/shared/{matrix4x4-DCRpqQsP.mjs → matrix4x4-Cq_UJZNO.mjs} +2 -2
- package/dist/shared/{matrix4x4-DCRpqQsP.mjs.map → matrix4x4-Cq_UJZNO.mjs.map} +1 -1
- package/dist/shared/{quadratic-DY3a1MVJ.mjs → quadratic-CvvVVM5r.mjs} +2 -2
- package/dist/shared/{quadratic-DY3a1MVJ.mjs.map → quadratic-CvvVVM5r.mjs.map} +1 -1
- package/dist/shared/{quadratic2d-CXlMyyCs.mjs → quadratic2d-CdwZ28Rg.mjs} +3 -3
- package/dist/shared/{quadratic2d-CXlMyyCs.mjs.map → quadratic2d-CdwZ28Rg.mjs.map} +1 -1
- package/dist/shared/{rationalCubic2d-CGU2mYjs.mjs → rationalCubic2d-A7ZkG9_r.mjs} +5 -5
- package/dist/shared/{rationalCubic2d-CGU2mYjs.mjs.map → rationalCubic2d-A7ZkG9_r.mjs.map} +1 -1
- package/dist/shared/{rationalCubic2d-aT1o6oCm.mjs → rationalCubic2d-CXTogOPX.mjs} +12 -9
- package/dist/shared/rationalCubic2d-CXTogOPX.mjs.map +1 -0
- package/dist/shared/{vector2-CrUOYb3v.mjs → vector2-BzDphAEw.mjs} +9 -7
- package/dist/shared/vector2-BzDphAEw.mjs.map +1 -0
- package/dist/shared/{vector2.internal-rPnW0RCx.mjs → vector2.internal-B42hdbQr.mjs} +2 -2
- package/dist/shared/{vector2.internal-rPnW0RCx.mjs.map → vector2.internal-B42hdbQr.mjs.map} +1 -1
- package/dist/shared/{vector3-CFL7Yx16.mjs → vector3--DNTuqZ-.mjs} +7 -5
- package/dist/shared/vector3--DNTuqZ-.mjs.map +1 -0
- package/dist/shared/{vector3.internal-CfWHl9SG.mjs → vector3.internal-DRO121Di.mjs} +2 -2
- package/dist/shared/{vector3.internal-CfWHl9SG.mjs.map → vector3.internal-DRO121Di.mjs.map} +1 -1
- package/dist/splines/index.mjs +10 -9
- package/dist/splines/index.mjs.map +1 -1
- package/dist/transform/index.mjs +1 -1
- package/dist/vector/index.mjs +2 -2
- package/dist/vector/vector2.d.ts +7 -5
- package/dist/vector/vector3.d.ts +6 -4
- package/package.json +9 -1
- package/dist/shared/cubic2d-CI82mN9o.mjs.map +0 -1
- package/dist/shared/cubic2d-q1HU0uM9.mjs.map +0 -1
- package/dist/shared/rationalCubic2d-aT1o6oCm.mjs.map +0 -1
- package/dist/shared/vector2-CrUOYb3v.mjs.map +0 -1
- 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,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-
|
|
1
|
+
import { n as characteristic_exports } from "../shared/characteristic-OjEkAZBA.mjs";
|
|
2
2
|
export { characteristic_exports as Characteristic };
|