brepjs 8.4.0 → 8.7.4
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 +2 -2
- package/dist/2d.js +13 -13
- package/dist/{Blueprint-zgFe_5Qj.cjs → Blueprint-BcbOBF-9.cjs} +11 -99
- package/dist/{Blueprint-Bp45tnh0.js → Blueprint-Cmh8lKc4.js} +29 -117
- package/dist/{boolean2D-CfEbRMPF.cjs → boolean2D-CqacqjME.cjs} +24 -25
- package/dist/{boolean2D-DN6ETTCq.js → boolean2D-D94Axs3i.js} +23 -24
- package/dist/{booleanFns-C-M6qqvB.js → booleanFns-DdjtpcM6.js} +306 -12
- package/dist/{booleanFns-5dDG0jpA.cjs → booleanFns-NtKxkiXn.cjs} +299 -5
- package/dist/brepjs.cjs +1619 -71
- package/dist/brepjs.js +1880 -333
- package/dist/core/errors.d.ts +18 -0
- package/dist/core/errors.d.ts.map +1 -1
- package/dist/core.cjs +4 -4
- package/dist/core.js +4 -4
- package/dist/{cornerFinder-CC_MunIh.js → cornerFinder-BBOYfsXl.js} +1 -1
- package/dist/{cornerFinder-BQ-_VJx0.cjs → cornerFinder-Bqy8Lw2p.cjs} +1 -1
- package/dist/{curveFns-ZuQUBZvd.js → curveFns-B85Glnfo.js} +19 -17
- package/dist/{curveFns-VMxgfkqw.cjs → curveFns-BXCbASW-.cjs} +6 -4
- package/dist/{drawFns-BbhX1IUq.js → drawFns-B-gJ2WUc.js} +47 -21
- package/dist/{drawFns-CKaHgGSK.cjs → drawFns-CAmFEqd1.cjs} +63 -37
- package/dist/{errors-CSYOlCCR.js → errors-Coh_5_19.js} +26 -1
- package/dist/{errors-D13q2HCk.cjs → errors-eRQu29oc.cjs} +26 -1
- package/dist/{faceFns-CfJIbHY3.js → faceFns-CltrEfOo.js} +109 -12
- package/dist/{faceFns-es3GENII.cjs → faceFns-DcndPHWm.cjs} +103 -6
- package/dist/{helpers-C0q_FVxq.cjs → helpers-CC21GeAr.cjs} +8 -9
- package/dist/{helpers-CmVkMubc.js → helpers-SksQIreB.js} +16 -17
- package/dist/index.d.ts +18 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/io/dxfImportFns.d.ts +17 -0
- package/dist/io/dxfImportFns.d.ts.map +1 -0
- package/dist/io/objImportFns.d.ts +19 -0
- package/dist/io/objImportFns.d.ts.map +1 -0
- package/dist/io/threemfImportFns.d.ts +19 -0
- package/dist/io/threemfImportFns.d.ts.map +1 -0
- package/dist/io.cjs +5 -5
- package/dist/io.js +5 -5
- package/dist/kernel/hullOps.d.ts +1 -0
- package/dist/kernel/hullOps.d.ts.map +1 -1
- package/dist/kernel/occtAdapter.d.ts +5 -0
- package/dist/kernel/occtAdapter.d.ts.map +1 -1
- package/dist/kernel/solverAdapter.d.ts +39 -0
- package/dist/kernel/solverAdapter.d.ts.map +1 -0
- package/dist/kernel/types.d.ts +5 -0
- package/dist/kernel/types.d.ts.map +1 -1
- package/dist/{loft-B-UCPW9P.cjs → loft-BcyyvWCj.cjs} +28 -28
- package/dist/{loft-oJq2OD3A.js → loft-CJMPx1NQ.js} +16 -16
- package/dist/{measurement-Cf_SoIiR.js → measurement-ByOztLxb.js} +3 -3
- package/dist/{measurement-CYmT-C77.cjs → measurement-DU3ry-0Q.cjs} +3 -3
- package/dist/measurement.cjs +1 -1
- package/dist/measurement.js +1 -1
- package/dist/{meshFns-CqNwW0PO.js → meshFns-D2gLyLFt.js} +3 -3
- package/dist/{meshFns-DDC_2U81.cjs → meshFns-DawUwI3W.cjs} +3 -3
- package/dist/{occtBoundary-D_gjqgzo.js → occtBoundary-CWzWqBCm.js} +17 -5
- package/dist/{occtBoundary-CocN2VKx.cjs → occtBoundary-DH2VO-rq.cjs} +12 -0
- package/dist/operations/assemblyFns.d.ts +1 -0
- package/dist/operations/assemblyFns.d.ts.map +1 -1
- package/dist/operations/guidedSweepFns.d.ts +25 -0
- package/dist/operations/guidedSweepFns.d.ts.map +1 -0
- package/dist/operations/mateFns.d.ts +50 -0
- package/dist/operations/mateFns.d.ts.map +1 -0
- package/dist/operations/multiSweepFns.d.ts +32 -0
- package/dist/operations/multiSweepFns.d.ts.map +1 -0
- package/dist/operations/roofFns.d.ts +16 -0
- package/dist/operations/roofFns.d.ts.map +1 -0
- package/dist/operations/straightSkeleton.d.ts +28 -0
- package/dist/operations/straightSkeleton.d.ts.map +1 -0
- package/dist/{operations-BQeW_DSM.cjs → operations-CdELWxgv.cjs} +7 -7
- package/dist/{operations-6hdpuYmY.js → operations-DiXo_4t9.js} +15 -15
- package/dist/operations.cjs +2 -2
- package/dist/operations.js +13 -13
- package/dist/query.cjs +5 -5
- package/dist/query.js +7 -7
- package/dist/result.cjs +1 -1
- package/dist/result.js +1 -1
- package/dist/{shapeFns-B0zSdO9c.cjs → shapeFns-3RYtsUVY.cjs} +54 -21
- package/dist/{shapeFns-k1YHFwmB.js → shapeFns-4ioRrhih.js} +52 -19
- package/dist/{shapeTypes-BxVxLdiD.cjs → shapeTypes-CMjrTv36.cjs} +1 -1
- package/dist/{shapeTypes-c-_pgYCx.js → shapeTypes-D0vfRxWb.js} +13 -13
- package/dist/sketching.cjs +2 -2
- package/dist/sketching.js +2 -2
- package/dist/{curveBuilders-BREwqvuc.js → surfaceBuilders-B7Jxob8g.js} +106 -13
- package/dist/{curveBuilders-BkEJ-RVn.cjs → surfaceBuilders-Xx9DRRxs.cjs} +96 -3
- package/dist/text/textBlueprints.d.ts +38 -0
- package/dist/text/textBlueprints.d.ts.map +1 -1
- package/dist/topology/api.d.ts +5 -0
- package/dist/topology/api.d.ts.map +1 -1
- package/dist/topology/booleanFns.d.ts +10 -1
- package/dist/topology/booleanFns.d.ts.map +1 -1
- package/dist/topology/colorFns.d.ts +38 -0
- package/dist/topology/colorFns.d.ts.map +1 -0
- package/dist/topology/curveFns.d.ts +1 -1
- package/dist/topology/curveFns.d.ts.map +1 -1
- package/dist/topology/faceTagFns.d.ts +44 -0
- package/dist/topology/faceTagFns.d.ts.map +1 -0
- package/dist/topology/modifierFns.d.ts.map +1 -1
- package/dist/topology/polyhedronFns.d.ts +8 -0
- package/dist/topology/polyhedronFns.d.ts.map +1 -0
- package/dist/topology/shapeFns.d.ts +4 -0
- package/dist/topology/shapeFns.d.ts.map +1 -1
- package/dist/topology/surfaceBuilders.d.ts +7 -0
- package/dist/topology/surfaceBuilders.d.ts.map +1 -1
- package/dist/topology/surfaceFns.d.ts +38 -0
- package/dist/topology/surfaceFns.d.ts.map +1 -0
- package/dist/{topology-CycEc6Oe.cjs → topology-D-nGjCzV.cjs} +19 -20
- package/dist/{topology-tMKHJgw2.js → topology-DRP9zreU.js} +8 -9
- package/dist/topology.cjs +13 -14
- package/dist/topology.js +51 -52
- package/dist/{vectors-DE0XriuQ.js → vectors-CZV4ZrTz.js} +2 -2
- package/dist/{vectors-DVmHF4zt.cjs → vectors-DwFeX0Ja.cjs} +2 -2
- package/dist/vectors.cjs +2 -2
- package/dist/vectors.js +2 -2
- package/package.json +4 -3
- package/dist/cast-CPNOTNFm.cjs +0 -102
- package/dist/cast-Cerqtxtb.js +0 -103
package/dist/brepjs.cjs
CHANGED
|
@@ -1,30 +1,29 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
3
|
-
const occtBoundary = require("./occtBoundary-
|
|
4
|
-
const errors = require("./errors-
|
|
5
|
-
const shapeTypes = require("./shapeTypes-
|
|
3
|
+
const occtBoundary = require("./occtBoundary-DH2VO-rq.cjs");
|
|
4
|
+
const errors = require("./errors-eRQu29oc.cjs");
|
|
5
|
+
const shapeTypes = require("./shapeTypes-CMjrTv36.cjs");
|
|
6
6
|
const vecOps = require("./vecOps-CjRL1jau.cjs");
|
|
7
|
-
const Blueprint = require("./Blueprint-
|
|
8
|
-
const curveFns = require("./curveFns-
|
|
9
|
-
const loft$2 = require("./loft-
|
|
10
|
-
const operations = require("./operations-
|
|
11
|
-
const boolean2D = require("./boolean2D-
|
|
7
|
+
const Blueprint = require("./Blueprint-BcbOBF-9.cjs");
|
|
8
|
+
const curveFns = require("./curveFns-BXCbASW-.cjs");
|
|
9
|
+
const loft$2 = require("./loft-BcyyvWCj.cjs");
|
|
10
|
+
const operations = require("./operations-CdELWxgv.cjs");
|
|
11
|
+
const boolean2D = require("./boolean2D-CqacqjME.cjs");
|
|
12
12
|
const _2d = require("./2d.cjs");
|
|
13
|
-
const helpers = require("./helpers-
|
|
13
|
+
const helpers = require("./helpers-CC21GeAr.cjs");
|
|
14
14
|
const io = require("./io.cjs");
|
|
15
|
-
const drawFns = require("./drawFns-
|
|
16
|
-
const vectors = require("./vectors-
|
|
17
|
-
const shapeFns = require("./shapeFns-
|
|
18
|
-
const
|
|
19
|
-
const
|
|
20
|
-
const
|
|
21
|
-
const
|
|
22
|
-
const measurement = require("./measurement-
|
|
23
|
-
const
|
|
24
|
-
const cast = require("./cast-CPNOTNFm.cjs");
|
|
15
|
+
const drawFns = require("./drawFns-CAmFEqd1.cjs");
|
|
16
|
+
const vectors = require("./vectors-DwFeX0Ja.cjs");
|
|
17
|
+
const shapeFns = require("./shapeFns-3RYtsUVY.cjs");
|
|
18
|
+
const booleanFns = require("./booleanFns-NtKxkiXn.cjs");
|
|
19
|
+
const topology = require("./topology-D-nGjCzV.cjs");
|
|
20
|
+
const faceFns = require("./faceFns-DcndPHWm.cjs");
|
|
21
|
+
const meshFns = require("./meshFns-DawUwI3W.cjs");
|
|
22
|
+
const measurement = require("./measurement-DU3ry-0Q.cjs");
|
|
23
|
+
const surfaceBuilders = require("./surfaceBuilders-Xx9DRRxs.cjs");
|
|
25
24
|
const query = require("./query.cjs");
|
|
26
25
|
const result = require("./result.cjs");
|
|
27
|
-
const cornerFinder = require("./cornerFinder-
|
|
26
|
+
const cornerFinder = require("./cornerFinder-Bqy8Lw2p.cjs");
|
|
28
27
|
const worker = require("./worker.cjs");
|
|
29
28
|
const errorFactories = {
|
|
30
29
|
OCCT_OPERATION: (code, message, cause) => ({ kind: "OCCT_OPERATION", code, message, cause }),
|
|
@@ -82,7 +81,7 @@ function buildWireFinder(filters) {
|
|
|
82
81
|
isOpen: () => withFilter((wire2) => !curveFns.curveIsClosed(wire2)),
|
|
83
82
|
ofEdgeCount: (count) => withFilter((wire2) => {
|
|
84
83
|
let edgeCount = 0;
|
|
85
|
-
for (const _raw of
|
|
84
|
+
for (const _raw of faceFns.iterTopo(wire2.wrapped, "edge")) {
|
|
86
85
|
edgeCount++;
|
|
87
86
|
}
|
|
88
87
|
return edgeCount === count;
|
|
@@ -145,6 +144,261 @@ function buildVertexFinder(filters) {
|
|
|
145
144
|
function vertexFinder() {
|
|
146
145
|
return buildVertexFinder([]);
|
|
147
146
|
}
|
|
147
|
+
function surfaceFromGrid(heights, options = {}) {
|
|
148
|
+
if (heights.length < 2) {
|
|
149
|
+
return errors.err(
|
|
150
|
+
errors.validationError(
|
|
151
|
+
errors.BrepErrorCode.SURFACE_GRID_TOO_SMALL,
|
|
152
|
+
`surfaceFromGrid: need at least 2 rows, got ${heights.length}`
|
|
153
|
+
)
|
|
154
|
+
);
|
|
155
|
+
}
|
|
156
|
+
const rows = heights.length;
|
|
157
|
+
const cols = heights[0]?.length ?? 0;
|
|
158
|
+
if (cols < 2) {
|
|
159
|
+
return errors.err(
|
|
160
|
+
errors.validationError(
|
|
161
|
+
errors.BrepErrorCode.SURFACE_GRID_TOO_SMALL,
|
|
162
|
+
`surfaceFromGrid: need at least 2 columns, got ${cols}`
|
|
163
|
+
)
|
|
164
|
+
);
|
|
165
|
+
}
|
|
166
|
+
for (let r = 0; r < rows; r++) {
|
|
167
|
+
const row = heights[r];
|
|
168
|
+
if (!row || row.length !== cols) {
|
|
169
|
+
return errors.err(
|
|
170
|
+
errors.validationError(
|
|
171
|
+
errors.BrepErrorCode.SURFACE_GRID_JAGGED,
|
|
172
|
+
`surfaceFromGrid: row ${r} has ${row?.length ?? 0} columns, expected ${cols}`
|
|
173
|
+
)
|
|
174
|
+
);
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
const { width = cols - 1, depth = rows - 1, scaleZ = 1 } = options;
|
|
178
|
+
const dx = width / (cols - 1);
|
|
179
|
+
const dy = depth / (rows - 1);
|
|
180
|
+
try {
|
|
181
|
+
return buildBSplineSurface(heights, rows, cols, dx, dy, scaleZ);
|
|
182
|
+
} catch {
|
|
183
|
+
}
|
|
184
|
+
try {
|
|
185
|
+
return buildTriangulatedSurface(heights, rows, cols, dx, dy, scaleZ);
|
|
186
|
+
} catch (e) {
|
|
187
|
+
const raw = e instanceof Error ? e.message : String(e);
|
|
188
|
+
return errors.err(errors.occtError(errors.BrepErrorCode.SURFACE_FAILED, `surfaceFromGrid failed: ${raw}`, e));
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
function buildBSplineSurface(heights, rows, cols, dx, dy, scaleZ) {
|
|
192
|
+
const oc = occtBoundary.getKernel().oc;
|
|
193
|
+
const OC = oc;
|
|
194
|
+
const pntArray = new OC.TColgp_Array2OfPnt_2(1, rows, 1, cols);
|
|
195
|
+
try {
|
|
196
|
+
for (let r = 0; r < rows; r++) {
|
|
197
|
+
for (let c = 0; c < cols; c++) {
|
|
198
|
+
const row = heights[r];
|
|
199
|
+
const z = (row ? row[c] ?? 0 : 0) * scaleZ;
|
|
200
|
+
const pnt = new oc.gp_Pnt_3(c * dx, r * dy, z);
|
|
201
|
+
pntArray.SetValue(r + 1, c + 1, pnt);
|
|
202
|
+
pnt.delete();
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
const fitter = new OC.GeomAPI_PointsToBSplineSurface_2(pntArray, 3, 8, 0, 1e-3);
|
|
206
|
+
const surface = fitter.Surface();
|
|
207
|
+
const faceMaker = new OC.BRepBuilderAPI_MakeFace_8(surface, 1e-6);
|
|
208
|
+
let result2;
|
|
209
|
+
if (faceMaker.IsDone()) {
|
|
210
|
+
const shape2 = shapeTypes.castShape(faceMaker.Face());
|
|
211
|
+
if (shapeTypes.isFace(shape2)) {
|
|
212
|
+
result2 = errors.ok(shape2);
|
|
213
|
+
} else {
|
|
214
|
+
shape2[Symbol.dispose]();
|
|
215
|
+
result2 = errors.err(
|
|
216
|
+
errors.occtError(errors.BrepErrorCode.SURFACE_FAILED, "B-spline surface did not produce a face")
|
|
217
|
+
);
|
|
218
|
+
}
|
|
219
|
+
} else {
|
|
220
|
+
result2 = errors.err(
|
|
221
|
+
errors.occtError(
|
|
222
|
+
errors.BrepErrorCode.SURFACE_FAILED,
|
|
223
|
+
"BRepBuilderAPI_MakeFace failed for B-spline surface"
|
|
224
|
+
)
|
|
225
|
+
);
|
|
226
|
+
}
|
|
227
|
+
faceMaker.delete();
|
|
228
|
+
fitter.delete();
|
|
229
|
+
return result2;
|
|
230
|
+
} finally {
|
|
231
|
+
pntArray.delete();
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
function buildTriangulatedSurface(heights, rows, cols, dx, dy, scaleZ) {
|
|
235
|
+
const oc = occtBoundary.getKernel().oc;
|
|
236
|
+
function pt(r, c) {
|
|
237
|
+
const row = heights[r];
|
|
238
|
+
const z = (row ? row[c] ?? 0 : 0) * scaleZ;
|
|
239
|
+
return { x: c * dx, y: r * dy, z };
|
|
240
|
+
}
|
|
241
|
+
function buildTriFace2(a, b, c) {
|
|
242
|
+
const gpA = new oc.gp_Pnt_3(a.x, a.y, a.z);
|
|
243
|
+
const gpB = new oc.gp_Pnt_3(b.x, b.y, b.z);
|
|
244
|
+
const gpC = new oc.gp_Pnt_3(c.x, c.y, c.z);
|
|
245
|
+
const e1 = new oc.BRepBuilderAPI_MakeEdge_3(gpA, gpB);
|
|
246
|
+
const e2 = new oc.BRepBuilderAPI_MakeEdge_3(gpB, gpC);
|
|
247
|
+
const e3 = new oc.BRepBuilderAPI_MakeEdge_3(gpC, gpA);
|
|
248
|
+
const wireBuilder = new oc.BRepBuilderAPI_MakeWire_1();
|
|
249
|
+
wireBuilder.Add_1(e1.Edge());
|
|
250
|
+
wireBuilder.Add_1(e2.Edge());
|
|
251
|
+
wireBuilder.Add_1(e3.Edge());
|
|
252
|
+
let face2 = null;
|
|
253
|
+
if (wireBuilder.IsDone()) {
|
|
254
|
+
const makeFace = new oc.BRepBuilderAPI_MakeFace_15(wireBuilder.Wire(), false);
|
|
255
|
+
if (makeFace.IsDone()) {
|
|
256
|
+
face2 = makeFace.Face();
|
|
257
|
+
}
|
|
258
|
+
makeFace.delete();
|
|
259
|
+
}
|
|
260
|
+
wireBuilder.delete();
|
|
261
|
+
e1.delete();
|
|
262
|
+
e2.delete();
|
|
263
|
+
e3.delete();
|
|
264
|
+
gpA.delete();
|
|
265
|
+
gpB.delete();
|
|
266
|
+
gpC.delete();
|
|
267
|
+
return face2;
|
|
268
|
+
}
|
|
269
|
+
const sewing = new oc.BRepBuilderAPI_Sewing(1e-6, true, true, true, false);
|
|
270
|
+
let faceCount = 0;
|
|
271
|
+
try {
|
|
272
|
+
for (let r = 0; r < rows - 1; r++) {
|
|
273
|
+
for (let c = 0; c < cols - 1; c++) {
|
|
274
|
+
const p00 = pt(r, c);
|
|
275
|
+
const p10 = pt(r + 1, c);
|
|
276
|
+
const p11 = pt(r + 1, c + 1);
|
|
277
|
+
const p01 = pt(r, c + 1);
|
|
278
|
+
const f1 = buildTriFace2(p00, p10, p11);
|
|
279
|
+
if (f1 !== null) {
|
|
280
|
+
sewing.Add(f1);
|
|
281
|
+
faceCount++;
|
|
282
|
+
}
|
|
283
|
+
const f2 = buildTriFace2(p00, p11, p01);
|
|
284
|
+
if (f2 !== null) {
|
|
285
|
+
sewing.Add(f2);
|
|
286
|
+
faceCount++;
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
if (faceCount === 0) {
|
|
291
|
+
sewing.delete();
|
|
292
|
+
return errors.err(
|
|
293
|
+
errors.occtError(errors.BrepErrorCode.SURFACE_FAILED, "surfaceFromGrid: no valid triangular faces built")
|
|
294
|
+
);
|
|
295
|
+
}
|
|
296
|
+
const sewProgress = new oc.Message_ProgressRange_1();
|
|
297
|
+
sewing.Perform(sewProgress);
|
|
298
|
+
sewProgress.delete();
|
|
299
|
+
const sewn = sewing.SewedShape();
|
|
300
|
+
const shape2 = shapeTypes.castShape(sewn);
|
|
301
|
+
if (shapeTypes.isFace(shape2)) {
|
|
302
|
+
return errors.ok(shape2);
|
|
303
|
+
}
|
|
304
|
+
if (shapeTypes.isShell(shape2)) {
|
|
305
|
+
return errors.ok(shape2);
|
|
306
|
+
}
|
|
307
|
+
shape2[Symbol.dispose]();
|
|
308
|
+
return errors.err(
|
|
309
|
+
errors.occtError(errors.BrepErrorCode.SURFACE_FAILED, "surfaceFromGrid: unexpected shape type from sewing")
|
|
310
|
+
);
|
|
311
|
+
} finally {
|
|
312
|
+
sewing.delete();
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
async function surfaceFromImage(blob, options = {}) {
|
|
316
|
+
const channel = options.channel ?? "luminance";
|
|
317
|
+
const downsample = Math.max(1, Math.round(options.downsample ?? 1));
|
|
318
|
+
if (typeof createImageBitmap !== "function") {
|
|
319
|
+
return errors.err(
|
|
320
|
+
errors.ioError(
|
|
321
|
+
errors.BrepErrorCode.SURFACE_FAILED,
|
|
322
|
+
"surfaceFromImage requires createImageBitmap (not available in this environment)"
|
|
323
|
+
)
|
|
324
|
+
);
|
|
325
|
+
}
|
|
326
|
+
let bitmap;
|
|
327
|
+
try {
|
|
328
|
+
bitmap = await createImageBitmap(blob);
|
|
329
|
+
} catch (e) {
|
|
330
|
+
return errors.err(
|
|
331
|
+
errors.ioError(
|
|
332
|
+
errors.BrepErrorCode.SURFACE_FAILED,
|
|
333
|
+
`surfaceFromImage: failed to decode image — ${e instanceof Error ? e.message : String(e)}`
|
|
334
|
+
)
|
|
335
|
+
);
|
|
336
|
+
}
|
|
337
|
+
const w = bitmap.width;
|
|
338
|
+
const h = bitmap.height;
|
|
339
|
+
if (w < 2 || h < 2) {
|
|
340
|
+
bitmap.close();
|
|
341
|
+
return errors.err(
|
|
342
|
+
errors.validationError(
|
|
343
|
+
errors.BrepErrorCode.SURFACE_GRID_TOO_SMALL,
|
|
344
|
+
`surfaceFromImage: image too small (${w}x${h}), need at least 2x2`
|
|
345
|
+
)
|
|
346
|
+
);
|
|
347
|
+
}
|
|
348
|
+
if (typeof OffscreenCanvas !== "function") {
|
|
349
|
+
bitmap.close();
|
|
350
|
+
return errors.err(
|
|
351
|
+
errors.ioError(
|
|
352
|
+
errors.BrepErrorCode.SURFACE_FAILED,
|
|
353
|
+
"surfaceFromImage requires OffscreenCanvas (not available in this environment)"
|
|
354
|
+
)
|
|
355
|
+
);
|
|
356
|
+
}
|
|
357
|
+
const canvas = new OffscreenCanvas(w, h);
|
|
358
|
+
const ctx = canvas.getContext("2d");
|
|
359
|
+
if (!ctx) {
|
|
360
|
+
bitmap.close();
|
|
361
|
+
return errors.err(
|
|
362
|
+
errors.ioError(errors.BrepErrorCode.SURFACE_FAILED, "surfaceFromImage: could not get 2D canvas context")
|
|
363
|
+
);
|
|
364
|
+
}
|
|
365
|
+
ctx.drawImage(bitmap, 0, 0);
|
|
366
|
+
bitmap.close();
|
|
367
|
+
const imageData = ctx.getImageData(0, 0, w, h);
|
|
368
|
+
const data = imageData.data;
|
|
369
|
+
const rows = [];
|
|
370
|
+
for (let y = 0; y < h; y += downsample) {
|
|
371
|
+
const row = [];
|
|
372
|
+
for (let x = 0; x < w; x += downsample) {
|
|
373
|
+
const idx = (y * w + x) * 4;
|
|
374
|
+
const r = data[idx] ?? 0;
|
|
375
|
+
const g = data[idx + 1] ?? 0;
|
|
376
|
+
const b = data[idx + 2] ?? 0;
|
|
377
|
+
let value;
|
|
378
|
+
switch (channel) {
|
|
379
|
+
case "r":
|
|
380
|
+
value = r / 255;
|
|
381
|
+
break;
|
|
382
|
+
case "g":
|
|
383
|
+
value = g / 255;
|
|
384
|
+
break;
|
|
385
|
+
case "b":
|
|
386
|
+
value = b / 255;
|
|
387
|
+
break;
|
|
388
|
+
default:
|
|
389
|
+
value = (0.299 * r + 0.587 * g + 0.114 * b) / 255;
|
|
390
|
+
break;
|
|
391
|
+
}
|
|
392
|
+
row.push(value);
|
|
393
|
+
}
|
|
394
|
+
rows.push(row);
|
|
395
|
+
}
|
|
396
|
+
const gridOpts = {};
|
|
397
|
+
if (options.width !== void 0) gridOpts.width = options.width;
|
|
398
|
+
if (options.depth !== void 0) gridOpts.depth = options.depth;
|
|
399
|
+
if (options.scaleZ !== void 0) gridOpts.scaleZ = options.scaleZ;
|
|
400
|
+
return surfaceFromGrid(rows, gridOpts);
|
|
401
|
+
}
|
|
148
402
|
function validateNotNull$1(shape2, label) {
|
|
149
403
|
if (shape2.wrapped.IsNull()) {
|
|
150
404
|
return errors.err(errors.validationError(errors.BrepErrorCode.NULL_SHAPE_INPUT, `${label} is a null shape`));
|
|
@@ -172,13 +426,13 @@ function hull(shapes, options = {}) {
|
|
|
172
426
|
const kernel = occtBoundary.getKernel();
|
|
173
427
|
const ocShapes = shapes.map((s) => s.wrapped);
|
|
174
428
|
const resultOc = kernel.hull(ocShapes, tolerance);
|
|
175
|
-
const
|
|
176
|
-
if (!shapeTypes.isSolid(
|
|
429
|
+
const cast = shapeTypes.castShape(resultOc);
|
|
430
|
+
if (!shapeTypes.isSolid(cast)) {
|
|
177
431
|
return errors.err(
|
|
178
432
|
errors.occtError(errors.BrepErrorCode.HULL_NOT_3D, "Hull result is not a solid; input may be degenerate")
|
|
179
433
|
);
|
|
180
434
|
}
|
|
181
|
-
return errors.ok(
|
|
435
|
+
return errors.ok(cast);
|
|
182
436
|
} catch (e) {
|
|
183
437
|
const raw = e instanceof Error ? e.message : String(e);
|
|
184
438
|
if (raw.includes("coplanar") || raw.includes("fewer than") || raw.includes("degenerate")) {
|
|
@@ -309,6 +563,809 @@ function minkowski(shape2, tool, options = {}) {
|
|
|
309
563
|
}
|
|
310
564
|
return minkowskiGeneral(shape2, tool, tolerance);
|
|
311
565
|
}
|
|
566
|
+
function polyhedron(points, faces, options = {}) {
|
|
567
|
+
const { tolerance = 1e-6 } = options;
|
|
568
|
+
if (points.length < 4) {
|
|
569
|
+
return errors.err(
|
|
570
|
+
errors.validationError(
|
|
571
|
+
errors.BrepErrorCode.POLYHEDRON_INSUFFICIENT_POINTS,
|
|
572
|
+
`polyhedron: need at least 4 points, got ${points.length}`
|
|
573
|
+
)
|
|
574
|
+
);
|
|
575
|
+
}
|
|
576
|
+
if (faces.length < 4) {
|
|
577
|
+
return errors.err(
|
|
578
|
+
errors.validationError(
|
|
579
|
+
errors.BrepErrorCode.POLYHEDRON_INSUFFICIENT_FACES,
|
|
580
|
+
`polyhedron: need at least 4 faces, got ${faces.length}`
|
|
581
|
+
)
|
|
582
|
+
);
|
|
583
|
+
}
|
|
584
|
+
const triangles = [];
|
|
585
|
+
for (const [fi, face2] of faces.entries()) {
|
|
586
|
+
for (const idx of face2) {
|
|
587
|
+
if (idx < 0 || idx >= points.length) {
|
|
588
|
+
return errors.err(
|
|
589
|
+
errors.validationError(
|
|
590
|
+
errors.BrepErrorCode.POLYHEDRON_INVALID_INDEX,
|
|
591
|
+
`polyhedron: face ${fi} has out-of-range index ${idx} (${points.length} points)`
|
|
592
|
+
)
|
|
593
|
+
);
|
|
594
|
+
}
|
|
595
|
+
}
|
|
596
|
+
if (face2.length < 3) continue;
|
|
597
|
+
const v0 = face2[0];
|
|
598
|
+
for (let i = 1; i < face2.length - 1; i++) {
|
|
599
|
+
triangles.push([v0, face2[i], face2[i + 1]]);
|
|
600
|
+
}
|
|
601
|
+
}
|
|
602
|
+
try {
|
|
603
|
+
const kernel = occtBoundary.getKernel();
|
|
604
|
+
const ptObjs = points.map(([x, y, z]) => ({ x, y, z }));
|
|
605
|
+
const resultOc = kernel.buildSolidFromFaces(ptObjs, triangles, tolerance);
|
|
606
|
+
const cast = shapeTypes.castShape(resultOc);
|
|
607
|
+
if (!shapeTypes.isSolid(cast)) {
|
|
608
|
+
cast[Symbol.dispose]();
|
|
609
|
+
return errors.err(errors.occtError(errors.BrepErrorCode.POLYHEDRON_FAILED, "Polyhedron did not produce a solid"));
|
|
610
|
+
}
|
|
611
|
+
return errors.ok(cast);
|
|
612
|
+
} catch (e) {
|
|
613
|
+
const raw = e instanceof Error ? e.message : String(e);
|
|
614
|
+
return errors.err(errors.occtError(errors.BrepErrorCode.POLYHEDRON_FAILED, `Polyhedron failed: ${raw}`, e));
|
|
615
|
+
}
|
|
616
|
+
}
|
|
617
|
+
function multiSectionSweep(sections, spine, options) {
|
|
618
|
+
if (sections.length < 2) {
|
|
619
|
+
return errors.err(
|
|
620
|
+
errors.validationError(
|
|
621
|
+
errors.BrepErrorCode.MULTI_SWEEP_INSUFFICIENT_SECTIONS,
|
|
622
|
+
`Multi-section sweep requires at least 2 sections, got ${sections.length}`
|
|
623
|
+
)
|
|
624
|
+
);
|
|
625
|
+
}
|
|
626
|
+
const { solid: solid2 = true, ruled = false, tolerance = 1e-6 } = options ?? {};
|
|
627
|
+
try {
|
|
628
|
+
const oc = occtBoundary.getKernel().oc;
|
|
629
|
+
const r = shapeTypes.gcWithScope();
|
|
630
|
+
const adaptor = r(new oc.BRepAdaptor_CompCurve_2(spine.wrapped, false));
|
|
631
|
+
const uFirst = Number(adaptor.FirstParameter());
|
|
632
|
+
const uLast = Number(adaptor.LastParameter());
|
|
633
|
+
const uRange = uLast - uFirst;
|
|
634
|
+
const params = sections.map((s, i) => {
|
|
635
|
+
if (s.location !== void 0) {
|
|
636
|
+
return uFirst + s.location * uRange;
|
|
637
|
+
}
|
|
638
|
+
return uFirst + i / (sections.length - 1) * uRange;
|
|
639
|
+
});
|
|
640
|
+
const builder = r(new oc.BRepOffsetAPI_ThruSections(solid2, ruled, tolerance));
|
|
641
|
+
for (let i = 0; i < sections.length; i++) {
|
|
642
|
+
const param = params[i];
|
|
643
|
+
const section2 = sections[i];
|
|
644
|
+
if (param === void 0 || section2 === void 0) continue;
|
|
645
|
+
const pnt = r(new oc.gp_Pnt_1());
|
|
646
|
+
const tangent = r(new oc.gp_Vec_1());
|
|
647
|
+
adaptor.D1(param, pnt, tangent);
|
|
648
|
+
const tangentDir = r(new oc.gp_Dir_2(tangent));
|
|
649
|
+
const toAx3 = r(new oc.gp_Ax3_4(pnt, tangentDir));
|
|
650
|
+
const trsf = r(new oc.gp_Trsf_1());
|
|
651
|
+
trsf.SetTransformation_2(toAx3);
|
|
652
|
+
trsf.Invert();
|
|
653
|
+
const transformer = r(new oc.BRepBuilderAPI_Transform_2(section2.wire.wrapped, trsf, true));
|
|
654
|
+
const transformedShape = transformer.Shape();
|
|
655
|
+
const transformedWire = oc.TopoDS.Wire_1(transformedShape);
|
|
656
|
+
builder.AddWire(transformedWire);
|
|
657
|
+
}
|
|
658
|
+
const progress = r(new oc.Message_ProgressRange_1());
|
|
659
|
+
builder.Build(progress);
|
|
660
|
+
if (!builder.IsDone()) {
|
|
661
|
+
return errors.err(errors.occtError(errors.BrepErrorCode.MULTI_SWEEP_FAILED, "Multi-section sweep build failed"));
|
|
662
|
+
}
|
|
663
|
+
const result2 = shapeTypes.castShape(builder.Shape());
|
|
664
|
+
if (!shapeTypes.isShape3D(result2)) {
|
|
665
|
+
return errors.err(
|
|
666
|
+
errors.typeCastError("MULTI_SWEEP_NOT_3D", "Multi-section sweep did not produce a 3D shape")
|
|
667
|
+
);
|
|
668
|
+
}
|
|
669
|
+
return errors.ok(result2);
|
|
670
|
+
} catch (e) {
|
|
671
|
+
const raw = e instanceof Error ? e.message : String(e);
|
|
672
|
+
return errors.err(
|
|
673
|
+
errors.occtError(errors.BrepErrorCode.MULTI_SWEEP_FAILED, `Multi-section sweep failed: ${raw}`, e)
|
|
674
|
+
);
|
|
675
|
+
}
|
|
676
|
+
}
|
|
677
|
+
function guidedSweep(profile, spine, guides, options = {}) {
|
|
678
|
+
const { transition = "transformed", solid: solid2 = true, tolerance } = options;
|
|
679
|
+
try {
|
|
680
|
+
const oc = occtBoundary.getKernel().oc;
|
|
681
|
+
const r = shapeTypes.gcWithScope();
|
|
682
|
+
const builder = r(new oc.BRepOffsetAPI_MakePipeShell(spine.wrapped));
|
|
683
|
+
const modeMap = {
|
|
684
|
+
transformed: oc.BRepBuilderAPI_TransitionMode.BRepBuilderAPI_Transformed,
|
|
685
|
+
round: oc.BRepBuilderAPI_TransitionMode.BRepBuilderAPI_RoundCorner,
|
|
686
|
+
right: oc.BRepBuilderAPI_TransitionMode.BRepBuilderAPI_RightCorner
|
|
687
|
+
};
|
|
688
|
+
builder.SetTransitionMode(modeMap[transition]);
|
|
689
|
+
if (tolerance !== void 0) {
|
|
690
|
+
builder.SetTolerance(tolerance, tolerance, 1e-7);
|
|
691
|
+
}
|
|
692
|
+
if (guides.length > 0) {
|
|
693
|
+
const firstGuide = guides[0];
|
|
694
|
+
builder.SetMode_5(firstGuide.wrapped, false, oc.BRepFill_TypeOfContact.BRepFill_NoContact);
|
|
695
|
+
}
|
|
696
|
+
builder.Add_1(profile.wrapped, false, false);
|
|
697
|
+
const progress = r(new oc.Message_ProgressRange_1());
|
|
698
|
+
builder.Build(progress);
|
|
699
|
+
if (!builder.IsDone()) {
|
|
700
|
+
return errors.err(errors.occtError(errors.BrepErrorCode.GUIDED_SWEEP_FAILED, "Guided sweep build failed"));
|
|
701
|
+
}
|
|
702
|
+
if (solid2) {
|
|
703
|
+
builder.MakeSolid();
|
|
704
|
+
}
|
|
705
|
+
const result2 = shapeTypes.castShape(builder.Shape());
|
|
706
|
+
if (!shapeTypes.isShape3D(result2)) {
|
|
707
|
+
return errors.err(errors.typeCastError("GUIDED_SWEEP_NOT_3D", "Guided sweep did not produce a 3D shape"));
|
|
708
|
+
}
|
|
709
|
+
return errors.ok(result2);
|
|
710
|
+
} catch (e) {
|
|
711
|
+
const raw = e instanceof Error ? e.message : String(e);
|
|
712
|
+
return errors.err(errors.occtError(errors.BrepErrorCode.GUIDED_SWEEP_FAILED, `Guided sweep failed: ${raw}`, e));
|
|
713
|
+
}
|
|
714
|
+
}
|
|
715
|
+
const EPS = 1e-10;
|
|
716
|
+
function cross2(ax, ay, bx, by) {
|
|
717
|
+
return ax * by - ay * bx;
|
|
718
|
+
}
|
|
719
|
+
function dot2(ax, ay, bx, by) {
|
|
720
|
+
return ax * bx + ay * by;
|
|
721
|
+
}
|
|
722
|
+
function len2(x, y) {
|
|
723
|
+
return Math.sqrt(x * x + y * y);
|
|
724
|
+
}
|
|
725
|
+
function polyAt(poly, i) {
|
|
726
|
+
const p = poly[(i % poly.length + poly.length) % poly.length];
|
|
727
|
+
if (!p) throw new Error(`Invalid polygon index ${i} for length ${poly.length}`);
|
|
728
|
+
return p;
|
|
729
|
+
}
|
|
730
|
+
function ensureCCW(poly) {
|
|
731
|
+
let area = 0;
|
|
732
|
+
for (let i = 0; i < poly.length; i++) {
|
|
733
|
+
const cur = polyAt(poly, i);
|
|
734
|
+
const nxt = polyAt(poly, i + 1);
|
|
735
|
+
area += cur.x * nxt.y - nxt.x * cur.y;
|
|
736
|
+
}
|
|
737
|
+
if (area < 0) return [...poly].reverse();
|
|
738
|
+
return poly;
|
|
739
|
+
}
|
|
740
|
+
function bisector(poly, i) {
|
|
741
|
+
const prev = polyAt(poly, i - 1);
|
|
742
|
+
const cur = polyAt(poly, i);
|
|
743
|
+
const next = polyAt(poly, i + 1);
|
|
744
|
+
const e1x = cur.x - prev.x;
|
|
745
|
+
const e1y = cur.y - prev.y;
|
|
746
|
+
const e1l = len2(e1x, e1y);
|
|
747
|
+
const e2x = next.x - cur.x;
|
|
748
|
+
const e2y = next.y - cur.y;
|
|
749
|
+
const e2l = len2(e2x, e2y);
|
|
750
|
+
if (e1l < EPS || e2l < EPS) return { dx: 0, dy: 0 };
|
|
751
|
+
const n1x = -e1y / e1l;
|
|
752
|
+
const n1y = e1x / e1l;
|
|
753
|
+
const n2x = -e2y / e2l;
|
|
754
|
+
const n2y = e2x / e2l;
|
|
755
|
+
let bx = n1x + n2x;
|
|
756
|
+
let by = n1y + n2y;
|
|
757
|
+
const bl = len2(bx, by);
|
|
758
|
+
if (bl < EPS) {
|
|
759
|
+
return { dx: n1x, dy: n1y };
|
|
760
|
+
}
|
|
761
|
+
bx /= bl;
|
|
762
|
+
by /= bl;
|
|
763
|
+
const cosHalf = dot2(bx, by, n1x, n1y);
|
|
764
|
+
const speed = Math.abs(cosHalf) > EPS ? 1 / cosHalf : 1;
|
|
765
|
+
return { dx: bx * speed, dy: by * speed };
|
|
766
|
+
}
|
|
767
|
+
function isLavNodeReflex(node) {
|
|
768
|
+
const prev = node.prev;
|
|
769
|
+
const next = node.next;
|
|
770
|
+
return cross2(node.x - prev.x, node.y - prev.y, next.x - node.x, next.y - node.y) < -EPS;
|
|
771
|
+
}
|
|
772
|
+
function createLav(poly) {
|
|
773
|
+
const nodes = poly.map((p, i) => {
|
|
774
|
+
const b = bisector(poly, i);
|
|
775
|
+
return {
|
|
776
|
+
x: p.x,
|
|
777
|
+
y: p.y,
|
|
778
|
+
bx: b.dx,
|
|
779
|
+
by: b.dy,
|
|
780
|
+
origIdx: i,
|
|
781
|
+
prev: null,
|
|
782
|
+
next: null,
|
|
783
|
+
active: true
|
|
784
|
+
};
|
|
785
|
+
});
|
|
786
|
+
for (let i = 0; i < nodes.length; i++) {
|
|
787
|
+
const node = nodes[i];
|
|
788
|
+
const prevNode = nodes[(i - 1 + nodes.length) % nodes.length];
|
|
789
|
+
const nextNode = nodes[(i + 1) % nodes.length];
|
|
790
|
+
if (node && prevNode && nextNode) {
|
|
791
|
+
node.prev = prevNode;
|
|
792
|
+
node.next = nextNode;
|
|
793
|
+
}
|
|
794
|
+
}
|
|
795
|
+
return nodes;
|
|
796
|
+
}
|
|
797
|
+
function lavSize(start) {
|
|
798
|
+
let count = 1;
|
|
799
|
+
let cur = start.next;
|
|
800
|
+
while (cur !== start) {
|
|
801
|
+
count++;
|
|
802
|
+
cur = cur.next;
|
|
803
|
+
if (count > 1e4) break;
|
|
804
|
+
}
|
|
805
|
+
return count;
|
|
806
|
+
}
|
|
807
|
+
function bisectorIntersectTime(a, b) {
|
|
808
|
+
const ddx = a.bx - b.bx;
|
|
809
|
+
const ddy = a.by - b.by;
|
|
810
|
+
const dxp = b.x - a.x;
|
|
811
|
+
const dyp = b.y - a.y;
|
|
812
|
+
if (Math.abs(ddx) < EPS && Math.abs(ddy) < EPS) return null;
|
|
813
|
+
let t;
|
|
814
|
+
if (Math.abs(ddx) > Math.abs(ddy)) {
|
|
815
|
+
t = dxp / ddx;
|
|
816
|
+
} else {
|
|
817
|
+
t = dyp / ddy;
|
|
818
|
+
}
|
|
819
|
+
if (t < EPS) return null;
|
|
820
|
+
const otherDd = Math.abs(ddx) > Math.abs(ddy) ? ddy : ddx;
|
|
821
|
+
const otherDp = Math.abs(ddx) > Math.abs(ddy) ? dyp : dxp;
|
|
822
|
+
if (Math.abs(otherDd) > EPS) {
|
|
823
|
+
const t2 = otherDp / otherDd;
|
|
824
|
+
if (Math.abs(t - t2) > 1e-4 * Math.max(1, Math.abs(t))) return null;
|
|
825
|
+
}
|
|
826
|
+
return t;
|
|
827
|
+
}
|
|
828
|
+
function raySplitTime(node, eA, eB) {
|
|
829
|
+
const edx = eB.x - eA.x;
|
|
830
|
+
const edy = eB.y - eA.y;
|
|
831
|
+
const el = len2(edx, edy);
|
|
832
|
+
if (el < EPS) return null;
|
|
833
|
+
const enx = -edy / el;
|
|
834
|
+
const eny = edx / el;
|
|
835
|
+
const d0 = (node.x - eA.x) * enx + (node.y - eA.y) * eny;
|
|
836
|
+
const relBx = node.bx - (eA.bx + eB.bx) / 2;
|
|
837
|
+
const relBy = node.by - (eA.by + eB.by) / 2;
|
|
838
|
+
const dRate = relBx * enx + relBy * eny;
|
|
839
|
+
if (Math.abs(dRate) < EPS) return null;
|
|
840
|
+
const t = -d0 / dRate;
|
|
841
|
+
if (t < EPS) return null;
|
|
842
|
+
const px = node.x + t * node.bx;
|
|
843
|
+
const py = node.y + t * node.by;
|
|
844
|
+
const ax = eA.x + t * eA.bx;
|
|
845
|
+
const ay = eA.y + t * eA.by;
|
|
846
|
+
const bxx = eB.x + t * eB.bx;
|
|
847
|
+
const byy = eB.y + t * eB.by;
|
|
848
|
+
const segDx = bxx - ax;
|
|
849
|
+
const segDy = byy - ay;
|
|
850
|
+
const segL = len2(segDx, segDy);
|
|
851
|
+
if (segL < EPS) return t;
|
|
852
|
+
const s = dot2(px - ax, py - ay, segDx, segDy) / (segL * segL);
|
|
853
|
+
if (s < -0.01 || s > 1.01) return null;
|
|
854
|
+
return t;
|
|
855
|
+
}
|
|
856
|
+
function computeEvents(lavNodes) {
|
|
857
|
+
const events = [];
|
|
858
|
+
for (const node of lavNodes) {
|
|
859
|
+
if (!node.active) continue;
|
|
860
|
+
const t = bisectorIntersectTime(node, node.next);
|
|
861
|
+
if (t !== null && t > EPS) {
|
|
862
|
+
const x = node.x + t * node.bx;
|
|
863
|
+
const y = node.y + t * node.by;
|
|
864
|
+
events.push({ time: t, x, y, nodeA: node, nodeB: node.next, type: "edge" });
|
|
865
|
+
}
|
|
866
|
+
if (isLavNodeReflex(node)) {
|
|
867
|
+
let cur = node.next.next;
|
|
868
|
+
let count = 0;
|
|
869
|
+
while (cur !== node.prev && cur !== node && count < 1e3) {
|
|
870
|
+
const st = raySplitTime(node, cur, cur.next);
|
|
871
|
+
if (st !== null && st > EPS) {
|
|
872
|
+
const x = node.x + st * node.bx;
|
|
873
|
+
const y = node.y + st * node.by;
|
|
874
|
+
events.push({ time: st, x, y, nodeA: node, nodeB: cur, type: "split" });
|
|
875
|
+
}
|
|
876
|
+
cur = cur.next;
|
|
877
|
+
count++;
|
|
878
|
+
}
|
|
879
|
+
}
|
|
880
|
+
}
|
|
881
|
+
events.sort((a, b) => a.time - b.time);
|
|
882
|
+
return events;
|
|
883
|
+
}
|
|
884
|
+
function computeStraightSkeleton(polygon2) {
|
|
885
|
+
if (polygon2.length < 3) {
|
|
886
|
+
return { nodes: [], faces: [] };
|
|
887
|
+
}
|
|
888
|
+
const poly = ensureCCW(polygon2);
|
|
889
|
+
const n = poly.length;
|
|
890
|
+
const skeletonNodes = [];
|
|
891
|
+
const vertexToSkelNodes = Array.from({ length: n }, () => []);
|
|
892
|
+
const lavNodes = createLav(poly);
|
|
893
|
+
let iterations = 0;
|
|
894
|
+
const maxIter = n * n * 2;
|
|
895
|
+
while (iterations < maxIter) {
|
|
896
|
+
iterations++;
|
|
897
|
+
const activeStart = lavNodes.find((nd) => nd.active);
|
|
898
|
+
if (!activeStart) break;
|
|
899
|
+
const sz = lavSize(activeStart);
|
|
900
|
+
if (sz <= 3) {
|
|
901
|
+
if (sz === 3) {
|
|
902
|
+
const a = activeStart;
|
|
903
|
+
const b = a.next;
|
|
904
|
+
const c = b.next;
|
|
905
|
+
const t = bisectorIntersectTime(a, b);
|
|
906
|
+
const time = t !== null && t > EPS ? t : 0;
|
|
907
|
+
const mx = (a.x + b.x + c.x) / 3 + time * (a.bx + b.bx + c.bx) / 3;
|
|
908
|
+
const my = (a.y + b.y + c.y) / 3 + time * (a.by + b.by + c.by) / 3;
|
|
909
|
+
const nodeIdx = skeletonNodes.length;
|
|
910
|
+
skeletonNodes.push({ x: mx, y: my, height: time });
|
|
911
|
+
const aNodes = vertexToSkelNodes[a.origIdx];
|
|
912
|
+
const bNodes = vertexToSkelNodes[b.origIdx];
|
|
913
|
+
const cNodes = vertexToSkelNodes[c.origIdx];
|
|
914
|
+
if (aNodes) aNodes.push(nodeIdx);
|
|
915
|
+
if (bNodes) bNodes.push(nodeIdx);
|
|
916
|
+
if (cNodes) cNodes.push(nodeIdx);
|
|
917
|
+
a.active = false;
|
|
918
|
+
b.active = false;
|
|
919
|
+
c.active = false;
|
|
920
|
+
} else {
|
|
921
|
+
let cur = activeStart;
|
|
922
|
+
for (let i = 0; i < sz; i++) {
|
|
923
|
+
cur.active = false;
|
|
924
|
+
cur = cur.next;
|
|
925
|
+
}
|
|
926
|
+
}
|
|
927
|
+
continue;
|
|
928
|
+
}
|
|
929
|
+
const activeNodes = lavNodes.filter((nd) => nd.active);
|
|
930
|
+
const events = computeEvents(activeNodes);
|
|
931
|
+
if (events.length === 0) {
|
|
932
|
+
for (const nd of activeNodes) {
|
|
933
|
+
nd.active = false;
|
|
934
|
+
}
|
|
935
|
+
break;
|
|
936
|
+
}
|
|
937
|
+
const ev = events[0];
|
|
938
|
+
if (!ev) break;
|
|
939
|
+
if (ev.type === "edge") {
|
|
940
|
+
const a = ev.nodeA;
|
|
941
|
+
const b = ev.nodeB;
|
|
942
|
+
if (!a.active || !b.active) continue;
|
|
943
|
+
const nodeIdx = skeletonNodes.length;
|
|
944
|
+
skeletonNodes.push({ x: ev.x, y: ev.y, height: ev.time });
|
|
945
|
+
const aNodes = vertexToSkelNodes[a.origIdx];
|
|
946
|
+
const bNodes = vertexToSkelNodes[b.origIdx];
|
|
947
|
+
if (aNodes) aNodes.push(nodeIdx);
|
|
948
|
+
if (bNodes) bNodes.push(nodeIdx);
|
|
949
|
+
a.x = ev.x;
|
|
950
|
+
a.y = ev.y;
|
|
951
|
+
a.next = b.next;
|
|
952
|
+
b.next.prev = a;
|
|
953
|
+
b.active = false;
|
|
954
|
+
const lavPoly = [];
|
|
955
|
+
let cur = a;
|
|
956
|
+
do {
|
|
957
|
+
lavPoly.push({ x: cur.x, y: cur.y });
|
|
958
|
+
cur = cur.next;
|
|
959
|
+
} while (cur !== a);
|
|
960
|
+
const bDir = bisector(lavPoly, 0);
|
|
961
|
+
a.bx = bDir.dx;
|
|
962
|
+
a.by = bDir.dy;
|
|
963
|
+
} else {
|
|
964
|
+
const a = ev.nodeA;
|
|
965
|
+
const b = ev.nodeB;
|
|
966
|
+
if (!a.active || !b.active) continue;
|
|
967
|
+
const nodeIdx = skeletonNodes.length;
|
|
968
|
+
skeletonNodes.push({ x: ev.x, y: ev.y, height: ev.time });
|
|
969
|
+
const aNodes = vertexToSkelNodes[a.origIdx];
|
|
970
|
+
if (aNodes) aNodes.push(nodeIdx);
|
|
971
|
+
const bNodes = vertexToSkelNodes[b.origIdx];
|
|
972
|
+
if (bNodes) bNodes.push(nodeIdx);
|
|
973
|
+
const aCopy = {
|
|
974
|
+
x: ev.x,
|
|
975
|
+
y: ev.y,
|
|
976
|
+
bx: 0,
|
|
977
|
+
by: 0,
|
|
978
|
+
origIdx: a.origIdx,
|
|
979
|
+
prev: null,
|
|
980
|
+
next: null,
|
|
981
|
+
active: true
|
|
982
|
+
};
|
|
983
|
+
lavNodes.push(aCopy);
|
|
984
|
+
a.x = ev.x;
|
|
985
|
+
a.y = ev.y;
|
|
986
|
+
const aNext = a.next;
|
|
987
|
+
const bNext = b.next;
|
|
988
|
+
a.next = bNext;
|
|
989
|
+
bNext.prev = a;
|
|
990
|
+
aCopy.next = aNext;
|
|
991
|
+
aNext.prev = aCopy;
|
|
992
|
+
aCopy.prev = b;
|
|
993
|
+
b.next = aCopy;
|
|
994
|
+
const buildLavPoly = (start) => {
|
|
995
|
+
const poly2 = [];
|
|
996
|
+
let c = start;
|
|
997
|
+
do {
|
|
998
|
+
poly2.push({ x: c.x, y: c.y });
|
|
999
|
+
c = c.next;
|
|
1000
|
+
} while (c !== start);
|
|
1001
|
+
return poly2;
|
|
1002
|
+
};
|
|
1003
|
+
const lav1Poly = buildLavPoly(a);
|
|
1004
|
+
const bDir1 = bisector(lav1Poly, 0);
|
|
1005
|
+
a.bx = bDir1.dx;
|
|
1006
|
+
a.by = bDir1.dy;
|
|
1007
|
+
const lav2Poly = buildLavPoly(aCopy);
|
|
1008
|
+
const bDir2 = bisector(lav2Poly, 0);
|
|
1009
|
+
aCopy.bx = bDir2.dx;
|
|
1010
|
+
aCopy.by = bDir2.dy;
|
|
1011
|
+
}
|
|
1012
|
+
}
|
|
1013
|
+
const faces = [];
|
|
1014
|
+
for (let i = 0; i < n; i++) {
|
|
1015
|
+
const j = (i + 1) % n;
|
|
1016
|
+
const pi = polyAt(poly, i);
|
|
1017
|
+
const pj = polyAt(poly, j);
|
|
1018
|
+
const faceVerts = [pi, pj];
|
|
1019
|
+
const faceHeights = [0, 0];
|
|
1020
|
+
const jNodes = vertexToSkelNodes[j];
|
|
1021
|
+
const iNodes = vertexToSkelNodes[i];
|
|
1022
|
+
if (jNodes) {
|
|
1023
|
+
for (const ni of jNodes) {
|
|
1024
|
+
const sn = skeletonNodes[ni];
|
|
1025
|
+
if (sn) {
|
|
1026
|
+
faceVerts.push({ x: sn.x, y: sn.y });
|
|
1027
|
+
faceHeights.push(sn.height);
|
|
1028
|
+
}
|
|
1029
|
+
}
|
|
1030
|
+
}
|
|
1031
|
+
if (iNodes) {
|
|
1032
|
+
for (let k = iNodes.length - 1; k >= 0; k--) {
|
|
1033
|
+
const idx = iNodes[k];
|
|
1034
|
+
if (idx === void 0) continue;
|
|
1035
|
+
const sn = skeletonNodes[idx];
|
|
1036
|
+
if (!sn) continue;
|
|
1037
|
+
const lastVert = faceVerts[faceVerts.length - 1];
|
|
1038
|
+
if (!lastVert) continue;
|
|
1039
|
+
const dist = len2(sn.x - lastVert.x, sn.y - lastVert.y);
|
|
1040
|
+
if (dist > EPS) {
|
|
1041
|
+
faceVerts.push({ x: sn.x, y: sn.y });
|
|
1042
|
+
faceHeights.push(sn.height);
|
|
1043
|
+
}
|
|
1044
|
+
}
|
|
1045
|
+
}
|
|
1046
|
+
if (faceVerts.length >= 3) {
|
|
1047
|
+
faces.push({ vertices: faceVerts, heights: faceHeights });
|
|
1048
|
+
}
|
|
1049
|
+
}
|
|
1050
|
+
const uniqueNodes = [];
|
|
1051
|
+
for (const sn of skeletonNodes) {
|
|
1052
|
+
const exists = uniqueNodes.some(
|
|
1053
|
+
(un) => Math.abs(un.x - sn.x) < 0.01 && Math.abs(un.y - sn.y) < 0.01
|
|
1054
|
+
);
|
|
1055
|
+
if (!exists) {
|
|
1056
|
+
uniqueNodes.push(sn);
|
|
1057
|
+
}
|
|
1058
|
+
}
|
|
1059
|
+
return { nodes: uniqueNodes, faces };
|
|
1060
|
+
}
|
|
1061
|
+
function extractPolygon(w) {
|
|
1062
|
+
const edges = shapeFns.getEdges(w);
|
|
1063
|
+
const pts = edges.map((e) => {
|
|
1064
|
+
const pt = curveFns.curveStartPoint(e);
|
|
1065
|
+
return { x: pt[0], y: pt[1] };
|
|
1066
|
+
});
|
|
1067
|
+
const first = pts[0];
|
|
1068
|
+
const last = pts[pts.length - 1];
|
|
1069
|
+
if (pts.length > 1 && first && last && Math.abs(first.x - last.x) < 1e-10 && Math.abs(first.y - last.y) < 1e-10) {
|
|
1070
|
+
pts.pop();
|
|
1071
|
+
}
|
|
1072
|
+
return pts;
|
|
1073
|
+
}
|
|
1074
|
+
function fanTriangulate(count) {
|
|
1075
|
+
const tris = [];
|
|
1076
|
+
for (let i = 1; i < count - 1; i++) {
|
|
1077
|
+
tris.push([0, i, i + 1]);
|
|
1078
|
+
}
|
|
1079
|
+
return tris;
|
|
1080
|
+
}
|
|
1081
|
+
function buildTriFace$2(oc, a, b, c) {
|
|
1082
|
+
const gpA = new oc.gp_Pnt_3(a[0], a[1], a[2]);
|
|
1083
|
+
const gpB = new oc.gp_Pnt_3(b[0], b[1], b[2]);
|
|
1084
|
+
const gpC = new oc.gp_Pnt_3(c[0], c[1], c[2]);
|
|
1085
|
+
const e1 = new oc.BRepBuilderAPI_MakeEdge_3(gpA, gpB);
|
|
1086
|
+
const e2 = new oc.BRepBuilderAPI_MakeEdge_3(gpB, gpC);
|
|
1087
|
+
const e3 = new oc.BRepBuilderAPI_MakeEdge_3(gpC, gpA);
|
|
1088
|
+
const wireBuilder = new oc.BRepBuilderAPI_MakeWire_1();
|
|
1089
|
+
wireBuilder.Add_1(e1.Edge());
|
|
1090
|
+
wireBuilder.Add_1(e2.Edge());
|
|
1091
|
+
wireBuilder.Add_1(e3.Edge());
|
|
1092
|
+
let face2 = null;
|
|
1093
|
+
if (wireBuilder.IsDone()) {
|
|
1094
|
+
const makeFace = new oc.BRepBuilderAPI_MakeFace_15(wireBuilder.Wire(), false);
|
|
1095
|
+
if (makeFace.IsDone()) {
|
|
1096
|
+
face2 = makeFace.Face();
|
|
1097
|
+
}
|
|
1098
|
+
makeFace.delete();
|
|
1099
|
+
}
|
|
1100
|
+
wireBuilder.delete();
|
|
1101
|
+
e1.delete();
|
|
1102
|
+
e2.delete();
|
|
1103
|
+
e3.delete();
|
|
1104
|
+
gpA.delete();
|
|
1105
|
+
gpB.delete();
|
|
1106
|
+
gpC.delete();
|
|
1107
|
+
return face2;
|
|
1108
|
+
}
|
|
1109
|
+
function roof(w, options) {
|
|
1110
|
+
const angle = (options?.angle ?? 45) * (Math.PI / 180);
|
|
1111
|
+
const tanAngle = Math.tan(angle);
|
|
1112
|
+
try {
|
|
1113
|
+
const polygon2 = extractPolygon(w);
|
|
1114
|
+
if (polygon2.length < 3) {
|
|
1115
|
+
return errors.err(
|
|
1116
|
+
errors.occtError(errors.BrepErrorCode.ROOF_FAILED, "Wire must have at least 3 edges for roof generation")
|
|
1117
|
+
);
|
|
1118
|
+
}
|
|
1119
|
+
const skeleton = computeStraightSkeleton(polygon2);
|
|
1120
|
+
if (skeleton.faces.length === 0) {
|
|
1121
|
+
return errors.err(
|
|
1122
|
+
errors.occtError(errors.BrepErrorCode.ROOF_FAILED, "Straight skeleton computation produced no faces")
|
|
1123
|
+
);
|
|
1124
|
+
}
|
|
1125
|
+
const oc = occtBoundary.getKernel().oc;
|
|
1126
|
+
const sewing = new oc.BRepBuilderAPI_Sewing(1e-6, true, true, true, false);
|
|
1127
|
+
let faceCount = 0;
|
|
1128
|
+
try {
|
|
1129
|
+
for (const skFace of skeleton.faces) {
|
|
1130
|
+
const verts3d = skFace.vertices.map(
|
|
1131
|
+
(v, i) => [
|
|
1132
|
+
v.x,
|
|
1133
|
+
v.y,
|
|
1134
|
+
(skFace.heights[i] ?? 0) * tanAngle
|
|
1135
|
+
]
|
|
1136
|
+
);
|
|
1137
|
+
const tris = fanTriangulate(verts3d.length);
|
|
1138
|
+
for (const [ai, bi, ci] of tris) {
|
|
1139
|
+
const va = verts3d[ai];
|
|
1140
|
+
const vb = verts3d[bi];
|
|
1141
|
+
const vc = verts3d[ci];
|
|
1142
|
+
if (!va || !vb || !vc) continue;
|
|
1143
|
+
const abx = vb[0] - va[0];
|
|
1144
|
+
const aby = vb[1] - va[1];
|
|
1145
|
+
const abz = vb[2] - va[2];
|
|
1146
|
+
const acx = vc[0] - va[0];
|
|
1147
|
+
const acy = vc[1] - va[1];
|
|
1148
|
+
const acz = vc[2] - va[2];
|
|
1149
|
+
const nx = aby * acz - abz * acy;
|
|
1150
|
+
const ny = abz * acx - abx * acz;
|
|
1151
|
+
const nz = abx * acy - aby * acx;
|
|
1152
|
+
const areaSq = nx * nx + ny * ny + nz * nz;
|
|
1153
|
+
if (areaSq < 1e-20) continue;
|
|
1154
|
+
const triFace = buildTriFace$2(oc, va, vb, vc);
|
|
1155
|
+
if (triFace !== null) {
|
|
1156
|
+
sewing.Add(triFace);
|
|
1157
|
+
faceCount++;
|
|
1158
|
+
}
|
|
1159
|
+
}
|
|
1160
|
+
}
|
|
1161
|
+
const p0 = polygon2[0];
|
|
1162
|
+
if (p0) {
|
|
1163
|
+
for (let i = 1; i < polygon2.length - 1; i++) {
|
|
1164
|
+
const pi = polygon2[i];
|
|
1165
|
+
const pi1 = polygon2[i + 1];
|
|
1166
|
+
if (!pi || !pi1) continue;
|
|
1167
|
+
const va = [p0.x, p0.y, 0];
|
|
1168
|
+
const vb = [pi.x, pi.y, 0];
|
|
1169
|
+
const vc = [pi1.x, pi1.y, 0];
|
|
1170
|
+
const triFace = buildTriFace$2(oc, va, vc, vb);
|
|
1171
|
+
if (triFace !== null) {
|
|
1172
|
+
sewing.Add(triFace);
|
|
1173
|
+
faceCount++;
|
|
1174
|
+
}
|
|
1175
|
+
}
|
|
1176
|
+
}
|
|
1177
|
+
if (faceCount === 0) {
|
|
1178
|
+
return errors.err(
|
|
1179
|
+
errors.occtError(errors.BrepErrorCode.ROOF_FAILED, "No valid triangular faces could be built")
|
|
1180
|
+
);
|
|
1181
|
+
}
|
|
1182
|
+
const progress = new oc.Message_ProgressRange_1();
|
|
1183
|
+
sewing.Perform(progress);
|
|
1184
|
+
progress.delete();
|
|
1185
|
+
const sewn = sewing.SewedShape();
|
|
1186
|
+
const fixer = new oc.ShapeFix_Solid_1();
|
|
1187
|
+
try {
|
|
1188
|
+
const shell2 = oc.TopoDS.Shell_1(sewn);
|
|
1189
|
+
const solid2 = fixer.SolidFromShell(shell2);
|
|
1190
|
+
const shapeFixer = new oc.ShapeFix_Shape_1(solid2);
|
|
1191
|
+
const shapeFixProgress = new oc.Message_ProgressRange_1();
|
|
1192
|
+
try {
|
|
1193
|
+
shapeFixer.Perform(shapeFixProgress);
|
|
1194
|
+
const fixed = shapeFixer.Shape();
|
|
1195
|
+
return errors.ok(shapeTypes.createSolid(fixed));
|
|
1196
|
+
} finally {
|
|
1197
|
+
shapeFixProgress.delete();
|
|
1198
|
+
shapeFixer.delete();
|
|
1199
|
+
}
|
|
1200
|
+
} catch {
|
|
1201
|
+
return errors.ok(shapeTypes.castShape(sewn));
|
|
1202
|
+
} finally {
|
|
1203
|
+
fixer.delete();
|
|
1204
|
+
}
|
|
1205
|
+
} finally {
|
|
1206
|
+
sewing.delete();
|
|
1207
|
+
}
|
|
1208
|
+
} catch (e) {
|
|
1209
|
+
const msg = e instanceof Error ? e.message : String(e);
|
|
1210
|
+
return errors.err(errors.occtError(errors.BrepErrorCode.ROOF_FAILED, `Roof generation failed: ${msg}`, e));
|
|
1211
|
+
}
|
|
1212
|
+
}
|
|
1213
|
+
function solveConstraints(nodes, constraints) {
|
|
1214
|
+
const transforms = /* @__PURE__ */ new Map();
|
|
1215
|
+
for (const node of nodes) {
|
|
1216
|
+
transforms.set(node, {
|
|
1217
|
+
position: [0, 0, 0],
|
|
1218
|
+
rotation: [1, 0, 0, 0]
|
|
1219
|
+
});
|
|
1220
|
+
}
|
|
1221
|
+
for (const c of constraints) {
|
|
1222
|
+
if (c.type === "coincident" && c.entityA && c.entityB) {
|
|
1223
|
+
const a = c.entityA;
|
|
1224
|
+
const b = c.entityB;
|
|
1225
|
+
if (a.entity.type === "plane" && b.entity.type === "plane") {
|
|
1226
|
+
const aNormal = a.entity.normal ?? [0, 0, 1];
|
|
1227
|
+
const aOrigin = a.entity.origin;
|
|
1228
|
+
const bOrigin = b.entity.origin;
|
|
1229
|
+
const dot = aNormal[0] * (aOrigin[0] - bOrigin[0]) + aNormal[1] * (aOrigin[1] - bOrigin[1]) + aNormal[2] * (aOrigin[2] - bOrigin[2]);
|
|
1230
|
+
const pos = [dot * aNormal[0], dot * aNormal[1], dot * aNormal[2]];
|
|
1231
|
+
transforms.set(b.node, { position: pos, rotation: [1, 0, 0, 0] });
|
|
1232
|
+
}
|
|
1233
|
+
}
|
|
1234
|
+
if (c.type === "distance" && c.entityA && c.entityB && c.value !== void 0) {
|
|
1235
|
+
const a = c.entityA;
|
|
1236
|
+
const b = c.entityB;
|
|
1237
|
+
if (a.entity.type === "plane" && b.entity.type === "plane") {
|
|
1238
|
+
const aNormal = a.entity.normal ?? [0, 0, 1];
|
|
1239
|
+
const aOrigin = a.entity.origin;
|
|
1240
|
+
const bOrigin = b.entity.origin;
|
|
1241
|
+
const currentDist = aNormal[0] * (aOrigin[0] - bOrigin[0]) + aNormal[1] * (aOrigin[1] - bOrigin[1]) + aNormal[2] * (aOrigin[2] - bOrigin[2]);
|
|
1242
|
+
const offset2 = currentDist + c.value;
|
|
1243
|
+
const pos = [offset2 * aNormal[0], offset2 * aNormal[1], offset2 * aNormal[2]];
|
|
1244
|
+
transforms.set(b.node, { position: pos, rotation: [1, 0, 0, 0] });
|
|
1245
|
+
}
|
|
1246
|
+
}
|
|
1247
|
+
}
|
|
1248
|
+
return { transforms, dof: 0, converged: true };
|
|
1249
|
+
}
|
|
1250
|
+
function extractEntity(mate) {
|
|
1251
|
+
if (mate.face) {
|
|
1252
|
+
const origin = faceFns.faceCenter(mate.face);
|
|
1253
|
+
const normal = faceFns.normalAt(mate.face);
|
|
1254
|
+
return { type: "plane", origin, normal };
|
|
1255
|
+
}
|
|
1256
|
+
if (mate.point) {
|
|
1257
|
+
return { type: "point", origin: mate.point };
|
|
1258
|
+
}
|
|
1259
|
+
return null;
|
|
1260
|
+
}
|
|
1261
|
+
function addMate(assembly, constraint) {
|
|
1262
|
+
const existing = assembly.mates ?? [];
|
|
1263
|
+
return { ...assembly, mates: [...existing, constraint] };
|
|
1264
|
+
}
|
|
1265
|
+
function solveAssembly(assembly) {
|
|
1266
|
+
const mates = assembly.mates;
|
|
1267
|
+
if (!mates || mates.length === 0) {
|
|
1268
|
+
return errors.err(
|
|
1269
|
+
errors.validationError(errors.BrepErrorCode.ASSEMBLY_MATE_INVALID, "solveAssembly: no mates defined")
|
|
1270
|
+
);
|
|
1271
|
+
}
|
|
1272
|
+
try {
|
|
1273
|
+
const nodes = [];
|
|
1274
|
+
operations.walkAssembly(assembly, (node) => {
|
|
1275
|
+
nodes.push(node.name);
|
|
1276
|
+
});
|
|
1277
|
+
const solverConstraints = [];
|
|
1278
|
+
for (const mate of mates) {
|
|
1279
|
+
if (mate.type === "fixed") {
|
|
1280
|
+
solverConstraints.push({
|
|
1281
|
+
type: "fixed",
|
|
1282
|
+
entityA: { node: mate.entity.node, entity: { type: "point", origin: [0, 0, 0] } }
|
|
1283
|
+
});
|
|
1284
|
+
continue;
|
|
1285
|
+
}
|
|
1286
|
+
if (mate.type === "coincident") {
|
|
1287
|
+
const entA = extractEntity(mate.entityA);
|
|
1288
|
+
const entB = extractEntity(mate.entityB);
|
|
1289
|
+
if (!entA || !entB) {
|
|
1290
|
+
return errors.err(
|
|
1291
|
+
errors.validationError(
|
|
1292
|
+
errors.BrepErrorCode.ASSEMBLY_MATE_INVALID,
|
|
1293
|
+
"solveAssembly: could not extract geometry from mate entities"
|
|
1294
|
+
)
|
|
1295
|
+
);
|
|
1296
|
+
}
|
|
1297
|
+
solverConstraints.push({
|
|
1298
|
+
type: "coincident",
|
|
1299
|
+
entityA: { node: mate.entityA.node, entity: entA },
|
|
1300
|
+
entityB: { node: mate.entityB.node, entity: entB }
|
|
1301
|
+
});
|
|
1302
|
+
}
|
|
1303
|
+
if (mate.type === "distance") {
|
|
1304
|
+
const entA = extractEntity(mate.entityA);
|
|
1305
|
+
const entB = extractEntity(mate.entityB);
|
|
1306
|
+
if (!entA || !entB) {
|
|
1307
|
+
return errors.err(
|
|
1308
|
+
errors.validationError(
|
|
1309
|
+
errors.BrepErrorCode.ASSEMBLY_MATE_INVALID,
|
|
1310
|
+
"solveAssembly: could not extract geometry from mate entities"
|
|
1311
|
+
)
|
|
1312
|
+
);
|
|
1313
|
+
}
|
|
1314
|
+
solverConstraints.push({
|
|
1315
|
+
type: "distance",
|
|
1316
|
+
entityA: { node: mate.entityA.node, entity: entA },
|
|
1317
|
+
entityB: { node: mate.entityB.node, entity: entB },
|
|
1318
|
+
value: mate.distance
|
|
1319
|
+
});
|
|
1320
|
+
}
|
|
1321
|
+
if (mate.type === "angle") {
|
|
1322
|
+
const entA = extractEntity(mate.entityA);
|
|
1323
|
+
const entB = extractEntity(mate.entityB);
|
|
1324
|
+
if (!entA || !entB) {
|
|
1325
|
+
return errors.err(
|
|
1326
|
+
errors.validationError(
|
|
1327
|
+
errors.BrepErrorCode.ASSEMBLY_MATE_INVALID,
|
|
1328
|
+
"solveAssembly: could not extract geometry from mate entities"
|
|
1329
|
+
)
|
|
1330
|
+
);
|
|
1331
|
+
}
|
|
1332
|
+
solverConstraints.push({
|
|
1333
|
+
type: "angle",
|
|
1334
|
+
entityA: { node: mate.entityA.node, entity: entA },
|
|
1335
|
+
entityB: { node: mate.entityB.node, entity: entB },
|
|
1336
|
+
value: mate.angle
|
|
1337
|
+
});
|
|
1338
|
+
}
|
|
1339
|
+
if (mate.type === "concentric") {
|
|
1340
|
+
const entA = extractEntity(mate.axisA);
|
|
1341
|
+
const entB = extractEntity(mate.axisB);
|
|
1342
|
+
if (!entA || !entB) {
|
|
1343
|
+
return errors.err(
|
|
1344
|
+
errors.validationError(
|
|
1345
|
+
errors.BrepErrorCode.ASSEMBLY_MATE_INVALID,
|
|
1346
|
+
"solveAssembly: could not extract geometry from mate entities"
|
|
1347
|
+
)
|
|
1348
|
+
);
|
|
1349
|
+
}
|
|
1350
|
+
solverConstraints.push({
|
|
1351
|
+
type: "concentric",
|
|
1352
|
+
entityA: { node: mate.axisA.node, entity: entA },
|
|
1353
|
+
entityB: { node: mate.axisB.node, entity: entB }
|
|
1354
|
+
});
|
|
1355
|
+
}
|
|
1356
|
+
}
|
|
1357
|
+
const result2 = solveConstraints(nodes, solverConstraints);
|
|
1358
|
+
if (!result2.converged) ;
|
|
1359
|
+
return errors.ok({
|
|
1360
|
+
transforms: result2.transforms,
|
|
1361
|
+
dof: result2.dof,
|
|
1362
|
+
converged: result2.converged
|
|
1363
|
+
});
|
|
1364
|
+
} catch (e) {
|
|
1365
|
+
const raw = e instanceof Error ? e.message : String(e);
|
|
1366
|
+
return errors.err(errors.occtError(errors.BrepErrorCode.ASSEMBLY_SOLVE_FAILED, `Assembly solve failed: ${raw}`, e));
|
|
1367
|
+
}
|
|
1368
|
+
}
|
|
312
1369
|
function checkInterference(shape1, shape2, tolerance = 1e-6) {
|
|
313
1370
|
if (shape1.wrapped.IsNull()) {
|
|
314
1371
|
return errors.err(
|
|
@@ -346,6 +1403,458 @@ function checkAllInterferences(shapes, tolerance = 1e-6) {
|
|
|
346
1403
|
});
|
|
347
1404
|
return pairs;
|
|
348
1405
|
}
|
|
1406
|
+
function parseEntities(text) {
|
|
1407
|
+
const lines = text.split(/\r?\n/);
|
|
1408
|
+
const entities = [];
|
|
1409
|
+
let inEntities = false;
|
|
1410
|
+
let current;
|
|
1411
|
+
for (let i = 0; i < lines.length - 1; i += 2) {
|
|
1412
|
+
const codeLine = lines[i];
|
|
1413
|
+
const valueLine = lines[i + 1];
|
|
1414
|
+
if (codeLine === void 0 || valueLine === void 0) continue;
|
|
1415
|
+
const code = parseInt(codeLine.trim(), 10);
|
|
1416
|
+
const value = valueLine.trim();
|
|
1417
|
+
if (isNaN(code)) continue;
|
|
1418
|
+
if (code === 2 && value === "ENTITIES") {
|
|
1419
|
+
inEntities = true;
|
|
1420
|
+
continue;
|
|
1421
|
+
}
|
|
1422
|
+
if (!inEntities) continue;
|
|
1423
|
+
if (code === 0) {
|
|
1424
|
+
if (value === "ENDSEC" || value === "EOF") {
|
|
1425
|
+
if (current) entities.push(current);
|
|
1426
|
+
break;
|
|
1427
|
+
}
|
|
1428
|
+
if (current) entities.push(current);
|
|
1429
|
+
current = { type: value, layer: "0", data: /* @__PURE__ */ new Map() };
|
|
1430
|
+
continue;
|
|
1431
|
+
}
|
|
1432
|
+
if (current) {
|
|
1433
|
+
if (code === 8) {
|
|
1434
|
+
current.layer = value;
|
|
1435
|
+
} else {
|
|
1436
|
+
current.data.set(code, value);
|
|
1437
|
+
}
|
|
1438
|
+
}
|
|
1439
|
+
}
|
|
1440
|
+
return entities;
|
|
1441
|
+
}
|
|
1442
|
+
function getNum(data, code, fallback = 0) {
|
|
1443
|
+
const v = data.get(code);
|
|
1444
|
+
if (v === void 0) return fallback;
|
|
1445
|
+
const n = parseFloat(v);
|
|
1446
|
+
return isNaN(n) ? fallback : n;
|
|
1447
|
+
}
|
|
1448
|
+
function entityToEdge(entity, oc) {
|
|
1449
|
+
const { type, data } = entity;
|
|
1450
|
+
if (type === "LINE") {
|
|
1451
|
+
const p1 = new oc.gp_Pnt_3(getNum(data, 10), getNum(data, 20), getNum(data, 30));
|
|
1452
|
+
const p2 = new oc.gp_Pnt_3(getNum(data, 11), getNum(data, 21), getNum(data, 31));
|
|
1453
|
+
try {
|
|
1454
|
+
const builder = new oc.BRepBuilderAPI_MakeEdge_3(p1, p2);
|
|
1455
|
+
const edge = builder.Edge();
|
|
1456
|
+
builder.delete();
|
|
1457
|
+
return edge;
|
|
1458
|
+
} finally {
|
|
1459
|
+
p1.delete();
|
|
1460
|
+
p2.delete();
|
|
1461
|
+
}
|
|
1462
|
+
}
|
|
1463
|
+
if (type === "CIRCLE") {
|
|
1464
|
+
const cx = getNum(data, 10);
|
|
1465
|
+
const cy = getNum(data, 20);
|
|
1466
|
+
const cz = getNum(data, 30);
|
|
1467
|
+
const radius = getNum(data, 40);
|
|
1468
|
+
const center = new oc.gp_Pnt_3(cx, cy, cz);
|
|
1469
|
+
const dir = new oc.gp_Dir_4(0, 0, 1);
|
|
1470
|
+
const ax2 = new oc.gp_Ax2_3(center, dir);
|
|
1471
|
+
const circ = new oc.gp_Circ_2(ax2, radius);
|
|
1472
|
+
try {
|
|
1473
|
+
const builder = new oc.BRepBuilderAPI_MakeEdge_8(circ);
|
|
1474
|
+
const edge = builder.Edge();
|
|
1475
|
+
builder.delete();
|
|
1476
|
+
return edge;
|
|
1477
|
+
} finally {
|
|
1478
|
+
center.delete();
|
|
1479
|
+
dir.delete();
|
|
1480
|
+
ax2.delete();
|
|
1481
|
+
circ.delete();
|
|
1482
|
+
}
|
|
1483
|
+
}
|
|
1484
|
+
if (type === "ARC") {
|
|
1485
|
+
const cx = getNum(data, 10);
|
|
1486
|
+
const cy = getNum(data, 20);
|
|
1487
|
+
const cz = getNum(data, 30);
|
|
1488
|
+
const radius = getNum(data, 40);
|
|
1489
|
+
const startAngleDeg = getNum(data, 50);
|
|
1490
|
+
const endAngleDeg = getNum(data, 51);
|
|
1491
|
+
const startAngle = startAngleDeg * Math.PI / 180;
|
|
1492
|
+
const endAngle = endAngleDeg * Math.PI / 180;
|
|
1493
|
+
const center = new oc.gp_Pnt_3(cx, cy, cz);
|
|
1494
|
+
const dir = new oc.gp_Dir_4(0, 0, 1);
|
|
1495
|
+
const ax2 = new oc.gp_Ax2_3(center, dir);
|
|
1496
|
+
const circ = new oc.gp_Circ_2(ax2, radius);
|
|
1497
|
+
try {
|
|
1498
|
+
const builder = new oc.BRepBuilderAPI_MakeEdge_9(circ, startAngle, endAngle);
|
|
1499
|
+
const edge = builder.Edge();
|
|
1500
|
+
builder.delete();
|
|
1501
|
+
return edge;
|
|
1502
|
+
} finally {
|
|
1503
|
+
center.delete();
|
|
1504
|
+
dir.delete();
|
|
1505
|
+
ax2.delete();
|
|
1506
|
+
circ.delete();
|
|
1507
|
+
}
|
|
1508
|
+
}
|
|
1509
|
+
return void 0;
|
|
1510
|
+
}
|
|
1511
|
+
async function importDXF(blob, options) {
|
|
1512
|
+
const oc = occtBoundary.getKernel().oc;
|
|
1513
|
+
let text;
|
|
1514
|
+
try {
|
|
1515
|
+
text = await blob.text();
|
|
1516
|
+
} catch (cause) {
|
|
1517
|
+
return errors.err(errors.ioError(errors.BrepErrorCode.DXF_IMPORT_FAILED, "Failed to read DXF blob", cause));
|
|
1518
|
+
}
|
|
1519
|
+
const allEntities = parseEntities(text);
|
|
1520
|
+
const entities = options?.layer !== void 0 ? allEntities.filter((e) => e.layer === options.layer) : allEntities;
|
|
1521
|
+
if (entities.length === 0) {
|
|
1522
|
+
return errors.ok([]);
|
|
1523
|
+
}
|
|
1524
|
+
const edges = [];
|
|
1525
|
+
try {
|
|
1526
|
+
for (const entity of entities) {
|
|
1527
|
+
const edge = entityToEdge(entity, oc);
|
|
1528
|
+
if (edge !== void 0) {
|
|
1529
|
+
edges.push(edge);
|
|
1530
|
+
}
|
|
1531
|
+
}
|
|
1532
|
+
if (edges.length === 0) {
|
|
1533
|
+
return errors.ok([]);
|
|
1534
|
+
}
|
|
1535
|
+
const wireBuilder = new oc.BRepBuilderAPI_MakeWire_1();
|
|
1536
|
+
try {
|
|
1537
|
+
for (const edge of edges) {
|
|
1538
|
+
wireBuilder.Add_1(edge);
|
|
1539
|
+
}
|
|
1540
|
+
if (wireBuilder.IsDone()) {
|
|
1541
|
+
const wire2 = wireBuilder.Wire();
|
|
1542
|
+
return errors.ok([shapeTypes.createWire(wire2)]);
|
|
1543
|
+
}
|
|
1544
|
+
return errors.err(
|
|
1545
|
+
errors.ioError(errors.BrepErrorCode.DXF_IMPORT_FAILED, "Failed to assemble DXF edges into a wire")
|
|
1546
|
+
);
|
|
1547
|
+
} finally {
|
|
1548
|
+
wireBuilder.delete();
|
|
1549
|
+
}
|
|
1550
|
+
} catch (cause) {
|
|
1551
|
+
return errors.err(
|
|
1552
|
+
errors.ioError(errors.BrepErrorCode.DXF_IMPORT_FAILED, "Failed to convert DXF entities to geometry", cause)
|
|
1553
|
+
);
|
|
1554
|
+
} finally {
|
|
1555
|
+
for (const edge of edges) {
|
|
1556
|
+
edge.delete();
|
|
1557
|
+
}
|
|
1558
|
+
}
|
|
1559
|
+
}
|
|
1560
|
+
async function importOBJ(blob) {
|
|
1561
|
+
const text = await blob.text();
|
|
1562
|
+
const lines = text.split("\n");
|
|
1563
|
+
const vertices = [];
|
|
1564
|
+
const faces = [];
|
|
1565
|
+
for (const raw of lines) {
|
|
1566
|
+
const line2 = raw.trim();
|
|
1567
|
+
if (line2.startsWith("v ")) {
|
|
1568
|
+
const parts = line2.split(/\s+/);
|
|
1569
|
+
const x = parseFloat(parts[1] ?? "");
|
|
1570
|
+
const y = parseFloat(parts[2] ?? "");
|
|
1571
|
+
const z = parseFloat(parts[3] ?? "");
|
|
1572
|
+
if (isNaN(x) || isNaN(y) || isNaN(z)) continue;
|
|
1573
|
+
vertices.push([x, y, z]);
|
|
1574
|
+
} else if (line2.startsWith("f ")) {
|
|
1575
|
+
const parts = line2.split(/\s+/).slice(1);
|
|
1576
|
+
const indices = [];
|
|
1577
|
+
for (const p of parts) {
|
|
1578
|
+
const idx = parseInt(p.split("/")[0] ?? "", 10);
|
|
1579
|
+
if (!isNaN(idx)) indices.push(idx);
|
|
1580
|
+
}
|
|
1581
|
+
if (indices.length >= 3) faces.push(indices);
|
|
1582
|
+
}
|
|
1583
|
+
}
|
|
1584
|
+
if (vertices.length === 0 || faces.length === 0) {
|
|
1585
|
+
return errors.err(errors.ioError(errors.BrepErrorCode.OBJ_IMPORT_FAILED, "OBJ file contains no valid geometry"));
|
|
1586
|
+
}
|
|
1587
|
+
try {
|
|
1588
|
+
return buildSolidFromMesh$1(vertices, faces);
|
|
1589
|
+
} catch (e) {
|
|
1590
|
+
const msg = e instanceof Error ? e.message : String(e);
|
|
1591
|
+
return errors.err(errors.ioError(errors.BrepErrorCode.OBJ_IMPORT_FAILED, `OBJ import failed: ${msg}`, e));
|
|
1592
|
+
}
|
|
1593
|
+
}
|
|
1594
|
+
function buildSolidFromMesh$1(vertices, faces) {
|
|
1595
|
+
const oc = occtBoundary.getKernel().oc;
|
|
1596
|
+
const sewing = new oc.BRepBuilderAPI_Sewing(1e-6, true, true, true, false);
|
|
1597
|
+
let faceCount = 0;
|
|
1598
|
+
try {
|
|
1599
|
+
for (const face2 of faces) {
|
|
1600
|
+
for (let i = 1; i < face2.length - 1; i++) {
|
|
1601
|
+
const rawA = face2[0] ?? 0;
|
|
1602
|
+
const rawB = face2[i] ?? 0;
|
|
1603
|
+
const rawC = face2[i + 1] ?? 0;
|
|
1604
|
+
const ai = rawA > 0 ? rawA - 1 : vertices.length + rawA;
|
|
1605
|
+
const bi = rawB > 0 ? rawB - 1 : vertices.length + rawB;
|
|
1606
|
+
const ci = rawC > 0 ? rawC - 1 : vertices.length + rawC;
|
|
1607
|
+
const va = vertices[ai];
|
|
1608
|
+
const vb = vertices[bi];
|
|
1609
|
+
const vc = vertices[ci];
|
|
1610
|
+
if (!va || !vb || !vc) continue;
|
|
1611
|
+
const triFace = buildTriFace$1(oc, va, vb, vc);
|
|
1612
|
+
if (triFace !== null) {
|
|
1613
|
+
sewing.Add(triFace);
|
|
1614
|
+
faceCount++;
|
|
1615
|
+
}
|
|
1616
|
+
}
|
|
1617
|
+
}
|
|
1618
|
+
if (faceCount === 0) {
|
|
1619
|
+
return errors.err(
|
|
1620
|
+
errors.ioError(errors.BrepErrorCode.OBJ_IMPORT_FAILED, "No valid triangular faces could be built")
|
|
1621
|
+
);
|
|
1622
|
+
}
|
|
1623
|
+
const progress = new oc.Message_ProgressRange_1();
|
|
1624
|
+
sewing.Perform(progress);
|
|
1625
|
+
progress.delete();
|
|
1626
|
+
const sewn = sewing.SewedShape();
|
|
1627
|
+
const fixer = new oc.ShapeFix_Solid_1();
|
|
1628
|
+
try {
|
|
1629
|
+
const shell2 = oc.TopoDS.Shell_1(sewn);
|
|
1630
|
+
const solid2 = fixer.SolidFromShell(shell2);
|
|
1631
|
+
return errors.ok(shapeTypes.castShape(solid2));
|
|
1632
|
+
} catch {
|
|
1633
|
+
return errors.ok(shapeTypes.castShape(sewn));
|
|
1634
|
+
} finally {
|
|
1635
|
+
fixer.delete();
|
|
1636
|
+
}
|
|
1637
|
+
} finally {
|
|
1638
|
+
sewing.delete();
|
|
1639
|
+
}
|
|
1640
|
+
}
|
|
1641
|
+
function buildTriFace$1(oc, a, b, c) {
|
|
1642
|
+
const gpA = new oc.gp_Pnt_3(a[0], a[1], a[2]);
|
|
1643
|
+
const gpB = new oc.gp_Pnt_3(b[0], b[1], b[2]);
|
|
1644
|
+
const gpC = new oc.gp_Pnt_3(c[0], c[1], c[2]);
|
|
1645
|
+
const e1 = new oc.BRepBuilderAPI_MakeEdge_3(gpA, gpB);
|
|
1646
|
+
const e2 = new oc.BRepBuilderAPI_MakeEdge_3(gpB, gpC);
|
|
1647
|
+
const e3 = new oc.BRepBuilderAPI_MakeEdge_3(gpC, gpA);
|
|
1648
|
+
const wireBuilder = new oc.BRepBuilderAPI_MakeWire_1();
|
|
1649
|
+
wireBuilder.Add_1(e1.Edge());
|
|
1650
|
+
wireBuilder.Add_1(e2.Edge());
|
|
1651
|
+
wireBuilder.Add_1(e3.Edge());
|
|
1652
|
+
let face2 = null;
|
|
1653
|
+
if (wireBuilder.IsDone()) {
|
|
1654
|
+
const makeFace = new oc.BRepBuilderAPI_MakeFace_15(wireBuilder.Wire(), false);
|
|
1655
|
+
if (makeFace.IsDone()) {
|
|
1656
|
+
face2 = makeFace.Face();
|
|
1657
|
+
}
|
|
1658
|
+
makeFace.delete();
|
|
1659
|
+
}
|
|
1660
|
+
wireBuilder.delete();
|
|
1661
|
+
e1.delete();
|
|
1662
|
+
e2.delete();
|
|
1663
|
+
e3.delete();
|
|
1664
|
+
gpA.delete();
|
|
1665
|
+
gpB.delete();
|
|
1666
|
+
gpC.delete();
|
|
1667
|
+
return face2;
|
|
1668
|
+
}
|
|
1669
|
+
function extractFromZip(data, target) {
|
|
1670
|
+
let eocdOffset = -1;
|
|
1671
|
+
for (let i = data.length - 22; i >= 0; i--) {
|
|
1672
|
+
if (data[i] === 80 && data[i + 1] === 75 && data[i + 2] === 5 && data[i + 3] === 6) {
|
|
1673
|
+
eocdOffset = i;
|
|
1674
|
+
break;
|
|
1675
|
+
}
|
|
1676
|
+
}
|
|
1677
|
+
if (eocdOffset < 0) return null;
|
|
1678
|
+
const view = new DataView(data.buffer, data.byteOffset, data.byteLength);
|
|
1679
|
+
const cdOffset = view.getUint32(eocdOffset + 16, true);
|
|
1680
|
+
const cdSize = view.getUint32(eocdOffset + 12, true);
|
|
1681
|
+
const cdEnd = cdOffset + cdSize;
|
|
1682
|
+
let pos = cdOffset;
|
|
1683
|
+
const decoder = new TextDecoder();
|
|
1684
|
+
while (pos < cdEnd) {
|
|
1685
|
+
const sig = view.getUint32(pos, true);
|
|
1686
|
+
if (sig !== 33639248) break;
|
|
1687
|
+
const nameLen = view.getUint16(pos + 28, true);
|
|
1688
|
+
const extraLen = view.getUint16(pos + 30, true);
|
|
1689
|
+
const commentLen = view.getUint16(pos + 32, true);
|
|
1690
|
+
const localOffset = view.getUint32(pos + 42, true);
|
|
1691
|
+
const name = decoder.decode(data.subarray(pos + 46, pos + 46 + nameLen));
|
|
1692
|
+
if (name === target) {
|
|
1693
|
+
const compressionMethod = view.getUint16(localOffset + 8, true);
|
|
1694
|
+
if (compressionMethod !== 0) {
|
|
1695
|
+
return null;
|
|
1696
|
+
}
|
|
1697
|
+
const localNameLen = view.getUint16(localOffset + 26, true);
|
|
1698
|
+
const localExtraLen = view.getUint16(localOffset + 28, true);
|
|
1699
|
+
const compressedSize = view.getUint32(localOffset + 18, true);
|
|
1700
|
+
const dataStart = localOffset + 30 + localNameLen + localExtraLen;
|
|
1701
|
+
return data.subarray(dataStart, dataStart + compressedSize);
|
|
1702
|
+
}
|
|
1703
|
+
pos += 46 + nameLen + extraLen + commentLen;
|
|
1704
|
+
}
|
|
1705
|
+
return null;
|
|
1706
|
+
}
|
|
1707
|
+
function isAttrChar(code) {
|
|
1708
|
+
return code >= 97 && code <= 122 || // a-z
|
|
1709
|
+
code >= 65 && code <= 90 || // A-Z
|
|
1710
|
+
code >= 48 && code <= 57 || // 0-9
|
|
1711
|
+
code === 95;
|
|
1712
|
+
}
|
|
1713
|
+
function parseTagAttrs(tag) {
|
|
1714
|
+
const attrs = {};
|
|
1715
|
+
let pos = 0;
|
|
1716
|
+
while (pos < tag.length) {
|
|
1717
|
+
const eq = tag.indexOf('="', pos);
|
|
1718
|
+
if (eq < 0) break;
|
|
1719
|
+
let nameStart = eq;
|
|
1720
|
+
while (nameStart > 0 && isAttrChar(tag.charCodeAt(nameStart - 1))) nameStart--;
|
|
1721
|
+
if (nameStart === eq) {
|
|
1722
|
+
pos = eq + 2;
|
|
1723
|
+
continue;
|
|
1724
|
+
}
|
|
1725
|
+
const name = tag.slice(nameStart, eq);
|
|
1726
|
+
const valStart = eq + 2;
|
|
1727
|
+
const closeQuote = tag.indexOf('"', valStart);
|
|
1728
|
+
if (closeQuote < 0) break;
|
|
1729
|
+
attrs[name] = tag.slice(valStart, closeQuote);
|
|
1730
|
+
pos = closeQuote + 1;
|
|
1731
|
+
}
|
|
1732
|
+
return attrs;
|
|
1733
|
+
}
|
|
1734
|
+
function findTags(xml, tagName) {
|
|
1735
|
+
const tags = [];
|
|
1736
|
+
const needle = `<${tagName} `;
|
|
1737
|
+
let pos = 0;
|
|
1738
|
+
while (pos < xml.length) {
|
|
1739
|
+
const start = xml.indexOf(needle, pos);
|
|
1740
|
+
if (start < 0) break;
|
|
1741
|
+
const end = xml.indexOf(">", start);
|
|
1742
|
+
if (end < 0) break;
|
|
1743
|
+
tags.push(xml.slice(start, end + 1));
|
|
1744
|
+
pos = end + 1;
|
|
1745
|
+
}
|
|
1746
|
+
return tags;
|
|
1747
|
+
}
|
|
1748
|
+
function parseModelXml(xml) {
|
|
1749
|
+
const vertices = [];
|
|
1750
|
+
const triangles = [];
|
|
1751
|
+
for (const tag of findTags(xml, "vertex")) {
|
|
1752
|
+
const a = parseTagAttrs(tag);
|
|
1753
|
+
if (a["x"] !== void 0 && a["y"] !== void 0 && a["z"] !== void 0) {
|
|
1754
|
+
vertices.push([parseFloat(a["x"]), parseFloat(a["y"]), parseFloat(a["z"])]);
|
|
1755
|
+
}
|
|
1756
|
+
}
|
|
1757
|
+
for (const tag of findTags(xml, "triangle")) {
|
|
1758
|
+
const a = parseTagAttrs(tag);
|
|
1759
|
+
if (a["v1"] !== void 0 && a["v2"] !== void 0 && a["v3"] !== void 0) {
|
|
1760
|
+
triangles.push([parseInt(a["v1"], 10), parseInt(a["v2"], 10), parseInt(a["v3"], 10)]);
|
|
1761
|
+
}
|
|
1762
|
+
}
|
|
1763
|
+
return { vertices, triangles };
|
|
1764
|
+
}
|
|
1765
|
+
function buildTriFace(oc, a, b, c) {
|
|
1766
|
+
const gpA = new oc.gp_Pnt_3(a[0], a[1], a[2]);
|
|
1767
|
+
const gpB = new oc.gp_Pnt_3(b[0], b[1], b[2]);
|
|
1768
|
+
const gpC = new oc.gp_Pnt_3(c[0], c[1], c[2]);
|
|
1769
|
+
const e1 = new oc.BRepBuilderAPI_MakeEdge_3(gpA, gpB);
|
|
1770
|
+
const e2 = new oc.BRepBuilderAPI_MakeEdge_3(gpB, gpC);
|
|
1771
|
+
const e3 = new oc.BRepBuilderAPI_MakeEdge_3(gpC, gpA);
|
|
1772
|
+
const wireBuilder = new oc.BRepBuilderAPI_MakeWire_1();
|
|
1773
|
+
wireBuilder.Add_1(e1.Edge());
|
|
1774
|
+
wireBuilder.Add_1(e2.Edge());
|
|
1775
|
+
wireBuilder.Add_1(e3.Edge());
|
|
1776
|
+
let face2 = null;
|
|
1777
|
+
if (wireBuilder.IsDone()) {
|
|
1778
|
+
const makeFace = new oc.BRepBuilderAPI_MakeFace_15(wireBuilder.Wire(), false);
|
|
1779
|
+
if (makeFace.IsDone()) {
|
|
1780
|
+
face2 = makeFace.Face();
|
|
1781
|
+
}
|
|
1782
|
+
makeFace.delete();
|
|
1783
|
+
}
|
|
1784
|
+
wireBuilder.delete();
|
|
1785
|
+
e1.delete();
|
|
1786
|
+
e2.delete();
|
|
1787
|
+
e3.delete();
|
|
1788
|
+
gpA.delete();
|
|
1789
|
+
gpB.delete();
|
|
1790
|
+
gpC.delete();
|
|
1791
|
+
return face2;
|
|
1792
|
+
}
|
|
1793
|
+
function buildSolidFromMesh(mesh2) {
|
|
1794
|
+
const oc = occtBoundary.getKernel().oc;
|
|
1795
|
+
const sewing = new oc.BRepBuilderAPI_Sewing(1e-6, true, true, true, false);
|
|
1796
|
+
let faceCount = 0;
|
|
1797
|
+
try {
|
|
1798
|
+
for (const [v1, v2, v3] of mesh2.triangles) {
|
|
1799
|
+
const va = mesh2.vertices[v1];
|
|
1800
|
+
const vb = mesh2.vertices[v2];
|
|
1801
|
+
const vc = mesh2.vertices[v3];
|
|
1802
|
+
if (!va || !vb || !vc) continue;
|
|
1803
|
+
const triFace = buildTriFace(oc, va, vb, vc);
|
|
1804
|
+
if (triFace !== null) {
|
|
1805
|
+
sewing.Add(triFace);
|
|
1806
|
+
faceCount++;
|
|
1807
|
+
}
|
|
1808
|
+
}
|
|
1809
|
+
if (faceCount === 0) {
|
|
1810
|
+
return errors.err(
|
|
1811
|
+
errors.ioError(errors.BrepErrorCode.THREEMF_IMPORT_FAILED, "No valid triangular faces could be built")
|
|
1812
|
+
);
|
|
1813
|
+
}
|
|
1814
|
+
const progress = new oc.Message_ProgressRange_1();
|
|
1815
|
+
sewing.Perform(progress);
|
|
1816
|
+
progress.delete();
|
|
1817
|
+
const sewn = sewing.SewedShape();
|
|
1818
|
+
const fixer = new oc.ShapeFix_Solid_1();
|
|
1819
|
+
try {
|
|
1820
|
+
const shell2 = oc.TopoDS.Shell_1(sewn);
|
|
1821
|
+
const solid2 = fixer.SolidFromShell(shell2);
|
|
1822
|
+
return errors.ok(shapeTypes.castShape(solid2));
|
|
1823
|
+
} catch {
|
|
1824
|
+
return errors.ok(shapeTypes.castShape(sewn));
|
|
1825
|
+
} finally {
|
|
1826
|
+
fixer.delete();
|
|
1827
|
+
}
|
|
1828
|
+
} finally {
|
|
1829
|
+
sewing.delete();
|
|
1830
|
+
}
|
|
1831
|
+
}
|
|
1832
|
+
async function importThreeMF(blob) {
|
|
1833
|
+
try {
|
|
1834
|
+
const arrayBuf = await blob.arrayBuffer();
|
|
1835
|
+
const data = new Uint8Array(arrayBuf);
|
|
1836
|
+
const modelData = extractFromZip(data, "3D/3dmodel.model");
|
|
1837
|
+
if (!modelData) {
|
|
1838
|
+
return errors.err(
|
|
1839
|
+
errors.ioError(
|
|
1840
|
+
errors.BrepErrorCode.THREEMF_IMPORT_FAILED,
|
|
1841
|
+
"3MF archive does not contain 3D/3dmodel.model (or uses unsupported compression)"
|
|
1842
|
+
)
|
|
1843
|
+
);
|
|
1844
|
+
}
|
|
1845
|
+
const xml = new TextDecoder().decode(modelData);
|
|
1846
|
+
const parsed = parseModelXml(xml);
|
|
1847
|
+
if (parsed.vertices.length === 0 || parsed.triangles.length === 0) {
|
|
1848
|
+
return errors.err(
|
|
1849
|
+
errors.ioError(errors.BrepErrorCode.THREEMF_IMPORT_FAILED, "3MF model contains no valid geometry")
|
|
1850
|
+
);
|
|
1851
|
+
}
|
|
1852
|
+
return buildSolidFromMesh(parsed);
|
|
1853
|
+
} catch (e) {
|
|
1854
|
+
const msg = e instanceof Error ? e.message : String(e);
|
|
1855
|
+
return errors.err(errors.ioError(errors.BrepErrorCode.THREEMF_IMPORT_FAILED, `3MF import failed: ${msg}`, e));
|
|
1856
|
+
}
|
|
1857
|
+
}
|
|
349
1858
|
function resolve(s) {
|
|
350
1859
|
if ("__wrapped" in s) {
|
|
351
1860
|
return s.val;
|
|
@@ -412,18 +1921,18 @@ function ellipsoid(rx, ry, rz, options) {
|
|
|
412
1921
|
return solid2;
|
|
413
1922
|
}
|
|
414
1923
|
function line(from, to) {
|
|
415
|
-
return
|
|
1924
|
+
return surfaceBuilders.makeLine(from, to);
|
|
416
1925
|
}
|
|
417
1926
|
function circle(radius, options) {
|
|
418
1927
|
const axisDir = options?.axis ?? [0, 0, 1];
|
|
419
|
-
return
|
|
1928
|
+
return surfaceBuilders.makeCircle(radius, options?.at ?? [0, 0, 0], axisDir);
|
|
420
1929
|
}
|
|
421
1930
|
function ellipse(majorRadius, minorRadius, options) {
|
|
422
1931
|
const axisDir = options?.axis ?? [0, 0, 1];
|
|
423
|
-
return
|
|
1932
|
+
return surfaceBuilders.makeEllipse(majorRadius, minorRadius, options?.at ?? [0, 0, 0], axisDir, options?.xDir);
|
|
424
1933
|
}
|
|
425
1934
|
function helix(pitch, height, radius, options) {
|
|
426
|
-
return
|
|
1935
|
+
return surfaceBuilders.makeHelix(
|
|
427
1936
|
pitch,
|
|
428
1937
|
height,
|
|
429
1938
|
radius,
|
|
@@ -433,11 +1942,11 @@ function helix(pitch, height, radius, options) {
|
|
|
433
1942
|
);
|
|
434
1943
|
}
|
|
435
1944
|
function threePointArc(p1, p2, p3) {
|
|
436
|
-
return
|
|
1945
|
+
return surfaceBuilders.makeThreePointArc(p1, p2, p3);
|
|
437
1946
|
}
|
|
438
1947
|
function ellipseArc(majorRadius, minorRadius, startAngle, endAngle, options) {
|
|
439
1948
|
const axisDir = options?.axis ?? [0, 0, 1];
|
|
440
|
-
return
|
|
1949
|
+
return surfaceBuilders.makeEllipseArc(
|
|
441
1950
|
majorRadius,
|
|
442
1951
|
minorRadius,
|
|
443
1952
|
startAngle * vecOps.DEG2RAD,
|
|
@@ -448,28 +1957,28 @@ function ellipseArc(majorRadius, minorRadius, startAngle, endAngle, options) {
|
|
|
448
1957
|
);
|
|
449
1958
|
}
|
|
450
1959
|
function bsplineApprox(points, config) {
|
|
451
|
-
return
|
|
1960
|
+
return surfaceBuilders.makeBSplineApproximation(points, config);
|
|
452
1961
|
}
|
|
453
1962
|
function bezier(points) {
|
|
454
|
-
return
|
|
1963
|
+
return surfaceBuilders.makeBezierCurve(points);
|
|
455
1964
|
}
|
|
456
1965
|
function tangentArc(startPoint, startTgt, endPoint) {
|
|
457
|
-
return
|
|
1966
|
+
return surfaceBuilders.makeTangentArc(startPoint, startTgt, endPoint);
|
|
458
1967
|
}
|
|
459
1968
|
function wire(listOfEdges) {
|
|
460
|
-
return
|
|
1969
|
+
return surfaceBuilders.assembleWire(listOfEdges);
|
|
461
1970
|
}
|
|
462
1971
|
function face(w, holes) {
|
|
463
|
-
return
|
|
1972
|
+
return surfaceBuilders.makeFace(w, holes);
|
|
464
1973
|
}
|
|
465
1974
|
function filledFace(w) {
|
|
466
|
-
return
|
|
1975
|
+
return surfaceBuilders.makeNonPlanarFace(w);
|
|
467
1976
|
}
|
|
468
1977
|
function subFace(originFace, w) {
|
|
469
|
-
return
|
|
1978
|
+
return surfaceBuilders.makeNewFaceWithinFace(originFace, w);
|
|
470
1979
|
}
|
|
471
1980
|
function polygon(points) {
|
|
472
|
-
return
|
|
1981
|
+
return surfaceBuilders.makePolygon(points);
|
|
473
1982
|
}
|
|
474
1983
|
function vertex(point) {
|
|
475
1984
|
return loft$2.makeVertex(point);
|
|
@@ -487,7 +1996,7 @@ function sewShells(facesOrShells, ignoreType) {
|
|
|
487
1996
|
return loft$2.weldShellsAndFaces(facesOrShells, ignoreType);
|
|
488
1997
|
}
|
|
489
1998
|
function addHoles(f, holes) {
|
|
490
|
-
return
|
|
1999
|
+
return surfaceBuilders.addHolesInFace(f, holes);
|
|
491
2000
|
}
|
|
492
2001
|
function validateNotNull(shape2, label) {
|
|
493
2002
|
if (shape2.wrapped.IsNull()) {
|
|
@@ -506,9 +2015,11 @@ function thicken$1(shape2, thickness) {
|
|
|
506
2015
|
const progress = r(new oc.Message_ProgressRange_1());
|
|
507
2016
|
builder.Build(progress);
|
|
508
2017
|
const resultOc = builder.Shape();
|
|
509
|
-
const
|
|
510
|
-
shapeFns.propagateOrigins(builder, [shape2],
|
|
511
|
-
|
|
2018
|
+
const cast = shapeTypes.castShape(resultOc);
|
|
2019
|
+
shapeFns.propagateOrigins(builder, [shape2], cast);
|
|
2020
|
+
booleanFns.propagateFaceTags(builder, [shape2], cast);
|
|
2021
|
+
booleanFns.propagateColors(builder, [shape2], cast);
|
|
2022
|
+
return errors.ok(cast);
|
|
512
2023
|
} catch (e) {
|
|
513
2024
|
const raw = e instanceof Error ? e.message : String(e);
|
|
514
2025
|
return errors.err(errors.occtError("THICKEN_FAILED", `Thicken operation failed: ${raw}`, e));
|
|
@@ -567,12 +2078,14 @@ function fillet$1(shape2, edges, radius) {
|
|
|
567
2078
|
}
|
|
568
2079
|
}
|
|
569
2080
|
const resultOc = builder.Shape();
|
|
570
|
-
const
|
|
571
|
-
if (!shapeTypes.isShape3D(
|
|
2081
|
+
const cast = shapeTypes.castShape(resultOc);
|
|
2082
|
+
if (!shapeTypes.isShape3D(cast)) {
|
|
572
2083
|
return errors.err(errors.occtError("FILLET_RESULT_NOT_3D", "Fillet result is not a 3D shape"));
|
|
573
2084
|
}
|
|
574
|
-
shapeFns.propagateOrigins(builder, [shape2],
|
|
575
|
-
|
|
2085
|
+
shapeFns.propagateOrigins(builder, [shape2], cast);
|
|
2086
|
+
booleanFns.propagateFaceTags(builder, [shape2], cast);
|
|
2087
|
+
booleanFns.propagateColors(builder, [shape2], cast);
|
|
2088
|
+
return errors.ok(cast);
|
|
576
2089
|
} catch (e) {
|
|
577
2090
|
const raw = e instanceof Error ? e.message : String(e);
|
|
578
2091
|
return errors.err(
|
|
@@ -661,12 +2174,14 @@ function chamfer$1(shape2, edges, distance) {
|
|
|
661
2174
|
}
|
|
662
2175
|
}
|
|
663
2176
|
const resultOc = builder.Shape();
|
|
664
|
-
const
|
|
665
|
-
if (!shapeTypes.isShape3D(
|
|
2177
|
+
const cast = shapeTypes.castShape(resultOc);
|
|
2178
|
+
if (!shapeTypes.isShape3D(cast)) {
|
|
666
2179
|
return errors.err(errors.occtError("CHAMFER_RESULT_NOT_3D", "Chamfer result is not a 3D shape"));
|
|
667
2180
|
}
|
|
668
|
-
shapeFns.propagateOrigins(builder, [shape2],
|
|
669
|
-
|
|
2181
|
+
shapeFns.propagateOrigins(builder, [shape2], cast);
|
|
2182
|
+
booleanFns.propagateFaceTags(builder, [shape2], cast);
|
|
2183
|
+
booleanFns.propagateColors(builder, [shape2], cast);
|
|
2184
|
+
return errors.ok(cast);
|
|
670
2185
|
} catch (e) {
|
|
671
2186
|
const raw = e instanceof Error ? e.message : String(e);
|
|
672
2187
|
return errors.err(
|
|
@@ -709,12 +2224,14 @@ function shell$1(shape2, faces, thickness, tolerance = 1e-3) {
|
|
|
709
2224
|
progress
|
|
710
2225
|
);
|
|
711
2226
|
const resultOc = builder.Shape();
|
|
712
|
-
const
|
|
713
|
-
if (!shapeTypes.isShape3D(
|
|
2227
|
+
const cast = shapeTypes.castShape(resultOc);
|
|
2228
|
+
if (!shapeTypes.isShape3D(cast)) {
|
|
714
2229
|
return errors.err(errors.occtError("SHELL_RESULT_NOT_3D", "Shell result is not a 3D shape"));
|
|
715
2230
|
}
|
|
716
|
-
shapeFns.propagateOrigins(builder, [shape2],
|
|
717
|
-
|
|
2231
|
+
shapeFns.propagateOrigins(builder, [shape2], cast);
|
|
2232
|
+
booleanFns.propagateFaceTags(builder, [shape2], cast);
|
|
2233
|
+
booleanFns.propagateColors(builder, [shape2], cast);
|
|
2234
|
+
return errors.ok(cast);
|
|
718
2235
|
} catch (e) {
|
|
719
2236
|
const raw = e instanceof Error ? e.message : String(e);
|
|
720
2237
|
return errors.err(
|
|
@@ -749,12 +2266,14 @@ function offset$1(shape2, distance, tolerance = 1e-6) {
|
|
|
749
2266
|
progress
|
|
750
2267
|
);
|
|
751
2268
|
const resultOc = builder.Shape();
|
|
752
|
-
const
|
|
753
|
-
if (!shapeTypes.isShape3D(
|
|
2269
|
+
const cast = shapeTypes.castShape(resultOc);
|
|
2270
|
+
if (!shapeTypes.isShape3D(cast)) {
|
|
754
2271
|
return errors.err(errors.occtError("OFFSET_RESULT_NOT_3D", "Offset result is not a 3D shape"));
|
|
755
2272
|
}
|
|
756
|
-
shapeFns.propagateOrigins(builder, [shape2],
|
|
757
|
-
|
|
2273
|
+
shapeFns.propagateOrigins(builder, [shape2], cast);
|
|
2274
|
+
booleanFns.propagateFaceTags(builder, [shape2], cast);
|
|
2275
|
+
booleanFns.propagateColors(builder, [shape2], cast);
|
|
2276
|
+
return errors.ok(cast);
|
|
758
2277
|
} catch (e) {
|
|
759
2278
|
const raw = e instanceof Error ? e.message : String(e);
|
|
760
2279
|
return errors.err(errors.occtError("OFFSET_FAILED", `Offset operation failed: ${raw}`, e));
|
|
@@ -795,6 +2314,9 @@ function intersect(a, b, options) {
|
|
|
795
2314
|
function section(shape2, plane, options) {
|
|
796
2315
|
return booleanFns.section(resolve(shape2), plane, options);
|
|
797
2316
|
}
|
|
2317
|
+
function sectionToFace(shape2, plane, options) {
|
|
2318
|
+
return booleanFns.sectionToFace(resolve(shape2), plane, options);
|
|
2319
|
+
}
|
|
798
2320
|
function split(shape2, tools) {
|
|
799
2321
|
return booleanFns.split(resolve(shape2), tools);
|
|
800
2322
|
}
|
|
@@ -904,7 +2426,7 @@ function toBREP(shape2) {
|
|
|
904
2426
|
return shapeFns.toBREP(resolve(shape2));
|
|
905
2427
|
}
|
|
906
2428
|
function fromBREP(data) {
|
|
907
|
-
return
|
|
2429
|
+
return faceFns.fromBREP(data);
|
|
908
2430
|
}
|
|
909
2431
|
function isValid(shape2) {
|
|
910
2432
|
return topology.isValid(resolve(shape2));
|
|
@@ -1029,7 +2551,7 @@ function pocket(shape2, options) {
|
|
|
1029
2551
|
const targetFace = resolveTargetFace(s, options.face);
|
|
1030
2552
|
const normal = faceFns.normalAt(targetFace);
|
|
1031
2553
|
const w = toWire(profile);
|
|
1032
|
-
const faceResult =
|
|
2554
|
+
const faceResult = surfaceBuilders.makeFace(w);
|
|
1033
2555
|
if (errors.isErr(faceResult)) return faceResult;
|
|
1034
2556
|
const extDir = vecOps.vecScale(vecOps.vecNormalize(normal), -depth);
|
|
1035
2557
|
const toolResult = operations.extrude(faceResult.value, extDir);
|
|
@@ -1045,7 +2567,7 @@ function boss(shape2, options) {
|
|
|
1045
2567
|
const targetFace = resolveTargetFace(s, options.face);
|
|
1046
2568
|
const normal = faceFns.normalAt(targetFace);
|
|
1047
2569
|
const w = toWire(profile);
|
|
1048
|
-
const faceResult =
|
|
2570
|
+
const faceResult = surfaceBuilders.makeFace(w);
|
|
1049
2571
|
if (errors.isErr(faceResult)) return faceResult;
|
|
1050
2572
|
const extDir = vecOps.vecScale(vecOps.vecNormalize(normal), height);
|
|
1051
2573
|
const toolResult = operations.extrude(faceResult.value, extDir);
|
|
@@ -1471,6 +2993,7 @@ exports.drawingFillet = drawFns.drawingFillet;
|
|
|
1471
2993
|
exports.drawingFuse = drawFns.drawingFuse;
|
|
1472
2994
|
exports.drawingIntersect = drawFns.drawingIntersect;
|
|
1473
2995
|
exports.drawingToSketchOnPlane = drawFns.drawingToSketchOnPlane;
|
|
2996
|
+
exports.fontMetrics = drawFns.fontMetrics;
|
|
1474
2997
|
exports.getFont = drawFns.getFont;
|
|
1475
2998
|
exports.isProjectionPlane = drawFns.isProjectionPlane;
|
|
1476
2999
|
exports.loadFont = drawFns.loadFont;
|
|
@@ -1497,6 +3020,7 @@ exports.sketchSweep = drawFns.sketchSweep;
|
|
|
1497
3020
|
exports.sketchText = drawFns.sketchText;
|
|
1498
3021
|
exports.sketchWires = drawFns.sketchWires;
|
|
1499
3022
|
exports.textBlueprints = drawFns.textBlueprints;
|
|
3023
|
+
exports.textMetrics = drawFns.textMetrics;
|
|
1500
3024
|
exports.translateDrawing = drawFns.translateDrawing;
|
|
1501
3025
|
exports.createNamedPlane = vectors.createNamedPlane;
|
|
1502
3026
|
exports.createPlane = vectors.createPlane;
|
|
@@ -1517,8 +3041,21 @@ exports.iterEdges = shapeFns.iterEdges;
|
|
|
1517
3041
|
exports.iterFaces = shapeFns.iterFaces;
|
|
1518
3042
|
exports.iterVertices = shapeFns.iterVertices;
|
|
1519
3043
|
exports.iterWires = shapeFns.iterWires;
|
|
3044
|
+
exports.resize = shapeFns.resize;
|
|
1520
3045
|
exports.setShapeOrigin = shapeFns.setShapeOrigin;
|
|
1521
3046
|
exports.vertexPosition = shapeFns.vertexPosition;
|
|
3047
|
+
exports.applyGlue = booleanFns.applyGlue;
|
|
3048
|
+
exports.colorFaces = booleanFns.colorFaces;
|
|
3049
|
+
exports.colorShape = booleanFns.colorShape;
|
|
3050
|
+
exports.cutAll = booleanFns.cutAll;
|
|
3051
|
+
exports.findFacesByTag = booleanFns.findFacesByTag;
|
|
3052
|
+
exports.fuseAll = booleanFns.fuseAll;
|
|
3053
|
+
exports.getFaceColor = booleanFns.getFaceColor;
|
|
3054
|
+
exports.getFaceTags = booleanFns.getFaceTags;
|
|
3055
|
+
exports.getShapeColor = booleanFns.getShapeColor;
|
|
3056
|
+
exports.getTagMetadata = booleanFns.getTagMetadata;
|
|
3057
|
+
exports.setTagMetadata = booleanFns.setTagMetadata;
|
|
3058
|
+
exports.tagFaces = booleanFns.tagFaces;
|
|
1522
3059
|
exports.adjacentFaces = topology.adjacentFaces;
|
|
1523
3060
|
exports.autoHeal = topology.autoHeal;
|
|
1524
3061
|
exports.chamferDistAngleShape = topology.chamferDistAngle;
|
|
@@ -1533,17 +3070,24 @@ exports.toGroupedBufferGeometryData = topology.toGroupedBufferGeometryData;
|
|
|
1533
3070
|
exports.toLineGeometryData = topology.toLineGeometryData;
|
|
1534
3071
|
exports.verticesOfEdge = topology.verticesOfEdge;
|
|
1535
3072
|
exports.wiresOfFace = topology.wiresOfFace;
|
|
3073
|
+
exports.asTopo = faceFns.asTopo;
|
|
3074
|
+
exports.cast = faceFns.cast;
|
|
1536
3075
|
exports.classifyPointOnFace = faceFns.classifyPointOnFace;
|
|
3076
|
+
exports.deserializeShape = faceFns.fromBREP;
|
|
3077
|
+
exports.downcast = faceFns.downcast;
|
|
1537
3078
|
exports.faceCenter = faceFns.faceCenter;
|
|
1538
3079
|
exports.faceGeomType = faceFns.faceGeomType;
|
|
1539
3080
|
exports.faceOrientation = faceFns.faceOrientation;
|
|
1540
3081
|
exports.flipFaceOrientation = faceFns.flipFaceOrientation;
|
|
1541
3082
|
exports.getSurfaceType = faceFns.getSurfaceType;
|
|
1542
3083
|
exports.innerWires = faceFns.innerWires;
|
|
3084
|
+
exports.isCompSolid = faceFns.isCompSolid;
|
|
3085
|
+
exports.iterTopo = faceFns.iterTopo;
|
|
1543
3086
|
exports.normalAt = faceFns.normalAt;
|
|
1544
3087
|
exports.outerWire = faceFns.outerWire;
|
|
1545
3088
|
exports.pointOnSurface = faceFns.pointOnSurface;
|
|
1546
3089
|
exports.projectPointOnFace = faceFns.projectPointOnFace;
|
|
3090
|
+
exports.shapeType = faceFns.shapeType;
|
|
1547
3091
|
exports.uvBounds = faceFns.uvBounds;
|
|
1548
3092
|
exports.uvCoordinates = faceFns.uvCoordinates;
|
|
1549
3093
|
exports.clearMeshCache = meshFns.clearMeshCache;
|
|
@@ -1551,9 +3095,6 @@ exports.createMeshCache = meshFns.createMeshCache;
|
|
|
1551
3095
|
exports.exportIGES = meshFns.exportIGES;
|
|
1552
3096
|
exports.exportSTEP = meshFns.exportSTEP;
|
|
1553
3097
|
exports.exportSTL = meshFns.exportSTL;
|
|
1554
|
-
exports.applyGlue = booleanFns.applyGlue;
|
|
1555
|
-
exports.cutAll = booleanFns.cutAll;
|
|
1556
|
-
exports.fuseAll = booleanFns.fuseAll;
|
|
1557
3098
|
exports.createDistanceQuery = measurement.createDistanceQuery;
|
|
1558
3099
|
exports.measureArea = measurement.measureArea;
|
|
1559
3100
|
exports.measureCurvatureAt = measurement.measureCurvatureAt;
|
|
@@ -1564,13 +3105,7 @@ exports.measureLinearProps = measurement.measureLinearProps;
|
|
|
1564
3105
|
exports.measureSurfaceProps = measurement.measureSurfaceProps;
|
|
1565
3106
|
exports.measureVolume = measurement.measureVolume;
|
|
1566
3107
|
exports.measureVolumeProps = measurement.measureVolumeProps;
|
|
1567
|
-
exports.
|
|
1568
|
-
exports.cast = cast.cast;
|
|
1569
|
-
exports.deserializeShape = cast.fromBREP;
|
|
1570
|
-
exports.downcast = cast.downcast;
|
|
1571
|
-
exports.isCompSolid = cast.isCompSolid;
|
|
1572
|
-
exports.iterTopo = cast.iterTopo;
|
|
1573
|
-
exports.shapeType = cast.shapeType;
|
|
3108
|
+
exports.fill = surfaceBuilders.fill;
|
|
1574
3109
|
exports.edgeFinder = query.edgeFinder;
|
|
1575
3110
|
exports.BrepBugError = result.BrepBugError;
|
|
1576
3111
|
exports.bug = result.bug;
|
|
@@ -1592,6 +3127,7 @@ exports.registerHandler = worker.registerHandler;
|
|
|
1592
3127
|
exports.rejectAll = worker.rejectAll;
|
|
1593
3128
|
exports.BrepWrapperError = BrepWrapperError;
|
|
1594
3129
|
exports.addHoles = addHoles;
|
|
3130
|
+
exports.addMate = addMate;
|
|
1595
3131
|
exports.applyMatrix = applyMatrix;
|
|
1596
3132
|
exports.bezier = bezier;
|
|
1597
3133
|
exports.boss = boss;
|
|
@@ -1603,6 +3139,7 @@ exports.checkInterference = checkInterference;
|
|
|
1603
3139
|
exports.circle = circle;
|
|
1604
3140
|
exports.clone = clone;
|
|
1605
3141
|
exports.compound = compound;
|
|
3142
|
+
exports.computeStraightSkeleton = computeStraightSkeleton;
|
|
1606
3143
|
exports.cone = cone;
|
|
1607
3144
|
exports.cut = cut;
|
|
1608
3145
|
exports.cylinder = cylinder;
|
|
@@ -1617,9 +3154,13 @@ exports.filledFace = filledFace;
|
|
|
1617
3154
|
exports.fillet = fillet;
|
|
1618
3155
|
exports.fromBREP = fromBREP;
|
|
1619
3156
|
exports.fuse = fuse;
|
|
3157
|
+
exports.guidedSweep = guidedSweep;
|
|
1620
3158
|
exports.heal = heal;
|
|
1621
3159
|
exports.helix = helix;
|
|
1622
3160
|
exports.hull = hull;
|
|
3161
|
+
exports.importDXF = importDXF;
|
|
3162
|
+
exports.importOBJ = importOBJ;
|
|
3163
|
+
exports.importThreeMF = importThreeMF;
|
|
1623
3164
|
exports.intersect = intersect;
|
|
1624
3165
|
exports.isChamferRadius = isChamferRadius;
|
|
1625
3166
|
exports.isEmpty = isEmpty;
|
|
@@ -1635,26 +3176,33 @@ exports.meshEdges = meshEdges;
|
|
|
1635
3176
|
exports.minkowski = minkowski;
|
|
1636
3177
|
exports.mirror = mirror;
|
|
1637
3178
|
exports.mirrorJoin = mirrorJoin;
|
|
3179
|
+
exports.multiSectionSweep = multiSectionSweep;
|
|
1638
3180
|
exports.offset = offset;
|
|
1639
3181
|
exports.offsetFace = offsetFace;
|
|
1640
3182
|
exports.pocket = pocket;
|
|
1641
3183
|
exports.polygon = polygon;
|
|
3184
|
+
exports.polyhedron = polyhedron;
|
|
1642
3185
|
exports.rectangularPattern = rectangularPattern;
|
|
1643
3186
|
exports.resolve = resolve;
|
|
1644
3187
|
exports.resolve3D = resolve3D;
|
|
1645
3188
|
exports.revolve = revolve;
|
|
3189
|
+
exports.roof = roof;
|
|
1646
3190
|
exports.rotate = rotate;
|
|
1647
3191
|
exports.scale = scale;
|
|
1648
3192
|
exports.section = section;
|
|
3193
|
+
exports.sectionToFace = sectionToFace;
|
|
1649
3194
|
exports.sewShells = sewShells;
|
|
1650
3195
|
exports.shape = shape;
|
|
1651
3196
|
exports.shell = shell;
|
|
1652
3197
|
exports.simplify = simplify;
|
|
1653
3198
|
exports.slice = slice;
|
|
1654
3199
|
exports.solid = solid;
|
|
3200
|
+
exports.solveAssembly = solveAssembly;
|
|
1655
3201
|
exports.sphere = sphere;
|
|
1656
3202
|
exports.split = split;
|
|
1657
3203
|
exports.subFace = subFace;
|
|
3204
|
+
exports.surfaceFromGrid = surfaceFromGrid;
|
|
3205
|
+
exports.surfaceFromImage = surfaceFromImage;
|
|
1658
3206
|
exports.tangentArc = tangentArc;
|
|
1659
3207
|
exports.thicken = thicken;
|
|
1660
3208
|
exports.threePointArc = threePointArc;
|