@faicad/faijs 0.18.3 → 0.19.0

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 (129) 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 +19 -19
  7. package/dist/api/brep-mirror/joinery-brep.js.map +1 -1
  8. package/dist/api/index.d.ts +4 -0
  9. package/dist/api/index.d.ts.map +1 -1
  10. package/dist/api/index.js +3 -0
  11. package/dist/api/index.js.map +1 -1
  12. package/dist/api/profile.d.ts.map +1 -1
  13. package/dist/api/profile.js +113 -182
  14. package/dist/api/profile.js.map +1 -1
  15. package/dist/api/punch-hole.d.ts +74 -0
  16. package/dist/api/punch-hole.d.ts.map +1 -0
  17. package/dist/api/punch-hole.js +207 -0
  18. package/dist/api/punch-hole.js.map +1 -0
  19. package/dist/api/sketch-on-face.d.ts +85 -0
  20. package/dist/api/sketch-on-face.d.ts.map +1 -0
  21. package/dist/api/sketch-on-face.js +136 -0
  22. package/dist/api/sketch-on-face.js.map +1 -0
  23. package/dist/api/sketch-on-plane.d.ts +81 -0
  24. package/dist/api/sketch-on-plane.d.ts.map +1 -0
  25. package/dist/api/sketch-on-plane.js +103 -0
  26. package/dist/api/sketch-on-plane.js.map +1 -0
  27. package/dist/boolean/csg-backend.d.ts +6 -6
  28. package/dist/boolean/csg-backend.d.ts.map +1 -1
  29. package/dist/boolean/csg-backend.js +9 -9
  30. package/dist/boolean/csg-backend.js.map +1 -1
  31. package/dist/boolean/csg-core.d.ts +10 -10
  32. package/dist/boolean/csg-core.d.ts.map +1 -1
  33. package/dist/boolean/csg-core.js +24 -24
  34. package/dist/boolean/csg-core.js.map +1 -1
  35. package/dist/boolean/extrude-helpers.d.ts +8 -8
  36. package/dist/boolean/extrude-helpers.d.ts.map +1 -1
  37. package/dist/boolean/extrude-helpers.js +13 -13
  38. package/dist/boolean/extrude-helpers.js.map +1 -1
  39. package/dist/brep/brep-ops.d.ts +20 -6
  40. package/dist/brep/brep-ops.d.ts.map +1 -1
  41. package/dist/brep/brep-ops.js +38 -12
  42. package/dist/brep/brep-ops.js.map +1 -1
  43. package/dist/browser-host/csg-worker-protocol.d.ts +3 -3
  44. package/dist/browser-host/csg-worker-protocol.d.ts.map +1 -1
  45. package/dist/browser-host/csg-worker-protocol.js.map +1 -1
  46. package/dist/browser-host/csg-worker.js +3 -3
  47. package/dist/browser-host/csg-worker.js.map +1 -1
  48. package/dist/browser-host/inline-csg-backend.d.ts +3 -3
  49. package/dist/browser-host/inline-csg-backend.d.ts.map +1 -1
  50. package/dist/browser-host/inline-csg-backend.js +3 -3
  51. package/dist/browser-host/inline-csg-backend.js.map +1 -1
  52. package/dist/browser-host/worker-csg-backend.d.ts +3 -3
  53. package/dist/browser-host/worker-csg-backend.d.ts.map +1 -1
  54. package/dist/browser-host/worker-csg-backend.js.map +1 -1
  55. package/dist/cad-runtime/ports.d.ts +3 -3
  56. package/dist/cad-runtime/ports.d.ts.map +1 -1
  57. package/dist/cad-runtime/ports.js.map +1 -1
  58. package/dist/geometry2d/adapt.d.ts +46 -0
  59. package/dist/geometry2d/adapt.d.ts.map +1 -0
  60. package/dist/geometry2d/adapt.js +41 -0
  61. package/dist/geometry2d/adapt.js.map +1 -0
  62. package/dist/geometry2d/bbox2d.d.ts +82 -0
  63. package/dist/geometry2d/bbox2d.d.ts.map +1 -0
  64. package/dist/geometry2d/bbox2d.js +123 -0
  65. package/dist/geometry2d/bbox2d.js.map +1 -0
  66. package/dist/geometry2d/blueprint-sketcher.d.ts +27 -0
  67. package/dist/geometry2d/blueprint-sketcher.d.ts.map +1 -0
  68. package/dist/geometry2d/blueprint-sketcher.js +29 -0
  69. package/dist/geometry2d/blueprint-sketcher.js.map +1 -0
  70. package/dist/geometry2d/blueprint.d.ts +102 -0
  71. package/dist/geometry2d/blueprint.d.ts.map +1 -0
  72. package/dist/geometry2d/blueprint.js +225 -0
  73. package/dist/geometry2d/blueprint.js.map +1 -0
  74. package/dist/geometry2d/blueprints.d.ts +58 -0
  75. package/dist/geometry2d/blueprints.d.ts.map +1 -0
  76. package/dist/geometry2d/blueprints.js +72 -0
  77. package/dist/geometry2d/blueprints.js.map +1 -0
  78. package/dist/geometry2d/bridge/lift-on-plane.d.ts +50 -0
  79. package/dist/geometry2d/bridge/lift-on-plane.d.ts.map +1 -0
  80. package/dist/geometry2d/bridge/lift-on-plane.js +72 -0
  81. package/dist/geometry2d/bridge/lift-on-plane.js.map +1 -0
  82. package/dist/geometry2d/bridge/on-surface.d.ts +98 -0
  83. package/dist/geometry2d/bridge/on-surface.d.ts.map +1 -0
  84. package/dist/geometry2d/bridge/on-surface.js +94 -0
  85. package/dist/geometry2d/bridge/on-surface.js.map +1 -0
  86. package/dist/geometry2d/bridge/plane.d.ts +69 -0
  87. package/dist/geometry2d/bridge/plane.d.ts.map +1 -0
  88. package/dist/geometry2d/bridge/plane.js +96 -0
  89. package/dist/geometry2d/bridge/plane.js.map +1 -0
  90. package/dist/geometry2d/canned-blueprints.d.ts +44 -0
  91. package/dist/geometry2d/canned-blueprints.d.ts.map +1 -0
  92. package/dist/geometry2d/canned-blueprints.js +94 -0
  93. package/dist/geometry2d/canned-blueprints.js.map +1 -0
  94. package/dist/geometry2d/compound-blueprint.d.ts +72 -0
  95. package/dist/geometry2d/compound-blueprint.d.ts.map +1 -0
  96. package/dist/geometry2d/compound-blueprint.js +95 -0
  97. package/dist/geometry2d/compound-blueprint.js.map +1 -0
  98. package/dist/geometry2d/curve2d.d.ts +298 -0
  99. package/dist/geometry2d/curve2d.d.ts.map +1 -0
  100. package/dist/geometry2d/curve2d.js +1110 -0
  101. package/dist/geometry2d/curve2d.js.map +1 -0
  102. package/dist/geometry2d/index.d.ts +22 -0
  103. package/dist/geometry2d/index.d.ts.map +1 -0
  104. package/dist/geometry2d/index.js +21 -0
  105. package/dist/geometry2d/index.js.map +1 -0
  106. package/dist/geometry2d/organise.d.ts +28 -0
  107. package/dist/geometry2d/organise.d.ts.map +1 -0
  108. package/dist/geometry2d/organise.js +108 -0
  109. package/dist/geometry2d/organise.js.map +1 -0
  110. package/dist/geometry2d/pen-sketcher.d.ts +340 -0
  111. package/dist/geometry2d/pen-sketcher.d.ts.map +1 -0
  112. package/dist/geometry2d/pen-sketcher.js +477 -0
  113. package/dist/geometry2d/pen-sketcher.js.map +1 -0
  114. package/dist/geometry2d/point.d.ts +44 -0
  115. package/dist/geometry2d/point.d.ts.map +1 -0
  116. package/dist/geometry2d/point.js +57 -0
  117. package/dist/geometry2d/point.js.map +1 -0
  118. package/dist/geometry2d/svg-ellipse.d.ts +74 -0
  119. package/dist/geometry2d/svg-ellipse.d.ts.map +1 -0
  120. package/dist/geometry2d/svg-ellipse.js +163 -0
  121. package/dist/geometry2d/svg-ellipse.js.map +1 -0
  122. package/dist/lang/symbol-table.generated.d.ts +3 -0
  123. package/dist/lang/symbol-table.generated.d.ts.map +1 -1
  124. package/dist/lang/symbol-table.generated.js +3 -0
  125. package/dist/lang/symbol-table.generated.js.map +1 -1
  126. package/dist/mesh/types.d.ts +1 -1
  127. package/dist/mesh/types.d.ts.map +1 -1
  128. package/dist/mesh/types.js.map +1 -1
  129. package/package.json +9 -1
@@ -0,0 +1,102 @@
1
+ /**
2
+ * Blueprint — ordered 2D profile of `Curve2dObj` segments (pure-data port of
3
+ * brepjs `Blueprint`, Apache-2.0).
4
+ *
5
+ * Key adaptation: brepjs stores kernel-backed `Curve2D` handles that must be
6
+ * disposed; faijs stores plain `Curve2dObj` objects (no handles, no dispose).
7
+ * Kernel-coupling methods (sketchOnPlane / sketchOnFace / subFace / punchHole)
8
+ * intentionally live in `geometry2d/bridge`, not here.
9
+ *
10
+ * @module
11
+ */
12
+ import type { Curve2dObj } from './curve2d.js';
13
+ import { type BBox2d } from './bbox2d.js';
14
+ /** 2D point. */
15
+ export type Point2 = [number, number];
16
+ /**
17
+ * True when `(x,y)` is within `tol` of curve `c`.
18
+ * @param c - the curve to test against.
19
+ * @param pt - the 2D point to test, `[x, y]`.
20
+ * @param tol - the distance tolerance (default 1e-9).
21
+ * @returns true when the point lies within `tol` of the curve.
22
+ */
23
+ export declare function isOnCurve(c: Curve2dObj, pt: readonly [number, number], tol?: number): boolean;
24
+ /**
25
+ * A planar 2D profile = an ordered sequence of 2D curves.
26
+ * Shared base for `cad.profile`, `cad.draw` and (solved) `cad.sketch` outputs on
27
+ * their way to `sketchOnPlane`/`sketchOnFace`.
28
+ */
29
+ export declare class Blueprint {
30
+ /** Ordered 2D curve segments composing this blueprint. */
31
+ readonly curves: Curve2dObj[];
32
+ private _bbox;
33
+ private _orientation;
34
+ private _guessedOrientation;
35
+ constructor(curves: Curve2dObj[]);
36
+ /**
37
+ * Return a shallow copy of this blueprint (new container, same curve objects).
38
+ * @returns a new Blueprint with the same curves.
39
+ */
40
+ clone(): Blueprint;
41
+ /** Bounding box (cached). */
42
+ get boundingBox(): BBox2d;
43
+ /** Winding orientation via shoelace (curve midpoints for non-lines). */
44
+ get orientation(): 'clockwise' | 'counterClockwise';
45
+ /**
46
+ * Scale the blueprint about a center point.
47
+ * @param factor - the scale factor to apply.
48
+ * @param center - the scaling center `[x, y]` (defaults to the bounding-box center).
49
+ * @returns a new Blueprint with every curve scaled about the center.
50
+ */
51
+ scale(factor: number, center?: Point2): Blueprint;
52
+ /**
53
+ * Translate the whole blueprint by a delta.
54
+ * @param dxOrPoint - the x delta, or a full `[dx, dy]` offset point.
55
+ * @param dy - the y delta (default 0, ignored when `dxOrPoint` is a point).
56
+ * @returns a new Blueprint with every curve translated.
57
+ */
58
+ translate(dxOrPoint: number | Point2, dy?: number): Blueprint;
59
+ /**
60
+ * Rotate the whole blueprint about a center point.
61
+ * @param angleDeg - the rotation angle in degrees.
62
+ * @param center - the rotation center `[x, y]` (defaults to the origin).
63
+ * @returns a new Blueprint with every curve rotated.
64
+ */
65
+ rotate(angleDeg: number, center?: Point2): Blueprint;
66
+ /**
67
+ * Mirror the whole blueprint.
68
+ * @param centerOrDirection - the mirror center (mode `center`) or the mirror axis direction.
69
+ * @param origin - the axis origin `[x, y]` when mirroring across a plane (defaults to the origin).
70
+ * @param mode - `center` mirrors about a point; `plane` mirrors across an axis.
71
+ * @returns a new Blueprint with every curve mirrored.
72
+ */
73
+ mirror(centerOrDirection: Point2, origin?: Point2, mode?: 'center' | 'plane'): Blueprint;
74
+ /**
75
+ * The starting point of the first curve.
76
+ * @returns the 2D point where this blueprint begins.
77
+ */
78
+ get firstPoint(): Point2;
79
+ /**
80
+ * The ending point of the last curve.
81
+ * @returns the 2D point where this blueprint ends.
82
+ */
83
+ get lastPoint(): Point2;
84
+ /**
85
+ * True when the profile closes back on itself.
86
+ * @returns true when the first and last points coincide.
87
+ */
88
+ isClosed(): boolean;
89
+ /**
90
+ * True when a point is strictly inside (ray-cast); false on the boundary.
91
+ * @param point - the 2D point to test, `[x, y]`.
92
+ * @returns true when the point is strictly inside, false on/outside the boundary.
93
+ */
94
+ isInside(point: readonly [number, number]): boolean;
95
+ /**
96
+ * True when any curve of `this` intersects any curve of `other`.
97
+ * @param other - the blueprint to test for intersections against.
98
+ * @returns true when any pair of curves intersects.
99
+ */
100
+ intersects(other: Blueprint): boolean;
101
+ }
102
+ //# sourceMappingURL=blueprint.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"blueprint.d.ts","sourceRoot":"","sources":["../../src/geometry2d/blueprint.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AACH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,WAAW,CAAA;AAE3C,OAAO,EAAgE,KAAK,MAAM,EAAE,MAAM,UAAU,CAAA;AAEpG,gBAAgB;AAChB,MAAM,MAAM,MAAM,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;AAcrC;;;;;;GAMG;AACH,wBAAgB,SAAS,CAAC,CAAC,EAAE,UAAU,EAAE,EAAE,EAAE,SAAS,CAAC,MAAM,EAAE,MAAM,CAAC,EAAE,GAAG,SAAO,GAAG,OAAO,CAa3F;AAED;;;;GAIG;AACH,qBAAa,SAAS;IACpB,0DAA0D;IAC1D,QAAQ,CAAC,MAAM,EAAE,UAAU,EAAE,CAAA;IAE7B,OAAO,CAAC,KAAK,CAAsB;IACnC,OAAO,CAAC,YAAY,CAAgD;IACpE,OAAO,CAAC,mBAAmB,CAAgD;gBAE/D,MAAM,EAAE,UAAU,EAAE;IAKhC;;;OAGG;IACH,KAAK,IAAI,SAAS;IAIlB,6BAA6B;IAC7B,IAAI,WAAW,IAAI,MAAM,CAOxB;IAED,wEAAwE;IACxE,IAAI,WAAW,IAAI,WAAW,GAAG,kBAAkB,CAiBlD;IAED;;;;;OAKG;IACH,KAAK,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,SAAS;IAKjD;;;;;OAKG;IACH,SAAS,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,EAAE,EAAE,CAAC,EAAE,MAAM,GAAG,SAAS;IAK7D;;;;;OAKG;IACH,MAAM,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,SAAS;IAMpD;;;;;;OAMG;IACH,MAAM,CAAC,iBAAiB,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,EAAE,IAAI,GAAE,QAAQ,GAAG,OAAkB,GAAG,SAAS;IAUlG;;;OAGG;IACH,IAAI,UAAU,IAAI,MAAM,CAEvB;IAED;;;OAGG;IACH,IAAI,SAAS,IAAI,MAAM,CAEtB;IAED;;;OAGG;IACH,QAAQ,IAAI,OAAO;IAMnB;;;;OAIG;IACH,QAAQ,CAAC,KAAK,EAAE,SAAS,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,OAAO;IAsBnD;;;;OAIG;IACH,UAAU,CAAC,KAAK,EAAE,SAAS,GAAG,OAAO;CAWtC"}
@@ -0,0 +1,225 @@
1
+ import { addCurveToBBox, evaluateCurve2d, curveBounds, intersectCurves2dFn, makeLine2d, mirrorAcrossAxis, mirrorAtPoint, rotateCurve2d, scaleCurve2d, translateCurve2d } from './curve2d.js';
2
+ import { centerOf, createBBox2d, isBBoxOut, mergeBBox, outsidePointOf } from './bbox2d.js';
3
+ // `addCurveToBBox` writes xMin/yMin/xMax/yMax — same fields as BBox2d, so the
4
+ // structural subtype is satisfied by passing a plain BBox2d.
5
+ function curveBBox(c) {
6
+ const bb = createBBox2d();
7
+ addCurveToBBox(bb, c, 1e-9);
8
+ return bb;
9
+ }
10
+ function containsBoxPoint(bb, pt) {
11
+ return pt[0] >= bb.xMin && pt[0] <= bb.xMax && pt[1] >= bb.yMin && pt[1] <= bb.yMax;
12
+ }
13
+ /**
14
+ * True when `(x,y)` is within `tol` of curve `c`.
15
+ * @param c - the curve to test against.
16
+ * @param pt - the 2D point to test, `[x, y]`.
17
+ * @param tol - the distance tolerance (default 1e-9).
18
+ * @returns true when the point lies within `tol` of the curve.
19
+ */
20
+ export function isOnCurve(c, pt, tol = 1e-9) {
21
+ const bb = curveBBox(c);
22
+ if (!containsBoxPoint(bb, pt))
23
+ return false;
24
+ const b = curveBounds(c);
25
+ const N = 32;
26
+ let best = Infinity;
27
+ for (let i = 0; i <= N; i++) {
28
+ const t = b.first + ((b.last - b.first) * i) / N;
29
+ const [px, py] = evaluateCurve2d(c, t);
30
+ const d2 = (px - pt[0]) ** 2 + (py - pt[1]) ** 2;
31
+ if (d2 < best)
32
+ best = d2;
33
+ }
34
+ return best <= tol * tol;
35
+ }
36
+ /**
37
+ * A planar 2D profile = an ordered sequence of 2D curves.
38
+ * Shared base for `cad.profile`, `cad.draw` and (solved) `cad.sketch` outputs on
39
+ * their way to `sketchOnPlane`/`sketchOnFace`.
40
+ */
41
+ export class Blueprint {
42
+ /** Ordered 2D curve segments composing this blueprint. */
43
+ curves;
44
+ _bbox = null;
45
+ _orientation = null;
46
+ _guessedOrientation = null;
47
+ constructor(curves) {
48
+ if (curves.length === 0)
49
+ throw new Error('Blueprint requires at least one curve');
50
+ this.curves = curves;
51
+ }
52
+ /**
53
+ * Return a shallow copy of this blueprint (new container, same curve objects).
54
+ * @returns a new Blueprint with the same curves.
55
+ */
56
+ clone() {
57
+ return new Blueprint([...this.curves]);
58
+ }
59
+ /** Bounding box (cached). */
60
+ get boundingBox() {
61
+ if (!this._bbox) {
62
+ const bb = createBBox2d();
63
+ for (const c of this.curves)
64
+ mergeBBox(bb, curveBBox(c));
65
+ this._bbox = bb;
66
+ }
67
+ return this._bbox;
68
+ }
69
+ /** Winding orientation via shoelace (curve midpoints for non-lines). */
70
+ get orientation() {
71
+ if (this._orientation)
72
+ return this._orientation;
73
+ if (this._guessedOrientation)
74
+ return this._guessedOrientation;
75
+ const vertices = [];
76
+ for (const c of this.curves) {
77
+ const b = curveBounds(c);
78
+ vertices.push(firstPointOf(c));
79
+ if (c.kind2d !== 'line')
80
+ vertices.push(evaluate(c, (b.first + b.last) / 2));
81
+ }
82
+ let area = 0;
83
+ for (let i = 0; i < vertices.length; i++) {
84
+ const v1 = vertices[i];
85
+ const v2 = vertices[(i + 1) % vertices.length];
86
+ area += (v2[0] - v1[0]) * (v2[1] + v1[1]);
87
+ }
88
+ this._guessedOrientation = area > 0 ? 'clockwise' : 'counterClockwise';
89
+ return this._guessedOrientation;
90
+ }
91
+ /**
92
+ * Scale the blueprint about a center point.
93
+ * @param factor - the scale factor to apply.
94
+ * @param center - the scaling center `[x, y]` (defaults to the bounding-box center).
95
+ * @returns a new Blueprint with every curve scaled about the center.
96
+ */
97
+ scale(factor, center) {
98
+ const [cx, cy] = center ?? centerOf(this.boundingBox);
99
+ return new Blueprint(this.curves.map((c) => scaleCurve2d(c, factor, cx, cy)));
100
+ }
101
+ /**
102
+ * Translate the whole blueprint by a delta.
103
+ * @param dxOrPoint - the x delta, or a full `[dx, dy]` offset point.
104
+ * @param dy - the y delta (default 0, ignored when `dxOrPoint` is a point).
105
+ * @returns a new Blueprint with every curve translated.
106
+ */
107
+ translate(dxOrPoint, dy) {
108
+ const [dx, yy] = typeof dxOrPoint === 'number' ? [dxOrPoint, dy ?? 0] : [dxOrPoint[0], dxOrPoint[1]];
109
+ return new Blueprint(this.curves.map((c) => translateCurve2d(c, dx, yy)));
110
+ }
111
+ /**
112
+ * Rotate the whole blueprint about a center point.
113
+ * @param angleDeg - the rotation angle in degrees.
114
+ * @param center - the rotation center `[x, y]` (defaults to the origin).
115
+ * @returns a new Blueprint with every curve rotated.
116
+ */
117
+ rotate(angleDeg, center) {
118
+ const a = (angleDeg * Math.PI) / 180;
119
+ const [cx, cy] = center ?? [0, 0];
120
+ return new Blueprint(this.curves.map((c) => rotateCurve2d(c, a, cx, cy)));
121
+ }
122
+ /**
123
+ * Mirror the whole blueprint.
124
+ * @param centerOrDirection - the mirror center (mode `center`) or the mirror axis direction.
125
+ * @param origin - the axis origin `[x, y]` when mirroring across a plane (defaults to the origin).
126
+ * @param mode - `center` mirrors about a point; `plane` mirrors across an axis.
127
+ * @returns a new Blueprint with every curve mirrored.
128
+ */
129
+ mirror(centerOrDirection, origin, mode = 'center') {
130
+ if (mode === 'plane') {
131
+ const [ox, oy] = origin ?? [0, 0];
132
+ const [dx, dy] = centerOrDirection;
133
+ return new Blueprint(this.curves.map((c) => mirrorAcrossAxis(c, ox, oy, dx, dy)));
134
+ }
135
+ const [cx, cy] = centerOrDirection;
136
+ return new Blueprint(this.curves.map((c) => mirrorAtPoint(c, cx, cy)));
137
+ }
138
+ /**
139
+ * The starting point of the first curve.
140
+ * @returns the 2D point where this blueprint begins.
141
+ */
142
+ get firstPoint() {
143
+ return firstPointOf(this.curves[0]);
144
+ }
145
+ /**
146
+ * The ending point of the last curve.
147
+ * @returns the 2D point where this blueprint ends.
148
+ */
149
+ get lastPoint() {
150
+ return lastPointOf(this.curves[this.curves.length - 1]);
151
+ }
152
+ /**
153
+ * True when the profile closes back on itself.
154
+ * @returns true when the first and last points coincide.
155
+ */
156
+ isClosed() {
157
+ const fp = this.firstPoint;
158
+ const lp = this.lastPoint;
159
+ return Math.abs(fp[0] - lp[0]) < 1e-9 && Math.abs(fp[1] - lp[1]) < 1e-9;
160
+ }
161
+ /**
162
+ * True when a point is strictly inside (ray-cast); false on the boundary.
163
+ * @param point - the 2D point to test, `[x, y]`.
164
+ * @returns true when the point is strictly inside, false on/outside the boundary.
165
+ */
166
+ isInside(point) {
167
+ const bbox = this.boundingBox;
168
+ const p = [point[0], point[1]];
169
+ if (!containsBoxPoint(bbox, p))
170
+ return false;
171
+ if (this.curves.some((c) => isOnCurve(c, p)))
172
+ return false;
173
+ const outside = outsidePointOf(bbox);
174
+ const segment = makeLine2d(p[0], p[1], outside[0], outside[1]);
175
+ const seen = [];
176
+ let crossCount = 0;
177
+ for (const c of this.curves) {
178
+ if (isBBoxOut(curveBBox(segment), curveBBox(c)))
179
+ continue;
180
+ const r = intersectCurves2dFn(segment, c, 1e-9);
181
+ for (const pt of r.points) {
182
+ if (!seen.some((s) => samePoint(s, pt))) {
183
+ seen.push(pt);
184
+ crossCount++;
185
+ }
186
+ }
187
+ }
188
+ return crossCount % 2 === 1;
189
+ }
190
+ /**
191
+ * True when any curve of `this` intersects any curve of `other`.
192
+ * @param other - the blueprint to test for intersections against.
193
+ * @returns true when any pair of curves intersects.
194
+ */
195
+ intersects(other) {
196
+ if (isBBoxOut(this.boundingBox, other.boundingBox))
197
+ return false;
198
+ for (const a of this.curves) {
199
+ for (const b of other.curves) {
200
+ if (isBBoxOut(curveBBox(a), curveBBox(b)))
201
+ continue;
202
+ const r = intersectCurves2dFn(a, b, 1e-9);
203
+ if (r.points.length || r.segments.length)
204
+ return true;
205
+ }
206
+ }
207
+ return false;
208
+ }
209
+ }
210
+ // ---------------------------------------------------------------------------
211
+ // Pure helpers
212
+ // ---------------------------------------------------------------------------
213
+ function evaluate(c, t) {
214
+ return evaluateCurve2d(c, t);
215
+ }
216
+ function firstPointOf(c) {
217
+ return evaluateCurve2d(c, curveBounds(c).first);
218
+ }
219
+ function lastPointOf(c) {
220
+ return evaluateCurve2d(c, curveBounds(c).last);
221
+ }
222
+ function samePoint(a, b, tol = 1e-9) {
223
+ return Math.abs(a[0] - b[0]) < tol && Math.abs(a[1] - b[1]) < tol;
224
+ }
225
+ //# sourceMappingURL=blueprint.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"blueprint.js","sourceRoot":"","sources":["../../src/geometry2d/blueprint.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Blueprint — ordered 2D profile of `Curve2dObj` segments (pure-data port of\n * brepjs `Blueprint`, Apache-2.0).\n *\n * Key adaptation: brepjs stores kernel-backed `Curve2D` handles that must be\n * disposed; faijs stores plain `Curve2dObj` objects (no handles, no dispose).\n * Kernel-coupling methods (sketchOnPlane / sketchOnFace / subFace / punchHole)\n * intentionally live in `geometry2d/bridge`, not here.\n *\n * @module\n */\nimport type { Curve2dObj } from './curve2d'\nimport { addCurveToBBox, evaluateCurve2d, curveBounds, intersectCurves2dFn, makeLine2d, mirrorAcrossAxis, mirrorAtPoint, rotateCurve2d, scaleCurve2d, translateCurve2d } from './curve2d'\nimport { centerOf, createBBox2d, isBBoxOut, mergeBBox, outsidePointOf, type BBox2d } from './bbox2d'\n\n/** 2D point. */\nexport type Point2 = [number, number]\n\n// `addCurveToBBox` writes xMin/yMin/xMax/yMax — same fields as BBox2d, so the\n// structural subtype is satisfied by passing a plain BBox2d.\nfunction curveBBox(c: Curve2dObj): BBox2d {\n const bb = createBBox2d()\n addCurveToBBox(bb as never, c, 1e-9)\n return bb\n}\n\nfunction containsBoxPoint(bb: BBox2d, pt: readonly [number, number]): boolean {\n return pt[0] >= bb.xMin && pt[0] <= bb.xMax && pt[1] >= bb.yMin && pt[1] <= bb.yMax\n}\n\n/**\n * True when `(x,y)` is within `tol` of curve `c`.\n * @param c - the curve to test against.\n * @param pt - the 2D point to test, `[x, y]`.\n * @param tol - the distance tolerance (default 1e-9).\n * @returns true when the point lies within `tol` of the curve.\n */\nexport function isOnCurve(c: Curve2dObj, pt: readonly [number, number], tol = 1e-9): boolean {\n const bb = curveBBox(c)\n if (!containsBoxPoint(bb, pt)) return false\n const b = curveBounds(c)\n const N = 32\n let best = Infinity\n for (let i = 0; i <= N; i++) {\n const t = b.first + ((b.last - b.first) * i) / N\n const [px, py] = evaluateCurve2d(c, t)\n const d2 = (px - pt[0]) ** 2 + (py - pt[1]) ** 2\n if (d2 < best) best = d2\n }\n return best <= tol * tol\n}\n\n/**\n * A planar 2D profile = an ordered sequence of 2D curves.\n * Shared base for `cad.profile`, `cad.draw` and (solved) `cad.sketch` outputs on\n * their way to `sketchOnPlane`/`sketchOnFace`.\n */\nexport class Blueprint {\n /** Ordered 2D curve segments composing this blueprint. */\n readonly curves: Curve2dObj[]\n\n private _bbox: BBox2d | null = null\n private _orientation: 'clockwise' | 'counterClockwise' | null = null\n private _guessedOrientation: 'clockwise' | 'counterClockwise' | null = null\n\n constructor(curves: Curve2dObj[]) {\n if (curves.length === 0) throw new Error('Blueprint requires at least one curve')\n this.curves = curves\n }\n\n /**\n * Return a shallow copy of this blueprint (new container, same curve objects).\n * @returns a new Blueprint with the same curves.\n */\n clone(): Blueprint {\n return new Blueprint([...this.curves])\n }\n\n /** Bounding box (cached). */\n get boundingBox(): BBox2d {\n if (!this._bbox) {\n const bb = createBBox2d()\n for (const c of this.curves) mergeBBox(bb, curveBBox(c))\n this._bbox = bb\n }\n return this._bbox\n }\n\n /** Winding orientation via shoelace (curve midpoints for non-lines). */\n get orientation(): 'clockwise' | 'counterClockwise' {\n if (this._orientation) return this._orientation\n if (this._guessedOrientation) return this._guessedOrientation\n const vertices: Point2[] = []\n for (const c of this.curves) {\n const b = curveBounds(c)\n vertices.push(firstPointOf(c))\n if (c.kind2d !== 'line') vertices.push(evaluate(c, (b.first + b.last) / 2) as Point2)\n }\n let area = 0\n for (let i = 0; i < vertices.length; i++) {\n const v1 = vertices[i]!\n const v2 = vertices[(i + 1) % vertices.length]!\n area += (v2[0] - v1[0]) * (v2[1] + v1[1])\n }\n this._guessedOrientation = area > 0 ? 'clockwise' : 'counterClockwise'\n return this._guessedOrientation\n }\n\n /**\n * Scale the blueprint about a center point.\n * @param factor - the scale factor to apply.\n * @param center - the scaling center `[x, y]` (defaults to the bounding-box center).\n * @returns a new Blueprint with every curve scaled about the center.\n */\n scale(factor: number, center?: Point2): Blueprint {\n const [cx, cy] = center ?? centerOf(this.boundingBox)\n return new Blueprint(this.curves.map((c) => scaleCurve2d(c, factor, cx, cy)))\n }\n\n /**\n * Translate the whole blueprint by a delta.\n * @param dxOrPoint - the x delta, or a full `[dx, dy]` offset point.\n * @param dy - the y delta (default 0, ignored when `dxOrPoint` is a point).\n * @returns a new Blueprint with every curve translated.\n */\n translate(dxOrPoint: number | Point2, dy?: number): Blueprint {\n const [dx, yy] = typeof dxOrPoint === 'number' ? [dxOrPoint, dy ?? 0] : [dxOrPoint[0], dxOrPoint[1]]\n return new Blueprint(this.curves.map((c) => translateCurve2d(c, dx, yy)))\n }\n\n /**\n * Rotate the whole blueprint about a center point.\n * @param angleDeg - the rotation angle in degrees.\n * @param center - the rotation center `[x, y]` (defaults to the origin).\n * @returns a new Blueprint with every curve rotated.\n */\n rotate(angleDeg: number, center?: Point2): Blueprint {\n const a = (angleDeg * Math.PI) / 180\n const [cx, cy] = center ?? [0, 0]\n return new Blueprint(this.curves.map((c) => rotateCurve2d(c, a, cx, cy)))\n }\n\n /**\n * Mirror the whole blueprint.\n * @param centerOrDirection - the mirror center (mode `center`) or the mirror axis direction.\n * @param origin - the axis origin `[x, y]` when mirroring across a plane (defaults to the origin).\n * @param mode - `center` mirrors about a point; `plane` mirrors across an axis.\n * @returns a new Blueprint with every curve mirrored.\n */\n mirror(centerOrDirection: Point2, origin?: Point2, mode: 'center' | 'plane' = 'center'): Blueprint {\n if (mode === 'plane') {\n const [ox, oy] = origin ?? [0, 0]\n const [dx, dy] = centerOrDirection\n return new Blueprint(this.curves.map((c) => mirrorAcrossAxis(c, ox, oy, dx, dy)))\n }\n const [cx, cy] = centerOrDirection\n return new Blueprint(this.curves.map((c) => mirrorAtPoint(c, cx, cy)))\n }\n\n /**\n * The starting point of the first curve.\n * @returns the 2D point where this blueprint begins.\n */\n get firstPoint(): Point2 {\n return firstPointOf(this.curves[0]!)\n }\n\n /**\n * The ending point of the last curve.\n * @returns the 2D point where this blueprint ends.\n */\n get lastPoint(): Point2 {\n return lastPointOf(this.curves[this.curves.length - 1]!)\n }\n\n /**\n * True when the profile closes back on itself.\n * @returns true when the first and last points coincide.\n */\n isClosed(): boolean {\n const fp = this.firstPoint\n const lp = this.lastPoint\n return Math.abs(fp[0] - lp[0]) < 1e-9 && Math.abs(fp[1] - lp[1]) < 1e-9\n }\n\n /**\n * True when a point is strictly inside (ray-cast); false on the boundary.\n * @param point - the 2D point to test, `[x, y]`.\n * @returns true when the point is strictly inside, false on/outside the boundary.\n */\n isInside(point: readonly [number, number]): boolean {\n const bbox = this.boundingBox\n const p: Point2 = [point[0], point[1]]\n if (!containsBoxPoint(bbox, p)) return false\n if (this.curves.some((c) => isOnCurve(c, p))) return false\n const outside = outsidePointOf(bbox)\n const segment = makeLine2d(p[0], p[1], outside[0], outside[1])\n const seen: Point2[] = []\n let crossCount = 0\n for (const c of this.curves) {\n if (isBBoxOut(curveBBox(segment), curveBBox(c))) continue\n const r = intersectCurves2dFn(segment, c, 1e-9)\n for (const pt of r.points) {\n if (!seen.some((s) => samePoint(s, pt))) {\n seen.push(pt)\n crossCount++\n }\n }\n }\n return crossCount % 2 === 1\n }\n\n /**\n * True when any curve of `this` intersects any curve of `other`.\n * @param other - the blueprint to test for intersections against.\n * @returns true when any pair of curves intersects.\n */\n intersects(other: Blueprint): boolean {\n if (isBBoxOut(this.boundingBox, other.boundingBox)) return false\n for (const a of this.curves) {\n for (const b of other.curves) {\n if (isBBoxOut(curveBBox(a), curveBBox(b))) continue\n const r = intersectCurves2dFn(a, b, 1e-9)\n if (r.points.length || r.segments.length) return true\n }\n }\n return false\n }\n}\n\n// ---------------------------------------------------------------------------\n// Pure helpers\n// ---------------------------------------------------------------------------\n\nfunction evaluate(c: Curve2dObj, t: number): [number, number] {\n return evaluateCurve2d(c, t)\n}\n\nfunction firstPointOf(c: Curve2dObj): Point2 {\n return evaluateCurve2d(c, curveBounds(c).first)\n}\n\nfunction lastPointOf(c: Curve2dObj): Point2 {\n return evaluateCurve2d(c, curveBounds(c).last)\n}\n\nfunction samePoint(a: readonly [number, number], b: readonly [number, number], tol = 1e-9): boolean {\n return Math.abs(a[0] - b[0]) < tol && Math.abs(a[1] - b[1]) < tol\n}"]}
@@ -0,0 +1,58 @@
1
+ /**
2
+ * Blueprints — collection of disjoint 2D profiles (pure-data port of brepjs,
3
+ * Apache-2.0). Typical result of boolean operations producing multiple regions.
4
+ * @module
5
+ */
6
+ import { Blueprint, type Point2 } from './blueprint.js';
7
+ import { CompoundBlueprint } from './compound-blueprint.js';
8
+ import { type BBox2d } from './bbox2d.js';
9
+ /**
10
+ * Blueprints — collection of disjoint 2D profiles.
11
+ * Typical result of boolean operations producing multiple independent regions.
12
+ */
13
+ export declare class Blueprints {
14
+ /** The independent profiles in this collection. */
15
+ readonly blueprints: Array<Blueprint | CompoundBlueprint>;
16
+ private _bbox;
17
+ constructor(blueprints: Array<Blueprint | CompoundBlueprint>);
18
+ /**
19
+ * Return a copy of this collection.
20
+ * @returns a new Blueprints whose profiles are clones of the originals.
21
+ */
22
+ clone(): Blueprints;
23
+ /**
24
+ * Bounding box (cached). The box spanning all contained profiles.
25
+ * @returns a BBox2d enclosing every profile in this collection.
26
+ */
27
+ get boundingBox(): BBox2d;
28
+ /**
29
+ * Scale every profile about a center point.
30
+ * @param factor - the scale factor to apply.
31
+ * @param center - the scaling center `[x, y]` (defaults to the bounding-box center).
32
+ * @returns a new Blueprints with every profile scaled.
33
+ */
34
+ scale(factor: number, center?: Point2): Blueprints;
35
+ /**
36
+ * Translate every profile by a delta.
37
+ * @param dxOrPoint - the x delta, or a full `[dx, dy]` offset point.
38
+ * @param dy - the y delta (default 0, ignored when `dxOrPoint` is a point).
39
+ * @returns a new Blueprints with every profile translated.
40
+ */
41
+ translate(dxOrPoint: number | Point2, dy?: number): Blueprints;
42
+ /**
43
+ * Rotate every profile about a center point.
44
+ * @param angleDeg - the rotation angle in degrees.
45
+ * @param center - the rotation center `[x, y]` (defaults to the origin).
46
+ * @returns a new Blueprints with every profile rotated.
47
+ */
48
+ rotate(angleDeg: number, center?: Point2): Blueprints;
49
+ /**
50
+ * Mirror every profile.
51
+ * @param centerOrDirection - the mirror center (mode `center`) or the mirror axis direction.
52
+ * @param origin - the axis origin `[x, y]` when mirroring across a plane (defaults to the origin).
53
+ * @param mode - `center` mirrors about a point; `plane` mirrors across an axis.
54
+ * @returns a new Blueprints with every profile mirrored.
55
+ */
56
+ mirror(centerOrDirection: Point2, origin?: Point2, mode?: 'center' | 'plane'): Blueprints;
57
+ }
58
+ //# sourceMappingURL=blueprints.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"blueprints.d.ts","sourceRoot":"","sources":["../../src/geometry2d/blueprints.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,EAAE,SAAS,EAAE,KAAK,MAAM,EAAE,MAAM,aAAa,CAAA;AACpD,OAAO,EAAE,iBAAiB,EAAE,MAAM,sBAAsB,CAAA;AACxD,OAAO,EAAqC,KAAK,MAAM,EAAE,MAAM,UAAU,CAAA;AAEzE;;;GAGG;AACH,qBAAa,UAAU;IACrB,mDAAmD;IACnD,QAAQ,CAAC,UAAU,EAAE,KAAK,CAAC,SAAS,GAAG,iBAAiB,CAAC,CAAA;IAEzD,OAAO,CAAC,KAAK,CAAsB;gBAEvB,UAAU,EAAE,KAAK,CAAC,SAAS,GAAG,iBAAiB,CAAC;IAI5D;;;OAGG;IACH,KAAK,IAAI,UAAU;IAInB;;;OAGG;IACH,IAAI,WAAW,IAAI,MAAM,CAOxB;IAED;;;;;OAKG;IACH,KAAK,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,UAAU;IAKlD;;;;;OAKG;IACH,SAAS,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,EAAE,EAAE,CAAC,EAAE,MAAM,GAAG,UAAU;IAI9D;;;;;OAKG;IACH,MAAM,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,UAAU;IAIrD;;;;;;OAMG;IACH,MAAM,CAAC,iBAAiB,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,EAAE,IAAI,GAAE,QAAQ,GAAG,OAAkB,GAAG,UAAU;CAGpG"}
@@ -0,0 +1,72 @@
1
+ import { centerOf, createBBox2d, mergeBBox } from './bbox2d.js';
2
+ /**
3
+ * Blueprints — collection of disjoint 2D profiles.
4
+ * Typical result of boolean operations producing multiple independent regions.
5
+ */
6
+ export class Blueprints {
7
+ /** The independent profiles in this collection. */
8
+ blueprints;
9
+ _bbox = null;
10
+ constructor(blueprints) {
11
+ this.blueprints = blueprints;
12
+ }
13
+ /**
14
+ * Return a copy of this collection.
15
+ * @returns a new Blueprints whose profiles are clones of the originals.
16
+ */
17
+ clone() {
18
+ return new Blueprints(this.blueprints.map((b) => b.clone()));
19
+ }
20
+ /**
21
+ * Bounding box (cached). The box spanning all contained profiles.
22
+ * @returns a BBox2d enclosing every profile in this collection.
23
+ */
24
+ get boundingBox() {
25
+ if (!this._bbox) {
26
+ const bb = createBBox2d();
27
+ for (const b of this.blueprints)
28
+ mergeBBox(bb, b.boundingBox);
29
+ this._bbox = bb;
30
+ }
31
+ return this._bbox;
32
+ }
33
+ /**
34
+ * Scale every profile about a center point.
35
+ * @param factor - the scale factor to apply.
36
+ * @param center - the scaling center `[x, y]` (defaults to the bounding-box center).
37
+ * @returns a new Blueprints with every profile scaled.
38
+ */
39
+ scale(factor, center) {
40
+ const ctr = center ?? centerOf(this.boundingBox);
41
+ return new Blueprints(this.blueprints.map((b) => b.scale(factor, ctr)));
42
+ }
43
+ /**
44
+ * Translate every profile by a delta.
45
+ * @param dxOrPoint - the x delta, or a full `[dx, dy]` offset point.
46
+ * @param dy - the y delta (default 0, ignored when `dxOrPoint` is a point).
47
+ * @returns a new Blueprints with every profile translated.
48
+ */
49
+ translate(dxOrPoint, dy) {
50
+ return new Blueprints(this.blueprints.map((b) => b.translate(dxOrPoint, dy ?? 0)));
51
+ }
52
+ /**
53
+ * Rotate every profile about a center point.
54
+ * @param angleDeg - the rotation angle in degrees.
55
+ * @param center - the rotation center `[x, y]` (defaults to the origin).
56
+ * @returns a new Blueprints with every profile rotated.
57
+ */
58
+ rotate(angleDeg, center) {
59
+ return new Blueprints(this.blueprints.map((b) => b.rotate(angleDeg, center)));
60
+ }
61
+ /**
62
+ * Mirror every profile.
63
+ * @param centerOrDirection - the mirror center (mode `center`) or the mirror axis direction.
64
+ * @param origin - the axis origin `[x, y]` when mirroring across a plane (defaults to the origin).
65
+ * @param mode - `center` mirrors about a point; `plane` mirrors across an axis.
66
+ * @returns a new Blueprints with every profile mirrored.
67
+ */
68
+ mirror(centerOrDirection, origin, mode = 'center') {
69
+ return new Blueprints(this.blueprints.map((b) => b.mirror(centerOrDirection, origin, mode)));
70
+ }
71
+ }
72
+ //# sourceMappingURL=blueprints.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"blueprints.js","sourceRoot":"","sources":["../../src/geometry2d/blueprints.ts"],"names":[],"mappings":"AAOA,OAAO,EAAE,QAAQ,EAAE,YAAY,EAAE,SAAS,EAAe,MAAM,UAAU,CAAA;AAEzE;;;GAGG;AACH,MAAM,OAAO,UAAU;IACrB,mDAAmD;IAC1C,UAAU,CAAsC;IAEjD,KAAK,GAAkB,IAAI,CAAA;IAEnC,YAAY,UAAgD;QAC1D,IAAI,CAAC,UAAU,GAAG,UAAU,CAAA;IAC9B,CAAC;IAED;;;OAGG;IACH,KAAK;QACH,OAAO,IAAI,UAAU,CAAC,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,EAAE,CAAC,CAAC,CAAA;IAC9D,CAAC;IAED;;;OAGG;IACH,IAAI,WAAW;QACb,IAAI,CAAC,IAAI,CAAC,KAAK,EAAE,CAAC;YAChB,MAAM,EAAE,GAAG,YAAY,EAAE,CAAA;YACzB,KAAK,MAAM,CAAC,IAAI,IAAI,CAAC,UAAU;gBAAE,SAAS,CAAC,EAAE,EAAE,CAAC,CAAC,WAAW,CAAC,CAAA;YAC7D,IAAI,CAAC,KAAK,GAAG,EAAE,CAAA;QACjB,CAAC;QACD,OAAO,IAAI,CAAC,KAAK,CAAA;IACnB,CAAC;IAED;;;;;OAKG;IACH,KAAK,CAAC,MAAc,EAAE,MAAe;QACnC,MAAM,GAAG,GAAG,MAAM,IAAI,QAAQ,CAAC,IAAI,CAAC,WAAW,CAAC,CAAA;QAChD,OAAO,IAAI,UAAU,CAAC,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC,CAAC,CAAA;IACzE,CAAC;IAED;;;;;OAKG;IACH,SAAS,CAAC,SAA0B,EAAE,EAAW;QAC/C,OAAO,IAAI,UAAU,CAAC,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC,SAAS,EAAE,EAAE,IAAI,CAAC,CAAC,CAAC,CAAC,CAAA;IACpF,CAAC;IAED;;;;;OAKG;IACH,MAAM,CAAC,QAAgB,EAAE,MAAe;QACtC,OAAO,IAAI,UAAU,CAAC,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC,CAAC,CAAA;IAC/E,CAAC;IAED;;;;;;OAMG;IACH,MAAM,CAAC,iBAAyB,EAAE,MAAe,EAAE,OAA2B,QAAQ;QACpF,OAAO,IAAI,UAAU,CAAC,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,iBAAiB,EAAE,MAAM,EAAE,IAAI,CAAC,CAAC,CAAC,CAAA;IAC9F,CAAC;CACF","sourcesContent":["/**\n * Blueprints — collection of disjoint 2D profiles (pure-data port of brepjs,\n * Apache-2.0). Typical result of boolean operations producing multiple regions.\n * @module\n */\nimport { Blueprint, type Point2 } from './blueprint'\nimport { CompoundBlueprint } from './compound-blueprint'\nimport { centerOf, createBBox2d, mergeBBox, type BBox2d } from './bbox2d'\n\n/**\n * Blueprints — collection of disjoint 2D profiles.\n * Typical result of boolean operations producing multiple independent regions.\n */\nexport class Blueprints {\n /** The independent profiles in this collection. */\n readonly blueprints: Array<Blueprint | CompoundBlueprint>\n\n private _bbox: BBox2d | null = null\n\n constructor(blueprints: Array<Blueprint | CompoundBlueprint>) {\n this.blueprints = blueprints\n }\n\n /**\n * Return a copy of this collection.\n * @returns a new Blueprints whose profiles are clones of the originals.\n */\n clone(): Blueprints {\n return new Blueprints(this.blueprints.map((b) => b.clone()))\n }\n\n /**\n * Bounding box (cached). The box spanning all contained profiles.\n * @returns a BBox2d enclosing every profile in this collection.\n */\n get boundingBox(): BBox2d {\n if (!this._bbox) {\n const bb = createBBox2d()\n for (const b of this.blueprints) mergeBBox(bb, b.boundingBox)\n this._bbox = bb\n }\n return this._bbox\n }\n\n /**\n * Scale every profile about a center point.\n * @param factor - the scale factor to apply.\n * @param center - the scaling center `[x, y]` (defaults to the bounding-box center).\n * @returns a new Blueprints with every profile scaled.\n */\n scale(factor: number, center?: Point2): Blueprints {\n const ctr = center ?? centerOf(this.boundingBox)\n return new Blueprints(this.blueprints.map((b) => b.scale(factor, ctr)))\n }\n\n /**\n * Translate every profile by a delta.\n * @param dxOrPoint - the x delta, or a full `[dx, dy]` offset point.\n * @param dy - the y delta (default 0, ignored when `dxOrPoint` is a point).\n * @returns a new Blueprints with every profile translated.\n */\n translate(dxOrPoint: number | Point2, dy?: number): Blueprints {\n return new Blueprints(this.blueprints.map((b) => b.translate(dxOrPoint, dy ?? 0)))\n }\n\n /**\n * Rotate every profile about a center point.\n * @param angleDeg - the rotation angle in degrees.\n * @param center - the rotation center `[x, y]` (defaults to the origin).\n * @returns a new Blueprints with every profile rotated.\n */\n rotate(angleDeg: number, center?: Point2): Blueprints {\n return new Blueprints(this.blueprints.map((b) => b.rotate(angleDeg, center)))\n }\n\n /**\n * Mirror every profile.\n * @param centerOrDirection - the mirror center (mode `center`) or the mirror axis direction.\n * @param origin - the axis origin `[x, y]` when mirroring across a plane (defaults to the origin).\n * @param mode - `center` mirrors about a point; `plane` mirrors across an axis.\n * @returns a new Blueprints with every profile mirrored.\n */\n mirror(centerOrDirection: Point2, origin?: Point2, mode: 'center' | 'plane' = 'center'): Blueprints {\n return new Blueprints(this.blueprints.map((b) => b.mirror(centerOrDirection, origin, mode)))\n }\n}"]}
@@ -0,0 +1,50 @@
1
+ /**
2
+ * 2D curve → 3D plane placement primitives (E2, occt-only bridge layer).
3
+ *
4
+ * This is the "lift" half of `sketchOnPlane`: it maps a pure-2D `Curve2dObj[]`
5
+ * (or `Blueprint`) onto an arbitrary plane and assembles the resulting 3D edges
6
+ * into a wire. `curvesAsEdgesOnPlane` / `assembleWire` mirror the plan's E2 work
7
+ * items. The kernel edge/wire primitives are accepted as `Pick<BrepEngineApi, …>`
8
+ * (the bridge may import the kernel contract, only `api/` is off-limits) so
9
+ * callers pass `getBrepApi()` directly with no casts.
10
+ * @module
11
+ */
12
+ import type { BrepEngineApi } from '../../brep/engine/primitives.js';
13
+ import type { BrepHandle } from '../../brep/engine/types.js';
14
+ import type { Curve2dObj } from '../curve2d.js';
15
+ import type { Blueprint } from '../blueprint.js';
16
+ import { type Plane } from './plane.js';
17
+ /** Minimal kernel edge/wire surface needed for planar placement. */
18
+ export type PlaneWireKernel = Pick<BrepEngineApi, 'makeLineEdge' | 'makeArcEdge' | 'makeBezierEdge' | 'makeWire'>;
19
+ /**
20
+ * Build the 3D edge(s) for a single 2D curve lifted onto a plane. Line and
21
+ * bezier build exact analytic edges; circle / trimmed-circle build a true arc
22
+ * edge from three on-plane lift points (a full circle is split into two arcs to
23
+ * keep `makeArcEdge` well-formed); ellipse / bspline fall back to a dense
24
+ * sampled polyline.
25
+ * @param kernel - the kernel edge primitives.
26
+ * @param plane - the target plane frame.
27
+ * @param c - the ordered 2D curve to lift.
28
+ * @returns the lifted 3D edge handle(s), in curve order.
29
+ */
30
+ export declare function liftCurve2dToPlane(kernel: PlaneWireKernel, plane: Plane, c: Curve2dObj): BrepHandle[];
31
+ /**
32
+ * Lift an ordered list of 2D curves to edges on a plane frame.
33
+ * @param kernel - the kernel edge/wire primitives.
34
+ * @param plane - the target plane.
35
+ * @param curves - the ordered 2D curves (a closed loop stays closed).
36
+ * @returns the lifted 3D edge handles in the same order.
37
+ */
38
+ export declare function curvesAsEdgesOnPlane(kernel: PlaneWireKernel, plane: Plane, curves: readonly Curve2dObj[]): BrepHandle[];
39
+ /**
40
+ * Assemble a Blueprint's curves into a 3D wire on a plane — the shared placement
41
+ * step for all of the profile / draw / sketch sources.
42
+ * @param kernel - the curve kernel/wire primitives.
43
+ * @param planeOrName - a plane frame or a named plane string (`'XY'` / `'XZ'` / …).
44
+ * @param bp - the blueprint whose ordered curves become the wire.
45
+ * @returns the assembled 3D wire.
46
+ */
47
+ export declare function assembleWire(kernel: PlaneWireKernel, planeOrName: Plane | string, bp: Blueprint): BrepHandle;
48
+ export { liftPointToPlane, namedPlane, makePlane, toVec3 } from './plane.js';
49
+ export type { Plane, Vec3, Vec3Input } from './plane.js';
50
+ //# sourceMappingURL=lift-on-plane.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"lift-on-plane.d.ts","sourceRoot":"","sources":["../../../src/geometry2d/bridge/lift-on-plane.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AACH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,8BAA8B,CAAA;AACjE,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,yBAAyB,CAAA;AACzD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAA;AAE5C,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,cAAc,CAAA;AAC7C,OAAO,EAAgC,KAAK,KAAK,EAAa,MAAM,SAAS,CAAA;AAE7E,oEAAoE;AACpE,MAAM,MAAM,eAAe,GAAG,IAAI,CAAC,aAAa,EAAE,cAAc,GAAG,aAAa,GAAG,gBAAgB,GAAG,UAAU,CAAC,CAAA;AAEjH;;;;;;;;;;GAUG;AACH,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,eAAe,EAAE,KAAK,EAAE,KAAK,EAAE,CAAC,EAAE,UAAU,GAAG,UAAU,EAAE,CAuBrG;AAaD;;;;;;GAMG;AACH,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,eAAe,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,SAAS,UAAU,EAAE,GAAG,UAAU,EAAE,CAIvH;AAED;;;;;;;GAOG;AACH,wBAAgB,YAAY,CAAC,MAAM,EAAE,eAAe,EAAE,WAAW,EAAE,KAAK,GAAG,MAAM,EAAE,EAAE,EAAE,SAAS,GAAG,UAAU,CAG5G;AAED,OAAO,EAAE,gBAAgB,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,SAAS,CAAA;AACzE,YAAY,EAAE,KAAK,EAAE,IAAI,EAAE,SAAS,EAAE,MAAM,SAAS,CAAA"}
@@ -0,0 +1,72 @@
1
+ import { evaluateCurve2d } from '../curve2d.js';
2
+ import { namedPlane, liftPointToPlane } from './plane.js';
3
+ /**
4
+ * Build the 3D edge(s) for a single 2D curve lifted onto a plane. Line and
5
+ * bezier build exact analytic edges; circle / trimmed-circle build a true arc
6
+ * edge from three on-plane lift points (a full circle is split into two arcs to
7
+ * keep `makeArcEdge` well-formed); ellipse / bspline fall back to a dense
8
+ * sampled polyline.
9
+ * @param kernel - the kernel edge primitives.
10
+ * @param plane - the target plane frame.
11
+ * @param c - the ordered 2D curve to lift.
12
+ * @returns the lifted 3D edge handle(s), in curve order.
13
+ */
14
+ export function liftCurve2dToPlane(kernel, plane, c) {
15
+ const on = (c2, t) => liftPointToPlane(plane, ...evaluateCurve2d(c2, t));
16
+ switch (c.kind2d) {
17
+ case 'line':
18
+ return [
19
+ kernel.makeLineEdge(liftPointToPlane(plane, c.ox, c.oy), liftPointToPlane(plane, c.ox + c.dx * c.len, c.oy + c.dy * c.len)),
20
+ ];
21
+ case 'bezier':
22
+ return [kernel.makeBezierEdge(c.poles.map(([x, y]) => liftPointToPlane(plane, x, y)))];
23
+ case 'circle':
24
+ return [
25
+ kernel.makeArcEdge(on(c, 0), on(c, Math.PI / 2), on(c, Math.PI)),
26
+ kernel.makeArcEdge(on(c, Math.PI), on(c, (3 * Math.PI) / 2), on(c, 2 * Math.PI)),
27
+ ];
28
+ case 'trimmed':
29
+ if (c.basis.kind2d === 'circle')
30
+ return [kernel.makeArcEdge(on(c, 0), on(c, 0.5), on(c, 1))];
31
+ return sampledEdges(kernel, plane, c);
32
+ default:
33
+ return sampledEdges(kernel, plane, c);
34
+ }
35
+ }
36
+ /** Sample a non-analytic curve into a polyline of `makeLineEdge`s on the plane. */
37
+ function sampledEdges(kernel, plane, c) {
38
+ const out = [];
39
+ for (let k = 0; k < 32; k++) {
40
+ const t0 = k / 32;
41
+ const t1 = (k + 1) / 32;
42
+ out.push(kernel.makeLineEdge(liftPointToPlane(plane, ...evaluateCurve2d(c, t0)), liftPointToPlane(plane, ...evaluateCurve2d(c, t1))));
43
+ }
44
+ return out;
45
+ }
46
+ /**
47
+ * Lift an ordered list of 2D curves to edges on a plane frame.
48
+ * @param kernel - the kernel edge/wire primitives.
49
+ * @param plane - the target plane.
50
+ * @param curves - the ordered 2D curves (a closed loop stays closed).
51
+ * @returns the lifted 3D edge handles in the same order.
52
+ */
53
+ export function curvesAsEdgesOnPlane(kernel, plane, curves) {
54
+ const out = [];
55
+ for (const c of curves)
56
+ out.push(...liftCurve2dToPlane(kernel, plane, c));
57
+ return out;
58
+ }
59
+ /**
60
+ * Assemble a Blueprint's curves into a 3D wire on a plane — the shared placement
61
+ * step for all of the profile / draw / sketch sources.
62
+ * @param kernel - the curve kernel/wire primitives.
63
+ * @param planeOrName - a plane frame or a named plane string (`'XY'` / `'XZ'` / …).
64
+ * @param bp - the blueprint whose ordered curves become the wire.
65
+ * @returns the assembled 3D wire.
66
+ */
67
+ export function assembleWire(kernel, planeOrName, bp) {
68
+ const plane = typeof planeOrName === 'string' ? namedPlane(planeOrName) : planeOrName;
69
+ return kernel.makeWire(curvesAsEdgesOnPlane(kernel, plane, bp.curves));
70
+ }
71
+ export { liftPointToPlane, namedPlane, makePlane, toVec3 } from './plane.js';
72
+ //# sourceMappingURL=lift-on-plane.js.map