brepjs 18.62.0 → 18.63.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/2d.cjs +6 -6
- package/dist/2d.js +6 -6
- package/dist/{blueprint-U7q8mCkd.js → blueprint-DaRszQg-.js} +5 -5
- package/dist/{blueprint-oAHtiBNZ.cjs → blueprint-XEJiK6ON.cjs} +5 -5
- package/dist/{blueprintFns-B430IS5G.js → blueprintFns-C0ULkqGT.js} +2 -2
- package/dist/{blueprintFns-BXIg6yIJ.cjs → blueprintFns-CTJGTMYw.cjs} +2 -2
- package/dist/{blueprintSketcher-CpYK3eMF.js → blueprintSketcher-DHWmjOmJ.js} +3 -3
- package/dist/{blueprintSketcher-BMy4GYLb.cjs → blueprintSketcher-r0uUFBZZ.cjs} +3 -3
- package/dist/{boolean2D-CalRrd7P.cjs → boolean2D-BT3RGDXW.cjs} +4 -4
- package/dist/{boolean2D-BVGfOj7k.js → boolean2D-BfavHsXe.js} +4 -4
- package/dist/{booleanFns-CejWQwHg.cjs → booleanFns-B3vIRhjz.cjs} +4 -4
- package/dist/{booleanFns-BF1OlY3H.js → booleanFns-DNG6xxu8.js} +4 -4
- package/dist/brepjs.cjs +24 -24
- package/dist/brepjs.js +24 -24
- package/dist/{cameraFns-CDmeZqa_.js → cameraFns-CQkS1TSY.js} +2 -2
- package/dist/{cameraFns-DkasWoY3.cjs → cameraFns-CqplcvtL.cjs} +2 -2
- package/dist/core.cjs +1 -1
- package/dist/core.js +1 -1
- package/dist/{cornerFinder-mHD8eDmo.cjs → cornerFinder-ByEss8KB.cjs} +1 -1
- package/dist/{cornerFinder-mUvhWdNG.js → cornerFinder-CE1b1IMu.js} +1 -1
- package/dist/{curveFns-Ba1IEqn_.cjs → curveFns-Dx9ha0n_.cjs} +1 -1
- package/dist/{curveFns-C_va_3Js.js → curveFns-vZbW7CVb.js} +1 -1
- package/dist/{drawFns-zcgjasyw.js → drawFns-DiJFFH16.js} +12 -12
- package/dist/{drawFns-DGENZIVf.cjs → drawFns-ZPhrUGWl.cjs} +12 -12
- package/dist/{extrudeFns-BkOhPexa.js → extrudeFns-BamV4cSU.js} +1 -1
- package/dist/{extrudeFns-DiIGGA5r.cjs → extrudeFns-DsvQYfqd.cjs} +1 -1
- package/dist/{faceFns-eCr0tWic.cjs → faceFns-DGmQI57P.cjs} +2 -2
- package/dist/{faceFns-DUmTMdax.js → faceFns-LJ_lU5IE.js} +2 -2
- package/dist/{helpers-Cpw0iU4L.cjs → helpers-B6abm0X7.cjs} +6 -6
- package/dist/{helpers-C7WpHbhO.js → helpers-CxZqc5vt.js} +6 -6
- package/dist/{historyFns-BVNMHteL.js → historyFns-DpHCn1yw.js} +4 -4
- package/dist/{historyFns-B5zXm33l.cjs → historyFns-a2plj33G.cjs} +4 -4
- package/dist/{importFns-DcUisQj3.js → importFns-CEz6N0mP.js} +2 -2
- package/dist/{importFns-BQEVbZwt.cjs → importFns-iJZHFevB.cjs} +2 -2
- package/dist/io.cjs +2 -2
- package/dist/io.js +2 -2
- package/dist/kernel/manifold/approximations.d.ts +23 -0
- package/dist/kernel/manifold/kernel2dNative.d.ts +26 -0
- package/dist/kernel/manifold/kernel2dOps.d.ts +1 -1
- package/dist/kernel/manifold/nativeEdges.d.ts +37 -0
- package/dist/kernel/manifold/nativeFaces.d.ts +27 -0
- package/dist/kernel/manifold/profileOps.d.ts +19 -0
- package/dist/kernel/manifold/sweepOps.d.ts +12 -0
- package/dist/{measureFns-BdYuCuf9.js → measureFns-1vEKylTt.js} +3 -3
- package/dist/{measureFns-Bve7WG1g.cjs → measureFns-CvAOj_Io.cjs} +3 -3
- package/dist/measurement.cjs +1 -1
- package/dist/measurement.js +1 -1
- package/dist/{meshFns-BtjQFcwe.js → meshFns-CoPoc7dh.js} +3 -3
- package/dist/{meshFns-Hxj3Vngd.cjs → meshFns-D2rlqrTt.cjs} +3 -3
- package/dist/operations.cjs +2 -2
- package/dist/operations.js +2 -2
- package/dist/{primitiveFns-n-OA8SFM.cjs → primitiveFns-Bi22B25-.cjs} +7 -7
- package/dist/{primitiveFns-ODt9feUB.js → primitiveFns-OuEHerl6.js} +7 -7
- package/dist/projection.cjs +1 -1
- package/dist/projection.js +1 -1
- package/dist/query.cjs +2 -2
- package/dist/query.js +2 -2
- package/dist/{shapeFns-CGiJTWpD.js → shapeFns-C3wVDhtn.js} +2 -2
- package/dist/{shapeFns-Dl7cAveQ.cjs → shapeFns-n4A9y80v.cjs} +2 -2
- package/dist/shapeRef.cjs +1 -1
- package/dist/shapeRef.js +1 -1
- package/dist/{shapeRefFns-CqLB7rA2.js → shapeRefFns-CUt56Cul.js} +4 -4
- package/dist/{shapeRefFns-DppFONN_.cjs → shapeRefFns-eqCfRF0P.cjs} +4 -4
- package/dist/{shapeTypes-BGeihZZ2.js → shapeTypes-9yfC5Z8_.js} +1910 -215
- package/dist/{shapeTypes-DgN4lV-c.cjs → shapeTypes-C_liO43e.cjs} +1910 -215
- package/dist/sketching.cjs +3 -3
- package/dist/sketching.js +3 -3
- package/dist/{solidBuilders-C8x5hl-i.cjs → solidBuilders-BtfspzpT.cjs} +2 -2
- package/dist/{solidBuilders-C_i7lfl1.js → solidBuilders-DSAmLmHd.js} +2 -2
- package/dist/{surfaceBuilders-8Q5NVxkT.cjs → surfaceBuilders-6BfGn0MN.cjs} +2 -2
- package/dist/{surfaceBuilders-OuKORf6n.js → surfaceBuilders-ChWLM9Io.js} +2 -2
- package/dist/text.cjs +2 -2
- package/dist/text.js +2 -2
- package/dist/{textBlueprints-CjWzCUDy.js → textBlueprints-B_RYPM3J.js} +7 -7
- package/dist/{textBlueprints-CMszuH5i.cjs → textBlueprints-DTaz774E.cjs} +7 -7
- package/dist/{textMetrics-ogNOndAW.cjs → textMetrics-CEBrAzpE.cjs} +1 -1
- package/dist/{textMetrics-nDL3MTCV.js → textMetrics-RRDn50ym.js} +1 -1
- package/dist/topology.cjs +7 -7
- package/dist/topology.js +7 -7
- package/dist/{topologyQueryFns-CTq8qOKc.cjs → topologyQueryFns-B6BTVGLX.cjs} +1 -1
- package/dist/{topologyQueryFns-B_zXrMDh.js → topologyQueryFns-nbhh_XJF.js} +1 -1
- package/package.json +1 -1
|
@@ -387,7 +387,7 @@ function iterShapesJS(oc, shape, type) {
|
|
|
387
387
|
/**
|
|
388
388
|
* Iterates sub-shapes of a given type, using C++ bulk extraction when available.
|
|
389
389
|
*/
|
|
390
|
-
function iterShapes$
|
|
390
|
+
function iterShapes$2(oc, shape, type) {
|
|
391
391
|
if (oc.TopologyExtractor) return iterShapesBulk(oc, shape, type);
|
|
392
392
|
return iterShapesJS(oc, shape, type);
|
|
393
393
|
}
|
|
@@ -416,7 +416,7 @@ function getShapeTypeMap(oc) {
|
|
|
416
416
|
/**
|
|
417
417
|
* Returns the shape type string for a given shape.
|
|
418
418
|
*/
|
|
419
|
-
function shapeType$
|
|
419
|
+
function shapeType$2(oc, shape) {
|
|
420
420
|
if (shape.IsNull()) throw new Error("Cannot determine shape type: shape is null");
|
|
421
421
|
const result = getShapeTypeMap(oc).get(shape.ShapeType());
|
|
422
422
|
if (!result) throw new Error("Unknown shape type enum value");
|
|
@@ -468,7 +468,7 @@ function iterShapeList$1(oc, list, callback) {
|
|
|
468
468
|
/**
|
|
469
469
|
* Checks if two shapes are the same (same TShape, location, and orientation).
|
|
470
470
|
*/
|
|
471
|
-
function isSame$
|
|
471
|
+
function isSame$2(a, b) {
|
|
472
472
|
return a.IsSame(b);
|
|
473
473
|
}
|
|
474
474
|
/**
|
|
@@ -480,12 +480,12 @@ function isEqual$1(a, b) {
|
|
|
480
480
|
/** Co-located factory: returns the topology-iteration slice of {@link KernelAdapter} bound to `oc`. */
|
|
481
481
|
function makeTopologyOps$2(oc) {
|
|
482
482
|
return {
|
|
483
|
-
iterShapes: (shape, type) => iterShapes$
|
|
483
|
+
iterShapes: (shape, type) => iterShapes$2(oc, shape, type),
|
|
484
484
|
iterShapeList: (list, callback) => {
|
|
485
485
|
iterShapeList$1(oc, list, callback);
|
|
486
486
|
},
|
|
487
|
-
shapeType: (shape) => shapeType$
|
|
488
|
-
isSame: (a, b) => isSame$
|
|
487
|
+
shapeType: (shape) => shapeType$2(oc, shape),
|
|
488
|
+
isSame: (a, b) => isSame$2(a, b),
|
|
489
489
|
isEqual: (a, b) => isEqual$1(a, b),
|
|
490
490
|
isValid: (shape) => isValid$1(oc, shape),
|
|
491
491
|
sew: (shapes, tolerance) => sew$1(oc, shapes, tolerance)
|
|
@@ -874,7 +874,7 @@ function makeFace$1(oc, wire, planar = true) {
|
|
|
874
874
|
return face;
|
|
875
875
|
}
|
|
876
876
|
const builder = new oc.BRepOffsetAPI_MakeFilling(3, 15, 2, false, 1e-5, 1e-4, .01, .1, 8, 9);
|
|
877
|
-
const edges = iterShapes$
|
|
877
|
+
const edges = iterShapes$2(oc, wire, "edge");
|
|
878
878
|
for (const edge of edges) builder.Add_1(edge, oc.GeomAbs_Shape.GeomAbs_C0, true);
|
|
879
879
|
const progress = new oc.Message_ProgressRange_1();
|
|
880
880
|
builder.Build(progress);
|
|
@@ -1055,7 +1055,7 @@ function at(arr, i) {
|
|
|
1055
1055
|
if (v === void 0) throw new Error(`Index ${i} out of bounds`);
|
|
1056
1056
|
return v;
|
|
1057
1057
|
}
|
|
1058
|
-
function extractVertices(oc, shapes, tolerance) {
|
|
1058
|
+
function extractVertices$1(oc, shapes, tolerance) {
|
|
1059
1059
|
const vertices = [];
|
|
1060
1060
|
const meshDeflection = Math.max(tolerance, 1);
|
|
1061
1061
|
for (const shape of shapes) {
|
|
@@ -1152,7 +1152,7 @@ function reconstructBrep(oc, hullResult, tolerance) {
|
|
|
1152
1152
|
*/
|
|
1153
1153
|
function hull$1(oc, shapes, tolerance) {
|
|
1154
1154
|
if (shapes.length === 0) throw new Error("hull: no shapes provided");
|
|
1155
|
-
const vertices = extractVertices(oc, shapes, tolerance);
|
|
1155
|
+
const vertices = extractVertices$1(oc, shapes, tolerance);
|
|
1156
1156
|
if (vertices.length < 4) throw new Error("hull: fewer than 4 vertices extracted from input shapes");
|
|
1157
1157
|
const hullResult = require_occtWasmAdapter.quickHull(vertices, tolerance);
|
|
1158
1158
|
if (hullResult.faces.length < 4) throw new Error("hull: degenerate hull (fewer than 4 faces)");
|
|
@@ -2167,7 +2167,7 @@ function transformBatch$2(oc, entries) {
|
|
|
2167
2167
|
/**
|
|
2168
2168
|
* Applies a transformation matrix to a shape.
|
|
2169
2169
|
*/
|
|
2170
|
-
function transform$
|
|
2170
|
+
function transform$3(oc, shape, trsf) {
|
|
2171
2171
|
const transformer = new oc.BRepBuilderAPI_Transform_2(shape, trsf, true, false);
|
|
2172
2172
|
const result = transformer.ModifiedShape(shape);
|
|
2173
2173
|
transformer.delete();
|
|
@@ -2180,7 +2180,7 @@ function translate$2(oc, shape, x, y, z) {
|
|
|
2180
2180
|
const trsf = new oc.gp_Trsf_1();
|
|
2181
2181
|
const vec = new oc.gp_Vec_4(x, y, z);
|
|
2182
2182
|
trsf.SetTranslation_1(vec);
|
|
2183
|
-
const result = transform$
|
|
2183
|
+
const result = transform$3(oc, shape, trsf);
|
|
2184
2184
|
trsf.delete();
|
|
2185
2185
|
vec.delete();
|
|
2186
2186
|
return result;
|
|
@@ -2202,7 +2202,7 @@ function rotate$2(oc, shape, angle, axis = [
|
|
|
2202
2202
|
const dir = new oc.gp_Dir_5(...axis);
|
|
2203
2203
|
const ax1 = new oc.gp_Ax1_2(origin, dir);
|
|
2204
2204
|
trsf.SetRotation_1(ax1, angle * Math.PI / 180);
|
|
2205
|
-
const result = transform$
|
|
2205
|
+
const result = transform$3(oc, shape, trsf);
|
|
2206
2206
|
trsf.delete();
|
|
2207
2207
|
ax1.delete();
|
|
2208
2208
|
origin.delete();
|
|
@@ -2218,7 +2218,7 @@ function mirror$2(oc, shape, origin, normal) {
|
|
|
2218
2218
|
const dir = new oc.gp_Dir_5(...normal);
|
|
2219
2219
|
const ax2 = new oc.gp_Ax2_4(pnt, dir);
|
|
2220
2220
|
trsf.SetMirror_3(ax2);
|
|
2221
|
-
const result = transform$
|
|
2221
|
+
const result = transform$3(oc, shape, trsf);
|
|
2222
2222
|
trsf.delete();
|
|
2223
2223
|
ax2.delete();
|
|
2224
2224
|
pnt.delete();
|
|
@@ -2232,7 +2232,7 @@ function scale$2(oc, shape, center, factor) {
|
|
|
2232
2232
|
const trsf = new oc.gp_Trsf_1();
|
|
2233
2233
|
const pnt = new oc.gp_Pnt_3(...center);
|
|
2234
2234
|
trsf.SetScale(pnt, factor);
|
|
2235
|
-
const result = transform$
|
|
2235
|
+
const result = transform$3(oc, shape, trsf);
|
|
2236
2236
|
trsf.delete();
|
|
2237
2237
|
pnt.delete();
|
|
2238
2238
|
return result;
|
|
@@ -2280,7 +2280,7 @@ function simplify$2(oc, shape) {
|
|
|
2280
2280
|
/** Co-located factory: returns the transform slice of {@link KernelAdapter} bound to `oc`. */
|
|
2281
2281
|
function makeTransformOps$2(oc) {
|
|
2282
2282
|
return {
|
|
2283
|
-
transform: (shape, trsf) => transform$
|
|
2283
|
+
transform: (shape, trsf) => transform$3(oc, shape, trsf),
|
|
2284
2284
|
translate: (shape, x, y, z) => translate$2(oc, shape, x, y, z),
|
|
2285
2285
|
rotate: (shape, angle, axis, center) => rotate$2(oc, shape, angle, axis, center),
|
|
2286
2286
|
mirror: (shape, origin, normal) => mirror$2(oc, shape, origin, normal),
|
|
@@ -2772,11 +2772,11 @@ function shapeTypeStr(oc, shape) {
|
|
|
2772
2772
|
return "compound";
|
|
2773
2773
|
}
|
|
2774
2774
|
/** Get the hash code of a shape. */
|
|
2775
|
-
function hashCode$
|
|
2775
|
+
function hashCode$2(oc, shape, upperBound) {
|
|
2776
2776
|
return oc.shapeHashCode(shape, upperBound);
|
|
2777
2777
|
}
|
|
2778
2778
|
/** Check if a shape is null. */
|
|
2779
|
-
function isNull$
|
|
2779
|
+
function isNull$2(_oc, shape) {
|
|
2780
2780
|
return shape.IsNull();
|
|
2781
2781
|
}
|
|
2782
2782
|
/** Return a copy of the shape with reversed orientation. */
|
|
@@ -2871,8 +2871,8 @@ function makeGeometryQueryOps(oc) {
|
|
|
2871
2871
|
curveParameters: (shape) => curveParameters$1(oc, shape),
|
|
2872
2872
|
shapeOrientation: (shape) => shapeOrientation$1(oc, shape),
|
|
2873
2873
|
downcast: (shape, type) => downcast$1(oc, shape, type),
|
|
2874
|
-
hashCode: (shape, upperBound) => hashCode$
|
|
2875
|
-
isNull: (shape) => isNull$
|
|
2874
|
+
hashCode: (shape, upperBound) => hashCode$2(oc, shape, upperBound),
|
|
2875
|
+
isNull: (shape) => isNull$2(oc, shape),
|
|
2876
2876
|
hasTriangulation: (shape) => hasTriangulation$2(oc, shape),
|
|
2877
2877
|
meshShape: (shape, tolerance, angularTolerance) => {
|
|
2878
2878
|
meshShape$2(oc, shape, tolerance, angularTolerance);
|
|
@@ -5134,7 +5134,7 @@ function fillSurface$1(oc, wires, options = {}) {
|
|
|
5134
5134
|
const { order = 3, nbPtsOnCur = 15, nbIter = 2, tol3d = 1e-5, tol2d = 1e-4, maxDeg = 8, maxSeg = 9 } = options;
|
|
5135
5135
|
const builder = new oc.BRepOffsetAPI_MakeFilling(order, nbPtsOnCur, nbIter, false, tol3d, tol2d, .01, .1, maxDeg, maxSeg);
|
|
5136
5136
|
for (let wi = 0; wi < wires.length; wi++) {
|
|
5137
|
-
const edges = iterShapes$
|
|
5137
|
+
const edges = iterShapes$2(oc, wires[wi], "edge");
|
|
5138
5138
|
for (const edge of edges) builder.Add_1(edge, oc.GeomAbs_Shape.GeomAbs_C0, wi === 0);
|
|
5139
5139
|
}
|
|
5140
5140
|
const progress = new oc.Message_ProgressRange_1();
|
|
@@ -5594,9 +5594,9 @@ function resolveUniformAngle(faces, angleDeg) {
|
|
|
5594
5594
|
//#region src/kernel/brepkit/topologyOps.ts
|
|
5595
5595
|
function iterCompound(bk, h, type) {
|
|
5596
5596
|
const children = syntheticCompounds.get(h);
|
|
5597
|
-
if (children) return children.flatMap((child) => child.type === type ? [child] : iterShapes(bk, child, type));
|
|
5597
|
+
if (children) return children.flatMap((child) => child.type === type ? [child] : iterShapes$1(bk, child, type));
|
|
5598
5598
|
if (type === "solid") return toArray(bk.getCompoundSolids(h)).map(solidHandle);
|
|
5599
|
-
if (type === "face" || type === "edge" || type === "vertex" || type === "wire") return toArray(bk.getCompoundSolids(h)).map(solidHandle).flatMap((s) => iterShapes(bk, s, type));
|
|
5599
|
+
if (type === "face" || type === "edge" || type === "vertex" || type === "wire") return toArray(bk.getCompoundSolids(h)).map(solidHandle).flatMap((s) => iterShapes$1(bk, s, type));
|
|
5600
5600
|
return [];
|
|
5601
5601
|
}
|
|
5602
5602
|
function iterSolid(bk, h, type) {
|
|
@@ -5612,7 +5612,7 @@ function iterShellChildren(bk, h, type) {
|
|
|
5612
5612
|
const faces = toArray(bk.getShellFaces(h)).map(faceHandle);
|
|
5613
5613
|
const seen = /* @__PURE__ */ new Set();
|
|
5614
5614
|
const results = [];
|
|
5615
|
-
for (const face of faces) for (const child of iterShapes(bk, face, type)) {
|
|
5615
|
+
for (const face of faces) for (const child of iterShapes$1(bk, face, type)) {
|
|
5616
5616
|
const childId = unwrap$1(child);
|
|
5617
5617
|
if (seen.has(childId)) continue;
|
|
5618
5618
|
seen.add(childId);
|
|
@@ -5672,7 +5672,7 @@ function iterEdge(bk, shape, h, type) {
|
|
|
5672
5672
|
}
|
|
5673
5673
|
return [];
|
|
5674
5674
|
}
|
|
5675
|
-
function iterShapes(bk, shape, type) {
|
|
5675
|
+
function iterShapes$1(bk, shape, type) {
|
|
5676
5676
|
const h = unwrap$1(shape);
|
|
5677
5677
|
switch (shape.type) {
|
|
5678
5678
|
case "compound": return iterCompound(bk, h, type);
|
|
@@ -5687,31 +5687,31 @@ function iterShapes(bk, shape, type) {
|
|
|
5687
5687
|
function iterShapeList(_bk, list, callback) {
|
|
5688
5688
|
if (Array.isArray(list)) for (const item of list) callback(item);
|
|
5689
5689
|
}
|
|
5690
|
-
function shapeType(_bk, shape) {
|
|
5690
|
+
function shapeType$1(_bk, shape) {
|
|
5691
5691
|
if (isBrepkitHandle(shape)) return shape.type;
|
|
5692
5692
|
throw new Error("brepkit: cannot determine shape type of non-brepkit handle");
|
|
5693
5693
|
}
|
|
5694
|
-
function isSame(_bk, a, b) {
|
|
5694
|
+
function isSame$1(_bk, a, b) {
|
|
5695
5695
|
return isBrepkitHandle(a) && isBrepkitHandle(b) && a.id === b.id && a.type === b.type;
|
|
5696
5696
|
}
|
|
5697
5697
|
function isEqual(_bk, a, b) {
|
|
5698
|
-
return isSame(_bk, a, b);
|
|
5698
|
+
return isSame$1(_bk, a, b);
|
|
5699
5699
|
}
|
|
5700
5700
|
function downcast(_bk, shape, _type) {
|
|
5701
5701
|
return shape;
|
|
5702
5702
|
}
|
|
5703
|
-
function hashCode(_bk, shape, upperBound) {
|
|
5703
|
+
function hashCode$1(_bk, shape, upperBound) {
|
|
5704
5704
|
if (!isBrepkitHandle(shape)) return 0;
|
|
5705
5705
|
return shape.id % upperBound;
|
|
5706
5706
|
}
|
|
5707
|
-
function isNull(_bk, shape) {
|
|
5707
|
+
function isNull$1(_bk, shape) {
|
|
5708
5708
|
return !shape || !isBrepkitHandle(shape);
|
|
5709
5709
|
}
|
|
5710
5710
|
function shapeOrientation(bk, shape) {
|
|
5711
5711
|
const h = unwrap$1(shape);
|
|
5712
5712
|
return bk.getShapeOrientation(h);
|
|
5713
5713
|
}
|
|
5714
|
-
function edgeToFaceMap(bk, shape) {
|
|
5714
|
+
function edgeToFaceMap$1(bk, shape) {
|
|
5715
5715
|
const solidId = unwrapSolidOrThrow(shape, "edgeToFaceMap");
|
|
5716
5716
|
return bk.edgeToFaceMap(solidId);
|
|
5717
5717
|
}
|
|
@@ -5720,7 +5720,7 @@ function sharedEdges(bk, faceA, faceB) {
|
|
|
5720
5720
|
const bId = unwrap$1(faceB, "face");
|
|
5721
5721
|
return Array.from(bk.sharedEdges(aId, bId)).map((id) => edgeHandle(id));
|
|
5722
5722
|
}
|
|
5723
|
-
function adjacentFaces(bk, shape, face) {
|
|
5723
|
+
function adjacentFaces$1(bk, shape, face) {
|
|
5724
5724
|
const solidId = unwrapSolidOrThrow(shape, "adjacentFaces");
|
|
5725
5725
|
const faceId = unwrap$1(face, "face");
|
|
5726
5726
|
return Array.from(bk.adjacentFaces(solidId, faceId)).map((id) => faceHandle(id));
|
|
@@ -5745,20 +5745,20 @@ function sew(bk, shapes, tolerance) {
|
|
|
5745
5745
|
/** Co-located factory: returns the topology-iteration slice of {@link KernelAdapter} bound to `bk`. */
|
|
5746
5746
|
function makeTopologyOps$1(bk) {
|
|
5747
5747
|
return {
|
|
5748
|
-
iterShapes: (shape, type) => iterShapes(bk, shape, type),
|
|
5748
|
+
iterShapes: (shape, type) => iterShapes$1(bk, shape, type),
|
|
5749
5749
|
iterShapeList: (list, callback) => {
|
|
5750
5750
|
iterShapeList(bk, list, callback);
|
|
5751
5751
|
},
|
|
5752
|
-
shapeType: (shape) => shapeType(bk, shape),
|
|
5753
|
-
isSame: (a, b) => isSame(bk, a, b),
|
|
5752
|
+
shapeType: (shape) => shapeType$1(bk, shape),
|
|
5753
|
+
isSame: (a, b) => isSame$1(bk, a, b),
|
|
5754
5754
|
isEqual: (a, b) => isEqual(bk, a, b),
|
|
5755
5755
|
downcast: (shape, type) => downcast(bk, shape, type),
|
|
5756
|
-
hashCode: (shape, upperBound) => hashCode(bk, shape, upperBound),
|
|
5757
|
-
isNull: (shape) => isNull(bk, shape),
|
|
5756
|
+
hashCode: (shape, upperBound) => hashCode$1(bk, shape, upperBound),
|
|
5757
|
+
isNull: (shape) => isNull$1(bk, shape),
|
|
5758
5758
|
shapeOrientation: (shape) => shapeOrientation(bk, shape),
|
|
5759
|
-
edgeToFaceMap: (shape) => edgeToFaceMap(bk, shape),
|
|
5759
|
+
edgeToFaceMap: (shape) => edgeToFaceMap$1(bk, shape),
|
|
5760
5760
|
sharedEdges: (faceA, faceB) => sharedEdges(bk, faceA, faceB),
|
|
5761
|
-
adjacentFaces: (shape, face) => adjacentFaces(bk, shape, face),
|
|
5761
|
+
adjacentFaces: (shape, face) => adjacentFaces$1(bk, shape, face),
|
|
5762
5762
|
sew: (shapes, tolerance) => sew(bk, shapes, tolerance)
|
|
5763
5763
|
};
|
|
5764
5764
|
}
|
|
@@ -5904,7 +5904,7 @@ function curvePeriod(bk, shape) {
|
|
|
5904
5904
|
}
|
|
5905
5905
|
function curveType(bk, shape) {
|
|
5906
5906
|
if (shape.type === "wire") {
|
|
5907
|
-
const first = iterShapes(bk, shape, "edge")[0];
|
|
5907
|
+
const first = iterShapes$1(bk, shape, "edge")[0];
|
|
5908
5908
|
if (first) return bk.getEdgeCurveType(unwrap$1(first, "edge"));
|
|
5909
5909
|
return "LINE";
|
|
5910
5910
|
}
|
|
@@ -5980,7 +5980,7 @@ function recognizeFeatures(bk, shape, tolerance) {
|
|
|
5980
5980
|
return bk.recognizeFeatures(solidId, tolerance);
|
|
5981
5981
|
}
|
|
5982
5982
|
function projectEdges(bk, shape, _cameraOrigin, _cameraDirection, _cameraXAxis) {
|
|
5983
|
-
const edges = iterShapes(bk, shape, "edge");
|
|
5983
|
+
const edges = iterShapes$1(bk, shape, "edge");
|
|
5984
5984
|
const emptyCompound = edges.length > 0 ? edges[0] : shape;
|
|
5985
5985
|
return {
|
|
5986
5986
|
visible: {
|
|
@@ -6069,7 +6069,7 @@ function makeGeometryOps$1(bk) {
|
|
|
6069
6069
|
}
|
|
6070
6070
|
//#endregion
|
|
6071
6071
|
//#region src/kernel/brepkit/transformOps.ts
|
|
6072
|
-
function transform$
|
|
6072
|
+
function transform$2(bk, shape, trsf) {
|
|
6073
6073
|
if (Array.isArray(trsf) && trsf.length === 16) return applyMatrix$1(bk, shape, trsf);
|
|
6074
6074
|
throw new Error("brepkit: transform expects a 16-element matrix array");
|
|
6075
6075
|
}
|
|
@@ -6147,7 +6147,7 @@ function transformBatch$1(bk, entries) {
|
|
|
6147
6147
|
/** Co-located factory: returns the transform slice of {@link KernelAdapter} bound to `bk`. */
|
|
6148
6148
|
function makeTransformOps$1(bk) {
|
|
6149
6149
|
return {
|
|
6150
|
-
transform: (shape, trsf) => transform$
|
|
6150
|
+
transform: (shape, trsf) => transform$2(bk, shape, trsf),
|
|
6151
6151
|
translate: (shape, x, y, z) => translate$1(bk, shape, x, y, z),
|
|
6152
6152
|
rotate: (shape, angle, axis, center) => rotate$1(bk, shape, angle, axis, center),
|
|
6153
6153
|
mirror: (shape, origin, normal) => mirror$1(bk, shape, origin, normal),
|
|
@@ -6235,7 +6235,7 @@ function extractPlaneFromFace(bk, faceShape) {
|
|
|
6235
6235
|
let faceId;
|
|
6236
6236
|
const h = faceShape;
|
|
6237
6237
|
if (h.type === "solid" || h.type === "compound") {
|
|
6238
|
-
const faces = iterShapes(bk, faceShape, "face");
|
|
6238
|
+
const faces = iterShapes$1(bk, faceShape, "face");
|
|
6239
6239
|
if (faces.length === 0) throw new Error("brepkit: extractPlaneFromFace: no faces found");
|
|
6240
6240
|
const firstFace = faces[0];
|
|
6241
6241
|
if (!firstFace) throw new Error("brepkit: extractPlaneFromFace: no faces found");
|
|
@@ -7381,7 +7381,7 @@ function brepkitJoinType(joinType) {
|
|
|
7381
7381
|
}
|
|
7382
7382
|
function offsetWire2D(bk, wire, offsetVal, joinType) {
|
|
7383
7383
|
if (typeof bk.offsetWire2DWithJoin === "function") return wireHandle(bk.offsetWire2DWithJoin(unwrap$1(wire, "wire"), offsetVal, brepkitJoinType(joinType)));
|
|
7384
|
-
const edges = iterShapes(bk, wire, "edge");
|
|
7384
|
+
const edges = iterShapes$1(bk, wire, "edge");
|
|
7385
7385
|
if (edges.length === 0) return wire;
|
|
7386
7386
|
const coords2d = [];
|
|
7387
7387
|
for (const edge of edges) {
|
|
@@ -8788,7 +8788,7 @@ function fixWireOnFace(wire, _face, _tolerance) {
|
|
|
8788
8788
|
}
|
|
8789
8789
|
function fillSurface(bk, wires, _options) {
|
|
8790
8790
|
if (wires.length >= 1) {
|
|
8791
|
-
const wireEdges = iterShapes(bk, wires[0], "edge");
|
|
8791
|
+
const wireEdges = iterShapes$1(bk, wires[0], "edge");
|
|
8792
8792
|
if (wireEdges.length === 4) {
|
|
8793
8793
|
const allCoords = [];
|
|
8794
8794
|
const curveLengths = [];
|
|
@@ -8900,7 +8900,7 @@ function volume$1(bk, shape) {
|
|
|
8900
8900
|
const h = shape;
|
|
8901
8901
|
if (h.type === "solid") return bk.volume(unwrap$1(shape), DEFAULT_DEFLECTION);
|
|
8902
8902
|
if (h.type === "compound") {
|
|
8903
|
-
const solids = iterShapes(bk, shape, "solid");
|
|
8903
|
+
const solids = iterShapes$1(bk, shape, "solid");
|
|
8904
8904
|
let total = 0;
|
|
8905
8905
|
for (const s of solids) total += bk.volume(unwrap$1(s), DEFAULT_DEFLECTION);
|
|
8906
8906
|
return total;
|
|
@@ -8912,7 +8912,7 @@ function area$1(bk, shape) {
|
|
|
8912
8912
|
if (h.type === "face") return bk.faceArea(unwrap$1(shape), DEFAULT_DEFLECTION);
|
|
8913
8913
|
if (h.type === "solid") return bk.surfaceArea(unwrap$1(shape), DEFAULT_DEFLECTION);
|
|
8914
8914
|
if (h.type === "compound") {
|
|
8915
|
-
const faces = iterShapes(bk, shape, "face");
|
|
8915
|
+
const faces = iterShapes$1(bk, shape, "face");
|
|
8916
8916
|
let total = 0;
|
|
8917
8917
|
for (const face of faces) total += bk.faceArea(unwrap$1(face), DEFAULT_DEFLECTION);
|
|
8918
8918
|
return total;
|
|
@@ -8943,7 +8943,7 @@ function centerOfMass$1(bk, shape) {
|
|
|
8943
8943
|
}
|
|
8944
8944
|
if (h.type === "edge") return edgeMidpoint(bk, h.id);
|
|
8945
8945
|
if (h.type === "vertex") return vertexPosition(bk, shape);
|
|
8946
|
-
const vertices = iterShapes(bk, shape, "vertex");
|
|
8946
|
+
const vertices = iterShapes$1(bk, shape, "vertex");
|
|
8947
8947
|
if (vertices.length > 0) {
|
|
8948
8948
|
let sx = 0, sy = 0, sz = 0;
|
|
8949
8949
|
for (const v of vertices) {
|
|
@@ -8985,7 +8985,7 @@ function boundingBox$1(bk, shape) {
|
|
|
8985
8985
|
max: [...pos]
|
|
8986
8986
|
};
|
|
8987
8987
|
}
|
|
8988
|
-
const vertices = iterShapes(bk, shape, "vertex");
|
|
8988
|
+
const vertices = iterShapes$1(bk, shape, "vertex");
|
|
8989
8989
|
if (vertices.length === 0) return {
|
|
8990
8990
|
min: [
|
|
8991
8991
|
0,
|
|
@@ -9417,7 +9417,7 @@ function sweep(bk, wire, spine, options) {
|
|
|
9417
9417
|
const profileHandle = wire;
|
|
9418
9418
|
const faceId = profileHandle.type === "wire" ? bk.makeFaceFromWire(profileHandle.id) : unwrap$1(wire, "face");
|
|
9419
9419
|
if (spine.type === "wire") {
|
|
9420
|
-
const edgeIds = iterShapes(bk, spine, "edge").map((e) => unwrap$1(e, "edge"));
|
|
9420
|
+
const edgeIds = iterShapes$1(bk, spine, "edge").map((e) => unwrap$1(e, "edge"));
|
|
9421
9421
|
if (contactMode && edgeIds.length === 1) {
|
|
9422
9422
|
const edgeId = edgeIds[0];
|
|
9423
9423
|
if (edgeId !== void 0) return solidHandle(bk.sweepWithOptions(faceId, edgeId, contactMode, [], 0, "transformed"));
|
|
@@ -9437,7 +9437,7 @@ function simplePipe(bk, profile, spine) {
|
|
|
9437
9437
|
const profileHandle = profile;
|
|
9438
9438
|
const faceId = profileHandle.type === "wire" ? bk.makeFaceFromWire(profileHandle.id) : unwrap$1(profile, "face");
|
|
9439
9439
|
if (spine.type === "wire") {
|
|
9440
|
-
const edgeIds = iterShapes(bk, spine, "edge").map((e) => unwrap$1(e, "edge"));
|
|
9440
|
+
const edgeIds = iterShapes$1(bk, spine, "edge").map((e) => unwrap$1(e, "edge"));
|
|
9441
9441
|
return solidHandle(bk.sweepAlongEdges(faceId, edgeIds));
|
|
9442
9442
|
}
|
|
9443
9443
|
const nurbsData = extractNurbsFromEdge(bk, spine);
|
|
@@ -9480,7 +9480,7 @@ function tryContactModeSweep(bk, faceId, edgeId, contactMode) {
|
|
|
9480
9480
|
function resolveContactModeEdge(bk, spine) {
|
|
9481
9481
|
try {
|
|
9482
9482
|
if (spine.type !== "wire") return { edgeId: unwrap$1(spine, "edge") };
|
|
9483
|
-
const edges = iterShapes(bk, spine, "edge");
|
|
9483
|
+
const edges = iterShapes$1(bk, spine, "edge");
|
|
9484
9484
|
if (edges.length === 1) {
|
|
9485
9485
|
const first = edges[0];
|
|
9486
9486
|
if (first) return { edgeId: unwrap$1(first, "edge") };
|
|
@@ -9687,7 +9687,10 @@ var REPLAYABLE_OPS = new Set([
|
|
|
9687
9687
|
"reverseShape",
|
|
9688
9688
|
"hull",
|
|
9689
9689
|
"hullFromPoints",
|
|
9690
|
-
"sewAndSolidify"
|
|
9690
|
+
"sewAndSolidify",
|
|
9691
|
+
"profileEdge",
|
|
9692
|
+
"profileWire",
|
|
9693
|
+
"profileFace"
|
|
9691
9694
|
]);
|
|
9692
9695
|
function opIsReplayable(op) {
|
|
9693
9696
|
return REPLAYABLE_OPS.has(op);
|
|
@@ -9746,12 +9749,11 @@ function nodeOf(shape) {
|
|
|
9746
9749
|
function asManifoldShape(shape) {
|
|
9747
9750
|
if (shape && typeof shape === "object" && "manifold" in shape && "node" in shape) return shape;
|
|
9748
9751
|
}
|
|
9752
|
+
var OCCT_FAMILY_IDS = ["occt", "occt-wasm"];
|
|
9749
9753
|
function resolveOcct() {
|
|
9750
|
-
try {
|
|
9751
|
-
return getKernel(
|
|
9752
|
-
} catch {
|
|
9753
|
-
return;
|
|
9754
|
-
}
|
|
9754
|
+
for (const id of OCCT_FAMILY_IDS) try {
|
|
9755
|
+
return getKernel(id);
|
|
9756
|
+
} catch {}
|
|
9755
9757
|
}
|
|
9756
9758
|
function occtOrThrow(method) {
|
|
9757
9759
|
const occt = resolveOcct();
|
|
@@ -10189,7 +10191,7 @@ function scale(shape, center, factor) {
|
|
|
10189
10191
|
factor
|
|
10190
10192
|
}, nodeOf(s));
|
|
10191
10193
|
}
|
|
10192
|
-
function transform(shape, trsf) {
|
|
10194
|
+
function transform$1(shape, trsf) {
|
|
10193
10195
|
if (!Array.isArray(trsf) || trsf.length !== 16) throw new Error("manifold: transform expects a 16-element column-major matrix");
|
|
10194
10196
|
const s = asShape$3(shape);
|
|
10195
10197
|
return applyMatrix(unwrap(s), trsf, "transformShape", { matrix: [...trsf] }, nodeOf(s));
|
|
@@ -10271,7 +10273,7 @@ function transformBatch(entries) {
|
|
|
10271
10273
|
function makeTransformOps(module) {
|
|
10272
10274
|
return {
|
|
10273
10275
|
composeTransform,
|
|
10274
|
-
transform,
|
|
10276
|
+
transform: transform$1,
|
|
10275
10277
|
translate,
|
|
10276
10278
|
rotate,
|
|
10277
10279
|
mirror,
|
|
@@ -10299,66 +10301,6 @@ function multiplyMatrix(a, b) {
|
|
|
10299
10301
|
return out;
|
|
10300
10302
|
}
|
|
10301
10303
|
//#endregion
|
|
10302
|
-
//#region src/kernel/manifold/builderOps.ts
|
|
10303
|
-
function makeBuilderOps(module) {
|
|
10304
|
-
const Manifold = module.Manifold;
|
|
10305
|
-
function hullFromPoints(points, tolerance) {
|
|
10306
|
-
const coords = points.map((p) => [
|
|
10307
|
-
p.x,
|
|
10308
|
-
p.y,
|
|
10309
|
-
p.z
|
|
10310
|
-
]);
|
|
10311
|
-
return wrap(Manifold.hull(coords), makeNode("hullFromPoints", {
|
|
10312
|
-
points: coords,
|
|
10313
|
-
tolerance
|
|
10314
|
-
}, []));
|
|
10315
|
-
}
|
|
10316
|
-
function hull(shapes, tolerance) {
|
|
10317
|
-
const operands = shapes.map((s) => unwrap(s));
|
|
10318
|
-
return wrap(Manifold.hull(operands), makeNode("hull", { tolerance }, shapes.map((s) => nodeOf(s))));
|
|
10319
|
-
}
|
|
10320
|
-
function sewAndSolidify(faces, tolerance) {
|
|
10321
|
-
const first = faces[0];
|
|
10322
|
-
if (!first) notImplemented("sewAndSolidify (no input faces on manifold kernel)");
|
|
10323
|
-
return wrap(unwrap(first), makeNode("sewAndSolidify", { tolerance }, faces.map((f) => nodeOf(f))));
|
|
10324
|
-
}
|
|
10325
|
-
return {
|
|
10326
|
-
makeVertex: () => notImplemented("makeVertex"),
|
|
10327
|
-
makeEdge: () => notImplemented("makeEdge"),
|
|
10328
|
-
makeWire: () => notImplemented("makeWire"),
|
|
10329
|
-
makeFace: () => notImplemented("makeFace"),
|
|
10330
|
-
makeLineEdge: () => notImplemented("makeLineEdge"),
|
|
10331
|
-
makeCircleEdge: () => notImplemented("makeCircleEdge"),
|
|
10332
|
-
makeCircleArc: () => notImplemented("makeCircleArc"),
|
|
10333
|
-
makeArcEdge: () => notImplemented("makeArcEdge"),
|
|
10334
|
-
makeEllipseEdge: () => notImplemented("makeEllipseEdge"),
|
|
10335
|
-
makeEllipseArc: () => notImplemented("makeEllipseArc"),
|
|
10336
|
-
makeBezierEdge: () => notImplemented("makeBezierEdge"),
|
|
10337
|
-
makeTangentArc: () => notImplemented("makeTangentArc"),
|
|
10338
|
-
makeHelixWire: () => notImplemented("makeHelixWire"),
|
|
10339
|
-
makeWireFromMixed: () => notImplemented("makeWireFromMixed"),
|
|
10340
|
-
makeCompound: () => notImplemented("makeCompound"),
|
|
10341
|
-
solidFromShell: () => notImplemented("solidFromShell"),
|
|
10342
|
-
hull,
|
|
10343
|
-
hullFromPoints,
|
|
10344
|
-
buildSolidFromFaces: () => notImplemented("buildSolidFromFaces"),
|
|
10345
|
-
makeNonPlanarFace: () => notImplemented("makeNonPlanarFace"),
|
|
10346
|
-
addHolesInFace: () => notImplemented("addHolesInFace"),
|
|
10347
|
-
removeHolesFromFace: () => notImplemented("removeHolesFromFace"),
|
|
10348
|
-
makeFaceOnSurface: () => notImplemented("makeFaceOnSurface"),
|
|
10349
|
-
bsplineSurface: (points, rows, cols) => occtOrThrow("bsplineSurface").bsplineSurface(points, rows, cols),
|
|
10350
|
-
triangulatedSurface: (points, rows, cols) => occtOrThrow("triangulatedSurface").triangulatedSurface(points, rows, cols),
|
|
10351
|
-
buildTriFace: () => notImplemented("buildTriFace"),
|
|
10352
|
-
sewAndSolidify,
|
|
10353
|
-
createPoint3d: () => notImplemented("createPoint3d"),
|
|
10354
|
-
createDirection3d: () => notImplemented("createDirection3d"),
|
|
10355
|
-
createVector3d: () => notImplemented("createVector3d"),
|
|
10356
|
-
createAxis1: () => notImplemented("createAxis1"),
|
|
10357
|
-
createAxis2: () => notImplemented("createAxis2"),
|
|
10358
|
-
createAxis3: () => notImplemented("createAxis3")
|
|
10359
|
-
};
|
|
10360
|
-
}
|
|
10361
|
-
//#endregion
|
|
10362
10304
|
//#region src/kernel/manifold/approximations.ts
|
|
10363
10305
|
function asShape$2(shape) {
|
|
10364
10306
|
return shape;
|
|
@@ -10445,6 +10387,10 @@ function signedArea(outline) {
|
|
|
10445
10387
|
function ensureCCW(outline) {
|
|
10446
10388
|
return signedArea(outline) < 0 ? [...outline].reverse() : outline;
|
|
10447
10389
|
}
|
|
10390
|
+
/** Force CW winding (used for holes, opposite the CCW outline). */
|
|
10391
|
+
function ensureCW(outline) {
|
|
10392
|
+
return signedArea(outline) > 0 ? [...outline].reverse() : outline;
|
|
10393
|
+
}
|
|
10448
10394
|
function readNodeParams(shape) {
|
|
10449
10395
|
return shape.node?.params;
|
|
10450
10396
|
}
|
|
@@ -10467,8 +10413,10 @@ function profileCrossSection(profile) {
|
|
|
10467
10413
|
0
|
|
10468
10414
|
];
|
|
10469
10415
|
const outline = ensureCCW(recorded.map((p) => [p[0], p[1]]));
|
|
10416
|
+
const holes = (params?.["holes"])?.filter((h) => h.length >= 3).map((h) => ensureCW(h.map((p) => [p[0], p[1]])));
|
|
10470
10417
|
if (params?.["xAxis"] && params["yAxis"]) return {
|
|
10471
10418
|
outline,
|
|
10419
|
+
holes,
|
|
10472
10420
|
origin,
|
|
10473
10421
|
xAxis: params["xAxis"],
|
|
10474
10422
|
yAxis: params["yAxis"]
|
|
@@ -10480,6 +10428,7 @@ function profileCrossSection(profile) {
|
|
|
10480
10428
|
]);
|
|
10481
10429
|
return {
|
|
10482
10430
|
outline,
|
|
10431
|
+
holes,
|
|
10483
10432
|
origin,
|
|
10484
10433
|
xAxis,
|
|
10485
10434
|
yAxis
|
|
@@ -10555,6 +10504,54 @@ function fanTriangulate(vertexCount) {
|
|
|
10555
10504
|
* in correspondence with the section's outline order. `scale` rescales the
|
|
10556
10505
|
* outline about its frame origin (for tapered/draft sweeps and scale laws).
|
|
10557
10506
|
*/
|
|
10507
|
+
/**
|
|
10508
|
+
* Upsample a closed 2D outline to exactly `n` points by KEEPING every original
|
|
10509
|
+
* vertex and inserting extra points on the longest segments (proportional to
|
|
10510
|
+
* length, largest-remainder allotment). Vertex-preserving so corners aren't
|
|
10511
|
+
* rounded off — resampling a 4-point rectangle to 4 returns it unchanged. Used
|
|
10512
|
+
* to give loft sections a common vertex count so {@link skinRings} can connect
|
|
10513
|
+
* them by index; lofting profiles of different point counts (circle ↔ rounded
|
|
10514
|
+
* rect) is otherwise impossible on the mesh kernel. `n < k` is not supported
|
|
10515
|
+
* (callers pass `n = max` count), so it never downsamples.
|
|
10516
|
+
*/
|
|
10517
|
+
function resampleClosed(outline, n) {
|
|
10518
|
+
const k = outline.length;
|
|
10519
|
+
if (k < 2 || n <= k) return outline.map((p) => [p[0], p[1]]);
|
|
10520
|
+
const seg = [];
|
|
10521
|
+
let total = 0;
|
|
10522
|
+
for (let i = 0; i < k; i++) {
|
|
10523
|
+
const a = outline[i] ?? [0, 0];
|
|
10524
|
+
const b = outline[(i + 1) % k] ?? [0, 0];
|
|
10525
|
+
const l = Math.hypot(b[0] - a[0], b[1] - a[1]);
|
|
10526
|
+
seg.push(l);
|
|
10527
|
+
total += l;
|
|
10528
|
+
}
|
|
10529
|
+
if (total === 0) return outline.map((p) => [p[0], p[1]]);
|
|
10530
|
+
const extra = n - k;
|
|
10531
|
+
const quota = seg.map((l) => extra * l / total);
|
|
10532
|
+
const add = quota.map((q) => Math.floor(q));
|
|
10533
|
+
let placed = add.reduce((s, v) => s + v, 0);
|
|
10534
|
+
const rema = quota.map((q, i) => ({
|
|
10535
|
+
i,
|
|
10536
|
+
f: q - Math.floor(q)
|
|
10537
|
+
})).sort((x, y) => y.f - x.f);
|
|
10538
|
+
for (let r = 0; placed < extra; r++, placed++) {
|
|
10539
|
+
const idx = rema[r % rema.length]?.i ?? 0;
|
|
10540
|
+
add[idx] = (add[idx] ?? 0) + 1;
|
|
10541
|
+
}
|
|
10542
|
+
const out = [];
|
|
10543
|
+
for (let i = 0; i < k; i++) {
|
|
10544
|
+
const a = outline[i] ?? [0, 0];
|
|
10545
|
+
const b = outline[(i + 1) % k] ?? [0, 0];
|
|
10546
|
+
out.push([a[0], a[1]]);
|
|
10547
|
+
const inner = add[i] ?? 0;
|
|
10548
|
+
for (let j = 1; j <= inner; j++) {
|
|
10549
|
+
const t = j / (inner + 1);
|
|
10550
|
+
out.push([a[0] + (b[0] - a[0]) * t, a[1] + (b[1] - a[1]) * t]);
|
|
10551
|
+
}
|
|
10552
|
+
}
|
|
10553
|
+
return out;
|
|
10554
|
+
}
|
|
10558
10555
|
function placeRing(section, frame, scale = 1) {
|
|
10559
10556
|
return section.outline.map((p) => {
|
|
10560
10557
|
const lx = p[0] * scale;
|
|
@@ -10589,7 +10586,32 @@ function skinRings(module, rings) {
|
|
|
10589
10586
|
vertProperties: Float32Array.from(verts),
|
|
10590
10587
|
triVerts: Uint32Array.from(tris)
|
|
10591
10588
|
});
|
|
10592
|
-
return new module.Manifold(built);
|
|
10589
|
+
return orientPositive(module, new module.Manifold(built));
|
|
10590
|
+
}
|
|
10591
|
+
/**
|
|
10592
|
+
* Normalize a built solid to outward (positive-volume) orientation. Skinning a
|
|
10593
|
+
* profile whose section order or outline winding runs "backwards" yields an
|
|
10594
|
+
* inside-out manifold (negative volume) that booleans then mishandle — a cut
|
|
10595
|
+
* tool that won't subtract, a fuse operand that cancels volume. If the volume
|
|
10596
|
+
* is negative, rebuild with reversed triangle winding so normals face outward.
|
|
10597
|
+
*/
|
|
10598
|
+
function orientPositive(module, solid) {
|
|
10599
|
+
if (typeof solid.volume !== "function" || solid.volume() >= 0) return solid;
|
|
10600
|
+
const mesh = solid.getMesh();
|
|
10601
|
+
const tv = mesh.triVerts;
|
|
10602
|
+
for (let i = 0; i + 2 < tv.length; i += 3) {
|
|
10603
|
+
const t = tv[i + 1] ?? 0;
|
|
10604
|
+
tv[i + 1] = tv[i + 2] ?? 0;
|
|
10605
|
+
tv[i + 2] = t;
|
|
10606
|
+
}
|
|
10607
|
+
const flipped = new module.Mesh({
|
|
10608
|
+
numProp: mesh.numProp,
|
|
10609
|
+
vertProperties: mesh.vertProperties,
|
|
10610
|
+
triVerts: tv
|
|
10611
|
+
});
|
|
10612
|
+
const result = new module.Manifold(flipped);
|
|
10613
|
+
if (typeof solid.delete === "function") solid.delete();
|
|
10614
|
+
return result;
|
|
10593
10615
|
}
|
|
10594
10616
|
/** Build the triangle index list for `ringCount` rings of `m` points each. */
|
|
10595
10617
|
function skinTriangles(ringCount, m) {
|
|
@@ -10679,6 +10701,358 @@ function rotationMinimizingFrames(path, seed) {
|
|
|
10679
10701
|
return frames;
|
|
10680
10702
|
}
|
|
10681
10703
|
//#endregion
|
|
10704
|
+
//#region src/kernel/manifold/profileOps.ts
|
|
10705
|
+
/** Segments used to approximate a full circle; arcs scale by angle span. */
|
|
10706
|
+
var FULL_CIRCLE_SEGMENTS = 24;
|
|
10707
|
+
/** Bezier sampling segments per edge. */
|
|
10708
|
+
var BEZIER_SEGMENTS = 24;
|
|
10709
|
+
var ZERO3 = [
|
|
10710
|
+
0,
|
|
10711
|
+
0,
|
|
10712
|
+
0
|
|
10713
|
+
];
|
|
10714
|
+
var EPS_JOIN = 1e-6;
|
|
10715
|
+
var PLACEHOLDER = {
|
|
10716
|
+
delete: () => {},
|
|
10717
|
+
isEmpty: () => false
|
|
10718
|
+
};
|
|
10719
|
+
function at3(pts, i) {
|
|
10720
|
+
return pts[i] ?? ZERO3;
|
|
10721
|
+
}
|
|
10722
|
+
function arcSegments(angleSpan) {
|
|
10723
|
+
return Math.max(2, Math.ceil(Math.abs(angleSpan) / (2 * Math.PI) * FULL_CIRCLE_SEGMENTS));
|
|
10724
|
+
}
|
|
10725
|
+
function pickPerp(n) {
|
|
10726
|
+
return normalize3(cross(n, Math.abs(n[0]) < .9 ? [
|
|
10727
|
+
1,
|
|
10728
|
+
0,
|
|
10729
|
+
0
|
|
10730
|
+
] : [
|
|
10731
|
+
0,
|
|
10732
|
+
1,
|
|
10733
|
+
0
|
|
10734
|
+
]));
|
|
10735
|
+
}
|
|
10736
|
+
/** Sample a circular arc in the plane framed by `normal` about `center`. */
|
|
10737
|
+
function sampleArc(center, normal, radius, startAngle, endAngle, xDir) {
|
|
10738
|
+
const n = normalize3(normal);
|
|
10739
|
+
const x = xDir ? normalize3(xDir) : pickPerp(n);
|
|
10740
|
+
const y = normalize3(cross(n, x));
|
|
10741
|
+
const span = endAngle - startAngle;
|
|
10742
|
+
const segs = arcSegments(span);
|
|
10743
|
+
const pts = [];
|
|
10744
|
+
for (let i = 0; i <= segs; i++) {
|
|
10745
|
+
const a = startAngle + span * i / segs;
|
|
10746
|
+
pts.push(add(center, add(scaleVec(x, radius * Math.cos(a)), scaleVec(y, radius * Math.sin(a)))));
|
|
10747
|
+
}
|
|
10748
|
+
return pts;
|
|
10749
|
+
}
|
|
10750
|
+
/** Circular arc through three points, sampled as a polyline p1..p2..p3. */
|
|
10751
|
+
function circleFrom3(p1, p2, p3) {
|
|
10752
|
+
const v1 = sub(p2, p1);
|
|
10753
|
+
const v2 = sub(p3, p1);
|
|
10754
|
+
const n = cross(v1, v2);
|
|
10755
|
+
if (length3(n) < 1e-12) return [
|
|
10756
|
+
p1,
|
|
10757
|
+
p2,
|
|
10758
|
+
p3
|
|
10759
|
+
];
|
|
10760
|
+
const nn = normalize3(n);
|
|
10761
|
+
const b = dot(v1, v1);
|
|
10762
|
+
const c = dot(v2, v2);
|
|
10763
|
+
const d = dot(v1, v2);
|
|
10764
|
+
const denom = 2 * (b * c - d * d);
|
|
10765
|
+
if (Math.abs(denom) < 1e-18) return [
|
|
10766
|
+
p1,
|
|
10767
|
+
p2,
|
|
10768
|
+
p3
|
|
10769
|
+
];
|
|
10770
|
+
const s = c * (b - d) / denom;
|
|
10771
|
+
const t = b * (c - d) / denom;
|
|
10772
|
+
const center = add(p1, add(scaleVec(v1, s), scaleVec(v2, t)));
|
|
10773
|
+
const radius = length3(sub(p1, center));
|
|
10774
|
+
const x = normalize3(sub(p1, center));
|
|
10775
|
+
const y = normalize3(cross(nn, x));
|
|
10776
|
+
const angleOf = (p) => Math.atan2(dot(sub(p, center), y), dot(sub(p, center), x));
|
|
10777
|
+
let a3 = angleOf(p3);
|
|
10778
|
+
if (a3 < 0) a3 += 2 * Math.PI;
|
|
10779
|
+
return sampleArc(center, nn, radius, 0, a3, x);
|
|
10780
|
+
}
|
|
10781
|
+
/** De Casteljau sampling of a Bezier of arbitrary degree. */
|
|
10782
|
+
function sampleBezier(points) {
|
|
10783
|
+
const out = [];
|
|
10784
|
+
for (let i = 0; i <= BEZIER_SEGMENTS; i++) {
|
|
10785
|
+
const t = i / BEZIER_SEGMENTS;
|
|
10786
|
+
const tmp = points.map((p) => [...p]);
|
|
10787
|
+
for (let k = 1; k < tmp.length; k++) for (let j = 0; j < tmp.length - k; j++) {
|
|
10788
|
+
const a = at3(tmp, j);
|
|
10789
|
+
const bnext = at3(tmp, j + 1);
|
|
10790
|
+
tmp[j] = [
|
|
10791
|
+
a[0] * (1 - t) + bnext[0] * t,
|
|
10792
|
+
a[1] * (1 - t) + bnext[1] * t,
|
|
10793
|
+
a[2] * (1 - t) + bnext[2] * t
|
|
10794
|
+
];
|
|
10795
|
+
}
|
|
10796
|
+
out.push(at3(tmp, 0));
|
|
10797
|
+
}
|
|
10798
|
+
return out;
|
|
10799
|
+
}
|
|
10800
|
+
/** Newell's method: area-weighted normal of a (possibly non-convex) planar ring. */
|
|
10801
|
+
function ringNormal(ring) {
|
|
10802
|
+
let nx = 0;
|
|
10803
|
+
let ny = 0;
|
|
10804
|
+
let nz = 0;
|
|
10805
|
+
for (let i = 0; i < ring.length; i++) {
|
|
10806
|
+
const a = at3(ring, i);
|
|
10807
|
+
const b = at3(ring, (i + 1) % ring.length);
|
|
10808
|
+
nx += (a[1] - b[1]) * (a[2] + b[2]);
|
|
10809
|
+
ny += (a[2] - b[2]) * (a[0] + b[0]);
|
|
10810
|
+
nz += (a[0] - b[0]) * (a[1] + b[1]);
|
|
10811
|
+
}
|
|
10812
|
+
const n = [
|
|
10813
|
+
nx,
|
|
10814
|
+
ny,
|
|
10815
|
+
nz
|
|
10816
|
+
];
|
|
10817
|
+
return length3(n) < 1e-12 ? [
|
|
10818
|
+
0,
|
|
10819
|
+
0,
|
|
10820
|
+
1
|
|
10821
|
+
] : normalize3(n);
|
|
10822
|
+
}
|
|
10823
|
+
function coincident(a, b) {
|
|
10824
|
+
return length3(sub(a, b)) < EPS_JOIN;
|
|
10825
|
+
}
|
|
10826
|
+
/** Chain edge polylines head-to-tail into one closed ring (flipping as needed). */
|
|
10827
|
+
function chainEdges(edgePts) {
|
|
10828
|
+
const first = edgePts[0];
|
|
10829
|
+
if (!first) return [];
|
|
10830
|
+
const ring = [...first];
|
|
10831
|
+
for (let i = 1; i < edgePts.length; i++) {
|
|
10832
|
+
let pts = edgePts[i] ?? [];
|
|
10833
|
+
if (pts.length === 0) continue;
|
|
10834
|
+
const end = at3(ring, ring.length - 1);
|
|
10835
|
+
const startsAtEnd = coincident(at3(pts, 0), end);
|
|
10836
|
+
const endsAtEnd = coincident(at3(pts, pts.length - 1), end);
|
|
10837
|
+
if (!startsAtEnd && endsAtEnd) pts = [...pts].reverse();
|
|
10838
|
+
const startSame = coincident(at3(pts, 0), end);
|
|
10839
|
+
for (let k = startSame ? 1 : 0; k < pts.length; k++) ring.push(at3(pts, k));
|
|
10840
|
+
}
|
|
10841
|
+
if (ring.length > 1 && coincident(at3(ring, 0), at3(ring, ring.length - 1))) ring.pop();
|
|
10842
|
+
return ring;
|
|
10843
|
+
}
|
|
10844
|
+
/** Project a planar 3D ring onto its own plane → 2D outline + world frame. */
|
|
10845
|
+
function frameFromRing(ring) {
|
|
10846
|
+
const normal = ringNormal(ring);
|
|
10847
|
+
const origin = at3(ring, 0);
|
|
10848
|
+
let xAxis = ring.length > 1 ? normalize3(sub(at3(ring, 1), origin)) : pickPerp(normal);
|
|
10849
|
+
xAxis = normalize3(sub(xAxis, scaleVec(normal, dot(xAxis, normal))));
|
|
10850
|
+
if (length3(xAxis) < 1e-9) xAxis = pickPerp(normal);
|
|
10851
|
+
const yAxis = normalize3(cross(normal, xAxis));
|
|
10852
|
+
return {
|
|
10853
|
+
outline: ensureCCW(ring.map((p) => {
|
|
10854
|
+
const rel = sub(p, origin);
|
|
10855
|
+
return [dot(rel, xAxis), dot(rel, yAxis)];
|
|
10856
|
+
})),
|
|
10857
|
+
origin,
|
|
10858
|
+
xAxis,
|
|
10859
|
+
yAxis
|
|
10860
|
+
};
|
|
10861
|
+
}
|
|
10862
|
+
var OCCT_CURVE_SEGMENTS = 12;
|
|
10863
|
+
/** Sample an OCCT edge into a polyline (line → endpoints, curve → 24 segments). */
|
|
10864
|
+
function sampleOcctEdge(occt, edge) {
|
|
10865
|
+
const [t0, t1] = occt.curveParameters(edge);
|
|
10866
|
+
let segs = OCCT_CURVE_SEGMENTS;
|
|
10867
|
+
try {
|
|
10868
|
+
if (occt.curveType(edge) === "line") segs = 1;
|
|
10869
|
+
} catch {}
|
|
10870
|
+
const pts = [];
|
|
10871
|
+
for (let i = 0; i <= segs; i++) pts.push(occt.curvePointAtParam(edge, t0 + (t1 - t0) * i / segs));
|
|
10872
|
+
return pts;
|
|
10873
|
+
}
|
|
10874
|
+
/** Discretize an OCCT wire (from the 2D-delegated blueprint path) into a ring. */
|
|
10875
|
+
function discretizeOcctWire(occt, wire) {
|
|
10876
|
+
return chainEdges(occt.iterShapes(wire, "edge").map((e) => sampleOcctEdge(occt, e)));
|
|
10877
|
+
}
|
|
10878
|
+
function makeProfileBuilders(_module) {
|
|
10879
|
+
function edge(pts) {
|
|
10880
|
+
return wrap(PLACEHOLDER, makeNode("profileEdge", { pts }, []));
|
|
10881
|
+
}
|
|
10882
|
+
function ringOrPts(shape) {
|
|
10883
|
+
const ms = asManifoldShape(shape);
|
|
10884
|
+
if (ms) {
|
|
10885
|
+
const params = ms.node.params;
|
|
10886
|
+
return params?.ring ?? params?.pts ?? [];
|
|
10887
|
+
}
|
|
10888
|
+
const occt = resolveOcct();
|
|
10889
|
+
return occt ? sampleOcctEdge(occt, shape) : [];
|
|
10890
|
+
}
|
|
10891
|
+
function inputNodes(items) {
|
|
10892
|
+
const nodes = [];
|
|
10893
|
+
for (const it of items) {
|
|
10894
|
+
const ms = asManifoldShape(it);
|
|
10895
|
+
if (ms) nodes.push(nodeOf(ms));
|
|
10896
|
+
}
|
|
10897
|
+
return nodes;
|
|
10898
|
+
}
|
|
10899
|
+
function wireFrom(items) {
|
|
10900
|
+
const ring = chainEdges(items.map((e) => ringOrPts(e)));
|
|
10901
|
+
return wrap(PLACEHOLDER, makeNode("profileWire", {
|
|
10902
|
+
ring,
|
|
10903
|
+
...ring.length >= 3 ? frameFromRing(ring) : void 0
|
|
10904
|
+
}, inputNodes(items)));
|
|
10905
|
+
}
|
|
10906
|
+
function faceFromRing(ring, input) {
|
|
10907
|
+
const { outline, origin, xAxis, yAxis } = frameFromRing(ring);
|
|
10908
|
+
return wrap(PLACEHOLDER, makeNode("profileFace", {
|
|
10909
|
+
outline,
|
|
10910
|
+
origin,
|
|
10911
|
+
xAxis,
|
|
10912
|
+
yAxis
|
|
10913
|
+
}, input ? [input] : []));
|
|
10914
|
+
}
|
|
10915
|
+
function makeFace(wire) {
|
|
10916
|
+
const ms = asManifoldShape(wire);
|
|
10917
|
+
if (ms) {
|
|
10918
|
+
const ring = ms.node.params?.ring ?? [];
|
|
10919
|
+
if (ring.length >= 3) return faceFromRing(ring, nodeOf(ms));
|
|
10920
|
+
}
|
|
10921
|
+
const occt = resolveOcct();
|
|
10922
|
+
return faceFromRing(occt ? discretizeOcctWire(occt, wire) : [], ms ? nodeOf(ms) : void 0);
|
|
10923
|
+
}
|
|
10924
|
+
function addHolesInFace(face, holeWires) {
|
|
10925
|
+
const fms = asManifoldShape(face);
|
|
10926
|
+
const fp = (fms?.node)?.params ?? {};
|
|
10927
|
+
const origin = fp.origin ?? ZERO3;
|
|
10928
|
+
const xAxis = fp.xAxis ?? [
|
|
10929
|
+
1,
|
|
10930
|
+
0,
|
|
10931
|
+
0
|
|
10932
|
+
];
|
|
10933
|
+
const yAxis = fp.yAxis ?? [
|
|
10934
|
+
0,
|
|
10935
|
+
1,
|
|
10936
|
+
0
|
|
10937
|
+
];
|
|
10938
|
+
const project = (p) => {
|
|
10939
|
+
const rel = sub(p, origin);
|
|
10940
|
+
return [dot(rel, xAxis), dot(rel, yAxis)];
|
|
10941
|
+
};
|
|
10942
|
+
const newHoles = [];
|
|
10943
|
+
for (const hw of holeWires) {
|
|
10944
|
+
const hms = asManifoldShape(hw);
|
|
10945
|
+
let ring;
|
|
10946
|
+
if (hms) ring = hms.node.params?.ring ?? [];
|
|
10947
|
+
else {
|
|
10948
|
+
const occt = resolveOcct();
|
|
10949
|
+
ring = occt ? discretizeOcctWire(occt, hw) : [];
|
|
10950
|
+
}
|
|
10951
|
+
if (ring.length >= 3) newHoles.push(ring.map(project));
|
|
10952
|
+
}
|
|
10953
|
+
const holes = [...fp.holes ?? [], ...newHoles];
|
|
10954
|
+
const inputs = fms ? [nodeOf(fms), ...inputNodes(holeWires)] : inputNodes(holeWires);
|
|
10955
|
+
return wrap(PLACEHOLDER, makeNode("profileFace", {
|
|
10956
|
+
outline: fp.outline ?? [],
|
|
10957
|
+
holes,
|
|
10958
|
+
origin,
|
|
10959
|
+
xAxis,
|
|
10960
|
+
yAxis
|
|
10961
|
+
}, inputs));
|
|
10962
|
+
}
|
|
10963
|
+
function ellipsePts(center, normal, majorRadius, minorRadius, xDir) {
|
|
10964
|
+
const n = normalize3(normal);
|
|
10965
|
+
const x = xDir ? normalize3(xDir) : pickPerp(n);
|
|
10966
|
+
const y = normalize3(cross(n, x));
|
|
10967
|
+
const pts = [];
|
|
10968
|
+
for (let i = 0; i <= FULL_CIRCLE_SEGMENTS; i++) {
|
|
10969
|
+
const a = 2 * Math.PI * i / FULL_CIRCLE_SEGMENTS;
|
|
10970
|
+
pts.push(add(center, add(scaleVec(x, majorRadius * Math.cos(a)), scaleVec(y, minorRadius * Math.sin(a)))));
|
|
10971
|
+
}
|
|
10972
|
+
return pts;
|
|
10973
|
+
}
|
|
10974
|
+
return {
|
|
10975
|
+
makeVertex: (x, y, z) => edge([[
|
|
10976
|
+
x,
|
|
10977
|
+
y,
|
|
10978
|
+
z
|
|
10979
|
+
]]),
|
|
10980
|
+
makeLineEdge: (p1, p2) => edge([p1, p2]),
|
|
10981
|
+
makeCircleEdge: (center, normal, radius) => edge(sampleArc(center, normal, radius, 0, 2 * Math.PI)),
|
|
10982
|
+
makeCircleArc: (center, normal, radius, startAngle, endAngle) => edge(sampleArc(center, normal, radius, startAngle, endAngle)),
|
|
10983
|
+
makeArcEdge: (p1, p2, p3) => edge(circleFrom3(p1, p2, p3)),
|
|
10984
|
+
makeEllipseEdge: (center, normal, majorRadius, minorRadius, xDir) => edge(ellipsePts(center, normal, majorRadius, minorRadius, xDir)),
|
|
10985
|
+
makeBezierEdge: (points) => edge(sampleBezier(points)),
|
|
10986
|
+
makeTangentArc: (startPoint, _startTangent, endPoint) => edge([startPoint, endPoint]),
|
|
10987
|
+
makeWire: (edges) => wireFrom(edges),
|
|
10988
|
+
makeWireFromMixed: (items) => wireFrom(items),
|
|
10989
|
+
makeFace,
|
|
10990
|
+
addHolesInFace,
|
|
10991
|
+
makePolygonFace: (points) => faceFromRing(points)
|
|
10992
|
+
};
|
|
10993
|
+
}
|
|
10994
|
+
//#endregion
|
|
10995
|
+
//#region src/kernel/manifold/builderOps.ts
|
|
10996
|
+
function makeBuilderOps(module) {
|
|
10997
|
+
const Manifold = module.Manifold;
|
|
10998
|
+
const profile = makeProfileBuilders(module);
|
|
10999
|
+
function hullFromPoints(points, tolerance) {
|
|
11000
|
+
const coords = points.map((p) => [
|
|
11001
|
+
p.x,
|
|
11002
|
+
p.y,
|
|
11003
|
+
p.z
|
|
11004
|
+
]);
|
|
11005
|
+
return wrap(Manifold.hull(coords), makeNode("hullFromPoints", {
|
|
11006
|
+
points: coords,
|
|
11007
|
+
tolerance
|
|
11008
|
+
}, []));
|
|
11009
|
+
}
|
|
11010
|
+
function hull(shapes, tolerance) {
|
|
11011
|
+
const operands = shapes.map((s) => unwrap(s));
|
|
11012
|
+
return wrap(Manifold.hull(operands), makeNode("hull", { tolerance }, shapes.map((s) => nodeOf(s))));
|
|
11013
|
+
}
|
|
11014
|
+
function sewAndSolidify(faces, tolerance) {
|
|
11015
|
+
const first = faces[0];
|
|
11016
|
+
if (!first) notImplemented("sewAndSolidify (no input faces on manifold kernel)");
|
|
11017
|
+
return wrap(unwrap(first), makeNode("sewAndSolidify", { tolerance }, faces.map((f) => nodeOf(f))));
|
|
11018
|
+
}
|
|
11019
|
+
return {
|
|
11020
|
+
makeVertex: (x, y, z) => profile.makeVertex(x, y, z),
|
|
11021
|
+
makeEdge: () => notImplemented("makeEdge"),
|
|
11022
|
+
makeWire: (edges) => profile.makeWire(edges),
|
|
11023
|
+
makeFace: (wire, planar) => profile.makeFace(wire, planar),
|
|
11024
|
+
makeLineEdge: (p1, p2) => profile.makeLineEdge(p1, p2),
|
|
11025
|
+
makeCircleEdge: (center, normal, radius) => profile.makeCircleEdge(center, normal, radius),
|
|
11026
|
+
makeCircleArc: (center, normal, radius, startAngle, endAngle) => profile.makeCircleArc(center, normal, radius, startAngle, endAngle),
|
|
11027
|
+
makeArcEdge: (p1, p2, p3) => profile.makeArcEdge(p1, p2, p3),
|
|
11028
|
+
makeEllipseEdge: (center, normal, majorRadius, minorRadius, xDir) => profile.makeEllipseEdge(center, normal, majorRadius, minorRadius, xDir),
|
|
11029
|
+
makeEllipseArc: () => notImplemented("makeEllipseArc"),
|
|
11030
|
+
makeBezierEdge: (points) => profile.makeBezierEdge(points),
|
|
11031
|
+
makeTangentArc: (startPoint, startTangent, endPoint) => profile.makeTangentArc(startPoint, startTangent, endPoint),
|
|
11032
|
+
makeHelixWire: () => notImplemented("makeHelixWire"),
|
|
11033
|
+
makeWireFromMixed: (items) => profile.makeWireFromMixed(items),
|
|
11034
|
+
makeCompound: () => notImplemented("makeCompound"),
|
|
11035
|
+
solidFromShell: () => notImplemented("solidFromShell"),
|
|
11036
|
+
hull,
|
|
11037
|
+
hullFromPoints,
|
|
11038
|
+
buildSolidFromFaces: () => notImplemented("buildSolidFromFaces"),
|
|
11039
|
+
makeNonPlanarFace: () => notImplemented("makeNonPlanarFace"),
|
|
11040
|
+
addHolesInFace: (face, holeWires) => profile.addHolesInFace(face, holeWires),
|
|
11041
|
+
removeHolesFromFace: () => notImplemented("removeHolesFromFace"),
|
|
11042
|
+
makeFaceOnSurface: () => notImplemented("makeFaceOnSurface"),
|
|
11043
|
+
bsplineSurface: (points, rows, cols) => occtOrThrow("bsplineSurface").bsplineSurface(points, rows, cols),
|
|
11044
|
+
triangulatedSurface: (points, rows, cols) => occtOrThrow("triangulatedSurface").triangulatedSurface(points, rows, cols),
|
|
11045
|
+
buildTriFace: () => notImplemented("buildTriFace"),
|
|
11046
|
+
sewAndSolidify,
|
|
11047
|
+
createPoint3d: () => notImplemented("createPoint3d"),
|
|
11048
|
+
createDirection3d: () => notImplemented("createDirection3d"),
|
|
11049
|
+
createVector3d: () => notImplemented("createVector3d"),
|
|
11050
|
+
createAxis1: () => notImplemented("createAxis1"),
|
|
11051
|
+
createAxis2: () => notImplemented("createAxis2"),
|
|
11052
|
+
createAxis3: () => notImplemented("createAxis3")
|
|
11053
|
+
};
|
|
11054
|
+
}
|
|
11055
|
+
//#endregion
|
|
10682
11056
|
//#region src/kernel/manifold/sweepOps.ts
|
|
10683
11057
|
var RAD_PER_DEG = Math.PI / 180;
|
|
10684
11058
|
function asShape$1(shape) {
|
|
@@ -10893,8 +11267,10 @@ function extrudeOp(module, face, direction, length) {
|
|
|
10893
11267
|
direction[1] * length,
|
|
10894
11268
|
direction[2] * length
|
|
10895
11269
|
]);
|
|
10896
|
-
|
|
11270
|
+
const polygons = [toPolygon(section), ...(section.holes ?? []).map((h) => h.map((p) => [p[0], p[1]]))];
|
|
11271
|
+
return wrap(orientExtrusion(orientPositive(module, module.Manifold.extrude(polygons, height)), section, dir), makeNode("extrude", {
|
|
10897
11272
|
outline: section.outline,
|
|
11273
|
+
holes: section.holes,
|
|
10898
11274
|
origin: section.origin,
|
|
10899
11275
|
xAxis: section.xAxis,
|
|
10900
11276
|
yAxis: section.yAxis,
|
|
@@ -10912,14 +11288,59 @@ function revolveOp(module, shape, axisOrigin, axisDirection, angleRad, op, param
|
|
|
10912
11288
|
const radial = profileRadialOutline(section, axisOrigin, axisDirection);
|
|
10913
11289
|
return wrap(orientRevolution(module.Manifold.revolve([radial], 0, angleDeg), axisOrigin, axisDirection), makeNode(op, params, [nodeOf(asShape$1(shape))]));
|
|
10914
11290
|
}
|
|
11291
|
+
/**
|
|
11292
|
+
* Rotate `ring`'s point order to the cyclic offset that best lines up with
|
|
11293
|
+
* `ref` (minimizes Σ‖ring[(j+off)%n] − ref[j]‖²). Both rings must share a
|
|
11294
|
+
* vertex count. Keeps loft correspondence from twisting between dissimilar
|
|
11295
|
+
* sections.
|
|
11296
|
+
*/
|
|
11297
|
+
function alignRing(ring, ref) {
|
|
11298
|
+
const n = ring.length;
|
|
11299
|
+
if (n === 0 || ref.length !== n) return ring;
|
|
11300
|
+
let bestOff = 0;
|
|
11301
|
+
let bestCost = Infinity;
|
|
11302
|
+
for (let off = 0; off < n; off++) {
|
|
11303
|
+
let cost = 0;
|
|
11304
|
+
for (let j = 0; j < n && cost < bestCost; j++) {
|
|
11305
|
+
const a = ring[(j + off) % n] ?? [
|
|
11306
|
+
0,
|
|
11307
|
+
0,
|
|
11308
|
+
0
|
|
11309
|
+
];
|
|
11310
|
+
const b = ref[j] ?? [
|
|
11311
|
+
0,
|
|
11312
|
+
0,
|
|
11313
|
+
0
|
|
11314
|
+
];
|
|
11315
|
+
const dx = a[0] - b[0];
|
|
11316
|
+
const dy = a[1] - b[1];
|
|
11317
|
+
const dz = a[2] - b[2];
|
|
11318
|
+
cost += dx * dx + dy * dy + dz * dz;
|
|
11319
|
+
}
|
|
11320
|
+
if (cost < bestCost) {
|
|
11321
|
+
bestCost = cost;
|
|
11322
|
+
bestOff = off;
|
|
11323
|
+
}
|
|
11324
|
+
}
|
|
11325
|
+
if (bestOff === 0) return ring;
|
|
11326
|
+
const out = [];
|
|
11327
|
+
for (let j = 0; j < n; j++) out.push(ring[(j + bestOff) % n] ?? [
|
|
11328
|
+
0,
|
|
11329
|
+
0,
|
|
11330
|
+
0
|
|
11331
|
+
]);
|
|
11332
|
+
return out;
|
|
11333
|
+
}
|
|
10915
11334
|
function loftOp(module, wires, op, extraParams) {
|
|
10916
11335
|
if (wires.length < 2) throw new Error("manifold: loft requires at least two profiles");
|
|
10917
11336
|
const sections = wires.map(profileCrossSection);
|
|
10918
|
-
const
|
|
10919
|
-
|
|
10920
|
-
|
|
10921
|
-
|
|
10922
|
-
}
|
|
11337
|
+
const target = sections.reduce((mx, s) => Math.max(mx, s.outline.length), 0);
|
|
11338
|
+
const rings = sections.map((s) => placeRing({
|
|
11339
|
+
...s,
|
|
11340
|
+
outline: resampleClosed(s.outline, target)
|
|
11341
|
+
}, sectionFrame(s)));
|
|
11342
|
+
for (let i = 1; i < rings.length; i++) rings[i] = alignRing(rings[i] ?? [], rings[i - 1] ?? []);
|
|
11343
|
+
return wrap(skinRings(module, rings), makeNode(op, {
|
|
10923
11344
|
sections: sections.map(serializeSection),
|
|
10924
11345
|
...extraParams
|
|
10925
11346
|
}, wires.map((w) => nodeOf(asShape$1(w)))));
|
|
@@ -11067,7 +11488,7 @@ function makeSweepOps(module) {
|
|
|
11067
11488
|
endFactor
|
|
11068
11489
|
}),
|
|
11069
11490
|
loftBatch: () => notImplemented("loftBatch"),
|
|
11070
|
-
extrudeBatch: () =>
|
|
11491
|
+
extrudeBatch: (entries) => entries.map((e) => extrudeOp(module, e.face, e.direction, e.length))
|
|
11071
11492
|
};
|
|
11072
11493
|
}
|
|
11073
11494
|
//#endregion
|
|
@@ -11203,10 +11624,55 @@ function chamferDistAngle(module, shape, edges, distance, angleDeg) {
|
|
|
11203
11624
|
selection
|
|
11204
11625
|
}, [nodeOf(input)]));
|
|
11205
11626
|
}
|
|
11627
|
+
/**
|
|
11628
|
+
* Hollow an extrude-origin solid with an open top — the gridfinity bin-body case
|
|
11629
|
+
* (and what `approxShellMesh` cannot do: manifold-3d exposes no Minkowski inward
|
|
11630
|
+
* offset, so the generic shell no-ops and leaves the body solid). Reconstruct the
|
|
11631
|
+
* cavity from the extrude op-node's recorded outline: offset it inward by
|
|
11632
|
+
* `thickness` (Clipper2 2D), extrude full height so it punches through the top
|
|
11633
|
+
* (open), lifted by `thickness` along the extrude dir so a floor remains, then
|
|
11634
|
+
* subtract. Returns undefined for non-extrude solids (caller falls back).
|
|
11635
|
+
*/
|
|
11636
|
+
function extrudeOpenTopShell(module, input, thickness) {
|
|
11637
|
+
const node = input.node;
|
|
11638
|
+
if (node?.op !== "extrude") return void 0;
|
|
11639
|
+
const p = node.params ?? {};
|
|
11640
|
+
const outline = p["outline"];
|
|
11641
|
+
const origin = p["origin"];
|
|
11642
|
+
const dir = p["direction"];
|
|
11643
|
+
const length = p["length"];
|
|
11644
|
+
if (!outline || outline.length < 3 || !origin || !dir || typeof length !== "number") return;
|
|
11645
|
+
const t = Math.abs(thickness);
|
|
11646
|
+
try {
|
|
11647
|
+
const inner = new module.CrossSection([outline.map((q) => [q[0], q[1]])]).offset(-t);
|
|
11648
|
+
if (typeof inner.isEmpty === "function" && inner.isEmpty()) return void 0;
|
|
11649
|
+
const cavity = module.Manifold.extrude(inner, length);
|
|
11650
|
+
const dlen = Math.hypot(dir[0], dir[1], dir[2]) || 1;
|
|
11651
|
+
const alignedZ = Math.abs(dir[0]) < 1e-9 && Math.abs(dir[1]) < 1e-9 && dir[2] > 0;
|
|
11652
|
+
let placed = cavity;
|
|
11653
|
+
if (!alignedZ) {
|
|
11654
|
+
const pitch = Math.atan2(Math.hypot(dir[0], dir[1]), dir[2]) * (180 / Math.PI);
|
|
11655
|
+
const yaw = Math.atan2(dir[1], dir[0]) * (180 / Math.PI);
|
|
11656
|
+
placed = placed.rotate([
|
|
11657
|
+
0,
|
|
11658
|
+
pitch,
|
|
11659
|
+
yaw
|
|
11660
|
+
]);
|
|
11661
|
+
}
|
|
11662
|
+
placed = placed.translate([
|
|
11663
|
+
origin[0] + dir[0] / dlen * t,
|
|
11664
|
+
origin[1] + dir[1] / dlen * t,
|
|
11665
|
+
origin[2] + dir[2] / dlen * t
|
|
11666
|
+
]);
|
|
11667
|
+
return orientPositive(module, unwrap(input).subtract(placed));
|
|
11668
|
+
} catch {
|
|
11669
|
+
return;
|
|
11670
|
+
}
|
|
11671
|
+
}
|
|
11206
11672
|
function shell(module, shape, faces, thickness, tolerance) {
|
|
11207
11673
|
const input = asShape(shape);
|
|
11208
11674
|
const selection = describeSelection(faces);
|
|
11209
|
-
return wrap(approxShellMesh(module, unwrap(input), thickness, false), makeNode("shell", tolerance === void 0 ? {
|
|
11675
|
+
return wrap(extrudeOpenTopShell(module, input, thickness) ?? approxShellMesh(module, unwrap(input), thickness, false), makeNode("shell", tolerance === void 0 ? {
|
|
11210
11676
|
thickness,
|
|
11211
11677
|
selection
|
|
11212
11678
|
} : {
|
|
@@ -11651,6 +12117,53 @@ var HANDLERS = {
|
|
|
11651
12117
|
if (typeof t.gridPattern !== "function") throw new Error("manifold replay: target kernel lacks gridPattern");
|
|
11652
12118
|
return t.gridPattern(input0(inputs), asVec3(p["directionX"]), asVec3(p["directionY"]), num(p["spacingX"]), num(p["spacingY"]), num(p["countX"], 1), num(p["countY"], 1));
|
|
11653
12119
|
},
|
|
12120
|
+
profileEdge: (t, p) => {
|
|
12121
|
+
const pts = p["pts"] ?? [];
|
|
12122
|
+
const a = pts[0] ?? [
|
|
12123
|
+
0,
|
|
12124
|
+
0,
|
|
12125
|
+
0
|
|
12126
|
+
];
|
|
12127
|
+
const b = pts.length > 1 ? pts[pts.length - 1] ?? a : [
|
|
12128
|
+
a[0] + .001,
|
|
12129
|
+
a[1],
|
|
12130
|
+
a[2]
|
|
12131
|
+
];
|
|
12132
|
+
return t.makeLineEdge([
|
|
12133
|
+
a[0],
|
|
12134
|
+
a[1],
|
|
12135
|
+
a[2]
|
|
12136
|
+
], [
|
|
12137
|
+
b[0],
|
|
12138
|
+
b[1],
|
|
12139
|
+
b[2]
|
|
12140
|
+
]);
|
|
12141
|
+
},
|
|
12142
|
+
profileWire: (t, p) => {
|
|
12143
|
+
const ring = p["ring"] ?? [];
|
|
12144
|
+
const edges = [];
|
|
12145
|
+
for (let i = 0; i < ring.length; i++) {
|
|
12146
|
+
const a = ring[i] ?? [
|
|
12147
|
+
0,
|
|
12148
|
+
0,
|
|
12149
|
+
0
|
|
12150
|
+
];
|
|
12151
|
+
const b = ring[(i + 1) % ring.length] ?? a;
|
|
12152
|
+
edges.push(t.makeLineEdge([
|
|
12153
|
+
a[0],
|
|
12154
|
+
a[1],
|
|
12155
|
+
a[2]
|
|
12156
|
+
], [
|
|
12157
|
+
b[0],
|
|
12158
|
+
b[1],
|
|
12159
|
+
b[2]
|
|
12160
|
+
]));
|
|
12161
|
+
}
|
|
12162
|
+
const wire = t.makeWire(edges);
|
|
12163
|
+
for (const e of edges) t.dispose(e);
|
|
12164
|
+
return wire;
|
|
12165
|
+
},
|
|
12166
|
+
profileFace: (t, p) => faceFromOutline(t, p),
|
|
11654
12167
|
extrude: (t, p) => {
|
|
11655
12168
|
const face = faceFromOutline(t, p);
|
|
11656
12169
|
return t.extrude(face, asVec3(p["direction"], [
|
|
@@ -11830,19 +12343,74 @@ function replay(node, targetKernel, cache = /* @__PURE__ */ new Map()) {
|
|
|
11830
12343
|
function solidOf(shape) {
|
|
11831
12344
|
return unwrap(shape);
|
|
11832
12345
|
}
|
|
11833
|
-
|
|
11834
|
-
|
|
11835
|
-
|
|
11836
|
-
|
|
11837
|
-
|
|
11838
|
-
|
|
11839
|
-
|
|
11840
|
-
|
|
11841
|
-
|
|
11842
|
-
|
|
11843
|
-
|
|
11844
|
-
|
|
11845
|
-
|
|
12346
|
+
/** World points recorded on a profile placeholder node (edge/wire/face/vertex). */
|
|
12347
|
+
function profileWorldPoints(shape) {
|
|
12348
|
+
const p = (shape?.node)?.params;
|
|
12349
|
+
if (!p) return void 0;
|
|
12350
|
+
const pts = p["pts"] ?? p["ring"];
|
|
12351
|
+
if (pts && pts.length) return pts;
|
|
12352
|
+
const outline = p["outline"];
|
|
12353
|
+
if (outline && outline.length) {
|
|
12354
|
+
const o = p["origin"] ?? [
|
|
12355
|
+
0,
|
|
12356
|
+
0,
|
|
12357
|
+
0
|
|
12358
|
+
];
|
|
12359
|
+
const x = p["xAxis"] ?? [
|
|
12360
|
+
1,
|
|
12361
|
+
0,
|
|
12362
|
+
0
|
|
12363
|
+
];
|
|
12364
|
+
const y = p["yAxis"] ?? [
|
|
12365
|
+
0,
|
|
12366
|
+
1,
|
|
12367
|
+
0
|
|
12368
|
+
];
|
|
12369
|
+
return outline.map((q) => [
|
|
12370
|
+
o[0] + x[0] * q[0] + y[0] * q[1],
|
|
12371
|
+
o[1] + x[1] * q[0] + y[1] * q[1],
|
|
12372
|
+
o[2] + x[2] * q[0] + y[2] * q[1]
|
|
12373
|
+
]);
|
|
12374
|
+
}
|
|
12375
|
+
}
|
|
12376
|
+
function aabbOfPoints(pts) {
|
|
12377
|
+
const min = [
|
|
12378
|
+
Infinity,
|
|
12379
|
+
Infinity,
|
|
12380
|
+
Infinity
|
|
12381
|
+
];
|
|
12382
|
+
const max = [
|
|
12383
|
+
-Infinity,
|
|
12384
|
+
-Infinity,
|
|
12385
|
+
-Infinity
|
|
12386
|
+
];
|
|
12387
|
+
for (const q of pts) for (let i = 0; i < 3; i++) {
|
|
12388
|
+
const v = q[i] ?? 0;
|
|
12389
|
+
if (v < (min[i] ?? Infinity)) min[i] = v;
|
|
12390
|
+
if (v > (max[i] ?? -Infinity)) max[i] = v;
|
|
12391
|
+
}
|
|
12392
|
+
return {
|
|
12393
|
+
min,
|
|
12394
|
+
max
|
|
12395
|
+
};
|
|
12396
|
+
}
|
|
12397
|
+
function boxOf(shape) {
|
|
12398
|
+
const w = shape;
|
|
12399
|
+
if (w && w.__manifoldSub && w.box) return w.box;
|
|
12400
|
+
const pts = profileWorldPoints(shape);
|
|
12401
|
+
if (pts) return aabbOfPoints(pts);
|
|
12402
|
+
return solidOf(shape).boundingBox();
|
|
12403
|
+
}
|
|
12404
|
+
function meshOf$2(shape) {
|
|
12405
|
+
return solidOf(shape)?.getMesh?.();
|
|
12406
|
+
}
|
|
12407
|
+
function vertexAt$2(mesh, i) {
|
|
12408
|
+
const base = i * mesh.numProp;
|
|
12409
|
+
return [
|
|
12410
|
+
mesh.vertProperties[base] ?? 0,
|
|
12411
|
+
mesh.vertProperties[base + 1] ?? 0,
|
|
12412
|
+
mesh.vertProperties[base + 2] ?? 0
|
|
12413
|
+
];
|
|
11846
12414
|
}
|
|
11847
12415
|
function triangleAt$1(mesh, t) {
|
|
11848
12416
|
const base = t * 3;
|
|
@@ -11970,9 +12538,16 @@ function volume(shape) {
|
|
|
11970
12538
|
return solidOf(shape).volume();
|
|
11971
12539
|
}
|
|
11972
12540
|
function area(shape) {
|
|
12541
|
+
const w = shape;
|
|
12542
|
+
if (w && w.__nativeFace && typeof w.area === "number") return w.area;
|
|
11973
12543
|
return solidOf(shape).surfaceArea();
|
|
11974
12544
|
}
|
|
11975
12545
|
function boundingBox(shape) {
|
|
12546
|
+
const w = shape;
|
|
12547
|
+
if (w && w.__manifoldSub && w.box) return {
|
|
12548
|
+
min: [...w.box.min],
|
|
12549
|
+
max: [...w.box.max]
|
|
12550
|
+
};
|
|
11976
12551
|
const bb = boxOf(shape);
|
|
11977
12552
|
return {
|
|
11978
12553
|
min: [...bb.min],
|
|
@@ -12043,7 +12618,11 @@ function makeMeasureOps(_module) {
|
|
|
12043
12618
|
return {
|
|
12044
12619
|
volume: (shape) => volume(shape),
|
|
12045
12620
|
area: (shape) => area(shape),
|
|
12046
|
-
length: () =>
|
|
12621
|
+
length: (shape) => {
|
|
12622
|
+
const e = shape;
|
|
12623
|
+
if (e && e.__nativeEdge && typeof e.length === "number") return e.length;
|
|
12624
|
+
return notImplemented("length");
|
|
12625
|
+
},
|
|
12047
12626
|
centerOfMass: (shape) => centerOfMass(shape),
|
|
12048
12627
|
linearCenterOfMass: (shape) => centerOfMass(shape),
|
|
12049
12628
|
boundingBox: (shape) => boundingBox(shape),
|
|
@@ -12058,6 +12637,459 @@ function makeMeasureOps(_module) {
|
|
|
12058
12637
|
};
|
|
12059
12638
|
}
|
|
12060
12639
|
//#endregion
|
|
12640
|
+
//#region src/kernel/manifold/nativeFaces.ts
|
|
12641
|
+
/** runOriginalID for a triangle index, via the runIndex run boundaries. */
|
|
12642
|
+
function originOfTri(mesh, triIndex) {
|
|
12643
|
+
const { runIndex, runOriginalID } = mesh;
|
|
12644
|
+
if (!runIndex || !runOriginalID) return 0;
|
|
12645
|
+
const vertPos = triIndex * 3;
|
|
12646
|
+
for (let r = 0; r < runOriginalID.length; r++) {
|
|
12647
|
+
const start = runIndex[r] ?? 0;
|
|
12648
|
+
const end = runIndex[r + 1] ?? Number.MAX_SAFE_INTEGER;
|
|
12649
|
+
if (vertPos >= start && vertPos < end) return runOriginalID[r] ?? 0;
|
|
12650
|
+
}
|
|
12651
|
+
return 0;
|
|
12652
|
+
}
|
|
12653
|
+
/**
|
|
12654
|
+
* Extract planar faces from a manifold solid by grouping triangles on `faceID`.
|
|
12655
|
+
* Returns one {@link NativeFace} per group with normal/center/area/bbox/origin.
|
|
12656
|
+
*/
|
|
12657
|
+
function extractFaces(meshUnknown) {
|
|
12658
|
+
const mesh = meshUnknown;
|
|
12659
|
+
const tv = mesh.triVerts;
|
|
12660
|
+
const vp = mesh.vertProperties;
|
|
12661
|
+
const stride = mesh.numProp || 3;
|
|
12662
|
+
const faceID = mesh.faceID;
|
|
12663
|
+
const triCount = tv.length / 3;
|
|
12664
|
+
const pos = (vi) => {
|
|
12665
|
+
const o = vi * stride;
|
|
12666
|
+
return [
|
|
12667
|
+
vp[o] ?? 0,
|
|
12668
|
+
vp[o + 1] ?? 0,
|
|
12669
|
+
vp[o + 2] ?? 0
|
|
12670
|
+
];
|
|
12671
|
+
};
|
|
12672
|
+
const groups = /* @__PURE__ */ new Map();
|
|
12673
|
+
for (let t = 0; t < triCount; t++) {
|
|
12674
|
+
const id = faceID ? faceID[t] ?? t : t;
|
|
12675
|
+
let g = groups.get(id);
|
|
12676
|
+
if (!g) {
|
|
12677
|
+
g = [];
|
|
12678
|
+
groups.set(id, g);
|
|
12679
|
+
}
|
|
12680
|
+
g.push(t);
|
|
12681
|
+
}
|
|
12682
|
+
const faces = [];
|
|
12683
|
+
for (const [faceId, tris] of groups) {
|
|
12684
|
+
let nx = 0;
|
|
12685
|
+
let ny = 0;
|
|
12686
|
+
let nz = 0;
|
|
12687
|
+
let cx = 0;
|
|
12688
|
+
let cy = 0;
|
|
12689
|
+
let cz = 0;
|
|
12690
|
+
let area = 0;
|
|
12691
|
+
let minX = Infinity;
|
|
12692
|
+
let minY = Infinity;
|
|
12693
|
+
let minZ = Infinity;
|
|
12694
|
+
let maxX = -Infinity;
|
|
12695
|
+
let maxY = -Infinity;
|
|
12696
|
+
let maxZ = -Infinity;
|
|
12697
|
+
const triData = new Float32Array(tris.length * 9);
|
|
12698
|
+
let w = 0;
|
|
12699
|
+
for (const t of tris) {
|
|
12700
|
+
const a = pos(tv[t * 3] ?? 0);
|
|
12701
|
+
const b = pos(tv[t * 3 + 1] ?? 0);
|
|
12702
|
+
const c = pos(tv[t * 3 + 2] ?? 0);
|
|
12703
|
+
const ux = b[0] - a[0];
|
|
12704
|
+
const uy = b[1] - a[1];
|
|
12705
|
+
const uz = b[2] - a[2];
|
|
12706
|
+
const vx = c[0] - a[0];
|
|
12707
|
+
const vy = c[1] - a[1];
|
|
12708
|
+
const vz = c[2] - a[2];
|
|
12709
|
+
const px = uy * vz - uz * vy;
|
|
12710
|
+
const py = uz * vx - ux * vz;
|
|
12711
|
+
const pz = ux * vy - uy * vx;
|
|
12712
|
+
nx += px;
|
|
12713
|
+
ny += py;
|
|
12714
|
+
nz += pz;
|
|
12715
|
+
const triArea = .5 * Math.hypot(px, py, pz);
|
|
12716
|
+
area += triArea;
|
|
12717
|
+
const tcx = (a[0] + b[0] + c[0]) / 3;
|
|
12718
|
+
const tcy = (a[1] + b[1] + c[1]) / 3;
|
|
12719
|
+
const tcz = (a[2] + b[2] + c[2]) / 3;
|
|
12720
|
+
cx += triArea * tcx;
|
|
12721
|
+
cy += triArea * tcy;
|
|
12722
|
+
cz += triArea * tcz;
|
|
12723
|
+
for (const p of [
|
|
12724
|
+
a,
|
|
12725
|
+
b,
|
|
12726
|
+
c
|
|
12727
|
+
]) {
|
|
12728
|
+
if (p[0] < minX) minX = p[0];
|
|
12729
|
+
if (p[1] < minY) minY = p[1];
|
|
12730
|
+
if (p[2] < minZ) minZ = p[2];
|
|
12731
|
+
if (p[0] > maxX) maxX = p[0];
|
|
12732
|
+
if (p[1] > maxY) maxY = p[1];
|
|
12733
|
+
if (p[2] > maxZ) maxZ = p[2];
|
|
12734
|
+
triData[w++] = p[0];
|
|
12735
|
+
triData[w++] = p[1];
|
|
12736
|
+
triData[w++] = p[2];
|
|
12737
|
+
}
|
|
12738
|
+
}
|
|
12739
|
+
const nlen = Math.hypot(nx, ny, nz) || 1;
|
|
12740
|
+
const normal = [
|
|
12741
|
+
nx / nlen,
|
|
12742
|
+
ny / nlen,
|
|
12743
|
+
nz / nlen
|
|
12744
|
+
];
|
|
12745
|
+
const center = area > 0 ? [
|
|
12746
|
+
cx / area,
|
|
12747
|
+
cy / area,
|
|
12748
|
+
cz / area
|
|
12749
|
+
] : [
|
|
12750
|
+
0,
|
|
12751
|
+
0,
|
|
12752
|
+
0
|
|
12753
|
+
];
|
|
12754
|
+
faces.push({
|
|
12755
|
+
__nativeFace: true,
|
|
12756
|
+
faceId,
|
|
12757
|
+
originId: originOfTri(mesh, tris[0] ?? 0),
|
|
12758
|
+
normal,
|
|
12759
|
+
center,
|
|
12760
|
+
area,
|
|
12761
|
+
min: [
|
|
12762
|
+
minX,
|
|
12763
|
+
minY,
|
|
12764
|
+
minZ
|
|
12765
|
+
],
|
|
12766
|
+
max: [
|
|
12767
|
+
maxX,
|
|
12768
|
+
maxY,
|
|
12769
|
+
maxZ
|
|
12770
|
+
],
|
|
12771
|
+
tris: triData
|
|
12772
|
+
});
|
|
12773
|
+
}
|
|
12774
|
+
return faces;
|
|
12775
|
+
}
|
|
12776
|
+
function isNativeFace(shape) {
|
|
12777
|
+
return !!shape && typeof shape === "object" && shape.__nativeFace === true;
|
|
12778
|
+
}
|
|
12779
|
+
//#endregion
|
|
12780
|
+
//#region src/kernel/manifold/nativeEdges.ts
|
|
12781
|
+
var CREASE_COS = Math.cos(45 * Math.PI / 180);
|
|
12782
|
+
var edgeKey = (a, b) => a < b ? a * 1e9 + b : b * 1e9 + a;
|
|
12783
|
+
var pairKey = (a, b) => a < b ? `${a},${b}` : `${b},${a}`;
|
|
12784
|
+
/**
|
|
12785
|
+
* Extract feature edges (face-pair boundaries) from a manifold solid's mesh.
|
|
12786
|
+
*/
|
|
12787
|
+
function extractEdges(meshUnknown) {
|
|
12788
|
+
const mesh = meshUnknown;
|
|
12789
|
+
const tv = mesh.triVerts;
|
|
12790
|
+
const vp = mesh.vertProperties;
|
|
12791
|
+
const stride = mesh.numProp || 3;
|
|
12792
|
+
const faceID = mesh.faceID;
|
|
12793
|
+
const triCount = tv.length / 3;
|
|
12794
|
+
if (!faceID) return [];
|
|
12795
|
+
const pos = (vi) => {
|
|
12796
|
+
const o = vi * stride;
|
|
12797
|
+
return [
|
|
12798
|
+
vp[o] ?? 0,
|
|
12799
|
+
vp[o + 1] ?? 0,
|
|
12800
|
+
vp[o + 2] ?? 0
|
|
12801
|
+
];
|
|
12802
|
+
};
|
|
12803
|
+
const triNormal = (t) => {
|
|
12804
|
+
const a = pos(tv[t * 3] ?? 0);
|
|
12805
|
+
const b = pos(tv[t * 3 + 1] ?? 0);
|
|
12806
|
+
const c = pos(tv[t * 3 + 2] ?? 0);
|
|
12807
|
+
const ux = b[0] - a[0];
|
|
12808
|
+
const uy = b[1] - a[1];
|
|
12809
|
+
const uz = b[2] - a[2];
|
|
12810
|
+
const vx = c[0] - a[0];
|
|
12811
|
+
const vy = c[1] - a[1];
|
|
12812
|
+
const vz = c[2] - a[2];
|
|
12813
|
+
const nx = uy * vz - uz * vy;
|
|
12814
|
+
const ny = uz * vx - ux * vz;
|
|
12815
|
+
const nz = ux * vy - uy * vx;
|
|
12816
|
+
const l = Math.hypot(nx, ny, nz) || 1;
|
|
12817
|
+
return [
|
|
12818
|
+
nx / l,
|
|
12819
|
+
ny / l,
|
|
12820
|
+
nz / l
|
|
12821
|
+
];
|
|
12822
|
+
};
|
|
12823
|
+
const edgeFaces = /* @__PURE__ */ new Map();
|
|
12824
|
+
for (let t = 0; t < triCount; t++) {
|
|
12825
|
+
const a = tv[t * 3] ?? 0;
|
|
12826
|
+
const b = tv[t * 3 + 1] ?? 0;
|
|
12827
|
+
const c = tv[t * 3 + 2] ?? 0;
|
|
12828
|
+
const fid = faceID[t] ?? t;
|
|
12829
|
+
const n = triNormal(t);
|
|
12830
|
+
for (const [u, w] of [
|
|
12831
|
+
[a, b],
|
|
12832
|
+
[b, c],
|
|
12833
|
+
[c, a]
|
|
12834
|
+
]) {
|
|
12835
|
+
const k = edgeKey(u, w);
|
|
12836
|
+
let e = edgeFaces.get(k);
|
|
12837
|
+
if (!e) {
|
|
12838
|
+
e = {
|
|
12839
|
+
v: [u, w],
|
|
12840
|
+
faces: [],
|
|
12841
|
+
nrm: []
|
|
12842
|
+
};
|
|
12843
|
+
edgeFaces.set(k, e);
|
|
12844
|
+
}
|
|
12845
|
+
e.faces.push(fid);
|
|
12846
|
+
e.nrm.push(n);
|
|
12847
|
+
}
|
|
12848
|
+
}
|
|
12849
|
+
const groups = /* @__PURE__ */ new Map();
|
|
12850
|
+
for (const { v, faces, nrm } of edgeFaces.values()) {
|
|
12851
|
+
if (faces.length !== 2) continue;
|
|
12852
|
+
const [f0, f1] = faces;
|
|
12853
|
+
if (f0 === f1) continue;
|
|
12854
|
+
const [n0, n1] = nrm;
|
|
12855
|
+
if (n0[0] * n1[0] + n0[1] * n1[1] + n0[2] * n1[2] > CREASE_COS) continue;
|
|
12856
|
+
const key = pairKey(f0, f1);
|
|
12857
|
+
let g = groups.get(key);
|
|
12858
|
+
if (!g) {
|
|
12859
|
+
g = {
|
|
12860
|
+
faces: f0 < f1 ? [f0, f1] : [f1, f0],
|
|
12861
|
+
segs: []
|
|
12862
|
+
};
|
|
12863
|
+
groups.set(key, g);
|
|
12864
|
+
}
|
|
12865
|
+
g.segs.push(v);
|
|
12866
|
+
}
|
|
12867
|
+
const edges = [];
|
|
12868
|
+
for (const { faces, segs } of groups.values()) for (const chain of chainSegments(segs)) edges.push(buildEdge(faces, chain, pos));
|
|
12869
|
+
return edges;
|
|
12870
|
+
}
|
|
12871
|
+
/** Order a bag of undirected vertex-pair segments into one or more vertex chains. */
|
|
12872
|
+
function chainSegments(segs) {
|
|
12873
|
+
const adj = /* @__PURE__ */ new Map();
|
|
12874
|
+
const used = /* @__PURE__ */ new Set();
|
|
12875
|
+
const addAdj = (v, i) => {
|
|
12876
|
+
let list = adj.get(v);
|
|
12877
|
+
if (!list) {
|
|
12878
|
+
list = [];
|
|
12879
|
+
adj.set(v, list);
|
|
12880
|
+
}
|
|
12881
|
+
list.push(i);
|
|
12882
|
+
};
|
|
12883
|
+
segs.forEach(([a, b], i) => {
|
|
12884
|
+
addAdj(a, i);
|
|
12885
|
+
addAdj(b, i);
|
|
12886
|
+
});
|
|
12887
|
+
const otherEnd = (i, v) => {
|
|
12888
|
+
const s = segs[i] ?? [v, v];
|
|
12889
|
+
return s[0] === v ? s[1] : s[0];
|
|
12890
|
+
};
|
|
12891
|
+
const chains = [];
|
|
12892
|
+
for (let start = 0; start < segs.length; start++) {
|
|
12893
|
+
if (used.has(start)) continue;
|
|
12894
|
+
used.add(start);
|
|
12895
|
+
const s = segs[start] ?? [0, 0];
|
|
12896
|
+
const chain = [s[0], s[1]];
|
|
12897
|
+
for (let guard = 0; guard < segs.length; guard++) {
|
|
12898
|
+
const tail = chain[chain.length - 1] ?? 0;
|
|
12899
|
+
const next = (adj.get(tail) ?? []).find((i) => !used.has(i));
|
|
12900
|
+
if (next === void 0) break;
|
|
12901
|
+
used.add(next);
|
|
12902
|
+
chain.push(otherEnd(next, tail));
|
|
12903
|
+
}
|
|
12904
|
+
for (let guard = 0; guard < segs.length; guard++) {
|
|
12905
|
+
const head = chain[0] ?? 0;
|
|
12906
|
+
const prev = (adj.get(head) ?? []).find((i) => !used.has(i));
|
|
12907
|
+
if (prev === void 0) break;
|
|
12908
|
+
used.add(prev);
|
|
12909
|
+
chain.unshift(otherEnd(prev, head));
|
|
12910
|
+
}
|
|
12911
|
+
chains.push(chain);
|
|
12912
|
+
}
|
|
12913
|
+
return chains;
|
|
12914
|
+
}
|
|
12915
|
+
function buildEdge(faces, chain, pos) {
|
|
12916
|
+
const n = chain.length;
|
|
12917
|
+
const pts = new Float32Array(n * 3);
|
|
12918
|
+
const arc = new Float32Array(n);
|
|
12919
|
+
let minX = Infinity;
|
|
12920
|
+
let minY = Infinity;
|
|
12921
|
+
let minZ = Infinity;
|
|
12922
|
+
let maxX = -Infinity;
|
|
12923
|
+
let maxY = -Infinity;
|
|
12924
|
+
let maxZ = -Infinity;
|
|
12925
|
+
let len = 0;
|
|
12926
|
+
let prev = null;
|
|
12927
|
+
for (let i = 0; i < n; i++) {
|
|
12928
|
+
const p = pos(chain[i] ?? 0);
|
|
12929
|
+
pts[i * 3] = p[0];
|
|
12930
|
+
pts[i * 3 + 1] = p[1];
|
|
12931
|
+
pts[i * 3 + 2] = p[2];
|
|
12932
|
+
if (prev) len += Math.hypot(p[0] - prev[0], p[1] - prev[1], p[2] - prev[2]);
|
|
12933
|
+
arc[i] = len;
|
|
12934
|
+
prev = p;
|
|
12935
|
+
if (p[0] < minX) minX = p[0];
|
|
12936
|
+
if (p[1] < minY) minY = p[1];
|
|
12937
|
+
if (p[2] < minZ) minZ = p[2];
|
|
12938
|
+
if (p[0] > maxX) maxX = p[0];
|
|
12939
|
+
if (p[1] > maxY) maxY = p[1];
|
|
12940
|
+
if (p[2] > maxZ) maxZ = p[2];
|
|
12941
|
+
}
|
|
12942
|
+
return {
|
|
12943
|
+
__nativeEdge: true,
|
|
12944
|
+
faces,
|
|
12945
|
+
pts,
|
|
12946
|
+
arc,
|
|
12947
|
+
length: len,
|
|
12948
|
+
min: [
|
|
12949
|
+
minX,
|
|
12950
|
+
minY,
|
|
12951
|
+
minZ
|
|
12952
|
+
],
|
|
12953
|
+
max: [
|
|
12954
|
+
maxX,
|
|
12955
|
+
maxY,
|
|
12956
|
+
maxZ
|
|
12957
|
+
],
|
|
12958
|
+
curveType: isStraight(pts) ? "LINE" : "CIRCLE"
|
|
12959
|
+
};
|
|
12960
|
+
}
|
|
12961
|
+
/** Straight if every interior point lies on the chord within a small tolerance. */
|
|
12962
|
+
function isStraight(pts) {
|
|
12963
|
+
const n = pts.length / 3;
|
|
12964
|
+
if (n <= 2) return true;
|
|
12965
|
+
const ax = pts[0] ?? 0;
|
|
12966
|
+
const ay = pts[1] ?? 0;
|
|
12967
|
+
const az = pts[2] ?? 0;
|
|
12968
|
+
const bx = pts[(n - 1) * 3] ?? 0;
|
|
12969
|
+
const by = pts[(n - 1) * 3 + 1] ?? 0;
|
|
12970
|
+
const bz = pts[(n - 1) * 3 + 2] ?? 0;
|
|
12971
|
+
let dx = bx - ax;
|
|
12972
|
+
let dy = by - ay;
|
|
12973
|
+
let dz = bz - az;
|
|
12974
|
+
const dl = Math.hypot(dx, dy, dz) || 1;
|
|
12975
|
+
dx /= dl;
|
|
12976
|
+
dy /= dl;
|
|
12977
|
+
dz /= dl;
|
|
12978
|
+
for (let i = 1; i < n - 1; i++) {
|
|
12979
|
+
const px = (pts[i * 3] ?? 0) - ax;
|
|
12980
|
+
const py = (pts[i * 3 + 1] ?? 0) - ay;
|
|
12981
|
+
const pz = (pts[i * 3 + 2] ?? 0) - az;
|
|
12982
|
+
const t = px * dx + py * dy + pz * dz;
|
|
12983
|
+
const ex = px - t * dx;
|
|
12984
|
+
const ey = py - t * dy;
|
|
12985
|
+
const ez = pz - t * dz;
|
|
12986
|
+
if (Math.hypot(ex, ey, ez) > 1e-6 * Math.max(1, dl)) return false;
|
|
12987
|
+
}
|
|
12988
|
+
return true;
|
|
12989
|
+
}
|
|
12990
|
+
/**
|
|
12991
|
+
* Extract B-rep vertices: mesh vertices where three or more distinct faces
|
|
12992
|
+
* (faceID groups) meet — i.e. the corners where edges terminate. A box yields
|
|
12993
|
+
* its 8 corners; interior/edge-midpoint vertices (1–2 faces) are excluded.
|
|
12994
|
+
*/
|
|
12995
|
+
function extractVertices(meshUnknown) {
|
|
12996
|
+
const mesh = meshUnknown;
|
|
12997
|
+
const tv = mesh.triVerts;
|
|
12998
|
+
const vp = mesh.vertProperties;
|
|
12999
|
+
const stride = mesh.numProp || 3;
|
|
13000
|
+
const faceID = mesh.faceID;
|
|
13001
|
+
if (!faceID) return [];
|
|
13002
|
+
const triCount = tv.length / 3;
|
|
13003
|
+
const facesAtVert = /* @__PURE__ */ new Map();
|
|
13004
|
+
for (let t = 0; t < triCount; t++) {
|
|
13005
|
+
const fid = faceID[t] ?? t;
|
|
13006
|
+
for (let j = 0; j < 3; j++) {
|
|
13007
|
+
const v = tv[t * 3 + j] ?? 0;
|
|
13008
|
+
let s = facesAtVert.get(v);
|
|
13009
|
+
if (!s) {
|
|
13010
|
+
s = /* @__PURE__ */ new Set();
|
|
13011
|
+
facesAtVert.set(v, s);
|
|
13012
|
+
}
|
|
13013
|
+
s.add(fid);
|
|
13014
|
+
}
|
|
13015
|
+
}
|
|
13016
|
+
const verts = [];
|
|
13017
|
+
for (const [v, faces] of facesAtVert) {
|
|
13018
|
+
if (faces.size < 3) continue;
|
|
13019
|
+
const o = v * stride;
|
|
13020
|
+
verts.push({
|
|
13021
|
+
__nativeVertex: true,
|
|
13022
|
+
point: [
|
|
13023
|
+
vp[o] ?? 0,
|
|
13024
|
+
vp[o + 1] ?? 0,
|
|
13025
|
+
vp[o + 2] ?? 0
|
|
13026
|
+
]
|
|
13027
|
+
});
|
|
13028
|
+
}
|
|
13029
|
+
return verts;
|
|
13030
|
+
}
|
|
13031
|
+
function isNativeVertex(shape) {
|
|
13032
|
+
return !!shape && typeof shape === "object" && shape.__nativeVertex === true;
|
|
13033
|
+
}
|
|
13034
|
+
function isNativeEdge(shape) {
|
|
13035
|
+
return !!shape && typeof shape === "object" && shape.__nativeEdge === true;
|
|
13036
|
+
}
|
|
13037
|
+
/** Point at arc-length `s` along the edge polyline. */
|
|
13038
|
+
function edgePointAt(edge, s) {
|
|
13039
|
+
const { pts, arc } = edge;
|
|
13040
|
+
const n = arc.length;
|
|
13041
|
+
if (n === 0) return [
|
|
13042
|
+
0,
|
|
13043
|
+
0,
|
|
13044
|
+
0
|
|
13045
|
+
];
|
|
13046
|
+
if (s <= 0) return [
|
|
13047
|
+
pts[0] ?? 0,
|
|
13048
|
+
pts[1] ?? 0,
|
|
13049
|
+
pts[2] ?? 0
|
|
13050
|
+
];
|
|
13051
|
+
if (s >= edge.length) return [
|
|
13052
|
+
pts[(n - 1) * 3] ?? 0,
|
|
13053
|
+
pts[(n - 1) * 3 + 1] ?? 0,
|
|
13054
|
+
pts[(n - 1) * 3 + 2] ?? 0
|
|
13055
|
+
];
|
|
13056
|
+
let i = 1;
|
|
13057
|
+
while (i < n && (arc[i] ?? 0) < s) i++;
|
|
13058
|
+
const a0 = arc[i - 1] ?? 0;
|
|
13059
|
+
const a1 = arc[i] ?? a0;
|
|
13060
|
+
const t = a1 > a0 ? (s - a0) / (a1 - a0) : 0;
|
|
13061
|
+
const o0 = (i - 1) * 3;
|
|
13062
|
+
const o1 = i * 3;
|
|
13063
|
+
return [
|
|
13064
|
+
(pts[o0] ?? 0) + ((pts[o1] ?? 0) - (pts[o0] ?? 0)) * t,
|
|
13065
|
+
(pts[o0 + 1] ?? 0) + ((pts[o1 + 1] ?? 0) - (pts[o0 + 1] ?? 0)) * t,
|
|
13066
|
+
(pts[o0 + 2] ?? 0) + ((pts[o1 + 2] ?? 0) - (pts[o0 + 2] ?? 0)) * t
|
|
13067
|
+
];
|
|
13068
|
+
}
|
|
13069
|
+
/** Unit tangent at arc-length `s` (direction of the containing segment). */
|
|
13070
|
+
function edgeTangentAt(edge, s) {
|
|
13071
|
+
const { pts, arc } = edge;
|
|
13072
|
+
const n = arc.length;
|
|
13073
|
+
if (n < 2) return [
|
|
13074
|
+
1,
|
|
13075
|
+
0,
|
|
13076
|
+
0
|
|
13077
|
+
];
|
|
13078
|
+
let i = 1;
|
|
13079
|
+
while (i < n - 1 && (arc[i] ?? 0) < s) i++;
|
|
13080
|
+
const o0 = (i - 1) * 3;
|
|
13081
|
+
const o1 = i * 3;
|
|
13082
|
+
const dx = (pts[o1] ?? 0) - (pts[o0] ?? 0);
|
|
13083
|
+
const dy = (pts[o1 + 1] ?? 0) - (pts[o0 + 1] ?? 0);
|
|
13084
|
+
const dz = (pts[o1 + 2] ?? 0) - (pts[o0 + 2] ?? 0);
|
|
13085
|
+
const l = Math.hypot(dx, dy, dz) || 1;
|
|
13086
|
+
return [
|
|
13087
|
+
dx / l,
|
|
13088
|
+
dy / l,
|
|
13089
|
+
dz / l
|
|
13090
|
+
];
|
|
13091
|
+
}
|
|
13092
|
+
//#endregion
|
|
12061
13093
|
//#region src/kernel/manifold/topologyOps.ts
|
|
12062
13094
|
function brepOf(shape, method) {
|
|
12063
13095
|
const ms = asManifoldShape(shape);
|
|
@@ -12076,79 +13108,116 @@ function brepOf(shape, method) {
|
|
|
12076
13108
|
brep
|
|
12077
13109
|
};
|
|
12078
13110
|
}
|
|
12079
|
-
function
|
|
12080
|
-
|
|
12081
|
-
|
|
12082
|
-
|
|
12083
|
-
|
|
12084
|
-
|
|
12085
|
-
|
|
12086
|
-
|
|
12087
|
-
|
|
12088
|
-
|
|
12089
|
-
|
|
12090
|
-
|
|
12091
|
-
|
|
12092
|
-
}
|
|
12093
|
-
|
|
12094
|
-
|
|
12095
|
-
|
|
12096
|
-
|
|
12097
|
-
|
|
12098
|
-
|
|
12099
|
-
|
|
12100
|
-
|
|
13111
|
+
function shapeType(shape) {
|
|
13112
|
+
if (asManifoldShape(shape)) return "solid";
|
|
13113
|
+
const { occt, brep } = brepOf(shape, "shapeType");
|
|
13114
|
+
return occt.shapeType(brep);
|
|
13115
|
+
}
|
|
13116
|
+
function isSame(a, b) {
|
|
13117
|
+
const sa = asManifoldShape(a);
|
|
13118
|
+
const sb = asManifoldShape(b);
|
|
13119
|
+
if (!sa || !sb) return false;
|
|
13120
|
+
return sa.manifold === sb.manifold;
|
|
13121
|
+
}
|
|
13122
|
+
function hashCode(shape, upperBound) {
|
|
13123
|
+
if (!asManifoldShape(shape)) return 0;
|
|
13124
|
+
const { occt, brep } = brepOf(shape, "hashCode");
|
|
13125
|
+
return occt.hashCode(brep, upperBound);
|
|
13126
|
+
}
|
|
13127
|
+
function isNull(shape) {
|
|
13128
|
+
const s = asManifoldShape(shape);
|
|
13129
|
+
if (!s) return true;
|
|
13130
|
+
const solid = unwrap(s);
|
|
13131
|
+
return !solid || typeof solid.isEmpty === "function" && solid.isEmpty();
|
|
13132
|
+
}
|
|
13133
|
+
function iterShapes(shape, type) {
|
|
13134
|
+
const s = asManifoldShape(shape);
|
|
13135
|
+
if (!s) return [];
|
|
13136
|
+
if (type === "solid") return [shape];
|
|
13137
|
+
if (type === "vertex") {
|
|
12101
13138
|
const solid = unwrap(s);
|
|
12102
|
-
|
|
12103
|
-
|
|
12104
|
-
function shapeOrientation(_shape) {
|
|
12105
|
-
return "forward";
|
|
12106
|
-
}
|
|
12107
|
-
function iterShapes(shape, type) {
|
|
12108
|
-
const s = asManifoldShape(shape);
|
|
12109
|
-
if (!s) return [];
|
|
12110
|
-
if (type === "solid") return [shape];
|
|
12111
|
-
if (type !== "edge" && type !== "face") return [];
|
|
12112
|
-
if (!s.node.replayable) return [];
|
|
12113
|
-
const occt = resolveOcct();
|
|
12114
|
-
if (!occt) return [];
|
|
12115
|
-
const brep = brepCache.get(s.node) ?? (() => {
|
|
12116
|
-
const b = replay(s.node, occt);
|
|
12117
|
-
brepCache.set(s.node, b);
|
|
12118
|
-
return b;
|
|
12119
|
-
})();
|
|
12120
|
-
return occt.iterShapes(brep, type).map((sub, index) => ({
|
|
13139
|
+
if (solid && typeof solid.getMesh === "function") return extractVertices(solid.getMesh()).map((v, index) => ({
|
|
13140
|
+
...v,
|
|
12121
13141
|
__manifoldSub: true,
|
|
12122
13142
|
index,
|
|
12123
|
-
box:
|
|
13143
|
+
box: {
|
|
13144
|
+
min: v.point,
|
|
13145
|
+
max: v.point
|
|
13146
|
+
},
|
|
13147
|
+
parent: s.node,
|
|
13148
|
+
subType: "vertex"
|
|
12124
13149
|
}));
|
|
13150
|
+
return [];
|
|
12125
13151
|
}
|
|
12126
|
-
|
|
12127
|
-
|
|
12128
|
-
|
|
12129
|
-
|
|
12130
|
-
|
|
12131
|
-
|
|
12132
|
-
|
|
12133
|
-
|
|
12134
|
-
|
|
13152
|
+
if (type !== "edge" && type !== "face") return [];
|
|
13153
|
+
if (type === "face") {
|
|
13154
|
+
const solid = unwrap(s);
|
|
13155
|
+
if (solid && typeof solid.getMesh === "function") return extractFaces(solid.getMesh()).map((f, index) => ({
|
|
13156
|
+
...f,
|
|
13157
|
+
__manifoldSub: true,
|
|
13158
|
+
index,
|
|
13159
|
+
box: {
|
|
13160
|
+
min: f.min,
|
|
13161
|
+
max: f.max
|
|
13162
|
+
},
|
|
13163
|
+
parent: s.node,
|
|
13164
|
+
subType: "face"
|
|
13165
|
+
}));
|
|
12135
13166
|
}
|
|
12136
|
-
|
|
12137
|
-
const
|
|
12138
|
-
return
|
|
13167
|
+
if (type === "edge") {
|
|
13168
|
+
const solid = unwrap(s);
|
|
13169
|
+
if (solid && typeof solid.getMesh === "function") return extractEdges(solid.getMesh()).map((e, index) => ({
|
|
13170
|
+
...e,
|
|
13171
|
+
__manifoldSub: true,
|
|
13172
|
+
index,
|
|
13173
|
+
box: {
|
|
13174
|
+
min: e.min,
|
|
13175
|
+
max: e.max
|
|
13176
|
+
},
|
|
13177
|
+
parent: s.node,
|
|
13178
|
+
subType: "edge"
|
|
13179
|
+
}));
|
|
12139
13180
|
}
|
|
13181
|
+
if (!s.node.replayable) return [];
|
|
13182
|
+
const occt = resolveOcct();
|
|
13183
|
+
if (!occt) return [];
|
|
13184
|
+
const brep = brepCache.get(s.node) ?? (() => {
|
|
13185
|
+
const b = replay(s.node, occt);
|
|
13186
|
+
brepCache.set(s.node, b);
|
|
13187
|
+
return b;
|
|
13188
|
+
})();
|
|
13189
|
+
return occt.iterShapes(brep, type).map((sub, index) => ({
|
|
13190
|
+
__manifoldSub: true,
|
|
13191
|
+
index,
|
|
13192
|
+
box: occt.boundingBox(sub),
|
|
13193
|
+
occt: sub,
|
|
13194
|
+
parent: s.node,
|
|
13195
|
+
subType: type
|
|
13196
|
+
}));
|
|
13197
|
+
}
|
|
13198
|
+
function edgeToFaceMap(shape) {
|
|
13199
|
+
const { occt, brep } = brepOf(shape, "edgeToFaceMap");
|
|
13200
|
+
return occt.edgeToFaceMap(brep);
|
|
13201
|
+
}
|
|
13202
|
+
function adjacentFaces(shape, face) {
|
|
13203
|
+
const { occt, brep } = brepOf(shape, "adjacentFaces");
|
|
13204
|
+
return occt.adjacentFaces(brep, face);
|
|
13205
|
+
}
|
|
13206
|
+
function makeTopologyOps(_module) {
|
|
12140
13207
|
return {
|
|
12141
13208
|
iterShapes,
|
|
12142
|
-
iterShapeList,
|
|
13209
|
+
iterShapeList: (list, callback) => {
|
|
13210
|
+
occtOrThrow("iterShapeList").iterShapeList(list, callback);
|
|
13211
|
+
},
|
|
12143
13212
|
shapeType,
|
|
12144
13213
|
isSame,
|
|
12145
|
-
isEqual,
|
|
13214
|
+
isEqual: isSame,
|
|
12146
13215
|
downcast: (shape) => shape,
|
|
12147
13216
|
hashCode,
|
|
12148
13217
|
isNull,
|
|
12149
|
-
shapeOrientation,
|
|
13218
|
+
shapeOrientation: (_shape) => "forward",
|
|
12150
13219
|
edgeToFaceMap,
|
|
12151
|
-
sharedEdges,
|
|
13220
|
+
sharedEdges: (faceA, faceB) => occtOrThrow("sharedEdges").sharedEdges(faceA, faceB),
|
|
12152
13221
|
adjacentFaces,
|
|
12153
13222
|
sew: () => {
|
|
12154
13223
|
throw new Error("manifold: sew is unsupported on the mesh kernel; use a B-rep kernel");
|
|
@@ -12698,6 +13767,12 @@ function vertexAt(mesh, index) {
|
|
|
12698
13767
|
];
|
|
12699
13768
|
}
|
|
12700
13769
|
function viaOcct(shape, query) {
|
|
13770
|
+
const witness = shape;
|
|
13771
|
+
if (witness && witness.__manifoldSub && witness.occt) {
|
|
13772
|
+
const occt = resolveOcct();
|
|
13773
|
+
if (!occt) throw new Error("manifold: sub-shape geometry query requires a registered occt kernel");
|
|
13774
|
+
return query(witness.occt, occt);
|
|
13775
|
+
}
|
|
12701
13776
|
const ms = asManifoldShape(shape);
|
|
12702
13777
|
if (!ms) throw new Error("manifold: exact geometry query requires a manifold shape handle");
|
|
12703
13778
|
const occt = resolveOcct();
|
|
@@ -12712,10 +13787,13 @@ function viaOcct(shape, query) {
|
|
|
12712
13787
|
}
|
|
12713
13788
|
function makeGeometryOps(_module) {
|
|
12714
13789
|
return {
|
|
12715
|
-
curveType: (shape) => viaOcct(shape, (s, occt) => occt.curveType(s)),
|
|
12716
|
-
curveParameters: (shape) => viaOcct(shape, (s, occt) => occt.curveParameters(s)),
|
|
12717
|
-
curvePointAtParam: (shape, param) => viaOcct(shape, (s, occt) => occt.curvePointAtParam(s, param)),
|
|
12718
|
-
curveTangent: (shape, param) =>
|
|
13790
|
+
curveType: (shape) => isNativeEdge(shape) ? shape.curveType : viaOcct(shape, (s, occt) => occt.curveType(s)),
|
|
13791
|
+
curveParameters: (shape) => isNativeEdge(shape) ? [0, shape.length] : viaOcct(shape, (s, occt) => occt.curveParameters(s)),
|
|
13792
|
+
curvePointAtParam: (shape, param) => isNativeEdge(shape) ? edgePointAt(shape, param) : viaOcct(shape, (s, occt) => occt.curvePointAtParam(s, param)),
|
|
13793
|
+
curveTangent: (shape, param) => isNativeEdge(shape) ? {
|
|
13794
|
+
point: edgePointAt(shape, param),
|
|
13795
|
+
tangent: edgeTangentAt(shape, param)
|
|
13796
|
+
} : viaOcct(shape, (s, occt) => occt.curveTangent(s, param)),
|
|
12719
13797
|
curveIsClosed: (shape) => viaOcct(shape, (s, occt) => occt.curveIsClosed(s)),
|
|
12720
13798
|
curveIsPeriodic: (shape) => viaOcct(shape, (s, occt) => occt.curveIsPeriodic(s)),
|
|
12721
13799
|
curvePeriod: (shape) => viaOcct(shape, (s, occt) => occt.curvePeriod(s)),
|
|
@@ -12729,13 +13807,24 @@ function makeGeometryOps(_module) {
|
|
|
12729
13807
|
getBezierPenultimatePole: (edge) => viaOcct(edge, (s, occt) => occt.getBezierPenultimatePole(s)),
|
|
12730
13808
|
getNurbsCurveData: (edge) => viaOcct(edge, (s, occt) => occt.getNurbsCurveData?.(s) ?? null),
|
|
12731
13809
|
vertexPosition: (vertex) => {
|
|
13810
|
+
if (isNativeVertex(vertex)) return vertex.point;
|
|
12732
13811
|
if (!asManifoldShape(vertex)) return viaOcct(vertex, (s, occt) => occt.vertexPosition(s));
|
|
12733
13812
|
return vertexAt(meshOf(vertex), 0);
|
|
12734
13813
|
},
|
|
12735
|
-
surfaceType: (face) =>
|
|
12736
|
-
|
|
13814
|
+
surfaceType: (face) => {
|
|
13815
|
+
if (isNativeFace(face)) return "plane";
|
|
13816
|
+
const ms = asManifoldShape(face);
|
|
13817
|
+
if (ms && ms.node.op === "profileFace") return "plane";
|
|
13818
|
+
return viaOcct(face, (s, occt) => occt.surfaceType(s));
|
|
13819
|
+
},
|
|
13820
|
+
uvBounds: (face) => isNativeFace(face) ? {
|
|
13821
|
+
uMin: 0,
|
|
13822
|
+
uMax: 1,
|
|
13823
|
+
vMin: 0,
|
|
13824
|
+
vMax: 1
|
|
13825
|
+
} : viaOcct(face, (s, occt) => occt.uvBounds(s)),
|
|
12737
13826
|
outerWire: (face) => viaOcct(face, (s, occt) => occt.outerWire(s)),
|
|
12738
|
-
surfaceNormal: (face, u, v) => viaOcct(face, (s, occt) => occt.surfaceNormal(s, u, v)),
|
|
13827
|
+
surfaceNormal: (face, u, v) => isNativeFace(face) ? face.normal : viaOcct(face, (s, occt) => occt.surfaceNormal(s, u, v)),
|
|
12739
13828
|
pointOnSurface: (face, u, v) => viaOcct(face, (s, occt) => occt.pointOnSurface(s, u, v)),
|
|
12740
13829
|
uvFromPoint: (face, point) => viaOcct(face, (s, occt) => occt.uvFromPoint(s, point)),
|
|
12741
13830
|
projectPointOnFace: (face, point) => viaOcct(face, (s, occt) => occt.projectPointOnFace(s, point)),
|
|
@@ -12829,6 +13918,614 @@ function makeRepairOps(_module) {
|
|
|
12829
13918
|
};
|
|
12830
13919
|
}
|
|
12831
13920
|
//#endregion
|
|
13921
|
+
//#region src/kernel/manifold/kernel2dNative.ts
|
|
13922
|
+
var CHORD_TOL = .004;
|
|
13923
|
+
function isNative(x) {
|
|
13924
|
+
return !!x && typeof x === "object" && x.__nativeC2d === true;
|
|
13925
|
+
}
|
|
13926
|
+
function line(p1, p2) {
|
|
13927
|
+
return {
|
|
13928
|
+
__nativeC2d: true,
|
|
13929
|
+
k: "line",
|
|
13930
|
+
p1,
|
|
13931
|
+
p2
|
|
13932
|
+
};
|
|
13933
|
+
}
|
|
13934
|
+
function conic(c, u, v, a0, a1) {
|
|
13935
|
+
return {
|
|
13936
|
+
__nativeC2d: true,
|
|
13937
|
+
k: "conic",
|
|
13938
|
+
c,
|
|
13939
|
+
u,
|
|
13940
|
+
v,
|
|
13941
|
+
a0,
|
|
13942
|
+
a1
|
|
13943
|
+
};
|
|
13944
|
+
}
|
|
13945
|
+
function applyPt(m, [x, y]) {
|
|
13946
|
+
return [m.a * x + m.b * y + m.tx, m.c * x + m.d * y + m.ty];
|
|
13947
|
+
}
|
|
13948
|
+
function applyVec(m, [x, y]) {
|
|
13949
|
+
return [m.a * x + m.b * y, m.c * x + m.d * y];
|
|
13950
|
+
}
|
|
13951
|
+
function compose(p, q) {
|
|
13952
|
+
return {
|
|
13953
|
+
a: p.a * q.a + p.b * q.c,
|
|
13954
|
+
b: p.a * q.b + p.b * q.d,
|
|
13955
|
+
c: p.c * q.a + p.d * q.c,
|
|
13956
|
+
d: p.c * q.b + p.d * q.d,
|
|
13957
|
+
tx: p.a * q.tx + p.b * q.ty + p.tx,
|
|
13958
|
+
ty: p.c * q.tx + p.d * q.ty + p.ty
|
|
13959
|
+
};
|
|
13960
|
+
}
|
|
13961
|
+
function transform(curve, m) {
|
|
13962
|
+
if (curve.k === "line") return line(applyPt(m, curve.p1), applyPt(m, curve.p2));
|
|
13963
|
+
if (curve.k === "bezier") return {
|
|
13964
|
+
__nativeC2d: true,
|
|
13965
|
+
k: "bezier",
|
|
13966
|
+
pts: curve.pts.map((p) => applyPt(m, p))
|
|
13967
|
+
};
|
|
13968
|
+
return conic(applyPt(m, curve.c), applyVec(m, curve.u), applyVec(m, curve.v), curve.a0, curve.a1);
|
|
13969
|
+
}
|
|
13970
|
+
function bezierAt(pts, t) {
|
|
13971
|
+
const tmp = pts.map((p) => [p[0], p[1]]);
|
|
13972
|
+
for (let k = 1; k < tmp.length; k++) for (let i = 0; i < tmp.length - k; i++) {
|
|
13973
|
+
const a = tmp[i] ?? [0, 0];
|
|
13974
|
+
const b = tmp[i + 1] ?? [0, 0];
|
|
13975
|
+
tmp[i] = [a[0] * (1 - t) + b[0] * t, a[1] * (1 - t) + b[1] * t];
|
|
13976
|
+
}
|
|
13977
|
+
return tmp[0] ?? [0, 0];
|
|
13978
|
+
}
|
|
13979
|
+
function conicPoint(c, t) {
|
|
13980
|
+
const ct = Math.cos(t);
|
|
13981
|
+
const st = Math.sin(t);
|
|
13982
|
+
return [c.c[0] + c.u[0] * ct + c.v[0] * st, c.c[1] + c.u[1] * ct + c.v[1] * st];
|
|
13983
|
+
}
|
|
13984
|
+
/** Bezier first derivative B'(t) = n·Σ(P_{i+1}−P_i)·b_{i,n−1}(t). */
|
|
13985
|
+
function bezierD1(pts, t) {
|
|
13986
|
+
const n = pts.length - 1;
|
|
13987
|
+
if (n < 1) return [0, 0];
|
|
13988
|
+
const diff = [];
|
|
13989
|
+
for (let i = 0; i < n; i++) {
|
|
13990
|
+
const a = pts[i] ?? [0, 0];
|
|
13991
|
+
const b = pts[i + 1] ?? [0, 0];
|
|
13992
|
+
diff.push([n * (b[0] - a[0]), n * (b[1] - a[1])]);
|
|
13993
|
+
}
|
|
13994
|
+
return bezierAt(diff, t);
|
|
13995
|
+
}
|
|
13996
|
+
/**
|
|
13997
|
+
* Segment count for a conic arc, driven by chord-height tolerance rather than a
|
|
13998
|
+
* fixed count: the polygon's sagitta is `ρ(1 − cos(Δθ/2))`, so to keep it under
|
|
13999
|
+
* CHORD_TOL the per-segment angle must satisfy `Δθ ≤ 2·acos(1 − tol/ρ)`. This
|
|
14000
|
+
* gives tiny gridfinity corner arcs few segments (fast) while large circles get
|
|
14001
|
+
* enough to match OCCT's exact volume (parity). `ρ` is the larger conjugate
|
|
14002
|
+
* radius (ellipse worst case).
|
|
14003
|
+
*/
|
|
14004
|
+
function conicSegments(curve) {
|
|
14005
|
+
const span = Math.abs(curve.a1 - curve.a0);
|
|
14006
|
+
const ru = Math.hypot(curve.u[0], curve.u[1]);
|
|
14007
|
+
const rv = Math.hypot(curve.v[0], curve.v[1]);
|
|
14008
|
+
const rho = Math.max(ru, rv);
|
|
14009
|
+
if (rho <= CHORD_TOL) return Math.max(2, Math.ceil(span / (2 * Math.PI) * 8));
|
|
14010
|
+
const maxAngle = 2 * Math.acos(Math.max(-1, 1 - CHORD_TOL / rho));
|
|
14011
|
+
return Math.max(2, Math.ceil(span / maxAngle));
|
|
14012
|
+
}
|
|
14013
|
+
function sample(curve) {
|
|
14014
|
+
if (curve.k === "line") return [curve.p1, curve.p2];
|
|
14015
|
+
if (curve.k === "bezier") {
|
|
14016
|
+
const out = [];
|
|
14017
|
+
for (let i = 0; i <= 24; i++) out.push(bezierAt(curve.pts, i / 24));
|
|
14018
|
+
return out;
|
|
14019
|
+
}
|
|
14020
|
+
const span = curve.a1 - curve.a0;
|
|
14021
|
+
const n = conicSegments(curve);
|
|
14022
|
+
const pts = [];
|
|
14023
|
+
for (let i = 0; i <= n; i++) {
|
|
14024
|
+
const t = curve.a0 + span * i / n;
|
|
14025
|
+
const ct = Math.cos(t);
|
|
14026
|
+
const st = Math.sin(t);
|
|
14027
|
+
pts.push([curve.c[0] + curve.u[0] * ct + curve.v[0] * st, curve.c[1] + curve.u[1] * ct + curve.v[1] * st]);
|
|
14028
|
+
}
|
|
14029
|
+
return pts;
|
|
14030
|
+
}
|
|
14031
|
+
/** Circle/arc through param helpers. */
|
|
14032
|
+
function circleThrough3(p1, pm, p2) {
|
|
14033
|
+
const ax = p1[0];
|
|
14034
|
+
const ay = p1[1];
|
|
14035
|
+
const bx = pm[0];
|
|
14036
|
+
const by = pm[1];
|
|
14037
|
+
const cx2 = p2[0];
|
|
14038
|
+
const cy2 = p2[1];
|
|
14039
|
+
const d = 2 * (ax * (by - cy2) + bx * (cy2 - ay) + cx2 * (ay - by));
|
|
14040
|
+
if (Math.abs(d) < 1e-12) return line(p1, p2);
|
|
14041
|
+
const ux = ((ax * ax + ay * ay) * (by - cy2) + (bx * bx + by * by) * (cy2 - ay) + (cx2 * cx2 + cy2 * cy2) * (ay - by)) / d;
|
|
14042
|
+
const uy = ((ax * ax + ay * ay) * (cx2 - bx) + (bx * bx + by * by) * (ax - cx2) + (cx2 * cx2 + cy2 * cy2) * (bx - ax)) / d;
|
|
14043
|
+
const center = [ux, uy];
|
|
14044
|
+
const r = Math.hypot(ax - ux, ay - uy);
|
|
14045
|
+
const ang = (p) => Math.atan2(p[1] - uy, p[0] - ux);
|
|
14046
|
+
const a0 = ang(p1);
|
|
14047
|
+
const am = ang(pm);
|
|
14048
|
+
let a1 = ang(p2);
|
|
14049
|
+
const norm = (x) => (x % (2 * Math.PI) + 2 * Math.PI) % (2 * Math.PI);
|
|
14050
|
+
const dm = norm(am - a0);
|
|
14051
|
+
const d1 = norm(a1 - a0);
|
|
14052
|
+
if (dm <= d1) a1 = a0 + d1;
|
|
14053
|
+
else a1 = a0 - norm(a0 - a1);
|
|
14054
|
+
return conic(center, [r, 0], [0, r], a0, a1);
|
|
14055
|
+
}
|
|
14056
|
+
function makeNativeKernel2DOps(module, occt) {
|
|
14057
|
+
const PLACEHOLDER = {
|
|
14058
|
+
delete: () => {},
|
|
14059
|
+
isEmpty: () => false
|
|
14060
|
+
};
|
|
14061
|
+
function delegate(method, ...args) {
|
|
14062
|
+
const o = occt();
|
|
14063
|
+
const fn = o?.[method];
|
|
14064
|
+
if (!fn) throw new Error(`manifold 2D: ${method} needs an OCCT kernel (none registered)`);
|
|
14065
|
+
return fn.call(o, ...args);
|
|
14066
|
+
}
|
|
14067
|
+
const asC = (h) => h;
|
|
14068
|
+
function occtOr(method) {
|
|
14069
|
+
const o = occt();
|
|
14070
|
+
if (!o) throw new Error(`manifold 2D: ${method} needs an OCCT kernel (none registered)`);
|
|
14071
|
+
return o;
|
|
14072
|
+
}
|
|
14073
|
+
/**
|
|
14074
|
+
* Reconstruct a native curve descriptor as an *exact* OCCT 2D curve so it can
|
|
14075
|
+
* flow into OCCT-only paths (2D booleans, intersection, NURBS). Curve type is
|
|
14076
|
+
* preserved — line→line, circle→circle, arc→3-point arc, ellipse→ellipse —
|
|
14077
|
+
* which keeps OCCT's shared-edge detection working in blueprint booleans.
|
|
14078
|
+
* Skewed/odd cases fall back to a dense B-spline. OCCT handles pass through.
|
|
14079
|
+
*/
|
|
14080
|
+
function toOcct(h) {
|
|
14081
|
+
if (!isNative(h)) return h;
|
|
14082
|
+
const o = occtOr("toOcct");
|
|
14083
|
+
const c = asC(h);
|
|
14084
|
+
if (c.k === "line") return o.makeLine2d(c.p1[0], c.p1[1], c.p2[0], c.p2[1]);
|
|
14085
|
+
if (c.k === "bezier") return o.makeBezier2d(c.pts);
|
|
14086
|
+
const ru = Math.hypot(c.u[0], c.u[1]);
|
|
14087
|
+
const rv = Math.hypot(c.v[0], c.v[1]);
|
|
14088
|
+
const full = Math.abs(Math.abs(c.a1 - c.a0) - 2 * Math.PI) < 1e-9;
|
|
14089
|
+
const sense = c.u[0] * c.v[1] - c.u[1] * c.v[0] >= 0;
|
|
14090
|
+
if (Math.abs(ru - rv) < 1e-9 * Math.max(1, ru)) {
|
|
14091
|
+
if (full) return o.makeCircle2d(c.c[0], c.c[1], ru, sense);
|
|
14092
|
+
const p0 = conicPoint(c, c.a0);
|
|
14093
|
+
const pm = conicPoint(c, (c.a0 + c.a1) / 2);
|
|
14094
|
+
const p1 = conicPoint(c, c.a1);
|
|
14095
|
+
return o.makeArc2dThreePoints(p0[0], p0[1], pm[0], pm[1], p1[0], p1[1]);
|
|
14096
|
+
}
|
|
14097
|
+
const dotUV = c.u[0] * c.v[0] + c.u[1] * c.v[1];
|
|
14098
|
+
if (Math.abs(dotUV) < 1e-9 * Math.max(1, ru * rv)) {
|
|
14099
|
+
const xdx = c.u[0] / ru;
|
|
14100
|
+
const xdy = c.u[1] / ru;
|
|
14101
|
+
return full ? o.makeEllipse2d(c.c[0], c.c[1], ru, rv, xdx, xdy, sense) : o.makeEllipseArc2d(c.c[0], c.c[1], ru, rv, c.a0, c.a1, xdx, xdy, sense);
|
|
14102
|
+
}
|
|
14103
|
+
return o.makeBSpline2d(sample(c).map((p) => [p[0], p[1]]));
|
|
14104
|
+
}
|
|
14105
|
+
const impl = {
|
|
14106
|
+
createPoint2d: (x, y) => ({
|
|
14107
|
+
x,
|
|
14108
|
+
y
|
|
14109
|
+
}),
|
|
14110
|
+
createDirection2d: (x, y) => ({
|
|
14111
|
+
x,
|
|
14112
|
+
y
|
|
14113
|
+
}),
|
|
14114
|
+
createVector2d: (x, y) => ({
|
|
14115
|
+
x,
|
|
14116
|
+
y
|
|
14117
|
+
}),
|
|
14118
|
+
createAxis2d: (px, py, dx, dy) => ({
|
|
14119
|
+
px,
|
|
14120
|
+
py,
|
|
14121
|
+
dx,
|
|
14122
|
+
dy
|
|
14123
|
+
}),
|
|
14124
|
+
wrapCurve2dHandle: (h) => h,
|
|
14125
|
+
createCurve2dAdaptor: (h) => h,
|
|
14126
|
+
makeLine2d: (x1, y1, x2, y2) => line([x1, y1], [x2, y2]),
|
|
14127
|
+
makeCircle2d: (cx, cy, r, sense = true) => conic([cx, cy], [r, 0], sense ? [0, r] : [0, -r], 0, 2 * Math.PI),
|
|
14128
|
+
makeArc2dThreePoints: (x1, y1, xm, ym, x2, y2) => circleThrough3([x1, y1], [xm, ym], [x2, y2]),
|
|
14129
|
+
makeArc2dTangent: (sx, sy, tx, ty, ex, ey) => {
|
|
14130
|
+
const tlen = Math.hypot(tx, ty) || 1;
|
|
14131
|
+
const nx = -ty / tlen;
|
|
14132
|
+
const ny = tx / tlen;
|
|
14133
|
+
const chord = [ex - sx, ey - sy];
|
|
14134
|
+
const ndotc = nx * chord[0] + ny * chord[1];
|
|
14135
|
+
if (Math.abs(ndotc) < 1e-12) return line([sx, sy], [ex, ey]);
|
|
14136
|
+
const t = (chord[0] * chord[0] + chord[1] * chord[1]) / (2 * ndotc);
|
|
14137
|
+
const cx = sx + nx * t;
|
|
14138
|
+
const cy = sy + ny * t;
|
|
14139
|
+
const r = Math.hypot(sx - cx, sy - cy);
|
|
14140
|
+
const a0 = Math.atan2(sy - cy, sx - cx);
|
|
14141
|
+
let a1 = Math.atan2(ey - cy, ex - cx);
|
|
14142
|
+
nx * tx + ny * ty;
|
|
14143
|
+
const norm = (x) => (x % (2 * Math.PI) + 2 * Math.PI) % (2 * Math.PI);
|
|
14144
|
+
const tangCCW = [-(sy - cy), sx - cx];
|
|
14145
|
+
if (tangCCW[0] * tx + tangCCW[1] * ty >= 0) a1 = a0 + norm(a1 - a0);
|
|
14146
|
+
else a1 = a0 - norm(a0 - a1);
|
|
14147
|
+
return conic([cx, cy], [r, 0], [0, r], a0, a1);
|
|
14148
|
+
},
|
|
14149
|
+
makeEllipse2d: (cx, cy, maj, min, xdx = 1, xdy = 0, sense = true) => {
|
|
14150
|
+
const xl = Math.hypot(xdx, xdy) || 1;
|
|
14151
|
+
const ux = xdx / xl * maj;
|
|
14152
|
+
const uy = xdy / xl * maj;
|
|
14153
|
+
const vx = -xdy / xl * min * (sense ? 1 : -1);
|
|
14154
|
+
const vy = xdx / xl * min * (sense ? 1 : -1);
|
|
14155
|
+
return conic([cx, cy], [ux, uy], [vx, vy], 0, 2 * Math.PI);
|
|
14156
|
+
},
|
|
14157
|
+
makeEllipseArc2d: (cx, cy, maj, min, a0, a1, xdx = 1, xdy = 0, sense = true) => {
|
|
14158
|
+
const xl = Math.hypot(xdx, xdy) || 1;
|
|
14159
|
+
const ux = xdx / xl * maj;
|
|
14160
|
+
const uy = xdy / xl * maj;
|
|
14161
|
+
const vx = -xdy / xl * min * (sense ? 1 : -1);
|
|
14162
|
+
const vy = xdx / xl * min * (sense ? 1 : -1);
|
|
14163
|
+
return conic([cx, cy], [ux, uy], [vx, vy], a0, a1);
|
|
14164
|
+
},
|
|
14165
|
+
makeBezier2d: (points) => ({
|
|
14166
|
+
__nativeC2d: true,
|
|
14167
|
+
k: "bezier",
|
|
14168
|
+
pts: points.map((p) => [p[0], p[1]])
|
|
14169
|
+
}),
|
|
14170
|
+
evaluateCurve2d: (h, param) => {
|
|
14171
|
+
const c = asC(h);
|
|
14172
|
+
if (c.k === "line") {
|
|
14173
|
+
const dx = c.p2[0] - c.p1[0];
|
|
14174
|
+
const dy = c.p2[1] - c.p1[1];
|
|
14175
|
+
const len = Math.hypot(dx, dy) || 1;
|
|
14176
|
+
return [c.p1[0] + dx * param / len, c.p1[1] + dy * param / len];
|
|
14177
|
+
}
|
|
14178
|
+
if (c.k === "bezier") return bezierAt(c.pts, param);
|
|
14179
|
+
return [c.c[0] + c.u[0] * Math.cos(param) + c.v[0] * Math.sin(param), c.c[1] + c.u[1] * Math.cos(param) + c.v[1] * Math.sin(param)];
|
|
14180
|
+
},
|
|
14181
|
+
evaluateCurve2dD1: (h, param) => {
|
|
14182
|
+
const c = asC(h);
|
|
14183
|
+
if (c.k === "line") {
|
|
14184
|
+
const dx = c.p2[0] - c.p1[0];
|
|
14185
|
+
const dy = c.p2[1] - c.p1[1];
|
|
14186
|
+
const len = Math.hypot(dx, dy) || 1;
|
|
14187
|
+
return {
|
|
14188
|
+
point: [c.p1[0] + dx * param / len, c.p1[1] + dy * param / len],
|
|
14189
|
+
tangent: [dx / len, dy / len]
|
|
14190
|
+
};
|
|
14191
|
+
}
|
|
14192
|
+
if (c.k === "bezier") return {
|
|
14193
|
+
point: bezierAt(c.pts, param),
|
|
14194
|
+
tangent: bezierD1(c.pts, param)
|
|
14195
|
+
};
|
|
14196
|
+
const ct = Math.cos(param);
|
|
14197
|
+
const st = Math.sin(param);
|
|
14198
|
+
return {
|
|
14199
|
+
point: [c.c[0] + c.u[0] * ct + c.v[0] * st, c.c[1] + c.u[1] * ct + c.v[1] * st],
|
|
14200
|
+
tangent: [-c.u[0] * st + c.v[0] * ct, -c.u[1] * st + c.v[1] * ct]
|
|
14201
|
+
};
|
|
14202
|
+
},
|
|
14203
|
+
getCurve2dBounds: (h) => {
|
|
14204
|
+
const c = asC(h);
|
|
14205
|
+
if (c.k === "conic") return {
|
|
14206
|
+
first: c.a0,
|
|
14207
|
+
last: c.a1
|
|
14208
|
+
};
|
|
14209
|
+
if (c.k === "line") return {
|
|
14210
|
+
first: 0,
|
|
14211
|
+
last: Math.hypot(c.p2[0] - c.p1[0], c.p2[1] - c.p1[1])
|
|
14212
|
+
};
|
|
14213
|
+
return {
|
|
14214
|
+
first: 0,
|
|
14215
|
+
last: 1
|
|
14216
|
+
};
|
|
14217
|
+
},
|
|
14218
|
+
getCurve2dType: (h) => {
|
|
14219
|
+
const c = asC(h);
|
|
14220
|
+
return c.k === "line" ? "LINE" : c.k === "bezier" ? "BEZIER" : "CIRCLE";
|
|
14221
|
+
},
|
|
14222
|
+
reverseCurve2d: (h) => {
|
|
14223
|
+
const c = asC(h);
|
|
14224
|
+
if (c.k === "line") {
|
|
14225
|
+
const t = c.p1;
|
|
14226
|
+
c.p1 = c.p2;
|
|
14227
|
+
c.p2 = t;
|
|
14228
|
+
} else if (c.k === "bezier") c.pts.reverse();
|
|
14229
|
+
else {
|
|
14230
|
+
const t = c.a0;
|
|
14231
|
+
c.a0 = c.a1;
|
|
14232
|
+
c.a1 = t;
|
|
14233
|
+
}
|
|
14234
|
+
},
|
|
14235
|
+
copyCurve2d: (h) => structuredClone(asC(h)),
|
|
14236
|
+
trimCurve2d: (h, start, end) => {
|
|
14237
|
+
const c = asC(h);
|
|
14238
|
+
if (c.k === "conic") return conic(c.c, c.u, c.v, start, end);
|
|
14239
|
+
if (c.k === "line") {
|
|
14240
|
+
const dx = c.p2[0] - c.p1[0];
|
|
14241
|
+
const dy = c.p2[1] - c.p1[1];
|
|
14242
|
+
const len = Math.hypot(dx, dy) || 1;
|
|
14243
|
+
return line([c.p1[0] + dx * start / len, c.p1[1] + dy * start / len], [c.p1[0] + dx * end / len, c.p1[1] + dy * end / len]);
|
|
14244
|
+
}
|
|
14245
|
+
return structuredClone(c);
|
|
14246
|
+
},
|
|
14247
|
+
createIdentityGTrsf2d: () => ({
|
|
14248
|
+
a: 1,
|
|
14249
|
+
b: 0,
|
|
14250
|
+
c: 0,
|
|
14251
|
+
d: 1,
|
|
14252
|
+
tx: 0,
|
|
14253
|
+
ty: 0
|
|
14254
|
+
}),
|
|
14255
|
+
createTranslationGTrsf2d: (dx, dy) => ({
|
|
14256
|
+
a: 1,
|
|
14257
|
+
b: 0,
|
|
14258
|
+
c: 0,
|
|
14259
|
+
d: 1,
|
|
14260
|
+
tx: dx,
|
|
14261
|
+
ty: dy
|
|
14262
|
+
}),
|
|
14263
|
+
createRotationGTrsf2d: (angle, cx, cy) => {
|
|
14264
|
+
const co = Math.cos(angle);
|
|
14265
|
+
const si = Math.sin(angle);
|
|
14266
|
+
return {
|
|
14267
|
+
a: co,
|
|
14268
|
+
b: -si,
|
|
14269
|
+
c: si,
|
|
14270
|
+
d: co,
|
|
14271
|
+
tx: cx - (co * cx - si * cy),
|
|
14272
|
+
ty: cy - (si * cx + co * cy)
|
|
14273
|
+
};
|
|
14274
|
+
},
|
|
14275
|
+
createScaleGTrsf2d: (f, cx, cy) => ({
|
|
14276
|
+
a: f,
|
|
14277
|
+
b: 0,
|
|
14278
|
+
c: 0,
|
|
14279
|
+
d: f,
|
|
14280
|
+
tx: cx - f * cx,
|
|
14281
|
+
ty: cy - f * cy
|
|
14282
|
+
}),
|
|
14283
|
+
createMirrorGTrsf2d: (cx, cy, mode, ox = 0, oy = 0, dx = 1, dy = 0) => {
|
|
14284
|
+
if (mode === "point") return {
|
|
14285
|
+
a: -1,
|
|
14286
|
+
b: 0,
|
|
14287
|
+
c: 0,
|
|
14288
|
+
d: -1,
|
|
14289
|
+
tx: 2 * cx,
|
|
14290
|
+
ty: 2 * cy
|
|
14291
|
+
};
|
|
14292
|
+
const l = Math.hypot(dx, dy) || 1;
|
|
14293
|
+
const ux = dx / l;
|
|
14294
|
+
const uy = dy / l;
|
|
14295
|
+
const a = ux * ux - uy * uy;
|
|
14296
|
+
const b = 2 * ux * uy;
|
|
14297
|
+
return {
|
|
14298
|
+
a,
|
|
14299
|
+
b,
|
|
14300
|
+
c: b,
|
|
14301
|
+
d: -a,
|
|
14302
|
+
tx: ox - (a * ox + b * oy),
|
|
14303
|
+
ty: oy - (b * ox - a * oy)
|
|
14304
|
+
};
|
|
14305
|
+
},
|
|
14306
|
+
createAffinityGTrsf2d: (ox, oy, dx, dy, ratio) => {
|
|
14307
|
+
const l = Math.hypot(dx, dy) || 1;
|
|
14308
|
+
const ux = dx / l;
|
|
14309
|
+
const uy = dy / l;
|
|
14310
|
+
const nx = -uy;
|
|
14311
|
+
const ny = ux;
|
|
14312
|
+
const a = ux * ux + ratio * nx * nx;
|
|
14313
|
+
const b = ux * uy + ratio * nx * ny;
|
|
14314
|
+
const c = uy * ux + ratio * ny * nx;
|
|
14315
|
+
const d = uy * uy + ratio * ny * ny;
|
|
14316
|
+
return {
|
|
14317
|
+
a,
|
|
14318
|
+
b,
|
|
14319
|
+
c,
|
|
14320
|
+
d,
|
|
14321
|
+
tx: ox - (a * ox + b * oy),
|
|
14322
|
+
ty: oy - (c * ox + d * oy)
|
|
14323
|
+
};
|
|
14324
|
+
},
|
|
14325
|
+
setGTrsf2dTranslationPart: (g, dx, dy) => {
|
|
14326
|
+
const m = g;
|
|
14327
|
+
m.tx = dx;
|
|
14328
|
+
m.ty = dy;
|
|
14329
|
+
},
|
|
14330
|
+
multiplyGTrsf2d: (base, other) => {
|
|
14331
|
+
const r = compose(base, other);
|
|
14332
|
+
Object.assign(base, r);
|
|
14333
|
+
},
|
|
14334
|
+
transformCurve2dGeneral: (h, g) => transform(asC(h), g),
|
|
14335
|
+
translateCurve2d: (h, dx, dy) => transform(asC(h), {
|
|
14336
|
+
a: 1,
|
|
14337
|
+
b: 0,
|
|
14338
|
+
c: 0,
|
|
14339
|
+
d: 1,
|
|
14340
|
+
tx: dx,
|
|
14341
|
+
ty: dy
|
|
14342
|
+
}),
|
|
14343
|
+
rotateCurve2d: (h, angle, cx, cy) => {
|
|
14344
|
+
const co = Math.cos(angle);
|
|
14345
|
+
const si = Math.sin(angle);
|
|
14346
|
+
return transform(asC(h), {
|
|
14347
|
+
a: co,
|
|
14348
|
+
b: -si,
|
|
14349
|
+
c: si,
|
|
14350
|
+
d: co,
|
|
14351
|
+
tx: cx - (co * cx - si * cy),
|
|
14352
|
+
ty: cy - (si * cx + co * cy)
|
|
14353
|
+
});
|
|
14354
|
+
},
|
|
14355
|
+
scaleCurve2d: (h, f, cx, cy) => transform(asC(h), {
|
|
14356
|
+
a: f,
|
|
14357
|
+
b: 0,
|
|
14358
|
+
c: 0,
|
|
14359
|
+
d: f,
|
|
14360
|
+
tx: cx - f * cx,
|
|
14361
|
+
ty: cy - f * cy
|
|
14362
|
+
}),
|
|
14363
|
+
mirrorCurve2dAtPoint: (h, cx, cy) => transform(asC(h), {
|
|
14364
|
+
a: -1,
|
|
14365
|
+
b: 0,
|
|
14366
|
+
c: 0,
|
|
14367
|
+
d: -1,
|
|
14368
|
+
tx: 2 * cx,
|
|
14369
|
+
ty: 2 * cy
|
|
14370
|
+
}),
|
|
14371
|
+
mirrorCurve2dAcrossAxis: (h, ox, oy, dx, dy) => {
|
|
14372
|
+
const l = Math.hypot(dx, dy) || 1;
|
|
14373
|
+
const ux = dx / l;
|
|
14374
|
+
const uy = dy / l;
|
|
14375
|
+
const a = ux * ux - uy * uy;
|
|
14376
|
+
const b = 2 * ux * uy;
|
|
14377
|
+
return transform(asC(h), {
|
|
14378
|
+
a,
|
|
14379
|
+
b,
|
|
14380
|
+
c: b,
|
|
14381
|
+
d: -a,
|
|
14382
|
+
tx: ox - (a * ox + b * oy),
|
|
14383
|
+
ty: oy - (b * ox - a * oy)
|
|
14384
|
+
});
|
|
14385
|
+
},
|
|
14386
|
+
affinityTransform2d: (h, ox, oy, dx, dy, ratio) => {
|
|
14387
|
+
const l = Math.hypot(dx, dy) || 1;
|
|
14388
|
+
const ux = dx / l;
|
|
14389
|
+
const uy = dy / l;
|
|
14390
|
+
const nx = -uy;
|
|
14391
|
+
const ny = ux;
|
|
14392
|
+
const a = ux * ux + ratio * nx * nx;
|
|
14393
|
+
const b = ux * uy + ratio * nx * ny;
|
|
14394
|
+
const c = uy * ux + ratio * ny * nx;
|
|
14395
|
+
const d = uy * uy + ratio * ny * ny;
|
|
14396
|
+
return transform(asC(h), {
|
|
14397
|
+
a,
|
|
14398
|
+
b,
|
|
14399
|
+
c,
|
|
14400
|
+
d,
|
|
14401
|
+
tx: ox - (a * ox + b * oy),
|
|
14402
|
+
ty: oy - (c * ox + d * oy)
|
|
14403
|
+
});
|
|
14404
|
+
},
|
|
14405
|
+
createBoundingBox2d: () => ({
|
|
14406
|
+
min: [Infinity, Infinity],
|
|
14407
|
+
max: [-Infinity, -Infinity]
|
|
14408
|
+
}),
|
|
14409
|
+
addCurveToBBox2d: (bb, h) => {
|
|
14410
|
+
const box = bb;
|
|
14411
|
+
let pts;
|
|
14412
|
+
if (isNative(h)) pts = sample(asC(h));
|
|
14413
|
+
else {
|
|
14414
|
+
const o = occtOr("addCurveToBBox2d");
|
|
14415
|
+
const { first, last } = o.getCurve2dBounds(h);
|
|
14416
|
+
pts = [];
|
|
14417
|
+
for (let i = 0; i <= 32; i++) pts.push(o.evaluateCurve2d(h, first + (last - first) * i / 32));
|
|
14418
|
+
}
|
|
14419
|
+
for (const [x, y] of pts) {
|
|
14420
|
+
if (x < box.min[0]) box.min[0] = x;
|
|
14421
|
+
if (y < box.min[1]) box.min[1] = y;
|
|
14422
|
+
if (x > box.max[0]) box.max[0] = x;
|
|
14423
|
+
if (y > box.max[1]) box.max[1] = y;
|
|
14424
|
+
}
|
|
14425
|
+
},
|
|
14426
|
+
getBBox2dBounds: (bb) => {
|
|
14427
|
+
const box = bb;
|
|
14428
|
+
return {
|
|
14429
|
+
xMin: box.min[0],
|
|
14430
|
+
yMin: box.min[1],
|
|
14431
|
+
xMax: box.max[0],
|
|
14432
|
+
yMax: box.max[1]
|
|
14433
|
+
};
|
|
14434
|
+
},
|
|
14435
|
+
mergeBBox2d: (t, o) => {
|
|
14436
|
+
const a = t;
|
|
14437
|
+
const b = o;
|
|
14438
|
+
a.min[0] = Math.min(a.min[0], b.min[0]);
|
|
14439
|
+
a.min[1] = Math.min(a.min[1], b.min[1]);
|
|
14440
|
+
a.max[0] = Math.max(a.max[0], b.max[0]);
|
|
14441
|
+
a.max[1] = Math.max(a.max[1], b.max[1]);
|
|
14442
|
+
},
|
|
14443
|
+
isBBox2dOut: (a, b) => {
|
|
14444
|
+
const x = a;
|
|
14445
|
+
const y = b;
|
|
14446
|
+
return x.max[0] < y.min[0] || x.min[0] > y.max[0] || x.max[1] < y.min[1] || x.min[1] > y.max[1];
|
|
14447
|
+
},
|
|
14448
|
+
isBBox2dOutPoint: (bb, x, y) => {
|
|
14449
|
+
const box = bb;
|
|
14450
|
+
return x < box.min[0] || x > box.max[0] || y < box.min[1] || y > box.max[1];
|
|
14451
|
+
},
|
|
14452
|
+
getCurve2dCircleData: (h) => {
|
|
14453
|
+
const c = asC(h);
|
|
14454
|
+
if (c.k !== "conic") return null;
|
|
14455
|
+
const ru = Math.hypot(c.u[0], c.u[1]);
|
|
14456
|
+
const rv = Math.hypot(c.v[0], c.v[1]);
|
|
14457
|
+
if (Math.abs(ru - rv) > 1e-6) return null;
|
|
14458
|
+
return {
|
|
14459
|
+
cx: c.c[0],
|
|
14460
|
+
cy: c.c[1],
|
|
14461
|
+
radius: ru,
|
|
14462
|
+
isDirect: true
|
|
14463
|
+
};
|
|
14464
|
+
},
|
|
14465
|
+
liftCurve2dToPlane: (h, origin, zDir, xDir) => {
|
|
14466
|
+
const zx = zDir[0];
|
|
14467
|
+
const zy = zDir[1];
|
|
14468
|
+
const zz = zDir[2];
|
|
14469
|
+
const xx = xDir[0];
|
|
14470
|
+
const xy = xDir[1];
|
|
14471
|
+
const xz = xDir[2];
|
|
14472
|
+
const yx = zy * xz - zz * xy;
|
|
14473
|
+
const yy = zz * xx - zx * xz;
|
|
14474
|
+
const yz = zx * xy - zy * xx;
|
|
14475
|
+
return wrap(PLACEHOLDER, makeNode("profileEdge", { pts: sample(asC(h)).map(([u, v]) => [
|
|
14476
|
+
origin[0] + xx * u + yx * v,
|
|
14477
|
+
origin[1] + xy * u + yy * v,
|
|
14478
|
+
origin[2] + xz * u + yz * v
|
|
14479
|
+
]) }, []));
|
|
14480
|
+
},
|
|
14481
|
+
makeBSpline2d: (points, options) => occtOr("makeBSpline2d").makeBSpline2d(points, options),
|
|
14482
|
+
offsetCurve2d: (c, offset) => occtOr("offsetCurve2d").offsetCurve2d(toOcct(c), offset),
|
|
14483
|
+
intersectCurves2d: (c1, c2, tol) => occtOr("intersectCurves2d").intersectCurves2d(toOcct(c1), toOcct(c2), tol),
|
|
14484
|
+
projectPointOnCurve2d: (c, x, y) => occtOr("projectPointOnCurve2d").projectPointOnCurve2d(toOcct(c), x, y),
|
|
14485
|
+
distanceBetweenCurves2d: (c1, c2, s1, e1, s2, e2) => occtOr("distanceBetweenCurves2d").distanceBetweenCurves2d(toOcct(c1), toOcct(c2), s1, e1, s2, e2),
|
|
14486
|
+
approximateCurve2dAsBSpline: (c, tol, cont, maxSeg) => occtOr("approximateCurve2dAsBSpline").approximateCurve2dAsBSpline(toOcct(c), tol, cont, maxSeg),
|
|
14487
|
+
decomposeBSpline2dToBeziers: (c) => occtOr("decomposeBSpline2dToBeziers").decomposeBSpline2dToBeziers(toOcct(c)),
|
|
14488
|
+
serializeCurve2d: (c) => occtOr("serializeCurve2d").serializeCurve2d(toOcct(c)),
|
|
14489
|
+
deserializeCurve2d: (data) => occtOr("deserializeCurve2d").deserializeCurve2d(data),
|
|
14490
|
+
splitCurve2d: (c, params) => occtOr("splitCurve2d").splitCurve2d(toOcct(c), params),
|
|
14491
|
+
getCurve2dEllipseData: (c) => occtOr("getCurve2dEllipseData").getCurve2dEllipseData(toOcct(c)),
|
|
14492
|
+
getCurve2dBezierPoles: (c) => occtOr("getCurve2dBezierPoles").getCurve2dBezierPoles(toOcct(c)),
|
|
14493
|
+
getCurve2dBezierDegree: (c) => occtOr("getCurve2dBezierDegree").getCurve2dBezierDegree(toOcct(c)),
|
|
14494
|
+
getCurve2dBSplineData: (c) => occtOr("getCurve2dBSplineData").getCurve2dBSplineData(toOcct(c)),
|
|
14495
|
+
buildEdgeOnSurface: (c, surface) => occtOr("buildEdgeOnSurface").buildEdgeOnSurface(toOcct(c), surface),
|
|
14496
|
+
extractSurfaceFromFace: (face) => occtOr("extractSurfaceFromFace").extractSurfaceFromFace(face),
|
|
14497
|
+
extractCurve2dFromEdge: (edge, face) => occtOr("extractCurve2dFromEdge").extractCurve2dFromEdge(edge, face),
|
|
14498
|
+
buildCurves3d: (wire) => {
|
|
14499
|
+
occtOr("buildCurves3d").buildCurves3d(wire);
|
|
14500
|
+
},
|
|
14501
|
+
fixWireOnFace: (wire, face, tol) => occtOr("fixWireOnFace").fixWireOnFace(wire, face, tol),
|
|
14502
|
+
fillSurface: (wires, opts) => occtOr("fillSurface").fillSurface(wires, opts)
|
|
14503
|
+
};
|
|
14504
|
+
for (const m of [
|
|
14505
|
+
"evaluateCurve2d",
|
|
14506
|
+
"evaluateCurve2dD1",
|
|
14507
|
+
"getCurve2dBounds",
|
|
14508
|
+
"getCurve2dType",
|
|
14509
|
+
"reverseCurve2d",
|
|
14510
|
+
"copyCurve2d",
|
|
14511
|
+
"trimCurve2d",
|
|
14512
|
+
"transformCurve2dGeneral",
|
|
14513
|
+
"translateCurve2d",
|
|
14514
|
+
"rotateCurve2d",
|
|
14515
|
+
"scaleCurve2d",
|
|
14516
|
+
"mirrorCurve2dAtPoint",
|
|
14517
|
+
"mirrorCurve2dAcrossAxis",
|
|
14518
|
+
"affinityTransform2d",
|
|
14519
|
+
"getCurve2dCircleData",
|
|
14520
|
+
"liftCurve2dToPlane"
|
|
14521
|
+
]) {
|
|
14522
|
+
const nativeFn = impl[m];
|
|
14523
|
+
if (!nativeFn) continue;
|
|
14524
|
+
impl[m] = ((h, ...rest) => isNative(h) ? nativeFn(h, ...rest) : delegate(m, h, ...rest));
|
|
14525
|
+
}
|
|
14526
|
+
return impl;
|
|
14527
|
+
}
|
|
14528
|
+
//#endregion
|
|
12832
14529
|
//#region src/kernel/manifold/kernel2dOps.ts
|
|
12833
14530
|
var KERNEL_2D_METHODS = [
|
|
12834
14531
|
"createPoint2d",
|
|
@@ -12896,17 +14593,15 @@ var KERNEL_2D_METHODS = [
|
|
|
12896
14593
|
"fillSurface"
|
|
12897
14594
|
];
|
|
12898
14595
|
function resolveOcct2D(method) {
|
|
12899
|
-
|
|
12900
|
-
|
|
12901
|
-
occt = getKernel("occt");
|
|
12902
|
-
} catch {
|
|
12903
|
-
throw new Error(`manifold: ${method} unsupported on manifold kernel; no B-rep kernel registered`);
|
|
12904
|
-
}
|
|
14596
|
+
const occt = resolveOcct();
|
|
14597
|
+
if (!occt) throw new Error(`manifold: ${method} unsupported on manifold kernel; no B-rep kernel registered`);
|
|
12905
14598
|
return occt;
|
|
12906
14599
|
}
|
|
12907
|
-
function makeKernel2DOps(
|
|
14600
|
+
function makeKernel2DOps(module) {
|
|
12908
14601
|
const ops = {};
|
|
12909
14602
|
for (const method of KERNEL_2D_METHODS) ops[method] = (...args) => resolveOcct2D(method)[method](...args);
|
|
14603
|
+
const native = makeNativeKernel2DOps(module, () => resolveOcct());
|
|
14604
|
+
Object.assign(ops, native);
|
|
12910
14605
|
return ops;
|
|
12911
14606
|
}
|
|
12912
14607
|
//#endregion
|