@faicad/cq-compat 0.13.2 → 0.14.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/browser.d.ts +0 -1
- package/dist/browser.d.ts.map +1 -1
- package/dist/browser.js +7 -6
- package/dist/browser.js.map +1 -1
- package/dist/gear-test-harness.d.ts.map +1 -1
- package/dist/gear-test-harness.js +9 -12
- package/dist/gear-test-harness.js.map +1 -1
- package/dist/index.d.ts +5 -7
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +14 -4
- package/dist/index.js.map +1 -1
- package/dist/sketch.d.ts +209 -0
- package/dist/sketch.d.ts.map +1 -0
- package/dist/sketch.js +529 -0
- package/dist/sketch.js.map +1 -0
- package/dist/workplane.d.ts +47 -0
- package/dist/workplane.d.ts.map +1 -1
- package/dist/workplane.js +424 -5
- package/dist/workplane.js.map +1 -1
- package/package.json +3 -2
package/dist/sketch.js
ADDED
|
@@ -0,0 +1,529 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Sketch — CadQuery `Sketch.py` geometry-container parity (non-planegcs part).
|
|
3
|
+
*
|
|
4
|
+
* Phase 2 of the cq-compat max-cadquery plan: expose a public Sketch API whose
|
|
5
|
+
* geometry-declaration segment (rect/circle/ellipse/polygon + modes a/s/i/c/r +
|
|
6
|
+
* faces/wires/edges/vertices selectors) mirrors upstream `Sketch.py` without the
|
|
7
|
+
* constraint solver (planegcs licensing is pending legal review; constraints are
|
|
8
|
+
* intentionally out of scope here).
|
|
9
|
+
*
|
|
10
|
+
* The constraint segment (`constrain`/`solve`) stays blocked until the
|
|
11
|
+
* LGPL-2.0-or-later verdict; this module implements everything that does not
|
|
12
|
+
* depend on it.
|
|
13
|
+
*
|
|
14
|
+
* Faces are OCCT brep faces living in the z=0 plane (kernel `makeRectangle`,
|
|
15
|
+
* `makeCircleEdge`/`makeWire`/`makeFace`, ...). Boolean modes use the kernel's
|
|
16
|
+
* face-level fuse/cut/common (verified working on faces, see probe_2d).
|
|
17
|
+
*/
|
|
18
|
+
import { getKernel } from '@faicad/faijs/occt-kernel/occtKernel';
|
|
19
|
+
import { fromHandle } from '@faicad/faijs/sdk';
|
|
20
|
+
function kernel() {
|
|
21
|
+
return getKernel();
|
|
22
|
+
}
|
|
23
|
+
/** Vec3 literal helper (avoids TS tuple-inference noise). */
|
|
24
|
+
function v3(x, y, z) {
|
|
25
|
+
return { x, y, z };
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Create an empty Sketch.
|
|
29
|
+
* @returns an empty Sketch
|
|
30
|
+
*/
|
|
31
|
+
export function sketch() {
|
|
32
|
+
return { faces: [], tags: new Map(), selected: [], locs: [] };
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Translate a shape so its centre lands at the origin. Used to centre
|
|
36
|
+
* kernel primitives that build in the [0,size] corner.
|
|
37
|
+
*/
|
|
38
|
+
function centre2D(k, h, w, d) {
|
|
39
|
+
const moved = k.translate(h, -w / 2, -d / 2, 0);
|
|
40
|
+
k.release(h);
|
|
41
|
+
return moved;
|
|
42
|
+
}
|
|
43
|
+
/** Rectangular face, centred at origin, w along X, h along Y. */
|
|
44
|
+
function makeRectFace(k, w, h) {
|
|
45
|
+
return centre2D(k, k.makeRectangle(w, h), w, h);
|
|
46
|
+
}
|
|
47
|
+
/** Circular face of radius r centred at origin. */
|
|
48
|
+
function makeCircleFace(k, r) {
|
|
49
|
+
const e = k.makeCircleEdge(v3(0, 0, 0), v3(0, 0, 1), r);
|
|
50
|
+
const wire = k.makeWire([e]);
|
|
51
|
+
k.release(e);
|
|
52
|
+
const f = k.makeFace(wire);
|
|
53
|
+
k.release(wire);
|
|
54
|
+
return f;
|
|
55
|
+
}
|
|
56
|
+
/** Elliptical face, major a along X, minor b along Y, centred at origin. */
|
|
57
|
+
function makeEllipseFace(k, a, b) {
|
|
58
|
+
const e = k.makeEllipseEdge(v3(0, 0, 0), v3(0, 0, 1), a, b);
|
|
59
|
+
const wire = k.makeWire([e]);
|
|
60
|
+
k.release(e);
|
|
61
|
+
const f = k.makeFace(wire);
|
|
62
|
+
k.release(wire);
|
|
63
|
+
return f;
|
|
64
|
+
}
|
|
65
|
+
/** Polygon face from a closed point list (first==last optional; auto-closed). */
|
|
66
|
+
function makePolygonFace(k, pts) {
|
|
67
|
+
// Drop the closing duplicate if present, then drop consecutive duplicates
|
|
68
|
+
// (OCCT makeLineEdge rejects zero-length edges, e.g. a 45-degree trapezoid
|
|
69
|
+
// degenerating into a triangle with two identical top corners).
|
|
70
|
+
const same = (a, b) => Math.abs(a[0] - b[0]) < 1e-12 && Math.abs(a[1] - b[1]) < 1e-12;
|
|
71
|
+
const fst = pts[0];
|
|
72
|
+
const lst = pts[pts.length - 1];
|
|
73
|
+
const ring = fst && lst && same(fst, lst) ? pts.slice(0, -1) : pts;
|
|
74
|
+
const clean = [];
|
|
75
|
+
for (const p of ring) {
|
|
76
|
+
const last = clean[clean.length - 1];
|
|
77
|
+
if (!last || !same(last, p))
|
|
78
|
+
clean.push(p);
|
|
79
|
+
}
|
|
80
|
+
if (clean.length < 3)
|
|
81
|
+
throw new Error('polygon needs at least 3 distinct points');
|
|
82
|
+
const edges = [];
|
|
83
|
+
for (let i = 0; i < clean.length; i++) {
|
|
84
|
+
const a = clean[i];
|
|
85
|
+
const b = clean[(i + 1) % clean.length];
|
|
86
|
+
edges.push(k.makeLineEdge(v3(a[0], a[1], 0), v3(b[0], b[1], 0)));
|
|
87
|
+
}
|
|
88
|
+
const wire = k.makeWire(edges);
|
|
89
|
+
edges.forEach((e) => k.release(e));
|
|
90
|
+
const f = k.makeFace(wire);
|
|
91
|
+
k.release(wire);
|
|
92
|
+
return f;
|
|
93
|
+
}
|
|
94
|
+
/** Rotate a face by angle degrees about the Z axis through its centre. */
|
|
95
|
+
function rotateFace(k, f, angleDeg) {
|
|
96
|
+
if (!angleDeg)
|
|
97
|
+
return f;
|
|
98
|
+
const rad = (angleDeg * Math.PI) / 180;
|
|
99
|
+
const cos = Math.cos(rad);
|
|
100
|
+
const sin = Math.sin(rad);
|
|
101
|
+
const m = [cos, -sin, 0, 0, sin, cos, 0, 0, 0, 0, 1, 0];
|
|
102
|
+
const r = k.transform(f, m);
|
|
103
|
+
k.release(f);
|
|
104
|
+
return r;
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* Apply the CQ each() mode against the current faces.
|
|
108
|
+
* - a: fuse all new faces into the current set (CQ `_faces.fuse(*res)`)
|
|
109
|
+
* - s: cut new faces away
|
|
110
|
+
* - i: intersect with new faces
|
|
111
|
+
* - r: replace current faces with the new ones
|
|
112
|
+
* - c: keep current faces; store new ones under the tag (required)
|
|
113
|
+
*/
|
|
114
|
+
function applyMode(k, faces, fresh, mode, tag) {
|
|
115
|
+
const tagOut = new Map();
|
|
116
|
+
switch (mode) {
|
|
117
|
+
case 'a': {
|
|
118
|
+
const all = [...faces, ...fresh];
|
|
119
|
+
if (all.length === 0)
|
|
120
|
+
return { faces: [], tags: tagOut, tagOut };
|
|
121
|
+
let acc = all[0];
|
|
122
|
+
for (let i = 1; i < all.length; i++) {
|
|
123
|
+
const merged = k.fuse(acc, all[i]);
|
|
124
|
+
k.release(acc);
|
|
125
|
+
k.release(all[i]);
|
|
126
|
+
acc = merged;
|
|
127
|
+
}
|
|
128
|
+
return { faces: [acc], tags: tagOut, tagOut };
|
|
129
|
+
}
|
|
130
|
+
case 's': {
|
|
131
|
+
let acc = faces.length ? faces[0] : null;
|
|
132
|
+
if (!acc)
|
|
133
|
+
return { faces: [], tags: tagOut, tagOut };
|
|
134
|
+
const rest = faces.slice(1);
|
|
135
|
+
for (const f of rest) {
|
|
136
|
+
const merged = k.fuse(acc, f);
|
|
137
|
+
k.release(acc);
|
|
138
|
+
k.release(f);
|
|
139
|
+
acc = merged;
|
|
140
|
+
}
|
|
141
|
+
for (const f of fresh) {
|
|
142
|
+
const cut = k.cut(acc, f);
|
|
143
|
+
k.release(acc);
|
|
144
|
+
k.release(f);
|
|
145
|
+
acc = cut;
|
|
146
|
+
}
|
|
147
|
+
return { faces: acc ? [acc] : [], tags: tagOut, tagOut };
|
|
148
|
+
}
|
|
149
|
+
case 'i': {
|
|
150
|
+
let acc = faces.length ? faces[0] : null;
|
|
151
|
+
if (!acc)
|
|
152
|
+
return { faces: [], tags: tagOut, tagOut };
|
|
153
|
+
for (const f of faces.slice(1)) {
|
|
154
|
+
const merged = k.fuse(acc, f);
|
|
155
|
+
k.release(acc);
|
|
156
|
+
k.release(f);
|
|
157
|
+
acc = merged;
|
|
158
|
+
}
|
|
159
|
+
for (const f of fresh) {
|
|
160
|
+
const common = k.common(acc, f);
|
|
161
|
+
k.release(acc);
|
|
162
|
+
k.release(f);
|
|
163
|
+
acc = common;
|
|
164
|
+
}
|
|
165
|
+
return { faces: acc ? [acc] : [], tags: tagOut, tagOut };
|
|
166
|
+
}
|
|
167
|
+
case 'c': {
|
|
168
|
+
if (!tag)
|
|
169
|
+
throw new Error('No tag specified - the geometry will be unreachable');
|
|
170
|
+
tagOut.set(tag, fresh);
|
|
171
|
+
// current faces unchanged (fresh faces are construction-only)
|
|
172
|
+
return { faces, tags: tagOut, tagOut };
|
|
173
|
+
}
|
|
174
|
+
case 'r': {
|
|
175
|
+
return { faces: fresh, tags: tagOut, tagOut };
|
|
176
|
+
}
|
|
177
|
+
default:
|
|
178
|
+
throw new Error('Invalid mode: ' + String(mode));
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
/** Merge the mode result into a Sketch (fresh faces released on a/s/i/r paths). */
|
|
182
|
+
function commit(sk, mode, tag, fresh) {
|
|
183
|
+
const k = kernel();
|
|
184
|
+
const { faces, tagOut } = applyMode(k, sk.faces, fresh, mode, tag);
|
|
185
|
+
const tags = new Map(sk.tags);
|
|
186
|
+
for (const [t, fs] of tagOut)
|
|
187
|
+
tags.set(t, fs);
|
|
188
|
+
return { faces, tags, selected: sk.selected, locs: sk.locs };
|
|
189
|
+
}
|
|
190
|
+
/**
|
|
191
|
+
* rect — CadQuery `Sketch.rect(w, h, angle, mode, tag)` parity.
|
|
192
|
+
* @param sk - Sketch
|
|
193
|
+
* @param w - width along X
|
|
194
|
+
* @param h - height along Y
|
|
195
|
+
* @param opts - mode/tag/angle
|
|
196
|
+
* @returns Sketch
|
|
197
|
+
*/
|
|
198
|
+
export function rect(sk, w, h, opts) {
|
|
199
|
+
const k = kernel();
|
|
200
|
+
const mode = opts?.mode ?? 'a';
|
|
201
|
+
const face = rotateFace(k, makeRectFace(k, w, h), opts?.angle ?? 0);
|
|
202
|
+
return commit(sk, mode, opts?.tag, [face]);
|
|
203
|
+
}
|
|
204
|
+
/**
|
|
205
|
+
* circle — CadQuery `Sketch.circle(r, mode, tag)` parity.
|
|
206
|
+
* @param sk - Sketch
|
|
207
|
+
* @param r - radius
|
|
208
|
+
* @param opts - mode/tag
|
|
209
|
+
* @returns Sketch
|
|
210
|
+
*/
|
|
211
|
+
export function circle(sk, r, opts) {
|
|
212
|
+
const k = kernel();
|
|
213
|
+
const mode = opts?.mode ?? 'a';
|
|
214
|
+
const face = makeCircleFace(k, r);
|
|
215
|
+
return commit(sk, mode, opts?.tag, [face]);
|
|
216
|
+
}
|
|
217
|
+
/**
|
|
218
|
+
* ellipse — CadQuery `Sketch.ellipse(a1, a2, angle, mode, tag)` parity.
|
|
219
|
+
* @param sk - Sketch
|
|
220
|
+
* @param a1 - radius along X
|
|
221
|
+
* @param a2 - radius along Y
|
|
222
|
+
* @param opts - mode/tag/angle
|
|
223
|
+
* @returns Sketch
|
|
224
|
+
*/
|
|
225
|
+
export function ellipse(sk, a1, a2, opts) {
|
|
226
|
+
const k = kernel();
|
|
227
|
+
const mode = opts?.mode ?? 'a';
|
|
228
|
+
const face = rotateFace(k, makeEllipseFace(k, a1, a2), opts?.angle ?? 0);
|
|
229
|
+
return commit(sk, mode, opts?.tag, [face]);
|
|
230
|
+
}
|
|
231
|
+
/**
|
|
232
|
+
* polygon — CadQuery `Sketch.polygon(pts, angle, mode, tag)` parity.
|
|
233
|
+
* @param sk - Sketch
|
|
234
|
+
* @param pts - closed point list [[x,y],...]
|
|
235
|
+
* @param opts - mode/tag/angle
|
|
236
|
+
* @returns Sketch
|
|
237
|
+
*/
|
|
238
|
+
export function polygon(sk, pts, opts) {
|
|
239
|
+
const k = kernel();
|
|
240
|
+
const mode = opts?.mode ?? 'a';
|
|
241
|
+
const face = rotateFace(k, makePolygonFace(k, pts), opts?.angle ?? 0);
|
|
242
|
+
return commit(sk, mode, opts?.tag, [face]);
|
|
243
|
+
}
|
|
244
|
+
/**
|
|
245
|
+
* regularPolygon — CadQuery `Sketch.regularPolygon(r, n, angle, mode, tag)`
|
|
246
|
+
* parity: n-gon inscribed in radius r, first vertex at the +Y direction.
|
|
247
|
+
* @param sk - Sketch
|
|
248
|
+
* @param r - circumradius
|
|
249
|
+
* @param n - number of sides
|
|
250
|
+
* @param opts - mode/tag/angle
|
|
251
|
+
* @returns Sketch
|
|
252
|
+
*/
|
|
253
|
+
export function regularPolygon(sk, r, n, opts) {
|
|
254
|
+
const pts = [];
|
|
255
|
+
for (let i = 0; i <= n; i++) {
|
|
256
|
+
const a = (i * 2 * Math.PI) / n;
|
|
257
|
+
pts.push([r * Math.sin(a), r * Math.cos(a)]);
|
|
258
|
+
}
|
|
259
|
+
return polygon(sk, pts, opts);
|
|
260
|
+
}
|
|
261
|
+
/**
|
|
262
|
+
* slot — CadQuery `Sketch.slot(w, h, angle, mode, tag)` parity: stadium / long
|
|
263
|
+
* slot face of length w and width h, centred at origin.
|
|
264
|
+
* @param sk - Sketch
|
|
265
|
+
* @param w - slot length along X
|
|
266
|
+
* @param h - slot width along Y
|
|
267
|
+
* @param opts - mode/tag/angle
|
|
268
|
+
* @returns Sketch
|
|
269
|
+
*/
|
|
270
|
+
export function slot(sk, w, h, opts) {
|
|
271
|
+
const k = kernel();
|
|
272
|
+
const mode = opts?.mode ?? 'a';
|
|
273
|
+
const p1 = [-w / 2, h / 2];
|
|
274
|
+
const p2 = [w / 2, h / 2];
|
|
275
|
+
const p3 = [-w / 2, -h / 2];
|
|
276
|
+
const p4 = [w / 2, -h / 2];
|
|
277
|
+
const p5 = [-w / 2 - h / 2, 0];
|
|
278
|
+
const p6 = [w / 2 + h / 2, 0];
|
|
279
|
+
const e1 = k.makeLineEdge(v3(p1[0], p1[1], 0), v3(p2[0], p2[1], 0));
|
|
280
|
+
const e2 = k.makeArcEdge(v3(p2[0], p2[1], 0), v3(p6[0], p6[1], 0), v3(p4[0], p4[1], 0));
|
|
281
|
+
const e3 = k.makeLineEdge(v3(p4[0], p4[1], 0), v3(p3[0], p3[1], 0));
|
|
282
|
+
const e4 = k.makeArcEdge(v3(p3[0], p3[1], 0), v3(p5[0], p5[1], 0), v3(p1[0], p1[1], 0));
|
|
283
|
+
const wire = k.makeWire([e1, e2, e3, e4]);
|
|
284
|
+
for (const e of [e1, e2, e3, e4])
|
|
285
|
+
k.release(e);
|
|
286
|
+
const face = k.makeFace(wire);
|
|
287
|
+
k.release(wire);
|
|
288
|
+
return commit(sk, mode, opts?.tag, [rotateFace(k, face, opts?.angle ?? 0)]);
|
|
289
|
+
}
|
|
290
|
+
/**
|
|
291
|
+
* trapezoid — CadQuery `Sketch.trapezoid(w, h, a1, a2, angle, mode, tag)`
|
|
292
|
+
* parity: isosceles-or-not trapezoid; a1/a2 are the base angles in degrees.
|
|
293
|
+
* @param sk - Sketch
|
|
294
|
+
* @param w - bottom width
|
|
295
|
+
* @param h - height
|
|
296
|
+
* @param a1 - bottom-left base angle (degrees)
|
|
297
|
+
* @param a2 - bottom-right base angle (degrees); defaults to a1
|
|
298
|
+
* @param opts - mode/tag/angle
|
|
299
|
+
* @returns Sketch
|
|
300
|
+
*/
|
|
301
|
+
export function trapezoid(sk, w, h, a1, a2, opts) {
|
|
302
|
+
const a2v = a2 ?? a1;
|
|
303
|
+
const v1 = [-w / 2, -h / 2];
|
|
304
|
+
const v2 = [w / 2, -h / 2];
|
|
305
|
+
const t1 = h / Math.tan((a1 * Math.PI) / 180);
|
|
306
|
+
const t2 = h / Math.tan((a2v * Math.PI) / 180);
|
|
307
|
+
const v3 = [-w / 2 + t1, h / 2];
|
|
308
|
+
const v4 = [w / 2 - t2, h / 2];
|
|
309
|
+
return polygon(sk, [v1, v2, v4, v3, v1], opts);
|
|
310
|
+
}
|
|
311
|
+
/**
|
|
312
|
+
* offset — CadQuery `Sketch.offset(d, mode, tag)` parity: offset each selected
|
|
313
|
+
* wire by d and feed the resulting faces through the given mode. Requires a
|
|
314
|
+
* selection (wires()/edges()).
|
|
315
|
+
* @param sk - Sketch
|
|
316
|
+
* @param d - signed offset distance
|
|
317
|
+
* @param opts - mode/tag
|
|
318
|
+
* @returns Sketch
|
|
319
|
+
*/
|
|
320
|
+
export function offset(sk, d, opts) {
|
|
321
|
+
if (!sk.selected.length)
|
|
322
|
+
throw new Error('Selection is needed to offset');
|
|
323
|
+
const k = kernel();
|
|
324
|
+
const mode = opts?.mode ?? 'a';
|
|
325
|
+
const fresh = [];
|
|
326
|
+
for (const el of sk.selected) {
|
|
327
|
+
const off = k.offsetWire2D(el, d);
|
|
328
|
+
const f = k.makeFace(off);
|
|
329
|
+
k.release(off);
|
|
330
|
+
fresh.push(f);
|
|
331
|
+
}
|
|
332
|
+
return commit(sk, mode, opts?.tag, fresh);
|
|
333
|
+
}
|
|
334
|
+
/**
|
|
335
|
+
* faces — CadQuery `Sketch.faces()` selector parity: select current faces.
|
|
336
|
+
* @param sk - Sketch
|
|
337
|
+
* @returns Sketch (selected faces feed the next geometric declaration)
|
|
338
|
+
*/
|
|
339
|
+
export function faces(sk) {
|
|
340
|
+
// Upstream _faces.Faces() returns the TOPOLOGICAL faces; a fused face
|
|
341
|
+
// handle may hold several (e.g. two overlapping rects stay 2 faces after
|
|
342
|
+
// fuse, asserted by upstream test_modes). Flatten via getSubShapes.
|
|
343
|
+
const k = kernel();
|
|
344
|
+
const out = [];
|
|
345
|
+
for (const f of sk.faces) {
|
|
346
|
+
const sub = k.getSubShapes(f, 'face');
|
|
347
|
+
out.push(...sub);
|
|
348
|
+
}
|
|
349
|
+
return { ...sk, selected: out };
|
|
350
|
+
}
|
|
351
|
+
/**
|
|
352
|
+
* wires — CadQuery `Sketch.wires()` selector parity: select boundary wires of
|
|
353
|
+
* the current faces.
|
|
354
|
+
* @param sk - Sketch
|
|
355
|
+
* @returns Sketch
|
|
356
|
+
*/
|
|
357
|
+
export function wires(sk) {
|
|
358
|
+
const k = kernel();
|
|
359
|
+
const wires = [];
|
|
360
|
+
for (const f of sk.faces) {
|
|
361
|
+
const w = k.outerWire(f);
|
|
362
|
+
wires.push(w);
|
|
363
|
+
}
|
|
364
|
+
return { ...sk, selected: wires };
|
|
365
|
+
}
|
|
366
|
+
/**
|
|
367
|
+
* edges — CadQuery `Sketch.edges()` selector parity: select all edges of the
|
|
368
|
+
* current faces.
|
|
369
|
+
* @param sk - Sketch
|
|
370
|
+
* @returns Sketch
|
|
371
|
+
*/
|
|
372
|
+
export function edges(sk) {
|
|
373
|
+
const k = kernel();
|
|
374
|
+
const out = [];
|
|
375
|
+
for (const f of sk.faces) {
|
|
376
|
+
const es = k.getSubShapes(f, 'edge');
|
|
377
|
+
out.push(...es);
|
|
378
|
+
}
|
|
379
|
+
return { ...sk, selected: out };
|
|
380
|
+
}
|
|
381
|
+
/**
|
|
382
|
+
* vertices — CadQuery `Sketch.vertices()` selector parity: select all vertices
|
|
383
|
+
* of the current faces.
|
|
384
|
+
* @param sk - Sketch
|
|
385
|
+
* @returns Sketch
|
|
386
|
+
*/
|
|
387
|
+
export function vertices(sk) {
|
|
388
|
+
const k = kernel();
|
|
389
|
+
const out = [];
|
|
390
|
+
for (const f of sk.faces) {
|
|
391
|
+
const vs = k.getSubShapes(f, 'vertex');
|
|
392
|
+
out.push(...vs);
|
|
393
|
+
}
|
|
394
|
+
return { ...sk, selected: out };
|
|
395
|
+
}
|
|
396
|
+
/**
|
|
397
|
+
* reset — CadQuery `Sketch.reset()` parity: clear the selection so the next
|
|
398
|
+
* geometric declaration applies to the whole sketch.
|
|
399
|
+
* @param sk - Sketch
|
|
400
|
+
* @returns Sketch
|
|
401
|
+
*/
|
|
402
|
+
export function reset(sk) {
|
|
403
|
+
return { ...sk, selected: [] };
|
|
404
|
+
}
|
|
405
|
+
/**
|
|
406
|
+
* val — CadQuery `Sketch.val()` parity: first effective face as a Shape.
|
|
407
|
+
* @param sk - Sketch
|
|
408
|
+
* @returns Shape
|
|
409
|
+
*/
|
|
410
|
+
export function val(sk) {
|
|
411
|
+
const v = vals(sk);
|
|
412
|
+
if (!v.length)
|
|
413
|
+
throw new Error('Sketch has no faces');
|
|
414
|
+
return v[0];
|
|
415
|
+
}
|
|
416
|
+
/**
|
|
417
|
+
* vals — CadQuery `Sketch.vals()` parity: the current selection, or the
|
|
418
|
+
* flattened topological faces when nothing is selected (upstream returns the
|
|
419
|
+
* `_faces` faces; a fused handle may hold several).
|
|
420
|
+
* @param sk - Sketch
|
|
421
|
+
* @returns Shape[]
|
|
422
|
+
*/
|
|
423
|
+
export function vals(sk) {
|
|
424
|
+
if (sk.selected.length)
|
|
425
|
+
return [...sk.selected];
|
|
426
|
+
const k = kernel();
|
|
427
|
+
const out = [];
|
|
428
|
+
for (const f of sk.faces) {
|
|
429
|
+
const sub = k.getSubShapes(f, 'face');
|
|
430
|
+
out.push(...sub);
|
|
431
|
+
}
|
|
432
|
+
return out;
|
|
433
|
+
}
|
|
434
|
+
/**
|
|
435
|
+
* tag — CadQuery `Sketch.tag(name)` parity: store the current selection (or all
|
|
436
|
+
* faces when nothing selected) under a name for later `.select()`.
|
|
437
|
+
* @param sk - Sketch
|
|
438
|
+
* @param name - tag name
|
|
439
|
+
* @returns Sketch
|
|
440
|
+
*/
|
|
441
|
+
export function tag(sk, name) {
|
|
442
|
+
const tags = new Map(sk.tags);
|
|
443
|
+
const payload = sk.selected.length ? sk.selected : sk.faces;
|
|
444
|
+
tags.set(name, [...payload]);
|
|
445
|
+
return { ...sk, tags };
|
|
446
|
+
}
|
|
447
|
+
/**
|
|
448
|
+
* select — CadQuery `Sketch.select(tag)` parity: select the faces stored under
|
|
449
|
+
* a tag.
|
|
450
|
+
* @param sk - Sketch
|
|
451
|
+
* @param name - tag name
|
|
452
|
+
* @returns Sketch
|
|
453
|
+
*/
|
|
454
|
+
export function select(sk, name) {
|
|
455
|
+
const payload = sk.tags.get(name);
|
|
456
|
+
if (!payload)
|
|
457
|
+
throw new Error('Tag not found: ' + name);
|
|
458
|
+
return { ...sk, selected: [...payload] };
|
|
459
|
+
}
|
|
460
|
+
/**
|
|
461
|
+
* area — total surface area of the effective faces (upstream `_faces.Area()`).
|
|
462
|
+
* @param sk - Sketch
|
|
463
|
+
* @returns number
|
|
464
|
+
*/
|
|
465
|
+
export function area(sk) {
|
|
466
|
+
const k = kernel();
|
|
467
|
+
let total = 0;
|
|
468
|
+
for (const f of sk.faces)
|
|
469
|
+
total += k.getSurfaceArea(f);
|
|
470
|
+
return total;
|
|
471
|
+
}
|
|
472
|
+
/**
|
|
473
|
+
* faceCount — number of effective faces (upstream `_faces.Faces()` length).
|
|
474
|
+
* @param sk - Sketch
|
|
475
|
+
* @returns number
|
|
476
|
+
*/
|
|
477
|
+
export function faceCount(sk) {
|
|
478
|
+
const k = kernel();
|
|
479
|
+
let n = 0;
|
|
480
|
+
for (const f of sk.faces)
|
|
481
|
+
n += k.getSubShapes(f, 'face').length;
|
|
482
|
+
return n;
|
|
483
|
+
}
|
|
484
|
+
/**
|
|
485
|
+
* extrude — CadQuery `Sketch` → solid via extrusion along +Z. Phase 2 action 3:
|
|
486
|
+
* sketch → extrude/revolve dual-chain outlet. This is the brep side
|
|
487
|
+
* (kernel.extrude on each effective face, fused into one solid).
|
|
488
|
+
* @param sk - Sketch
|
|
489
|
+
* @param height - extrusion height
|
|
490
|
+
* @returns Shape (solid)
|
|
491
|
+
*/
|
|
492
|
+
export function extrude(sk, height) {
|
|
493
|
+
const k = kernel();
|
|
494
|
+
const solids = [];
|
|
495
|
+
for (const f of sk.faces) {
|
|
496
|
+
solids.push(k.extrude(f, 0, 0, height));
|
|
497
|
+
}
|
|
498
|
+
let acc = null;
|
|
499
|
+
for (const s of solids) {
|
|
500
|
+
if (!acc) {
|
|
501
|
+
acc = s;
|
|
502
|
+
continue;
|
|
503
|
+
}
|
|
504
|
+
const merged = k.fuse(acc, s);
|
|
505
|
+
k.release(acc);
|
|
506
|
+
k.release(s);
|
|
507
|
+
acc = merged;
|
|
508
|
+
}
|
|
509
|
+
if (!acc)
|
|
510
|
+
throw new Error('Sketch has no faces to extrude');
|
|
511
|
+
// Wrap the kernel handle into a faijs Shape so script-facing mirrors can
|
|
512
|
+
// export it as a part (bare kernel handles are invisible to execute()).
|
|
513
|
+
return fromHandle(acc);
|
|
514
|
+
}
|
|
515
|
+
/**
|
|
516
|
+
* Release all handles held by a Sketch (run at end of script/unit test).
|
|
517
|
+
* @param sk - Sketch whose kernel handles are released
|
|
518
|
+
*/
|
|
519
|
+
export function dispose(sk) {
|
|
520
|
+
const k = kernel();
|
|
521
|
+
for (const f of sk.faces)
|
|
522
|
+
k.release(f);
|
|
523
|
+
for (const [, fs] of sk.tags)
|
|
524
|
+
for (const f of fs)
|
|
525
|
+
k.release(f);
|
|
526
|
+
for (const e of sk.selected)
|
|
527
|
+
k.release(e);
|
|
528
|
+
}
|
|
529
|
+
//# sourceMappingURL=sketch.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sketch.js","sourceRoot":"","sources":["../src/sketch.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Sketch — CadQuery `Sketch.py` geometry-container parity (non-planegcs part).\n *\n * Phase 2 of the cq-compat max-cadquery plan: expose a public Sketch API whose\n * geometry-declaration segment (rect/circle/ellipse/polygon + modes a/s/i/c/r +\n * faces/wires/edges/vertices selectors) mirrors upstream `Sketch.py` without the\n * constraint solver (planegcs licensing is pending legal review; constraints are\n * intentionally out of scope here).\n *\n * The constraint segment (`constrain`/`solve`) stays blocked until the\n * LGPL-2.0-or-later verdict; this module implements everything that does not\n * depend on it.\n *\n * Faces are OCCT brep faces living in the z=0 plane (kernel `makeRectangle`,\n * `makeCircleEdge`/`makeWire`/`makeFace`, ...). Boolean modes use the kernel's\n * face-level fuse/cut/common (verified working on faces, see probe_2d).\n */\n\nimport { getKernel } from '@faicad/faijs/occt-kernel/occtKernel'\nimport { fromHandle } from '@faicad/faijs/sdk'\nimport type { OcctKernel, ShapeHandle, Vec3 } from 'occt-wasm'\n\n/** Sketch face-container state. */\nexport interface Sketch {\n /** Current effective faces (upstream `_faces`). */\n faces: ShapeHandle[]\n /** Construction faces stored under their tag (mode \"c\"). */\n tags: Map<string, ShapeHandle[]>\n /** Selected entities (faces/wires/edges/vertices) feeding the next each(). */\n selected: ShapeHandle[]\n /** Pushed iteration locations (push/selection-derived). */\n locs: Array<[number, number]>\n}\n\n/** Sketch geometry-declaration mode (CadQuery Modes): a=additive, s=subtract, i=intersect, c=construction+tag, r=replace. */\nexport type SketchMode = 'a' | 's' | 'i' | 'c' | 'r'\n\n/** Options for a geometry declaration: mode/tag/angle (CadQuery keyword args). */\nexport interface SketchOpts {\n mode?: SketchMode\n tag?: string\n angle?: number\n}\n\nfunction kernel(): OcctKernel {\n return getKernel() as unknown as OcctKernel\n}\n\n/** Vec3 literal helper (avoids TS tuple-inference noise). */\nfunction v3(x: number, y: number, z: number): Vec3 {\n return { x, y, z }\n}\n\n/**\n * Create an empty Sketch.\n * @returns an empty Sketch\n */\nexport function sketch(): Sketch {\n return { faces: [], tags: new Map(), selected: [], locs: [] }\n}\n\n/**\n * Translate a shape so its centre lands at the origin. Used to centre\n * kernel primitives that build in the [0,size] corner.\n */\nfunction centre2D(k: OcctKernel, h: ShapeHandle, w: number, d: number): ShapeHandle {\n const moved = k.translate(h, -w / 2, -d / 2, 0)\n k.release(h)\n return moved\n}\n\n/** Rectangular face, centred at origin, w along X, h along Y. */\nfunction makeRectFace(k: OcctKernel, w: number, h: number): ShapeHandle {\n return centre2D(k, k.makeRectangle(w, h), w, h)\n}\n\n/** Circular face of radius r centred at origin. */\nfunction makeCircleFace(k: OcctKernel, r: number): ShapeHandle {\n const e = k.makeCircleEdge(v3(0, 0, 0), v3(0, 0, 1), r)\n const wire = k.makeWire([e])\n k.release(e)\n const f = k.makeFace(wire)\n k.release(wire)\n return f\n}\n\n/** Elliptical face, major a along X, minor b along Y, centred at origin. */\nfunction makeEllipseFace(k: OcctKernel, a: number, b: number): ShapeHandle {\n const e = k.makeEllipseEdge(v3(0, 0, 0), v3(0, 0, 1), a, b)\n const wire = k.makeWire([e])\n k.release(e)\n const f = k.makeFace(wire)\n k.release(wire)\n return f\n}\n\n/** Polygon face from a closed point list (first==last optional; auto-closed). */\nfunction makePolygonFace(k: OcctKernel, pts: Array<[number, number]>): ShapeHandle {\n // Drop the closing duplicate if present, then drop consecutive duplicates\n // (OCCT makeLineEdge rejects zero-length edges, e.g. a 45-degree trapezoid\n // degenerating into a triangle with two identical top corners).\n const same = (a: [number, number], b: [number, number]) =>\n Math.abs(a[0] - b[0]) < 1e-12 && Math.abs(a[1] - b[1]) < 1e-12\n const fst = pts[0]\n const lst = pts[pts.length - 1]\n const ring = fst && lst && same(fst, lst) ? pts.slice(0, -1) : pts\n const clean: Array<[number, number]> = []\n for (const p of ring) {\n const last = clean[clean.length - 1]\n if (!last || !same(last, p)) clean.push(p)\n }\n if (clean.length < 3) throw new Error('polygon needs at least 3 distinct points')\n const edges: ShapeHandle[] = []\n for (let i = 0; i < clean.length; i++) {\n const a = clean[i]\n const b = clean[(i + 1) % clean.length]\n edges.push(k.makeLineEdge(v3(a[0], a[1], 0), v3(b[0], b[1], 0)))\n }\n const wire = k.makeWire(edges)\n edges.forEach((e) => k.release(e))\n const f = k.makeFace(wire)\n k.release(wire)\n return f\n}\n\n/** Rotate a face by angle degrees about the Z axis through its centre. */\nfunction rotateFace(k: OcctKernel, f: ShapeHandle, angleDeg: number): ShapeHandle {\n if (!angleDeg) return f\n const rad = (angleDeg * Math.PI) / 180\n const cos = Math.cos(rad)\n const sin = Math.sin(rad)\n const m = [cos, -sin, 0, 0, sin, cos, 0, 0, 0, 0, 1, 0]\n const r = k.transform(f, m)\n k.release(f)\n return r\n}\n\n/**\n * Apply the CQ each() mode against the current faces.\n * - a: fuse all new faces into the current set (CQ `_faces.fuse(*res)`)\n * - s: cut new faces away\n * - i: intersect with new faces\n * - r: replace current faces with the new ones\n * - c: keep current faces; store new ones under the tag (required)\n */\nfunction applyMode(\n k: OcctKernel,\n faces: ShapeHandle[],\n fresh: ShapeHandle[],\n mode: SketchMode,\n tag?: string,\n): { faces: ShapeHandle[]; tags: Map<string, ShapeHandle[]>; tagOut: Map<string, ShapeHandle[]> } {\n const tagOut = new Map<string, ShapeHandle[]>()\n switch (mode) {\n case 'a': {\n const all = [...faces, ...fresh]\n if (all.length === 0) return { faces: [], tags: tagOut, tagOut }\n let acc: ShapeHandle = all[0]\n for (let i = 1; i < all.length; i++) {\n const merged = k.fuse(acc, all[i])\n k.release(acc)\n k.release(all[i])\n acc = merged\n }\n return { faces: [acc], tags: tagOut, tagOut }\n }\n case 's': {\n let acc: ShapeHandle | null = faces.length ? faces[0] : null\n if (!acc) return { faces: [], tags: tagOut, tagOut }\n const rest = faces.slice(1)\n for (const f of rest) {\n const merged = k.fuse(acc, f)\n k.release(acc)\n k.release(f)\n acc = merged\n }\n for (const f of fresh) {\n const cut = k.cut(acc, f)\n k.release(acc)\n k.release(f)\n acc = cut\n }\n return { faces: acc ? [acc] : [], tags: tagOut, tagOut }\n }\n case 'i': {\n let acc: ShapeHandle | null = faces.length ? faces[0] : null\n if (!acc) return { faces: [], tags: tagOut, tagOut }\n for (const f of faces.slice(1)) {\n const merged = k.fuse(acc, f)\n k.release(acc)\n k.release(f)\n acc = merged\n }\n for (const f of fresh) {\n const common = k.common(acc, f)\n k.release(acc)\n k.release(f)\n acc = common\n }\n return { faces: acc ? [acc] : [], tags: tagOut, tagOut }\n }\n case 'c': {\n if (!tag) throw new Error('No tag specified - the geometry will be unreachable')\n tagOut.set(tag, fresh)\n // current faces unchanged (fresh faces are construction-only)\n return { faces, tags: tagOut, tagOut }\n }\n case 'r': {\n return { faces: fresh, tags: tagOut, tagOut }\n }\n default:\n throw new Error('Invalid mode: ' + String(mode))\n }\n}\n\n/** Merge the mode result into a Sketch (fresh faces released on a/s/i/r paths). */\nfunction commit(sk: Sketch, mode: SketchMode, tag: string | undefined, fresh: ShapeHandle[]): Sketch {\n const k = kernel()\n const { faces, tagOut } = applyMode(k, sk.faces, fresh, mode, tag)\n const tags = new Map(sk.tags)\n for (const [t, fs] of tagOut) tags.set(t, fs)\n return { faces, tags, selected: sk.selected, locs: sk.locs }\n}\n\n/**\n * rect — CadQuery `Sketch.rect(w, h, angle, mode, tag)` parity.\n * @param sk - Sketch\n * @param w - width along X\n * @param h - height along Y\n * @param opts - mode/tag/angle\n * @returns Sketch\n */\nexport function rect(sk: Sketch, w: number, h: number, opts?: SketchOpts): Sketch {\n const k = kernel()\n const mode = opts?.mode ?? 'a'\n const face = rotateFace(k, makeRectFace(k, w, h), opts?.angle ?? 0)\n return commit(sk, mode, opts?.tag, [face])\n}\n\n/**\n * circle — CadQuery `Sketch.circle(r, mode, tag)` parity.\n * @param sk - Sketch\n * @param r - radius\n * @param opts - mode/tag\n * @returns Sketch\n */\nexport function circle(sk: Sketch, r: number, opts?: SketchOpts): Sketch {\n const k = kernel()\n const mode = opts?.mode ?? 'a'\n const face = makeCircleFace(k, r)\n return commit(sk, mode, opts?.tag, [face])\n}\n\n/**\n * ellipse — CadQuery `Sketch.ellipse(a1, a2, angle, mode, tag)` parity.\n * @param sk - Sketch\n * @param a1 - radius along X\n * @param a2 - radius along Y\n * @param opts - mode/tag/angle\n * @returns Sketch\n */\nexport function ellipse(sk: Sketch, a1: number, a2: number, opts?: SketchOpts): Sketch {\n const k = kernel()\n const mode = opts?.mode ?? 'a'\n const face = rotateFace(k, makeEllipseFace(k, a1, a2), opts?.angle ?? 0)\n return commit(sk, mode, opts?.tag, [face])\n}\n\n/**\n * polygon — CadQuery `Sketch.polygon(pts, angle, mode, tag)` parity.\n * @param sk - Sketch\n * @param pts - closed point list [[x,y],...]\n * @param opts - mode/tag/angle\n * @returns Sketch\n */\nexport function polygon(sk: Sketch, pts: Array<[number, number]>, opts?: SketchOpts): Sketch {\n const k = kernel()\n const mode = opts?.mode ?? 'a'\n const face = rotateFace(k, makePolygonFace(k, pts), opts?.angle ?? 0)\n return commit(sk, mode, opts?.tag, [face])\n}\n\n/**\n * regularPolygon — CadQuery `Sketch.regularPolygon(r, n, angle, mode, tag)`\n * parity: n-gon inscribed in radius r, first vertex at the +Y direction.\n * @param sk - Sketch\n * @param r - circumradius\n * @param n - number of sides\n * @param opts - mode/tag/angle\n * @returns Sketch\n */\nexport function regularPolygon(sk: Sketch, r: number, n: number, opts?: SketchOpts): Sketch {\n const pts: Array<[number, number]> = []\n for (let i = 0; i <= n; i++) {\n const a = (i * 2 * Math.PI) / n\n pts.push([r * Math.sin(a), r * Math.cos(a)])\n }\n return polygon(sk, pts, opts)\n}\n\n/**\n * slot — CadQuery `Sketch.slot(w, h, angle, mode, tag)` parity: stadium / long\n * slot face of length w and width h, centred at origin.\n * @param sk - Sketch\n * @param w - slot length along X\n * @param h - slot width along Y\n * @param opts - mode/tag/angle\n * @returns Sketch\n */\nexport function slot(sk: Sketch, w: number, h: number, opts?: SketchOpts): Sketch {\n const k = kernel()\n const mode = opts?.mode ?? 'a'\n const p1: [number, number] = [-w / 2, h / 2]\n const p2: [number, number] = [w / 2, h / 2]\n const p3: [number, number] = [-w / 2, -h / 2]\n const p4: [number, number] = [w / 2, -h / 2]\n const p5: [number, number] = [-w / 2 - h / 2, 0]\n const p6: [number, number] = [w / 2 + h / 2, 0]\n const e1 = k.makeLineEdge(v3(p1[0], p1[1], 0), v3(p2[0], p2[1], 0))\n const e2 = k.makeArcEdge(v3(p2[0], p2[1], 0), v3(p6[0], p6[1], 0), v3(p4[0], p4[1], 0))\n const e3 = k.makeLineEdge(v3(p4[0], p4[1], 0), v3(p3[0], p3[1], 0))\n const e4 = k.makeArcEdge(v3(p3[0], p3[1], 0), v3(p5[0], p5[1], 0), v3(p1[0], p1[1], 0))\n const wire = k.makeWire([e1, e2, e3, e4])\n for (const e of [e1, e2, e3, e4]) k.release(e)\n const face = k.makeFace(wire)\n k.release(wire)\n return commit(sk, mode, opts?.tag, [rotateFace(k, face, opts?.angle ?? 0)])\n}\n\n/**\n * trapezoid — CadQuery `Sketch.trapezoid(w, h, a1, a2, angle, mode, tag)`\n * parity: isosceles-or-not trapezoid; a1/a2 are the base angles in degrees.\n * @param sk - Sketch\n * @param w - bottom width\n * @param h - height\n * @param a1 - bottom-left base angle (degrees)\n * @param a2 - bottom-right base angle (degrees); defaults to a1\n * @param opts - mode/tag/angle\n * @returns Sketch\n */\nexport function trapezoid(sk: Sketch, w: number, h: number, a1: number, a2?: number, opts?: SketchOpts): Sketch {\n const a2v = a2 ?? a1\n const v1: [number, number] = [-w / 2, -h / 2]\n const v2: [number, number] = [w / 2, -h / 2]\n const t1 = h / Math.tan((a1 * Math.PI) / 180)\n const t2 = h / Math.tan((a2v * Math.PI) / 180)\n const v3: [number, number] = [-w / 2 + t1, h / 2]\n const v4: [number, number] = [w / 2 - t2, h / 2]\n return polygon(sk, [v1, v2, v4, v3, v1], opts)\n}\n\n/**\n * offset — CadQuery `Sketch.offset(d, mode, tag)` parity: offset each selected\n * wire by d and feed the resulting faces through the given mode. Requires a\n * selection (wires()/edges()).\n * @param sk - Sketch\n * @param d - signed offset distance\n * @param opts - mode/tag\n * @returns Sketch\n */\nexport function offset(sk: Sketch, d: number, opts?: SketchOpts): Sketch {\n if (!sk.selected.length) throw new Error('Selection is needed to offset')\n const k = kernel()\n const mode = opts?.mode ?? 'a'\n const fresh: ShapeHandle[] = []\n for (const el of sk.selected) {\n const off = k.offsetWire2D(el, d)\n const f = k.makeFace(off)\n k.release(off)\n fresh.push(f)\n }\n return commit(sk, mode, opts?.tag, fresh)\n}\n\n/**\n * faces — CadQuery `Sketch.faces()` selector parity: select current faces.\n * @param sk - Sketch\n * @returns Sketch (selected faces feed the next geometric declaration)\n */\nexport function faces(sk: Sketch): Sketch {\n // Upstream _faces.Faces() returns the TOPOLOGICAL faces; a fused face\n // handle may hold several (e.g. two overlapping rects stay 2 faces after\n // fuse, asserted by upstream test_modes). Flatten via getSubShapes.\n const k = kernel()\n const out: ShapeHandle[] = []\n for (const f of sk.faces) {\n const sub = k.getSubShapes(f, 'face') as unknown as ShapeHandle[]\n out.push(...sub)\n }\n return { ...sk, selected: out }\n}\n\n/**\n * wires — CadQuery `Sketch.wires()` selector parity: select boundary wires of\n * the current faces.\n * @param sk - Sketch\n * @returns Sketch\n */\nexport function wires(sk: Sketch): Sketch {\n const k = kernel()\n const wires: ShapeHandle[] = []\n for (const f of sk.faces) {\n const w = k.outerWire(f)\n wires.push(w)\n }\n return { ...sk, selected: wires }\n}\n\n/**\n * edges — CadQuery `Sketch.edges()` selector parity: select all edges of the\n * current faces.\n * @param sk - Sketch\n * @returns Sketch\n */\nexport function edges(sk: Sketch): Sketch {\n const k = kernel()\n const out: ShapeHandle[] = []\n for (const f of sk.faces) {\n const es = k.getSubShapes(f, 'edge') as unknown as ShapeHandle[]\n out.push(...es)\n }\n return { ...sk, selected: out }\n}\n\n/**\n * vertices — CadQuery `Sketch.vertices()` selector parity: select all vertices\n * of the current faces.\n * @param sk - Sketch\n * @returns Sketch\n */\nexport function vertices(sk: Sketch): Sketch {\n const k = kernel()\n const out: ShapeHandle[] = []\n for (const f of sk.faces) {\n const vs = k.getSubShapes(f, 'vertex') as unknown as ShapeHandle[]\n out.push(...vs)\n }\n return { ...sk, selected: out }\n}\n\n/**\n * reset — CadQuery `Sketch.reset()` parity: clear the selection so the next\n * geometric declaration applies to the whole sketch.\n * @param sk - Sketch\n * @returns Sketch\n */\nexport function reset(sk: Sketch): Sketch {\n return { ...sk, selected: [] }\n}\n\n/**\n * val — CadQuery `Sketch.val()` parity: first effective face as a Shape.\n * @param sk - Sketch\n * @returns Shape\n */\nexport function val(sk: Sketch): ShapeHandle {\n const v = vals(sk)\n if (!v.length) throw new Error('Sketch has no faces')\n return v[0]\n}\n\n/**\n * vals — CadQuery `Sketch.vals()` parity: the current selection, or the\n * flattened topological faces when nothing is selected (upstream returns the\n * `_faces` faces; a fused handle may hold several).\n * @param sk - Sketch\n * @returns Shape[]\n */\nexport function vals(sk: Sketch): ShapeHandle[] {\n if (sk.selected.length) return [...sk.selected]\n const k = kernel()\n const out: ShapeHandle[] = []\n for (const f of sk.faces) {\n const sub = k.getSubShapes(f, 'face') as unknown as ShapeHandle[]\n out.push(...sub)\n }\n return out\n}\n\n/**\n * tag — CadQuery `Sketch.tag(name)` parity: store the current selection (or all\n * faces when nothing selected) under a name for later `.select()`.\n * @param sk - Sketch\n * @param name - tag name\n * @returns Sketch\n */\nexport function tag(sk: Sketch, name: string): Sketch {\n const tags = new Map(sk.tags)\n const payload = sk.selected.length ? sk.selected : sk.faces\n tags.set(name, [...payload])\n return { ...sk, tags }\n}\n\n/**\n * select — CadQuery `Sketch.select(tag)` parity: select the faces stored under\n * a tag.\n * @param sk - Sketch\n * @param name - tag name\n * @returns Sketch\n */\nexport function select(sk: Sketch, name: string): Sketch {\n const payload = sk.tags.get(name)\n if (!payload) throw new Error('Tag not found: ' + name)\n return { ...sk, selected: [...payload] }\n}\n\n/**\n * area — total surface area of the effective faces (upstream `_faces.Area()`).\n * @param sk - Sketch\n * @returns number\n */\nexport function area(sk: Sketch): number {\n const k = kernel()\n let total = 0\n for (const f of sk.faces) total += k.getSurfaceArea(f)\n return total\n}\n\n/**\n * faceCount — number of effective faces (upstream `_faces.Faces()` length).\n * @param sk - Sketch\n * @returns number\n */\nexport function faceCount(sk: Sketch): number {\n const k = kernel()\n let n = 0\n for (const f of sk.faces) n += (k.getSubShapes(f, 'face') as unknown as ShapeHandle[]).length\n return n\n}\n\n/**\n * extrude — CadQuery `Sketch` → solid via extrusion along +Z. Phase 2 action 3:\n * sketch → extrude/revolve dual-chain outlet. This is the brep side\n * (kernel.extrude on each effective face, fused into one solid).\n * @param sk - Sketch\n * @param height - extrusion height\n * @returns Shape (solid)\n */\nexport function extrude(sk: Sketch, height: number): ShapeHandle {\n const k = kernel()\n const solids: ShapeHandle[] = []\n for (const f of sk.faces) {\n solids.push(k.extrude(f, 0, 0, height))\n }\n let acc: ShapeHandle | null = null\n for (const s of solids) {\n if (!acc) {\n acc = s\n continue\n }\n const merged = k.fuse(acc, s)\n k.release(acc)\n k.release(s)\n acc = merged\n }\n if (!acc) throw new Error('Sketch has no faces to extrude')\n // Wrap the kernel handle into a faijs Shape so script-facing mirrors can\n // export it as a part (bare kernel handles are invisible to execute()).\n return fromHandle(acc) as unknown as ShapeHandle\n}\n\n/**\n * Release all handles held by a Sketch (run at end of script/unit test).\n * @param sk - Sketch whose kernel handles are released\n */\nexport function dispose(sk: Sketch): void {\n const k = kernel()\n for (const f of sk.faces) k.release(f)\n for (const [, fs] of sk.tags) for (const f of fs) k.release(f)\n for (const e of sk.selected) k.release(e)\n}\n"]}
|
package/dist/workplane.d.ts
CHANGED
|
@@ -186,6 +186,19 @@ export interface Workplane {
|
|
|
186
186
|
firstPoint?: [number, number];
|
|
187
187
|
/** Optional color (sRGB 0..1) for this part. */
|
|
188
188
|
color?: RGB;
|
|
189
|
+
/**
|
|
190
|
+
* Tagged workplane snapshots (CadQuery .tag()), keyed by tag name.
|
|
191
|
+
* Each snapshot records the plane frame and carried shape so
|
|
192
|
+
* workplaneFromTagged can jump back to the marked plane.
|
|
193
|
+
*/
|
|
194
|
+
tags?: Record<string, TaggedWorkplane>;
|
|
195
|
+
}
|
|
196
|
+
/** Snapshot captured by ag(): plane frame + carried shape. */
|
|
197
|
+
export interface TaggedWorkplane {
|
|
198
|
+
origin: [number, number, number];
|
|
199
|
+
xDir: [number, number, number];
|
|
200
|
+
normal: [number, number, number];
|
|
201
|
+
shape: Shape | null;
|
|
189
202
|
}
|
|
190
203
|
/**
|
|
191
204
|
* Resolve a CadQuery-style face selector string to the selected face's center
|
|
@@ -703,6 +716,15 @@ export declare function cskHole(wp: Workplane, diameter: number, cskDiameter: nu
|
|
|
703
716
|
* @returns Promise<Workplane>
|
|
704
717
|
*/
|
|
705
718
|
export declare function threadedHole(wp: Workplane, diameterOrFastener: number | unknown, depth?: number): Promise<Workplane>;
|
|
719
|
+
/**
|
|
720
|
+
* siblings — CadQuery Shape.siblings:拓扑邻接选择(Phase 3)。
|
|
721
|
+
* @param start - 起点(Workplane 带 faceSel/edgeSel,或 Shape)。
|
|
722
|
+
* @param ctxShape - 邻接搜索的容器 shape(CadQuery 的 ctx)。
|
|
723
|
+
* @param kind - 链接实体类型:'Edge'(返回面网络)| 'Vertex'(返回边网络)| 'Face'。
|
|
724
|
+
* @param level - 拓扑距离:int 或 int 数组(各层并集,每层独立排除)。
|
|
725
|
+
* @returns Promise<Workplane> 选中的实体集合(shape = 实体 compound;空集返回空 compound)。
|
|
726
|
+
*/
|
|
727
|
+
export declare function siblings(start: Shape | Workplane, ctxShape: Shape | Workplane, kind: 'Edge' | 'Vertex' | 'Face', level: number | number[]): Promise<Workplane>;
|
|
706
728
|
/**
|
|
707
729
|
* faces
|
|
708
730
|
* @param wp - Workplane
|
|
@@ -710,6 +732,31 @@ export declare function threadedHole(wp: Workplane, diameterOrFastener: number |
|
|
|
710
732
|
* @returns Workplane
|
|
711
733
|
*/
|
|
712
734
|
export declare function faces(wp: Workplane, sel: string): Workplane;
|
|
735
|
+
/**
|
|
736
|
+
* tag — CadQuery Workplane.tag(name) parity (dataflow carrier).
|
|
737
|
+
*
|
|
738
|
+
* Upstream records the current workplane state (origin/xDir/normal + current
|
|
739
|
+
* objects) under a name so a later workplaneFromTagged can jump back to it.
|
|
740
|
+
* The faijs carrier keeps a snapshot of the plane frame and the carried
|
|
741
|
+
* shape; the tagged objects stay the current shape's sub-shapes.
|
|
742
|
+
*
|
|
743
|
+
* @param wp - Workplane to mark
|
|
744
|
+
* @param name - Tag name
|
|
745
|
+
* @returns Workplane carrying the tag snapshot
|
|
746
|
+
*/
|
|
747
|
+
export declare function tag(wp: Workplane, name: string): Workplane;
|
|
748
|
+
/**
|
|
749
|
+
* workplaneFromTagged — CadQuery Workplane.workplaneFromTagged(name) parity.
|
|
750
|
+
*
|
|
751
|
+
* Restores the workplane frame (origin/xDir/normal) and carried shape captured
|
|
752
|
+
* by an earlier ag(name). Points/selectors are reset (upstream jumps back
|
|
753
|
+
* to the tagged plane with an empty stack).
|
|
754
|
+
*
|
|
755
|
+
* @param wp - Workplane carrying the tags
|
|
756
|
+
* @param name - Tag name to restore
|
|
757
|
+
* @returns Workplane restored to the tagged plane
|
|
758
|
+
*/
|
|
759
|
+
export declare function workplaneFromTagged(wp: Workplane, name: string): Workplane;
|
|
713
760
|
/**
|
|
714
761
|
* edges
|
|
715
762
|
* @param wp - Workplane
|