@faicad/faijs 0.18.3 → 0.22.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (241) hide show
  1. package/dist/api/api-namespace.d.ts.map +1 -1
  2. package/dist/api/api-namespace.js +4 -1
  3. package/dist/api/api-namespace.js.map +1 -1
  4. package/dist/api/brep-mirror/joinery-brep.d.ts +1 -1
  5. package/dist/api/brep-mirror/joinery-brep.d.ts.map +1 -1
  6. package/dist/api/brep-mirror/joinery-brep.js +22 -20
  7. package/dist/api/brep-mirror/joinery-brep.js.map +1 -1
  8. package/dist/api/generated/script-face-manifest.d.ts +4 -0
  9. package/dist/api/generated/script-face-manifest.d.ts.map +1 -1
  10. package/dist/api/generated/script-face-manifest.js.map +1 -1
  11. package/dist/api/index.d.ts +4 -0
  12. package/dist/api/index.d.ts.map +1 -1
  13. package/dist/api/index.js +3 -0
  14. package/dist/api/index.js.map +1 -1
  15. package/dist/api/knurl.d.ts.map +1 -1
  16. package/dist/api/knurl.js +1 -0
  17. package/dist/api/knurl.js.map +1 -1
  18. package/dist/api/primitives.d.ts +4 -3
  19. package/dist/api/primitives.d.ts.map +1 -1
  20. package/dist/api/primitives.js +9 -3
  21. package/dist/api/primitives.js.map +1 -1
  22. package/dist/api/profile.d.ts +34 -5
  23. package/dist/api/profile.d.ts.map +1 -1
  24. package/dist/api/profile.js +168 -186
  25. package/dist/api/profile.js.map +1 -1
  26. package/dist/api/punch-hole.d.ts +77 -0
  27. package/dist/api/punch-hole.d.ts.map +1 -0
  28. package/dist/api/punch-hole.js +207 -0
  29. package/dist/api/punch-hole.js.map +1 -0
  30. package/dist/api/sketch-on-face.d.ts +85 -0
  31. package/dist/api/sketch-on-face.d.ts.map +1 -0
  32. package/dist/api/sketch-on-face.js +136 -0
  33. package/dist/api/sketch-on-face.js.map +1 -0
  34. package/dist/api/sketch-on-plane.d.ts +87 -0
  35. package/dist/api/sketch-on-plane.d.ts.map +1 -0
  36. package/dist/api/sketch-on-plane.js +106 -0
  37. package/dist/api/sketch-on-plane.js.map +1 -0
  38. package/dist/api/surface/arg-spec.d.ts +8 -0
  39. package/dist/api/surface/arg-spec.d.ts.map +1 -1
  40. package/dist/api/surface/arg-spec.js.map +1 -1
  41. package/dist/api/transform.d.ts +5 -5
  42. package/dist/api/transform.d.ts.map +1 -1
  43. package/dist/api/transform.js +12 -10
  44. package/dist/api/transform.js.map +1 -1
  45. package/dist/api/xml-dom.d.ts +27 -0
  46. package/dist/api/xml-dom.d.ts.map +1 -0
  47. package/dist/api/xml-dom.js +45 -0
  48. package/dist/api/xml-dom.js.map +1 -0
  49. package/dist/boolean/csg-backend.d.ts +6 -6
  50. package/dist/boolean/csg-backend.d.ts.map +1 -1
  51. package/dist/boolean/csg-backend.js +9 -9
  52. package/dist/boolean/csg-backend.js.map +1 -1
  53. package/dist/boolean/csg-core.d.ts +10 -10
  54. package/dist/boolean/csg-core.d.ts.map +1 -1
  55. package/dist/boolean/csg-core.js +24 -24
  56. package/dist/boolean/csg-core.js.map +1 -1
  57. package/dist/boolean/extrude-helpers.d.ts +8 -8
  58. package/dist/boolean/extrude-helpers.d.ts.map +1 -1
  59. package/dist/boolean/extrude-helpers.js +13 -13
  60. package/dist/boolean/extrude-helpers.js.map +1 -1
  61. package/dist/brep/brep-ops.d.ts +24 -10
  62. package/dist/brep/brep-ops.d.ts.map +1 -1
  63. package/dist/brep/brep-ops.js +46 -18
  64. package/dist/brep/brep-ops.js.map +1 -1
  65. package/dist/brep/brep-topology.d.ts.map +1 -1
  66. package/dist/brep/brep-topology.js +3 -1
  67. package/dist/brep/brep-topology.js.map +1 -1
  68. package/dist/brep/export/export-model.d.ts +79 -0
  69. package/dist/brep/export/export-model.d.ts.map +1 -0
  70. package/dist/brep/export/export-model.js +335 -0
  71. package/dist/brep/export/export-model.js.map +1 -0
  72. package/dist/brep/primitives-brep.d.ts.map +1 -1
  73. package/dist/brep/primitives-brep.js +3 -1
  74. package/dist/brep/primitives-brep.js.map +1 -1
  75. package/dist/brepkit-kernel/brepkitKernel.d.ts.map +1 -1
  76. package/dist/brepkit-kernel/brepkitKernel.js +4 -2
  77. package/dist/brepkit-kernel/brepkitKernel.js.map +1 -1
  78. package/dist/browser-host/csg-worker-protocol.d.ts +3 -3
  79. package/dist/browser-host/csg-worker-protocol.d.ts.map +1 -1
  80. package/dist/browser-host/csg-worker-protocol.js.map +1 -1
  81. package/dist/browser-host/csg-worker.js +3 -3
  82. package/dist/browser-host/csg-worker.js.map +1 -1
  83. package/dist/browser-host/inline-csg-backend.d.ts +3 -3
  84. package/dist/browser-host/inline-csg-backend.d.ts.map +1 -1
  85. package/dist/browser-host/inline-csg-backend.js +3 -3
  86. package/dist/browser-host/inline-csg-backend.js.map +1 -1
  87. package/dist/browser-host/worker-csg-backend.d.ts +3 -3
  88. package/dist/browser-host/worker-csg-backend.d.ts.map +1 -1
  89. package/dist/browser-host/worker-csg-backend.js.map +1 -1
  90. package/dist/cad-runtime/direct-executor.d.ts +4 -0
  91. package/dist/cad-runtime/direct-executor.d.ts.map +1 -1
  92. package/dist/cad-runtime/direct-executor.js +17 -1
  93. package/dist/cad-runtime/direct-executor.js.map +1 -1
  94. package/dist/cad-runtime/ports.d.ts +3 -3
  95. package/dist/cad-runtime/ports.d.ts.map +1 -1
  96. package/dist/cad-runtime/ports.js.map +1 -1
  97. package/dist/cad-runtime/runtime.d.ts +24 -1
  98. package/dist/cad-runtime/runtime.d.ts.map +1 -1
  99. package/dist/cad-runtime/runtime.js +53 -3
  100. package/dist/cad-runtime/runtime.js.map +1 -1
  101. package/dist/define-op.d.ts +22 -0
  102. package/dist/define-op.d.ts.map +1 -1
  103. package/dist/define-op.js +15 -0
  104. package/dist/define-op.js.map +1 -1
  105. package/dist/env-agnostic.d.ts +7 -7
  106. package/dist/env-agnostic.d.ts.map +1 -1
  107. package/dist/env-agnostic.js +3 -3
  108. package/dist/env-agnostic.js.map +1 -1
  109. package/dist/geometry2d/adapt.d.ts +46 -0
  110. package/dist/geometry2d/adapt.d.ts.map +1 -0
  111. package/dist/geometry2d/adapt.js +41 -0
  112. package/dist/geometry2d/adapt.js.map +1 -0
  113. package/dist/geometry2d/bbox2d.d.ts +82 -0
  114. package/dist/geometry2d/bbox2d.d.ts.map +1 -0
  115. package/dist/geometry2d/bbox2d.js +123 -0
  116. package/dist/geometry2d/bbox2d.js.map +1 -0
  117. package/dist/geometry2d/blueprint-sketcher.d.ts +27 -0
  118. package/dist/geometry2d/blueprint-sketcher.d.ts.map +1 -0
  119. package/dist/geometry2d/blueprint-sketcher.js +29 -0
  120. package/dist/geometry2d/blueprint-sketcher.js.map +1 -0
  121. package/dist/geometry2d/blueprint.d.ts +102 -0
  122. package/dist/geometry2d/blueprint.d.ts.map +1 -0
  123. package/dist/geometry2d/blueprint.js +225 -0
  124. package/dist/geometry2d/blueprint.js.map +1 -0
  125. package/dist/geometry2d/blueprints.d.ts +58 -0
  126. package/dist/geometry2d/blueprints.d.ts.map +1 -0
  127. package/dist/geometry2d/blueprints.js +72 -0
  128. package/dist/geometry2d/blueprints.js.map +1 -0
  129. package/dist/geometry2d/bridge/lift-on-plane.d.ts +50 -0
  130. package/dist/geometry2d/bridge/lift-on-plane.d.ts.map +1 -0
  131. package/dist/geometry2d/bridge/lift-on-plane.js +78 -0
  132. package/dist/geometry2d/bridge/lift-on-plane.js.map +1 -0
  133. package/dist/geometry2d/bridge/on-surface.d.ts +98 -0
  134. package/dist/geometry2d/bridge/on-surface.d.ts.map +1 -0
  135. package/dist/geometry2d/bridge/on-surface.js +94 -0
  136. package/dist/geometry2d/bridge/on-surface.js.map +1 -0
  137. package/dist/geometry2d/bridge/plane.d.ts +69 -0
  138. package/dist/geometry2d/bridge/plane.d.ts.map +1 -0
  139. package/dist/geometry2d/bridge/plane.js +96 -0
  140. package/dist/geometry2d/bridge/plane.js.map +1 -0
  141. package/dist/geometry2d/canned-blueprints.d.ts +44 -0
  142. package/dist/geometry2d/canned-blueprints.d.ts.map +1 -0
  143. package/dist/geometry2d/canned-blueprints.js +94 -0
  144. package/dist/geometry2d/canned-blueprints.js.map +1 -0
  145. package/dist/geometry2d/compound-blueprint.d.ts +72 -0
  146. package/dist/geometry2d/compound-blueprint.d.ts.map +1 -0
  147. package/dist/geometry2d/compound-blueprint.js +95 -0
  148. package/dist/geometry2d/compound-blueprint.js.map +1 -0
  149. package/dist/geometry2d/curve2d.d.ts +298 -0
  150. package/dist/geometry2d/curve2d.d.ts.map +1 -0
  151. package/dist/geometry2d/curve2d.js +1110 -0
  152. package/dist/geometry2d/curve2d.js.map +1 -0
  153. package/dist/geometry2d/index.d.ts +22 -0
  154. package/dist/geometry2d/index.d.ts.map +1 -0
  155. package/dist/geometry2d/index.js +21 -0
  156. package/dist/geometry2d/index.js.map +1 -0
  157. package/dist/geometry2d/organise.d.ts +28 -0
  158. package/dist/geometry2d/organise.d.ts.map +1 -0
  159. package/dist/geometry2d/organise.js +108 -0
  160. package/dist/geometry2d/organise.js.map +1 -0
  161. package/dist/geometry2d/pen-sketcher.d.ts +365 -0
  162. package/dist/geometry2d/pen-sketcher.d.ts.map +1 -0
  163. package/dist/geometry2d/pen-sketcher.js +520 -0
  164. package/dist/geometry2d/pen-sketcher.js.map +1 -0
  165. package/dist/geometry2d/point.d.ts +44 -0
  166. package/dist/geometry2d/point.d.ts.map +1 -0
  167. package/dist/geometry2d/point.js +57 -0
  168. package/dist/geometry2d/point.js.map +1 -0
  169. package/dist/geometry2d/svg-ellipse.d.ts +74 -0
  170. package/dist/geometry2d/svg-ellipse.d.ts.map +1 -0
  171. package/dist/geometry2d/svg-ellipse.js +163 -0
  172. package/dist/geometry2d/svg-ellipse.js.map +1 -0
  173. package/dist/lang/code-to-args.d.ts +29 -3
  174. package/dist/lang/code-to-args.d.ts.map +1 -1
  175. package/dist/lang/code-to-args.js +41 -2
  176. package/dist/lang/code-to-args.js.map +1 -1
  177. package/dist/lang/codegen.d.ts +45 -1
  178. package/dist/lang/codegen.d.ts.map +1 -1
  179. package/dist/lang/codegen.js +135 -6
  180. package/dist/lang/codegen.js.map +1 -1
  181. package/dist/lang/host-arg.d.ts +6 -0
  182. package/dist/lang/host-arg.d.ts.map +1 -1
  183. package/dist/lang/host-arg.js.map +1 -1
  184. package/dist/lang/metadata-extractor.d.ts +25 -0
  185. package/dist/lang/metadata-extractor.d.ts.map +1 -1
  186. package/dist/lang/metadata-extractor.js +289 -25
  187. package/dist/lang/metadata-extractor.js.map +1 -1
  188. package/dist/lang/parse-error.d.ts +7 -1
  189. package/dist/lang/parse-error.d.ts.map +1 -1
  190. package/dist/lang/parse-error.js.map +1 -1
  191. package/dist/lang/security-scanner.d.ts +9 -1
  192. package/dist/lang/security-scanner.d.ts.map +1 -1
  193. package/dist/lang/security-scanner.js +38 -1
  194. package/dist/lang/security-scanner.js.map +1 -1
  195. package/dist/lang/symbol-table.generated.d.ts +3 -0
  196. package/dist/lang/symbol-table.generated.d.ts.map +1 -1
  197. package/dist/lang/symbol-table.generated.js +3 -0
  198. package/dist/lang/symbol-table.generated.js.map +1 -1
  199. package/dist/mesh/io.d.ts +62 -9
  200. package/dist/mesh/io.d.ts.map +1 -1
  201. package/dist/mesh/io.js +124 -17
  202. package/dist/mesh/io.js.map +1 -1
  203. package/dist/mesh/threemf-loader.d.ts +15 -0
  204. package/dist/mesh/threemf-loader.d.ts.map +1 -0
  205. package/dist/mesh/threemf-loader.js +163 -0
  206. package/dist/mesh/threemf-loader.js.map +1 -0
  207. package/dist/mesh/transform.d.ts +2 -2
  208. package/dist/mesh/transform.d.ts.map +1 -1
  209. package/dist/mesh/transform.js +3 -3
  210. package/dist/mesh/transform.js.map +1 -1
  211. package/dist/mesh/types.d.ts +2 -2
  212. package/dist/mesh/types.d.ts.map +1 -1
  213. package/dist/mesh/types.js.map +1 -1
  214. package/dist/node-host/cli.d.ts.map +1 -1
  215. package/dist/node-host/cli.js +53 -26
  216. package/dist/node-host/cli.js.map +1 -1
  217. package/dist/occt-kernel/occtKernel.d.ts.map +1 -1
  218. package/dist/occt-kernel/occtKernel.js +4 -2
  219. package/dist/occt-kernel/occtKernel.js.map +1 -1
  220. package/dist/occt-kernel/topologyExt.d.ts.map +1 -1
  221. package/dist/occt-kernel/topologyExt.js +4 -1
  222. package/dist/occt-kernel/topologyExt.js.map +1 -1
  223. package/dist/runtime-state.d.ts +18 -0
  224. package/dist/runtime-state.d.ts.map +1 -1
  225. package/dist/runtime-state.js +23 -0
  226. package/dist/runtime-state.js.map +1 -1
  227. package/dist/sdk.d.ts +1 -1
  228. package/dist/sdk.d.ts.map +1 -1
  229. package/dist/sdk.js +1 -1
  230. package/dist/sdk.js.map +1 -1
  231. package/dist/tolerance.d.ts +38 -0
  232. package/dist/tolerance.d.ts.map +1 -0
  233. package/dist/tolerance.js +40 -0
  234. package/dist/tolerance.js.map +1 -0
  235. package/dist/topology/naming/score.js +3 -3
  236. package/dist/topology/naming/score.js.map +1 -1
  237. package/dist/units.d.ts +248 -0
  238. package/dist/units.d.ts.map +1 -0
  239. package/dist/units.js +397 -0
  240. package/dist/units.js.map +1 -0
  241. package/package.json +19 -2
@@ -0,0 +1,520 @@
1
+ /**
2
+ * geometry2d — 2D `BaseSketcher2d` pen (C1), adapted for the pure-object base.
3
+ *
4
+ * Ported from brepjs `2d/blueprints/baseSketcher2d.ts` (Apache-2.0).
5
+ *
6
+ * The brepjs original accumulates kernel-backed `Curve2D` handles (mutable:
7
+ * `delete`/`reverse`/`tangentAt`). Here those are replaced by the pure
8
+ * `Curve2dObj` base of `geometry2d/curve2d` — each pen method emits a plain
9
+ * object, the pointer advances by plain arithmetic, and end-tangent lookup maps
10
+ * to `tangentCurve2d`. `curves()`/`close()` return the ordered `Curve2dObj[]`,
11
+ * which feeds `Blueprint` and the 2D→3D placement pipeline.
12
+ *
13
+ * Not-yet-ported (honest `throw`s, per the D-group/port plan):
14
+ * · `ellipse*` — needs the SVG ellipse→arc helper;
15
+ * · `smoothSplit*` — needs the spline control helper;
16
+ * · `customCorner`/`closeWithMirror` — needs 2D corner/mirror ops (D-group).
17
+ *
18
+ * @module
19
+ */
20
+ import { makeLine2d, makeArc2dThreePoints, makeArc2dTangent, makeBezier2d, tangentCurve2d, } from './curve2d.js';
21
+ import { makeEllipseArcFromSvgParams, normalizeEllipseRadii } from './svg-ellipse.js';
22
+ import { distance2d, normalize2d, polarAngle2d, polarToCartesian, samePoint } from './point.js';
23
+ const DEG2RAD = Math.PI / 180;
24
+ const RAD2DEG = 180 / Math.PI;
25
+ /** Guard-style error: throw so callers immediately see pen misuse. */
26
+ function bug(caller, message) {
27
+ throw new Error(`[geometry2d/pen] ${caller}: ${message}`);
28
+ }
29
+ /** Non-normalized tangent at the end of a curve (t=1 within its direct parameter space). */
30
+ function endTangent(c) {
31
+ return tangentCurve2d(c, 1);
32
+ }
33
+ /**
34
+ * Base class for 2D flood-pen sketchers that accumulate `Curve2dObj` segments.
35
+ *
36
+ * Provides the shared pen-drawing API (lines, arcs, beziers) used by the
37
+ * drawing DSL. Subclasses implement `close()` to package the accumulated curves
38
+ * as a `Blueprint` or plain curve list.
39
+ */
40
+ export class BaseSketcher2d {
41
+ /** Current pen position `[x, y]`. */
42
+ pointer;
43
+ /** The starting point of the pen run. */
44
+ firstPoint;
45
+ /** Accumulated segments, in draw order. */
46
+ pendingCurves;
47
+ /** A queued one-shot corner transform (D-group; unused until ported). */
48
+ _nextCorner;
49
+ constructor(origin = [0, 0]) {
50
+ this.pointer = origin;
51
+ this.firstPoint = origin;
52
+ this.pendingCurves = [];
53
+ this._nextCorner = null;
54
+ }
55
+ /**
56
+ * The most recently drawn curve, or `null`.
57
+ * @returns the last drawn curve, or `null` when nothing has been drawn.
58
+ */
59
+ _lastCurve() {
60
+ return this.pendingCurves.length ? this.pendingCurves[this.pendingCurves.length - 1] : null;
61
+ }
62
+ /**
63
+ * Fetch the last drawn curve, or throw a misuse error.
64
+ * @param caller - the calling method name (for the error message).
65
+ * @returns the last curve.
66
+ */
67
+ _requireLastCurve(caller) {
68
+ const c = this._lastCurve();
69
+ if (!c)
70
+ bug(caller, 'You need a previous curve to continue');
71
+ return c;
72
+ }
73
+ /**
74
+ * Add a relative offset to the current pointer.
75
+ * @param xDist - relative x distance.
76
+ * @param yDist - relative y distance.
77
+ * @returns the resulting absolute point.
78
+ */
79
+ _resolveRelative(xDist, yDist) {
80
+ return [this.pointer[0] + xDist, this.pointer[1] + yDist];
81
+ }
82
+ /**
83
+ * Save a curve and advance the pen to `end`.
84
+ * @param curve - the curve to record.
85
+ * @param end - the new pen position.
86
+ * @returns this pen, for chaining.
87
+ */
88
+ _saveCurveAndAdvance(curve, end) {
89
+ this.saveCurve(curve);
90
+ this.pointer = end;
91
+ return this;
92
+ }
93
+ /** The current pen position `[x, y]`. */
94
+ get penPosition() {
95
+ return this.pointer;
96
+ }
97
+ /** The current pen angle in degrees (direction of the last segment's end tangent). */
98
+ get penAngle() {
99
+ const last = this._lastCurve();
100
+ if (!last)
101
+ return 0;
102
+ const [dx, dy] = endTangent(last);
103
+ return Math.atan2(dy, dx) * RAD2DEG;
104
+ }
105
+ /**
106
+ * Move the pen to an absolute position before any segment is drawn.
107
+ * @param point - the absolute start position.
108
+ * @returns this pen, for chaining.
109
+ */
110
+ movePointerTo(point) {
111
+ if (this.pendingCurves.length)
112
+ bug('movePointerTo', 'You can only move the pointer if there is no curve defined');
113
+ this.pointer = point;
114
+ this.firstPoint = point;
115
+ return this;
116
+ }
117
+ /**
118
+ * Record a segment, applying a queued corner transform if present.
119
+ * @param curve - the curve to record.
120
+ */
121
+ saveCurve(curve) {
122
+ if (!this._nextCorner) {
123
+ this.pendingCurves.push(curve);
124
+ return;
125
+ }
126
+ const previous = this.pendingCurves.pop();
127
+ if (!previous)
128
+ bug('saveCurve', 'No previous curve available for custom corner');
129
+ const cornered = this._nextCorner(previous, curve);
130
+ this.pendingCurves.push(...cornered);
131
+ this._nextCorner = null;
132
+ }
133
+ /**
134
+ * Draw a straight line to an absolute point.
135
+ * @param point - the absolute end point.
136
+ * @returns this pen, for chaining.
137
+ */
138
+ lineTo(point) {
139
+ return this._saveCurveAndAdvance(makeLine2d(this.pointer[0], this.pointer[1], point[0], point[1]), point);
140
+ }
141
+ /**
142
+ * Draw a straight line by relative horizontal and vertical distances.
143
+ * @param x - relative x distance.
144
+ * @param y - relative y distance.
145
+ * @returns this pen, for chaining.
146
+ */
147
+ line(x, y) {
148
+ return this.lineTo(this._resolveRelative(x, y));
149
+ }
150
+ /**
151
+ * Draw a vertical line of the given signed distance.
152
+ * @param distance - signed vertical distance.
153
+ * @returns this pen, for chaining.
154
+ */
155
+ vLine(distance) {
156
+ return this.line(0, distance);
157
+ }
158
+ /**
159
+ * Draw a horizontal line of the given signed distance.
160
+ * @param distance - signed horizontal distance.
161
+ * @returns this pen, for chaining.
162
+ */
163
+ hLine(distance) {
164
+ return this.line(distance, 0);
165
+ }
166
+ /**
167
+ * Draw a vertical line to an absolute Y coordinate.
168
+ * @param yPos - the absolute y.
169
+ * @returns this pen, for chaining.
170
+ */
171
+ vLineTo(yPos) {
172
+ return this.lineTo([this.pointer[0], yPos]);
173
+ }
174
+ /**
175
+ * Draw a horizontal line to an absolute X coordinate.
176
+ * @param xPos - the absolute x.
177
+ * @returns this pen, for chaining.
178
+ */
179
+ hLineTo(xPos) {
180
+ return this.lineTo([xPos, this.pointer[1]]);
181
+ }
182
+ /**
183
+ * Draw a whole contour from an explicit point list, in one call.
184
+ *
185
+ * The batched counterpart of a chained `lineTo` run, and the only form that
186
+ * survives the `.fai.js` dialect: the parser caps AST nesting at 100
187
+ * (`SEC_LIMIT`), and a chained call builds a nested
188
+ * `MemberExpression`/`CallExpression` tree whose depth equals the segment count
189
+ * — a contour of a few hundred tessellated points cannot be emitted as
190
+ * `pen.lineTo(a).lineTo(b)…` (measured: a 150-call chain already trips the
191
+ * limit). Handing the points over as ONE array literal keeps the emitted depth
192
+ * constant (array nesting = 2) at any point count.
193
+ *
194
+ * The first point also (re)seats an empty pen, so `firstPoint` keeps its
195
+ * meaning for {@link close} / `movePointerTo`. GOTCHA (2026-09-28):
196
+ * `movePointerTo` refuses to lift the pointer once a curve exists, so ONE pen
197
+ * carries exactly ONE contour — a shape holding many disjoint loops (a rebuilt
198
+ * Draft drawing was measured carrying 12 / 36 / 56 / 61 of them) needs one pen
199
+ * per loop, never one pen with several lifts.
200
+ *
201
+ * @param points - the contour's points in draw order (at least 2).
202
+ * @param close - append a final segment back to `points[0]` (skipped when the
203
+ * run already ended there, mirroring {@link close}).
204
+ * @returns this pen, for chaining.
205
+ */
206
+ polyline(points, close = false) {
207
+ if (points.length < 2)
208
+ bug('polyline', 'a polyline needs at least two points');
209
+ const start = points[0];
210
+ if (this.pendingCurves.length === 0) {
211
+ this.pointer = [start[0], start[1]];
212
+ this.firstPoint = this.pointer;
213
+ }
214
+ else if (!samePoint(this.pointer, start)) {
215
+ bug('polyline', 'a run is already in flight — the pen must be sitting on the polyline start (use one pen per contour)');
216
+ }
217
+ for (let i = 1; i < points.length; i++) {
218
+ const p = points[i];
219
+ this.lineTo([p[0], p[1]]);
220
+ }
221
+ if (close && !samePoint(this.pointer, start))
222
+ this.lineTo([start[0], start[1]]);
223
+ return this;
224
+ }
225
+ /**
226
+ * Draw a line to an absolute point in polar form.
227
+ * @param polar - `[radius, angleDeg]`.
228
+ * @returns this pen, for chaining.
229
+ */
230
+ polarLineTo(polar) {
231
+ const [x, y] = polarToCartesian(polar[0], polar[1] * DEG2RAD);
232
+ return this.lineTo([x, y]);
233
+ }
234
+ /**
235
+ * Draw a line in polar relative form.
236
+ * @param distance - radial distance.
237
+ * @param angle - angle in degrees.
238
+ * @returns this pen, for chaining.
239
+ */
240
+ polarLine(distance, angle) {
241
+ const [x, y] = polarToCartesian(distance, angle * DEG2RAD);
242
+ return this.line(x, y);
243
+ }
244
+ /**
245
+ * Draw a line tangent to the previous curve.
246
+ * @param distance - distance along the tangent.
247
+ * @returns this pen, for chaining.
248
+ */
249
+ tangentLine(distance) {
250
+ const previous = this._requireLastCurve('tangentLine');
251
+ const [dx, dy] = normalize2d(endTangent(previous));
252
+ return this.line(dx * distance, dy * distance);
253
+ }
254
+ /**
255
+ * Draw a circular arc through a mid-point to an absolute end point.
256
+ * @param end - the absolute end point.
257
+ * @param midPoint - a point on the arc.
258
+ * @returns this pen, for chaining.
259
+ */
260
+ threePointsArcTo(end, midPoint) {
261
+ const curve = makeArc2dThreePoints(this.pointer[0], this.pointer[1], midPoint[0], midPoint[1], end[0], end[1]);
262
+ return this._saveCurveAndAdvance(curve, end);
263
+ }
264
+ /**
265
+ * Draw a circular arc through a via-point to an end point, both relative.
266
+ * @param x - relative x end distance.
267
+ * @param y - relative y end distance.
268
+ * @param viaX - relative via x distance.
269
+ * @param viaY - relative via y distance.
270
+ * @returns this pen, for chaining.
271
+ */
272
+ threePointsArc(x, y, viaX, viaY) {
273
+ const [ax, ay] = this.pointer;
274
+ return this.threePointsArcTo([ax + x, ay + y], [ax + viaX, ay + viaY]);
275
+ }
276
+ /**
277
+ * Draw a circular arc to an absolute end, bulging `sagitta` off the chord.
278
+ * @param end - the absolute end point.
279
+ * @param sagitta - the sagitta (signed bulge off the chord).
280
+ * @returns this pen, for chaining.
281
+ */
282
+ sagittaArcTo(end, sagitta) {
283
+ const [x0, y0] = this.pointer;
284
+ const [x1, y1] = end;
285
+ const midX = (x0 + x1) / 2;
286
+ const midY = (y0 + y1) / 2;
287
+ const sX = -(y1 - y0);
288
+ const sY = x1 - x0;
289
+ const sLen = Math.hypot(sX, sY);
290
+ if (sLen < 1e-12)
291
+ bug('sagittaArcTo', 'Start and end points cannot be identical');
292
+ const sag = [midX + (sX / sLen) * sagitta, midY + (sY / sLen) * sagitta];
293
+ return this.threePointsArcTo(end, sag);
294
+ }
295
+ /**
296
+ * Draw a circular arc to a relative end, bulging `sagitta`.
297
+ * @param x - relative x end distance.
298
+ * @param y - relative y end distance.
299
+ * @param sagitta - the sagitta.
300
+ * @returns this pen, for chaining.
301
+ */
302
+ sagittaArc(x, y, sagitta) {
303
+ return this.sagittaArcTo(this._resolveRelative(x, y), sagitta);
304
+ }
305
+ /**
306
+ * Draw a vertical sagitta arc of `distance` and `sagitta`.
307
+ * @param distance - vertical distance.
308
+ * @param sagitta - the sagitta.
309
+ * @returns this pen, for chaining.
310
+ */
311
+ vSagittaArc(distance, sagitta) {
312
+ return this.sagittaArc(0, distance, sagitta);
313
+ }
314
+ /**
315
+ * Draw a horizontal sagitta arc of `distance` and `sagitta`.
316
+ * @param distance - horizontal distance.
317
+ * @param sagitta - the sagitta.
318
+ * @returns this pen, for chaining.
319
+ */
320
+ hSagittaArc(distance, sagitta) {
321
+ return this.sagittaArc(distance, 0, sagitta);
322
+ }
323
+ /**
324
+ * Draw a circular arc to an absolute end via a bulge factor.
325
+ * @param end - the absolute end point.
326
+ * @param bulge - the bulge factor.
327
+ * @returns this pen, for chaining.
328
+ */
329
+ bulgeArcTo(end, bulge) {
330
+ if (!bulge)
331
+ return this.lineTo(end);
332
+ const halfChord = distance2d(this.pointer, end) / 2;
333
+ return this.sagittaArcTo(end, -bulge * halfChord);
334
+ }
335
+ /**
336
+ * Draw a circular arc to a relative end via a bulge factor.
337
+ * @param x - horizontal end distance.
338
+ * @param y - vertical end distance.
339
+ * @param bulge - the bulge factor.
340
+ * @returns this pen, for chaining.
341
+ */
342
+ bulgeArc(x, y, bulge) {
343
+ return this.bulgeArcTo(this._resolveRelative(x, y), bulge);
344
+ }
345
+ /**
346
+ * Draw a vertical bulge arc.
347
+ * @param distance - vertical distance.
348
+ * @param bulge - the bulge factor.
349
+ * @returns this pen, for chaining.
350
+ */
351
+ vBulgeArc(distance, bulge) {
352
+ return this.bulgeArc(0, distance, bulge);
353
+ }
354
+ /**
355
+ * Draw a horizontal bulge arc.
356
+ * @param distance - horizontal distance.
357
+ * @param bulge - the bulge factor.
358
+ * @returns this pen, for chaining.
359
+ */
360
+ hBulgeArc(distance, bulge) {
361
+ return this.bulgeArc(distance, 0, bulge);
362
+ }
363
+ /**
364
+ * Draw a circular arc tangent to the previous curve, ending at `end`.
365
+ * @param end - the absolute end point.
366
+ * @returns this pen, for chaining.
367
+ */
368
+ tangentArcTo(end) {
369
+ const previous = this._requireLastCurve('tangentArc');
370
+ const arc = makeArc2dTangent(this.pointer[0], this.pointer[1], ...endTangent(previous), end[0], end[1]);
371
+ return this._saveCurveAndAdvance(arc, end);
372
+ }
373
+ /**
374
+ * Draw a tangent arc to a relative offset.
375
+ * @param x - horizontal end distance.
376
+ * @param y - vertical end distance.
377
+ * @returns this pen, for chaining.
378
+ */
379
+ tangentArc(x, y) {
380
+ return this.tangentArcTo(this._resolveRelative(x, y));
381
+ }
382
+ /**
383
+ * Draw an elliptical arc (SVG-style endpoint parameters).
384
+ * @param end - the absolute end point.
385
+ * @param horizontalRadius - the horizontal radius.
386
+ * @param verticalRadius - the vertical radius.
387
+ * @param rotation - rotation in degrees.
388
+ * @param longAxis - SVG large-arc flag.
389
+ * @param sweep - SVG sweep flag.
390
+ * @returns this pen, for chaining.
391
+ */
392
+ ellipseTo(end, horizontalRadius, verticalRadius, rotation = 0, longAxis = false, sweep = false) {
393
+ const { majorRadius, minorRadius, rotationAngle } = normalizeEllipseRadii(horizontalRadius, verticalRadius, rotation);
394
+ const arc = makeEllipseArcFromSvgParams(this.pointer, end, majorRadius, minorRadius, rotationAngle, longAxis, sweep);
395
+ return this._saveCurveAndAdvance(arc, end);
396
+ }
397
+ /**
398
+ * Draw an elliptical arc to a relative end point.
399
+ * @param x - relative x end distance.
400
+ * @param y - relative y end distance.
401
+ * @param horizontalRadius - the horizontal radius.
402
+ * @param verticalRadius - the vertical radius.
403
+ * @param rotation - rotation in degrees.
404
+ * @param longAxis - SVG large-arc flag.
405
+ * @param sweep - SVG sweep flag.
406
+ * @returns this pen, for chaining.
407
+ */
408
+ ellipse(x, y, horizontalRadius, verticalRadius, rotation = 0, longAxis = false, sweep = false) {
409
+ return this.ellipseTo(this._resolveRelative(x, y), horizontalRadius, verticalRadius, rotation, longAxis, sweep);
410
+ }
411
+ /**
412
+ * Draw a half-ellipse arc to an absolute end point with a given minor radius.
413
+ * @param end - the absolute end point.
414
+ * @param minorRadius - the minor radius.
415
+ * @param sweep - SVG sweep flag.
416
+ * @returns this pen, for chaining.
417
+ */
418
+ halfEllipseTo(end, minorRadius, sweep = false) {
419
+ const angle = polarAngle2d(end, this.pointer);
420
+ const dist = distance2d(end, this.pointer);
421
+ return this.ellipseTo(end, dist / 2, minorRadius, angle * RAD2DEG, true, sweep);
422
+ }
423
+ /**
424
+ * Draw a half-ellipse arc to a relative end point with a given minor radius.
425
+ * @param x - relative x end distance.
426
+ * @param y - relative y end distance.
427
+ * @param minorRadius - the minor radius.
428
+ * @param sweep - SVG sweep flag.
429
+ * @returns this pen, for chaining.
430
+ */
431
+ halfEllipse(x, y, minorRadius, sweep = false) {
432
+ return this.halfEllipseTo(this._resolveRelative(x, y), minorRadius, sweep);
433
+ }
434
+ /**
435
+ * Draw a Bezier curve to an absolute end through control points.
436
+ * @param end - the absolute end point.
437
+ * @param controlPoints - one control point (quadratic) or two (cubic).
438
+ * @returns this pen, for chaining.
439
+ */
440
+ bezierCurveTo(end, controlPoints) {
441
+ const poles = [[this.pointer[0], this.pointer[1]], ...controlPoints, [end[0], end[1]]];
442
+ return this._saveCurveAndAdvance(makeBezier2d(poles), end);
443
+ }
444
+ /**
445
+ * Draw a quadratic Bezier to an absolute end point.
446
+ * @param end - the absolute end point.
447
+ * @param controlPoint - the single control point.
448
+ * @returns this pen, for chaining.
449
+ */
450
+ quadraticBezierCurveTo(end, controlPoint) {
451
+ return this.bezierCurveTo(end, [controlPoint]);
452
+ }
453
+ /**
454
+ * Draw a cubic Bezier to an absolute end point.
455
+ * @param end - the absolute end point.
456
+ * @param startControlPoint - the start control point.
457
+ * @param endControlPoint - the end control point.
458
+ * @returns this pen, for chaining.
459
+ */
460
+ cubicBezierCurveTo(end, startControlPoint, endControlPoint) {
461
+ return this.bezierCurveTo(end, [startControlPoint, endControlPoint]);
462
+ }
463
+ /**
464
+ * Draw a smooth cubic spline to an absolute end point.
465
+ * @param _end - the absolute end point.
466
+ * @param _config - spline smoothing options.
467
+ * @returns this pen, for chaining.
468
+ * @throws not yet ported (needs the spline control helper).
469
+ */
470
+ smoothSplineTo(_end, _config) {
471
+ throw new Error('[geometry2d/pen] smoothSplineTo is not yet ported');
472
+ }
473
+ /**
474
+ * Draw a smooth cubic spline to a relative end point.
475
+ * @param _x - relative x end distance.
476
+ * @param _y - relative y end distance.
477
+ * @param _config - spline smoothing options.
478
+ * @returns this pen, for chaining.
479
+ * @throws not yet ported (needs the spline control helper).
480
+ */
481
+ smoothSpline(_x, _y, _config) {
482
+ throw new Error('[geometry2d/pen] smoothSpline is not yet ported');
483
+ }
484
+ /**
485
+ * Change the corner between the previous and next segment.
486
+ * @param _radius - the corner radius.
487
+ * @param _mode - the corner kind.
488
+ * @returns this pen, for chaining.
489
+ * @throws D-group corner ops (fillet/chamfer/dogbone) are not yet ported.
490
+ */
491
+ customCorner(_radius, _mode = 'fillet') {
492
+ throw new Error('[geometry2d/pen] customCorner: D-group corner ops are not yet ported');
493
+ }
494
+ /**
495
+ * Close the sketch by drawing a final segment back to the start.
496
+ * @returns the closed, ordered curve list.
497
+ */
498
+ close() {
499
+ if (!samePoint(this.pointer, this.firstPoint)) {
500
+ this.lineTo(this.firstPoint);
501
+ }
502
+ return [...this.pendingCurves];
503
+ }
504
+ /**
505
+ * Close by mirroring the drawn segments across the start→current chord.
506
+ * @returns the closed, mirror-augmented curve list.
507
+ * @throws not yet ported (needs the curve-mirror transform).
508
+ */
509
+ closeWithMirror() {
510
+ throw new Error('[geometry2d/pen] closeWithMirror is not yet ported');
511
+ }
512
+ /**
513
+ * The ordered drawn curve list (no implicit close).
514
+ * @returns the drawn segments in draw order.
515
+ */
516
+ curves() {
517
+ return [...this.pendingCurves];
518
+ }
519
+ }
520
+ //# sourceMappingURL=pen-sketcher.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pen-sketcher.js","sourceRoot":"","sources":["../../src/geometry2d/pen-sketcher.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * geometry2d — 2D `BaseSketcher2d` pen (C1), adapted for the pure-object base.\n *\n * Ported from brepjs `2d/blueprints/baseSketcher2d.ts` (Apache-2.0).\n *\n * The brepjs original accumulates kernel-backed `Curve2D` handles (mutable:\n * `delete`/`reverse`/`tangentAt`). Here those are replaced by the pure\n * `Curve2dObj` base of `geometry2d/curve2d` — each pen method emits a plain\n * object, the pointer advances by plain arithmetic, and end-tangent lookup maps\n * to `tangentCurve2d`. `curves()`/`close()` return the ordered `Curve2dObj[]`,\n * which feeds `Blueprint` and the 2D→3D placement pipeline.\n *\n * Not-yet-ported (honest `throw`s, per the D-group/port plan):\n * · `ellipse*` — needs the SVG ellipse→arc helper;\n * · `smoothSplit*` — needs the spline control helper;\n * · `customCorner`/`closeWithMirror` — needs 2D corner/mirror ops (D-group).\n *\n * @module\n */\n\nimport {\n makeLine2d,\n makeArc2dThreePoints,\n makeArc2dTangent,\n makeBezier2d,\n tangentCurve2d,\n type Curve2dObj,\n} from './curve2d'\nimport { makeEllipseArcFromSvgParams, normalizeEllipseRadii } from './svg-ellipse'\nimport { distance2d, normalize2d, polarAngle2d, polarToCartesian, samePoint } from './point'\n\nconst DEG2RAD = Math.PI / 180\nconst RAD2DEG = 180 / Math.PI\n\n/** A `[x, y]` 2D point (plain tuple). */\nexport type Point2 = [number, number]\n\n/** Options accepted by the spline methods. */\nexport type SplineOptions = {\n /** Explicit start tangent; defaults to `[1,0]` or the previous segment's end tangent. */\n startTangent?: Point2\n /** Explicit end tangent, or the literal `'symmetric'` (mirror of the start tangent). */\n endTangent?: Point2 | 'symmetric'\n /** Start control-length factor. */\n startFactor?: number\n /** End control-length factor. */\n endFactor?: number\n}\n\n/** Corner modes accepted by `customCorner` (D-group, not yet ported). */\nexport type CornerMode = 'fillet' | 'chamfer' | 'dogbone'\n\n/** Guard-style error: throw so callers immediately see pen misuse. */\nfunction bug(caller: string, message: string): never {\n throw new Error(`[geometry2d/pen] ${caller}: ${message}`)\n}\n\n/** Non-normalized tangent at the end of a curve (t=1 within its direct parameter space). */\nfunction endTangent(c: Curve2dObj): [number, number] {\n return tangentCurve2d(c, 1)\n}\n\n/**\n * Base class for 2D flood-pen sketchers that accumulate `Curve2dObj` segments.\n *\n * Provides the shared pen-drawing API (lines, arcs, beziers) used by the\n * drawing DSL. Subclasses implement `close()` to package the accumulated curves\n * as a `Blueprint` or plain curve list.\n */\nexport class BaseSketcher2d {\n /** Current pen position `[x, y]`. */\n pointer: Point2\n /** The starting point of the pen run. */\n firstPoint: Point2\n /** Accumulated segments, in draw order. */\n pendingCurves: Curve2dObj[]\n /** A queued one-shot corner transform (D-group; unused until ported). */\n _nextCorner: ((a: Curve2dObj, b: Curve2dObj) => Curve2dObj[]) | null\n\n constructor(origin: Point2 = [0, 0]) {\n this.pointer = origin\n this.firstPoint = origin\n this.pendingCurves = []\n this._nextCorner = null\n }\n\n /**\n * The most recently drawn curve, or `null`.\n * @returns the last drawn curve, or `null` when nothing has been drawn.\n */\n _lastCurve(): Curve2dObj | null {\n return this.pendingCurves.length ? this.pendingCurves[this.pendingCurves.length - 1]! : null\n }\n\n /**\n * Fetch the last drawn curve, or throw a misuse error.\n * @param caller - the calling method name (for the error message).\n * @returns the last curve.\n */\n _requireLastCurve(caller: string): Curve2dObj {\n const c = this._lastCurve()\n if (!c) bug(caller, 'You need a previous curve to continue')\n return c\n }\n\n /**\n * Add a relative offset to the current pointer.\n * @param xDist - relative x distance.\n * @param yDist - relative y distance.\n * @returns the resulting absolute point.\n */\n _resolveRelative(xDist: number, yDist: number): Point2 {\n return [this.pointer[0] + xDist, this.pointer[1] + yDist]\n }\n\n /**\n * Save a curve and advance the pen to `end`.\n * @param curve - the curve to record.\n * @param end - the new pen position.\n * @returns this pen, for chaining.\n */\n _saveCurveAndAdvance(curve: Curve2dObj, end: Point2): this {\n this.saveCurve(curve)\n this.pointer = end\n return this\n }\n\n /** The current pen position `[x, y]`. */\n get penPosition(): Point2 {\n return this.pointer\n }\n\n /** The current pen angle in degrees (direction of the last segment's end tangent). */\n get penAngle(): number {\n const last = this._lastCurve()\n if (!last) return 0\n const [dx, dy] = endTangent(last)\n return Math.atan2(dy, dx) * RAD2DEG\n }\n\n /**\n * Move the pen to an absolute position before any segment is drawn.\n * @param point - the absolute start position.\n * @returns this pen, for chaining.\n */\n movePointerTo(point: Point2): this {\n if (this.pendingCurves.length) bug('movePointerTo', 'You can only move the pointer if there is no curve defined')\n this.pointer = point\n this.firstPoint = point\n return this\n }\n\n /**\n * Record a segment, applying a queued corner transform if present.\n * @param curve - the curve to record.\n */\n saveCurve(curve: Curve2dObj): void {\n if (!this._nextCorner) {\n this.pendingCurves.push(curve)\n return\n }\n const previous = this.pendingCurves.pop()\n if (!previous) bug('saveCurve', 'No previous curve available for custom corner')\n const cornered = this._nextCorner!(previous, curve)\n this.pendingCurves.push(...cornered)\n this._nextCorner = null\n }\n\n /**\n * Draw a straight line to an absolute point.\n * @param point - the absolute end point.\n * @returns this pen, for chaining.\n */\n lineTo(point: Point2): this {\n return this._saveCurveAndAdvance(makeLine2d(this.pointer[0], this.pointer[1], point[0], point[1]), point)\n }\n\n /**\n * Draw a straight line by relative horizontal and vertical distances.\n * @param x - relative x distance.\n * @param y - relative y distance.\n * @returns this pen, for chaining.\n */\n line(x: number, y: number): this {\n return this.lineTo(this._resolveRelative(x, y))\n }\n\n /**\n * Draw a vertical line of the given signed distance.\n * @param distance - signed vertical distance.\n * @returns this pen, for chaining.\n */\n vLine(distance: number): this {\n return this.line(0, distance)\n }\n\n /**\n * Draw a horizontal line of the given signed distance.\n * @param distance - signed horizontal distance.\n * @returns this pen, for chaining.\n */\n hLine(distance: number): this {\n return this.line(distance, 0)\n }\n\n /**\n * Draw a vertical line to an absolute Y coordinate.\n * @param yPos - the absolute y.\n * @returns this pen, for chaining.\n */\n vLineTo(yPos: number): this {\n return this.lineTo([this.pointer[0], yPos])\n }\n\n /**\n * Draw a horizontal line to an absolute X coordinate.\n * @param xPos - the absolute x.\n * @returns this pen, for chaining.\n */\n hLineTo(xPos: number): this {\n return this.lineTo([xPos, this.pointer[1]])\n }\n\n /**\n * Draw a whole contour from an explicit point list, in one call.\n *\n * The batched counterpart of a chained `lineTo` run, and the only form that\n * survives the `.fai.js` dialect: the parser caps AST nesting at 100\n * (`SEC_LIMIT`), and a chained call builds a nested\n * `MemberExpression`/`CallExpression` tree whose depth equals the segment count\n * — a contour of a few hundred tessellated points cannot be emitted as\n * `pen.lineTo(a).lineTo(b)…` (measured: a 150-call chain already trips the\n * limit). Handing the points over as ONE array literal keeps the emitted depth\n * constant (array nesting = 2) at any point count.\n *\n * The first point also (re)seats an empty pen, so `firstPoint` keeps its\n * meaning for {@link close} / `movePointerTo`. GOTCHA (2026-09-28):\n * `movePointerTo` refuses to lift the pointer once a curve exists, so ONE pen\n * carries exactly ONE contour — a shape holding many disjoint loops (a rebuilt\n * Draft drawing was measured carrying 12 / 36 / 56 / 61 of them) needs one pen\n * per loop, never one pen with several lifts.\n *\n * @param points - the contour's points in draw order (at least 2).\n * @param close - append a final segment back to `points[0]` (skipped when the\n * run already ended there, mirroring {@link close}).\n * @returns this pen, for chaining.\n */\n polyline(points: Point2[], close = false): this {\n if (points.length < 2) bug('polyline', 'a polyline needs at least two points')\n const start = points[0]!\n if (this.pendingCurves.length === 0) {\n this.pointer = [start[0], start[1]]\n this.firstPoint = this.pointer\n } else if (!samePoint(this.pointer, start)) {\n bug(\n 'polyline',\n 'a run is already in flight — the pen must be sitting on the polyline start (use one pen per contour)',\n )\n }\n for (let i = 1; i < points.length; i++) {\n const p = points[i]!\n this.lineTo([p[0], p[1]])\n }\n if (close && !samePoint(this.pointer, start)) this.lineTo([start[0], start[1]])\n return this\n }\n\n /**\n * Draw a line to an absolute point in polar form.\n * @param polar - `[radius, angleDeg]`.\n * @returns this pen, for chaining.\n */\n polarLineTo(polar: Point2): this {\n const [x, y] = polarToCartesian(polar[0], polar[1] * DEG2RAD)\n return this.lineTo([x, y])\n }\n\n /**\n * Draw a line in polar relative form.\n * @param distance - radial distance.\n * @param angle - angle in degrees.\n * @returns this pen, for chaining.\n */\n polarLine(distance: number, angle: number): this {\n const [x, y] = polarToCartesian(distance, angle * DEG2RAD)\n return this.line(x, y)\n }\n\n /**\n * Draw a line tangent to the previous curve.\n * @param distance - distance along the tangent.\n * @returns this pen, for chaining.\n */\n tangentLine(distance: number): this {\n const previous = this._requireLastCurve('tangentLine')\n const [dx, dy] = normalize2d(endTangent(previous))\n return this.line(dx * distance, dy * distance)\n }\n\n /**\n * Draw a circular arc through a mid-point to an absolute end point.\n * @param end - the absolute end point.\n * @param midPoint - a point on the arc.\n * @returns this pen, for chaining.\n */\n threePointsArcTo(end: Point2, midPoint: Point2): this {\n const curve = makeArc2dThreePoints(this.pointer[0], this.pointer[1], midPoint[0], midPoint[1], end[0], end[1])\n return this._saveCurveAndAdvance(curve, end)\n }\n\n /**\n * Draw a circular arc through a via-point to an end point, both relative.\n * @param x - relative x end distance.\n * @param y - relative y end distance.\n * @param viaX - relative via x distance.\n * @param viaY - relative via y distance.\n * @returns this pen, for chaining.\n */\n threePointsArc(x: number, y: number, viaX: number, viaY: number): this {\n const [ax, ay] = this.pointer\n return this.threePointsArcTo([ax + x, ay + y], [ax + viaX, ay + viaY])\n }\n\n /**\n * Draw a circular arc to an absolute end, bulging `sagitta` off the chord.\n * @param end - the absolute end point.\n * @param sagitta - the sagitta (signed bulge off the chord).\n * @returns this pen, for chaining.\n */\n sagittaArcTo(end: Point2, sagitta: number): this {\n const [x0, y0] = this.pointer\n const [x1, y1] = end\n const midX = (x0 + x1) / 2\n const midY = (y0 + y1) / 2\n const sX = -(y1 - y0)\n const sY = x1 - x0\n const sLen = Math.hypot(sX, sY)\n if (sLen < 1e-12) bug('sagittaArcTo', 'Start and end points cannot be identical')\n const sag: Point2 = [midX + (sX / sLen) * sagitta, midY + (sY / sLen) * sagitta]\n return this.threePointsArcTo(end, sag)\n }\n\n /**\n * Draw a circular arc to a relative end, bulging `sagitta`.\n * @param x - relative x end distance.\n * @param y - relative y end distance.\n * @param sagitta - the sagitta.\n * @returns this pen, for chaining.\n */\n sagittaArc(x: number, y: number, sagitta: number): this {\n return this.sagittaArcTo(this._resolveRelative(x, y), sagitta)\n }\n\n /**\n * Draw a vertical sagitta arc of `distance` and `sagitta`.\n * @param distance - vertical distance.\n * @param sagitta - the sagitta.\n * @returns this pen, for chaining.\n */\n vSagittaArc(distance: number, sagitta: number): this {\n return this.sagittaArc(0, distance, sagitta)\n }\n\n /**\n * Draw a horizontal sagitta arc of `distance` and `sagitta`.\n * @param distance - horizontal distance.\n * @param sagitta - the sagitta.\n * @returns this pen, for chaining.\n */\n hSagittaArc(distance: number, sagitta: number): this {\n return this.sagittaArc(distance, 0, sagitta)\n }\n\n /**\n * Draw a circular arc to an absolute end via a bulge factor.\n * @param end - the absolute end point.\n * @param bulge - the bulge factor.\n * @returns this pen, for chaining.\n */\n bulgeArcTo(end: Point2, bulge: number): this {\n if (!bulge) return this.lineTo(end)\n const halfChord = distance2d(this.pointer, end) / 2\n return this.sagittaArcTo(end, -bulge * halfChord)\n }\n\n /**\n * Draw a circular arc to a relative end via a bulge factor.\n * @param x - horizontal end distance.\n * @param y - vertical end distance.\n * @param bulge - the bulge factor.\n * @returns this pen, for chaining.\n */\n bulgeArc(x: number, y: number, bulge: number): this {\n return this.bulgeArcTo(this._resolveRelative(x, y), bulge)\n }\n\n /**\n * Draw a vertical bulge arc.\n * @param distance - vertical distance.\n * @param bulge - the bulge factor.\n * @returns this pen, for chaining.\n */\n vBulgeArc(distance: number, bulge: number): this {\n return this.bulgeArc(0, distance, bulge)\n }\n\n /**\n * Draw a horizontal bulge arc.\n * @param distance - horizontal distance.\n * @param bulge - the bulge factor.\n * @returns this pen, for chaining.\n */\n hBulgeArc(distance: number, bulge: number): this {\n return this.bulgeArc(distance, 0, bulge)\n }\n\n /**\n * Draw a circular arc tangent to the previous curve, ending at `end`.\n * @param end - the absolute end point.\n * @returns this pen, for chaining.\n */\n tangentArcTo(end: Point2): this {\n const previous = this._requireLastCurve('tangentArc')\n const arc = makeArc2dTangent(this.pointer[0], this.pointer[1], ...endTangent(previous), end[0], end[1])\n return this._saveCurveAndAdvance(arc, end)\n }\n\n /**\n * Draw a tangent arc to a relative offset.\n * @param x - horizontal end distance.\n * @param y - vertical end distance.\n * @returns this pen, for chaining.\n */\n tangentArc(x: number, y: number): this {\n return this.tangentArcTo(this._resolveRelative(x, y))\n }\n\n /**\n * Draw an elliptical arc (SVG-style endpoint parameters).\n * @param end - the absolute end point.\n * @param horizontalRadius - the horizontal radius.\n * @param verticalRadius - the vertical radius.\n * @param rotation - rotation in degrees.\n * @param longAxis - SVG large-arc flag.\n * @param sweep - SVG sweep flag.\n * @returns this pen, for chaining.\n */\n ellipseTo(end: Point2, horizontalRadius: number, verticalRadius: number, rotation = 0, longAxis = false, sweep = false): this {\n const { majorRadius, minorRadius, rotationAngle } = normalizeEllipseRadii(horizontalRadius, verticalRadius, rotation)\n const arc = makeEllipseArcFromSvgParams(this.pointer, end, majorRadius, minorRadius, rotationAngle, longAxis, sweep)\n return this._saveCurveAndAdvance(arc, end)\n }\n\n /**\n * Draw an elliptical arc to a relative end point.\n * @param x - relative x end distance.\n * @param y - relative y end distance.\n * @param horizontalRadius - the horizontal radius.\n * @param verticalRadius - the vertical radius.\n * @param rotation - rotation in degrees.\n * @param longAxis - SVG large-arc flag.\n * @param sweep - SVG sweep flag.\n * @returns this pen, for chaining.\n */\n ellipse(x: number, y: number, horizontalRadius: number, verticalRadius: number, rotation = 0, longAxis = false, sweep = false): this {\n return this.ellipseTo(this._resolveRelative(x, y), horizontalRadius, verticalRadius, rotation, longAxis, sweep)\n }\n\n /**\n * Draw a half-ellipse arc to an absolute end point with a given minor radius.\n * @param end - the absolute end point.\n * @param minorRadius - the minor radius.\n * @param sweep - SVG sweep flag.\n * @returns this pen, for chaining.\n */\n halfEllipseTo(end: Point2, minorRadius: number, sweep = false): this {\n const angle = polarAngle2d(end, this.pointer)\n const dist = distance2d(end, this.pointer)\n return this.ellipseTo(end, dist / 2, minorRadius, angle * RAD2DEG, true, sweep)\n }\n\n /**\n * Draw a half-ellipse arc to a relative end point with a given minor radius.\n * @param x - relative x end distance.\n * @param y - relative y end distance.\n * @param minorRadius - the minor radius.\n * @param sweep - SVG sweep flag.\n * @returns this pen, for chaining.\n */\n halfEllipse(x: number, y: number, minorRadius: number, sweep = false): this {\n return this.halfEllipseTo(this._resolveRelative(x, y), minorRadius, sweep)\n }\n\n /**\n * Draw a Bezier curve to an absolute end through control points.\n * @param end - the absolute end point.\n * @param controlPoints - one control point (quadratic) or two (cubic).\n * @returns this pen, for chaining.\n */\n bezierCurveTo(end: Point2, controlPoints: Point2[]): this {\n const poles: [number, number][] = [[this.pointer[0], this.pointer[1]], ...controlPoints, [end[0], end[1]]]\n return this._saveCurveAndAdvance(makeBezier2d(poles), end)\n }\n\n /**\n * Draw a quadratic Bezier to an absolute end point.\n * @param end - the absolute end point.\n * @param controlPoint - the single control point.\n * @returns this pen, for chaining.\n */\n quadraticBezierCurveTo(end: Point2, controlPoint: Point2): this {\n return this.bezierCurveTo(end, [controlPoint])\n }\n\n /**\n * Draw a cubic Bezier to an absolute end point.\n * @param end - the absolute end point.\n * @param startControlPoint - the start control point.\n * @param endControlPoint - the end control point.\n * @returns this pen, for chaining.\n */\n cubicBezierCurveTo(end: Point2, startControlPoint: Point2, endControlPoint: Point2): this {\n return this.bezierCurveTo(end, [startControlPoint, endControlPoint])\n }\n\n /**\n * Draw a smooth cubic spline to an absolute end point.\n * @param _end - the absolute end point.\n * @param _config - spline smoothing options.\n * @returns this pen, for chaining.\n * @throws not yet ported (needs the spline control helper).\n */\n smoothSplineTo(_end: Point2, _config?: SplineOptions): this {\n throw new Error('[geometry2d/pen] smoothSplineTo is not yet ported')\n }\n\n /**\n * Draw a smooth cubic spline to a relative end point.\n * @param _x - relative x end distance.\n * @param _y - relative y end distance.\n * @param _config - spline smoothing options.\n * @returns this pen, for chaining.\n * @throws not yet ported (needs the spline control helper).\n */\n smoothSpline(_x: number, _y: number, _config?: SplineOptions): this {\n throw new Error('[geometry2d/pen] smoothSpline is not yet ported')\n }\n\n /**\n * Change the corner between the previous and next segment.\n * @param _radius - the corner radius.\n * @param _mode - the corner kind.\n * @returns this pen, for chaining.\n * @throws D-group corner ops (fillet/chamfer/dogbone) are not yet ported.\n */\n customCorner(_radius: number, _mode: CornerMode = 'fillet'): this {\n throw new Error('[geometry2d/pen] customCorner: D-group corner ops are not yet ported')\n }\n\n /**\n * Close the sketch by drawing a final segment back to the start.\n * @returns the closed, ordered curve list.\n */\n close(): Curve2dObj[] {\n if (!samePoint(this.pointer, this.firstPoint)) {\n this.lineTo(this.firstPoint)\n }\n return [...this.pendingCurves]\n }\n\n /**\n * Close by mirroring the drawn segments across the start→current chord.\n * @returns the closed, mirror-augmented curve list.\n * @throws not yet ported (needs the curve-mirror transform).\n */\n closeWithMirror(): Curve2dObj[] {\n throw new Error('[geometry2d/pen] closeWithMirror is not yet ported')\n }\n\n /**\n * The ordered drawn curve list (no implicit close).\n * @returns the drawn segments in draw order.\n */\n curves(): Curve2dObj[] {\n return [...this.pendingCurves]\n }\n}"]}
@@ -0,0 +1,44 @@
1
+ /**
2
+ * geometry2d — small 2D point / vector helpers shared by the sketcher pens and
3
+ * the draw package. Pure TS, zero dependency.
4
+ *
5
+ * Ported from brepjs `2d/lib`-style utilities (Apache-2.0).
6
+ *
7
+ * @module
8
+ */
9
+ /**
10
+ * Euclidean distance between two 2D points.
11
+ * @param a - first point.
12
+ * @param b - second point.
13
+ * @returns the distance.
14
+ */
15
+ export declare function distance2d(a: readonly [number, number], b: readonly [number, number]): number;
16
+ /**
17
+ * True when two 2D points coincide within `eps`.
18
+ * @param a - first point.
19
+ * @param b - second point.
20
+ * @param eps - coincidence tolerance (default 1e-9).
21
+ * @returns whether `a` and `b` are the same point.
22
+ */
23
+ export declare function samePoint(a: readonly [number, number], b: readonly [number, number], eps?: number): boolean;
24
+ /**
25
+ * Convert polar `[r, theta]` (radians) to Cartesian `[x, y]`.
26
+ * @param r - radial distance.
27
+ * @param theta - angle in radians.
28
+ * @returns the Cartesian point.
29
+ */
30
+ export declare function polarToCartesian(r: number, theta: number): [number, number];
31
+ /**
32
+ * Normalize a 2D vector to unit length.
33
+ * @param v - the input vector.
34
+ * @returns the unit vector (the zero vector normalizes to `[1,0]`).
35
+ */
36
+ export declare function normalize2d(v: readonly [number, number]): [number, number];
37
+ /**
38
+ * Absolute polar angle of `b` relative to `a`.
39
+ * @param a - the reference point.
40
+ * @param b - the target point.
41
+ * @returns the angle in radians, in `[0, 2π)`.
42
+ */
43
+ export declare function polarAngle2d(a: readonly [number, number], b: readonly [number, number]): number;
44
+ //# sourceMappingURL=point.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"point.d.ts","sourceRoot":"","sources":["../../src/geometry2d/point.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH;;;;;GAKG;AACH,wBAAgB,UAAU,CAAC,CAAC,EAAE,SAAS,CAAC,MAAM,EAAE,MAAM,CAAC,EAAE,CAAC,EAAE,SAAS,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,MAAM,CAE7F;AAED;;;;;;GAMG;AACH,wBAAgB,SAAS,CAAC,CAAC,EAAE,SAAS,CAAC,MAAM,EAAE,MAAM,CAAC,EAAE,CAAC,EAAE,SAAS,CAAC,MAAM,EAAE,MAAM,CAAC,EAAE,GAAG,SAAO,GAAG,OAAO,CAEzG;AAED;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAAC,CAAC,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAE3E;AAED;;;;GAIG;AACH,wBAAgB,WAAW,CAAC,CAAC,EAAE,SAAS,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAI1E;AAED;;;;;GAKG;AACH,wBAAgB,YAAY,CAAC,CAAC,EAAE,SAAS,CAAC,MAAM,EAAE,MAAM,CAAC,EAAE,CAAC,EAAE,SAAS,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,MAAM,CAE/F"}