brepjs 2.0.1 → 2.0.3
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/README.md +79 -20
- package/dist/brepjs.cjs +1057 -957
- package/dist/brepjs.d.ts +143 -57
- package/dist/brepjs.js +1057 -957
- package/package.json +4 -3
package/dist/brepjs.cjs
CHANGED
|
@@ -53,921 +53,1017 @@ function uniqueIOFilename(prefix, ext) {
|
|
|
53
53
|
function uniqueId() {
|
|
54
54
|
return `_io_${++_counter}`;
|
|
55
55
|
}
|
|
56
|
+
function exportSTEP$2(oc, shapes) {
|
|
57
|
+
const writer = new oc.STEPControl_Writer_1();
|
|
58
|
+
oc.Interface_Static.SetIVal("write.step.schema", 5);
|
|
59
|
+
writer.Model(true).delete();
|
|
60
|
+
const progress = new oc.Message_ProgressRange_1();
|
|
61
|
+
for (const shape of shapes) {
|
|
62
|
+
writer.Transfer(shape, oc.STEPControl_StepModelType.STEPControl_AsIs, true, progress);
|
|
63
|
+
}
|
|
64
|
+
const filename = uniqueIOFilename("_export", "step");
|
|
65
|
+
const done = writer.Write(filename);
|
|
66
|
+
writer.delete();
|
|
67
|
+
progress.delete();
|
|
68
|
+
if (done === oc.IFSelect_ReturnStatus.IFSelect_RetDone) {
|
|
69
|
+
const file = oc.FS.readFile("/" + filename);
|
|
70
|
+
oc.FS.unlink("/" + filename);
|
|
71
|
+
return new TextDecoder().decode(file);
|
|
72
|
+
}
|
|
73
|
+
throw new Error("STEP export failed: writer did not complete successfully");
|
|
74
|
+
}
|
|
75
|
+
function exportSTL$1(oc, shape, binary = false) {
|
|
76
|
+
const filename = uniqueIOFilename("_export", "stl");
|
|
77
|
+
const done = oc.StlAPI.Write(shape, filename, !binary);
|
|
78
|
+
if (done) {
|
|
79
|
+
const file = oc.FS.readFile("/" + filename);
|
|
80
|
+
oc.FS.unlink("/" + filename);
|
|
81
|
+
if (binary) return file.buffer;
|
|
82
|
+
return new TextDecoder().decode(file);
|
|
83
|
+
}
|
|
84
|
+
throw new Error("STL export failed: StlAPI.Write returned false");
|
|
85
|
+
}
|
|
86
|
+
function importSTEP$2(oc, data) {
|
|
87
|
+
const filename = uniqueIOFilename("_import", "step");
|
|
88
|
+
const buffer = typeof data === "string" ? new TextEncoder().encode(data) : new Uint8Array(data);
|
|
89
|
+
oc.FS.writeFile("/" + filename, buffer);
|
|
90
|
+
const reader = new oc.STEPControl_Reader_1();
|
|
91
|
+
if (reader.ReadFile(filename)) {
|
|
92
|
+
oc.FS.unlink("/" + filename);
|
|
93
|
+
const progress = new oc.Message_ProgressRange_1();
|
|
94
|
+
reader.TransferRoots(progress);
|
|
95
|
+
progress.delete();
|
|
96
|
+
const shape = reader.OneShape();
|
|
97
|
+
reader.delete();
|
|
98
|
+
return [shape];
|
|
99
|
+
}
|
|
100
|
+
oc.FS.unlink("/" + filename);
|
|
101
|
+
reader.delete();
|
|
102
|
+
throw new Error("Failed to import STEP file: reader could not parse the input data");
|
|
103
|
+
}
|
|
104
|
+
function importSTL$2(oc, data) {
|
|
105
|
+
const filename = uniqueIOFilename("_import", "stl");
|
|
106
|
+
const buffer = typeof data === "string" ? new TextEncoder().encode(data) : new Uint8Array(data);
|
|
107
|
+
oc.FS.writeFile("/" + filename, buffer);
|
|
108
|
+
const reader = new oc.StlAPI_Reader();
|
|
109
|
+
const readShape = new oc.TopoDS_Shell();
|
|
110
|
+
if (reader.Read(readShape, filename)) {
|
|
111
|
+
oc.FS.unlink("/" + filename);
|
|
112
|
+
const upgrader = new oc.ShapeUpgrade_UnifySameDomain_2(readShape, true, true, false);
|
|
113
|
+
upgrader.Build();
|
|
114
|
+
const upgraded = upgrader.Shape();
|
|
115
|
+
const solidBuilder = new oc.BRepBuilderAPI_MakeSolid_1();
|
|
116
|
+
solidBuilder.Add(oc.TopoDS.Shell_1(upgraded));
|
|
117
|
+
const solid = solidBuilder.Solid();
|
|
118
|
+
readShape.delete();
|
|
119
|
+
upgrader.delete();
|
|
120
|
+
solidBuilder.delete();
|
|
121
|
+
reader.delete();
|
|
122
|
+
return solid;
|
|
123
|
+
}
|
|
124
|
+
oc.FS.unlink("/" + filename);
|
|
125
|
+
readShape.delete();
|
|
126
|
+
reader.delete();
|
|
127
|
+
throw new Error("Failed to import STL file: reader could not parse the input data");
|
|
128
|
+
}
|
|
56
129
|
const HASH_CODE_MAX$1 = 2147483647;
|
|
130
|
+
function volume(oc, shape) {
|
|
131
|
+
const props = new oc.GProp_GProps_1();
|
|
132
|
+
oc.BRepGProp.VolumeProperties_1(shape, props, true, false, false);
|
|
133
|
+
const vol = props.Mass();
|
|
134
|
+
props.delete();
|
|
135
|
+
return vol;
|
|
136
|
+
}
|
|
137
|
+
function area(oc, shape) {
|
|
138
|
+
const props = new oc.GProp_GProps_1();
|
|
139
|
+
oc.BRepGProp.SurfaceProperties_2(shape, props, 1e-7, true);
|
|
140
|
+
const a = props.Mass();
|
|
141
|
+
props.delete();
|
|
142
|
+
return a;
|
|
143
|
+
}
|
|
144
|
+
function length(oc, shape) {
|
|
145
|
+
const props = new oc.GProp_GProps_1();
|
|
146
|
+
oc.BRepGProp.LinearProperties(shape, props, true, false);
|
|
147
|
+
const len = props.Mass();
|
|
148
|
+
props.delete();
|
|
149
|
+
return len;
|
|
150
|
+
}
|
|
151
|
+
function centerOfMass(oc, shape) {
|
|
152
|
+
const props = new oc.GProp_GProps_1();
|
|
153
|
+
oc.BRepGProp.VolumeProperties_1(shape, props, true, false, false);
|
|
154
|
+
const center = props.CentreOfMass();
|
|
155
|
+
const result = [center.X(), center.Y(), center.Z()];
|
|
156
|
+
center.delete();
|
|
157
|
+
props.delete();
|
|
158
|
+
return result;
|
|
159
|
+
}
|
|
160
|
+
function boundingBox(oc, shape) {
|
|
161
|
+
const box = new oc.Bnd_Box_1();
|
|
162
|
+
oc.BRepBndLib.Add(shape, box, true);
|
|
163
|
+
const xMin = { current: 0 };
|
|
164
|
+
const yMin = { current: 0 };
|
|
165
|
+
const zMin = { current: 0 };
|
|
166
|
+
const xMax = { current: 0 };
|
|
167
|
+
const yMax = { current: 0 };
|
|
168
|
+
const zMax = { current: 0 };
|
|
169
|
+
box.Get(xMin, yMin, zMin, xMax, yMax, zMax);
|
|
170
|
+
box.delete();
|
|
171
|
+
return {
|
|
172
|
+
min: [xMin.current, yMin.current, zMin.current],
|
|
173
|
+
max: [xMax.current, yMax.current, zMax.current]
|
|
174
|
+
};
|
|
175
|
+
}
|
|
176
|
+
function transform(oc, shape, trsf) {
|
|
177
|
+
const transformer = new oc.BRepBuilderAPI_Transform_2(shape, trsf, true);
|
|
178
|
+
const result = transformer.ModifiedShape(shape);
|
|
179
|
+
transformer.delete();
|
|
180
|
+
return result;
|
|
181
|
+
}
|
|
182
|
+
function translate$1(oc, shape, x, y, z) {
|
|
183
|
+
const trsf = new oc.gp_Trsf_1();
|
|
184
|
+
const vec2 = new oc.gp_Vec_4(x, y, z);
|
|
185
|
+
trsf.SetTranslation_1(vec2);
|
|
186
|
+
const result = transform(oc, shape, trsf);
|
|
187
|
+
trsf.delete();
|
|
188
|
+
vec2.delete();
|
|
189
|
+
return result;
|
|
190
|
+
}
|
|
191
|
+
function rotate$1(oc, shape, angle, axis = [0, 0, 1], center = [0, 0, 0]) {
|
|
192
|
+
const trsf = new oc.gp_Trsf_1();
|
|
193
|
+
const origin = new oc.gp_Pnt_3(...center);
|
|
194
|
+
const dir = new oc.gp_Dir_4(...axis);
|
|
195
|
+
const ax1 = new oc.gp_Ax1_2(origin, dir);
|
|
196
|
+
trsf.SetRotation_1(ax1, angle * Math.PI / 180);
|
|
197
|
+
const result = transform(oc, shape, trsf);
|
|
198
|
+
trsf.delete();
|
|
199
|
+
ax1.delete();
|
|
200
|
+
origin.delete();
|
|
201
|
+
dir.delete();
|
|
202
|
+
return result;
|
|
203
|
+
}
|
|
204
|
+
function mirror$1(oc, shape, origin, normal) {
|
|
205
|
+
const trsf = new oc.gp_Trsf_1();
|
|
206
|
+
const pnt2 = new oc.gp_Pnt_3(...origin);
|
|
207
|
+
const dir = new oc.gp_Dir_4(...normal);
|
|
208
|
+
const ax2 = new oc.gp_Ax2_3(pnt2, dir);
|
|
209
|
+
trsf.SetMirror_3(ax2);
|
|
210
|
+
const result = transform(oc, shape, trsf);
|
|
211
|
+
trsf.delete();
|
|
212
|
+
ax2.delete();
|
|
213
|
+
pnt2.delete();
|
|
214
|
+
dir.delete();
|
|
215
|
+
return result;
|
|
216
|
+
}
|
|
217
|
+
function scale$1(oc, shape, center, factor) {
|
|
218
|
+
const trsf = new oc.gp_Trsf_1();
|
|
219
|
+
const pnt2 = new oc.gp_Pnt_3(...center);
|
|
220
|
+
trsf.SetScale(pnt2, factor);
|
|
221
|
+
const result = transform(oc, shape, trsf);
|
|
222
|
+
trsf.delete();
|
|
223
|
+
pnt2.delete();
|
|
224
|
+
return result;
|
|
225
|
+
}
|
|
226
|
+
function simplify(oc, shape) {
|
|
227
|
+
const upgrader = new oc.ShapeUpgrade_UnifySameDomain_2(shape, true, true, false);
|
|
228
|
+
upgrader.Build();
|
|
229
|
+
const result = upgrader.Shape();
|
|
230
|
+
upgrader.delete();
|
|
231
|
+
return result;
|
|
232
|
+
}
|
|
233
|
+
function applyGlue$2(oc, op, optimisation) {
|
|
234
|
+
if (optimisation === "commonFace") {
|
|
235
|
+
op.SetGlue(oc.BOPAlgo_GlueEnum.BOPAlgo_GlueShift);
|
|
236
|
+
}
|
|
237
|
+
if (optimisation === "sameFace") {
|
|
238
|
+
op.SetGlue(oc.BOPAlgo_GlueEnum.BOPAlgo_GlueFull);
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
function buildCompound$2(oc, shapes) {
|
|
242
|
+
const builder = new oc.TopoDS_Builder();
|
|
243
|
+
const compound = new oc.TopoDS_Compound();
|
|
244
|
+
builder.MakeCompound(compound);
|
|
245
|
+
for (const s of shapes) {
|
|
246
|
+
builder.Add(compound, s);
|
|
247
|
+
}
|
|
248
|
+
builder.delete();
|
|
249
|
+
return compound;
|
|
250
|
+
}
|
|
251
|
+
function fuse(oc, shape, tool, options = {}) {
|
|
252
|
+
const { optimisation, simplify: simplify2 = false } = options;
|
|
253
|
+
const progress = new oc.Message_ProgressRange_1();
|
|
254
|
+
const fuseOp = new oc.BRepAlgoAPI_Fuse_3(shape, tool, progress);
|
|
255
|
+
applyGlue$2(oc, fuseOp, optimisation);
|
|
256
|
+
fuseOp.Build(progress);
|
|
257
|
+
if (simplify2) fuseOp.SimplifyResult(true, true, 1e-3);
|
|
258
|
+
const result = fuseOp.Shape();
|
|
259
|
+
fuseOp.delete();
|
|
260
|
+
progress.delete();
|
|
261
|
+
return result;
|
|
262
|
+
}
|
|
263
|
+
function cut(oc, shape, tool, options = {}) {
|
|
264
|
+
const { optimisation, simplify: simplify2 = false } = options;
|
|
265
|
+
const progress = new oc.Message_ProgressRange_1();
|
|
266
|
+
const cutOp = new oc.BRepAlgoAPI_Cut_3(shape, tool, progress);
|
|
267
|
+
applyGlue$2(oc, cutOp, optimisation);
|
|
268
|
+
cutOp.Build(progress);
|
|
269
|
+
if (simplify2) cutOp.SimplifyResult(true, true, 1e-3);
|
|
270
|
+
const result = cutOp.Shape();
|
|
271
|
+
cutOp.delete();
|
|
272
|
+
progress.delete();
|
|
273
|
+
return result;
|
|
274
|
+
}
|
|
275
|
+
function intersect(oc, shape, tool, options = {}) {
|
|
276
|
+
const { optimisation, simplify: simplify2 = false } = options;
|
|
277
|
+
const progress = new oc.Message_ProgressRange_1();
|
|
278
|
+
const commonOp = new oc.BRepAlgoAPI_Common_3(shape, tool, progress);
|
|
279
|
+
applyGlue$2(oc, commonOp, optimisation);
|
|
280
|
+
commonOp.Build(progress);
|
|
281
|
+
if (simplify2) commonOp.SimplifyResult(true, true, 1e-3);
|
|
282
|
+
const result = commonOp.Shape();
|
|
283
|
+
commonOp.delete();
|
|
284
|
+
progress.delete();
|
|
285
|
+
return result;
|
|
286
|
+
}
|
|
287
|
+
function fuseAllBatch(oc, shapes, options = {}) {
|
|
288
|
+
const { optimisation, simplify: simplify2 = false } = options;
|
|
289
|
+
const batch = new oc.BooleanBatch();
|
|
290
|
+
for (const s of shapes) {
|
|
291
|
+
batch.addShape(s);
|
|
292
|
+
}
|
|
293
|
+
const glueMode = optimisation === "commonFace" ? 1 : optimisation === "sameFace" ? 2 : 0;
|
|
294
|
+
const result = batch.fuseAll(glueMode, simplify2);
|
|
295
|
+
batch.delete();
|
|
296
|
+
return result;
|
|
297
|
+
}
|
|
298
|
+
function fuseAllNative(oc, shapes, options = {}) {
|
|
299
|
+
const { optimisation, simplify: simplify2 = false } = options;
|
|
300
|
+
const argList = new oc.TopTools_ListOfShape_1();
|
|
301
|
+
for (const s of shapes) {
|
|
302
|
+
argList.Append_1(s);
|
|
303
|
+
}
|
|
304
|
+
const builder = new oc.BRepAlgoAPI_BuilderAlgo_1();
|
|
305
|
+
builder.SetArguments(argList);
|
|
306
|
+
applyGlue$2(oc, builder, optimisation);
|
|
307
|
+
const progress = new oc.Message_ProgressRange_1();
|
|
308
|
+
builder.Build(progress);
|
|
309
|
+
let result = builder.Shape();
|
|
310
|
+
if (simplify2) {
|
|
311
|
+
const upgrader = new oc.ShapeUpgrade_UnifySameDomain_2(result, true, true, false);
|
|
312
|
+
upgrader.Build();
|
|
313
|
+
result = upgrader.Shape();
|
|
314
|
+
upgrader.delete();
|
|
315
|
+
}
|
|
316
|
+
argList.delete();
|
|
317
|
+
builder.delete();
|
|
318
|
+
progress.delete();
|
|
319
|
+
return result;
|
|
320
|
+
}
|
|
321
|
+
function fuseAllPairwise(oc, shapes, options = {}) {
|
|
322
|
+
const mid = Math.ceil(shapes.length / 2);
|
|
323
|
+
const left = fuseAll$3(oc, shapes.slice(0, mid), {
|
|
324
|
+
...options,
|
|
325
|
+
simplify: false,
|
|
326
|
+
strategy: "pairwise"
|
|
327
|
+
});
|
|
328
|
+
const right = fuseAll$3(oc, shapes.slice(mid), {
|
|
329
|
+
...options,
|
|
330
|
+
simplify: false,
|
|
331
|
+
strategy: "pairwise"
|
|
332
|
+
});
|
|
333
|
+
return fuse(oc, left, right, options);
|
|
334
|
+
}
|
|
335
|
+
function fuseAll$3(oc, shapes, options = {}) {
|
|
336
|
+
if (shapes.length === 0) throw new Error("fuseAll requires at least one shape");
|
|
337
|
+
if (shapes.length === 1) return shapes[0];
|
|
338
|
+
const { strategy = "native" } = options;
|
|
339
|
+
if (strategy === "pairwise") {
|
|
340
|
+
return fuseAllPairwise(oc, shapes, options);
|
|
341
|
+
}
|
|
342
|
+
if (oc.BooleanBatch) {
|
|
343
|
+
return fuseAllBatch(oc, shapes, options);
|
|
344
|
+
}
|
|
345
|
+
return fuseAllNative(oc, shapes, options);
|
|
346
|
+
}
|
|
347
|
+
function cutAllBatch(oc, shape, tools, options = {}) {
|
|
348
|
+
const { optimisation, simplify: simplify2 = false } = options;
|
|
349
|
+
const batch = new oc.BooleanBatch();
|
|
350
|
+
for (const t of tools) {
|
|
351
|
+
batch.addShape(t);
|
|
352
|
+
}
|
|
353
|
+
const glueMode = optimisation === "commonFace" ? 1 : optimisation === "sameFace" ? 2 : 0;
|
|
354
|
+
const result = batch.cutAll(shape, glueMode, simplify2);
|
|
355
|
+
batch.delete();
|
|
356
|
+
return result;
|
|
357
|
+
}
|
|
358
|
+
function cutAll$2(oc, shape, tools, options = {}) {
|
|
359
|
+
if (tools.length === 0) return shape;
|
|
360
|
+
if (oc.BooleanBatch) {
|
|
361
|
+
return cutAllBatch(oc, shape, tools, options);
|
|
362
|
+
}
|
|
363
|
+
const toolCompound = buildCompound$2(oc, tools);
|
|
364
|
+
const result = cut(oc, shape, toolCompound, options);
|
|
365
|
+
toolCompound.delete();
|
|
366
|
+
return result;
|
|
367
|
+
}
|
|
368
|
+
function meshBulk(oc, shape, options) {
|
|
369
|
+
const raw = oc.MeshExtractor.extract(
|
|
370
|
+
shape,
|
|
371
|
+
options.tolerance,
|
|
372
|
+
options.angularTolerance,
|
|
373
|
+
!!options.skipNormals
|
|
374
|
+
);
|
|
375
|
+
const verticesSize = raw.getVerticesSize();
|
|
376
|
+
const normalsSize = raw.getNormalsSize();
|
|
377
|
+
const trianglesSize = raw.getTrianglesSize();
|
|
378
|
+
const faceGroupsSize = raw.getFaceGroupsSize();
|
|
379
|
+
const verticesPtr = raw.getVerticesPtr() / 4;
|
|
380
|
+
const vertices = oc.HEAPF32.slice(verticesPtr, verticesPtr + verticesSize);
|
|
381
|
+
let normals;
|
|
382
|
+
if (options.skipNormals || normalsSize === 0) {
|
|
383
|
+
normals = new Float32Array(0);
|
|
384
|
+
} else {
|
|
385
|
+
const normalsPtr = raw.getNormalsPtr() / 4;
|
|
386
|
+
normals = oc.HEAPF32.slice(normalsPtr, normalsPtr + normalsSize);
|
|
387
|
+
}
|
|
388
|
+
const trianglesPtr = raw.getTrianglesPtr() / 4;
|
|
389
|
+
const triangles = oc.HEAPU32.slice(trianglesPtr, trianglesPtr + trianglesSize);
|
|
390
|
+
const faceGroups = [];
|
|
391
|
+
if (faceGroupsSize > 0) {
|
|
392
|
+
const fgPtr = raw.getFaceGroupsPtr() / 4;
|
|
393
|
+
const fgRaw = oc.HEAP32.slice(fgPtr, fgPtr + faceGroupsSize);
|
|
394
|
+
for (let i = 0; i < fgRaw.length; i += 3) {
|
|
395
|
+
faceGroups.push({
|
|
396
|
+
start: fgRaw[i],
|
|
397
|
+
count: fgRaw[i + 1],
|
|
398
|
+
faceHash: fgRaw[i + 2]
|
|
399
|
+
});
|
|
400
|
+
}
|
|
401
|
+
}
|
|
402
|
+
raw.delete();
|
|
403
|
+
return { vertices, normals, triangles, faceGroups };
|
|
404
|
+
}
|
|
405
|
+
function meshJS(oc, shape, options) {
|
|
406
|
+
const mesher = new oc.BRepMesh_IncrementalMesh_2(
|
|
407
|
+
shape,
|
|
408
|
+
options.tolerance,
|
|
409
|
+
false,
|
|
410
|
+
options.angularTolerance,
|
|
411
|
+
false
|
|
412
|
+
);
|
|
413
|
+
mesher.delete();
|
|
414
|
+
let totalNodes = 0;
|
|
415
|
+
let totalTris = 0;
|
|
416
|
+
const explorer = new oc.TopExp_Explorer_2(
|
|
417
|
+
shape,
|
|
418
|
+
oc.TopAbs_ShapeEnum.TopAbs_FACE,
|
|
419
|
+
oc.TopAbs_ShapeEnum.TopAbs_SHAPE
|
|
420
|
+
);
|
|
421
|
+
while (explorer.More()) {
|
|
422
|
+
const face = oc.TopoDS.Face_1(explorer.Current());
|
|
423
|
+
const loc = new oc.TopLoc_Location_1();
|
|
424
|
+
const tri = oc.BRep_Tool.Triangulation(face, loc, 0);
|
|
425
|
+
if (!tri.IsNull()) {
|
|
426
|
+
const t = tri.get();
|
|
427
|
+
totalNodes += t.NbNodes();
|
|
428
|
+
totalTris += t.NbTriangles();
|
|
429
|
+
}
|
|
430
|
+
loc.delete();
|
|
431
|
+
tri.delete();
|
|
432
|
+
explorer.Next();
|
|
433
|
+
}
|
|
434
|
+
const vertices = new Float32Array(totalNodes * 3);
|
|
435
|
+
const normals = options.skipNormals ? new Float32Array(0) : new Float32Array(totalNodes * 3);
|
|
436
|
+
const triangles = new Uint32Array(totalTris * 3);
|
|
437
|
+
const faceGroups = [];
|
|
438
|
+
let vIdx = 0;
|
|
439
|
+
let nIdx = 0;
|
|
440
|
+
let tIdx = 0;
|
|
441
|
+
explorer.Init(shape, oc.TopAbs_ShapeEnum.TopAbs_FACE, oc.TopAbs_ShapeEnum.TopAbs_SHAPE);
|
|
442
|
+
while (explorer.More()) {
|
|
443
|
+
const face = oc.TopoDS.Face_1(explorer.Current());
|
|
444
|
+
const location = new oc.TopLoc_Location_1();
|
|
445
|
+
const triangulation = oc.BRep_Tool.Triangulation(face, location, 0);
|
|
446
|
+
if (!triangulation.IsNull()) {
|
|
447
|
+
const tri = triangulation.get();
|
|
448
|
+
const transformation = location.Transformation();
|
|
449
|
+
const nbNodes = tri.NbNodes();
|
|
450
|
+
const vertexOffset = vIdx / 3;
|
|
451
|
+
const triStart = tIdx;
|
|
452
|
+
for (let i = 1; i <= nbNodes; i++) {
|
|
453
|
+
const p = tri.Node(i).Transformed(transformation);
|
|
454
|
+
vertices[vIdx++] = p.X();
|
|
455
|
+
vertices[vIdx++] = p.Y();
|
|
456
|
+
vertices[vIdx++] = p.Z();
|
|
457
|
+
p.delete();
|
|
458
|
+
}
|
|
459
|
+
if (!options.skipNormals) {
|
|
460
|
+
const normalsArray = new oc.TColgp_Array1OfDir_2(1, nbNodes);
|
|
461
|
+
const pc = new oc.Poly_Connect_2(triangulation);
|
|
462
|
+
oc.StdPrs_ToolTriangulatedShape.Normal(face, pc, normalsArray);
|
|
463
|
+
for (let i = normalsArray.Lower(); i <= normalsArray.Upper(); i++) {
|
|
464
|
+
const d = normalsArray.Value(i).Transformed(transformation);
|
|
465
|
+
normals[nIdx++] = d.X();
|
|
466
|
+
normals[nIdx++] = d.Y();
|
|
467
|
+
normals[nIdx++] = d.Z();
|
|
468
|
+
d.delete();
|
|
469
|
+
}
|
|
470
|
+
normalsArray.delete();
|
|
471
|
+
pc.delete();
|
|
472
|
+
}
|
|
473
|
+
const orient = face.Orientation_1();
|
|
474
|
+
const isForward = orient === oc.TopAbs_Orientation.TopAbs_FORWARD;
|
|
475
|
+
const nbTriangles = tri.NbTriangles();
|
|
476
|
+
for (let nt = 1; nt <= nbTriangles; nt++) {
|
|
477
|
+
const t = tri.Triangle(nt);
|
|
478
|
+
let n1 = t.Value(1);
|
|
479
|
+
let n2 = t.Value(2);
|
|
480
|
+
const n3 = t.Value(3);
|
|
481
|
+
if (!isForward) {
|
|
482
|
+
const tmp = n1;
|
|
483
|
+
n1 = n2;
|
|
484
|
+
n2 = tmp;
|
|
485
|
+
}
|
|
486
|
+
triangles[tIdx++] = n1 - 1 + vertexOffset;
|
|
487
|
+
triangles[tIdx++] = n2 - 1 + vertexOffset;
|
|
488
|
+
triangles[tIdx++] = n3 - 1 + vertexOffset;
|
|
489
|
+
t.delete();
|
|
490
|
+
}
|
|
491
|
+
faceGroups.push({
|
|
492
|
+
start: triStart,
|
|
493
|
+
count: tIdx - triStart,
|
|
494
|
+
faceHash: face.HashCode(HASH_CODE_MAX$1)
|
|
495
|
+
});
|
|
496
|
+
transformation.delete();
|
|
497
|
+
}
|
|
498
|
+
location.delete();
|
|
499
|
+
triangulation.delete();
|
|
500
|
+
explorer.Next();
|
|
501
|
+
}
|
|
502
|
+
explorer.delete();
|
|
503
|
+
return { vertices, normals, triangles, faceGroups };
|
|
504
|
+
}
|
|
505
|
+
function mesh(oc, shape, options) {
|
|
506
|
+
if (oc.MeshExtractor) {
|
|
507
|
+
return meshBulk(oc, shape, options);
|
|
508
|
+
}
|
|
509
|
+
return meshJS(oc, shape, options);
|
|
510
|
+
}
|
|
511
|
+
function meshEdgesBulk(oc, shape, tolerance, angularTolerance) {
|
|
512
|
+
const raw = oc.EdgeMeshExtractor.extract(shape, tolerance, angularTolerance);
|
|
513
|
+
const linesSize = raw.getLinesSize();
|
|
514
|
+
const edgeGroupsSize = raw.getEdgeGroupsSize();
|
|
515
|
+
let lines;
|
|
516
|
+
if (linesSize > 0) {
|
|
517
|
+
const linesPtr = raw.getLinesPtr() / 4;
|
|
518
|
+
lines = oc.HEAPF32.slice(linesPtr, linesPtr + linesSize);
|
|
519
|
+
} else {
|
|
520
|
+
lines = new Float32Array(0);
|
|
521
|
+
}
|
|
522
|
+
const edgeGroups = [];
|
|
523
|
+
if (edgeGroupsSize > 0) {
|
|
524
|
+
const egPtr = raw.getEdgeGroupsPtr() / 4;
|
|
525
|
+
const egRaw = oc.HEAP32.slice(egPtr, egPtr + edgeGroupsSize);
|
|
526
|
+
for (let i = 0; i < egRaw.length; i += 3) {
|
|
527
|
+
edgeGroups.push({
|
|
528
|
+
start: egRaw[i],
|
|
529
|
+
count: egRaw[i + 1],
|
|
530
|
+
edgeHash: egRaw[i + 2]
|
|
531
|
+
});
|
|
532
|
+
}
|
|
533
|
+
}
|
|
534
|
+
raw.delete();
|
|
535
|
+
return { lines, edgeGroups };
|
|
536
|
+
}
|
|
537
|
+
function meshEdgesJS(oc, shape, tolerance, angularTolerance) {
|
|
538
|
+
const mesher = new oc.BRepMesh_IncrementalMesh_2(
|
|
539
|
+
shape,
|
|
540
|
+
tolerance,
|
|
541
|
+
false,
|
|
542
|
+
angularTolerance,
|
|
543
|
+
false
|
|
544
|
+
);
|
|
545
|
+
mesher.delete();
|
|
546
|
+
const lines = [];
|
|
547
|
+
const edgeGroups = [];
|
|
548
|
+
const seenHashes = /* @__PURE__ */ new Set();
|
|
549
|
+
const faceExplorer = new oc.TopExp_Explorer_2(
|
|
550
|
+
shape,
|
|
551
|
+
oc.TopAbs_ShapeEnum.TopAbs_FACE,
|
|
552
|
+
oc.TopAbs_ShapeEnum.TopAbs_SHAPE
|
|
553
|
+
);
|
|
554
|
+
while (faceExplorer.More()) {
|
|
555
|
+
const face = oc.TopoDS.Face_1(faceExplorer.Current());
|
|
556
|
+
const faceLoc = new oc.TopLoc_Location_1();
|
|
557
|
+
const tri = oc.BRep_Tool.Triangulation(face, faceLoc, 0);
|
|
558
|
+
if (!tri.IsNull()) {
|
|
559
|
+
const triObj = tri.get();
|
|
560
|
+
const edgeExplorer2 = new oc.TopExp_Explorer_2(
|
|
561
|
+
face,
|
|
562
|
+
oc.TopAbs_ShapeEnum.TopAbs_EDGE,
|
|
563
|
+
oc.TopAbs_ShapeEnum.TopAbs_SHAPE
|
|
564
|
+
);
|
|
565
|
+
while (edgeExplorer2.More()) {
|
|
566
|
+
const edgeShape = edgeExplorer2.Current();
|
|
567
|
+
const edge = oc.TopoDS.Edge_1(edgeShape);
|
|
568
|
+
const edgeHash = edge.HashCode(HASH_CODE_MAX$1);
|
|
569
|
+
if (!seenHashes.has(edgeHash)) {
|
|
570
|
+
seenHashes.add(edgeHash);
|
|
571
|
+
const edgeLoc = new oc.TopLoc_Location_1();
|
|
572
|
+
const polygon = oc.BRep_Tool.PolygonOnTriangulation_1(edge, tri, edgeLoc);
|
|
573
|
+
const edgeNodes = polygon && !polygon.IsNull() ? polygon.get().Nodes() : null;
|
|
574
|
+
if (edgeNodes) {
|
|
575
|
+
const lineStart = lines.length / 3;
|
|
576
|
+
let prevX = 0, prevY = 0, prevZ = 0;
|
|
577
|
+
let hasPrev = false;
|
|
578
|
+
for (let i = edgeNodes.Lower(); i <= edgeNodes.Upper(); i++) {
|
|
579
|
+
const p = triObj.Node(edgeNodes.Value(i)).Transformed(edgeLoc.Transformation());
|
|
580
|
+
const x = p.X(), y = p.Y(), z = p.Z();
|
|
581
|
+
if (hasPrev) {
|
|
582
|
+
lines.push(prevX, prevY, prevZ, x, y, z);
|
|
583
|
+
}
|
|
584
|
+
prevX = x;
|
|
585
|
+
prevY = y;
|
|
586
|
+
prevZ = z;
|
|
587
|
+
hasPrev = true;
|
|
588
|
+
p.delete();
|
|
589
|
+
}
|
|
590
|
+
edgeGroups.push({
|
|
591
|
+
start: lineStart,
|
|
592
|
+
count: lines.length / 3 - lineStart,
|
|
593
|
+
edgeHash
|
|
594
|
+
});
|
|
595
|
+
edgeNodes.delete();
|
|
596
|
+
}
|
|
597
|
+
if (polygon && !polygon.IsNull()) polygon.delete();
|
|
598
|
+
edgeLoc.delete();
|
|
599
|
+
}
|
|
600
|
+
edgeExplorer2.Next();
|
|
601
|
+
}
|
|
602
|
+
edgeExplorer2.delete();
|
|
603
|
+
}
|
|
604
|
+
tri.delete();
|
|
605
|
+
faceLoc.delete();
|
|
606
|
+
faceExplorer.Next();
|
|
607
|
+
}
|
|
608
|
+
faceExplorer.delete();
|
|
609
|
+
const edgeExplorer = new oc.TopExp_Explorer_2(
|
|
610
|
+
shape,
|
|
611
|
+
oc.TopAbs_ShapeEnum.TopAbs_EDGE,
|
|
612
|
+
oc.TopAbs_ShapeEnum.TopAbs_SHAPE
|
|
613
|
+
);
|
|
614
|
+
while (edgeExplorer.More()) {
|
|
615
|
+
const edgeShape = edgeExplorer.Current();
|
|
616
|
+
const edge = oc.TopoDS.Edge_1(edgeShape);
|
|
617
|
+
const edgeHash = edge.HashCode(HASH_CODE_MAX$1);
|
|
618
|
+
if (!seenHashes.has(edgeHash)) {
|
|
619
|
+
seenHashes.add(edgeHash);
|
|
620
|
+
const adaptor = new oc.BRepAdaptor_Curve_2(edge);
|
|
621
|
+
const tangDef = new oc.GCPnts_TangentialDeflection_2(
|
|
622
|
+
adaptor,
|
|
623
|
+
tolerance,
|
|
624
|
+
angularTolerance,
|
|
625
|
+
2,
|
|
626
|
+
1e-9,
|
|
627
|
+
1e-7
|
|
628
|
+
);
|
|
629
|
+
const lineStart = lines.length / 3;
|
|
630
|
+
let prevX = 0, prevY = 0, prevZ = 0;
|
|
631
|
+
let hasPrev = false;
|
|
632
|
+
for (let j = 1; j <= tangDef.NbPoints(); j++) {
|
|
633
|
+
const p = tangDef.Value(j);
|
|
634
|
+
const x = p.X(), y = p.Y(), z = p.Z();
|
|
635
|
+
if (hasPrev) {
|
|
636
|
+
lines.push(prevX, prevY, prevZ, x, y, z);
|
|
637
|
+
}
|
|
638
|
+
prevX = x;
|
|
639
|
+
prevY = y;
|
|
640
|
+
prevZ = z;
|
|
641
|
+
hasPrev = true;
|
|
642
|
+
p.delete();
|
|
643
|
+
}
|
|
644
|
+
edgeGroups.push({
|
|
645
|
+
start: lineStart,
|
|
646
|
+
count: lines.length / 3 - lineStart,
|
|
647
|
+
edgeHash
|
|
648
|
+
});
|
|
649
|
+
tangDef.delete();
|
|
650
|
+
adaptor.delete();
|
|
651
|
+
}
|
|
652
|
+
edgeExplorer.Next();
|
|
653
|
+
}
|
|
654
|
+
edgeExplorer.delete();
|
|
655
|
+
return { lines: new Float32Array(lines), edgeGroups };
|
|
656
|
+
}
|
|
657
|
+
function meshEdges(oc, shape, tolerance, angularTolerance) {
|
|
658
|
+
if (oc.EdgeMeshExtractor) {
|
|
659
|
+
return meshEdgesBulk(oc, shape, tolerance, angularTolerance);
|
|
660
|
+
}
|
|
661
|
+
return meshEdgesJS(oc, shape, tolerance, angularTolerance);
|
|
662
|
+
}
|
|
663
|
+
function iterShapesBulk(oc, shape, type) {
|
|
664
|
+
const typeEnumMap = {
|
|
665
|
+
vertex: 7,
|
|
666
|
+
edge: 6,
|
|
667
|
+
wire: 5,
|
|
668
|
+
face: 4,
|
|
669
|
+
shell: 3,
|
|
670
|
+
solid: 2,
|
|
671
|
+
compsolid: 1,
|
|
672
|
+
compound: 0
|
|
673
|
+
};
|
|
674
|
+
const raw = oc.TopologyExtractor.extract(shape, typeEnumMap[type]);
|
|
675
|
+
const count = raw.getShapesCount();
|
|
676
|
+
const result = [];
|
|
677
|
+
for (let i = 0; i < count; i++) {
|
|
678
|
+
result.push(raw.getShape(i));
|
|
679
|
+
}
|
|
680
|
+
raw.delete();
|
|
681
|
+
return result;
|
|
682
|
+
}
|
|
683
|
+
function iterShapesJS(oc, shape, type) {
|
|
684
|
+
const typeMap = {
|
|
685
|
+
vertex: oc.TopAbs_ShapeEnum.TopAbs_VERTEX,
|
|
686
|
+
edge: oc.TopAbs_ShapeEnum.TopAbs_EDGE,
|
|
687
|
+
wire: oc.TopAbs_ShapeEnum.TopAbs_WIRE,
|
|
688
|
+
face: oc.TopAbs_ShapeEnum.TopAbs_FACE,
|
|
689
|
+
shell: oc.TopAbs_ShapeEnum.TopAbs_SHELL,
|
|
690
|
+
solid: oc.TopAbs_ShapeEnum.TopAbs_SOLID,
|
|
691
|
+
compsolid: oc.TopAbs_ShapeEnum.TopAbs_COMPSOLID,
|
|
692
|
+
compound: oc.TopAbs_ShapeEnum.TopAbs_COMPOUND
|
|
693
|
+
};
|
|
694
|
+
const explorer = new oc.TopExp_Explorer_2(shape, typeMap[type], oc.TopAbs_ShapeEnum.TopAbs_SHAPE);
|
|
695
|
+
const result = [];
|
|
696
|
+
const seen = /* @__PURE__ */ new Map();
|
|
697
|
+
while (explorer.More()) {
|
|
698
|
+
const item = explorer.Current();
|
|
699
|
+
const hash = item.HashCode(HASH_CODE_MAX$1);
|
|
700
|
+
const bucket = seen.get(hash);
|
|
701
|
+
if (!bucket) {
|
|
702
|
+
seen.set(hash, [item]);
|
|
703
|
+
result.push(item);
|
|
704
|
+
} else if (!bucket.some((s) => s.IsSame(item))) {
|
|
705
|
+
bucket.push(item);
|
|
706
|
+
result.push(item);
|
|
707
|
+
}
|
|
708
|
+
explorer.Next();
|
|
709
|
+
}
|
|
710
|
+
explorer.delete();
|
|
711
|
+
return result;
|
|
712
|
+
}
|
|
713
|
+
function iterShapes(oc, shape, type) {
|
|
714
|
+
if (oc.TopologyExtractor) {
|
|
715
|
+
return iterShapesBulk(oc, shape, type);
|
|
716
|
+
}
|
|
717
|
+
return iterShapesJS(oc, shape, type);
|
|
718
|
+
}
|
|
719
|
+
const shapeTypeMaps = /* @__PURE__ */ new WeakMap();
|
|
720
|
+
function getShapeTypeMap(oc) {
|
|
721
|
+
let map2 = shapeTypeMaps.get(oc);
|
|
722
|
+
if (!map2) {
|
|
723
|
+
const ta = oc.TopAbs_ShapeEnum;
|
|
724
|
+
map2 = /* @__PURE__ */ new Map([
|
|
725
|
+
[ta.TopAbs_VERTEX, "vertex"],
|
|
726
|
+
[ta.TopAbs_EDGE, "edge"],
|
|
727
|
+
[ta.TopAbs_WIRE, "wire"],
|
|
728
|
+
[ta.TopAbs_FACE, "face"],
|
|
729
|
+
[ta.TopAbs_SHELL, "shell"],
|
|
730
|
+
[ta.TopAbs_SOLID, "solid"],
|
|
731
|
+
[ta.TopAbs_COMPSOLID, "compsolid"],
|
|
732
|
+
[ta.TopAbs_COMPOUND, "compound"]
|
|
733
|
+
]);
|
|
734
|
+
shapeTypeMaps.set(oc, map2);
|
|
735
|
+
}
|
|
736
|
+
return map2;
|
|
737
|
+
}
|
|
738
|
+
function shapeType$1(oc, shape) {
|
|
739
|
+
if (shape.IsNull()) throw new Error("Cannot determine shape type: shape is null");
|
|
740
|
+
const result = getShapeTypeMap(oc).get(shape.ShapeType());
|
|
741
|
+
if (!result) throw new Error(`Unknown shape type enum value: ${shape.ShapeType()}`);
|
|
742
|
+
return result;
|
|
743
|
+
}
|
|
744
|
+
function isSame(a, b) {
|
|
745
|
+
return a.IsSame(b);
|
|
746
|
+
}
|
|
747
|
+
function isEqual(a, b) {
|
|
748
|
+
return a.IsEqual(b);
|
|
749
|
+
}
|
|
750
|
+
function makeVertex$1(oc, x, y, z) {
|
|
751
|
+
const pnt2 = new oc.gp_Pnt_3(x, y, z);
|
|
752
|
+
const maker = new oc.BRepBuilderAPI_MakeVertex(pnt2);
|
|
753
|
+
const vertex = maker.Vertex();
|
|
754
|
+
maker.delete();
|
|
755
|
+
pnt2.delete();
|
|
756
|
+
return vertex;
|
|
757
|
+
}
|
|
758
|
+
function makeEdge(oc, curve, start, end) {
|
|
759
|
+
const maker = start !== void 0 && end !== void 0 ? new oc.BRepBuilderAPI_MakeEdge_24(curve, start, end) : new oc.BRepBuilderAPI_MakeEdge_24(curve);
|
|
760
|
+
const edge = maker.Edge();
|
|
761
|
+
maker.delete();
|
|
762
|
+
return edge;
|
|
763
|
+
}
|
|
764
|
+
function makeWire(oc, edges) {
|
|
765
|
+
const wireBuilder = new oc.BRepBuilderAPI_MakeWire_1();
|
|
766
|
+
for (const edge of edges) {
|
|
767
|
+
wireBuilder.Add_1(edge);
|
|
768
|
+
}
|
|
769
|
+
const progress = new oc.Message_ProgressRange_1();
|
|
770
|
+
wireBuilder.Build(progress);
|
|
771
|
+
const wire = wireBuilder.Wire();
|
|
772
|
+
wireBuilder.delete();
|
|
773
|
+
progress.delete();
|
|
774
|
+
return wire;
|
|
775
|
+
}
|
|
776
|
+
function makeFace$1(oc, wire, planar = true) {
|
|
777
|
+
if (planar) {
|
|
778
|
+
const builder2 = new oc.BRepBuilderAPI_MakeFace_15(wire, false);
|
|
779
|
+
const face = builder2.Face();
|
|
780
|
+
builder2.delete();
|
|
781
|
+
return face;
|
|
782
|
+
}
|
|
783
|
+
const builder = new oc.BRepOffsetAPI_MakeFilling(3, 15, 2, false, 1e-5, 1e-4, 0.01, 0.1, 8, 9);
|
|
784
|
+
const edges = iterShapes(oc, wire, "edge");
|
|
785
|
+
for (const edge of edges) {
|
|
786
|
+
builder.Add_1(edge, oc.GeomAbs_Shape.GeomAbs_C0, true);
|
|
787
|
+
}
|
|
788
|
+
const progress = new oc.Message_ProgressRange_1();
|
|
789
|
+
builder.Build(progress);
|
|
790
|
+
const shape = builder.Shape();
|
|
791
|
+
builder.delete();
|
|
792
|
+
progress.delete();
|
|
793
|
+
return shape;
|
|
794
|
+
}
|
|
795
|
+
function makeBox$1(oc, width, height, depth) {
|
|
796
|
+
const maker = new oc.BRepPrimAPI_MakeBox_2(width, height, depth);
|
|
797
|
+
const solid = maker.Solid();
|
|
798
|
+
maker.delete();
|
|
799
|
+
return solid;
|
|
800
|
+
}
|
|
801
|
+
function makeCylinder$1(oc, radius, height, center = [0, 0, 0], direction = [0, 0, 1]) {
|
|
802
|
+
const origin = new oc.gp_Pnt_3(...center);
|
|
803
|
+
const dir = new oc.gp_Dir_4(...direction);
|
|
804
|
+
const axis = new oc.gp_Ax2_3(origin, dir);
|
|
805
|
+
const maker = new oc.BRepPrimAPI_MakeCylinder_3(axis, radius, height);
|
|
806
|
+
const solid = maker.Shape();
|
|
807
|
+
maker.delete();
|
|
808
|
+
axis.delete();
|
|
809
|
+
origin.delete();
|
|
810
|
+
dir.delete();
|
|
811
|
+
return solid;
|
|
812
|
+
}
|
|
813
|
+
function makeSphere$1(oc, radius, center = [0, 0, 0]) {
|
|
814
|
+
const origin = new oc.gp_Pnt_3(...center);
|
|
815
|
+
const maker = new oc.BRepPrimAPI_MakeSphere_2(origin, radius);
|
|
816
|
+
const solid = maker.Shape();
|
|
817
|
+
maker.delete();
|
|
818
|
+
origin.delete();
|
|
819
|
+
return solid;
|
|
820
|
+
}
|
|
821
|
+
function extrude(oc, face, direction, length2) {
|
|
822
|
+
const vec2 = new oc.gp_Vec_4(direction[0] * length2, direction[1] * length2, direction[2] * length2);
|
|
823
|
+
const maker = new oc.BRepPrimAPI_MakePrism_1(face, vec2, false, true);
|
|
824
|
+
const result = maker.Shape();
|
|
825
|
+
maker.delete();
|
|
826
|
+
vec2.delete();
|
|
827
|
+
return result;
|
|
828
|
+
}
|
|
829
|
+
function revolve(oc, shape, axis, angle) {
|
|
830
|
+
const maker = new oc.BRepPrimAPI_MakeRevol_1(shape, axis, angle, false);
|
|
831
|
+
const result = maker.Shape();
|
|
832
|
+
maker.delete();
|
|
833
|
+
return result;
|
|
834
|
+
}
|
|
835
|
+
function loft$1(oc, wires, ruled = false, startShape, endShape) {
|
|
836
|
+
const loftBuilder = new oc.BRepOffsetAPI_ThruSections(true, ruled, 1e-6);
|
|
837
|
+
if (startShape) loftBuilder.AddVertex(startShape);
|
|
838
|
+
for (const wire of wires) {
|
|
839
|
+
loftBuilder.AddWire(wire);
|
|
840
|
+
}
|
|
841
|
+
if (endShape) loftBuilder.AddVertex(endShape);
|
|
842
|
+
const progress = new oc.Message_ProgressRange_1();
|
|
843
|
+
loftBuilder.Build(progress);
|
|
844
|
+
const result = loftBuilder.Shape();
|
|
845
|
+
loftBuilder.delete();
|
|
846
|
+
progress.delete();
|
|
847
|
+
return result;
|
|
848
|
+
}
|
|
849
|
+
function sweep$1(oc, wire, spine, options = {}) {
|
|
850
|
+
const { transitionMode } = options;
|
|
851
|
+
const sweepBuilder = new oc.BRepOffsetAPI_MakePipeShell(spine);
|
|
852
|
+
if (transitionMode !== void 0) {
|
|
853
|
+
sweepBuilder.SetTransitionMode(transitionMode);
|
|
854
|
+
}
|
|
855
|
+
sweepBuilder.Add_1(wire, false, false);
|
|
856
|
+
const progress = new oc.Message_ProgressRange_1();
|
|
857
|
+
sweepBuilder.Build(progress);
|
|
858
|
+
progress.delete();
|
|
859
|
+
sweepBuilder.MakeSolid();
|
|
860
|
+
const result = sweepBuilder.Shape();
|
|
861
|
+
sweepBuilder.delete();
|
|
862
|
+
return result;
|
|
863
|
+
}
|
|
864
|
+
function fillet(oc, shape, edges, radius) {
|
|
865
|
+
const builder = new oc.BRepFilletAPI_MakeFillet(shape, oc.ChFi3d_FilletShape.ChFi3d_Rational);
|
|
866
|
+
for (const edge of edges) {
|
|
867
|
+
const r = typeof radius === "function" ? radius(edge) : radius;
|
|
868
|
+
if (r > 0) builder.Add_2(r, edge);
|
|
869
|
+
}
|
|
870
|
+
const result = builder.Shape();
|
|
871
|
+
builder.delete();
|
|
872
|
+
return result;
|
|
873
|
+
}
|
|
874
|
+
function chamfer(oc, shape, edges, distance) {
|
|
875
|
+
const builder = new oc.BRepFilletAPI_MakeChamfer(shape);
|
|
876
|
+
for (const edge of edges) {
|
|
877
|
+
const d = typeof distance === "function" ? distance(edge) : distance;
|
|
878
|
+
if (d > 0) builder.Add_2(d, edge);
|
|
879
|
+
}
|
|
880
|
+
const result = builder.Shape();
|
|
881
|
+
builder.delete();
|
|
882
|
+
return result;
|
|
883
|
+
}
|
|
884
|
+
function shell(oc, shape, faces, thickness, tolerance = 1e-3) {
|
|
885
|
+
const facesToRemove = new oc.TopTools_ListOfShape_1();
|
|
886
|
+
for (const face of faces) {
|
|
887
|
+
facesToRemove.Append_1(face);
|
|
888
|
+
}
|
|
889
|
+
const progress = new oc.Message_ProgressRange_1();
|
|
890
|
+
const builder = new oc.BRepOffsetAPI_MakeThickSolid();
|
|
891
|
+
builder.MakeThickSolidByJoin(
|
|
892
|
+
shape,
|
|
893
|
+
facesToRemove,
|
|
894
|
+
-thickness,
|
|
895
|
+
tolerance,
|
|
896
|
+
oc.BRepOffset_Mode.BRepOffset_Skin,
|
|
897
|
+
false,
|
|
898
|
+
false,
|
|
899
|
+
oc.GeomAbs_JoinType.GeomAbs_Arc,
|
|
900
|
+
false,
|
|
901
|
+
progress
|
|
902
|
+
);
|
|
903
|
+
const result = builder.Shape();
|
|
904
|
+
builder.delete();
|
|
905
|
+
facesToRemove.delete();
|
|
906
|
+
progress.delete();
|
|
907
|
+
return result;
|
|
908
|
+
}
|
|
909
|
+
function offset$1(oc, shape, distance, tolerance = 1e-6) {
|
|
910
|
+
const progress = new oc.Message_ProgressRange_1();
|
|
911
|
+
const builder = new oc.BRepOffsetAPI_MakeOffsetShape();
|
|
912
|
+
builder.PerformByJoin(
|
|
913
|
+
shape,
|
|
914
|
+
distance,
|
|
915
|
+
tolerance,
|
|
916
|
+
oc.BRepOffset_Mode.BRepOffset_Skin,
|
|
917
|
+
false,
|
|
918
|
+
false,
|
|
919
|
+
oc.GeomAbs_JoinType.GeomAbs_Arc,
|
|
920
|
+
false,
|
|
921
|
+
progress
|
|
922
|
+
);
|
|
923
|
+
const result = builder.Shape();
|
|
924
|
+
builder.delete();
|
|
925
|
+
progress.delete();
|
|
926
|
+
return result;
|
|
927
|
+
}
|
|
57
928
|
class OCCTAdapter {
|
|
58
929
|
oc;
|
|
59
930
|
constructor(oc) {
|
|
60
931
|
this.oc = oc;
|
|
61
932
|
}
|
|
62
|
-
// --- Boolean operations ---
|
|
933
|
+
// --- Boolean operations (delegates to booleanOps.ts) ---
|
|
63
934
|
fuse(shape, tool, options = {}) {
|
|
64
|
-
|
|
65
|
-
const progress = new this.oc.Message_ProgressRange_1();
|
|
66
|
-
const fuseOp = new this.oc.BRepAlgoAPI_Fuse_3(shape, tool, progress);
|
|
67
|
-
this._applyGlue(fuseOp, optimisation);
|
|
68
|
-
fuseOp.Build(progress);
|
|
69
|
-
if (simplify) fuseOp.SimplifyResult(true, true, 1e-3);
|
|
70
|
-
const result = fuseOp.Shape();
|
|
71
|
-
fuseOp.delete();
|
|
72
|
-
progress.delete();
|
|
73
|
-
return result;
|
|
935
|
+
return fuse(this.oc, shape, tool, options);
|
|
74
936
|
}
|
|
75
937
|
cut(shape, tool, options = {}) {
|
|
76
|
-
|
|
77
|
-
const progress = new this.oc.Message_ProgressRange_1();
|
|
78
|
-
const cutOp = new this.oc.BRepAlgoAPI_Cut_3(shape, tool, progress);
|
|
79
|
-
this._applyGlue(cutOp, optimisation);
|
|
80
|
-
cutOp.Build(progress);
|
|
81
|
-
if (simplify) cutOp.SimplifyResult(true, true, 1e-3);
|
|
82
|
-
const result = cutOp.Shape();
|
|
83
|
-
cutOp.delete();
|
|
84
|
-
progress.delete();
|
|
85
|
-
return result;
|
|
938
|
+
return cut(this.oc, shape, tool, options);
|
|
86
939
|
}
|
|
87
940
|
intersect(shape, tool, options = {}) {
|
|
88
|
-
|
|
89
|
-
const progress = new this.oc.Message_ProgressRange_1();
|
|
90
|
-
const commonOp = new this.oc.BRepAlgoAPI_Common_3(shape, tool, progress);
|
|
91
|
-
this._applyGlue(commonOp, optimisation);
|
|
92
|
-
commonOp.Build(progress);
|
|
93
|
-
if (simplify) commonOp.SimplifyResult(true, true, 1e-3);
|
|
94
|
-
const result = commonOp.Shape();
|
|
95
|
-
commonOp.delete();
|
|
96
|
-
progress.delete();
|
|
97
|
-
return result;
|
|
941
|
+
return intersect(this.oc, shape, tool, options);
|
|
98
942
|
}
|
|
99
943
|
fuseAll(shapes, options = {}) {
|
|
100
|
-
|
|
101
|
-
if (shapes.length === 1) return shapes[0];
|
|
102
|
-
const { strategy = "native" } = options;
|
|
103
|
-
if (strategy === "pairwise") {
|
|
104
|
-
return this._fuseAllPairwise(shapes, options);
|
|
105
|
-
}
|
|
106
|
-
if (this.oc.BooleanBatch) {
|
|
107
|
-
return this._fuseAllBatch(shapes, options);
|
|
108
|
-
}
|
|
109
|
-
return this._fuseAllNative(shapes, options);
|
|
110
|
-
}
|
|
111
|
-
_fuseAllBatch(shapes, options = {}) {
|
|
112
|
-
const { optimisation, simplify = false } = options;
|
|
113
|
-
const batch = new this.oc.BooleanBatch();
|
|
114
|
-
for (const s of shapes) {
|
|
115
|
-
batch.addShape(s);
|
|
116
|
-
}
|
|
117
|
-
const glueMode = optimisation === "commonFace" ? 1 : optimisation === "sameFace" ? 2 : 0;
|
|
118
|
-
const result = batch.fuseAll(glueMode, simplify);
|
|
119
|
-
batch.delete();
|
|
120
|
-
return result;
|
|
121
|
-
}
|
|
122
|
-
_fuseAllNative(shapes, options = {}) {
|
|
123
|
-
const { optimisation, simplify = false } = options;
|
|
124
|
-
const argList = new this.oc.TopTools_ListOfShape_1();
|
|
125
|
-
for (const s of shapes) {
|
|
126
|
-
argList.Append_1(s);
|
|
127
|
-
}
|
|
128
|
-
const builder = new this.oc.BRepAlgoAPI_BuilderAlgo_1();
|
|
129
|
-
builder.SetArguments(argList);
|
|
130
|
-
this._applyGlue(builder, optimisation);
|
|
131
|
-
const progress = new this.oc.Message_ProgressRange_1();
|
|
132
|
-
builder.Build(progress);
|
|
133
|
-
let result = builder.Shape();
|
|
134
|
-
if (simplify) {
|
|
135
|
-
const upgrader = new this.oc.ShapeUpgrade_UnifySameDomain_2(result, true, true, false);
|
|
136
|
-
upgrader.Build();
|
|
137
|
-
result = upgrader.Shape();
|
|
138
|
-
upgrader.delete();
|
|
139
|
-
}
|
|
140
|
-
argList.delete();
|
|
141
|
-
builder.delete();
|
|
142
|
-
progress.delete();
|
|
143
|
-
return result;
|
|
144
|
-
}
|
|
145
|
-
_fuseAllPairwise(shapes, options = {}) {
|
|
146
|
-
const mid = Math.ceil(shapes.length / 2);
|
|
147
|
-
const left = this.fuseAll(shapes.slice(0, mid), {
|
|
148
|
-
...options,
|
|
149
|
-
simplify: false,
|
|
150
|
-
strategy: "pairwise"
|
|
151
|
-
});
|
|
152
|
-
const right = this.fuseAll(shapes.slice(mid), {
|
|
153
|
-
...options,
|
|
154
|
-
simplify: false,
|
|
155
|
-
strategy: "pairwise"
|
|
156
|
-
});
|
|
157
|
-
return this.fuse(left, right, options);
|
|
944
|
+
return fuseAll$3(this.oc, shapes, options);
|
|
158
945
|
}
|
|
159
946
|
cutAll(shape, tools, options = {}) {
|
|
160
|
-
|
|
161
|
-
if (this.oc.BooleanBatch) {
|
|
162
|
-
return this._cutAllBatch(shape, tools, options);
|
|
163
|
-
}
|
|
164
|
-
const toolCompound = this._buildCompound(tools);
|
|
165
|
-
const result = this.cut(shape, toolCompound, options);
|
|
166
|
-
toolCompound.delete();
|
|
167
|
-
return result;
|
|
947
|
+
return cutAll$2(this.oc, shape, tools, options);
|
|
168
948
|
}
|
|
169
|
-
|
|
170
|
-
const { optimisation, simplify = false } = options;
|
|
171
|
-
const batch = new this.oc.BooleanBatch();
|
|
172
|
-
for (const t of tools) {
|
|
173
|
-
batch.addShape(t);
|
|
174
|
-
}
|
|
175
|
-
const glueMode = optimisation === "commonFace" ? 1 : optimisation === "sameFace" ? 2 : 0;
|
|
176
|
-
const result = batch.cutAll(shape, glueMode, simplify);
|
|
177
|
-
batch.delete();
|
|
178
|
-
return result;
|
|
179
|
-
}
|
|
180
|
-
// --- Shape construction ---
|
|
949
|
+
// --- Shape construction (delegates to constructorOps.ts) ---
|
|
181
950
|
makeVertex(x, y, z) {
|
|
182
|
-
|
|
183
|
-
const maker = new this.oc.BRepBuilderAPI_MakeVertex(pnt2);
|
|
184
|
-
const vertex = maker.Vertex();
|
|
185
|
-
maker.delete();
|
|
186
|
-
pnt2.delete();
|
|
187
|
-
return vertex;
|
|
951
|
+
return makeVertex$1(this.oc, x, y, z);
|
|
188
952
|
}
|
|
189
953
|
makeEdge(curve, start, end) {
|
|
190
|
-
|
|
191
|
-
const edge = maker.Edge();
|
|
192
|
-
maker.delete();
|
|
193
|
-
return edge;
|
|
954
|
+
return makeEdge(this.oc, curve, start, end);
|
|
194
955
|
}
|
|
195
956
|
makeWire(edges) {
|
|
196
|
-
|
|
197
|
-
for (const edge of edges) {
|
|
198
|
-
wireBuilder.Add_1(edge);
|
|
199
|
-
}
|
|
200
|
-
const progress = new this.oc.Message_ProgressRange_1();
|
|
201
|
-
wireBuilder.Build(progress);
|
|
202
|
-
const wire = wireBuilder.Wire();
|
|
203
|
-
wireBuilder.delete();
|
|
204
|
-
progress.delete();
|
|
205
|
-
return wire;
|
|
957
|
+
return makeWire(this.oc, edges);
|
|
206
958
|
}
|
|
207
959
|
makeFace(wire, planar = true) {
|
|
208
|
-
|
|
209
|
-
const builder2 = new this.oc.BRepBuilderAPI_MakeFace_15(wire, false);
|
|
210
|
-
const face = builder2.Face();
|
|
211
|
-
builder2.delete();
|
|
212
|
-
return face;
|
|
213
|
-
}
|
|
214
|
-
const builder = new this.oc.BRepOffsetAPI_MakeFilling(
|
|
215
|
-
3,
|
|
216
|
-
15,
|
|
217
|
-
2,
|
|
218
|
-
false,
|
|
219
|
-
1e-5,
|
|
220
|
-
1e-4,
|
|
221
|
-
0.01,
|
|
222
|
-
0.1,
|
|
223
|
-
8,
|
|
224
|
-
9
|
|
225
|
-
);
|
|
226
|
-
const edges = this.iterShapes(wire, "edge");
|
|
227
|
-
for (const edge of edges) {
|
|
228
|
-
builder.Add_1(edge, this.oc.GeomAbs_Shape.GeomAbs_C0, true);
|
|
229
|
-
}
|
|
230
|
-
const progress = new this.oc.Message_ProgressRange_1();
|
|
231
|
-
builder.Build(progress);
|
|
232
|
-
const shape = builder.Shape();
|
|
233
|
-
builder.delete();
|
|
234
|
-
progress.delete();
|
|
235
|
-
return shape;
|
|
960
|
+
return makeFace$1(this.oc, wire, planar);
|
|
236
961
|
}
|
|
237
962
|
makeBox(width, height, depth) {
|
|
238
|
-
|
|
239
|
-
const solid = maker.Solid();
|
|
240
|
-
maker.delete();
|
|
241
|
-
return solid;
|
|
963
|
+
return makeBox$1(this.oc, width, height, depth);
|
|
242
964
|
}
|
|
243
965
|
makeCylinder(radius, height, center = [0, 0, 0], direction = [0, 0, 1]) {
|
|
244
|
-
|
|
245
|
-
const dir = new this.oc.gp_Dir_4(...direction);
|
|
246
|
-
const axis = new this.oc.gp_Ax2_3(origin, dir);
|
|
247
|
-
const maker = new this.oc.BRepPrimAPI_MakeCylinder_3(axis, radius, height);
|
|
248
|
-
const solid = maker.Shape();
|
|
249
|
-
maker.delete();
|
|
250
|
-
axis.delete();
|
|
251
|
-
origin.delete();
|
|
252
|
-
dir.delete();
|
|
253
|
-
return solid;
|
|
966
|
+
return makeCylinder$1(this.oc, radius, height, center, direction);
|
|
254
967
|
}
|
|
255
968
|
makeSphere(radius, center = [0, 0, 0]) {
|
|
256
|
-
|
|
257
|
-
const maker = new this.oc.BRepPrimAPI_MakeSphere_2(origin, radius);
|
|
258
|
-
const solid = maker.Shape();
|
|
259
|
-
maker.delete();
|
|
260
|
-
origin.delete();
|
|
261
|
-
return solid;
|
|
969
|
+
return makeSphere$1(this.oc, radius, center);
|
|
262
970
|
}
|
|
263
|
-
// --- Extrusion / sweep / loft / revolution ---
|
|
264
|
-
extrude(face, direction,
|
|
265
|
-
|
|
266
|
-
direction[0] * length,
|
|
267
|
-
direction[1] * length,
|
|
268
|
-
direction[2] * length
|
|
269
|
-
);
|
|
270
|
-
const maker = new this.oc.BRepPrimAPI_MakePrism_1(face, vec2, false, true);
|
|
271
|
-
const result = maker.Shape();
|
|
272
|
-
maker.delete();
|
|
273
|
-
vec2.delete();
|
|
274
|
-
return result;
|
|
971
|
+
// --- Extrusion / sweep / loft / revolution (delegates to sweepOps.ts) ---
|
|
972
|
+
extrude(face, direction, length2) {
|
|
973
|
+
return extrude(this.oc, face, direction, length2);
|
|
275
974
|
}
|
|
276
975
|
revolve(shape, axis, angle) {
|
|
277
|
-
|
|
278
|
-
const result = maker.Shape();
|
|
279
|
-
maker.delete();
|
|
280
|
-
return result;
|
|
976
|
+
return revolve(this.oc, shape, axis, angle);
|
|
281
977
|
}
|
|
282
|
-
loft(wires, ruled = false, startShape, endShape) {
|
|
283
|
-
|
|
284
|
-
if (startShape) loftBuilder.AddVertex(startShape);
|
|
285
|
-
for (const wire of wires) {
|
|
286
|
-
loftBuilder.AddWire(wire);
|
|
287
|
-
}
|
|
288
|
-
if (endShape) loftBuilder.AddVertex(endShape);
|
|
289
|
-
const progress = new this.oc.Message_ProgressRange_1();
|
|
290
|
-
loftBuilder.Build(progress);
|
|
291
|
-
const result = loftBuilder.Shape();
|
|
292
|
-
loftBuilder.delete();
|
|
293
|
-
progress.delete();
|
|
294
|
-
return result;
|
|
978
|
+
loft(wires, ruled = false, startShape, endShape) {
|
|
979
|
+
return loft$1(this.oc, wires, ruled, startShape, endShape);
|
|
295
980
|
}
|
|
296
981
|
sweep(wire, spine, options = {}) {
|
|
297
|
-
|
|
298
|
-
const sweepBuilder = new this.oc.BRepOffsetAPI_MakePipeShell(spine);
|
|
299
|
-
if (transitionMode !== void 0) {
|
|
300
|
-
sweepBuilder.SetTransitionMode(transitionMode);
|
|
301
|
-
}
|
|
302
|
-
sweepBuilder.Add_1(wire, false, false);
|
|
303
|
-
const progress = new this.oc.Message_ProgressRange_1();
|
|
304
|
-
sweepBuilder.Build(progress);
|
|
305
|
-
progress.delete();
|
|
306
|
-
sweepBuilder.MakeSolid();
|
|
307
|
-
const result = sweepBuilder.Shape();
|
|
308
|
-
sweepBuilder.delete();
|
|
309
|
-
return result;
|
|
982
|
+
return sweep$1(this.oc, wire, spine, options);
|
|
310
983
|
}
|
|
311
|
-
// --- Modification ---
|
|
984
|
+
// --- Modification (delegates to modifierOps.ts) ---
|
|
312
985
|
fillet(shape, edges, radius) {
|
|
313
|
-
|
|
314
|
-
shape,
|
|
315
|
-
this.oc.ChFi3d_FilletShape.ChFi3d_Rational
|
|
316
|
-
);
|
|
317
|
-
for (const edge of edges) {
|
|
318
|
-
const r = typeof radius === "function" ? radius(edge) : radius;
|
|
319
|
-
if (r > 0) builder.Add_2(r, edge);
|
|
320
|
-
}
|
|
321
|
-
const result = builder.Shape();
|
|
322
|
-
builder.delete();
|
|
323
|
-
return result;
|
|
986
|
+
return fillet(this.oc, shape, edges, radius);
|
|
324
987
|
}
|
|
325
988
|
chamfer(shape, edges, distance) {
|
|
326
|
-
|
|
327
|
-
for (const edge of edges) {
|
|
328
|
-
const d = typeof distance === "function" ? distance(edge) : distance;
|
|
329
|
-
if (d > 0) builder.Add_2(d, edge);
|
|
330
|
-
}
|
|
331
|
-
const result = builder.Shape();
|
|
332
|
-
builder.delete();
|
|
333
|
-
return result;
|
|
989
|
+
return chamfer(this.oc, shape, edges, distance);
|
|
334
990
|
}
|
|
335
991
|
shell(shape, faces, thickness, tolerance = 1e-3) {
|
|
336
|
-
|
|
337
|
-
for (const face of faces) {
|
|
338
|
-
facesToRemove.Append_1(face);
|
|
339
|
-
}
|
|
340
|
-
const progress = new this.oc.Message_ProgressRange_1();
|
|
341
|
-
const builder = new this.oc.BRepOffsetAPI_MakeThickSolid();
|
|
342
|
-
builder.MakeThickSolidByJoin(
|
|
343
|
-
shape,
|
|
344
|
-
facesToRemove,
|
|
345
|
-
-thickness,
|
|
346
|
-
tolerance,
|
|
347
|
-
this.oc.BRepOffset_Mode.BRepOffset_Skin,
|
|
348
|
-
false,
|
|
349
|
-
false,
|
|
350
|
-
this.oc.GeomAbs_JoinType.GeomAbs_Arc,
|
|
351
|
-
false,
|
|
352
|
-
progress
|
|
353
|
-
);
|
|
354
|
-
const result = builder.Shape();
|
|
355
|
-
builder.delete();
|
|
356
|
-
facesToRemove.delete();
|
|
357
|
-
progress.delete();
|
|
358
|
-
return result;
|
|
992
|
+
return shell(this.oc, shape, faces, thickness, tolerance);
|
|
359
993
|
}
|
|
360
994
|
offset(shape, distance, tolerance = 1e-6) {
|
|
361
|
-
|
|
362
|
-
const builder = new this.oc.BRepOffsetAPI_MakeOffsetShape();
|
|
363
|
-
builder.PerformByJoin(
|
|
364
|
-
shape,
|
|
365
|
-
distance,
|
|
366
|
-
tolerance,
|
|
367
|
-
this.oc.BRepOffset_Mode.BRepOffset_Skin,
|
|
368
|
-
false,
|
|
369
|
-
false,
|
|
370
|
-
this.oc.GeomAbs_JoinType.GeomAbs_Arc,
|
|
371
|
-
false,
|
|
372
|
-
progress
|
|
373
|
-
);
|
|
374
|
-
const result = builder.Shape();
|
|
375
|
-
builder.delete();
|
|
376
|
-
progress.delete();
|
|
377
|
-
return result;
|
|
995
|
+
return offset$1(this.oc, shape, distance, tolerance);
|
|
378
996
|
}
|
|
379
|
-
// --- Transforms ---
|
|
997
|
+
// --- Transforms (delegates to transformOps.ts) ---
|
|
380
998
|
transform(shape, trsf) {
|
|
381
|
-
|
|
382
|
-
const result = transformer.ModifiedShape(shape);
|
|
383
|
-
transformer.delete();
|
|
384
|
-
return result;
|
|
999
|
+
return transform(this.oc, shape, trsf);
|
|
385
1000
|
}
|
|
386
1001
|
translate(shape, x, y, z) {
|
|
387
|
-
|
|
388
|
-
const vec2 = new this.oc.gp_Vec_4(x, y, z);
|
|
389
|
-
trsf.SetTranslation_1(vec2);
|
|
390
|
-
const result = this.transform(shape, trsf);
|
|
391
|
-
trsf.delete();
|
|
392
|
-
vec2.delete();
|
|
393
|
-
return result;
|
|
1002
|
+
return translate$1(this.oc, shape, x, y, z);
|
|
394
1003
|
}
|
|
395
1004
|
rotate(shape, angle, axis = [0, 0, 1], center = [0, 0, 0]) {
|
|
396
|
-
|
|
397
|
-
const origin = new this.oc.gp_Pnt_3(...center);
|
|
398
|
-
const dir = new this.oc.gp_Dir_4(...axis);
|
|
399
|
-
const ax1 = new this.oc.gp_Ax1_2(origin, dir);
|
|
400
|
-
trsf.SetRotation_1(ax1, angle * Math.PI / 180);
|
|
401
|
-
const result = this.transform(shape, trsf);
|
|
402
|
-
trsf.delete();
|
|
403
|
-
ax1.delete();
|
|
404
|
-
origin.delete();
|
|
405
|
-
dir.delete();
|
|
406
|
-
return result;
|
|
1005
|
+
return rotate$1(this.oc, shape, angle, axis, center);
|
|
407
1006
|
}
|
|
408
1007
|
mirror(shape, origin, normal) {
|
|
409
|
-
|
|
410
|
-
const pnt2 = new this.oc.gp_Pnt_3(...origin);
|
|
411
|
-
const dir = new this.oc.gp_Dir_4(...normal);
|
|
412
|
-
const ax2 = new this.oc.gp_Ax2_3(pnt2, dir);
|
|
413
|
-
trsf.SetMirror_3(ax2);
|
|
414
|
-
const result = this.transform(shape, trsf);
|
|
415
|
-
trsf.delete();
|
|
416
|
-
ax2.delete();
|
|
417
|
-
pnt2.delete();
|
|
418
|
-
dir.delete();
|
|
419
|
-
return result;
|
|
1008
|
+
return mirror$1(this.oc, shape, origin, normal);
|
|
420
1009
|
}
|
|
421
1010
|
scale(shape, center, factor) {
|
|
422
|
-
|
|
423
|
-
const pnt2 = new this.oc.gp_Pnt_3(...center);
|
|
424
|
-
trsf.SetScale(pnt2, factor);
|
|
425
|
-
const result = this.transform(shape, trsf);
|
|
426
|
-
trsf.delete();
|
|
427
|
-
pnt2.delete();
|
|
428
|
-
return result;
|
|
1011
|
+
return scale$1(this.oc, shape, center, factor);
|
|
429
1012
|
}
|
|
430
|
-
// --- Meshing ---
|
|
1013
|
+
// --- Meshing (delegates to meshOps.ts) ---
|
|
431
1014
|
mesh(shape, options) {
|
|
432
|
-
|
|
433
|
-
return this._meshBulk(shape, options);
|
|
434
|
-
}
|
|
435
|
-
return this._meshJS(shape, options);
|
|
436
|
-
}
|
|
437
|
-
_meshBulk(shape, options) {
|
|
438
|
-
const raw = this.oc.MeshExtractor.extract(
|
|
439
|
-
shape,
|
|
440
|
-
options.tolerance,
|
|
441
|
-
options.angularTolerance,
|
|
442
|
-
!!options.skipNormals
|
|
443
|
-
);
|
|
444
|
-
const verticesSize = raw.getVerticesSize();
|
|
445
|
-
const normalsSize = raw.getNormalsSize();
|
|
446
|
-
const trianglesSize = raw.getTrianglesSize();
|
|
447
|
-
const faceGroupsSize = raw.getFaceGroupsSize();
|
|
448
|
-
const verticesPtr = raw.getVerticesPtr() / 4;
|
|
449
|
-
const vertices = this.oc.HEAPF32.slice(verticesPtr, verticesPtr + verticesSize);
|
|
450
|
-
let normals;
|
|
451
|
-
if (options.skipNormals || normalsSize === 0) {
|
|
452
|
-
normals = new Float32Array(0);
|
|
453
|
-
} else {
|
|
454
|
-
const normalsPtr = raw.getNormalsPtr() / 4;
|
|
455
|
-
normals = this.oc.HEAPF32.slice(normalsPtr, normalsPtr + normalsSize);
|
|
456
|
-
}
|
|
457
|
-
const trianglesPtr = raw.getTrianglesPtr() / 4;
|
|
458
|
-
const triangles = this.oc.HEAPU32.slice(
|
|
459
|
-
trianglesPtr,
|
|
460
|
-
trianglesPtr + trianglesSize
|
|
461
|
-
);
|
|
462
|
-
const faceGroups = [];
|
|
463
|
-
if (faceGroupsSize > 0) {
|
|
464
|
-
const fgPtr = raw.getFaceGroupsPtr() / 4;
|
|
465
|
-
const fgRaw = this.oc.HEAP32.slice(fgPtr, fgPtr + faceGroupsSize);
|
|
466
|
-
for (let i = 0; i < fgRaw.length; i += 3) {
|
|
467
|
-
faceGroups.push({
|
|
468
|
-
start: fgRaw[i],
|
|
469
|
-
count: fgRaw[i + 1],
|
|
470
|
-
faceHash: fgRaw[i + 2]
|
|
471
|
-
});
|
|
472
|
-
}
|
|
473
|
-
}
|
|
474
|
-
raw.delete();
|
|
475
|
-
return { vertices, normals, triangles, faceGroups };
|
|
476
|
-
}
|
|
477
|
-
_meshJS(shape, options) {
|
|
478
|
-
const mesher = new this.oc.BRepMesh_IncrementalMesh_2(
|
|
479
|
-
shape,
|
|
480
|
-
options.tolerance,
|
|
481
|
-
false,
|
|
482
|
-
options.angularTolerance,
|
|
483
|
-
false
|
|
484
|
-
);
|
|
485
|
-
mesher.delete();
|
|
486
|
-
let totalNodes = 0;
|
|
487
|
-
let totalTris = 0;
|
|
488
|
-
const explorer = new this.oc.TopExp_Explorer_2(
|
|
489
|
-
shape,
|
|
490
|
-
this.oc.TopAbs_ShapeEnum.TopAbs_FACE,
|
|
491
|
-
this.oc.TopAbs_ShapeEnum.TopAbs_SHAPE
|
|
492
|
-
);
|
|
493
|
-
while (explorer.More()) {
|
|
494
|
-
const face = this.oc.TopoDS.Face_1(explorer.Current());
|
|
495
|
-
const loc = new this.oc.TopLoc_Location_1();
|
|
496
|
-
const tri = this.oc.BRep_Tool.Triangulation(face, loc, 0);
|
|
497
|
-
if (!tri.IsNull()) {
|
|
498
|
-
const t = tri.get();
|
|
499
|
-
totalNodes += t.NbNodes();
|
|
500
|
-
totalTris += t.NbTriangles();
|
|
501
|
-
}
|
|
502
|
-
loc.delete();
|
|
503
|
-
tri.delete();
|
|
504
|
-
explorer.Next();
|
|
505
|
-
}
|
|
506
|
-
const vertices = new Float32Array(totalNodes * 3);
|
|
507
|
-
const normals = options.skipNormals ? new Float32Array(0) : new Float32Array(totalNodes * 3);
|
|
508
|
-
const triangles = new Uint32Array(totalTris * 3);
|
|
509
|
-
const faceGroups = [];
|
|
510
|
-
let vIdx = 0;
|
|
511
|
-
let nIdx = 0;
|
|
512
|
-
let tIdx = 0;
|
|
513
|
-
explorer.Init(
|
|
514
|
-
shape,
|
|
515
|
-
this.oc.TopAbs_ShapeEnum.TopAbs_FACE,
|
|
516
|
-
this.oc.TopAbs_ShapeEnum.TopAbs_SHAPE
|
|
517
|
-
);
|
|
518
|
-
while (explorer.More()) {
|
|
519
|
-
const face = this.oc.TopoDS.Face_1(explorer.Current());
|
|
520
|
-
const location = new this.oc.TopLoc_Location_1();
|
|
521
|
-
const triangulation = this.oc.BRep_Tool.Triangulation(face, location, 0);
|
|
522
|
-
if (!triangulation.IsNull()) {
|
|
523
|
-
const tri = triangulation.get();
|
|
524
|
-
const transformation = location.Transformation();
|
|
525
|
-
const nbNodes = tri.NbNodes();
|
|
526
|
-
const vertexOffset = vIdx / 3;
|
|
527
|
-
const triStart = tIdx;
|
|
528
|
-
for (let i = 1; i <= nbNodes; i++) {
|
|
529
|
-
const p = tri.Node(i).Transformed(transformation);
|
|
530
|
-
vertices[vIdx++] = p.X();
|
|
531
|
-
vertices[vIdx++] = p.Y();
|
|
532
|
-
vertices[vIdx++] = p.Z();
|
|
533
|
-
p.delete();
|
|
534
|
-
}
|
|
535
|
-
if (!options.skipNormals) {
|
|
536
|
-
const normalsArray = new this.oc.TColgp_Array1OfDir_2(1, nbNodes);
|
|
537
|
-
const pc = new this.oc.Poly_Connect_2(triangulation);
|
|
538
|
-
this.oc.StdPrs_ToolTriangulatedShape.Normal(face, pc, normalsArray);
|
|
539
|
-
for (let i = normalsArray.Lower(); i <= normalsArray.Upper(); i++) {
|
|
540
|
-
const d = normalsArray.Value(i).Transformed(transformation);
|
|
541
|
-
normals[nIdx++] = d.X();
|
|
542
|
-
normals[nIdx++] = d.Y();
|
|
543
|
-
normals[nIdx++] = d.Z();
|
|
544
|
-
d.delete();
|
|
545
|
-
}
|
|
546
|
-
normalsArray.delete();
|
|
547
|
-
pc.delete();
|
|
548
|
-
}
|
|
549
|
-
const orient = face.Orientation_1();
|
|
550
|
-
const isForward = orient === this.oc.TopAbs_Orientation.TopAbs_FORWARD;
|
|
551
|
-
const nbTriangles = tri.NbTriangles();
|
|
552
|
-
for (let nt = 1; nt <= nbTriangles; nt++) {
|
|
553
|
-
const t = tri.Triangle(nt);
|
|
554
|
-
let n1 = t.Value(1);
|
|
555
|
-
let n2 = t.Value(2);
|
|
556
|
-
const n3 = t.Value(3);
|
|
557
|
-
if (!isForward) {
|
|
558
|
-
const tmp = n1;
|
|
559
|
-
n1 = n2;
|
|
560
|
-
n2 = tmp;
|
|
561
|
-
}
|
|
562
|
-
triangles[tIdx++] = n1 - 1 + vertexOffset;
|
|
563
|
-
triangles[tIdx++] = n2 - 1 + vertexOffset;
|
|
564
|
-
triangles[tIdx++] = n3 - 1 + vertexOffset;
|
|
565
|
-
t.delete();
|
|
566
|
-
}
|
|
567
|
-
faceGroups.push({
|
|
568
|
-
start: triStart,
|
|
569
|
-
count: tIdx - triStart,
|
|
570
|
-
faceHash: face.HashCode(HASH_CODE_MAX$1)
|
|
571
|
-
});
|
|
572
|
-
transformation.delete();
|
|
573
|
-
}
|
|
574
|
-
location.delete();
|
|
575
|
-
triangulation.delete();
|
|
576
|
-
explorer.Next();
|
|
577
|
-
}
|
|
578
|
-
explorer.delete();
|
|
579
|
-
return { vertices, normals, triangles, faceGroups };
|
|
1015
|
+
return mesh(this.oc, shape, options);
|
|
580
1016
|
}
|
|
581
1017
|
meshEdges(shape, tolerance, angularTolerance) {
|
|
582
|
-
|
|
583
|
-
return this._meshEdgesBulk(shape, tolerance, angularTolerance);
|
|
584
|
-
}
|
|
585
|
-
return this._meshEdgesJS(shape, tolerance, angularTolerance);
|
|
586
|
-
}
|
|
587
|
-
_meshEdgesBulk(shape, tolerance, angularTolerance) {
|
|
588
|
-
const raw = this.oc.EdgeMeshExtractor.extract(shape, tolerance, angularTolerance);
|
|
589
|
-
const linesSize = raw.getLinesSize();
|
|
590
|
-
const edgeGroupsSize = raw.getEdgeGroupsSize();
|
|
591
|
-
let lines;
|
|
592
|
-
if (linesSize > 0) {
|
|
593
|
-
const linesPtr = raw.getLinesPtr() / 4;
|
|
594
|
-
lines = this.oc.HEAPF32.slice(linesPtr, linesPtr + linesSize);
|
|
595
|
-
} else {
|
|
596
|
-
lines = new Float32Array(0);
|
|
597
|
-
}
|
|
598
|
-
const edgeGroups = [];
|
|
599
|
-
if (edgeGroupsSize > 0) {
|
|
600
|
-
const egPtr = raw.getEdgeGroupsPtr() / 4;
|
|
601
|
-
const egRaw = this.oc.HEAP32.slice(egPtr, egPtr + edgeGroupsSize);
|
|
602
|
-
for (let i = 0; i < egRaw.length; i += 3) {
|
|
603
|
-
edgeGroups.push({
|
|
604
|
-
start: egRaw[i],
|
|
605
|
-
count: egRaw[i + 1],
|
|
606
|
-
edgeHash: egRaw[i + 2]
|
|
607
|
-
});
|
|
608
|
-
}
|
|
609
|
-
}
|
|
610
|
-
raw.delete();
|
|
611
|
-
return { lines, edgeGroups };
|
|
612
|
-
}
|
|
613
|
-
_meshEdgesJS(shape, tolerance, angularTolerance) {
|
|
614
|
-
const mesher = new this.oc.BRepMesh_IncrementalMesh_2(
|
|
615
|
-
shape,
|
|
616
|
-
tolerance,
|
|
617
|
-
false,
|
|
618
|
-
angularTolerance,
|
|
619
|
-
false
|
|
620
|
-
);
|
|
621
|
-
mesher.delete();
|
|
622
|
-
const lines = [];
|
|
623
|
-
const edgeGroups = [];
|
|
624
|
-
const seenHashes = /* @__PURE__ */ new Set();
|
|
625
|
-
const faceExplorer = new this.oc.TopExp_Explorer_2(
|
|
626
|
-
shape,
|
|
627
|
-
this.oc.TopAbs_ShapeEnum.TopAbs_FACE,
|
|
628
|
-
this.oc.TopAbs_ShapeEnum.TopAbs_SHAPE
|
|
629
|
-
);
|
|
630
|
-
while (faceExplorer.More()) {
|
|
631
|
-
const face = this.oc.TopoDS.Face_1(faceExplorer.Current());
|
|
632
|
-
const faceLoc = new this.oc.TopLoc_Location_1();
|
|
633
|
-
const tri = this.oc.BRep_Tool.Triangulation(face, faceLoc, 0);
|
|
634
|
-
if (!tri.IsNull()) {
|
|
635
|
-
const triObj = tri.get();
|
|
636
|
-
const edgeExplorer2 = new this.oc.TopExp_Explorer_2(
|
|
637
|
-
face,
|
|
638
|
-
this.oc.TopAbs_ShapeEnum.TopAbs_EDGE,
|
|
639
|
-
this.oc.TopAbs_ShapeEnum.TopAbs_SHAPE
|
|
640
|
-
);
|
|
641
|
-
while (edgeExplorer2.More()) {
|
|
642
|
-
const edgeShape = edgeExplorer2.Current();
|
|
643
|
-
const edge = this.oc.TopoDS.Edge_1(edgeShape);
|
|
644
|
-
const edgeHash = edge.HashCode(HASH_CODE_MAX$1);
|
|
645
|
-
if (!seenHashes.has(edgeHash)) {
|
|
646
|
-
seenHashes.add(edgeHash);
|
|
647
|
-
const edgeLoc = new this.oc.TopLoc_Location_1();
|
|
648
|
-
const polygon = this.oc.BRep_Tool.PolygonOnTriangulation_1(edge, tri, edgeLoc);
|
|
649
|
-
const edgeNodes = polygon && !polygon.IsNull() ? polygon.get().Nodes() : null;
|
|
650
|
-
if (edgeNodes) {
|
|
651
|
-
const lineStart = lines.length / 3;
|
|
652
|
-
let prevX = 0, prevY = 0, prevZ = 0;
|
|
653
|
-
let hasPrev = false;
|
|
654
|
-
for (let i = edgeNodes.Lower(); i <= edgeNodes.Upper(); i++) {
|
|
655
|
-
const p = triObj.Node(edgeNodes.Value(i)).Transformed(edgeLoc.Transformation());
|
|
656
|
-
const x = p.X(), y = p.Y(), z = p.Z();
|
|
657
|
-
if (hasPrev) {
|
|
658
|
-
lines.push(prevX, prevY, prevZ, x, y, z);
|
|
659
|
-
}
|
|
660
|
-
prevX = x;
|
|
661
|
-
prevY = y;
|
|
662
|
-
prevZ = z;
|
|
663
|
-
hasPrev = true;
|
|
664
|
-
p.delete();
|
|
665
|
-
}
|
|
666
|
-
edgeGroups.push({
|
|
667
|
-
start: lineStart,
|
|
668
|
-
count: lines.length / 3 - lineStart,
|
|
669
|
-
edgeHash
|
|
670
|
-
});
|
|
671
|
-
edgeNodes.delete();
|
|
672
|
-
}
|
|
673
|
-
if (polygon && !polygon.IsNull()) polygon.delete();
|
|
674
|
-
edgeLoc.delete();
|
|
675
|
-
}
|
|
676
|
-
edgeExplorer2.Next();
|
|
677
|
-
}
|
|
678
|
-
edgeExplorer2.delete();
|
|
679
|
-
}
|
|
680
|
-
tri.delete();
|
|
681
|
-
faceLoc.delete();
|
|
682
|
-
faceExplorer.Next();
|
|
683
|
-
}
|
|
684
|
-
faceExplorer.delete();
|
|
685
|
-
const edgeExplorer = new this.oc.TopExp_Explorer_2(
|
|
686
|
-
shape,
|
|
687
|
-
this.oc.TopAbs_ShapeEnum.TopAbs_EDGE,
|
|
688
|
-
this.oc.TopAbs_ShapeEnum.TopAbs_SHAPE
|
|
689
|
-
);
|
|
690
|
-
while (edgeExplorer.More()) {
|
|
691
|
-
const edgeShape = edgeExplorer.Current();
|
|
692
|
-
const edge = this.oc.TopoDS.Edge_1(edgeShape);
|
|
693
|
-
const edgeHash = edge.HashCode(HASH_CODE_MAX$1);
|
|
694
|
-
if (!seenHashes.has(edgeHash)) {
|
|
695
|
-
seenHashes.add(edgeHash);
|
|
696
|
-
const adaptor = new this.oc.BRepAdaptor_Curve_2(edge);
|
|
697
|
-
const tangDef = new this.oc.GCPnts_TangentialDeflection_2(
|
|
698
|
-
adaptor,
|
|
699
|
-
tolerance,
|
|
700
|
-
angularTolerance,
|
|
701
|
-
2,
|
|
702
|
-
1e-9,
|
|
703
|
-
1e-7
|
|
704
|
-
);
|
|
705
|
-
const lineStart = lines.length / 3;
|
|
706
|
-
let prevX = 0, prevY = 0, prevZ = 0;
|
|
707
|
-
let hasPrev = false;
|
|
708
|
-
for (let j = 1; j <= tangDef.NbPoints(); j++) {
|
|
709
|
-
const p = tangDef.Value(j);
|
|
710
|
-
const x = p.X(), y = p.Y(), z = p.Z();
|
|
711
|
-
if (hasPrev) {
|
|
712
|
-
lines.push(prevX, prevY, prevZ, x, y, z);
|
|
713
|
-
}
|
|
714
|
-
prevX = x;
|
|
715
|
-
prevY = y;
|
|
716
|
-
prevZ = z;
|
|
717
|
-
hasPrev = true;
|
|
718
|
-
p.delete();
|
|
719
|
-
}
|
|
720
|
-
edgeGroups.push({
|
|
721
|
-
start: lineStart,
|
|
722
|
-
count: lines.length / 3 - lineStart,
|
|
723
|
-
edgeHash
|
|
724
|
-
});
|
|
725
|
-
tangDef.delete();
|
|
726
|
-
adaptor.delete();
|
|
727
|
-
}
|
|
728
|
-
edgeExplorer.Next();
|
|
729
|
-
}
|
|
730
|
-
edgeExplorer.delete();
|
|
731
|
-
return { lines: new Float32Array(lines), edgeGroups };
|
|
1018
|
+
return meshEdges(this.oc, shape, tolerance, angularTolerance);
|
|
732
1019
|
}
|
|
733
|
-
// --- File I/O ---
|
|
1020
|
+
// --- File I/O (delegates to ioOps.ts) ---
|
|
734
1021
|
exportSTEP(shapes) {
|
|
735
|
-
|
|
736
|
-
this.oc.Interface_Static.SetIVal("write.step.schema", 5);
|
|
737
|
-
writer.Model(true).delete();
|
|
738
|
-
const progress = new this.oc.Message_ProgressRange_1();
|
|
739
|
-
for (const shape of shapes) {
|
|
740
|
-
writer.Transfer(shape, this.oc.STEPControl_StepModelType.STEPControl_AsIs, true, progress);
|
|
741
|
-
}
|
|
742
|
-
const filename = uniqueIOFilename("_export", "step");
|
|
743
|
-
const done = writer.Write(filename);
|
|
744
|
-
writer.delete();
|
|
745
|
-
progress.delete();
|
|
746
|
-
if (done === this.oc.IFSelect_ReturnStatus.IFSelect_RetDone) {
|
|
747
|
-
const file = this.oc.FS.readFile("/" + filename);
|
|
748
|
-
this.oc.FS.unlink("/" + filename);
|
|
749
|
-
return new TextDecoder().decode(file);
|
|
750
|
-
}
|
|
751
|
-
throw new Error("STEP export failed: writer did not complete successfully");
|
|
1022
|
+
return exportSTEP$2(this.oc, shapes);
|
|
752
1023
|
}
|
|
753
1024
|
exportSTL(shape, binary = false) {
|
|
754
|
-
|
|
755
|
-
const done = this.oc.StlAPI.Write(shape, filename, !binary);
|
|
756
|
-
if (done) {
|
|
757
|
-
const file = this.oc.FS.readFile("/" + filename);
|
|
758
|
-
this.oc.FS.unlink("/" + filename);
|
|
759
|
-
if (binary) return file.buffer;
|
|
760
|
-
return new TextDecoder().decode(file);
|
|
761
|
-
}
|
|
762
|
-
throw new Error("STL export failed: StlAPI.Write returned false");
|
|
1025
|
+
return exportSTL$1(this.oc, shape, binary);
|
|
763
1026
|
}
|
|
764
1027
|
importSTEP(data) {
|
|
765
|
-
|
|
766
|
-
const buffer = typeof data === "string" ? new TextEncoder().encode(data) : new Uint8Array(data);
|
|
767
|
-
this.oc.FS.writeFile("/" + filename, buffer);
|
|
768
|
-
const reader = new this.oc.STEPControl_Reader_1();
|
|
769
|
-
if (reader.ReadFile(filename)) {
|
|
770
|
-
this.oc.FS.unlink("/" + filename);
|
|
771
|
-
const progress = new this.oc.Message_ProgressRange_1();
|
|
772
|
-
reader.TransferRoots(progress);
|
|
773
|
-
progress.delete();
|
|
774
|
-
const shape = reader.OneShape();
|
|
775
|
-
reader.delete();
|
|
776
|
-
return [shape];
|
|
777
|
-
}
|
|
778
|
-
this.oc.FS.unlink("/" + filename);
|
|
779
|
-
reader.delete();
|
|
780
|
-
throw new Error("Failed to import STEP file: reader could not parse the input data");
|
|
1028
|
+
return importSTEP$2(this.oc, data);
|
|
781
1029
|
}
|
|
782
1030
|
importSTL(data) {
|
|
783
|
-
|
|
784
|
-
const buffer = typeof data === "string" ? new TextEncoder().encode(data) : new Uint8Array(data);
|
|
785
|
-
this.oc.FS.writeFile("/" + filename, buffer);
|
|
786
|
-
const reader = new this.oc.StlAPI_Reader();
|
|
787
|
-
const readShape = new this.oc.TopoDS_Shell();
|
|
788
|
-
if (reader.Read(readShape, filename)) {
|
|
789
|
-
this.oc.FS.unlink("/" + filename);
|
|
790
|
-
const upgrader = new this.oc.ShapeUpgrade_UnifySameDomain_2(readShape, true, true, false);
|
|
791
|
-
upgrader.Build();
|
|
792
|
-
const upgraded = upgrader.Shape();
|
|
793
|
-
const solidBuilder = new this.oc.BRepBuilderAPI_MakeSolid_1();
|
|
794
|
-
solidBuilder.Add(this.oc.TopoDS.Shell_1(upgraded));
|
|
795
|
-
const solid = solidBuilder.Solid();
|
|
796
|
-
readShape.delete();
|
|
797
|
-
upgrader.delete();
|
|
798
|
-
solidBuilder.delete();
|
|
799
|
-
reader.delete();
|
|
800
|
-
return solid;
|
|
801
|
-
}
|
|
802
|
-
this.oc.FS.unlink("/" + filename);
|
|
803
|
-
readShape.delete();
|
|
804
|
-
reader.delete();
|
|
805
|
-
throw new Error("Failed to import STL file: reader could not parse the input data");
|
|
1031
|
+
return importSTL$2(this.oc, data);
|
|
806
1032
|
}
|
|
807
|
-
// --- Measurement ---
|
|
1033
|
+
// --- Measurement (delegates to measureOps.ts) ---
|
|
808
1034
|
volume(shape) {
|
|
809
|
-
|
|
810
|
-
this.oc.BRepGProp.VolumeProperties_1(shape, props, true, false, false);
|
|
811
|
-
const vol = props.Mass();
|
|
812
|
-
props.delete();
|
|
813
|
-
return vol;
|
|
1035
|
+
return volume(this.oc, shape);
|
|
814
1036
|
}
|
|
815
1037
|
area(shape) {
|
|
816
|
-
|
|
817
|
-
this.oc.BRepGProp.SurfaceProperties_2(shape, props, 1e-7, true);
|
|
818
|
-
const a = props.Mass();
|
|
819
|
-
props.delete();
|
|
820
|
-
return a;
|
|
1038
|
+
return area(this.oc, shape);
|
|
821
1039
|
}
|
|
822
1040
|
length(shape) {
|
|
823
|
-
|
|
824
|
-
this.oc.BRepGProp.LinearProperties(shape, props, true, false);
|
|
825
|
-
const len = props.Mass();
|
|
826
|
-
props.delete();
|
|
827
|
-
return len;
|
|
1041
|
+
return length(this.oc, shape);
|
|
828
1042
|
}
|
|
829
1043
|
centerOfMass(shape) {
|
|
830
|
-
|
|
831
|
-
this.oc.BRepGProp.VolumeProperties_1(shape, props, true, false, false);
|
|
832
|
-
const center = props.CentreOfMass();
|
|
833
|
-
const result = [center.X(), center.Y(), center.Z()];
|
|
834
|
-
center.delete();
|
|
835
|
-
props.delete();
|
|
836
|
-
return result;
|
|
1044
|
+
return centerOfMass(this.oc, shape);
|
|
837
1045
|
}
|
|
838
1046
|
boundingBox(shape) {
|
|
839
|
-
|
|
840
|
-
this.oc.BRepBndLib.Add(shape, box, true);
|
|
841
|
-
const xMin = { current: 0 };
|
|
842
|
-
const yMin = { current: 0 };
|
|
843
|
-
const zMin = { current: 0 };
|
|
844
|
-
const xMax = { current: 0 };
|
|
845
|
-
const yMax = { current: 0 };
|
|
846
|
-
const zMax = { current: 0 };
|
|
847
|
-
box.Get(xMin, yMin, zMin, xMax, yMax, zMax);
|
|
848
|
-
box.delete();
|
|
849
|
-
return {
|
|
850
|
-
min: [xMin.current, yMin.current, zMin.current],
|
|
851
|
-
max: [xMax.current, yMax.current, zMax.current]
|
|
852
|
-
};
|
|
1047
|
+
return boundingBox(this.oc, shape);
|
|
853
1048
|
}
|
|
854
|
-
// --- Topology iteration ---
|
|
1049
|
+
// --- Topology iteration (delegates to topologyOps.ts) ---
|
|
855
1050
|
iterShapes(shape, type) {
|
|
856
|
-
|
|
857
|
-
return this._iterShapesBulk(shape, type);
|
|
858
|
-
}
|
|
859
|
-
return this._iterShapesJS(shape, type);
|
|
860
|
-
}
|
|
861
|
-
_iterShapesBulk(shape, type) {
|
|
862
|
-
const typeEnumMap = {
|
|
863
|
-
vertex: 7,
|
|
864
|
-
edge: 6,
|
|
865
|
-
wire: 5,
|
|
866
|
-
face: 4,
|
|
867
|
-
shell: 3,
|
|
868
|
-
solid: 2,
|
|
869
|
-
compsolid: 1,
|
|
870
|
-
compound: 0
|
|
871
|
-
};
|
|
872
|
-
const raw = this.oc.TopologyExtractor.extract(shape, typeEnumMap[type]);
|
|
873
|
-
const count = raw.getShapesCount();
|
|
874
|
-
const result = [];
|
|
875
|
-
for (let i = 0; i < count; i++) {
|
|
876
|
-
result.push(raw.getShape(i));
|
|
877
|
-
}
|
|
878
|
-
raw.delete();
|
|
879
|
-
return result;
|
|
880
|
-
}
|
|
881
|
-
_iterShapesJS(shape, type) {
|
|
882
|
-
const typeMap = {
|
|
883
|
-
vertex: this.oc.TopAbs_ShapeEnum.TopAbs_VERTEX,
|
|
884
|
-
edge: this.oc.TopAbs_ShapeEnum.TopAbs_EDGE,
|
|
885
|
-
wire: this.oc.TopAbs_ShapeEnum.TopAbs_WIRE,
|
|
886
|
-
face: this.oc.TopAbs_ShapeEnum.TopAbs_FACE,
|
|
887
|
-
shell: this.oc.TopAbs_ShapeEnum.TopAbs_SHELL,
|
|
888
|
-
solid: this.oc.TopAbs_ShapeEnum.TopAbs_SOLID,
|
|
889
|
-
compsolid: this.oc.TopAbs_ShapeEnum.TopAbs_COMPSOLID,
|
|
890
|
-
compound: this.oc.TopAbs_ShapeEnum.TopAbs_COMPOUND
|
|
891
|
-
};
|
|
892
|
-
const explorer = new this.oc.TopExp_Explorer_2(
|
|
893
|
-
shape,
|
|
894
|
-
typeMap[type],
|
|
895
|
-
this.oc.TopAbs_ShapeEnum.TopAbs_SHAPE
|
|
896
|
-
);
|
|
897
|
-
const result = [];
|
|
898
|
-
const seen = /* @__PURE__ */ new Map();
|
|
899
|
-
while (explorer.More()) {
|
|
900
|
-
const item = explorer.Current();
|
|
901
|
-
const hash = item.HashCode(HASH_CODE_MAX$1);
|
|
902
|
-
const bucket = seen.get(hash);
|
|
903
|
-
if (!bucket) {
|
|
904
|
-
seen.set(hash, [item]);
|
|
905
|
-
result.push(item);
|
|
906
|
-
} else if (!bucket.some((s) => s.IsSame(item))) {
|
|
907
|
-
bucket.push(item);
|
|
908
|
-
result.push(item);
|
|
909
|
-
}
|
|
910
|
-
explorer.Next();
|
|
911
|
-
}
|
|
912
|
-
explorer.delete();
|
|
913
|
-
return result;
|
|
914
|
-
}
|
|
915
|
-
_shapeTypeMap = null;
|
|
916
|
-
_getShapeTypeMap() {
|
|
917
|
-
if (!this._shapeTypeMap) {
|
|
918
|
-
const ta = this.oc.TopAbs_ShapeEnum;
|
|
919
|
-
this._shapeTypeMap = /* @__PURE__ */ new Map([
|
|
920
|
-
[ta.TopAbs_VERTEX, "vertex"],
|
|
921
|
-
[ta.TopAbs_EDGE, "edge"],
|
|
922
|
-
[ta.TopAbs_WIRE, "wire"],
|
|
923
|
-
[ta.TopAbs_FACE, "face"],
|
|
924
|
-
[ta.TopAbs_SHELL, "shell"],
|
|
925
|
-
[ta.TopAbs_SOLID, "solid"],
|
|
926
|
-
[ta.TopAbs_COMPSOLID, "compsolid"],
|
|
927
|
-
[ta.TopAbs_COMPOUND, "compound"]
|
|
928
|
-
]);
|
|
929
|
-
}
|
|
930
|
-
return this._shapeTypeMap;
|
|
1051
|
+
return iterShapes(this.oc, shape, type);
|
|
931
1052
|
}
|
|
932
1053
|
shapeType(shape) {
|
|
933
|
-
|
|
934
|
-
const result = this._getShapeTypeMap().get(shape.ShapeType());
|
|
935
|
-
if (!result) throw new Error(`Unknown shape type enum value: ${shape.ShapeType()}`);
|
|
936
|
-
return result;
|
|
1054
|
+
return shapeType$1(this.oc, shape);
|
|
937
1055
|
}
|
|
938
1056
|
isSame(a, b) {
|
|
939
|
-
return a
|
|
1057
|
+
return isSame(a, b);
|
|
940
1058
|
}
|
|
941
1059
|
isEqual(a, b) {
|
|
942
|
-
return a
|
|
1060
|
+
return isEqual(a, b);
|
|
943
1061
|
}
|
|
944
1062
|
// --- Simplification ---
|
|
945
1063
|
simplify(shape) {
|
|
946
|
-
|
|
947
|
-
upgrader.Build();
|
|
948
|
-
const result = upgrader.Shape();
|
|
949
|
-
upgrader.delete();
|
|
950
|
-
return result;
|
|
1064
|
+
return simplify(this.oc, shape);
|
|
951
1065
|
}
|
|
952
1066
|
// --- Private helpers ---
|
|
953
|
-
_buildCompound(shapes) {
|
|
954
|
-
const builder = new this.oc.TopoDS_Builder();
|
|
955
|
-
const compound = new this.oc.TopoDS_Compound();
|
|
956
|
-
builder.MakeCompound(compound);
|
|
957
|
-
for (const s of shapes) {
|
|
958
|
-
builder.Add(compound, s);
|
|
959
|
-
}
|
|
960
|
-
builder.delete();
|
|
961
|
-
return compound;
|
|
962
|
-
}
|
|
963
|
-
_applyGlue(op, optimisation) {
|
|
964
|
-
if (optimisation === "commonFace") {
|
|
965
|
-
op.SetGlue(this.oc.BOPAlgo_GlueEnum.BOPAlgo_GlueShift);
|
|
966
|
-
}
|
|
967
|
-
if (optimisation === "sameFace") {
|
|
968
|
-
op.SetGlue(this.oc.BOPAlgo_GlueEnum.BOPAlgo_GlueFull);
|
|
969
|
-
}
|
|
970
|
-
}
|
|
971
1067
|
}
|
|
972
1068
|
let _kernel = null;
|
|
973
1069
|
function getKernel() {
|
|
@@ -1589,9 +1685,9 @@ function asDir(coords) {
|
|
|
1589
1685
|
return dir;
|
|
1590
1686
|
}
|
|
1591
1687
|
class Transformation extends WrappingObj {
|
|
1592
|
-
constructor(
|
|
1688
|
+
constructor(transform2) {
|
|
1593
1689
|
const oc = getKernel().oc;
|
|
1594
|
-
super(
|
|
1690
|
+
super(transform2 || new oc.gp_Trsf_1());
|
|
1595
1691
|
}
|
|
1596
1692
|
translate(xDistOrVector, yDist = 0, zDist = 0) {
|
|
1597
1693
|
const translation = new Vector(
|
|
@@ -1999,7 +2095,7 @@ function meshShape(shape, {
|
|
|
1999
2095
|
angularTolerance,
|
|
2000
2096
|
skipNormals
|
|
2001
2097
|
});
|
|
2002
|
-
const
|
|
2098
|
+
const mesh2 = {
|
|
2003
2099
|
vertices: result.vertices,
|
|
2004
2100
|
normals: result.normals,
|
|
2005
2101
|
triangles: result.triangles,
|
|
@@ -2010,9 +2106,9 @@ function meshShape(shape, {
|
|
|
2010
2106
|
}))
|
|
2011
2107
|
};
|
|
2012
2108
|
if (cache) {
|
|
2013
|
-
setMeshForShape(shape.wrapped, cacheKey,
|
|
2109
|
+
setMeshForShape(shape.wrapped, cacheKey, mesh2);
|
|
2014
2110
|
}
|
|
2015
|
-
return
|
|
2111
|
+
return mesh2;
|
|
2016
2112
|
}
|
|
2017
2113
|
function meshShapeEdges(shape, { tolerance = 1e-3, angularTolerance = 0.1, cache = true } = {}) {
|
|
2018
2114
|
const cacheKey = buildEdgeMeshCacheKey(0, tolerance, angularTolerance);
|
|
@@ -2205,6 +2301,73 @@ function deserializeShape(data) {
|
|
|
2205
2301
|
const oc = getKernel().oc;
|
|
2206
2302
|
return cast(oc.BRepToolsWrapper.Read(data));
|
|
2207
2303
|
}
|
|
2304
|
+
function isShape3DInternal(shape) {
|
|
2305
|
+
const name = shape.constructor.name;
|
|
2306
|
+
return name === "Shell" || name === "Solid" || name === "CompSolid" || name === "Compound";
|
|
2307
|
+
}
|
|
2308
|
+
function buildCompoundOc(shapes) {
|
|
2309
|
+
const oc = getKernel().oc;
|
|
2310
|
+
const builder = new oc.TopoDS_Builder();
|
|
2311
|
+
const compound = new oc.TopoDS_Compound();
|
|
2312
|
+
builder.MakeCompound(compound);
|
|
2313
|
+
for (const s of shapes) {
|
|
2314
|
+
builder.Add(compound, s);
|
|
2315
|
+
}
|
|
2316
|
+
builder.delete();
|
|
2317
|
+
return compound;
|
|
2318
|
+
}
|
|
2319
|
+
function buildCompound$1(shapes) {
|
|
2320
|
+
return buildCompoundOc(shapes.map((s) => s.wrapped));
|
|
2321
|
+
}
|
|
2322
|
+
function applyGlue$1(op, optimisation) {
|
|
2323
|
+
const oc = getKernel().oc;
|
|
2324
|
+
if (optimisation === "commonFace") {
|
|
2325
|
+
op.SetGlue(oc.BOPAlgo_GlueEnum.BOPAlgo_GlueShift);
|
|
2326
|
+
}
|
|
2327
|
+
if (optimisation === "sameFace") {
|
|
2328
|
+
op.SetGlue(oc.BOPAlgo_GlueEnum.BOPAlgo_GlueFull);
|
|
2329
|
+
}
|
|
2330
|
+
}
|
|
2331
|
+
function fuseAll$2(shapes, { optimisation = "none", simplify: simplify2 = false, strategy = "native" } = {}) {
|
|
2332
|
+
if (shapes.length === 0)
|
|
2333
|
+
return err(validationError("FUSE_ALL_EMPTY", "fuseAll requires at least one shape"));
|
|
2334
|
+
if (shapes.length === 1) return ok(shapes[0]);
|
|
2335
|
+
if (strategy === "native") {
|
|
2336
|
+
const result = getKernel().fuseAll(
|
|
2337
|
+
shapes.map((s) => s.wrapped),
|
|
2338
|
+
{ optimisation, simplify: simplify2, strategy }
|
|
2339
|
+
);
|
|
2340
|
+
return andThen(cast(result), (newShape) => {
|
|
2341
|
+
if (!isShape3DInternal(newShape))
|
|
2342
|
+
return err(typeCastError("FUSE_ALL_NOT_3D", "fuseAll did not produce a 3D shape"));
|
|
2343
|
+
return ok(newShape);
|
|
2344
|
+
});
|
|
2345
|
+
}
|
|
2346
|
+
const mid = Math.ceil(shapes.length / 2);
|
|
2347
|
+
const leftResult = fuseAll$2(shapes.slice(0, mid), { optimisation, simplify: false, strategy });
|
|
2348
|
+
if (isErr(leftResult)) return leftResult;
|
|
2349
|
+
const rightResult = fuseAll$2(shapes.slice(mid), { optimisation, simplify: false, strategy });
|
|
2350
|
+
if (isErr(rightResult)) return rightResult;
|
|
2351
|
+
return leftResult.value.fuse(rightResult.value, { optimisation, simplify: simplify2 });
|
|
2352
|
+
}
|
|
2353
|
+
function cutAll$1(base, tools, { optimisation = "none", simplify: simplify2 = false } = {}) {
|
|
2354
|
+
if (tools.length === 0) return ok(base);
|
|
2355
|
+
const oc = getKernel().oc;
|
|
2356
|
+
const r = gcWithScope();
|
|
2357
|
+
const toolCompound = r(buildCompound$1(tools));
|
|
2358
|
+
const progress = r(new oc.Message_ProgressRange_1());
|
|
2359
|
+
const cutOp = r(new oc.BRepAlgoAPI_Cut_3(base.wrapped, toolCompound, progress));
|
|
2360
|
+
applyGlue$1(cutOp, optimisation);
|
|
2361
|
+
cutOp.Build(progress);
|
|
2362
|
+
if (simplify2) {
|
|
2363
|
+
cutOp.SimplifyResult(true, true, 1e-3);
|
|
2364
|
+
}
|
|
2365
|
+
return andThen(cast(cutOp.Shape()), (newShape) => {
|
|
2366
|
+
if (!isShape3DInternal(newShape))
|
|
2367
|
+
return err(typeCastError("CUT_ALL_NOT_3D", "cutAll did not produce a 3D shape"));
|
|
2368
|
+
return ok(newShape);
|
|
2369
|
+
});
|
|
2370
|
+
}
|
|
2208
2371
|
let _queryModule = null;
|
|
2209
2372
|
function getQueryModule() {
|
|
2210
2373
|
if (!_queryModule) {
|
|
@@ -2585,9 +2748,9 @@ class _1DShape extends Shape {
|
|
|
2585
2748
|
get length() {
|
|
2586
2749
|
const properties = new this.oc.GProp_GProps_1();
|
|
2587
2750
|
this.oc.BRepGProp.LinearProperties(this.wrapped, properties, true, false);
|
|
2588
|
-
const
|
|
2751
|
+
const length2 = properties.Mass();
|
|
2589
2752
|
properties.delete();
|
|
2590
|
-
return
|
|
2753
|
+
return length2;
|
|
2591
2754
|
}
|
|
2592
2755
|
get orientation() {
|
|
2593
2756
|
const orient = this.wrapped.Orientation_1();
|
|
@@ -2818,13 +2981,13 @@ class _3DShape extends Shape {
|
|
|
2818
2981
|
*
|
|
2819
2982
|
* @category Shape Modifications
|
|
2820
2983
|
*/
|
|
2821
|
-
fuse(other, { optimisation = "none", simplify = false } = {}) {
|
|
2984
|
+
fuse(other, { optimisation = "none", simplify: simplify2 = false } = {}) {
|
|
2822
2985
|
const r = gcWithScope();
|
|
2823
2986
|
const progress = r(new this.oc.Message_ProgressRange_1());
|
|
2824
2987
|
const newBody = r(new this.oc.BRepAlgoAPI_Fuse_3(this.wrapped, other.wrapped, progress));
|
|
2825
2988
|
applyGlue$1(newBody, optimisation);
|
|
2826
2989
|
newBody.Build(progress);
|
|
2827
|
-
if (
|
|
2990
|
+
if (simplify2) {
|
|
2828
2991
|
newBody.SimplifyResult(true, true, 1e-3);
|
|
2829
2992
|
}
|
|
2830
2993
|
return andThen(cast(newBody.Shape()), (newShape) => {
|
|
@@ -2838,13 +3001,13 @@ class _3DShape extends Shape {
|
|
|
2838
3001
|
*
|
|
2839
3002
|
* @category Shape Modifications
|
|
2840
3003
|
*/
|
|
2841
|
-
cut(tool, { optimisation = "none", simplify = false } = {}) {
|
|
3004
|
+
cut(tool, { optimisation = "none", simplify: simplify2 = false } = {}) {
|
|
2842
3005
|
const r = gcWithScope();
|
|
2843
3006
|
const progress = r(new this.oc.Message_ProgressRange_1());
|
|
2844
3007
|
const cutter = r(new this.oc.BRepAlgoAPI_Cut_3(this.wrapped, tool.wrapped, progress));
|
|
2845
3008
|
applyGlue$1(cutter, optimisation);
|
|
2846
3009
|
cutter.Build(progress);
|
|
2847
|
-
if (
|
|
3010
|
+
if (simplify2) {
|
|
2848
3011
|
cutter.SimplifyResult(true, true, 1e-3);
|
|
2849
3012
|
}
|
|
2850
3013
|
return andThen(cast(cutter.Shape()), (newShape) => {
|
|
@@ -2858,12 +3021,12 @@ class _3DShape extends Shape {
|
|
|
2858
3021
|
*
|
|
2859
3022
|
* @category Shape Modifications
|
|
2860
3023
|
*/
|
|
2861
|
-
intersect(tool, { simplify = false } = {}) {
|
|
3024
|
+
intersect(tool, { simplify: simplify2 = false } = {}) {
|
|
2862
3025
|
const r = gcWithScope();
|
|
2863
3026
|
const progress = r(new this.oc.Message_ProgressRange_1());
|
|
2864
3027
|
const intersector = r(new this.oc.BRepAlgoAPI_Common_3(this.wrapped, tool.wrapped, progress));
|
|
2865
3028
|
intersector.Build(progress);
|
|
2866
|
-
if (
|
|
3029
|
+
if (simplify2) {
|
|
2867
3030
|
intersector.SimplifyResult(true, true, 1e-3);
|
|
2868
3031
|
}
|
|
2869
3032
|
return andThen(cast(intersector.Shape()), (newShape) => {
|
|
@@ -3042,69 +3205,6 @@ class Compound extends _3DShape {
|
|
|
3042
3205
|
function isShape3D$1(shape) {
|
|
3043
3206
|
return shape instanceof Shell || shape instanceof Solid || shape instanceof CompSolid || shape instanceof Compound;
|
|
3044
3207
|
}
|
|
3045
|
-
function buildCompoundOc(shapes) {
|
|
3046
|
-
const oc = getKernel().oc;
|
|
3047
|
-
const builder = new oc.TopoDS_Builder();
|
|
3048
|
-
const compound = new oc.TopoDS_Compound();
|
|
3049
|
-
builder.MakeCompound(compound);
|
|
3050
|
-
for (const s of shapes) {
|
|
3051
|
-
builder.Add(compound, s);
|
|
3052
|
-
}
|
|
3053
|
-
builder.delete();
|
|
3054
|
-
return compound;
|
|
3055
|
-
}
|
|
3056
|
-
function buildCompound$1(shapes) {
|
|
3057
|
-
return buildCompoundOc(shapes.map((s) => s.wrapped));
|
|
3058
|
-
}
|
|
3059
|
-
function applyGlue$1(op, optimisation) {
|
|
3060
|
-
const oc = getKernel().oc;
|
|
3061
|
-
if (optimisation === "commonFace") {
|
|
3062
|
-
op.SetGlue(oc.BOPAlgo_GlueEnum.BOPAlgo_GlueShift);
|
|
3063
|
-
}
|
|
3064
|
-
if (optimisation === "sameFace") {
|
|
3065
|
-
op.SetGlue(oc.BOPAlgo_GlueEnum.BOPAlgo_GlueFull);
|
|
3066
|
-
}
|
|
3067
|
-
}
|
|
3068
|
-
function fuseAll$2(shapes, { optimisation = "none", simplify = false, strategy = "native" } = {}) {
|
|
3069
|
-
if (shapes.length === 0)
|
|
3070
|
-
return err(validationError("FUSE_ALL_EMPTY", "fuseAll requires at least one shape"));
|
|
3071
|
-
if (shapes.length === 1) return ok(shapes[0]);
|
|
3072
|
-
if (strategy === "native") {
|
|
3073
|
-
const result = getKernel().fuseAll(
|
|
3074
|
-
shapes.map((s) => s.wrapped),
|
|
3075
|
-
{ optimisation, simplify, strategy }
|
|
3076
|
-
);
|
|
3077
|
-
return andThen(cast(result), (newShape) => {
|
|
3078
|
-
if (!isShape3D$1(newShape))
|
|
3079
|
-
return err(typeCastError("FUSE_ALL_NOT_3D", "fuseAll did not produce a 3D shape"));
|
|
3080
|
-
return ok(newShape);
|
|
3081
|
-
});
|
|
3082
|
-
}
|
|
3083
|
-
const mid = Math.ceil(shapes.length / 2);
|
|
3084
|
-
const leftResult = fuseAll$2(shapes.slice(0, mid), { optimisation, simplify: false, strategy });
|
|
3085
|
-
if (isErr(leftResult)) return leftResult;
|
|
3086
|
-
const rightResult = fuseAll$2(shapes.slice(mid), { optimisation, simplify: false, strategy });
|
|
3087
|
-
if (isErr(rightResult)) return rightResult;
|
|
3088
|
-
return leftResult.value.fuse(rightResult.value, { optimisation, simplify });
|
|
3089
|
-
}
|
|
3090
|
-
function cutAll$1(base, tools, { optimisation = "none", simplify = false } = {}) {
|
|
3091
|
-
if (tools.length === 0) return ok(base);
|
|
3092
|
-
const oc = getKernel().oc;
|
|
3093
|
-
const r = gcWithScope();
|
|
3094
|
-
const toolCompound = r(buildCompound$1(tools));
|
|
3095
|
-
const progress = r(new oc.Message_ProgressRange_1());
|
|
3096
|
-
const cutOp = r(new oc.BRepAlgoAPI_Cut_3(base.wrapped, toolCompound, progress));
|
|
3097
|
-
applyGlue$1(cutOp, optimisation);
|
|
3098
|
-
cutOp.Build(progress);
|
|
3099
|
-
if (simplify) {
|
|
3100
|
-
cutOp.SimplifyResult(true, true, 1e-3);
|
|
3101
|
-
}
|
|
3102
|
-
return andThen(cast(cutOp.Shape()), (newShape) => {
|
|
3103
|
-
if (!isShape3D$1(newShape))
|
|
3104
|
-
return err(typeCastError("CUT_ALL_NOT_3D", "cutAll did not produce a 3D shape"));
|
|
3105
|
-
return ok(newShape);
|
|
3106
|
-
});
|
|
3107
|
-
}
|
|
3108
3208
|
const shapesModule = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
|
|
3109
3209
|
__proto__: null,
|
|
3110
3210
|
CompSolid,
|
|
@@ -3411,15 +3511,15 @@ class EllipsoidTransform extends WrappingObj {
|
|
|
3411
3511
|
const ax1 = r(makeAx1([0, 0, 0], [0, 1, 0]));
|
|
3412
3512
|
const ax2 = r(makeAx1([0, 0, 0], [0, 0, 1]));
|
|
3413
3513
|
const ax3 = r(makeAx1([0, 0, 0], [1, 0, 0]));
|
|
3414
|
-
const
|
|
3415
|
-
|
|
3514
|
+
const transform2 = new oc.gp_GTrsf_1();
|
|
3515
|
+
transform2.SetAffinity_1(ax1, xzRatio);
|
|
3416
3516
|
const xy = r(new oc.gp_GTrsf_1());
|
|
3417
3517
|
xy.SetAffinity_1(ax2, xyRatio);
|
|
3418
3518
|
const yz = r(new oc.gp_GTrsf_1());
|
|
3419
3519
|
yz.SetAffinity_1(ax3, yzRatio);
|
|
3420
|
-
|
|
3421
|
-
|
|
3422
|
-
super(
|
|
3520
|
+
transform2.Multiply(xy);
|
|
3521
|
+
transform2.Multiply(yz);
|
|
3522
|
+
super(transform2);
|
|
3423
3523
|
}
|
|
3424
3524
|
applyToPoint(p) {
|
|
3425
3525
|
const oc = getKernel().oc;
|
|
@@ -3450,18 +3550,18 @@ const makeEllipsoid = (aLength, bLength, cLength) => {
|
|
|
3450
3550
|
const baseSurface = oc.GeomConvert.SurfaceToBSplineSurface(sphericalSurface.UReversed()).get();
|
|
3451
3551
|
try {
|
|
3452
3552
|
const poles = convertToJSArray(baseSurface.Poles_2());
|
|
3453
|
-
const
|
|
3553
|
+
const transform2 = new EllipsoidTransform(aLength, bLength, cLength);
|
|
3454
3554
|
poles.forEach((columns, rowIdx) => {
|
|
3455
3555
|
columns.forEach((value, colIdx) => {
|
|
3456
|
-
const newPoint =
|
|
3556
|
+
const newPoint = transform2.applyToPoint(value);
|
|
3457
3557
|
baseSurface.SetPole_1(rowIdx + 1, colIdx + 1, newPoint);
|
|
3458
3558
|
newPoint.delete();
|
|
3459
3559
|
});
|
|
3460
3560
|
});
|
|
3461
|
-
const
|
|
3561
|
+
const shell2 = unwrap(
|
|
3462
3562
|
cast(r(new oc.BRepBuilderAPI_MakeShell_2(baseSurface.UReversed(), false)).Shell())
|
|
3463
3563
|
);
|
|
3464
|
-
return unwrap(makeSolid([
|
|
3564
|
+
return unwrap(makeSolid([shell2]));
|
|
3465
3565
|
} finally {
|
|
3466
3566
|
baseSurface.delete();
|
|
3467
3567
|
}
|
|
@@ -3537,16 +3637,16 @@ function _weld(facesOrShells) {
|
|
|
3537
3637
|
return unwrap(cast(unwrap(downcast(shellBuilder.SewedShape()))));
|
|
3538
3638
|
}
|
|
3539
3639
|
function weldShellsAndFaces(facesOrShells, ignoreType = false) {
|
|
3540
|
-
const
|
|
3541
|
-
if (!ignoreType && !(
|
|
3640
|
+
const shell2 = _weld(facesOrShells);
|
|
3641
|
+
if (!ignoreType && !(shell2 instanceof Shell))
|
|
3542
3642
|
return err(typeCastError("WELD_NOT_SHELL", "Could not make a shell from faces and shells"));
|
|
3543
|
-
return ok(
|
|
3643
|
+
return ok(shell2);
|
|
3544
3644
|
}
|
|
3545
3645
|
function makeSolid(facesOrShells) {
|
|
3546
3646
|
const r = gcWithScope();
|
|
3547
3647
|
const oc = getKernel().oc;
|
|
3548
|
-
const
|
|
3549
|
-
return andThen(cast(r(new oc.ShapeFix_Solid_1()).SolidFromShell(
|
|
3648
|
+
const shell2 = _weld(facesOrShells);
|
|
3649
|
+
return andThen(cast(r(new oc.ShapeFix_Solid_1()).SolidFromShell(shell2.wrapped)), (solid) => {
|
|
3550
3650
|
if (!(solid instanceof Solid))
|
|
3551
3651
|
return err(typeCastError("SOLID_BUILD_FAILED", "Could not make a solid of faces and shells"));
|
|
3552
3652
|
return ok(solid);
|
|
@@ -4099,43 +4199,43 @@ function castToShape3D(shape, errorCode, errorMsg) {
|
|
|
4099
4199
|
}
|
|
4100
4200
|
return ok(wrapped);
|
|
4101
4201
|
}
|
|
4102
|
-
function fuseShapes(a, b, { optimisation = "none", simplify = false } = {}) {
|
|
4202
|
+
function fuseShapes(a, b, { optimisation = "none", simplify: simplify2 = false } = {}) {
|
|
4103
4203
|
const oc = getKernel().oc;
|
|
4104
4204
|
const r = gcWithScope();
|
|
4105
4205
|
const progress = r(new oc.Message_ProgressRange_1());
|
|
4106
4206
|
const fuseOp = r(new oc.BRepAlgoAPI_Fuse_3(a.wrapped, b.wrapped, progress));
|
|
4107
4207
|
applyGlue(fuseOp, optimisation);
|
|
4108
4208
|
fuseOp.Build(progress);
|
|
4109
|
-
if (
|
|
4209
|
+
if (simplify2) fuseOp.SimplifyResult(true, true, 1e-3);
|
|
4110
4210
|
return castToShape3D(fuseOp.Shape(), "FUSE_NOT_3D", "Fuse did not produce a 3D shape");
|
|
4111
4211
|
}
|
|
4112
|
-
function cutShape(base, tool, { optimisation = "none", simplify = false } = {}) {
|
|
4212
|
+
function cutShape(base, tool, { optimisation = "none", simplify: simplify2 = false } = {}) {
|
|
4113
4213
|
const oc = getKernel().oc;
|
|
4114
4214
|
const r = gcWithScope();
|
|
4115
4215
|
const progress = r(new oc.Message_ProgressRange_1());
|
|
4116
4216
|
const cutOp = r(new oc.BRepAlgoAPI_Cut_3(base.wrapped, tool.wrapped, progress));
|
|
4117
4217
|
applyGlue(cutOp, optimisation);
|
|
4118
4218
|
cutOp.Build(progress);
|
|
4119
|
-
if (
|
|
4219
|
+
if (simplify2) cutOp.SimplifyResult(true, true, 1e-3);
|
|
4120
4220
|
return castToShape3D(cutOp.Shape(), "CUT_NOT_3D", "Cut did not produce a 3D shape");
|
|
4121
4221
|
}
|
|
4122
|
-
function intersectShapes(a, b, { simplify = false } = {}) {
|
|
4222
|
+
function intersectShapes(a, b, { simplify: simplify2 = false } = {}) {
|
|
4123
4223
|
const oc = getKernel().oc;
|
|
4124
4224
|
const r = gcWithScope();
|
|
4125
4225
|
const progress = r(new oc.Message_ProgressRange_1());
|
|
4126
4226
|
const intOp = r(new oc.BRepAlgoAPI_Common_3(a.wrapped, b.wrapped, progress));
|
|
4127
4227
|
intOp.Build(progress);
|
|
4128
|
-
if (
|
|
4228
|
+
if (simplify2) intOp.SimplifyResult(true, true, 1e-3);
|
|
4129
4229
|
return castToShape3D(intOp.Shape(), "INTERSECT_NOT_3D", "Intersect did not produce a 3D shape");
|
|
4130
4230
|
}
|
|
4131
|
-
function fuseAll$1(shapes, { optimisation = "none", simplify = false, strategy = "native" } = {}) {
|
|
4231
|
+
function fuseAll$1(shapes, { optimisation = "none", simplify: simplify2 = false, strategy = "native" } = {}) {
|
|
4132
4232
|
if (shapes.length === 0)
|
|
4133
4233
|
return err(validationError("FUSE_ALL_EMPTY", "fuseAll requires at least one shape"));
|
|
4134
4234
|
if (shapes.length === 1) return ok(shapes[0]);
|
|
4135
4235
|
if (strategy === "native") {
|
|
4136
4236
|
const result = getKernel().fuseAll(
|
|
4137
4237
|
shapes.map((s) => s.wrapped),
|
|
4138
|
-
{ optimisation, simplify, strategy }
|
|
4238
|
+
{ optimisation, simplify: simplify2, strategy }
|
|
4139
4239
|
);
|
|
4140
4240
|
return castToShape3D(result, "FUSE_ALL_NOT_3D", "fuseAll did not produce a 3D shape");
|
|
4141
4241
|
}
|
|
@@ -4144,9 +4244,9 @@ function fuseAll$1(shapes, { optimisation = "none", simplify = false, strategy =
|
|
|
4144
4244
|
if (isErr(leftResult)) return leftResult;
|
|
4145
4245
|
const rightResult = fuseAll$1(shapes.slice(mid), { optimisation, simplify: false, strategy });
|
|
4146
4246
|
if (isErr(rightResult)) return rightResult;
|
|
4147
|
-
return fuseShapes(leftResult.value, rightResult.value, { optimisation, simplify });
|
|
4247
|
+
return fuseShapes(leftResult.value, rightResult.value, { optimisation, simplify: simplify2 });
|
|
4148
4248
|
}
|
|
4149
|
-
function cutAll(base, tools, { optimisation = "none", simplify = false } = {}) {
|
|
4249
|
+
function cutAll(base, tools, { optimisation = "none", simplify: simplify2 = false } = {}) {
|
|
4150
4250
|
if (tools.length === 0) return ok(base);
|
|
4151
4251
|
const oc = getKernel().oc;
|
|
4152
4252
|
const r = gcWithScope();
|
|
@@ -4155,7 +4255,7 @@ function cutAll(base, tools, { optimisation = "none", simplify = false } = {}) {
|
|
|
4155
4255
|
const cutOp = r(new oc.BRepAlgoAPI_Cut_3(base.wrapped, toolCompound, progress));
|
|
4156
4256
|
applyGlue(cutOp, optimisation);
|
|
4157
4257
|
cutOp.Build(progress);
|
|
4158
|
-
if (
|
|
4258
|
+
if (simplify2) cutOp.SimplifyResult(true, true, 1e-3);
|
|
4159
4259
|
return castToShape3D(cutOp.Shape(), "CUT_ALL_NOT_3D", "cutAll did not produce a 3D shape");
|
|
4160
4260
|
}
|
|
4161
4261
|
function buildCompound(shapes) {
|
|
@@ -4423,12 +4523,12 @@ function exportSTEP(shapes = [], { unit, modelUnit } = {}) {
|
|
|
4423
4523
|
doc.delete();
|
|
4424
4524
|
}
|
|
4425
4525
|
}
|
|
4426
|
-
function fuseAllShapes(shapes, { optimisation = "none", simplify = false, strategy = "native" } = {}) {
|
|
4526
|
+
function fuseAllShapes(shapes, { optimisation = "none", simplify: simplify2 = false, strategy = "native" } = {}) {
|
|
4427
4527
|
if (shapes.length === 0)
|
|
4428
4528
|
return err(validationError("FUSE_ALL_EMPTY", "fuseAll requires at least one shape"));
|
|
4429
4529
|
if (shapes.length === 1) return ok(shapes[0]);
|
|
4430
4530
|
if (strategy === "native") {
|
|
4431
|
-
const result = getKernel().fuseAll(shapes, { optimisation, simplify, strategy });
|
|
4531
|
+
const result = getKernel().fuseAll(shapes, { optimisation, simplify: simplify2, strategy });
|
|
4432
4532
|
return ok(result);
|
|
4433
4533
|
}
|
|
4434
4534
|
const oc = getKernel().oc;
|
|
@@ -4446,12 +4546,12 @@ function fuseAllShapes(shapes, { optimisation = "none", simplify = false, strate
|
|
|
4446
4546
|
const fuseOp = r(new oc.BRepAlgoAPI_Fuse_3(leftResult.value, rightResult.value, progress));
|
|
4447
4547
|
applyGlue$1(fuseOp, optimisation);
|
|
4448
4548
|
fuseOp.Build(progress);
|
|
4449
|
-
if (
|
|
4549
|
+
if (simplify2) {
|
|
4450
4550
|
fuseOp.SimplifyResult(true, true, 1e-3);
|
|
4451
4551
|
}
|
|
4452
4552
|
return ok(fuseOp.Shape());
|
|
4453
4553
|
}
|
|
4454
|
-
function cutAllShapes(base, tools, { optimisation = "none", simplify = false } = {}) {
|
|
4554
|
+
function cutAllShapes(base, tools, { optimisation = "none", simplify: simplify2 = false } = {}) {
|
|
4455
4555
|
if (tools.length === 0) return ok(base);
|
|
4456
4556
|
const oc = getKernel().oc;
|
|
4457
4557
|
const r = gcWithScope();
|
|
@@ -4460,7 +4560,7 @@ function cutAllShapes(base, tools, { optimisation = "none", simplify = false } =
|
|
|
4460
4560
|
const cutOp = r(new oc.BRepAlgoAPI_Cut_3(base, toolCompound, progress));
|
|
4461
4561
|
applyGlue$1(cutOp, optimisation);
|
|
4462
4562
|
cutOp.Build(progress);
|
|
4463
|
-
if (
|
|
4563
|
+
if (simplify2) {
|
|
4464
4564
|
cutOp.SimplifyResult(true, true, 1e-3);
|
|
4465
4565
|
}
|
|
4466
4566
|
return ok(cutOp.Shape());
|
|
@@ -5824,19 +5924,19 @@ class Transformation2D extends WrappingObj {
|
|
|
5824
5924
|
const stretchTransform2d = (ratio, direction, origin = [0, 0]) => {
|
|
5825
5925
|
const oc = getKernel().oc;
|
|
5826
5926
|
const ax = axis2d(origin, direction);
|
|
5827
|
-
const
|
|
5828
|
-
|
|
5927
|
+
const transform2 = new oc.gp_GTrsf2d_1();
|
|
5928
|
+
transform2.SetAffinity(ax, ratio);
|
|
5829
5929
|
ax.delete();
|
|
5830
|
-
return new Transformation2D(
|
|
5930
|
+
return new Transformation2D(transform2);
|
|
5831
5931
|
};
|
|
5832
5932
|
const translationTransform2d = (translation) => {
|
|
5833
5933
|
const oc = getKernel().oc;
|
|
5834
5934
|
const [r, gc] = localGC();
|
|
5835
5935
|
const rotation = new oc.gp_Trsf2d_1();
|
|
5836
5936
|
rotation.SetTranslation_1(r(vec(translation)));
|
|
5837
|
-
const
|
|
5937
|
+
const transform2 = new oc.gp_GTrsf2d_2(rotation);
|
|
5838
5938
|
gc();
|
|
5839
|
-
return new Transformation2D(
|
|
5939
|
+
return new Transformation2D(transform2);
|
|
5840
5940
|
};
|
|
5841
5941
|
const mirrorTransform2d = (centerOrDirection, origin = [0, 0], mode = "center") => {
|
|
5842
5942
|
const oc = getKernel().oc;
|
|
@@ -5847,27 +5947,27 @@ const mirrorTransform2d = (centerOrDirection, origin = [0, 0], mode = "center")
|
|
|
5847
5947
|
} else {
|
|
5848
5948
|
rotation.SetMirror_2(r(axis2d(origin, centerOrDirection)));
|
|
5849
5949
|
}
|
|
5850
|
-
const
|
|
5950
|
+
const transform2 = new oc.gp_GTrsf2d_2(rotation);
|
|
5851
5951
|
gc();
|
|
5852
|
-
return new Transformation2D(
|
|
5952
|
+
return new Transformation2D(transform2);
|
|
5853
5953
|
};
|
|
5854
5954
|
const rotateTransform2d = (angle, center = [0, 0]) => {
|
|
5855
5955
|
const oc = getKernel().oc;
|
|
5856
5956
|
const [r, gc] = localGC();
|
|
5857
5957
|
const rotation = new oc.gp_Trsf2d_1();
|
|
5858
5958
|
rotation.SetRotation(r(pnt(center)), angle);
|
|
5859
|
-
const
|
|
5959
|
+
const transform2 = new oc.gp_GTrsf2d_2(rotation);
|
|
5860
5960
|
gc();
|
|
5861
|
-
return new Transformation2D(
|
|
5961
|
+
return new Transformation2D(transform2);
|
|
5862
5962
|
};
|
|
5863
5963
|
const scaleTransform2d = (scaleFactor, center = [0, 0]) => {
|
|
5864
5964
|
const oc = getKernel().oc;
|
|
5865
5965
|
const [r, gc] = localGC();
|
|
5866
5966
|
const scaling = new oc.gp_Trsf2d_1();
|
|
5867
5967
|
scaling.SetScale(r(pnt(center)), scaleFactor);
|
|
5868
|
-
const
|
|
5968
|
+
const transform2 = new oc.gp_GTrsf2d_2(scaling);
|
|
5869
5969
|
gc();
|
|
5870
|
-
return new Transformation2D(
|
|
5970
|
+
return new Transformation2D(transform2);
|
|
5871
5971
|
};
|
|
5872
5972
|
function curvesAsEdgesOnFace(curves, face, scale2 = "original") {
|
|
5873
5973
|
const [r, gc] = localGC();
|
|
@@ -5936,8 +6036,8 @@ const viewbox = (bbox, margin = 1) => {
|
|
|
5936
6036
|
const minY = -bbox.bounds[1][1] - margin;
|
|
5937
6037
|
return `${minX} ${minY} ${bbox.width + 2 * margin} ${bbox.height + 2 * margin}`;
|
|
5938
6038
|
};
|
|
5939
|
-
const asSVG = (body,
|
|
5940
|
-
const vbox = viewbox(
|
|
6039
|
+
const asSVG = (body, boundingBox2, margin = 1) => {
|
|
6040
|
+
const vbox = viewbox(boundingBox2, margin);
|
|
5941
6041
|
return `<svg version="1.1" xmlns="http://www.w3.org/2000/svg" viewBox="${vbox}" fill="none" stroke="black" stroke-width="0.6%" vector-effect="non-scaling-stroke">
|
|
5942
6042
|
${body}
|
|
5943
6043
|
</svg>`;
|
|
@@ -7486,7 +7586,7 @@ const rotateToStartAtSegment = (curves, segment) => {
|
|
|
7486
7586
|
const end = curves.slice(startIndex);
|
|
7487
7587
|
return end.concat(start);
|
|
7488
7588
|
};
|
|
7489
|
-
const hashPoint = (p) => `${p[0].toFixed(
|
|
7589
|
+
const hashPoint = (p) => `${p[0].toFixed(9)},${p[1].toFixed(9)}`;
|
|
7490
7590
|
const hashSegment = (first, last) => {
|
|
7491
7591
|
const h1 = hashPoint(first);
|
|
7492
7592
|
const h2 = hashPoint(last);
|
|
@@ -8013,8 +8113,8 @@ function intersect2D(first, second) {
|
|
|
8013
8113
|
return intersect2D(wrapper, second);
|
|
8014
8114
|
}
|
|
8015
8115
|
let result = intersect2D(wrapper, second);
|
|
8016
|
-
for (const
|
|
8017
|
-
result = cut2D(result,
|
|
8116
|
+
for (const cut2 of cuts) {
|
|
8117
|
+
result = cut2D(result, cut2);
|
|
8018
8118
|
}
|
|
8019
8119
|
return result;
|
|
8020
8120
|
}
|
|
@@ -8028,8 +8128,8 @@ function intersect2D(first, second) {
|
|
|
8028
8128
|
return intersect2D(wrapper, first);
|
|
8029
8129
|
}
|
|
8030
8130
|
let result = intersect2D(wrapper, first);
|
|
8031
|
-
for (const
|
|
8032
|
-
result = cut2D(result,
|
|
8131
|
+
for (const cut2 of cuts) {
|
|
8132
|
+
result = cut2D(result, cut2);
|
|
8033
8133
|
}
|
|
8034
8134
|
return result;
|
|
8035
8135
|
}
|
|
@@ -8123,10 +8223,10 @@ class EdgeFinder extends Finder3d {
|
|
|
8123
8223
|
*
|
|
8124
8224
|
* @category Filter
|
|
8125
8225
|
*/
|
|
8126
|
-
ofLength(
|
|
8226
|
+
ofLength(length2) {
|
|
8127
8227
|
const check = ({ element }) => {
|
|
8128
|
-
if (typeof
|
|
8129
|
-
return
|
|
8228
|
+
if (typeof length2 === "number") return Math.abs(element.length - length2) < 1e-9;
|
|
8229
|
+
return length2(element.length);
|
|
8130
8230
|
};
|
|
8131
8231
|
this.filters.push(check);
|
|
8132
8232
|
return this;
|
|
@@ -8837,8 +8937,8 @@ const solidFromShellGenerator = (sketches, shellGenerator) => {
|
|
|
8837
8937
|
const startWires = [];
|
|
8838
8938
|
const endWires = [];
|
|
8839
8939
|
sketches.forEach((sketch) => {
|
|
8840
|
-
const [
|
|
8841
|
-
shells.push(
|
|
8940
|
+
const [shell2, startWire, endWire] = unwrap(shellGenerator(sketch));
|
|
8941
|
+
shells.push(shell2);
|
|
8842
8942
|
startWires.push(startWire);
|
|
8843
8943
|
endWires.push(endWire);
|
|
8844
8944
|
});
|
|
@@ -10380,7 +10480,7 @@ function createEdgeFinder(filters) {
|
|
|
10380
10480
|
return Math.abs(ang - DEG2RAD * angle) < 1e-6;
|
|
10381
10481
|
});
|
|
10382
10482
|
},
|
|
10383
|
-
ofLength: (
|
|
10483
|
+
ofLength: (length2, tolerance = 1e-3) => withFilter((edge) => Math.abs(curveLength(edge) - length2) < tolerance),
|
|
10384
10484
|
ofCurveType: (curveType) => withFilter((edge) => getCurveType(edge) === curveType),
|
|
10385
10485
|
parallelTo: (dir = "Z") => createEdgeFinder([...filters]).inDirection(dir, 0),
|
|
10386
10486
|
atDistance: (distance, point = [0, 0, 0]) => withFilter((edge) => {
|