brepjs 20.12.7 → 20.12.8
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/{adjacencyFns-mMmTBUBY.cjs → adjacencyFns-BfgFo-Rh.cjs} +3 -3
- package/dist/{adjacencyFns-hMihivxC.js → adjacencyFns-Bl109A3Z.js} +3 -3
- package/dist/{blueprint-17RUHsoP.cjs → blueprint-DTDSztfd.cjs} +5 -5
- package/dist/{blueprint-BS50D3J_.js → blueprint-RqemOtg5.js} +5 -5
- package/dist/{blueprintFns-zy5lo2IF.js → blueprintFns-B9_PhTr8.js} +2 -2
- package/dist/{blueprintFns-Dw5_4_Bk.cjs → blueprintFns-C7E5R89N.cjs} +2 -2
- package/dist/{blueprintSketcher-C1WCI6E0.js → blueprintSketcher-B15522Kr.js} +3 -3
- package/dist/{blueprintSketcher-BG--DxWB.cjs → blueprintSketcher-Brj4lXjj.cjs} +3 -3
- package/dist/{boolean2D-7SQ3B0pC.cjs → boolean2D-DZ8aJbI-.cjs} +4 -4
- package/dist/{boolean2D-CsdyfjFE.js → boolean2D-_eiIiNw1.js} +4 -4
- package/dist/{solidBuilders-DdG4NPHM.cjs → booleanFns-D5nQ1nWS.cjs} +11 -217
- package/dist/{solidBuilders-Bmr59cGp.js → booleanFns-cNfXGqMX.js} +10 -156
- package/dist/brepjs.cjs +325 -168
- package/dist/brepjs.js +282 -125
- package/dist/{cameraFns-BAtzhCYM.cjs → cameraFns-6Er2lhp5.cjs} +3 -3
- package/dist/{cameraFns-BVWyAscu.js → cameraFns-YhB7A_Zc.js} +3 -3
- package/dist/core.cjs +2 -2
- package/dist/core.js +2 -2
- package/dist/{cornerFinder-e4Wc7_yp.cjs → cornerFinder-D9Wx3DWu.cjs} +1 -1
- package/dist/{cornerFinder-Dv_2rmaY.js → cornerFinder-G1WkSkVl.js} +1 -1
- package/dist/{curveFns-BAM7QHrP.cjs → curveFns-B5_N-gMj.cjs} +1 -1
- package/dist/{curveFns-CEI-rouh.js → curveFns-C4CqthJp.js} +1 -1
- package/dist/{drawFns-Cl1i8B_B.js → drawFns-DU5fewKl.js} +12 -12
- package/dist/{drawFns-d-RvC6u6.cjs → drawFns-UPbO2heB.cjs} +12 -12
- package/dist/{faceFns-Q87HCJrp.js → faceFns-BgRNa5vx.js} +2 -2
- package/dist/{faceFns-C-2ttg8X.cjs → faceFns-C4NOGZBg.cjs} +2 -2
- package/dist/{healingFns-Cm4NkKD8.js → healingFns-BzOo0yyz.js} +5 -5
- package/dist/{healingFns-DZkO5okn.cjs → healingFns-i5gV3BMG.cjs} +29 -29
- package/dist/{helpers-BdGGaLhF.cjs → helpers-DJQeDf_5.cjs} +6 -6
- package/dist/{helpers-DpGcM2qZ.js → helpers-DPHQt2Kr.js} +6 -6
- package/dist/{importFns-DLiP26NW.cjs → importFns-BiRpt227.cjs} +319 -14
- package/dist/{importFns-Bp-p0jiP.js → importFns-CwrJsNvg.js} +314 -15
- package/dist/io/igesSupport.d.ts +6 -0
- package/dist/io/importFns.d.ts +15 -5
- package/dist/io/ioUtils.d.ts +15 -3
- package/dist/io/meshNesting.d.ts +11 -0
- package/dist/io/threemfImportFns.d.ts +6 -3
- package/dist/io.cjs +2 -2
- package/dist/io.js +2 -2
- package/dist/kernel/occtWasm/occtWasmAdapter.cjs +1 -1
- package/dist/kernel/occtWasm/occtWasmAdapter.js +1 -1
- package/dist/kernel/occtWasm/occtWasmTypes.d.ts +4 -2
- package/dist/{loftFns-DGV1z2NJ.cjs → loftFns-DgkK4Kj_.cjs} +1 -1
- package/dist/{loftFns-DQ7Z29n3.js → loftFns-lwzTh1fI.js} +1 -1
- package/dist/{measureFns-BdSjw5fr.cjs → measureFns-D_RRjCZg.cjs} +3 -3
- package/dist/{measureFns-BrdCH4cH.js → measureFns-Q3K25IfN.js} +3 -3
- package/dist/measurement.cjs +2 -2
- package/dist/measurement.js +2 -2
- package/dist/{meshFns-UE8tByyw.js → meshFns-BGoJU6_P.js} +20 -6
- package/dist/{meshFns-BeubBqEI.cjs → meshFns-Djbb4PUC.cjs} +25 -5
- package/dist/{occtWasmAdapter-DA7oMgcQ.js → occtWasmAdapter-BCCwaYkq.js} +7 -5
- package/dist/{occtWasmAdapter-D3qerQTq.cjs → occtWasmAdapter-UcYZRi-w.cjs} +7 -5
- package/dist/operations.cjs +2 -2
- package/dist/operations.js +2 -2
- package/dist/{primitiveFns-CLGVLwG8.cjs → primitiveFns-CfSnex9P.cjs} +19 -18
- package/dist/{primitiveFns-3-gs-FUX.js → primitiveFns-D-aYcwt2.js} +5 -4
- package/dist/{principalBoxFns-RMZItjfR.js → principalBoxFns-Dcp9gg5e.js} +3 -3
- package/dist/{principalBoxFns-CiXzjOkr.cjs → principalBoxFns-IY8FfPVj.cjs} +3 -3
- 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/{refResolveFns-kJg2iCad.js → refResolveFns-BPge7T5w.js} +6 -6
- package/dist/{refResolveFns-DNX0bCrP.cjs → refResolveFns-gZQ1o5XK.cjs} +6 -6
- package/dist/{shapeFns-SgIrOjN4.cjs → shapeFns-Bs92VrZh.cjs} +2 -2
- package/dist/{shapeFns-CZ6VF1yd.js → shapeFns-TWdr4Dv4.js} +2 -2
- package/dist/shapeRef.cjs +1 -1
- package/dist/shapeRef.js +1 -1
- package/dist/{shapeTypes-BNGu103j.js → shapeTypes-CIH-8d_a.js} +1 -1
- package/dist/{shapeTypes-MUEH4XuH.cjs → shapeTypes-DmThK_oa.cjs} +1 -1
- package/dist/sketching.cjs +3 -3
- package/dist/sketching.js +3 -3
- package/dist/{originTrackingFns-rEKOAP65.cjs → solidBuilders-DGskMugU.cjs} +209 -2
- package/dist/{originTrackingFns-c2qgRZ_9.js → solidBuilders-q_hwYsdo.js} +150 -3
- package/dist/{surfaceBuilders-DI376ai0.js → surfaceBuilders-DXo4N7wQ.js} +3 -3
- package/dist/{surfaceBuilders-DOmDVuMs.cjs → surfaceBuilders-DeSLKg73.cjs} +3 -3
- package/dist/text.cjs +2 -2
- package/dist/text.js +2 -2
- package/dist/{textBlueprints-CE0oxB43.js → textBlueprints-BYWZho_c.js} +8 -7
- package/dist/{textBlueprints-B7Vhr0xu.cjs → textBlueprints-Dz6wNgve.cjs} +9 -8
- package/dist/{textMetrics-C6_kSht6.cjs → textMetrics-bKoFTj3m.cjs} +1 -1
- package/dist/{textMetrics-_VGqdewQ.js → textMetrics-k_rGqib2.js} +1 -1
- package/dist/{threadFns-CHdY-4Cz.js → threadFns-BeB8s0tA.js} +7 -7
- package/dist/{threadFns-1H60LrFX.cjs → threadFns-CoGAFHHt.cjs} +9 -9
- package/dist/topology/meshFns.d.ts +3 -0
- package/dist/topology.cjs +11 -11
- package/dist/topology.js +9 -9
- package/dist/{topologyQueryFns-C_fXO6xL.cjs → topologyQueryFns-CXbCFaU2.cjs} +1 -1
- package/dist/{topologyQueryFns-CltEv7Pi.js → topologyQueryFns-Cp0yekBh.js} +1 -1
- package/dist/{validityTypes-GanLrmvY.js → validityTypes-DlrWkrSR.js} +1 -1
- package/dist/{validityTypes-CGX2ES81.cjs → validityTypes-m6eLRTYE.cjs} +1 -1
- package/package.json +1 -1
package/dist/brepjs.cjs
CHANGED
|
@@ -1,42 +1,42 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
2
|
const require_rolldown_runtime = require("./rolldown-runtime-BW-eSwOZ.cjs");
|
|
3
|
-
const require_shapeTypes = require("./shapeTypes-
|
|
4
|
-
const require_occtWasmAdapter = require("./occtWasmAdapter-
|
|
3
|
+
const require_shapeTypes = require("./shapeTypes-DmThK_oa.cjs");
|
|
4
|
+
const require_occtWasmAdapter = require("./occtWasmAdapter-UcYZRi-w.cjs");
|
|
5
5
|
const require_bug = require("./bug-CBcpIPuf.cjs");
|
|
6
6
|
const require_errors = require("./errors-O_blYTWT.cjs");
|
|
7
|
-
const require_topologyQueryFns = require("./topologyQueryFns-
|
|
8
|
-
const require_validityTypes = require("./validityTypes-
|
|
7
|
+
const require_topologyQueryFns = require("./topologyQueryFns-CXbCFaU2.cjs");
|
|
8
|
+
const require_validityTypes = require("./validityTypes-m6eLRTYE.cjs");
|
|
9
9
|
const require_constants = require("./constants-oee0S_x6.cjs");
|
|
10
10
|
const require_types = require("./types-CjF9Rofr.cjs");
|
|
11
11
|
const require_vecOps = require("./vecOps-CrGEPPQM.cjs");
|
|
12
12
|
const require_planeOps = require("./planeOps-DZfLToKZ.cjs");
|
|
13
|
-
const require_faceFns = require("./faceFns-
|
|
14
|
-
const
|
|
15
|
-
const
|
|
16
|
-
const require_primitiveFns = require("./primitiveFns-
|
|
17
|
-
const require_shapeFns = require("./shapeFns-
|
|
18
|
-
const require_curveFns = require("./curveFns-
|
|
19
|
-
const require_meshFns = require("./meshFns-
|
|
13
|
+
const require_faceFns = require("./faceFns-C4NOGZBg.cjs");
|
|
14
|
+
const require_solidBuilders = require("./solidBuilders-DGskMugU.cjs");
|
|
15
|
+
const require_booleanFns = require("./booleanFns-D5nQ1nWS.cjs");
|
|
16
|
+
const require_primitiveFns = require("./primitiveFns-CfSnex9P.cjs");
|
|
17
|
+
const require_shapeFns = require("./shapeFns-Bs92VrZh.cjs");
|
|
18
|
+
const require_curveFns = require("./curveFns-B5_N-gMj.cjs");
|
|
19
|
+
const require_meshFns = require("./meshFns-Djbb4PUC.cjs");
|
|
20
20
|
const require_arrayAccess = require("./arrayAccess-DpJYARwv.cjs");
|
|
21
|
-
const require_surfaceBuilders = require("./surfaceBuilders-
|
|
22
|
-
const require_healingFns = require("./healingFns-
|
|
23
|
-
const require_threadFns = require("./threadFns-
|
|
24
|
-
const require_blueprintSketcher = require("./blueprintSketcher-
|
|
25
|
-
const require_helpers = require("./helpers-
|
|
26
|
-
const require_blueprint = require("./blueprint-
|
|
27
|
-
const require_drawFns = require("./drawFns-
|
|
28
|
-
const require_measureFns = require("./measureFns-
|
|
29
|
-
const require_cornerFinder = require("./cornerFinder-
|
|
30
|
-
const require_boolean2D = require("./boolean2D-
|
|
31
|
-
const require_blueprintFns = require("./blueprintFns-
|
|
32
|
-
const require_importFns = require("./importFns-
|
|
33
|
-
const require_textBlueprints = require("./textBlueprints-
|
|
34
|
-
const require_loftFns = require("./loftFns-
|
|
35
|
-
const require_refResolveFns = require("./refResolveFns-
|
|
36
|
-
const require_adjacencyFns = require("./adjacencyFns-
|
|
37
|
-
const require_cameraFns = require("./cameraFns-
|
|
38
|
-
const require_textMetrics = require("./textMetrics-
|
|
39
|
-
const require_principalBoxFns = require("./principalBoxFns-
|
|
21
|
+
const require_surfaceBuilders = require("./surfaceBuilders-DeSLKg73.cjs");
|
|
22
|
+
const require_healingFns = require("./healingFns-i5gV3BMG.cjs");
|
|
23
|
+
const require_threadFns = require("./threadFns-CoGAFHHt.cjs");
|
|
24
|
+
const require_blueprintSketcher = require("./blueprintSketcher-Brj4lXjj.cjs");
|
|
25
|
+
const require_helpers = require("./helpers-DJQeDf_5.cjs");
|
|
26
|
+
const require_blueprint = require("./blueprint-DTDSztfd.cjs");
|
|
27
|
+
const require_drawFns = require("./drawFns-UPbO2heB.cjs");
|
|
28
|
+
const require_measureFns = require("./measureFns-D_RRjCZg.cjs");
|
|
29
|
+
const require_cornerFinder = require("./cornerFinder-D9Wx3DWu.cjs");
|
|
30
|
+
const require_boolean2D = require("./boolean2D-DZ8aJbI-.cjs");
|
|
31
|
+
const require_blueprintFns = require("./blueprintFns-C7E5R89N.cjs");
|
|
32
|
+
const require_importFns = require("./importFns-BiRpt227.cjs");
|
|
33
|
+
const require_textBlueprints = require("./textBlueprints-Dz6wNgve.cjs");
|
|
34
|
+
const require_loftFns = require("./loftFns-DgkK4Kj_.cjs");
|
|
35
|
+
const require_refResolveFns = require("./refResolveFns-gZQ1o5XK.cjs");
|
|
36
|
+
const require_adjacencyFns = require("./adjacencyFns-BfgFo-Rh.cjs");
|
|
37
|
+
const require_cameraFns = require("./cameraFns-6Er2lhp5.cjs");
|
|
38
|
+
const require_textMetrics = require("./textMetrics-bKoFTj3m.cjs");
|
|
39
|
+
const require_principalBoxFns = require("./principalBoxFns-IY8FfPVj.cjs");
|
|
40
40
|
const require_workerPool = require("./workerPool-D5tiNXrI.cjs");
|
|
41
41
|
// src/kernel/types.ts
|
|
42
42
|
/** Check if the kernel supports hidden-line-removal projection. */
|
|
@@ -2023,7 +2023,7 @@ function shell$1(target, refs, thickness) {
|
|
|
2023
2023
|
* handle before coloring, so plain consumers of the same subtree stay
|
|
2024
2024
|
* metadata-free. */
|
|
2025
2025
|
function color(target, input) {
|
|
2026
|
-
const rgba =
|
|
2026
|
+
const rgba = require_booleanFns.parseColor(input).map((c) => Math.min(1, Math.max(0, c)));
|
|
2027
2027
|
let h = mix(startHash("Color"), target);
|
|
2028
2028
|
for (const c of rgba) h = fnvMixNumber(h, c);
|
|
2029
2029
|
return {
|
|
@@ -2489,7 +2489,7 @@ function evalFuse(node, ctx) {
|
|
|
2489
2489
|
if (!a.ok) return a;
|
|
2490
2490
|
const b = resolveOperand(ctx, node.b, "Fuse.b");
|
|
2491
2491
|
if (!b.ok) return b;
|
|
2492
|
-
return
|
|
2492
|
+
return require_booleanFns.fuse(a.value, b.value, boolOptions(node, ctx));
|
|
2493
2493
|
}
|
|
2494
2494
|
function evalCut(node, ctx) {
|
|
2495
2495
|
if (node.a.kind === "Empty") return emptyResult$1("Cut");
|
|
@@ -2498,7 +2498,7 @@ function evalCut(node, ctx) {
|
|
|
2498
2498
|
if (!a.ok) return a;
|
|
2499
2499
|
const b = resolveOperand(ctx, node.b, "Cut.b");
|
|
2500
2500
|
if (!b.ok) return b;
|
|
2501
|
-
return
|
|
2501
|
+
return require_booleanFns.cut(a.value, b.value, boolOptions(node, ctx));
|
|
2502
2502
|
}
|
|
2503
2503
|
function evalIntersect(node, ctx) {
|
|
2504
2504
|
if (node.a.kind === "Empty" || node.b.kind === "Empty") return emptyResult$1("Intersect");
|
|
@@ -2506,7 +2506,7 @@ function evalIntersect(node, ctx) {
|
|
|
2506
2506
|
if (!a.ok) return a;
|
|
2507
2507
|
const b = resolveOperand(ctx, node.b, "Intersect.b");
|
|
2508
2508
|
if (!b.ok) return b;
|
|
2509
|
-
return
|
|
2509
|
+
return require_booleanFns.intersect(a.value, b.value, boolOptions(node, ctx));
|
|
2510
2510
|
}
|
|
2511
2511
|
function resolveAll(ctx, nodes, where) {
|
|
2512
2512
|
const out = [];
|
|
@@ -2523,7 +2523,7 @@ function evalFuseAll(node, ctx) {
|
|
|
2523
2523
|
if (non.length === 1 && non[0]) return ctx.evalNode(non[0]);
|
|
2524
2524
|
const resolved = resolveAll(ctx, non, "FuseAll.operand");
|
|
2525
2525
|
if (!resolved.ok) return resolved;
|
|
2526
|
-
return
|
|
2526
|
+
return require_booleanFns.fuseAll(resolved.value, boolOptions(node, ctx));
|
|
2527
2527
|
}
|
|
2528
2528
|
function evalCutAll(node, ctx) {
|
|
2529
2529
|
if (node.base.kind === "Empty") return emptyResult$1("CutAll");
|
|
@@ -2533,7 +2533,7 @@ function evalCutAll(node, ctx) {
|
|
|
2533
2533
|
if (!base.ok) return base;
|
|
2534
2534
|
const resolved = resolveAll(ctx, tools, "CutAll.tool");
|
|
2535
2535
|
if (!resolved.ok) return resolved;
|
|
2536
|
-
return
|
|
2536
|
+
return require_booleanFns.cutAll(base.value, resolved.value, boolOptions(node, ctx));
|
|
2537
2537
|
}
|
|
2538
2538
|
// src/csg/evaluators/transforms.ts
|
|
2539
2539
|
function emptyResult(kind) {
|
|
@@ -2566,7 +2566,7 @@ function relocate(shape, ops) {
|
|
|
2566
2566
|
} finally {
|
|
2567
2567
|
dispose();
|
|
2568
2568
|
}
|
|
2569
|
-
if (
|
|
2569
|
+
if (require_booleanFns.hasAnyMetadata(shape)) require_booleanFns.propagateMetadataThroughRelocation(shape, moved);
|
|
2570
2570
|
return moved;
|
|
2571
2571
|
}
|
|
2572
2572
|
function evalTranslate(node, ctx) {
|
|
@@ -2772,7 +2772,7 @@ function combine(source, placements, fuse) {
|
|
|
2772
2772
|
}
|
|
2773
2773
|
copies.push(placed.value);
|
|
2774
2774
|
}
|
|
2775
|
-
const result = fuse ?
|
|
2775
|
+
const result = fuse ? require_booleanFns.fuseAll(copies, { unsafe: true }) : require_errors.ok(require_solidBuilders.makeCompound(copies));
|
|
2776
2776
|
for (const c of copies) if (!result.ok || c !== result.value) c[Symbol.dispose]();
|
|
2777
2777
|
return result;
|
|
2778
2778
|
}
|
|
@@ -3122,8 +3122,8 @@ function evalColor(node, ctx) {
|
|
|
3122
3122
|
} finally {
|
|
3123
3123
|
dispose();
|
|
3124
3124
|
}
|
|
3125
|
-
if (
|
|
3126
|
-
return require_errors.ok(
|
|
3125
|
+
if (require_booleanFns.hasAnyMetadata(t.value)) require_booleanFns.propagateMetadataThroughRelocation(t.value, moved);
|
|
3126
|
+
return require_errors.ok(require_booleanFns.colorShape(moved, [...node.color]));
|
|
3127
3127
|
}
|
|
3128
3128
|
// src/csg/evaluators/fillet.ts
|
|
3129
3129
|
function evalFillet(node, ctx) {
|
|
@@ -7200,49 +7200,8 @@ async function importDXF(blob, options) {
|
|
|
7200
7200
|
for (const edge of edges) kernel.dispose(edge);
|
|
7201
7201
|
}
|
|
7202
7202
|
}
|
|
7203
|
-
// src/io/ioUtils.ts
|
|
7204
|
-
/**
|
|
7205
|
-
* Shared mesh-to-solid sewing utilities for mesh importers.
|
|
7206
|
-
*
|
|
7207
|
-
* Builds triangular B-Rep faces from vertex/index data and sews them into
|
|
7208
|
-
* a solid, with a fallback to a shell when solidification fails.
|
|
7209
|
-
*/
|
|
7210
|
-
/**
|
|
7211
|
-
* Build triangular B-Rep faces from vertex data and sew them into a solid.
|
|
7212
|
-
*
|
|
7213
|
-
* For each triple of vertex coordinates, calls `kernel.buildTriFace` to create
|
|
7214
|
-
* a planar triangular face, then attempts `sewAndSolidify`. If solidification
|
|
7215
|
-
* fails, falls back to `sew` (returning a shell or compound).
|
|
7216
|
-
*
|
|
7217
|
-
* @param triangles - Array of vertex triples, each triple being three [x,y,z] tuples.
|
|
7218
|
-
* @param errorCode - The error code to use in any returned errors.
|
|
7219
|
-
* @param tolerance - Sewing tolerance (default 1e-6).
|
|
7220
|
-
* @returns A `Result` wrapping the sewn shape, or an error.
|
|
7221
|
-
*/
|
|
7222
|
-
function sewMeshToSolid(triangles, errorCode, tolerance = 1e-6) {
|
|
7223
|
-
const kernel = require_shapeTypes.getKernel();
|
|
7224
|
-
const triFaces = [];
|
|
7225
|
-
for (const [va, vb, vc] of triangles) {
|
|
7226
|
-
const triFace = kernel.buildTriFace(va, vb, vc);
|
|
7227
|
-
if (triFace !== null) triFaces.push(triFace);
|
|
7228
|
-
}
|
|
7229
|
-
if (triFaces.length === 0) return require_errors.err(require_errors.ioError(errorCode, "No valid triangular faces could be built"));
|
|
7230
|
-
try {
|
|
7231
|
-
const solid = kernel.sewAndSolidify(triFaces, tolerance);
|
|
7232
|
-
const cast = require_shapeTypes.castResultShape(solid);
|
|
7233
|
-
for (const triFace of triFaces) kernel.dispose(triFace);
|
|
7234
|
-
return require_errors.ok(cast);
|
|
7235
|
-
} catch {
|
|
7236
|
-
try {
|
|
7237
|
-
return require_errors.ok(require_shapeTypes.castShape(kernel.sew(triFaces, tolerance)));
|
|
7238
|
-
} catch (e) {
|
|
7239
|
-
return require_errors.err(require_errors.ioError(errorCode, "Failed to sew triangular faces", e));
|
|
7240
|
-
}
|
|
7241
|
-
}
|
|
7242
|
-
}
|
|
7243
7203
|
// src/io/objImportFns.ts
|
|
7244
|
-
function
|
|
7245
|
-
const parts = line.split(/\s+/);
|
|
7204
|
+
function parseVertex(parts) {
|
|
7246
7205
|
const x = parseFloat(parts[1] ?? "");
|
|
7247
7206
|
const y = parseFloat(parts[2] ?? "");
|
|
7248
7207
|
const z = parseFloat(parts[3] ?? "");
|
|
@@ -7253,8 +7212,18 @@ function parseVertexLine(line) {
|
|
|
7253
7212
|
z
|
|
7254
7213
|
];
|
|
7255
7214
|
}
|
|
7256
|
-
|
|
7257
|
-
|
|
7215
|
+
/**
|
|
7216
|
+
* Face corners as 0-based vertex indices. A negative OBJ index counts back from
|
|
7217
|
+
* the vertices defined so far, so it resolves against `vertexCount` at this line.
|
|
7218
|
+
*/
|
|
7219
|
+
function parseFaceIndices(parts, vertexCount) {
|
|
7220
|
+
const indices = [];
|
|
7221
|
+
for (const part of parts.slice(1)) {
|
|
7222
|
+
const raw = parseInt(part.split("/")[0] ?? "", 10);
|
|
7223
|
+
if (isNaN(raw)) continue;
|
|
7224
|
+
indices.push(raw > 0 ? raw - 1 : raw < 0 ? vertexCount + raw : -1);
|
|
7225
|
+
}
|
|
7226
|
+
return indices;
|
|
7258
7227
|
}
|
|
7259
7228
|
/**
|
|
7260
7229
|
* Import a Wavefront OBJ file from a Blob.
|
|
@@ -7276,12 +7245,12 @@ async function importOBJ(blob) {
|
|
|
7276
7245
|
const vertices = [];
|
|
7277
7246
|
const faces = [];
|
|
7278
7247
|
for (const raw of lines) {
|
|
7279
|
-
const
|
|
7280
|
-
if (
|
|
7281
|
-
const vertex =
|
|
7248
|
+
const parts = raw.trim().split(/\s+/);
|
|
7249
|
+
if (parts[0] === "v") {
|
|
7250
|
+
const vertex = parseVertex(parts);
|
|
7282
7251
|
if (vertex) vertices.push(vertex);
|
|
7283
|
-
} else if (
|
|
7284
|
-
const indices = parseFaceIndices(
|
|
7252
|
+
} else if (parts[0] === "f") {
|
|
7253
|
+
const indices = parseFaceIndices(parts, vertices.length);
|
|
7285
7254
|
if (indices.length >= 3) faces.push(indices);
|
|
7286
7255
|
}
|
|
7287
7256
|
}
|
|
@@ -7296,15 +7265,9 @@ async function importOBJ(blob) {
|
|
|
7296
7265
|
function buildSolidFromMesh$1(vertices, faces) {
|
|
7297
7266
|
const triangles = [];
|
|
7298
7267
|
for (const face of faces) for (let i = 1; i < face.length - 1; i++) {
|
|
7299
|
-
const
|
|
7300
|
-
const
|
|
7301
|
-
const
|
|
7302
|
-
const ai = rawA > 0 ? rawA - 1 : vertices.length + rawA;
|
|
7303
|
-
const bi = rawB > 0 ? rawB - 1 : vertices.length + rawB;
|
|
7304
|
-
const ci = rawC > 0 ? rawC - 1 : vertices.length + rawC;
|
|
7305
|
-
const va = vertices[ai];
|
|
7306
|
-
const vb = vertices[bi];
|
|
7307
|
-
const vc = vertices[ci];
|
|
7268
|
+
const va = vertices[face[0] ?? -1];
|
|
7269
|
+
const vb = vertices[face[i] ?? -1];
|
|
7270
|
+
const vc = vertices[face[i + 1] ?? -1];
|
|
7308
7271
|
if (!va || !vb || !vc) continue;
|
|
7309
7272
|
triangles.push([
|
|
7310
7273
|
va,
|
|
@@ -7312,11 +7275,11 @@ function buildSolidFromMesh$1(vertices, faces) {
|
|
|
7312
7275
|
vc
|
|
7313
7276
|
]);
|
|
7314
7277
|
}
|
|
7315
|
-
return sewMeshToSolid(triangles, require_errors.BrepErrorCode.OBJ_IMPORT_FAILED);
|
|
7278
|
+
return require_importFns.sewMeshToSolid(triangles, require_errors.BrepErrorCode.OBJ_IMPORT_FAILED);
|
|
7316
7279
|
}
|
|
7317
7280
|
// src/io/threemfImportFns.ts
|
|
7318
7281
|
/**
|
|
7319
|
-
* 3MF import
|
|
7282
|
+
* 3MF import: parses a 3MF ZIP archive and builds one solid per placed object via sewing.
|
|
7320
7283
|
*/
|
|
7321
7284
|
function extractFromZip(data, target) {
|
|
7322
7285
|
let eocdOffset = -1;
|
|
@@ -7348,6 +7311,26 @@ function extractFromZip(data, target) {
|
|
|
7348
7311
|
}
|
|
7349
7312
|
return null;
|
|
7350
7313
|
}
|
|
7314
|
+
/** Millimeters per model unit, keyed by the values the 3MF `unit` attribute allows. */
|
|
7315
|
+
var MM_PER_UNIT = {
|
|
7316
|
+
micron: .001,
|
|
7317
|
+
millimeter: 1,
|
|
7318
|
+
centimeter: 10,
|
|
7319
|
+
inch: 25.4,
|
|
7320
|
+
foot: 304.8,
|
|
7321
|
+
meter: 1e3
|
|
7322
|
+
};
|
|
7323
|
+
/**
|
|
7324
|
+
* Components nest and repeat, so a few KB of XML can describe billions of
|
|
7325
|
+
* placements; stop expanding long before that exhausts memory.
|
|
7326
|
+
*/
|
|
7327
|
+
var MAX_PLACED_OBJECTS = 1e5;
|
|
7328
|
+
/** At roughly 2.5 s per 10,000 sewn triangles, more than this would take hours to build. */
|
|
7329
|
+
var MAX_PLACED_TRIANGLES = 2e6;
|
|
7330
|
+
/** Each placement copies its object's vertices; three per triangle fits any mesh under the triangle limit. */
|
|
7331
|
+
var MAX_PLACED_VERTICES = 3 * MAX_PLACED_TRIANGLES;
|
|
7332
|
+
/** Assemblies nest a few levels deep; a far deeper chain only serves to exhaust the stack. */
|
|
7333
|
+
var MAX_COMPONENT_DEPTH = 64;
|
|
7351
7334
|
/** Check if a char code is a valid XML attribute name character [a-zA-Z0-9_]. */
|
|
7352
7335
|
function isAttrChar(code) {
|
|
7353
7336
|
return code >= 97 && code <= 122 || code >= 65 && code <= 90 || code >= 48 && code <= 57 || code === 95;
|
|
@@ -7374,13 +7357,27 @@ function parseTagAttrs(tag) {
|
|
|
7374
7357
|
}
|
|
7375
7358
|
return attrs;
|
|
7376
7359
|
}
|
|
7360
|
+
/** True when `<tagName` at `start` names that exact element (not a longer one like `<vertices`). */
|
|
7361
|
+
function isTagStart(xml, start, tagName) {
|
|
7362
|
+
const next = xml.charCodeAt(start + tagName.length + 1);
|
|
7363
|
+
return next === 32 || next === 9 || next === 10 || next === 13 || next === 47 || next === 62;
|
|
7364
|
+
}
|
|
7365
|
+
/** Index of the next `<tagName` start tag at or after `from`, or -1. */
|
|
7366
|
+
function indexOfTag(xml, tagName, from) {
|
|
7367
|
+
const needle = `<${tagName}`;
|
|
7368
|
+
let pos = from;
|
|
7369
|
+
for (;;) {
|
|
7370
|
+
const start = xml.indexOf(needle, pos);
|
|
7371
|
+
if (start < 0 || isTagStart(xml, start, tagName)) return start;
|
|
7372
|
+
pos = start + needle.length;
|
|
7373
|
+
}
|
|
7374
|
+
}
|
|
7377
7375
|
/** Collect all tags matching `<tagName ...>` using indexOf (O(n), no regex). */
|
|
7378
7376
|
function findTags(xml, tagName) {
|
|
7379
7377
|
const tags = [];
|
|
7380
|
-
const needle = `<${tagName} `;
|
|
7381
7378
|
let pos = 0;
|
|
7382
7379
|
while (pos < xml.length) {
|
|
7383
|
-
const start = xml
|
|
7380
|
+
const start = indexOfTag(xml, tagName, pos);
|
|
7384
7381
|
if (start < 0) break;
|
|
7385
7382
|
const end = xml.indexOf(">", start);
|
|
7386
7383
|
if (end < 0) break;
|
|
@@ -7390,15 +7387,36 @@ function findTags(xml, tagName) {
|
|
|
7390
7387
|
return tags;
|
|
7391
7388
|
}
|
|
7392
7389
|
/**
|
|
7393
|
-
*
|
|
7394
|
-
*
|
|
7390
|
+
* Collect every `<tagName ...>...</tagName>` element as its start tag plus inner
|
|
7391
|
+
* content. A self-closing `<tagName ... />` yields an empty body.
|
|
7395
7392
|
*/
|
|
7396
|
-
function
|
|
7397
|
-
const
|
|
7398
|
-
|
|
7399
|
-
|
|
7400
|
-
|
|
7401
|
-
|
|
7393
|
+
function findElements(xml, tagName) {
|
|
7394
|
+
const elements = [];
|
|
7395
|
+
const close = `</${tagName}>`;
|
|
7396
|
+
let pos = 0;
|
|
7397
|
+
while (pos < xml.length) {
|
|
7398
|
+
const start = indexOfTag(xml, tagName, pos);
|
|
7399
|
+
if (start < 0) break;
|
|
7400
|
+
const tagEnd = xml.indexOf(">", start);
|
|
7401
|
+
if (tagEnd < 0) break;
|
|
7402
|
+
const tag = xml.slice(start, tagEnd + 1);
|
|
7403
|
+
if (xml.charCodeAt(tagEnd - 1) === 47) {
|
|
7404
|
+
elements.push({
|
|
7405
|
+
tag,
|
|
7406
|
+
body: ""
|
|
7407
|
+
});
|
|
7408
|
+
pos = tagEnd + 1;
|
|
7409
|
+
continue;
|
|
7410
|
+
}
|
|
7411
|
+
const closeAt = xml.indexOf(close, tagEnd);
|
|
7412
|
+
if (closeAt < 0) break;
|
|
7413
|
+
elements.push({
|
|
7414
|
+
tag,
|
|
7415
|
+
body: xml.slice(tagEnd + 1, closeAt)
|
|
7416
|
+
});
|
|
7417
|
+
pos = closeAt + close.length;
|
|
7418
|
+
}
|
|
7419
|
+
return elements;
|
|
7402
7420
|
}
|
|
7403
7421
|
/** Parse a hex color string like #RRGGBB or #RRGGBBAA into [r,g,b,a] floats. */
|
|
7404
7422
|
function parseHexColor(hex) {
|
|
@@ -7464,12 +7482,11 @@ function parseResourceColors(xml) {
|
|
|
7464
7482
|
}
|
|
7465
7483
|
return resources;
|
|
7466
7484
|
}
|
|
7467
|
-
function
|
|
7485
|
+
function parseMesh(body, objectAttrs, resourceColors) {
|
|
7468
7486
|
const vertices = [];
|
|
7469
7487
|
const triangles = [];
|
|
7470
7488
|
const triangleColors = [];
|
|
7471
|
-
const
|
|
7472
|
-
for (const tag of findTags(xml, "vertex")) {
|
|
7489
|
+
for (const tag of findTags(body, "vertex")) {
|
|
7473
7490
|
const a = parseTagAttrs(tag);
|
|
7474
7491
|
if (a["x"] !== void 0 && a["y"] !== void 0 && a["z"] !== void 0) vertices.push([
|
|
7475
7492
|
parseFloat(a["x"]),
|
|
@@ -7477,18 +7494,7 @@ function parseModelXml(xml) {
|
|
|
7477
7494
|
parseFloat(a["z"])
|
|
7478
7495
|
]);
|
|
7479
7496
|
}
|
|
7480
|
-
|
|
7481
|
-
let objectDefaultPindex = null;
|
|
7482
|
-
const objectBlock = findTagBlock(xml, "object");
|
|
7483
|
-
if (objectBlock !== null) {
|
|
7484
|
-
const objTagEnd = objectBlock.indexOf(">");
|
|
7485
|
-
if (objTagEnd >= 0) {
|
|
7486
|
-
const objAttrs = parseTagAttrs(objectBlock.slice(0, objTagEnd + 1));
|
|
7487
|
-
if (objAttrs["pid"] !== void 0) objectDefaultPid = parseInt(objAttrs["pid"], 10);
|
|
7488
|
-
if (objAttrs["pindex"] !== void 0) objectDefaultPindex = parseInt(objAttrs["pindex"], 10);
|
|
7489
|
-
}
|
|
7490
|
-
}
|
|
7491
|
-
for (const tag of findTags(xml, "triangle")) {
|
|
7497
|
+
for (const tag of findTags(body, "triangle")) {
|
|
7492
7498
|
const a = parseTagAttrs(tag);
|
|
7493
7499
|
if (a["v1"] !== void 0 && a["v2"] !== void 0 && a["v3"] !== void 0) {
|
|
7494
7500
|
triangles.push([
|
|
@@ -7497,8 +7503,8 @@ function parseModelXml(xml) {
|
|
|
7497
7503
|
parseInt(a["v3"], 10)
|
|
7498
7504
|
]);
|
|
7499
7505
|
let color = null;
|
|
7500
|
-
const pidStr = a["pid"] ??
|
|
7501
|
-
const p1Str = a["p1"] ??
|
|
7506
|
+
const pidStr = a["pid"] ?? objectAttrs["pid"];
|
|
7507
|
+
const p1Str = a["p1"] ?? objectAttrs["pindex"];
|
|
7502
7508
|
if (pidStr !== void 0 && p1Str !== void 0) {
|
|
7503
7509
|
const pid = parseInt(pidStr, 10);
|
|
7504
7510
|
const p1 = parseInt(p1Str, 10);
|
|
@@ -7514,6 +7520,135 @@ function parseModelXml(xml) {
|
|
|
7514
7520
|
triangleColors
|
|
7515
7521
|
};
|
|
7516
7522
|
}
|
|
7523
|
+
function parseTransform(value) {
|
|
7524
|
+
if (value === void 0) return null;
|
|
7525
|
+
const m = value.trim().split(/\s+/).map(Number);
|
|
7526
|
+
return m.length === 12 && m.every(Number.isFinite) ? m : null;
|
|
7527
|
+
}
|
|
7528
|
+
function parseObjectRefs(tags) {
|
|
7529
|
+
const refs = [];
|
|
7530
|
+
for (const tag of tags) {
|
|
7531
|
+
const a = parseTagAttrs(tag);
|
|
7532
|
+
const objectId = a["objectid"];
|
|
7533
|
+
if (objectId !== void 0) refs.push({
|
|
7534
|
+
objectId,
|
|
7535
|
+
transform: parseTransform(a["transform"])
|
|
7536
|
+
});
|
|
7537
|
+
}
|
|
7538
|
+
return refs;
|
|
7539
|
+
}
|
|
7540
|
+
/** `inner` then `outer`: with row vectors that is the matrix product inner × outer. */
|
|
7541
|
+
function composeTransforms$1(inner, outer) {
|
|
7542
|
+
if (inner === null) return outer;
|
|
7543
|
+
if (outer === null) return inner;
|
|
7544
|
+
const out = [];
|
|
7545
|
+
for (let row = 0; row < 4; row++) for (let col = 0; col < 3; col++) {
|
|
7546
|
+
let sum = row === 3 ? outer[9 + col] ?? 0 : 0;
|
|
7547
|
+
for (let k = 0; k < 3; k++) sum += (inner[row * 3 + k] ?? 0) * (outer[k * 3 + col] ?? 0);
|
|
7548
|
+
out.push(sum);
|
|
7549
|
+
}
|
|
7550
|
+
return out;
|
|
7551
|
+
}
|
|
7552
|
+
function transformMesh(mesh, m) {
|
|
7553
|
+
if (m === null) return mesh;
|
|
7554
|
+
const [m0 = 0, m1 = 0, m2 = 0, m3 = 0, m4 = 0, m5 = 0, m6 = 0, m7 = 0, m8 = 0] = m;
|
|
7555
|
+
const [m9 = 0, m10 = 0, m11 = 0] = m.slice(9);
|
|
7556
|
+
return {
|
|
7557
|
+
vertices: mesh.vertices.map(([x, y, z]) => [
|
|
7558
|
+
x * m0 + y * m3 + z * m6 + m9,
|
|
7559
|
+
x * m1 + y * m4 + z * m7 + m10,
|
|
7560
|
+
x * m2 + y * m5 + z * m8 + m11
|
|
7561
|
+
]),
|
|
7562
|
+
triangles: m0 * (m4 * m8 - m5 * m7) - m1 * (m3 * m8 - m5 * m6) + m2 * (m3 * m7 - m4 * m6) < 0 ? mesh.triangles.map(([a, b, c]) => [
|
|
7563
|
+
a,
|
|
7564
|
+
c,
|
|
7565
|
+
b
|
|
7566
|
+
]) : mesh.triangles,
|
|
7567
|
+
triangleColors: mesh.triangleColors
|
|
7568
|
+
};
|
|
7569
|
+
}
|
|
7570
|
+
/** Place `ref` and its components into `out`; returns why it stopped early, or `null`. */
|
|
7571
|
+
function instantiate(objects, ref, outer, ancestors, out) {
|
|
7572
|
+
const object = objects.get(ref.objectId);
|
|
7573
|
+
if (object === void 0 || ancestors.has(ref.objectId)) return null;
|
|
7574
|
+
if (ancestors.size > MAX_COMPONENT_DEPTH) return `components nest more than ${MAX_COMPONENT_DEPTH} levels deep`;
|
|
7575
|
+
if (++out.objects > MAX_PLACED_OBJECTS) return `the build places more than ${MAX_PLACED_OBJECTS.toLocaleString("en-US")} objects`;
|
|
7576
|
+
const transform = composeTransforms$1(ref.transform, outer);
|
|
7577
|
+
if (object.mesh !== null && object.mesh.triangles.length > 0) {
|
|
7578
|
+
out.triangles += object.mesh.triangles.length;
|
|
7579
|
+
if (out.triangles > MAX_PLACED_TRIANGLES) return `the build places more than ${MAX_PLACED_TRIANGLES.toLocaleString("en-US")} triangles`;
|
|
7580
|
+
out.vertices += object.mesh.vertices.length;
|
|
7581
|
+
if (out.vertices > MAX_PLACED_VERTICES) return `the build places more than ${MAX_PLACED_VERTICES.toLocaleString("en-US")} vertices`;
|
|
7582
|
+
out.meshes.push(transformMesh(object.mesh, transform));
|
|
7583
|
+
}
|
|
7584
|
+
ancestors.add(ref.objectId);
|
|
7585
|
+
try {
|
|
7586
|
+
for (const component of object.components) {
|
|
7587
|
+
const stopped = instantiate(objects, component, transform, ancestors, out);
|
|
7588
|
+
if (stopped !== null) return stopped;
|
|
7589
|
+
}
|
|
7590
|
+
} finally {
|
|
7591
|
+
ancestors.delete(ref.objectId);
|
|
7592
|
+
}
|
|
7593
|
+
return null;
|
|
7594
|
+
}
|
|
7595
|
+
/**
|
|
7596
|
+
* Parse the model XML into one mesh per placed object, in millimeters.
|
|
7597
|
+
*
|
|
7598
|
+
* Each object keeps its own vertex list (triangle indices are per object), build
|
|
7599
|
+
* items and components contribute their transforms, and the model `unit` scales
|
|
7600
|
+
* coordinates to millimeters. Fails once the build expands past
|
|
7601
|
+
* {@link MAX_PLACED_OBJECTS} placements, {@link MAX_PLACED_TRIANGLES} triangles,
|
|
7602
|
+
* or {@link MAX_PLACED_VERTICES} vertices, or nests deeper than
|
|
7603
|
+
* {@link MAX_COMPONENT_DEPTH} levels.
|
|
7604
|
+
*/
|
|
7605
|
+
function parseModelXml(xml) {
|
|
7606
|
+
const resourceColors = parseResourceColors(xml);
|
|
7607
|
+
const modelTag = findTags(xml, "model")[0];
|
|
7608
|
+
const mm = MM_PER_UNIT[(modelTag !== void 0 ? parseTagAttrs(modelTag)["unit"] : void 0) ?? "millimeter"] ?? 1;
|
|
7609
|
+
const toMillimeters = mm === 1 ? null : [
|
|
7610
|
+
mm,
|
|
7611
|
+
0,
|
|
7612
|
+
0,
|
|
7613
|
+
0,
|
|
7614
|
+
mm,
|
|
7615
|
+
0,
|
|
7616
|
+
0,
|
|
7617
|
+
0,
|
|
7618
|
+
mm,
|
|
7619
|
+
0,
|
|
7620
|
+
0,
|
|
7621
|
+
0
|
|
7622
|
+
];
|
|
7623
|
+
const objects = /* @__PURE__ */ new Map();
|
|
7624
|
+
for (const { tag, body } of findElements(xml, "object")) {
|
|
7625
|
+
const attrs = parseTagAttrs(tag);
|
|
7626
|
+
const id = attrs["id"];
|
|
7627
|
+
if (id === void 0) continue;
|
|
7628
|
+
const meshElement = findElements(body, "mesh")[0];
|
|
7629
|
+
objects.set(id, {
|
|
7630
|
+
mesh: meshElement ? parseMesh(meshElement.body, attrs, resourceColors) : null,
|
|
7631
|
+
components: parseObjectRefs(findTags(body, "component"))
|
|
7632
|
+
});
|
|
7633
|
+
}
|
|
7634
|
+
const build = findElements(xml, "build")[0];
|
|
7635
|
+
let items = build ? parseObjectRefs(findTags(build.body, "item")) : [];
|
|
7636
|
+
if (items.length === 0) items = [...objects].filter(([, object]) => object.mesh !== null).map(([objectId]) => ({
|
|
7637
|
+
objectId,
|
|
7638
|
+
transform: null
|
|
7639
|
+
}));
|
|
7640
|
+
const expansion = {
|
|
7641
|
+
meshes: [],
|
|
7642
|
+
objects: 0,
|
|
7643
|
+
triangles: 0,
|
|
7644
|
+
vertices: 0
|
|
7645
|
+
};
|
|
7646
|
+
for (const item of items) {
|
|
7647
|
+
const stopped = instantiate(objects, item, toMillimeters, /* @__PURE__ */ new Set(), expansion);
|
|
7648
|
+
if (stopped !== null) return require_errors.err(require_errors.ioError(require_errors.BrepErrorCode.THREEMF_IMPORT_FAILED, `3MF model is too large to import: ${stopped}`));
|
|
7649
|
+
}
|
|
7650
|
+
return require_errors.ok(expansion.meshes.filter((m) => m.vertices.length > 0 && m.triangles.length > 0));
|
|
7651
|
+
}
|
|
7517
7652
|
/** Find the most common non-null color across all triangle colors. */
|
|
7518
7653
|
function findDominantColor(triangleColors) {
|
|
7519
7654
|
const counts = /* @__PURE__ */ new Map();
|
|
@@ -7555,17 +7690,37 @@ function buildSolidFromMesh(mesh) {
|
|
|
7555
7690
|
vc
|
|
7556
7691
|
]);
|
|
7557
7692
|
}
|
|
7558
|
-
return sewMeshToSolid(triangles, require_errors.BrepErrorCode.THREEMF_IMPORT_FAILED);
|
|
7693
|
+
return require_importFns.sewMeshToSolid(triangles, require_errors.BrepErrorCode.THREEMF_IMPORT_FAILED);
|
|
7559
7694
|
}
|
|
7560
7695
|
}
|
|
7696
|
+
/** One solid per mesh; several are grouped into a compound that takes ownership of them. */
|
|
7697
|
+
function buildShapeFromMeshes(meshes) {
|
|
7698
|
+
const solids = [];
|
|
7699
|
+
for (const mesh of meshes) {
|
|
7700
|
+
const solid = buildSolidFromMesh(mesh);
|
|
7701
|
+
if (!solid.ok) {
|
|
7702
|
+
for (const built of solids) built[Symbol.dispose]();
|
|
7703
|
+
return solid;
|
|
7704
|
+
}
|
|
7705
|
+
solids.push(solid.value);
|
|
7706
|
+
}
|
|
7707
|
+
const [first] = solids;
|
|
7708
|
+
if (solids.length === 1 && first !== void 0) return require_errors.ok(first);
|
|
7709
|
+
const compound = require_solidBuilders.makeCompound(solids);
|
|
7710
|
+
for (const built of solids) built[Symbol.dispose]();
|
|
7711
|
+
return require_errors.ok(compound);
|
|
7712
|
+
}
|
|
7561
7713
|
/**
|
|
7562
7714
|
* Import a 3MF file from a Blob.
|
|
7563
7715
|
*
|
|
7564
|
-
* Extracts the model XML from the ZIP archive
|
|
7565
|
-
*
|
|
7716
|
+
* Extracts the model XML from the ZIP archive and builds one solid per placed
|
|
7717
|
+
* object by sewing its triangles. Build-item and component transforms are
|
|
7718
|
+
* applied, and coordinates are scaled from the model `unit` to millimeters.
|
|
7566
7719
|
*
|
|
7567
7720
|
* @param blob - A Blob or File containing 3MF data (.3mf).
|
|
7568
|
-
* @returns A `Result` wrapping the imported solid
|
|
7721
|
+
* @returns A `Result` wrapping the imported solid (a `Compound` of solids when the
|
|
7722
|
+
* build places several objects), or an error if parsing fails or the build
|
|
7723
|
+
* expands to more than 100,000 placed objects or 2,000,000 triangles.
|
|
7569
7724
|
*
|
|
7570
7725
|
* @example
|
|
7571
7726
|
* ```ts
|
|
@@ -7579,13 +7734,15 @@ async function importThreeMF(blob) {
|
|
|
7579
7734
|
const modelData = extractFromZip(new Uint8Array(arrayBuf), "3D/3dmodel.model");
|
|
7580
7735
|
if (!modelData) return require_errors.err(require_errors.ioError(require_errors.BrepErrorCode.THREEMF_IMPORT_FAILED, "3MF archive does not contain 3D/3dmodel.model (or uses unsupported compression)"));
|
|
7581
7736
|
const parsed = parseModelXml(new TextDecoder().decode(modelData));
|
|
7582
|
-
if (parsed.
|
|
7583
|
-
const
|
|
7584
|
-
if (
|
|
7585
|
-
|
|
7586
|
-
|
|
7737
|
+
if (!parsed.ok) return parsed;
|
|
7738
|
+
const meshes = parsed.value;
|
|
7739
|
+
if (meshes.length === 0) return require_errors.err(require_errors.ioError(require_errors.BrepErrorCode.THREEMF_IMPORT_FAILED, "3MF model contains no valid geometry"));
|
|
7740
|
+
const shape = buildShapeFromMeshes(meshes);
|
|
7741
|
+
if (shape.ok) {
|
|
7742
|
+
const dominantColor = findDominantColor(meshes.flatMap((m) => m.triangleColors));
|
|
7743
|
+
if (dominantColor !== null) require_booleanFns.colorShape(shape.value, dominantColor);
|
|
7587
7744
|
}
|
|
7588
|
-
return
|
|
7745
|
+
return shape;
|
|
7589
7746
|
} catch (e) {
|
|
7590
7747
|
const msg = e instanceof Error ? e.message : String(e);
|
|
7591
7748
|
return require_errors.err(require_errors.ioError(require_errors.BrepErrorCode.THREEMF_IMPORT_FAILED, `3MF import failed: ${msg}`, e));
|
|
@@ -7690,54 +7847,54 @@ function locate(shape, placement) {
|
|
|
7690
7847
|
}
|
|
7691
7848
|
/** Fuse two 3D shapes (boolean union). */
|
|
7692
7849
|
function fuse(a, b, options) {
|
|
7693
|
-
return
|
|
7850
|
+
return require_booleanFns.fuse(resolve(a), resolve(b), {
|
|
7694
7851
|
...options,
|
|
7695
7852
|
unsafe: true
|
|
7696
7853
|
});
|
|
7697
7854
|
}
|
|
7698
7855
|
/** Cut a tool from a base shape (boolean subtraction). */
|
|
7699
7856
|
function cut(base, tool, options) {
|
|
7700
|
-
return
|
|
7857
|
+
return require_booleanFns.cut(resolve(base), resolve(tool), {
|
|
7701
7858
|
...options,
|
|
7702
7859
|
unsafe: true
|
|
7703
7860
|
});
|
|
7704
7861
|
}
|
|
7705
7862
|
/** Fuse many 3D shapes (boolean union) in a single operation. */
|
|
7706
7863
|
function fuseAll(shapes, options) {
|
|
7707
|
-
return
|
|
7864
|
+
return require_booleanFns.fuseAll(shapes.map((s) => resolve(s)), {
|
|
7708
7865
|
...options,
|
|
7709
7866
|
unsafe: true
|
|
7710
7867
|
});
|
|
7711
7868
|
}
|
|
7712
7869
|
/** Cut many tool shapes from a base shape (boolean subtraction) in a single operation. */
|
|
7713
7870
|
function cutAll(base, tools, options) {
|
|
7714
|
-
return
|
|
7871
|
+
return require_booleanFns.cutAll(resolve(base), tools.map((s) => resolve(s)), {
|
|
7715
7872
|
...options,
|
|
7716
7873
|
unsafe: true
|
|
7717
7874
|
});
|
|
7718
7875
|
}
|
|
7719
7876
|
/** Compute the intersection of two shapes (boolean common). */
|
|
7720
7877
|
function intersect(a, b, options) {
|
|
7721
|
-
return
|
|
7878
|
+
return require_booleanFns.intersect(resolve(a), resolve(b), {
|
|
7722
7879
|
...options,
|
|
7723
7880
|
unsafe: true
|
|
7724
7881
|
});
|
|
7725
7882
|
}
|
|
7726
7883
|
/** Section (cross-section) a shape with a plane. */
|
|
7727
7884
|
function section(shape, plane, options) {
|
|
7728
|
-
return
|
|
7885
|
+
return require_booleanFns.section(resolve(shape), plane, options);
|
|
7729
7886
|
}
|
|
7730
7887
|
/** Section a shape with a plane and return a filled Face. */
|
|
7731
7888
|
function sectionToFace(shape, plane, options) {
|
|
7732
|
-
return
|
|
7889
|
+
return require_booleanFns.sectionToFace(resolve(shape), plane, options);
|
|
7733
7890
|
}
|
|
7734
7891
|
/** Split a shape with tool shapes. */
|
|
7735
7892
|
function split(shape, tools) {
|
|
7736
|
-
return
|
|
7893
|
+
return require_booleanFns.split(resolve(shape), tools);
|
|
7737
7894
|
}
|
|
7738
7895
|
/** Slice a shape with multiple planes. */
|
|
7739
7896
|
function slice(shape, planes, options) {
|
|
7740
|
-
return
|
|
7897
|
+
return require_booleanFns.slice(resolve(shape), planes, options);
|
|
7741
7898
|
}
|
|
7742
7899
|
/**
|
|
7743
7900
|
* Resolve a FinderFn callback or ShapeFinder into an array of elements.
|
|
@@ -8109,7 +8266,7 @@ function drill(shape, options) {
|
|
|
8109
8266
|
tool = require_solidBuilders.makeCylinder(radius, depth, startPos, dir);
|
|
8110
8267
|
}
|
|
8111
8268
|
try {
|
|
8112
|
-
return
|
|
8269
|
+
return require_booleanFns.cut(s, tool, { unsafe: true });
|
|
8113
8270
|
} finally {
|
|
8114
8271
|
tool[Symbol.dispose]();
|
|
8115
8272
|
}
|
|
@@ -8129,7 +8286,7 @@ function pocket(shape, options) {
|
|
|
8129
8286
|
const toolResult = profileTool(s, options.face, profile, -depth);
|
|
8130
8287
|
if (require_errors.isErr(toolResult)) return toolResult;
|
|
8131
8288
|
const tool = _usingCtx3.u(toolResult.value);
|
|
8132
|
-
return
|
|
8289
|
+
return require_booleanFns.cut(s, tool, { unsafe: true });
|
|
8133
8290
|
} catch (_) {
|
|
8134
8291
|
_usingCtx3.e = _;
|
|
8135
8292
|
} finally {
|
|
@@ -8151,7 +8308,7 @@ function boss(shape, options) {
|
|
|
8151
8308
|
const toolResult = profileTool(s, options.face, profile, height);
|
|
8152
8309
|
if (require_errors.isErr(toolResult)) return toolResult;
|
|
8153
8310
|
const tool = _usingCtx4.u(toolResult.value);
|
|
8154
|
-
return
|
|
8311
|
+
return require_booleanFns.fuse(s, tool, { unsafe: true });
|
|
8155
8312
|
} catch (_) {
|
|
8156
8313
|
_usingCtx4.e = _;
|
|
8157
8314
|
} finally {
|
|
@@ -8175,7 +8332,7 @@ function mirrorJoin(shape, options) {
|
|
|
8175
8332
|
const planeOrigin = options?.at;
|
|
8176
8333
|
if (require_vecOps.vecIsZero(normal)) return require_errors.err(require_errors.validationError("MIRROR_ZERO_NORMAL", "Mirror plane normal cannot be zero"));
|
|
8177
8334
|
const mirrored = _usingCtx5.u(require_primitiveFns.mirror(s, normal, planeOrigin));
|
|
8178
|
-
return
|
|
8335
|
+
return require_booleanFns.fuse(s, mirrored, { unsafe: true });
|
|
8179
8336
|
} catch (_) {
|
|
8180
8337
|
_usingCtx5.e = _;
|
|
8181
8338
|
} finally {
|
|
@@ -8211,7 +8368,7 @@ function rectangularPattern(shape, options) {
|
|
|
8211
8368
|
owned.push(c);
|
|
8212
8369
|
}
|
|
8213
8370
|
try {
|
|
8214
|
-
return
|
|
8371
|
+
return require_booleanFns.fuseAll(copies, { unsafe: true });
|
|
8215
8372
|
} finally {
|
|
8216
8373
|
for (const c of owned) c[Symbol.dispose]();
|
|
8217
8374
|
}
|
|
@@ -8330,11 +8487,11 @@ function create3DBooleans(val) {
|
|
|
8330
8487
|
...opts,
|
|
8331
8488
|
unsafe: true
|
|
8332
8489
|
}))),
|
|
8333
|
-
fuseAll: (tools, opts) => wrap3D(trustAsT(unwrapOrThrow(
|
|
8490
|
+
fuseAll: (tools, opts) => wrap3D(trustAsT(unwrapOrThrow(require_booleanFns.fuseAll([val, ...tools.map(resolve)], {
|
|
8334
8491
|
...opts,
|
|
8335
8492
|
unsafe: true
|
|
8336
8493
|
})))),
|
|
8337
|
-
cutAll: (tools, opts) => wrap3D(trustAsT(unwrapOrThrow(
|
|
8494
|
+
cutAll: (tools, opts) => wrap3D(trustAsT(unwrapOrThrow(require_booleanFns.cutAll(val, tools, {
|
|
8338
8495
|
...opts,
|
|
8339
8496
|
unsafe: true
|
|
8340
8497
|
})))),
|
|
@@ -8958,7 +9115,7 @@ function finalizeExternalSolid(wire, thickness, bore, geom, diagnostics) {
|
|
|
8958
9115
|
0,
|
|
8959
9116
|
-.5
|
|
8960
9117
|
]));
|
|
8961
|
-
const cutResult =
|
|
9118
|
+
const cutResult = require_booleanFns.cut(solidResult.value, boreSolid);
|
|
8962
9119
|
if (require_errors.isErr(cutResult)) return cutResult;
|
|
8963
9120
|
return require_errors.ok(buildGearResult(cutResult.value, geom, diagnostics));
|
|
8964
9121
|
} catch (_) {
|
|
@@ -9135,10 +9292,10 @@ var booleans_exports = /* @__PURE__ */ require_rolldown_runtime.__exportAll({
|
|
|
9135
9292
|
checkBoolean: () => require_healingFns.checkBoolean,
|
|
9136
9293
|
convexHull: () => convexHull,
|
|
9137
9294
|
cut: () => cut,
|
|
9138
|
-
cutAll: () =>
|
|
9295
|
+
cutAll: () => require_booleanFns.cutAll,
|
|
9139
9296
|
cutAllBisect: () => require_healingFns.cutAllBisect,
|
|
9140
9297
|
fuse: () => fuse,
|
|
9141
|
-
fuseAll: () =>
|
|
9298
|
+
fuseAll: () => require_booleanFns.fuseAll,
|
|
9142
9299
|
fuseAllBisect: () => require_healingFns.fuseAllBisect,
|
|
9143
9300
|
hull: () => hull,
|
|
9144
9301
|
intersect: () => intersect,
|
|
@@ -9362,7 +9519,7 @@ exports.autoHeal = require_healingFns.autoHeal;
|
|
|
9362
9519
|
exports.bezier = require_primitiveFns.bezier;
|
|
9363
9520
|
exports.blueprintToContour = blueprintToContour;
|
|
9364
9521
|
exports.blueprintToDXF = require_importFns.blueprintToDXF;
|
|
9365
|
-
exports.booleanPipeline =
|
|
9522
|
+
exports.booleanPipeline = require_booleanFns.booleanPipeline;
|
|
9366
9523
|
Object.defineProperty(exports, "booleans", {
|
|
9367
9524
|
enumerable: true,
|
|
9368
9525
|
get: function() {
|
|
@@ -9393,8 +9550,8 @@ exports.clone = clone;
|
|
|
9393
9550
|
exports.closedWire = require_validityTypes.closedWire;
|
|
9394
9551
|
exports.collect = require_errors.collect;
|
|
9395
9552
|
exports.collectShapes = require_threadFns.collectShapes;
|
|
9396
|
-
exports.colorFaces =
|
|
9397
|
-
exports.colorShape =
|
|
9553
|
+
exports.colorFaces = require_booleanFns.colorFaces;
|
|
9554
|
+
exports.colorShape = require_booleanFns.colorShape;
|
|
9398
9555
|
exports.complexExtrude = require_loftFns.complexExtrude;
|
|
9399
9556
|
exports.composeTransforms = require_primitiveFns.composeTransforms;
|
|
9400
9557
|
exports.compound = require_primitiveFns.compound;
|
|
@@ -9540,7 +9697,7 @@ exports.fill = require_surfaceBuilders.fill;
|
|
|
9540
9697
|
exports.filledFace = require_primitiveFns.filledFace;
|
|
9541
9698
|
exports.fillet = fillet;
|
|
9542
9699
|
exports.filletWithEvolution = require_healingFns.filletWithEvolution;
|
|
9543
|
-
exports.findFacesByTag =
|
|
9700
|
+
exports.findFacesByTag = require_booleanFns.findFacesByTag;
|
|
9544
9701
|
exports.findNode = require_threadFns.findNode;
|
|
9545
9702
|
exports.findStep = require_threadFns.findStep;
|
|
9546
9703
|
exports.fixSelfIntersection = require_healingFns.fixSelfIntersection;
|
|
@@ -9570,9 +9727,9 @@ exports.getCompSolids = require_topologyQueryFns.getCompSolids;
|
|
|
9570
9727
|
exports.getCurveType = require_curveFns.getCurveType;
|
|
9571
9728
|
exports.getDisposalStats = require_shapeTypes.getDisposalStats;
|
|
9572
9729
|
exports.getEdges = require_topologyQueryFns.getEdges;
|
|
9573
|
-
exports.getFaceColor =
|
|
9574
|
-
exports.getFaceOrigins =
|
|
9575
|
-
exports.getFaceTags =
|
|
9730
|
+
exports.getFaceColor = require_booleanFns.getFaceColor;
|
|
9731
|
+
exports.getFaceOrigins = require_solidBuilders.getFaceOrigins;
|
|
9732
|
+
exports.getFaceTags = require_booleanFns.getFaceTags;
|
|
9576
9733
|
exports.getFaces = require_topologyQueryFns.getFaces;
|
|
9577
9734
|
exports.getFont = require_textBlueprints.getFont;
|
|
9578
9735
|
exports.getHashCode = require_shapeFns.getHashCode;
|
|
@@ -9585,13 +9742,13 @@ exports.getNurbsSurfaceData = require_healingFns.getNurbsSurfaceData;
|
|
|
9585
9742
|
exports.getOrientation = require_curveFns.getOrientation;
|
|
9586
9743
|
exports.getOrientation2D = require_blueprintFns.getOrientation2D;
|
|
9587
9744
|
exports.getPerformanceStats = require_shapeTypes.getPerformanceStats;
|
|
9588
|
-
exports.getShapeColor =
|
|
9745
|
+
exports.getShapeColor = require_booleanFns.getShapeColor;
|
|
9589
9746
|
exports.getShapeKind = require_shapeTypes.getShapeKind;
|
|
9590
9747
|
exports.getShells = require_topologyQueryFns.getShells;
|
|
9591
9748
|
exports.getSingleFace = require_helpers.getSingleFace;
|
|
9592
9749
|
exports.getSolids = require_topologyQueryFns.getSolids;
|
|
9593
9750
|
exports.getSurfaceType = require_faceFns.getSurfaceType;
|
|
9594
|
-
exports.getTagMetadata =
|
|
9751
|
+
exports.getTagMetadata = require_booleanFns.getTagMetadata;
|
|
9595
9752
|
exports.getVertices = require_topologyQueryFns.getVertices;
|
|
9596
9753
|
exports.getVoxel = getVoxel;
|
|
9597
9754
|
exports.getWires = require_topologyQueryFns.getWires;
|
|
@@ -9862,8 +10019,8 @@ exports.serializeHistory = require_threadFns.serializeHistory;
|
|
|
9862
10019
|
exports.setFallbackFont = require_textBlueprints.setFallbackFont;
|
|
9863
10020
|
exports.setJointValue = require_threadFns.setJointValue;
|
|
9864
10021
|
exports.setJointValues = require_threadFns.setJointValues;
|
|
9865
|
-
exports.setShapeOrigin =
|
|
9866
|
-
exports.setTagMetadata =
|
|
10022
|
+
exports.setShapeOrigin = require_solidBuilders.setShapeOrigin;
|
|
10023
|
+
exports.setTagMetadata = require_booleanFns.setTagMetadata;
|
|
9867
10024
|
exports.sewShells = require_primitiveFns.sewShells;
|
|
9868
10025
|
exports.shape = shape;
|
|
9869
10026
|
exports.shapeToMeshInput = shapeToMeshInput;
|
|
@@ -9909,7 +10066,7 @@ exports.supportsProjection = supportsProjection;
|
|
|
9909
10066
|
exports.surfaceFromGrid = surfaceFromGrid;
|
|
9910
10067
|
exports.surfaceFromImage = surfaceFromImage;
|
|
9911
10068
|
exports.sweep = require_loftFns.sweep;
|
|
9912
|
-
exports.tagFaces =
|
|
10069
|
+
exports.tagFaces = require_booleanFns.tagFaces;
|
|
9913
10070
|
exports.tangentArc = require_primitiveFns.tangentArc;
|
|
9914
10071
|
exports.tap = require_errors.tap;
|
|
9915
10072
|
exports.tapErr = require_errors.tapErr;
|