brepjs 18.124.8 → 18.126.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.
- package/dist/brepjs.cjs +689 -57
- package/dist/brepjs.js +700 -68
- package/dist/csg/builders.d.ts +21 -2
- package/dist/csg/evaluators/extrude.d.ts +5 -0
- package/dist/csg/evaluators/loft.d.ts +5 -0
- package/dist/csg/evaluators/path.d.ts +5 -0
- package/dist/csg/evaluators/profileFace.d.ts +8 -0
- package/dist/csg/evaluators/revolve.d.ts +5 -0
- package/dist/csg/expressions.d.ts +1 -0
- package/dist/csg/index.d.ts +3 -2
- package/dist/csg/segments.d.ts +44 -0
- package/dist/csg/types.d.ts +32 -1
- package/package.json +7 -7
package/dist/brepjs.js
CHANGED
|
@@ -16,7 +16,7 @@ import { a as isSameShape, i as isEqualShape, n as getHashCode, o as simplify$1,
|
|
|
16
16
|
import { a as curveIsPeriodic, c as curvePointAt, d as flipOrientation, f as getCurveType, h as offsetWire2D, i as curveIsClosed, l as curveStartPoint, m as interpolateCurve, n as curveAxis, o as curveLength, p as getOrientation, r as curveEndPoint, s as curvePeriod, t as approximateCurve, u as curveTangentAt } from "./curveFns-Bh_PHl9N.js";
|
|
17
17
|
import { a as meshEdges$1, c as meshMultiLOD, d as createMeshCache, i as mesh$1, l as buildMeshCacheKey, n as exportSTEP, o as meshLODs, r as exportSTL, s as meshLODsProgressive, t as exportIGES, u as clearMeshCache } from "./meshFns-CpfeEN1b.js";
|
|
18
18
|
import { n as getAtOrThrow, r as lastOrThrow, t as firstOrThrow } from "./arrayAccess-DrUGPADn.js";
|
|
19
|
-
import { _ as makeThreePointArc, d as makeCircle, h as makeLine, l as makeBSplineInterpolation, n as fill, r as makeFace, s as assembleWire } from "./surfaceBuilders-B7WlmoVr.js";
|
|
19
|
+
import { _ as makeThreePointArc, d as makeCircle, h as makeLine, l as makeBSplineInterpolation, n as fill, p as makeEllipseArc, r as makeFace, s as assembleWire, u as makeBezierCurve } from "./surfaceBuilders-B7WlmoVr.js";
|
|
20
20
|
import { A as toBufferGeometryData, C as shellWithEvolution, D as getNurbsCurveData, E as fuseAllBisect, M as toLODGeometryData, N as toLODGeometryLevels, O as getNurbsSurfaceData, P as toLineGeometryData, S as intersectWithEvolution, T as cutAllBisect, _ as positionOnCurve, a as healFace, b as filletWithEvolution, c as isValid$1, d as draft$1, f as fillet$1, g as variableFillet, h as thicken$1, i as heal$1, j as toGroupedBufferGeometryData, k as chamferDistAngle, l as solidFromShell, m as shell$1, n as fixSelfIntersection, o as healSolid, p as offset$1, r as fixShape, s as healWire, t as autoHeal, u as chamfer$1, v as chamferWithEvolution, w as checkBoolean, x as fuseWithEvolution, y as cutWithEvolution } from "./healingFns-Digw1d6D.js";
|
|
21
21
|
import { A as setJointValue, B as createAssemblyNode, C as cylindricalJoint, D as planarJoint, E as mechanismDOF, F as quatMultiply, G as circularPattern, H as removeChild, I as quatRotate, J as exportAssemblySTEP, K as gridPattern, L as addChild, M as sphericalJoint, N as quatFromAxisAngle, O as prismaticJoint, P as quatFromTo, R as collectShapes, S as addJoint, T as jointTransform, U as updateNode, V as findNode, W as walkAssembly, Y as createAssembly, _ as exportURDF, a as deserializeHistory, b as inverseKinematics, c as modifyStep, d as replayFrom, f as replayHistory, g as undoLast, h as stepsFrom, i as createRegistry, j as setJointValues, k as revoluteJoint, l as registerOperation, m as stepCount, n as addStep, o as findStep, p as serializeHistory, q as linearPattern, r as createHistory, s as getShape, t as thread, u as registerShape, v as importURDF, w as forwardKinematics, x as jointTrajectory, y as jointsFromDH, z as countNodes } from "./threadFns-BWbibv4L.js";
|
|
22
22
|
import { n as BaseSketcher2d, r as organiseBlueprints, t as BlueprintSketcher } from "./blueprintSketcher-yZiAeqft.js";
|
|
@@ -27,8 +27,8 @@ import { t as cornerFinder } from "./cornerFinder-CiHpo7kU.js";
|
|
|
27
27
|
import { a as fuseBlueprints, c as roundedRectangleBlueprint, i as cutBlueprints, n as fuse2D, o as intersectBlueprints, r as intersect2D, s as polysidesBlueprint, t as cut2D } from "./boolean2D-BuM5xJSa.js";
|
|
28
28
|
import { S as reverseCurve, _ as curve2dIsOnCurve, a as isInside2D, b as curve2dSplitAt, c as scale2D, d as stretch2D, f as toSVGPathD, g as curve2dFirstPoint, h as curve2dDistanceFrom, i as getOrientation2D, l as sketchOnFace2D, m as curve2dBoundingBox, n as createCompoundBlueprint, o as mirror2D, p as translate2D, r as getBounds2D, s as rotate2D, t as createBlueprint, u as sketchOnPlane2D, v as curve2dLastPoint, x as curve2dTangentAt, y as curve2dParameter } from "./blueprintFns-COSD5yZH.js";
|
|
29
29
|
import { a as importSVG, c as blueprintToDXF, d as exportGltf, f as exportOBJ, i as exportSTEPConfigured, l as exportDXF, n as importSTEP, o as importSVGPathD, r as importSTL, s as exportThreeMF, t as importIGES, u as exportGlb } from "./importFns-BId6d2pt.js";
|
|
30
|
-
import { a as multiSectionSweep, c as twistExtrude, i as guidedSweep, n as loftAll, o as supportExtrude, r as complexExtrude, s as sweep$1, t as loft$
|
|
31
|
-
import { a as Sketch, b as extrudeAll, c as compoundSketchLoft, d as sketchFace, f as sketchLoft, h as sketchWires, i as Sketches, l as compoundSketchRevolve, m as sketchSweep, n as getFont, o as compoundSketchExtrude, p as sketchRevolve, r as loadFont, s as compoundSketchFace, t as textBlueprints, u as sketchExtrude, v as CompoundSketch, x as revolve$
|
|
30
|
+
import { a as multiSectionSweep, c as twistExtrude, i as guidedSweep, n as loftAll, o as supportExtrude, r as complexExtrude, s as sweep$1, t as loft$2 } from "./loftFns-m7LoJWE2.js";
|
|
31
|
+
import { a as Sketch, b as extrudeAll, c as compoundSketchLoft, d as sketchFace, f as sketchLoft, h as sketchWires, i as Sketches, l as compoundSketchRevolve, m as sketchSweep, n as getFont, o as compoundSketchExtrude, p as sketchRevolve, r as loadFont, s as compoundSketchFace, t as textBlueprints, u as sketchExtrude, v as CompoundSketch, x as revolve$2, y as extrude$2 } from "./textBlueprints-C1aMaWLc.js";
|
|
32
32
|
import { a as makeProjectedEdges, i as projectEdges, n as cameraLookAt, r as createCamera, s as isProjectionPlane, t as cameraFromPlane } from "./cameraFns-VVI0cWLa.js";
|
|
33
33
|
import { n as textMetrics, r as sketchText, t as fontMetrics } from "./textMetrics-DH3YPwVC.js";
|
|
34
34
|
import { a as facesOfVertex, c as verticesOfFace, i as facesOfEdge, l as wiresOfFace, n as adjacentFaces, o as sharedEdges, r as edgesOfFace, s as verticesOfEdge } from "./adjacencyFns-CwcdjOsT.js";
|
|
@@ -264,8 +264,8 @@ function repairMesh(mesh, opts, id) {
|
|
|
264
264
|
if (isErr(engine)) return engine;
|
|
265
265
|
try {
|
|
266
266
|
try {
|
|
267
|
-
var _usingCtx$
|
|
268
|
-
const repaired = _usingCtx$
|
|
267
|
+
var _usingCtx$10 = _usingCtx();
|
|
268
|
+
const repaired = _usingCtx$10.u(engine.value.repair_mesh(mesh.vertices, mesh.triangles, resolution, padding));
|
|
269
269
|
const vertexCount = repaired.positions.length / 3;
|
|
270
270
|
return ok({
|
|
271
271
|
vertices: repaired.positions,
|
|
@@ -279,9 +279,9 @@ function repairMesh(mesh, opts, id) {
|
|
|
279
279
|
}]
|
|
280
280
|
});
|
|
281
281
|
} catch (_) {
|
|
282
|
-
_usingCtx$
|
|
282
|
+
_usingCtx$10.e = _;
|
|
283
283
|
} finally {
|
|
284
|
-
_usingCtx$
|
|
284
|
+
_usingCtx$10.d();
|
|
285
285
|
}
|
|
286
286
|
} catch (cause) {
|
|
287
287
|
return err(computationError("VOXEL_REPAIR_FAILED", cause instanceof Error ? cause.message : "voxel repair failed (grid too large?).", cause));
|
|
@@ -360,12 +360,12 @@ function offsetMesh(mesh, distance, opts, id) {
|
|
|
360
360
|
if (isErr(engine)) return engine;
|
|
361
361
|
try {
|
|
362
362
|
try {
|
|
363
|
-
var _usingCtx$
|
|
364
|
-
return meshFromResult(_usingCtx$
|
|
363
|
+
var _usingCtx$9 = _usingCtx();
|
|
364
|
+
return meshFromResult(_usingCtx$9.u(engine.value.offset_mesh(mesh.vertices, mesh.triangles, distance, params.value.resolution, params.value.padding)));
|
|
365
365
|
} catch (_) {
|
|
366
|
-
_usingCtx$
|
|
366
|
+
_usingCtx$9.e = _;
|
|
367
367
|
} finally {
|
|
368
|
-
_usingCtx$
|
|
368
|
+
_usingCtx$9.d();
|
|
369
369
|
}
|
|
370
370
|
} catch (cause) {
|
|
371
371
|
return err(computationError("VOXEL_OFFSET_FAILED", cause instanceof Error ? cause.message : "voxel offset failed (grid too large?).", cause));
|
|
@@ -490,9 +490,9 @@ function resolveGridParams$1(opts) {
|
|
|
490
490
|
*/
|
|
491
491
|
function meshFromField(field) {
|
|
492
492
|
try {
|
|
493
|
-
var _usingCtx$
|
|
493
|
+
var _usingCtx$8 = _usingCtx();
|
|
494
494
|
const rawResult = field.contour();
|
|
495
|
-
const { positions, normals, indices } = _usingCtx$
|
|
495
|
+
const { positions, normals, indices } = _usingCtx$8.u({
|
|
496
496
|
value: rawResult,
|
|
497
497
|
[Symbol.dispose]() {
|
|
498
498
|
rawResult.free();
|
|
@@ -512,9 +512,9 @@ function meshFromField(field) {
|
|
|
512
512
|
}]
|
|
513
513
|
});
|
|
514
514
|
} catch (_) {
|
|
515
|
-
_usingCtx$
|
|
515
|
+
_usingCtx$8.e = _;
|
|
516
516
|
} finally {
|
|
517
|
-
_usingCtx$
|
|
517
|
+
_usingCtx$8.d();
|
|
518
518
|
}
|
|
519
519
|
}
|
|
520
520
|
function fieldDeletable(raw) {
|
|
@@ -1082,13 +1082,13 @@ function latticeInfill(mesh, opts, id) {
|
|
|
1082
1082
|
const { tag, period, thickness, resolution, padding } = resolved.value;
|
|
1083
1083
|
try {
|
|
1084
1084
|
try {
|
|
1085
|
-
var _usingCtx$
|
|
1086
|
-
const repaired = _usingCtx$
|
|
1085
|
+
var _usingCtx$7 = _usingCtx();
|
|
1086
|
+
const repaired = _usingCtx$7.u(engine.value.lattice_infill(mesh.vertices, mesh.triangles, resolution, padding, tag, period, thickness));
|
|
1087
1087
|
return ok(toMesh(repaired));
|
|
1088
1088
|
} catch (_) {
|
|
1089
|
-
_usingCtx$
|
|
1089
|
+
_usingCtx$7.e = _;
|
|
1090
1090
|
} finally {
|
|
1091
|
-
_usingCtx$
|
|
1091
|
+
_usingCtx$7.d();
|
|
1092
1092
|
}
|
|
1093
1093
|
} catch (cause) {
|
|
1094
1094
|
return err(computationError("LATTICE_INFILL_FAILED", cause instanceof Error ? cause.message : "lattice infill failed (grid too large?).", cause));
|
|
@@ -1567,7 +1567,7 @@ function polyhedron(points, faces, options = {}) {
|
|
|
1567
1567
|
}
|
|
1568
1568
|
//#endregion
|
|
1569
1569
|
//#region src/operations/straightSkeleton.ts
|
|
1570
|
-
var EPS = 1e-10;
|
|
1570
|
+
var EPS$1 = 1e-10;
|
|
1571
1571
|
function cross2(ax, ay, bx, by) {
|
|
1572
1572
|
return ax * by - ay * bx;
|
|
1573
1573
|
}
|
|
@@ -1605,7 +1605,7 @@ function bisector(poly, i) {
|
|
|
1605
1605
|
const e2x = next.x - cur.x;
|
|
1606
1606
|
const e2y = next.y - cur.y;
|
|
1607
1607
|
const e2l = len2(e2x, e2y);
|
|
1608
|
-
if (e1l < EPS || e2l < EPS) return {
|
|
1608
|
+
if (e1l < EPS$1 || e2l < EPS$1) return {
|
|
1609
1609
|
dx: 0,
|
|
1610
1610
|
dy: 0
|
|
1611
1611
|
};
|
|
@@ -1616,14 +1616,14 @@ function bisector(poly, i) {
|
|
|
1616
1616
|
let bx = n1x + n2x;
|
|
1617
1617
|
let by = n1y + n2y;
|
|
1618
1618
|
const bl = len2(bx, by);
|
|
1619
|
-
if (bl < EPS) return {
|
|
1619
|
+
if (bl < EPS$1) return {
|
|
1620
1620
|
dx: n1x,
|
|
1621
1621
|
dy: n1y
|
|
1622
1622
|
};
|
|
1623
1623
|
bx /= bl;
|
|
1624
1624
|
by /= bl;
|
|
1625
1625
|
const cosHalf = dot2(bx, by, n1x, n1y);
|
|
1626
|
-
const speed = Math.abs(cosHalf) > EPS ? 1 / cosHalf : 1;
|
|
1626
|
+
const speed = Math.abs(cosHalf) > EPS$1 ? 1 / cosHalf : 1;
|
|
1627
1627
|
return {
|
|
1628
1628
|
dx: bx * speed,
|
|
1629
1629
|
dy: by * speed
|
|
@@ -1685,14 +1685,14 @@ function bisectorIntersectTime(a, b) {
|
|
|
1685
1685
|
const ddy = a.by - b.by;
|
|
1686
1686
|
const dxp = b.x - a.x;
|
|
1687
1687
|
const dyp = b.y - a.y;
|
|
1688
|
-
if (Math.abs(ddx) < EPS && Math.abs(ddy) < EPS) return null;
|
|
1688
|
+
if (Math.abs(ddx) < EPS$1 && Math.abs(ddy) < EPS$1) return null;
|
|
1689
1689
|
let t;
|
|
1690
1690
|
if (Math.abs(ddx) > Math.abs(ddy)) t = dxp / ddx;
|
|
1691
1691
|
else t = dyp / ddy;
|
|
1692
|
-
if (t < EPS) return null;
|
|
1692
|
+
if (t < EPS$1) return null;
|
|
1693
1693
|
const otherDd = Math.abs(ddx) > Math.abs(ddy) ? ddy : ddx;
|
|
1694
1694
|
const otherDp = Math.abs(ddx) > Math.abs(ddy) ? dyp : dxp;
|
|
1695
|
-
if (Math.abs(otherDd) > EPS) {
|
|
1695
|
+
if (Math.abs(otherDd) > EPS$1) {
|
|
1696
1696
|
const t2 = otherDp / otherDd;
|
|
1697
1697
|
if (Math.abs(t - t2) > 1e-4 * Math.max(1, Math.abs(t))) return null;
|
|
1698
1698
|
}
|
|
@@ -1703,16 +1703,16 @@ function raySplitTime(node, eA, eB) {
|
|
|
1703
1703
|
const edx = eB.x - eA.x;
|
|
1704
1704
|
const edy = eB.y - eA.y;
|
|
1705
1705
|
const el = len2(edx, edy);
|
|
1706
|
-
if (el < EPS) return null;
|
|
1706
|
+
if (el < EPS$1) return null;
|
|
1707
1707
|
const enx = -edy / el;
|
|
1708
1708
|
const eny = edx / el;
|
|
1709
1709
|
const d0 = (node.x - eA.x) * enx + (node.y - eA.y) * eny;
|
|
1710
1710
|
const relBx = node.bx - (eA.bx + eB.bx) / 2;
|
|
1711
1711
|
const relBy = node.by - (eA.by + eB.by) / 2;
|
|
1712
1712
|
const dRate = relBx * enx + relBy * eny;
|
|
1713
|
-
if (Math.abs(dRate) < EPS) return null;
|
|
1713
|
+
if (Math.abs(dRate) < EPS$1) return null;
|
|
1714
1714
|
const t = -d0 / dRate;
|
|
1715
|
-
if (t < EPS) return null;
|
|
1715
|
+
if (t < EPS$1) return null;
|
|
1716
1716
|
const px = node.x + t * node.bx;
|
|
1717
1717
|
const py = node.y + t * node.by;
|
|
1718
1718
|
const ax = eA.x + t * eA.bx;
|
|
@@ -1722,7 +1722,7 @@ function raySplitTime(node, eA, eB) {
|
|
|
1722
1722
|
const segDx = bxx - ax;
|
|
1723
1723
|
const segDy = byy - ay;
|
|
1724
1724
|
const segL = len2(segDx, segDy);
|
|
1725
|
-
if (segL < EPS) return t;
|
|
1725
|
+
if (segL < EPS$1) return t;
|
|
1726
1726
|
const s = dot2(px - ax, py - ay, segDx, segDy) / (segL * segL);
|
|
1727
1727
|
if (s < -.01 || s > 1.01) return null;
|
|
1728
1728
|
return t;
|
|
@@ -1732,7 +1732,7 @@ function computeEvents(lavNodes) {
|
|
|
1732
1732
|
for (const node of lavNodes) {
|
|
1733
1733
|
if (!node.active || !node.next) continue;
|
|
1734
1734
|
const t = bisectorIntersectTime(node, node.next);
|
|
1735
|
-
if (t !== null && t > EPS) {
|
|
1735
|
+
if (t !== null && t > EPS$1) {
|
|
1736
1736
|
const x = node.x + t * node.bx;
|
|
1737
1737
|
const y = node.y + t * node.by;
|
|
1738
1738
|
events.push({
|
|
@@ -1749,7 +1749,7 @@ function computeEvents(lavNodes) {
|
|
|
1749
1749
|
let count = 0;
|
|
1750
1750
|
while (cur !== node.prev && cur !== node && count < 1e3) {
|
|
1751
1751
|
const st = raySplitTime(node, cur, cur.next);
|
|
1752
|
-
if (st !== null && st > EPS) {
|
|
1752
|
+
if (st !== null && st > EPS$1) {
|
|
1753
1753
|
const x = node.x + st * node.bx;
|
|
1754
1754
|
const y = node.y + st * node.by;
|
|
1755
1755
|
events.push({
|
|
@@ -1805,7 +1805,7 @@ function computeStraightSkeletonImpl(polygon) {
|
|
|
1805
1805
|
const b = a.next;
|
|
1806
1806
|
const c = b.next;
|
|
1807
1807
|
const t = bisectorIntersectTime(a, b);
|
|
1808
|
-
const time = t !== null && t > EPS ? t : 0;
|
|
1808
|
+
const time = t !== null && t > EPS$1 ? t : 0;
|
|
1809
1809
|
const mx = (a.x + b.x + c.x) / 3 + time * (a.bx + b.bx + c.bx) / 3;
|
|
1810
1810
|
const my = (a.y + b.y + c.y) / 3 + time * (a.by + b.by + c.by) / 3;
|
|
1811
1811
|
const nodeIdx = skeletonNodes.length;
|
|
@@ -1944,7 +1944,7 @@ function computeStraightSkeletonImpl(polygon) {
|
|
|
1944
1944
|
if (!sn) continue;
|
|
1945
1945
|
const lastVert = faceVerts[faceVerts.length - 1];
|
|
1946
1946
|
if (!lastVert) continue;
|
|
1947
|
-
if (len2(sn.x - lastVert.x, sn.y - lastVert.y) > EPS) {
|
|
1947
|
+
if (len2(sn.x - lastVert.x, sn.y - lastVert.y) > EPS$1) {
|
|
1948
1948
|
faceVerts.push({
|
|
1949
1949
|
x: sn.x,
|
|
1950
1950
|
y: sn.y
|
|
@@ -3737,7 +3737,7 @@ function isEmpty(shape) {
|
|
|
3737
3737
|
*/
|
|
3738
3738
|
function extrude(face, height) {
|
|
3739
3739
|
const f = resolve(face);
|
|
3740
|
-
return extrude$
|
|
3740
|
+
return extrude$2(f, typeof height === "number" ? [
|
|
3741
3741
|
0,
|
|
3742
3742
|
0,
|
|
3743
3743
|
height
|
|
@@ -3752,7 +3752,7 @@ function revolve(face, options) {
|
|
|
3752
3752
|
0,
|
|
3753
3753
|
0
|
|
3754
3754
|
];
|
|
3755
|
-
return revolve$
|
|
3755
|
+
return revolve$2(resolve(face), pivotPoint, options?.axis ?? [
|
|
3756
3756
|
0,
|
|
3757
3757
|
0,
|
|
3758
3758
|
1
|
|
@@ -3763,7 +3763,7 @@ function revolve(face, options) {
|
|
|
3763
3763
|
*/
|
|
3764
3764
|
function loft(wires, options) {
|
|
3765
3765
|
const resolvedWires = wires.map((w) => resolve(w));
|
|
3766
|
-
return loft$
|
|
3766
|
+
return loft$2(resolvedWires, options);
|
|
3767
3767
|
}
|
|
3768
3768
|
//#endregion
|
|
3769
3769
|
//#region src/operations/compoundOpsFns.ts
|
|
@@ -3910,7 +3910,7 @@ function drill(shape, options) {
|
|
|
3910
3910
|
*/
|
|
3911
3911
|
function pocket(shape, options) {
|
|
3912
3912
|
try {
|
|
3913
|
-
var _usingCtx$
|
|
3913
|
+
var _usingCtx$6 = _usingCtx();
|
|
3914
3914
|
const s = resolve(shape);
|
|
3915
3915
|
const { profile, depth } = options;
|
|
3916
3916
|
if (depth <= 0) return err(validationError("POCKET_INVALID_DEPTH", "Pocket depth must be positive"));
|
|
@@ -3919,7 +3919,7 @@ function pocket(shape, options) {
|
|
|
3919
3919
|
const targetFace = targetResult.value;
|
|
3920
3920
|
const normal = normalAt(targetFace);
|
|
3921
3921
|
const center = faceCenter(targetFace);
|
|
3922
|
-
const scope = _usingCtx$
|
|
3922
|
+
const scope = _usingCtx$6.u(new DisposalScope());
|
|
3923
3923
|
const { wire: w, owned } = toWire(profile);
|
|
3924
3924
|
if (owned) scope.register(w);
|
|
3925
3925
|
const faceResult = makeFace(w);
|
|
@@ -3927,14 +3927,14 @@ function pocket(shape, options) {
|
|
|
3927
3927
|
scope.register(faceResult.value);
|
|
3928
3928
|
const positioned = scope.register(translate$2(faceResult.value, center));
|
|
3929
3929
|
const extDir = vecScale(vecNormalize(normal), -depth);
|
|
3930
|
-
const toolResult = extrude$
|
|
3930
|
+
const toolResult = extrude$2(positioned, extDir);
|
|
3931
3931
|
if (isErr(toolResult)) return toolResult;
|
|
3932
3932
|
scope.register(toolResult.value);
|
|
3933
3933
|
return cut$2(s, toolResult.value, { unsafe: true });
|
|
3934
3934
|
} catch (_) {
|
|
3935
|
-
_usingCtx$
|
|
3935
|
+
_usingCtx$6.e = _;
|
|
3936
3936
|
} finally {
|
|
3937
|
-
_usingCtx$
|
|
3937
|
+
_usingCtx$6.d();
|
|
3938
3938
|
}
|
|
3939
3939
|
}
|
|
3940
3940
|
/**
|
|
@@ -3962,7 +3962,7 @@ function boss(shape, options) {
|
|
|
3962
3962
|
scope.register(faceResult.value);
|
|
3963
3963
|
const positioned = scope.register(translate$2(faceResult.value, center));
|
|
3964
3964
|
const extDir = vecScale(vecNormalize(normal), height);
|
|
3965
|
-
const toolResult = extrude$
|
|
3965
|
+
const toolResult = extrude$2(positioned, extDir);
|
|
3966
3966
|
if (isErr(toolResult)) return toolResult;
|
|
3967
3967
|
scope.register(toolResult.value);
|
|
3968
3968
|
return fuse$2(s, toolResult.value, { unsafe: true });
|
|
@@ -4524,12 +4524,12 @@ function makeInternalGearProfileWire(params) {
|
|
|
4524
4524
|
}
|
|
4525
4525
|
function makeProfileWire(params, isInternal) {
|
|
4526
4526
|
try {
|
|
4527
|
-
var _usingCtx$
|
|
4527
|
+
var _usingCtx$5 = _usingCtx();
|
|
4528
4528
|
const { teeth, moduleSize, pressureAngle, shift, clearance, flankThinning, samples = adaptiveSampleCount(moduleSize) } = params;
|
|
4529
4529
|
if (teeth < 4) return err(validationError("GEAR_TEETH_TOO_FEW", `gear needs ≥ 4 teeth, got ${teeth}`));
|
|
4530
4530
|
if (moduleSize <= 0) return err(validationError("GEAR_MODULE_NONPOSITIVE", `module must be > 0, got ${moduleSize}`));
|
|
4531
4531
|
const tm = gearGeometry(teeth, moduleSize, pressureAngle, shift, clearance, flankThinning, isInternal);
|
|
4532
|
-
const scope = _usingCtx$
|
|
4532
|
+
const scope = _usingCtx$5.u(new DisposalScope());
|
|
4533
4533
|
const allEdges = [];
|
|
4534
4534
|
for (let i = 0; i < teeth; i++) {
|
|
4535
4535
|
const periodEdges = buildToothPeriodEdges(tm, i, teeth, samples, scope);
|
|
@@ -4540,9 +4540,9 @@ function makeProfileWire(params, isInternal) {
|
|
|
4540
4540
|
if (isErr(wireResult)) return wireResult;
|
|
4541
4541
|
return ok(wireResult.value);
|
|
4542
4542
|
} catch (_) {
|
|
4543
|
-
_usingCtx$
|
|
4543
|
+
_usingCtx$5.e = _;
|
|
4544
4544
|
} finally {
|
|
4545
|
-
_usingCtx$
|
|
4545
|
+
_usingCtx$5.d();
|
|
4546
4546
|
}
|
|
4547
4547
|
}
|
|
4548
4548
|
//#endregion
|
|
@@ -4723,8 +4723,8 @@ function resolvePlanetaryParams(params) {
|
|
|
4723
4723
|
}
|
|
4724
4724
|
function makeOuterCircleWire(radius) {
|
|
4725
4725
|
try {
|
|
4726
|
-
var _usingCtx$
|
|
4727
|
-
const circleEdge = _usingCtx$
|
|
4726
|
+
var _usingCtx$4 = _usingCtx();
|
|
4727
|
+
const circleEdge = _usingCtx$4.u(new DisposalScope()).register(makeCircle(radius, [
|
|
4728
4728
|
0,
|
|
4729
4729
|
0,
|
|
4730
4730
|
0
|
|
@@ -4737,9 +4737,9 @@ function makeOuterCircleWire(radius) {
|
|
|
4737
4737
|
if (isErr(wireResult)) return wireResult;
|
|
4738
4738
|
return ok(wireResult.value);
|
|
4739
4739
|
} catch (_) {
|
|
4740
|
-
_usingCtx$
|
|
4740
|
+
_usingCtx$4.e = _;
|
|
4741
4741
|
} finally {
|
|
4742
|
-
_usingCtx$
|
|
4742
|
+
_usingCtx$4.d();
|
|
4743
4743
|
}
|
|
4744
4744
|
}
|
|
4745
4745
|
function finalizeExternalSolid(wire, thickness, bore, geom, diagnostics) {
|
|
@@ -4750,7 +4750,7 @@ function finalizeExternalSolid(wire, thickness, bore, geom, diagnostics) {
|
|
|
4750
4750
|
const faceResult = makeFace(wire);
|
|
4751
4751
|
if (isErr(faceResult)) return faceResult;
|
|
4752
4752
|
profileScope.register(faceResult.value);
|
|
4753
|
-
const solidResult = extrude$
|
|
4753
|
+
const solidResult = extrude$2(faceResult.value, [
|
|
4754
4754
|
0,
|
|
4755
4755
|
0,
|
|
4756
4756
|
thickness
|
|
@@ -4762,7 +4762,7 @@ function finalizeExternalSolid(wire, thickness, bore, geom, diagnostics) {
|
|
|
4762
4762
|
const boreFaceResult = makeBoreFace(bore / 2);
|
|
4763
4763
|
if (isErr(boreFaceResult)) return boreFaceResult;
|
|
4764
4764
|
boreScope.register(boreFaceResult.value);
|
|
4765
|
-
const boreRaw = extrude$
|
|
4765
|
+
const boreRaw = extrude$2(boreFaceResult.value, [
|
|
4766
4766
|
0,
|
|
4767
4767
|
0,
|
|
4768
4768
|
thickness + 1
|
|
@@ -4791,7 +4791,7 @@ function makeBoreFace(radius) {
|
|
|
4791
4791
|
function finalizeInternalSolid(outerWire, innerToothedWire, thickness, geom, diagnostics) {
|
|
4792
4792
|
const faceResult = makeFace(outerWire, [innerToothedWire]);
|
|
4793
4793
|
if (isErr(faceResult)) return faceResult;
|
|
4794
|
-
const solidResult = extrude$
|
|
4794
|
+
const solidResult = extrude$2(faceResult.value, [
|
|
4795
4795
|
0,
|
|
4796
4796
|
0,
|
|
4797
4797
|
thickness
|
|
@@ -5336,6 +5336,14 @@ function evalVec3(expr, env, where) {
|
|
|
5336
5336
|
c
|
|
5337
5337
|
]);
|
|
5338
5338
|
}
|
|
5339
|
+
function evalVec2(expr, env, where) {
|
|
5340
|
+
const r = evalExpr(expr, env);
|
|
5341
|
+
if (!r.ok) return r;
|
|
5342
|
+
const v = expectVecLen(r.value, 2, where);
|
|
5343
|
+
if (!v.ok) return v;
|
|
5344
|
+
const [a, b] = v.value;
|
|
5345
|
+
return ok([a, b]);
|
|
5346
|
+
}
|
|
5339
5347
|
function projectEnv(env, deps) {
|
|
5340
5348
|
if (deps.size === 0) return Object.freeze({});
|
|
5341
5349
|
const out = {};
|
|
@@ -5346,6 +5354,91 @@ function projectEnv(env, deps) {
|
|
|
5346
5354
|
return Object.freeze(out);
|
|
5347
5355
|
}
|
|
5348
5356
|
//#endregion
|
|
5357
|
+
//#region src/csg/segments.ts
|
|
5358
|
+
/**
|
|
5359
|
+
* Serializable 2D segment vocabulary — endpoint-parametrized (SVG-style)
|
|
5360
|
+
* curve segments shared by the Path node (open spines) and, later, Profile
|
|
5361
|
+
* contours. Positions and radii are expressions, so `freeParams` propagates
|
|
5362
|
+
* and segment data hashes with the same FNV machinery as every node field.
|
|
5363
|
+
*/
|
|
5364
|
+
function lineTo(to) {
|
|
5365
|
+
return {
|
|
5366
|
+
kind: "Line",
|
|
5367
|
+
to: asVec2Expr(to)
|
|
5368
|
+
};
|
|
5369
|
+
}
|
|
5370
|
+
function arcTo(to, radius, options) {
|
|
5371
|
+
return {
|
|
5372
|
+
kind: "Arc",
|
|
5373
|
+
to: asVec2Expr(to),
|
|
5374
|
+
radius: asScalarExpr(radius),
|
|
5375
|
+
largeArc: options?.largeArc ?? false,
|
|
5376
|
+
clockwise: options?.clockwise ?? false
|
|
5377
|
+
};
|
|
5378
|
+
}
|
|
5379
|
+
function bezierTo(controls, to) {
|
|
5380
|
+
return {
|
|
5381
|
+
kind: "Bezier",
|
|
5382
|
+
controls: controls.map(asVec2Expr),
|
|
5383
|
+
to: asVec2Expr(to)
|
|
5384
|
+
};
|
|
5385
|
+
}
|
|
5386
|
+
function ellipseArcTo(to, radii, options) {
|
|
5387
|
+
return {
|
|
5388
|
+
kind: "EllipseArc",
|
|
5389
|
+
to: asVec2Expr(to),
|
|
5390
|
+
radii: asVec2Expr(radii),
|
|
5391
|
+
rotation: asScalarExpr(options?.rotation ?? 0),
|
|
5392
|
+
largeArc: options?.largeArc ?? false,
|
|
5393
|
+
clockwise: options?.clockwise ?? false
|
|
5394
|
+
};
|
|
5395
|
+
}
|
|
5396
|
+
function hashSegments(h0, segments) {
|
|
5397
|
+
let h = fnvMixInt32(h0, segments.length);
|
|
5398
|
+
const mix = (acc, e) => fnvMixHash(acc, e.structuralHash);
|
|
5399
|
+
for (const s of segments) {
|
|
5400
|
+
h = fnvMixString(h, s.kind);
|
|
5401
|
+
h = mix(h, s.to);
|
|
5402
|
+
if (s.kind === "Arc") {
|
|
5403
|
+
h = mix(h, s.radius);
|
|
5404
|
+
h = fnvMixBool(fnvMixBool(h, s.largeArc), s.clockwise);
|
|
5405
|
+
} else if (s.kind === "Bezier") {
|
|
5406
|
+
h = fnvMixInt32(h, s.controls.length);
|
|
5407
|
+
for (const c of s.controls) h = mix(h, c);
|
|
5408
|
+
} else if (s.kind === "EllipseArc") {
|
|
5409
|
+
h = mix(h, s.radii);
|
|
5410
|
+
h = mix(h, s.rotation);
|
|
5411
|
+
h = fnvMixBool(fnvMixBool(h, s.largeArc), s.clockwise);
|
|
5412
|
+
}
|
|
5413
|
+
}
|
|
5414
|
+
return h;
|
|
5415
|
+
}
|
|
5416
|
+
function segmentFreeParams(segments) {
|
|
5417
|
+
const out = [];
|
|
5418
|
+
for (const s of segments) {
|
|
5419
|
+
out.push(s.to);
|
|
5420
|
+
if (s.kind === "Arc") out.push(s.radius);
|
|
5421
|
+
else if (s.kind === "Bezier") out.push(...s.controls);
|
|
5422
|
+
else if (s.kind === "EllipseArc") out.push(s.radii, s.rotation);
|
|
5423
|
+
}
|
|
5424
|
+
return out;
|
|
5425
|
+
}
|
|
5426
|
+
function foldSegment(s, foldExpr) {
|
|
5427
|
+
switch (s.kind) {
|
|
5428
|
+
case "Line": return lineTo(foldExpr(s.to));
|
|
5429
|
+
case "Arc": return arcTo(foldExpr(s.to), foldExpr(s.radius), {
|
|
5430
|
+
largeArc: s.largeArc,
|
|
5431
|
+
clockwise: s.clockwise
|
|
5432
|
+
});
|
|
5433
|
+
case "Bezier": return bezierTo(s.controls.map(foldExpr), foldExpr(s.to));
|
|
5434
|
+
case "EllipseArc": return ellipseArcTo(foldExpr(s.to), foldExpr(s.radii), {
|
|
5435
|
+
rotation: foldExpr(s.rotation),
|
|
5436
|
+
largeArc: s.largeArc,
|
|
5437
|
+
clockwise: s.clockwise
|
|
5438
|
+
});
|
|
5439
|
+
}
|
|
5440
|
+
}
|
|
5441
|
+
//#endregion
|
|
5349
5442
|
//#region src/csg/builders.ts
|
|
5350
5443
|
var EMPTY_DEPS = /* @__PURE__ */ new Set();
|
|
5351
5444
|
function startHash(tag) {
|
|
@@ -5522,29 +5615,31 @@ function intersect$1(a, b, tolerance) {
|
|
|
5522
5615
|
};
|
|
5523
5616
|
}
|
|
5524
5617
|
function fuseAll$1(shapes, tolerance) {
|
|
5525
|
-
|
|
5526
|
-
|
|
5618
|
+
const copied = [...shapes];
|
|
5619
|
+
let h = fnvMixInt32(startHash("FuseAll"), copied.length);
|
|
5620
|
+
for (const s of copied) h = mix(h, s);
|
|
5527
5621
|
h = mixOptNumber(h, tolerance);
|
|
5528
5622
|
return {
|
|
5529
5623
|
kind: "FuseAll",
|
|
5530
|
-
shapes,
|
|
5624
|
+
shapes: copied,
|
|
5531
5625
|
tolerance,
|
|
5532
5626
|
structuralHash: h,
|
|
5533
|
-
freeParams: depsOf(...
|
|
5627
|
+
freeParams: depsOf(...copied)
|
|
5534
5628
|
};
|
|
5535
5629
|
}
|
|
5536
5630
|
function cutAll$1(base, tools, tolerance) {
|
|
5631
|
+
const copied = [...tools];
|
|
5537
5632
|
let h = mix(startHash("CutAll"), base);
|
|
5538
|
-
h = fnvMixInt32(h,
|
|
5539
|
-
for (const t of
|
|
5633
|
+
h = fnvMixInt32(h, copied.length);
|
|
5634
|
+
for (const t of copied) h = mix(h, t);
|
|
5540
5635
|
h = mixOptNumber(h, tolerance);
|
|
5541
5636
|
return {
|
|
5542
5637
|
kind: "CutAll",
|
|
5543
5638
|
base,
|
|
5544
|
-
tools,
|
|
5639
|
+
tools: copied,
|
|
5545
5640
|
tolerance,
|
|
5546
5641
|
structuralHash: h,
|
|
5547
|
-
freeParams: depsOf(base, ...
|
|
5642
|
+
freeParams: depsOf(base, ...copied)
|
|
5548
5643
|
};
|
|
5549
5644
|
}
|
|
5550
5645
|
function optVec3$1(v) {
|
|
@@ -5606,14 +5701,76 @@ function mirror$1(target, options) {
|
|
|
5606
5701
|
freeParams: depsOf(target, nE, atE)
|
|
5607
5702
|
};
|
|
5608
5703
|
}
|
|
5704
|
+
function extrude$1(profile, vector) {
|
|
5705
|
+
const ve = asVec3Expr(vector);
|
|
5706
|
+
return {
|
|
5707
|
+
kind: "Extrude",
|
|
5708
|
+
profile,
|
|
5709
|
+
vector: ve,
|
|
5710
|
+
structuralHash: mix(mix(startHash("Extrude"), profile), ve),
|
|
5711
|
+
freeParams: depsOf(profile, ve)
|
|
5712
|
+
};
|
|
5713
|
+
}
|
|
5714
|
+
/** Open (or incidentally closed) planar path in the XY plane at z = 0,
|
|
5715
|
+
* producing a Wire. Segments come from `lineTo`/`arcTo`/`bezierTo`/
|
|
5716
|
+
* `ellipseArcTo`. */
|
|
5717
|
+
function path(start, segments) {
|
|
5718
|
+
const se = asVec2Expr(start);
|
|
5719
|
+
const copied = [...segments];
|
|
5720
|
+
let h = mix(startHash("Path"), se);
|
|
5721
|
+
h = hashSegments(h, copied);
|
|
5722
|
+
return {
|
|
5723
|
+
kind: "Path",
|
|
5724
|
+
start: se,
|
|
5725
|
+
segments: copied,
|
|
5726
|
+
structuralHash: h,
|
|
5727
|
+
freeParams: depsOf(se, ...segmentFreeParams(copied))
|
|
5728
|
+
};
|
|
5729
|
+
}
|
|
5730
|
+
/** Loft through two or more face-producing sections (default ruled). */
|
|
5731
|
+
function loft$1(sections, options) {
|
|
5732
|
+
const copied = [...sections];
|
|
5733
|
+
const ruled = options?.ruled ?? true;
|
|
5734
|
+
let h = fnvMixInt32(startHash("Loft"), copied.length);
|
|
5735
|
+
for (const s of copied) h = mix(h, s);
|
|
5736
|
+
h = fnvMixBool(h, ruled);
|
|
5737
|
+
return {
|
|
5738
|
+
kind: "Loft",
|
|
5739
|
+
sections: copied,
|
|
5740
|
+
ruled,
|
|
5741
|
+
structuralHash: h,
|
|
5742
|
+
freeParams: depsOf(...copied)
|
|
5743
|
+
};
|
|
5744
|
+
}
|
|
5745
|
+
/** Angle is in degrees (matching `rotate`); defaults to a full revolution
|
|
5746
|
+
* around the Z axis at the origin. Evaluation clamps angles above 360 to one
|
|
5747
|
+
* revolution (kernels diverge past 2*pi) and rejects non-positive angles. */
|
|
5748
|
+
function revolve$1(profile, angle = 360, options) {
|
|
5749
|
+
const ae = asScalarExpr(angle);
|
|
5750
|
+
const axisE = optVec3$1(options?.axis);
|
|
5751
|
+
const atE = optVec3$1(options?.at);
|
|
5752
|
+
let h = mix(mix(startHash("Revolve"), profile), ae);
|
|
5753
|
+
h = mixOptExpr(h, axisE);
|
|
5754
|
+
h = mixOptExpr(h, atE);
|
|
5755
|
+
return {
|
|
5756
|
+
kind: "Revolve",
|
|
5757
|
+
profile,
|
|
5758
|
+
angle: ae,
|
|
5759
|
+
axis: axisE,
|
|
5760
|
+
at: atE,
|
|
5761
|
+
structuralHash: h,
|
|
5762
|
+
freeParams: depsOf(profile, ae, axisE, atE)
|
|
5763
|
+
};
|
|
5764
|
+
}
|
|
5609
5765
|
function compound$1(children) {
|
|
5610
|
-
|
|
5611
|
-
|
|
5766
|
+
const copied = [...children];
|
|
5767
|
+
let h = fnvMixInt32(startHash("Compound"), copied.length);
|
|
5768
|
+
for (const c of copied) h = mix(h, c);
|
|
5612
5769
|
return {
|
|
5613
5770
|
kind: "Compound",
|
|
5614
|
-
children,
|
|
5771
|
+
children: copied,
|
|
5615
5772
|
structuralHash: h,
|
|
5616
|
-
freeParams: depsOf(...
|
|
5773
|
+
freeParams: depsOf(...copied)
|
|
5617
5774
|
};
|
|
5618
5775
|
}
|
|
5619
5776
|
function instance$1(source, placements, fuse = false) {
|
|
@@ -5652,6 +5809,10 @@ function outputKindOf(node) {
|
|
|
5652
5809
|
case "Rotate":
|
|
5653
5810
|
case "Scale":
|
|
5654
5811
|
case "Mirror": return outputKindOf(node.target);
|
|
5812
|
+
case "Extrude":
|
|
5813
|
+
case "Revolve":
|
|
5814
|
+
case "Loft": return "Solid";
|
|
5815
|
+
case "Path": return "Wire";
|
|
5655
5816
|
case "Compound": return "Compound";
|
|
5656
5817
|
case "Instance": return node.fuse ? "Solid" : "Compound";
|
|
5657
5818
|
}
|
|
@@ -5931,6 +6092,291 @@ function evalInstance(node, ctx) {
|
|
|
5931
6092
|
return materialize(instance(r.value, node.placements), { fuse: node.fuse });
|
|
5932
6093
|
}
|
|
5933
6094
|
//#endregion
|
|
6095
|
+
//#region src/csg/evaluators/profileFace.ts
|
|
6096
|
+
/** Evaluate a profile child and prove it is an oriented planar face — the
|
|
6097
|
+
* input contract shared by every profile-consuming feature node. */
|
|
6098
|
+
function resolveProfileFace(ctx, profile, where) {
|
|
6099
|
+
const p = ctx.evalNode(profile);
|
|
6100
|
+
if (!p.ok) return p;
|
|
6101
|
+
if (!isFace(p.value)) return err(typeCastError("CSG_NOT_FACE", `${where}: node did not produce a Face`));
|
|
6102
|
+
const oriented = orientedFace(p.value);
|
|
6103
|
+
if (!oriented.ok) return err(typeCastError("CSG_NOT_FACE", `${where}: ${oriented.error}`));
|
|
6104
|
+
if (!isPlanarFace(oriented.value)) return err(typeCastError("CSG_NOT_FACE", `${where}: face is not planar`));
|
|
6105
|
+
return ok(oriented.value);
|
|
6106
|
+
}
|
|
6107
|
+
//#endregion
|
|
6108
|
+
//#region src/csg/evaluators/extrude.ts
|
|
6109
|
+
function evalExtrude(node, ctx) {
|
|
6110
|
+
const v = evalVec3(node.vector, ctx.env, "Extrude.vector");
|
|
6111
|
+
if (!v.ok) return v;
|
|
6112
|
+
const face = resolveProfileFace(ctx, node.profile, "Extrude.profile");
|
|
6113
|
+
if (!face.ok) return face;
|
|
6114
|
+
return extrude$2(face.value, v.value);
|
|
6115
|
+
}
|
|
6116
|
+
//#endregion
|
|
6117
|
+
//#region src/csg/evaluators/revolve.ts
|
|
6118
|
+
function evalRevolve(node, ctx) {
|
|
6119
|
+
const a = evalScalar(node.angle, ctx.env, "Revolve.angle");
|
|
6120
|
+
if (!a.ok) return a;
|
|
6121
|
+
if (a.value <= 0) return err(validationError("CSG_REVOLVE_ANGLE", `Revolve.angle must be positive (degrees), got ${a.value}`));
|
|
6122
|
+
const deg = Math.min(a.value, 360);
|
|
6123
|
+
const axis = node.axis ? evalVec3(node.axis, ctx.env, "Revolve.axis") : ok([
|
|
6124
|
+
0,
|
|
6125
|
+
0,
|
|
6126
|
+
1
|
|
6127
|
+
]);
|
|
6128
|
+
if (!axis.ok) return axis;
|
|
6129
|
+
const at = node.at ? evalVec3(node.at, ctx.env, "Revolve.at") : ok([
|
|
6130
|
+
0,
|
|
6131
|
+
0,
|
|
6132
|
+
0
|
|
6133
|
+
]);
|
|
6134
|
+
if (!at.ok) return at;
|
|
6135
|
+
const face = resolveProfileFace(ctx, node.profile, "Revolve.profile");
|
|
6136
|
+
if (!face.ok) return face;
|
|
6137
|
+
return revolve$2(face.value, at.value, axis.value, deg * Math.PI / 180);
|
|
6138
|
+
}
|
|
6139
|
+
//#endregion
|
|
6140
|
+
//#region src/csg/evaluators/loft.ts
|
|
6141
|
+
function evalLoft(node, ctx) {
|
|
6142
|
+
try {
|
|
6143
|
+
var _usingCtx$3 = _usingCtx();
|
|
6144
|
+
if (node.sections.length < 2) return err(validationError("CSG_LOFT_SECTIONS", `Loft requires at least 2 sections, got ${node.sections.length}`));
|
|
6145
|
+
const scope = _usingCtx$3.u(new DisposalScope());
|
|
6146
|
+
const wires = [];
|
|
6147
|
+
for (const [i, section] of node.sections.entries()) {
|
|
6148
|
+
const face = resolveProfileFace(ctx, section, `Loft.sections[${i}]`);
|
|
6149
|
+
if (!face.ok) return face;
|
|
6150
|
+
const w = outerWire(face.value);
|
|
6151
|
+
scope.register(w);
|
|
6152
|
+
wires.push(w);
|
|
6153
|
+
}
|
|
6154
|
+
return loft$2(wires, { ruled: node.ruled });
|
|
6155
|
+
} catch (_) {
|
|
6156
|
+
_usingCtx$3.e = _;
|
|
6157
|
+
} finally {
|
|
6158
|
+
_usingCtx$3.d();
|
|
6159
|
+
}
|
|
6160
|
+
}
|
|
6161
|
+
//#endregion
|
|
6162
|
+
//#region src/csg/evaluators/path.ts
|
|
6163
|
+
var EPS = 1e-9;
|
|
6164
|
+
function v3(p) {
|
|
6165
|
+
return [
|
|
6166
|
+
p[0],
|
|
6167
|
+
p[1],
|
|
6168
|
+
0
|
|
6169
|
+
];
|
|
6170
|
+
}
|
|
6171
|
+
function fail(msg) {
|
|
6172
|
+
return err(validationError("CSG_PATH_SEGMENT", `Path: ${msg}`));
|
|
6173
|
+
}
|
|
6174
|
+
/** SVG-style endpoint circular arc: recover the on-arc midpoint so the edge
|
|
6175
|
+
* can be built as a three-point arc. */
|
|
6176
|
+
function circularArcMidpoint(from, to, r, largeArc, clockwise) {
|
|
6177
|
+
const [x1, y1] = from;
|
|
6178
|
+
const [x2, y2] = to;
|
|
6179
|
+
const dx = x2 - x1;
|
|
6180
|
+
const dy = y2 - y1;
|
|
6181
|
+
const d = Math.hypot(dx, dy);
|
|
6182
|
+
if (d < EPS) return fail("Arc: coincident endpoints");
|
|
6183
|
+
if (d > 2 * r + 1e-6) return fail(`Arc: radius ${r} too small for chord ${d}`);
|
|
6184
|
+
const h = Math.sqrt(Math.max(0, r * r - d / 2 * (d / 2)));
|
|
6185
|
+
const ux = dx / d;
|
|
6186
|
+
const uy = dy / d;
|
|
6187
|
+
const sign = clockwise === largeArc ? 1 : -1;
|
|
6188
|
+
const cx = (x1 + x2) / 2 + sign * h * -uy;
|
|
6189
|
+
const cy = (y1 + y2) / 2 + sign * h * ux;
|
|
6190
|
+
const a0 = Math.atan2(y1 - cy, x1 - cx);
|
|
6191
|
+
let a1 = Math.atan2(y2 - cy, x2 - cx);
|
|
6192
|
+
if (clockwise) while (a1 >= a0 - EPS) a1 -= 2 * Math.PI;
|
|
6193
|
+
else while (a1 <= a0 + EPS) a1 += 2 * Math.PI;
|
|
6194
|
+
const amid = (a0 + a1) / 2;
|
|
6195
|
+
return ok([cx + r * Math.cos(amid), cy + r * Math.sin(amid)]);
|
|
6196
|
+
}
|
|
6197
|
+
/** SVG F.6.5 endpoint-to-center conversion (math y-up; sweep = !clockwise).
|
|
6198
|
+
* Angles are relative to the rotated x-axis. */
|
|
6199
|
+
function ellipseArcParams(from, to, radii, phi, largeArc, clockwise) {
|
|
6200
|
+
const sweep = !clockwise;
|
|
6201
|
+
let [rx, ry] = radii;
|
|
6202
|
+
if (rx <= 0 || ry <= 0) return fail("EllipseArc: non-positive radius");
|
|
6203
|
+
const cosPhi = Math.cos(phi);
|
|
6204
|
+
const sinPhi = Math.sin(phi);
|
|
6205
|
+
const hx = (from[0] - to[0]) / 2;
|
|
6206
|
+
const hy = (from[1] - to[1]) / 2;
|
|
6207
|
+
const x1p = cosPhi * hx + sinPhi * hy;
|
|
6208
|
+
const y1p = -sinPhi * hx + cosPhi * hy;
|
|
6209
|
+
const lambda = x1p * x1p / (rx * rx) + y1p * y1p / (ry * ry);
|
|
6210
|
+
if (lambda > 1) {
|
|
6211
|
+
const s = Math.sqrt(lambda);
|
|
6212
|
+
rx *= s;
|
|
6213
|
+
ry *= s;
|
|
6214
|
+
}
|
|
6215
|
+
const num = rx * rx * ry * ry - rx * rx * y1p * y1p - ry * ry * x1p * x1p;
|
|
6216
|
+
const den = rx * rx * y1p * y1p + ry * ry * x1p * x1p;
|
|
6217
|
+
if (den < EPS) return fail("EllipseArc: coincident endpoints");
|
|
6218
|
+
const coef = (largeArc !== sweep ? 1 : -1) * Math.sqrt(Math.max(0, num / den));
|
|
6219
|
+
const cxp = coef * (rx * y1p / ry);
|
|
6220
|
+
const cyp = coef * (-(ry * x1p) / rx);
|
|
6221
|
+
const cx = cosPhi * cxp - sinPhi * cyp + (from[0] + to[0]) / 2;
|
|
6222
|
+
const cy = sinPhi * cxp + cosPhi * cyp + (from[1] + to[1]) / 2;
|
|
6223
|
+
const theta1 = Math.atan2((y1p - cyp) / ry, (x1p - cxp) / rx);
|
|
6224
|
+
let dTheta = Math.atan2((-y1p - cyp) / ry, (-x1p - cxp) / rx) - theta1;
|
|
6225
|
+
if (!sweep && dTheta > 0) dTheta -= 2 * Math.PI;
|
|
6226
|
+
if (sweep && dTheta < 0) dTheta += 2 * Math.PI;
|
|
6227
|
+
const t1 = dTheta >= 0 ? theta1 : theta1 + dTheta;
|
|
6228
|
+
const t2 = dTheta >= 0 ? theta1 + dTheta : theta1;
|
|
6229
|
+
return ok({
|
|
6230
|
+
center: [cx, cy],
|
|
6231
|
+
theta1: t1,
|
|
6232
|
+
theta2: t2,
|
|
6233
|
+
rx,
|
|
6234
|
+
ry
|
|
6235
|
+
});
|
|
6236
|
+
}
|
|
6237
|
+
function ellipseEdge(from, seg, ctx) {
|
|
6238
|
+
if (seg.kind !== "EllipseArc") return fail("internal: not an ellipse segment");
|
|
6239
|
+
const to = evalVec2(seg.to, ctx.env, "Path.EllipseArc.to");
|
|
6240
|
+
if (!to.ok) return to;
|
|
6241
|
+
const radii = evalVec2(seg.radii, ctx.env, "Path.EllipseArc.radii");
|
|
6242
|
+
if (!radii.ok) return radii;
|
|
6243
|
+
const rotDeg = evalScalar(seg.rotation, ctx.env, "Path.EllipseArc.rotation");
|
|
6244
|
+
if (!rotDeg.ok) return rotDeg;
|
|
6245
|
+
const phi = rotDeg.value * Math.PI / 180;
|
|
6246
|
+
const p = ellipseArcParams(from, to.value, radii.value, phi, seg.largeArc, seg.clockwise);
|
|
6247
|
+
if (!p.ok) return p;
|
|
6248
|
+
const { center, theta1, theta2, rx, ry } = p.value;
|
|
6249
|
+
let arc;
|
|
6250
|
+
let psi;
|
|
6251
|
+
if (rx >= ry) {
|
|
6252
|
+
arc = makeEllipseArc(rx, ry, theta1, theta2, v3(center), [
|
|
6253
|
+
0,
|
|
6254
|
+
0,
|
|
6255
|
+
1
|
|
6256
|
+
]);
|
|
6257
|
+
psi = phi;
|
|
6258
|
+
} else {
|
|
6259
|
+
arc = makeEllipseArc(ry, rx, theta1 - Math.PI / 2, theta2 - Math.PI / 2, v3(center), [
|
|
6260
|
+
0,
|
|
6261
|
+
0,
|
|
6262
|
+
1
|
|
6263
|
+
]);
|
|
6264
|
+
psi = phi + Math.PI / 2;
|
|
6265
|
+
}
|
|
6266
|
+
if (!arc.ok) return arc;
|
|
6267
|
+
let edge = arc.value;
|
|
6268
|
+
if (Math.abs(psi) > EPS) try {
|
|
6269
|
+
var _usingCtx$2 = _usingCtx();
|
|
6270
|
+
const rotated = rotateEdgeAbout(_usingCtx$2.u(edge), psi * 180 / Math.PI, center);
|
|
6271
|
+
if (!rotated.ok) return rotated;
|
|
6272
|
+
edge = rotated.value;
|
|
6273
|
+
} catch (_) {
|
|
6274
|
+
_usingCtx$2.e = _;
|
|
6275
|
+
} finally {
|
|
6276
|
+
_usingCtx$2.d();
|
|
6277
|
+
}
|
|
6278
|
+
if (seg.clockwise) try {
|
|
6279
|
+
var _usingCtx3 = _usingCtx();
|
|
6280
|
+
const tmp = _usingCtx3.u(edge);
|
|
6281
|
+
edge = flipOrientation(tmp);
|
|
6282
|
+
} catch (_) {
|
|
6283
|
+
_usingCtx3.e = _;
|
|
6284
|
+
} finally {
|
|
6285
|
+
_usingCtx3.d();
|
|
6286
|
+
}
|
|
6287
|
+
return ok(edge);
|
|
6288
|
+
}
|
|
6289
|
+
/** Rotate an edge about the Z axis at `center` (degrees) via a cheap location
|
|
6290
|
+
* re-tag; returns a fresh, independently-disposable handle. Kernels without
|
|
6291
|
+
* an edge-relocation path (brepkit) surface as a Result error, not a throw. */
|
|
6292
|
+
function rotateEdgeAbout(edge, angleDeg, center) {
|
|
6293
|
+
const kernel = getKernel();
|
|
6294
|
+
const { handle, dispose } = kernel.composeTransform([{
|
|
6295
|
+
type: "rotate",
|
|
6296
|
+
angle: angleDeg,
|
|
6297
|
+
axis: [
|
|
6298
|
+
0,
|
|
6299
|
+
0,
|
|
6300
|
+
1
|
|
6301
|
+
],
|
|
6302
|
+
center: [
|
|
6303
|
+
center[0],
|
|
6304
|
+
center[1],
|
|
6305
|
+
0
|
|
6306
|
+
]
|
|
6307
|
+
}]);
|
|
6308
|
+
try {
|
|
6309
|
+
return ok(castShape(kernel.locate(edge.wrapped, handle)));
|
|
6310
|
+
} catch (e) {
|
|
6311
|
+
return err(kernelError("CSG_PATH_ELLIPSE_ROTATE", "Path: kernel cannot relocate ellipse-arc edges", e, { operation: "evalPath" }));
|
|
6312
|
+
} finally {
|
|
6313
|
+
dispose();
|
|
6314
|
+
}
|
|
6315
|
+
}
|
|
6316
|
+
function segmentEnd(seg, ctx) {
|
|
6317
|
+
return evalVec2(seg.to, ctx.env, `Path.${seg.kind}.to`);
|
|
6318
|
+
}
|
|
6319
|
+
function segmentToEdge(from, seg, ctx) {
|
|
6320
|
+
switch (seg.kind) {
|
|
6321
|
+
case "Line": {
|
|
6322
|
+
const to = segmentEnd(seg, ctx);
|
|
6323
|
+
if (!to.ok) return to;
|
|
6324
|
+
if (Math.hypot(to.value[0] - from[0], to.value[1] - from[1]) < EPS) return fail("Line: zero length");
|
|
6325
|
+
return ok(makeLine(v3(from), v3(to.value)));
|
|
6326
|
+
}
|
|
6327
|
+
case "Arc": {
|
|
6328
|
+
const to = segmentEnd(seg, ctx);
|
|
6329
|
+
if (!to.ok) return to;
|
|
6330
|
+
const r = evalScalar(seg.radius, ctx.env, "Path.Arc.radius");
|
|
6331
|
+
if (!r.ok) return r;
|
|
6332
|
+
const mid = circularArcMidpoint(from, to.value, r.value, seg.largeArc, seg.clockwise);
|
|
6333
|
+
if (!mid.ok) return mid;
|
|
6334
|
+
return ok(makeThreePointArc(v3(from), v3(mid.value), v3(to.value)));
|
|
6335
|
+
}
|
|
6336
|
+
case "Bezier": {
|
|
6337
|
+
const to = segmentEnd(seg, ctx);
|
|
6338
|
+
if (!to.ok) return to;
|
|
6339
|
+
const controls = [];
|
|
6340
|
+
for (const c of seg.controls) {
|
|
6341
|
+
const cv = evalVec2(c, ctx.env, "Path.Bezier.control");
|
|
6342
|
+
if (!cv.ok) return cv;
|
|
6343
|
+
controls.push(v3(cv.value));
|
|
6344
|
+
}
|
|
6345
|
+
return makeBezierCurve([
|
|
6346
|
+
v3(from),
|
|
6347
|
+
...controls,
|
|
6348
|
+
v3(to.value)
|
|
6349
|
+
]);
|
|
6350
|
+
}
|
|
6351
|
+
case "EllipseArc": return ellipseEdge(from, seg, ctx);
|
|
6352
|
+
}
|
|
6353
|
+
}
|
|
6354
|
+
function evalPath(node, ctx) {
|
|
6355
|
+
try {
|
|
6356
|
+
var _usingCtx4 = _usingCtx();
|
|
6357
|
+
if (node.segments.length === 0) return fail("at least one segment required");
|
|
6358
|
+
const start = evalVec2(node.start, ctx.env, "Path.start");
|
|
6359
|
+
if (!start.ok) return start;
|
|
6360
|
+
const scope = _usingCtx4.u(new DisposalScope());
|
|
6361
|
+
const edges = [];
|
|
6362
|
+
let cur = start.value;
|
|
6363
|
+
for (const seg of node.segments) {
|
|
6364
|
+
const e = segmentToEdge(cur, seg, ctx);
|
|
6365
|
+
if (!e.ok) return e;
|
|
6366
|
+
scope.register(e.value);
|
|
6367
|
+
edges.push(e.value);
|
|
6368
|
+
const end = segmentEnd(seg, ctx);
|
|
6369
|
+
if (!end.ok) return end;
|
|
6370
|
+
cur = end.value;
|
|
6371
|
+
}
|
|
6372
|
+
return assembleWire(edges);
|
|
6373
|
+
} catch (_) {
|
|
6374
|
+
_usingCtx4.e = _;
|
|
6375
|
+
} finally {
|
|
6376
|
+
_usingCtx4.d();
|
|
6377
|
+
}
|
|
6378
|
+
}
|
|
6379
|
+
//#endregion
|
|
5934
6380
|
//#region src/csg/evaluate.ts
|
|
5935
6381
|
function dispatch(node, ctx) {
|
|
5936
6382
|
switch (node.kind) {
|
|
@@ -5955,6 +6401,10 @@ function dispatch(node, ctx) {
|
|
|
5955
6401
|
case "Mirror": return evalMirror(node, ctx);
|
|
5956
6402
|
case "Compound": return evalCompound(node, ctx);
|
|
5957
6403
|
case "Instance": return evalInstance(node, ctx);
|
|
6404
|
+
case "Extrude": return evalExtrude(node, ctx);
|
|
6405
|
+
case "Revolve": return evalRevolve(node, ctx);
|
|
6406
|
+
case "Loft": return evalLoft(node, ctx);
|
|
6407
|
+
case "Path": return evalPath(node, ctx);
|
|
5958
6408
|
}
|
|
5959
6409
|
}
|
|
5960
6410
|
function hashExprValue(h, v) {
|
|
@@ -6491,6 +6941,34 @@ function booleanToJson(n) {
|
|
|
6491
6941
|
function optExprToJson(e) {
|
|
6492
6942
|
return e ? exprToJson(e) : void 0;
|
|
6493
6943
|
}
|
|
6944
|
+
function segmentToJson(s) {
|
|
6945
|
+
switch (s.kind) {
|
|
6946
|
+
case "Line": return {
|
|
6947
|
+
kind: "Line",
|
|
6948
|
+
to: exprToJson(s.to)
|
|
6949
|
+
};
|
|
6950
|
+
case "Arc": return {
|
|
6951
|
+
kind: "Arc",
|
|
6952
|
+
to: exprToJson(s.to),
|
|
6953
|
+
radius: exprToJson(s.radius),
|
|
6954
|
+
largeArc: s.largeArc,
|
|
6955
|
+
clockwise: s.clockwise
|
|
6956
|
+
};
|
|
6957
|
+
case "Bezier": return {
|
|
6958
|
+
kind: "Bezier",
|
|
6959
|
+
controls: s.controls.map(exprToJson),
|
|
6960
|
+
to: exprToJson(s.to)
|
|
6961
|
+
};
|
|
6962
|
+
case "EllipseArc": return {
|
|
6963
|
+
kind: "EllipseArc",
|
|
6964
|
+
to: exprToJson(s.to),
|
|
6965
|
+
radii: exprToJson(s.radii),
|
|
6966
|
+
rotation: exprToJson(s.rotation),
|
|
6967
|
+
largeArc: s.largeArc,
|
|
6968
|
+
clockwise: s.clockwise
|
|
6969
|
+
};
|
|
6970
|
+
}
|
|
6971
|
+
}
|
|
6494
6972
|
function transformToJson(n) {
|
|
6495
6973
|
switch (n.kind) {
|
|
6496
6974
|
case "Translate": return {
|
|
@@ -6521,6 +6999,28 @@ function transformToJson(n) {
|
|
|
6521
6999
|
}
|
|
6522
7000
|
}
|
|
6523
7001
|
function nodeToJson(n) {
|
|
7002
|
+
if (n.kind === "Extrude") return {
|
|
7003
|
+
kind: "Extrude",
|
|
7004
|
+
profile: nodeToJson(n.profile),
|
|
7005
|
+
vector: exprToJson(n.vector)
|
|
7006
|
+
};
|
|
7007
|
+
if (n.kind === "Revolve") return {
|
|
7008
|
+
kind: "Revolve",
|
|
7009
|
+
profile: nodeToJson(n.profile),
|
|
7010
|
+
angle: exprToJson(n.angle),
|
|
7011
|
+
axis: optExprToJson(n.axis),
|
|
7012
|
+
at: optExprToJson(n.at)
|
|
7013
|
+
};
|
|
7014
|
+
if (n.kind === "Loft") return {
|
|
7015
|
+
kind: "Loft",
|
|
7016
|
+
sections: n.sections.map(nodeToJson),
|
|
7017
|
+
ruled: n.ruled
|
|
7018
|
+
};
|
|
7019
|
+
if (n.kind === "Path") return {
|
|
7020
|
+
kind: "Path",
|
|
7021
|
+
start: exprToJson(n.start),
|
|
7022
|
+
segments: n.segments.map(segmentToJson)
|
|
7023
|
+
};
|
|
6524
7024
|
if (n.kind === "Compound") return {
|
|
6525
7025
|
kind: "Compound",
|
|
6526
7026
|
children: n.children.map(nodeToJson)
|
|
@@ -6672,6 +7172,10 @@ function readNode(j) {
|
|
|
6672
7172
|
case "Mirror": return readTransform(kind, j);
|
|
6673
7173
|
case "Compound": return readCompound(j);
|
|
6674
7174
|
case "Instance": return readInstance(j);
|
|
7175
|
+
case "Extrude": return readExtrude(j);
|
|
7176
|
+
case "Revolve": return readRevolve(j);
|
|
7177
|
+
case "Loft": return readLoft(j);
|
|
7178
|
+
case "Path": return readPath(j);
|
|
6675
7179
|
default: return bad(`unknown node kind: ${String(kind)}`);
|
|
6676
7180
|
}
|
|
6677
7181
|
}
|
|
@@ -6826,6 +7330,100 @@ function readMirror(j, target) {
|
|
|
6826
7330
|
at: at.value
|
|
6827
7331
|
}));
|
|
6828
7332
|
}
|
|
7333
|
+
function readExtrude(j) {
|
|
7334
|
+
const profile = readNode(j["profile"]);
|
|
7335
|
+
if (!profile.ok) return profile;
|
|
7336
|
+
const vector = readExpr(j["vector"]);
|
|
7337
|
+
if (!vector.ok) return vector;
|
|
7338
|
+
return ok(extrude$1(profile.value, vector.value));
|
|
7339
|
+
}
|
|
7340
|
+
function readRevolve(j) {
|
|
7341
|
+
const profile = readNode(j["profile"]);
|
|
7342
|
+
if (!profile.ok) return profile;
|
|
7343
|
+
const angle = readExpr(j["angle"]);
|
|
7344
|
+
if (!angle.ok) return angle;
|
|
7345
|
+
const axis = readOptExpr(j, "axis");
|
|
7346
|
+
if (!axis.ok) return axis;
|
|
7347
|
+
const at = readOptExpr(j, "at");
|
|
7348
|
+
if (!at.ok) return at;
|
|
7349
|
+
return ok(revolve$1(profile.value, angle.value, {
|
|
7350
|
+
axis: axis.value,
|
|
7351
|
+
at: at.value
|
|
7352
|
+
}));
|
|
7353
|
+
}
|
|
7354
|
+
function readLoft(j) {
|
|
7355
|
+
const sections = readNodeArray(j["sections"], "Loft.sections");
|
|
7356
|
+
if (!sections.ok) return sections;
|
|
7357
|
+
const ruled = j["ruled"];
|
|
7358
|
+
if (ruled !== void 0 && typeof ruled !== "boolean") return bad("Loft.ruled: not a boolean");
|
|
7359
|
+
return ok(loft$1(sections.value, { ruled }));
|
|
7360
|
+
}
|
|
7361
|
+
function readFlag(j, key) {
|
|
7362
|
+
const v = j[key];
|
|
7363
|
+
if (v === void 0) return ok(false);
|
|
7364
|
+
return typeof v === "boolean" ? ok(v) : bad(`${key}: not a boolean`);
|
|
7365
|
+
}
|
|
7366
|
+
function readSegment(j) {
|
|
7367
|
+
if (!isObj(j)) return bad("segment: not an object");
|
|
7368
|
+
const to = readExpr(j["to"]);
|
|
7369
|
+
if (!to.ok) return to;
|
|
7370
|
+
const kind = j["kind"];
|
|
7371
|
+
switch (kind) {
|
|
7372
|
+
case "Line": return ok(lineTo(to.value));
|
|
7373
|
+
case "Arc": {
|
|
7374
|
+
const radius = readExpr(j["radius"]);
|
|
7375
|
+
if (!radius.ok) return radius;
|
|
7376
|
+
const largeArc = readFlag(j, "largeArc");
|
|
7377
|
+
if (!largeArc.ok) return largeArc;
|
|
7378
|
+
const clockwise = readFlag(j, "clockwise");
|
|
7379
|
+
if (!clockwise.ok) return clockwise;
|
|
7380
|
+
return ok(arcTo(to.value, radius.value, {
|
|
7381
|
+
largeArc: largeArc.value,
|
|
7382
|
+
clockwise: clockwise.value
|
|
7383
|
+
}));
|
|
7384
|
+
}
|
|
7385
|
+
case "Bezier": {
|
|
7386
|
+
const raw = j["controls"];
|
|
7387
|
+
if (!Array.isArray(raw)) return bad("Bezier.controls: not array");
|
|
7388
|
+
const controls = [];
|
|
7389
|
+
for (const c of raw) {
|
|
7390
|
+
const r = readExpr(c);
|
|
7391
|
+
if (!r.ok) return r;
|
|
7392
|
+
controls.push(r.value);
|
|
7393
|
+
}
|
|
7394
|
+
return ok(bezierTo(controls, to.value));
|
|
7395
|
+
}
|
|
7396
|
+
case "EllipseArc": {
|
|
7397
|
+
const radii = readExpr(j["radii"]);
|
|
7398
|
+
if (!radii.ok) return radii;
|
|
7399
|
+
const rotation = readExpr(j["rotation"]);
|
|
7400
|
+
if (!rotation.ok) return rotation;
|
|
7401
|
+
const largeArc = readFlag(j, "largeArc");
|
|
7402
|
+
if (!largeArc.ok) return largeArc;
|
|
7403
|
+
const clockwise = readFlag(j, "clockwise");
|
|
7404
|
+
if (!clockwise.ok) return clockwise;
|
|
7405
|
+
return ok(ellipseArcTo(to.value, radii.value, {
|
|
7406
|
+
rotation: rotation.value,
|
|
7407
|
+
largeArc: largeArc.value,
|
|
7408
|
+
clockwise: clockwise.value
|
|
7409
|
+
}));
|
|
7410
|
+
}
|
|
7411
|
+
default: return bad(`unknown segment kind: ${String(kind)}`);
|
|
7412
|
+
}
|
|
7413
|
+
}
|
|
7414
|
+
function readPath(j) {
|
|
7415
|
+
const start = readExpr(j["start"]);
|
|
7416
|
+
if (!start.ok) return start;
|
|
7417
|
+
const raw = j["segments"];
|
|
7418
|
+
if (!Array.isArray(raw)) return bad("Path.segments: not array");
|
|
7419
|
+
const segments = [];
|
|
7420
|
+
for (const s of raw) {
|
|
7421
|
+
const r = readSegment(s);
|
|
7422
|
+
if (!r.ok) return r;
|
|
7423
|
+
segments.push(r.value);
|
|
7424
|
+
}
|
|
7425
|
+
return ok(path(start.value, segments));
|
|
7426
|
+
}
|
|
6829
7427
|
function readCompound(j) {
|
|
6830
7428
|
const children = readNodeArray(j["children"], "Compound.children");
|
|
6831
7429
|
return children.ok ? ok(compound$1(children.value)) : children;
|
|
@@ -6937,6 +7535,21 @@ function optimizeNode(n) {
|
|
|
6937
7535
|
});
|
|
6938
7536
|
case "Compound": return compound$1(n.children.map(optimizeNode).filter((c) => c.kind !== "Empty"));
|
|
6939
7537
|
case "Instance": return instance$1(optimizeNode(n.source), n.placements, n.fuse);
|
|
7538
|
+
case "Extrude":
|
|
7539
|
+
case "Revolve":
|
|
7540
|
+
case "Loft":
|
|
7541
|
+
case "Path": return optimizeFeature(n);
|
|
7542
|
+
}
|
|
7543
|
+
}
|
|
7544
|
+
function optimizeFeature(n) {
|
|
7545
|
+
switch (n.kind) {
|
|
7546
|
+
case "Extrude": return extrude$1(optimizeNode(n.profile), foldExpr(n.vector));
|
|
7547
|
+
case "Revolve": return revolve$1(optimizeNode(n.profile), foldExpr(n.angle), {
|
|
7548
|
+
axis: n.axis ? foldExpr(n.axis) : void 0,
|
|
7549
|
+
at: n.at ? foldExpr(n.at) : void 0
|
|
7550
|
+
});
|
|
7551
|
+
case "Loft": return loft$1(n.sections.map(optimizeNode), { ruled: n.ruled });
|
|
7552
|
+
case "Path": return path(foldExpr(n.start), n.segments.map((s) => foldSegment(s, foldExpr)));
|
|
6940
7553
|
}
|
|
6941
7554
|
}
|
|
6942
7555
|
function optimizeFuse(a, b, tol) {
|
|
@@ -7009,7 +7622,8 @@ function rebuildChildren(n, pred, repl) {
|
|
|
7009
7622
|
case "Circle":
|
|
7010
7623
|
case "Line":
|
|
7011
7624
|
case "Vertex":
|
|
7012
|
-
case "Empty":
|
|
7625
|
+
case "Empty":
|
|
7626
|
+
case "Path": return n;
|
|
7013
7627
|
case "Fuse": return fuse$1(walk(n.a, pred, repl), walk(n.b, pred, repl), n.tolerance);
|
|
7014
7628
|
case "Cut": return cut$1(walk(n.a, pred, repl), walk(n.b, pred, repl), n.tolerance);
|
|
7015
7629
|
case "Intersect": return intersect$1(walk(n.a, pred, repl), walk(n.b, pred, repl), n.tolerance);
|
|
@@ -7027,6 +7641,12 @@ function rebuildChildren(n, pred, repl) {
|
|
|
7027
7641
|
});
|
|
7028
7642
|
case "Compound": return compound$1(n.children.map((c) => walk(c, pred, repl)));
|
|
7029
7643
|
case "Instance": return instance$1(walk(n.source, pred, repl), n.placements, n.fuse);
|
|
7644
|
+
case "Extrude": return extrude$1(walk(n.profile, pred, repl), n.vector);
|
|
7645
|
+
case "Revolve": return revolve$1(walk(n.profile, pred, repl), n.angle, {
|
|
7646
|
+
axis: n.axis,
|
|
7647
|
+
at: n.at
|
|
7648
|
+
});
|
|
7649
|
+
case "Loft": return loft$1(n.sections.map((s) => walk(s, pred, repl)), { ruled: n.ruled });
|
|
7030
7650
|
}
|
|
7031
7651
|
}
|
|
7032
7652
|
function forEachNode(root, fn) {
|
|
@@ -7044,7 +7664,8 @@ function childrenOf(n) {
|
|
|
7044
7664
|
case "Circle":
|
|
7045
7665
|
case "Line":
|
|
7046
7666
|
case "Vertex":
|
|
7047
|
-
case "Empty":
|
|
7667
|
+
case "Empty":
|
|
7668
|
+
case "Path": return [];
|
|
7048
7669
|
case "Fuse":
|
|
7049
7670
|
case "Cut":
|
|
7050
7671
|
case "Intersect": return [n.a, n.b];
|
|
@@ -7056,6 +7677,9 @@ function childrenOf(n) {
|
|
|
7056
7677
|
case "Mirror": return [n.target];
|
|
7057
7678
|
case "Compound": return n.children;
|
|
7058
7679
|
case "Instance": return [n.source];
|
|
7680
|
+
case "Extrude":
|
|
7681
|
+
case "Revolve": return [n.profile];
|
|
7682
|
+
case "Loft": return n.sections;
|
|
7059
7683
|
}
|
|
7060
7684
|
}
|
|
7061
7685
|
function nodeCount(root) {
|
|
@@ -7071,9 +7695,11 @@ var csg_exports = /* @__PURE__ */ __exportAll({
|
|
|
7071
7695
|
CSG_VERSION: () => 1,
|
|
7072
7696
|
Evaluator: () => Evaluator,
|
|
7073
7697
|
add: () => add,
|
|
7698
|
+
arcTo: () => arcTo,
|
|
7074
7699
|
asScalarExpr: () => asScalarExpr,
|
|
7075
7700
|
asVec2Expr: () => asVec2Expr,
|
|
7076
7701
|
asVec3Expr: () => asVec3Expr,
|
|
7702
|
+
bezierTo: () => bezierTo,
|
|
7077
7703
|
binOp: () => binOp,
|
|
7078
7704
|
box: () => box$2,
|
|
7079
7705
|
buildVec: () => buildVec,
|
|
@@ -7084,9 +7710,11 @@ var csg_exports = /* @__PURE__ */ __exportAll({
|
|
|
7084
7710
|
cut: () => cut$1,
|
|
7085
7711
|
cutAll: () => cutAll$1,
|
|
7086
7712
|
cylinder: () => cylinder$2,
|
|
7713
|
+
ellipseArcTo: () => ellipseArcTo,
|
|
7087
7714
|
emptyFace: () => emptyFace,
|
|
7088
7715
|
emptySolid: () => emptySolid,
|
|
7089
7716
|
emptyWire: () => emptyWire,
|
|
7717
|
+
extrude: () => extrude$1,
|
|
7090
7718
|
foldExpr: () => foldExpr,
|
|
7091
7719
|
forEachNode: () => forEachNode,
|
|
7092
7720
|
fromJSON: () => fromJSON,
|
|
@@ -7095,6 +7723,8 @@ var csg_exports = /* @__PURE__ */ __exportAll({
|
|
|
7095
7723
|
instance: () => instance$1,
|
|
7096
7724
|
intersect: () => intersect$1,
|
|
7097
7725
|
line: () => line$1,
|
|
7726
|
+
lineTo: () => lineTo,
|
|
7727
|
+
loft: () => loft$1,
|
|
7098
7728
|
mirror: () => mirror$1,
|
|
7099
7729
|
mul: () => mul,
|
|
7100
7730
|
nodeCount: () => nodeCount,
|
|
@@ -7102,8 +7732,10 @@ var csg_exports = /* @__PURE__ */ __exportAll({
|
|
|
7102
7732
|
optimize: () => optimize,
|
|
7103
7733
|
outputKindOf: () => outputKindOf,
|
|
7104
7734
|
param: () => param,
|
|
7735
|
+
path: () => path,
|
|
7105
7736
|
polygon: () => polygon$1,
|
|
7106
7737
|
replaceNode: () => replaceNode,
|
|
7738
|
+
revolve: () => revolve$1,
|
|
7107
7739
|
rotate: () => rotate$1,
|
|
7108
7740
|
scale: () => scale$1,
|
|
7109
7741
|
sphere: () => sphere$2,
|