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