curvy 2.0.0-alpha.18 → 2.0.0-alpha.19

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 (206) hide show
  1. package/dist/arc/arc.d.ts +239 -64
  2. package/dist/arc/index.d.ts +1 -0
  3. package/dist/arc/index.mjs +95 -26
  4. package/dist/arc/index.mjs.map +1 -1
  5. package/dist/characteristic/index.mjs +1 -1
  6. package/dist/coordinates/coordinateSystem.d.ts +92 -48
  7. package/dist/coordinates/dimension.d.ts +174 -22
  8. package/dist/coordinates/index.mjs +274 -85
  9. package/dist/coordinates/index.mjs.map +1 -1
  10. package/dist/curve/cubic2d.d.ts +6 -7
  11. package/dist/curve/index.mjs +2 -2
  12. package/dist/curve/internal/certified.d.ts +1 -0
  13. package/dist/curve/internal/cubic2d.d.ts +1 -0
  14. package/dist/curve/{curve2d.d.ts → internal/curve2d.d.ts} +5 -5
  15. package/dist/curve/internal/linear2d.d.ts +1 -0
  16. package/dist/curve/internal/quadratic2d.d.ts +1 -0
  17. package/dist/curve/internal/rationalCubic2d.d.ts +2 -0
  18. package/dist/curve/linear2d.d.ts +6 -7
  19. package/dist/curve/quadratic2d.d.ts +6 -7
  20. package/dist/curve/rationalCubic2d.d.ts +7 -7
  21. package/dist/interval/index.mjs +2 -2
  22. package/dist/interval/internal/interval.d.ts +1 -0
  23. package/dist/interval/internal/interval2d.d.ts +1 -0
  24. package/dist/interval/interval.d.ts +9 -5
  25. package/dist/interval/interval2d.d.ts +3 -4
  26. package/dist/matrix/index.mjs +2 -2
  27. package/dist/matrix/index.mjs.map +1 -1
  28. package/dist/matrix/internal/matrix2x2.d.ts +1 -0
  29. package/dist/matrix/internal/matrix3x3.d.ts +2 -0
  30. package/dist/matrix/internal/matrix4x4.d.ts +1 -0
  31. package/dist/matrix/matrix2x2.d.ts +4 -5
  32. package/dist/matrix/matrix3x3.d.ts +6 -7
  33. package/dist/matrix/matrix4x4.d.ts +6 -7
  34. package/dist/monotonicity/index.mjs +1 -1
  35. package/dist/number.mjs +1 -1
  36. package/dist/number.mjs.map +1 -1
  37. package/dist/path/cubic2d.d.ts +5 -6
  38. package/dist/path/index.mjs +4 -4
  39. package/dist/path/internal/cubic2d.d.ts +1 -0
  40. package/dist/path/internal/linear2d.d.ts +1 -0
  41. package/dist/path/{path2d.d.ts → internal/path2d.d.ts} +12 -10
  42. package/dist/path/internal/quadratic2d.d.ts +1 -0
  43. package/dist/path/internal/rationalCubic2d.d.ts +1 -0
  44. package/dist/path/linear2d.d.ts +5 -6
  45. package/dist/path/quadratic2d.d.ts +5 -6
  46. package/dist/path/rationalCubic2d.d.ts +3 -4
  47. package/dist/piecewise/index.mjs +16 -13
  48. package/dist/piecewise/index.mjs.map +1 -1
  49. package/dist/piecewise/internal/piecewise.d.ts +1 -0
  50. package/dist/piecewise/piecewise.d.ts +6 -7
  51. package/dist/polynomial/cubic.d.ts +5 -6
  52. package/dist/polynomial/index.mjs +2 -2
  53. package/dist/polynomial/internal/cubic.d.ts +1 -0
  54. package/dist/polynomial/internal/cubicImpl.d.ts +1 -0
  55. package/dist/polynomial/internal/linear.d.ts +1 -0
  56. package/dist/polynomial/{polynomial.d.ts → internal/polynomial.d.ts} +2 -2
  57. package/dist/polynomial/internal/quadratic.d.ts +1 -0
  58. package/dist/polynomial/internal/quadraticImpl.d.ts +1 -0
  59. package/dist/polynomial/linear.d.ts +5 -6
  60. package/dist/polynomial/quadratic.d.ts +5 -6
  61. package/dist/shared/{affine2d-DUqbI9RP.mjs → affine2d-DBrrscDK.mjs} +10 -13
  62. package/dist/shared/affine2d-DBrrscDK.mjs.map +1 -0
  63. package/dist/shared/arc-D4Q75qss.mjs +344 -0
  64. package/dist/shared/arc-D4Q75qss.mjs.map +1 -0
  65. package/dist/shared/{characteristic-OjEkAZBA.mjs → characteristic-BDz-BfjP.mjs} +3 -3
  66. package/dist/shared/{characteristic-OjEkAZBA.mjs.map → characteristic-BDz-BfjP.mjs.map} +1 -1
  67. package/dist/shared/{cubic-CddsJ7ek.mjs → cubic-Cfby-PoP.mjs} +44 -25
  68. package/dist/shared/cubic-Cfby-PoP.mjs.map +1 -0
  69. package/dist/shared/{cubic2d-CnREttj6.mjs → cubic2d-B9SkLTNj.mjs} +44 -24
  70. package/dist/shared/cubic2d-B9SkLTNj.mjs.map +1 -0
  71. package/dist/shared/{cubic2d-B6OVwHqs.mjs → cubic2d-Bg6DAceR.mjs} +32 -34
  72. package/dist/shared/cubic2d-Bg6DAceR.mjs.map +1 -0
  73. package/dist/{utils.mjs → shared/function-9StDYgP-.mjs} +3 -36
  74. package/dist/shared/function-9StDYgP-.mjs.map +1 -0
  75. package/dist/shared/{interval-8-erxD4h.mjs → interval-CVE7RB0r.mjs} +7 -10
  76. package/dist/shared/interval-CVE7RB0r.mjs.map +1 -0
  77. package/dist/shared/{interval2d-BCabpCmV.mjs → interval2d-JPEHgQSB.mjs} +20 -13
  78. package/dist/shared/interval2d-JPEHgQSB.mjs.map +1 -0
  79. package/dist/shared/{linear2d-B01Cuo06.mjs → linear2d-vSq0s0rv.mjs} +6 -6
  80. package/dist/shared/linear2d-vSq0s0rv.mjs.map +1 -0
  81. package/dist/shared/{matrix3x3.internal-BW6BMirB.mjs → matrix3x3-CkajJmjn.mjs} +15 -28
  82. package/dist/shared/matrix3x3-CkajJmjn.mjs.map +1 -0
  83. package/dist/shared/{matrix4x4-Cq_UJZNO.mjs → matrix4x4-YBpje9Xv.mjs} +10 -16
  84. package/dist/shared/matrix4x4-YBpje9Xv.mjs.map +1 -0
  85. package/dist/shared/{monotonicity-C-lodqfb.mjs → monotonicity-C2ANe23J.mjs} +1 -1
  86. package/dist/shared/{monotonicity-C-lodqfb.mjs.map → monotonicity-C2ANe23J.mjs.map} +1 -1
  87. package/dist/shared/{quadratic-CvvVVM5r.mjs → quadratic-Fygzcc14.mjs} +2 -2
  88. package/dist/shared/quadratic-Fygzcc14.mjs.map +1 -0
  89. package/dist/shared/{quadratic2d-CdwZ28Rg.mjs → quadratic2d-DVPLYmqX.mjs} +6 -6
  90. package/dist/shared/quadratic2d-DVPLYmqX.mjs.map +1 -0
  91. package/dist/shared/{rationalCubic2d-CXTogOPX.mjs → rationalCubic2d-CQdLNPrT.mjs} +125 -148
  92. package/dist/shared/rationalCubic2d-CQdLNPrT.mjs.map +1 -0
  93. package/dist/shared/{rationalCubic2d-A7ZkG9_r.mjs → rationalCubic2d-xGfQYkpL.mjs} +13 -10
  94. package/dist/shared/rationalCubic2d-xGfQYkpL.mjs.map +1 -0
  95. package/dist/shared/{solution-Bi6zCdQH.mjs → solution-DeWeVSi6.mjs} +22 -8
  96. package/dist/shared/solution-DeWeVSi6.mjs.map +1 -0
  97. package/dist/shared/value-D-cjWuxu.mjs +115 -0
  98. package/dist/shared/value-D-cjWuxu.mjs.map +1 -0
  99. package/dist/shared/{vector2-BzDphAEw.mjs → vector2-Df3kN-_g.mjs} +2 -2
  100. package/dist/shared/vector2-Df3kN-_g.mjs.map +1 -0
  101. package/dist/shared/{vector2.internal-B42hdbQr.mjs → vector2-Dtk5XT5b.mjs} +15 -19
  102. package/dist/shared/{vector2.internal-B42hdbQr.mjs.map → vector2-Dtk5XT5b.mjs.map} +1 -1
  103. package/dist/shared/{vector3--DNTuqZ-.mjs → vector3-CFxXUgGS.mjs} +2 -2
  104. package/dist/shared/vector3-CFxXUgGS.mjs.map +1 -0
  105. package/dist/shared/{vector3.internal-DRO121Di.mjs → vector3-mc97w7ef.mjs} +14 -10
  106. package/dist/shared/vector3-mc97w7ef.mjs.map +1 -0
  107. package/dist/shared/{vector4.internal-DH5DzNYO.mjs → vector4-C7pBKhVb.mjs} +15 -10
  108. package/dist/shared/vector4-C7pBKhVb.mjs.map +1 -0
  109. package/dist/shared/{vector4-syi93IOY.mjs → vector4-CqL8xajZ.mjs} +2 -2
  110. package/dist/shared/vector4-CqL8xajZ.mjs.map +1 -0
  111. package/dist/solution/index.mjs +1 -1
  112. package/dist/solution/{solution.internal.d.ts → internal/solution.d.ts} +1 -1
  113. package/dist/solution/solution.d.ts +9 -5
  114. package/dist/splines/basis2d.d.ts +3 -4
  115. package/dist/splines/bezier2d.d.ts +3 -4
  116. package/dist/splines/cardinal2d.d.ts +3 -4
  117. package/dist/splines/hermite2d.d.ts +3 -4
  118. package/dist/splines/index.mjs +51 -38
  119. package/dist/splines/index.mjs.map +1 -1
  120. package/dist/splines/internal/basis2d.d.ts +1 -0
  121. package/dist/splines/internal/bezier2d.d.ts +1 -0
  122. package/dist/splines/internal/cardinal2d.d.ts +1 -0
  123. package/dist/splines/internal/hermite2d.d.ts +1 -0
  124. package/dist/splines/internal/linear2d.d.ts +1 -0
  125. package/dist/splines/internal/rationalBezier2d.d.ts +1 -0
  126. package/dist/splines/{util.d.ts → internal/util.d.ts} +3 -3
  127. package/dist/splines/linear2d.d.ts +3 -4
  128. package/dist/splines/rationalBezier2d.d.ts +3 -4
  129. package/dist/transform/affine2d.d.ts +5 -6
  130. package/dist/transform/index.mjs +1 -1
  131. package/dist/transform/internal/affine2d.d.ts +1 -0
  132. package/dist/transform/{traits.d.ts → internal/traits.d.ts} +1 -1
  133. package/dist/{utils.d.ts → utils/function.d.ts} +2 -61
  134. package/dist/utils/index.d.ts +4 -0
  135. package/dist/utils/index.mjs +3 -0
  136. package/dist/utils/invariant.d.ts +17 -0
  137. package/dist/utils/pipeable.d.ts +44 -0
  138. package/dist/utils/value.d.ts +110 -0
  139. package/dist/vector/index.mjs +3 -3
  140. package/dist/vector/internal/vector2.d.ts +1 -0
  141. package/dist/vector/internal/vector3.d.ts +1 -0
  142. package/dist/vector/internal/vector4.d.ts +1 -0
  143. package/dist/vector/vector2.d.ts +11 -7
  144. package/dist/vector/vector3.d.ts +9 -5
  145. package/dist/vector/vector4.d.ts +9 -5
  146. package/package.json +3 -3
  147. package/dist/arc/arc.internal.d.ts +0 -2
  148. package/dist/coordinates/coordinateSystem.internal.d.ts +0 -2
  149. package/dist/coordinates/dimension.internal.d.ts +0 -2
  150. package/dist/curve/cubic2d.internal.d.ts +0 -2
  151. package/dist/curve/linear2d.internal.d.ts +0 -2
  152. package/dist/curve/quadratic2d.internal.d.ts +0 -2
  153. package/dist/curve/rationalCubic2d.internal.d.ts +0 -2
  154. package/dist/interval/interval2d.internal.d.ts +0 -2
  155. package/dist/matrix/matrix2x2.internal.d.ts +0 -2
  156. package/dist/matrix/matrix3x3.internal.d.ts +0 -4
  157. package/dist/matrix/matrix4x4.internal.d.ts +0 -2
  158. package/dist/path/cubic2d.internal.d.ts +0 -2
  159. package/dist/path/linear2d.internal.d.ts +0 -2
  160. package/dist/path/quadratic2d.internal.d.ts +0 -2
  161. package/dist/path/rationalCubic2d.internal.d.ts +0 -2
  162. package/dist/piecewise/piecewise.internal.d.ts +0 -2
  163. package/dist/polynomial/cubic.internal.circular.d.ts +0 -2
  164. package/dist/polynomial/linear.internal.d.ts +0 -2
  165. package/dist/polynomial/quadratic.internal.circular.d.ts +0 -2
  166. package/dist/shared/affine2d-DUqbI9RP.mjs.map +0 -1
  167. package/dist/shared/arc.internal-DBLPlj56.mjs +0 -138
  168. package/dist/shared/arc.internal-DBLPlj56.mjs.map +0 -1
  169. package/dist/shared/cubic-CddsJ7ek.mjs.map +0 -1
  170. package/dist/shared/cubic2d-B6OVwHqs.mjs.map +0 -1
  171. package/dist/shared/cubic2d-CnREttj6.mjs.map +0 -1
  172. package/dist/shared/interval-8-erxD4h.mjs.map +0 -1
  173. package/dist/shared/interval2d-BCabpCmV.mjs.map +0 -1
  174. package/dist/shared/linear2d-B01Cuo06.mjs.map +0 -1
  175. package/dist/shared/matrix3x3.internal-BW6BMirB.mjs.map +0 -1
  176. package/dist/shared/matrix4x4-Cq_UJZNO.mjs.map +0 -1
  177. package/dist/shared/quadratic-CvvVVM5r.mjs.map +0 -1
  178. package/dist/shared/quadratic2d-CdwZ28Rg.mjs.map +0 -1
  179. package/dist/shared/rationalCubic2d-A7ZkG9_r.mjs.map +0 -1
  180. package/dist/shared/rationalCubic2d-CXTogOPX.mjs.map +0 -1
  181. package/dist/shared/solution-Bi6zCdQH.mjs.map +0 -1
  182. package/dist/shared/vector2-BzDphAEw.mjs.map +0 -1
  183. package/dist/shared/vector3--DNTuqZ-.mjs.map +0 -1
  184. package/dist/shared/vector3.internal-DRO121Di.mjs.map +0 -1
  185. package/dist/shared/vector4-syi93IOY.mjs.map +0 -1
  186. package/dist/shared/vector4.internal-DH5DzNYO.mjs.map +0 -1
  187. package/dist/splines/basis2d.internal.d.ts +0 -2
  188. package/dist/splines/bezier2d.internal.d.ts +0 -2
  189. package/dist/splines/cardinal2d.internal.d.ts +0 -2
  190. package/dist/splines/hermite2d.internal.d.ts +0 -2
  191. package/dist/splines/linear2d.internal.d.ts +0 -2
  192. package/dist/splines/rationalBezier2d.internal.d.ts +0 -2
  193. package/dist/transform/affine2d.internal.d.ts +0 -2
  194. package/dist/utils.mjs.map +0 -1
  195. package/dist/vector/vector2.internal.d.ts +0 -4
  196. package/dist/vector/vector3.internal.d.ts +0 -2
  197. package/dist/vector/vector4.internal.d.ts +0 -2
  198. /package/dist/{interval/interval.internal.d.ts → arc/internal/arc.d.ts} +0 -0
  199. /package/dist/{polynomial/cubic.internal.d.ts → coordinates/internal/coordinateSystem.d.ts} +0 -0
  200. /package/dist/{polynomial/quadratic.internal.d.ts → coordinates/internal/dimension.d.ts} +0 -0
  201. /package/dist/{dimensions.d.ts → internal/dimensions.d.ts} +0 -0
  202. /package/dist/{length.d.ts → internal/length.d.ts} +0 -0
  203. /package/dist/matrix/{traits.d.ts → internal/traits.d.ts} +0 -0
  204. /package/dist/path/{traits.d.ts → internal/traits.d.ts} +0 -0
  205. /package/dist/piecewise/{traits.d.ts → internal/traits.d.ts} +0 -0
  206. /package/dist/polynomial/{traits.d.ts → internal/traits.d.ts} +0 -0
package/dist/arc/arc.d.ts CHANGED
@@ -1,32 +1,44 @@
1
1
  import type { Closed } from '../interval/interval.ts';
2
2
  import type { Interval2d } from '../interval/interval2d.ts';
3
3
  import type { RationalCubicPath2d } from '../path/rationalCubic2d.ts';
4
- import type { Pipeable } from '../utils.ts';
4
+ import type { Value } from '../utils/value.ts';
5
5
  import type { Vector2 } from '../vector/vector2.ts';
6
- import type { ArcTypeId } from './arc.internal.ts';
7
6
  /**
8
- * A circular arc: the points `center + radius * (cos(a), sin(a))` for `a`
9
- * running from `startAngle` to `startAngle + sweep`.
7
+ * An arc described by its geometry rather than its curve coefficients:
8
+ * `Circular` for a piece of a circle, `Elliptical` for a piece of a
9
+ * possibly rotated ellipse.
10
10
  *
11
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.
12
+ * here, query its geometry (`solve`, `length`, `boundingBox`), and lower it
13
+ * with `toPath` for curve math or `toPathData` for SVG. The description
14
+ * keeps answers the lowered form loses. Point-at-parameter is one
15
+ * `cos`/`sin` here and a rational evaluation there, and length is a closed
16
+ * form or a fixed-cost elliptic integral rather than a tolerance-driven
17
+ * iteration.
17
18
  *
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.
19
+ * Every operation in this module accepts both kinds. Angles are in
20
+ * radians, positive rotating `+x` toward `+y` — clockwise in an SVG
21
+ * viewport's y-down coordinates. Direction and multiplicity live in the
22
+ * sweep's sign and magnitude: a negative sweep runs the other way, and a
23
+ * magnitude past `2 * pi` keeps going around.
23
24
  *
24
25
  * All fields are readonly. No operation mutates an arc.
25
26
  *
26
27
  * @since 2.0.0
27
28
  */
28
- export interface Circular extends Pipeable {
29
- readonly [ArcTypeId]: ArcTypeId;
29
+ export type Arc = Circular | Elliptical;
30
+ /**
31
+ * A circular arc: the points `center + radius * (cos(a), sin(a))` for `a`
32
+ * running from `startAngle` to `startAngle + sweep`.
33
+ *
34
+ * Angles are in radians, measured from the `+x` direction, positive
35
+ * rotating `+x` toward `+y` — clockwise in an SVG viewport's y-down
36
+ * coordinates.
37
+ *
38
+ * @since 2.0.0
39
+ */
40
+ export interface Circular extends Value.Instance {
41
+ readonly '~curvy/Arc': '~curvy/Arc';
30
42
  readonly kind: 'circular';
31
43
  /**
32
44
  * The cartesian center of the circle the arc lies on.
@@ -75,6 +87,102 @@ export interface CircularConfig {
75
87
  */
76
88
  readonly sweep?: number;
77
89
  }
90
+ /**
91
+ * An elliptical arc: the points of an ellipse with semi-axes `radiusX` and
92
+ * `radiusY`, rotated by `rotation` around `center`, for parametric angles
93
+ * running from `startAngle` to `startAngle + sweep`.
94
+ *
95
+ * The point at parametric angle `a` is
96
+ * `center + R(rotation) * (radiusX * cos(a), radiusY * sin(a))`, where
97
+ * `R` rotates `+x` toward `+y`. This is SVG's own arc parametrization.
98
+ *
99
+ * The parametric angle is not the direction from the center to the
100
+ * point. It is the angle on the circle that the radii stretch into the
101
+ * ellipse, so the two agree only on the axes, or everywhere when the radii
102
+ * are equal. Equal steps in it also cover unequal distances along the
103
+ * curve, unlike a circle's.
104
+ *
105
+ * @since 2.0.0
106
+ */
107
+ export interface Elliptical extends Value.Instance {
108
+ readonly '~curvy/Arc': '~curvy/Arc';
109
+ readonly kind: 'elliptical';
110
+ /**
111
+ * The cartesian center of the ellipse the arc lies on.
112
+ */
113
+ readonly center: Vector2;
114
+ /**
115
+ * The semi-axis along the ellipse's own x axis, before rotation.
116
+ * Non-negative. `0` flattens the ellipse to a segment along its y axis.
117
+ */
118
+ readonly radiusX: number;
119
+ /**
120
+ * The semi-axis along the ellipse's own y axis, before rotation.
121
+ * Non-negative. `0` flattens the ellipse to a segment along its x axis.
122
+ */
123
+ readonly radiusY: number;
124
+ /**
125
+ * The angle from the `+x` direction to the ellipse's own x axis, in
126
+ * radians, positive rotating `+x` toward `+y`.
127
+ */
128
+ readonly rotation: number;
129
+ /**
130
+ * The parametric angle where the arc starts, in radians. `0` is the end
131
+ * of the ellipse's own x axis.
132
+ */
133
+ readonly startAngle: number;
134
+ /**
135
+ * The signed parametric extent, in radians. Positive runs `+x` toward
136
+ * `+y` in the ellipse's own frame. A magnitude past `2 * pi` traces the
137
+ * ellipse more than once.
138
+ */
139
+ readonly sweep: number;
140
+ }
141
+ /**
142
+ * Configuration for `elliptical`. Only the two radii are required. The
143
+ * defaults give a full, unrotated ellipse around the origin.
144
+ *
145
+ * @since 2.0.0
146
+ */
147
+ export interface EllipticalConfig {
148
+ /**
149
+ * The cartesian center of the ellipse. Defaults to the origin.
150
+ */
151
+ readonly center?: Vector2;
152
+ /**
153
+ * The semi-axis along the ellipse's own x axis. Must be finite and
154
+ * non-negative.
155
+ */
156
+ readonly radiusX: number;
157
+ /**
158
+ * The semi-axis along the ellipse's own y axis. Must be finite and
159
+ * non-negative.
160
+ */
161
+ readonly radiusY: number;
162
+ /**
163
+ * The angle from `+x` to the ellipse's own x axis, in radians. Defaults
164
+ * to `0`, an axis-aligned ellipse.
165
+ */
166
+ readonly rotation?: number;
167
+ /**
168
+ * The parametric angle where the arc starts, in radians. Defaults to
169
+ * `0`, the end of the ellipse's own x axis.
170
+ */
171
+ readonly startAngle?: number;
172
+ /**
173
+ * The signed parametric extent, in radians. Defaults to `2 * pi`, the
174
+ * whole ellipse.
175
+ */
176
+ readonly sweep?: number;
177
+ }
178
+ /**
179
+ * Checks if a value is an `Arc` of either kind.
180
+ *
181
+ * @param v - The value to check.
182
+ * @returns `true` if the value is an `Arc`, `false` otherwise.
183
+ * @since 2.0.0
184
+ */
185
+ export declare const isArc: (v: unknown) => v is Arc;
78
186
  /**
79
187
  * Checks if a value is a `Circular` arc.
80
188
  *
@@ -102,41 +210,78 @@ export declare const isCircular: (v: unknown) => v is Circular;
102
210
  * ```
103
211
  */
104
212
  export declare const circular: (config: CircularConfig) => Circular;
213
+ /**
214
+ * Checks if a value is an `Elliptical` arc.
215
+ *
216
+ * @param v - The value to check.
217
+ * @returns `true` if the value is an `Elliptical` arc, `false` otherwise.
218
+ * @since 2.0.0
219
+ */
220
+ export declare const isElliptical: (v: unknown) => v is Elliptical;
221
+ /**
222
+ * Creates an `Elliptical` arc.
223
+ *
224
+ * Equal radii give an ellipse that is geometrically a circle, but the
225
+ * value stays `Elliptical`. Build a `Circular` arc with `circular` to get
226
+ * its closed-form length.
227
+ *
228
+ * @param config - Center, radii, rotation, start angle, and sweep. Only
229
+ * `radiusX` and `radiusY` are required. See `EllipticalConfig` for the
230
+ * defaults.
231
+ * @returns A new `Elliptical` arc.
232
+ * @throws `Error` when either radius is negative, or when a radius,
233
+ * `rotation`, `startAngle`, or `sweep` is not finite.
234
+ * @since 2.0.0
235
+ * @example
236
+ * ```ts
237
+ * // The ellipse inscribed in a 200 x 100 box at the origin:
238
+ * const oval = Arc.elliptical({
239
+ * center: Vector2.make(100, 50),
240
+ * radiusX: 100,
241
+ * radiusY: 50,
242
+ * })
243
+ *
244
+ * // Its lower half, from 3 o'clock through 6 o'clock to 9 o'clock:
245
+ * const lower = Arc.elliptical({ radiusX: 100, radiusY: 50, sweep: Math.PI })
246
+ * ```
247
+ */
248
+ export declare const elliptical: (config: EllipticalConfig) => Elliptical;
105
249
  export declare const equals: {
106
250
  /**
107
- * Checks two `Circular` arcs for equality, field by field. Numeric
108
- * fields compare within the tolerance of `coincident` from
109
- * `curvy/number`.
251
+ * Checks two arcs for equality, field by field. Numeric fields compare
252
+ * within the tolerance of `coincident` from `curvy/number`.
110
253
  *
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.
254
+ * Comparison is structural, not geometric. Arcs of different kinds
255
+ * always compare unequal, even an `Elliptical` arc with equal radii
256
+ * against the `Circular` arc it traces. So do two arcs tracing the same
257
+ * points from different descriptions, like a start angle shifted by
258
+ * `2 * pi` or the reverse direction.
114
259
  *
115
260
  * @param a - The first arc.
116
261
  * @param b - The second arc.
117
262
  * @returns `true` if the arcs are equal, `false` otherwise.
118
263
  * @since 2.0.0
119
264
  */
120
- (a: Circular, b: Circular): boolean;
265
+ (a: Arc, b: Arc): boolean;
121
266
  /**
122
- * Checks two `Circular` arcs for equality.
267
+ * Checks two arcs for equality, field by field.
123
268
  *
124
269
  * @param b - The arc to compare against.
125
270
  * @returns A function that takes an arc and returns whether the two are
126
271
  * equal.
127
272
  * @since 2.0.0
128
273
  */
129
- (b: Circular): (a: Circular) => boolean;
274
+ (b: Arc): (a: Arc) => boolean;
130
275
  };
131
276
  /**
132
- * Computes the point where the arc starts,
133
- * `center + radius * (cos(startAngle), sin(startAngle))`.
277
+ * Computes the point where the arc starts, at angle `startAngle`. For a
278
+ * circular arc that is `center + radius * (cos(startAngle), sin(startAngle))`.
134
279
  *
135
280
  * @param a - The arc.
136
281
  * @returns The arc's first point.
137
282
  * @since 2.0.0
138
283
  */
139
- export declare const startPoint: (a: Circular) => Vector2;
284
+ export declare const startPoint: (a: Arc) => Vector2;
140
285
  /**
141
286
  * Computes the point where the arc ends, evaluated at
142
287
  * `startAngle + sweep`.
@@ -149,16 +294,19 @@ export declare const startPoint: (a: Circular) => Vector2;
149
294
  * @returns The arc's last point.
150
295
  * @since 2.0.0
151
296
  */
152
- export declare const endPoint: (a: Circular) => Vector2;
297
+ export declare const endPoint: (a: Arc) => Vector2;
153
298
  export declare const solve: {
154
299
  /**
155
300
  * Evaluates the arc at parameter `t`, the point at angle
156
301
  * `startAngle + t * sweep`.
157
302
  *
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.
303
+ * On a circular arc the uniform parameter is also the arc-length
304
+ * parameter. Equal steps in `t` cover equal distance along the arc, a
305
+ * property polynomial curves lack. An elliptical arc's angle is
306
+ * parametric, so equal steps cover more distance near the ends of the
307
+ * longer axis.
308
+ *
309
+ * `t` is not clamped. Values outside `[0, 1]` continue around the curve.
162
310
  *
163
311
  * @param a - The arc to evaluate.
164
312
  * @param t - The parameter. `0` is the start of the arc, `1` the end.
@@ -169,62 +317,83 @@ export declare const solve: {
169
317
  * // The midpoint of a quarter arc sits at 45 degrees:
170
318
  * Arc.solve(Arc.circular({ radius: 1, sweep: Math.PI / 2 }), 0.5)
171
319
  * // (cos(pi / 4), sin(pi / 4))
320
+ *
321
+ * // On an ellipse the same parameter lands at (100 * cos(pi / 4), 50 * sin(pi / 4)),
322
+ * // which lies at about 26.6 degrees from the center, not 45:
323
+ * Arc.solve(Arc.elliptical({ radiusX: 100, radiusY: 50, sweep: Math.PI / 2 }), 0.5)
172
324
  * ```
173
325
  */
174
- (a: Circular, t: number): Vector2;
326
+ (a: Arc, t: number): Vector2;
175
327
  /**
176
- * Evaluates the arc at parameter `t`.
328
+ * Evaluates the arc at parameter `t`, the point at angle
329
+ * `startAngle + t * sweep`.
177
330
  *
178
331
  * @param t - The parameter. `0` is the start of the arc, `1` the end.
179
332
  * @returns A function that takes an arc and returns the point at `t`.
180
333
  * @since 2.0.0
181
334
  */
182
- (t: number): (a: Circular) => Vector2;
335
+ (t: number): (a: Arc) => Vector2;
183
336
  };
184
337
  /**
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.
338
+ * Computes the arc's length. A sweep past one full turn counts every
339
+ * traversal.
340
+ *
341
+ * Neither kind takes a tolerance parameter or iterates to one, unlike arc
342
+ * length on a lowered path:
343
+ * - circular: `radius * abs(sweep)`, exact in closed form
344
+ * - elliptical: an incomplete elliptic integral of the second kind,
345
+ * evaluated through Carlson's symmetric forms in a fixed number of
346
+ * steps. The relative error stays near `1e-15`. Equal radii take the
347
+ * closed form, and so does a flat ellipse.
188
348
  *
189
349
  * @param a - The arc.
190
350
  * @returns The length of the arc.
191
351
  * @since 2.0.0
352
+ * @example
353
+ * ```ts
354
+ * // The perimeter of a 2:1 ellipse:
355
+ * Arc.length(Arc.elliptical({ radiusX: 2, radiusY: 1 })) // 9.688448220547677
356
+ * ```
192
357
  */
193
- export declare const length: (a: Circular) => number;
358
+ export declare const length: (a: Arc) => number;
194
359
  /**
195
- * Reverses the arc's direction: the same points traced the other way.
360
+ * Reverses the arc's direction, tracing the same points the other way.
196
361
  * The start angle moves to the far end and the sweep negates, so
197
362
  * `solve(reverse(a), t)` is `solve(a, 1 - t)`.
198
363
  *
199
364
  * @param a - The arc.
200
- * @returns A new `Circular` arc tracing the input backward.
365
+ * @returns A new arc of the same kind, tracing the input backward.
201
366
  * @since 2.0.0
202
367
  */
203
- export declare const reverse: (a: Circular) => Circular;
368
+ export declare const reverse: <A extends Arc>(a: A) => A;
204
369
  /**
205
370
  * Computes the exact axis-aligned bounding box of the arc.
206
371
  *
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`.
372
+ * Extremes occur only at the endpoints or at the angles where the curve
373
+ * runs parallel to an axis, and both are known in closed form. Every side
374
+ * is therefore exact up to IEEE 754 rounding, with no tolerance parameter.
375
+ * Contrast `RationalCubicPath2d.boundingBox`, which is tight only to a
376
+ * tolerance you choose. An arc whose radii are all `0` has a box that
377
+ * collapses to `center`.
213
378
  *
214
379
  * @param a - The arc.
215
380
  * @returns A closed `Interval2d` enclosing exactly the arc's points.
216
381
  * @since 2.0.0
217
382
  */
218
- export declare const boundingBox: (a: Circular) => Interval2d<Closed, Closed>;
383
+ export declare const boundingBox: (a: Arc) => Interval2d<Closed, Closed>;
219
384
  /**
220
385
  * 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.
386
+ * rounding. The path is made of rational cubic segments of at most a
387
+ * quarter turn each, uniform in angle, and a sweep past one full turn
388
+ * traces the curve more than once. Circular arcs use the same
389
+ * construction as `CoordinateSystem.arc`, and elliptical arcs carry it
390
+ * through the ellipse's stretch and rotation.
224
391
  *
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.
392
+ * The path is the form to transform, since circles and ellipses are not
393
+ * closed under every affine map but rational cubics are. Lower first and
394
+ * apply `RationalCubicPath2d.transform` to the result. It is also the form
395
+ * `CoordinateSystem.image` takes, to carry an arc drawn in chart space
396
+ * into a polar system.
228
397
  *
229
398
  * @param a - The arc.
230
399
  * @returns The arc as a `RationalCubicPath2d`.
@@ -242,21 +411,27 @@ export declare const boundingBox: (a: Circular) => Interval2d<Closed, Closed>;
242
411
  * )
243
412
  * ```
244
413
  */
245
- export declare const toPath: (a: Circular) => RationalCubicPath2d;
414
+ export declare const toPath: (a: Arc) => RationalCubicPath2d;
246
415
  /**
247
416
  * Emits exact SVG path data for the arc, using `A` commands computed from
248
417
  * the arc's description rather than recovered from curve coefficients.
418
+ * An elliptical arc's commands carry both radii and its rotation in
419
+ * degrees, which is how SVG draws ellipses natively.
420
+ *
249
421
  * 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
422
+ * `0`. The sweep flag is `1` for a positive sweep, which renders
251
423
  * clockwise in an SVG viewport's y-down coordinates.
252
424
  *
253
425
  * Degenerate contracts:
254
- * - zero sweep, or radius `0`: an `M` command alone, which renders
426
+ * - zero sweep, or every radius `0`: an `M` command alone, which renders
255
427
  * 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
428
+ * - an elliptical arc with one radius `0`: `L` commands tracing the flat
429
+ * ellipse back and forth, since SVG would draw an `A` with a zero radius
430
+ * as a single line between its endpoints
431
+ * - a full-turn sweep: two half-turn `A` commands, closing on the exact
432
+ * starting coordinates
433
+ * - a sweep past one full turn: clamped to one lap, where `toPath` keeps
434
+ * going around. SVG path data cannot express multiple laps.
260
435
  *
261
436
  * @param a - The arc.
262
437
  * @returns The SVG path data string.
@@ -274,4 +449,4 @@ export declare const toPath: (a: Circular) => RationalCubicPath2d;
274
449
  * )
275
450
  * ```
276
451
  */
277
- export declare const toPathData: (a: Circular) => string;
452
+ export declare const toPathData: (a: Arc) => string;
@@ -1,2 +1,3 @@
1
1
  import * as ArcNs from './arc.ts';
2
+ export type Arc = ArcNs.Arc;
2
3
  export { ArcNs as Arc };
@@ -1,12 +1,15 @@
1
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";
2
+ import { _ as solve$1, b as toPathData$1, c as endPoint$1, d as isCircular$1, f as isElliptical$1, g as reverse$1, i as circular$1, l as equals$1, m as length$1, r as boundingBox$1, s as elliptical$1, u as isArc$1, v as startPoint$1, y as toPath$1 } from "../shared/arc-D4Q75qss.mjs";
3
3
  //#region src/arc/arc.ts
4
4
  var arc_exports = /* @__PURE__ */ __exportAll({
5
5
  boundingBox: () => boundingBox,
6
6
  circular: () => circular,
7
+ elliptical: () => elliptical,
7
8
  endPoint: () => endPoint,
8
9
  equals: () => equals,
10
+ isArc: () => isArc,
9
11
  isCircular: () => isCircular,
12
+ isElliptical: () => isElliptical,
10
13
  length: () => length,
11
14
  reverse: () => reverse,
12
15
  solve: () => solve,
@@ -15,6 +18,14 @@ var arc_exports = /* @__PURE__ */ __exportAll({
15
18
  toPathData: () => toPathData
16
19
  });
17
20
  /**
21
+ * Checks if a value is an `Arc` of either kind.
22
+ *
23
+ * @param v - The value to check.
24
+ * @returns `true` if the value is an `Arc`, `false` otherwise.
25
+ * @since 2.0.0
26
+ */
27
+ const isArc = isArc$1;
28
+ /**
18
29
  * Checks if a value is a `Circular` arc.
19
30
  *
20
31
  * @param v - The value to check.
@@ -41,10 +52,46 @@ const isCircular = isCircular$1;
41
52
  * ```
42
53
  */
43
54
  const circular = circular$1;
55
+ /**
56
+ * Checks if a value is an `Elliptical` arc.
57
+ *
58
+ * @param v - The value to check.
59
+ * @returns `true` if the value is an `Elliptical` arc, `false` otherwise.
60
+ * @since 2.0.0
61
+ */
62
+ const isElliptical = isElliptical$1;
63
+ /**
64
+ * Creates an `Elliptical` arc.
65
+ *
66
+ * Equal radii give an ellipse that is geometrically a circle, but the
67
+ * value stays `Elliptical`. Build a `Circular` arc with `circular` to get
68
+ * its closed-form length.
69
+ *
70
+ * @param config - Center, radii, rotation, start angle, and sweep. Only
71
+ * `radiusX` and `radiusY` are required. See `EllipticalConfig` for the
72
+ * defaults.
73
+ * @returns A new `Elliptical` arc.
74
+ * @throws `Error` when either radius is negative, or when a radius,
75
+ * `rotation`, `startAngle`, or `sweep` is not finite.
76
+ * @since 2.0.0
77
+ * @example
78
+ * ```ts
79
+ * // The ellipse inscribed in a 200 x 100 box at the origin:
80
+ * const oval = Arc.elliptical({
81
+ * center: Vector2.make(100, 50),
82
+ * radiusX: 100,
83
+ * radiusY: 50,
84
+ * })
85
+ *
86
+ * // Its lower half, from 3 o'clock through 6 o'clock to 9 o'clock:
87
+ * const lower = Arc.elliptical({ radiusX: 100, radiusY: 50, sweep: Math.PI })
88
+ * ```
89
+ */
90
+ const elliptical = elliptical$1;
44
91
  const equals = equals$1;
45
92
  /**
46
- * Computes the point where the arc starts,
47
- * `center + radius * (cos(startAngle), sin(startAngle))`.
93
+ * Computes the point where the arc starts, at angle `startAngle`. For a
94
+ * circular arc that is `center + radius * (cos(startAngle), sin(startAngle))`.
48
95
  *
49
96
  * @param a - The arc.
50
97
  * @returns The arc's first point.
@@ -66,34 +113,46 @@ const startPoint = startPoint$1;
66
113
  const endPoint = endPoint$1;
67
114
  const solve = solve$1;
68
115
  /**
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.
116
+ * Computes the arc's length. A sweep past one full turn counts every
117
+ * traversal.
118
+ *
119
+ * Neither kind takes a tolerance parameter or iterates to one, unlike arc
120
+ * length on a lowered path:
121
+ * - circular: `radius * abs(sweep)`, exact in closed form
122
+ * - elliptical: an incomplete elliptic integral of the second kind,
123
+ * evaluated through Carlson's symmetric forms in a fixed number of
124
+ * steps. The relative error stays near `1e-15`. Equal radii take the
125
+ * closed form, and so does a flat ellipse.
72
126
  *
73
127
  * @param a - The arc.
74
128
  * @returns The length of the arc.
75
129
  * @since 2.0.0
130
+ * @example
131
+ * ```ts
132
+ * // The perimeter of a 2:1 ellipse:
133
+ * Arc.length(Arc.elliptical({ radiusX: 2, radiusY: 1 })) // 9.688448220547677
134
+ * ```
76
135
  */
77
136
  const length = length$1;
78
137
  /**
79
- * Reverses the arc's direction: the same points traced the other way.
138
+ * Reverses the arc's direction, tracing the same points the other way.
80
139
  * The start angle moves to the far end and the sweep negates, so
81
140
  * `solve(reverse(a), t)` is `solve(a, 1 - t)`.
82
141
  *
83
142
  * @param a - The arc.
84
- * @returns A new `Circular` arc tracing the input backward.
143
+ * @returns A new arc of the same kind, tracing the input backward.
85
144
  * @since 2.0.0
86
145
  */
87
146
  const reverse = reverse$1;
88
147
  /**
89
148
  * Computes the exact axis-aligned bounding box of the arc.
90
149
  *
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`.
150
+ * Extremes occur only at the endpoints or at the angles where the curve
151
+ * runs parallel to an axis, and both are known in closed form. Every side
152
+ * is therefore exact up to IEEE 754 rounding, with no tolerance parameter.
153
+ * Contrast `RationalCubicPath2d.boundingBox`, which is tight only to a
154
+ * tolerance you choose. An arc whose radii are all `0` has a box that
155
+ * collapses to `center`.
97
156
  *
98
157
  * @param a - The arc.
99
158
  * @returns A closed `Interval2d` enclosing exactly the arc's points.
@@ -102,13 +161,17 @@ const reverse = reverse$1;
102
161
  const boundingBox = boundingBox$1;
103
162
  /**
104
163
  * 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.
164
+ * rounding. The path is made of rational cubic segments of at most a
165
+ * quarter turn each, uniform in angle, and a sweep past one full turn
166
+ * traces the curve more than once. Circular arcs use the same
167
+ * construction as `CoordinateSystem.arc`, and elliptical arcs carry it
168
+ * through the ellipse's stretch and rotation.
108
169
  *
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.
170
+ * The path is the form to transform, since circles and ellipses are not
171
+ * closed under every affine map but rational cubics are. Lower first and
172
+ * apply `RationalCubicPath2d.transform` to the result. It is also the form
173
+ * `CoordinateSystem.image` takes, to carry an arc drawn in chart space
174
+ * into a polar system.
112
175
  *
113
176
  * @param a - The arc.
114
177
  * @returns The arc as a `RationalCubicPath2d`.
@@ -130,17 +193,23 @@ const toPath = toPath$1;
130
193
  /**
131
194
  * Emits exact SVG path data for the arc, using `A` commands computed from
132
195
  * the arc's description rather than recovered from curve coefficients.
196
+ * An elliptical arc's commands carry both radii and its rotation in
197
+ * degrees, which is how SVG draws ellipses natively.
198
+ *
133
199
  * 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
200
+ * `0`. The sweep flag is `1` for a positive sweep, which renders
135
201
  * clockwise in an SVG viewport's y-down coordinates.
136
202
  *
137
203
  * Degenerate contracts:
138
- * - zero sweep, or radius `0`: an `M` command alone, which renders
204
+ * - zero sweep, or every radius `0`: an `M` command alone, which renders
139
205
  * 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
206
+ * - an elliptical arc with one radius `0`: `L` commands tracing the flat
207
+ * ellipse back and forth, since SVG would draw an `A` with a zero radius
208
+ * as a single line between its endpoints
209
+ * - a full-turn sweep: two half-turn `A` commands, closing on the exact
210
+ * starting coordinates
211
+ * - a sweep past one full turn: clamped to one lap, where `toPath` keeps
212
+ * going around. SVG path data cannot express multiple laps.
144
213
  *
145
214
  * @param a - The arc.
146
215
  * @returns The SVG path data string.