brep-io-kernel 1.0.18 → 1.0.20
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist-kernel/brep-kernel.js +9157 -8530
- package/package.json +1 -1
- package/src/FeatureRegistry.js +3 -0
- package/src/PartHistory.js +35 -0
- package/src/UI/SelectionFilter.js +262 -18
- package/src/UI/featureDialogs.js +268 -21
- package/src/UI/history/HistoryCollectionWidget.js +20 -1
- package/src/UI/pmi/AnnotationRegistry.js +3 -0
- package/src/assemblyConstraints/AssemblyConstraintRegistry.js +3 -0
- package/src/features/boolean/BooleanFeature.js +15 -0
- package/src/features/chamfer/ChamferFeature.js +12 -0
- package/src/features/extrude/ExtrudeFeature.js +11 -0
- package/src/features/fillet/FilletFeature.js +12 -0
- package/src/features/hole/HoleFeature.js +15 -0
- package/src/features/loft/LoftFeature.js +17 -0
- package/src/features/mirror/MirrorFeature.js +14 -0
- package/src/features/patternLinear/PatternLinearFeature.js +9 -0
- package/src/features/patternRadial/PatternRadialFeature.js +13 -0
- package/src/features/plane/PlaneFeature.js +10 -0
- package/src/features/revolve/RevolveFeature.js +15 -0
- package/src/features/sketch/SketchFeature.js +11 -0
- package/src/features/sweep/SweepFeature.js +17 -0
- package/src/features/transform/TransformFeature.js +12 -0
- package/src/features/tube/TubeFeature.js +69 -14
|
@@ -34,6 +34,15 @@ export class PatternLinearFeature {
|
|
|
34
34
|
static shortName = "PATLIN";
|
|
35
35
|
static longName = "Pattern Linear";
|
|
36
36
|
static inputParamsSchema = inputParamsSchema;
|
|
37
|
+
static showContexButton(selectedItems) {
|
|
38
|
+
const items = Array.isArray(selectedItems) ? selectedItems : [];
|
|
39
|
+
const solids = items
|
|
40
|
+
.filter((it) => String(it?.type || '').toUpperCase() === 'SOLID')
|
|
41
|
+
.map((it) => it?.name)
|
|
42
|
+
.filter((name) => !!name);
|
|
43
|
+
if (!solids.length) return false;
|
|
44
|
+
return { params: { solids } };
|
|
45
|
+
}
|
|
37
46
|
|
|
38
47
|
constructor() {
|
|
39
48
|
this.inputParams = {};
|
|
@@ -49,6 +49,19 @@ export class PatternRadialFeature {
|
|
|
49
49
|
static shortName = "PATRAD";
|
|
50
50
|
static longName = "Pattern Radial";
|
|
51
51
|
static inputParamsSchema = inputParamsSchema;
|
|
52
|
+
static showContexButton(selectedItems) {
|
|
53
|
+
const items = Array.isArray(selectedItems) ? selectedItems : [];
|
|
54
|
+
const solids = items
|
|
55
|
+
.filter((it) => String(it?.type || '').toUpperCase() === 'SOLID')
|
|
56
|
+
.map((it) => it?.name)
|
|
57
|
+
.filter((name) => !!name);
|
|
58
|
+
if (!solids.length) return false;
|
|
59
|
+
const axis = items.find((it) => String(it?.type || '').toUpperCase() === 'EDGE');
|
|
60
|
+
const axisName = axis?.name || axis?.userData?.edgeName || null;
|
|
61
|
+
const params = { solids };
|
|
62
|
+
if (axisName) params.axisRef = axisName;
|
|
63
|
+
return { params };
|
|
64
|
+
}
|
|
52
65
|
|
|
53
66
|
constructor() {
|
|
54
67
|
this.inputParams = {};
|
|
@@ -46,6 +46,16 @@ export class PlaneFeature {
|
|
|
46
46
|
static shortName = "P";
|
|
47
47
|
static longName = "Plane";
|
|
48
48
|
static inputParamsSchema = inputParamsSchema;
|
|
49
|
+
static showContexButton(selectedItems) {
|
|
50
|
+
const items = Array.isArray(selectedItems) ? selectedItems : [];
|
|
51
|
+
const ref = items.find((it) => {
|
|
52
|
+
const type = String(it?.type || '').toUpperCase();
|
|
53
|
+
return type === 'FACE' || type === 'PLANE';
|
|
54
|
+
});
|
|
55
|
+
const name = ref?.name || ref?.userData?.faceName || null;
|
|
56
|
+
if (!name) return false;
|
|
57
|
+
return { field: 'datum', value: name };
|
|
58
|
+
}
|
|
49
59
|
|
|
50
60
|
constructor() {
|
|
51
61
|
this.inputParams = {};
|
|
@@ -47,6 +47,21 @@ export class RevolveFeature {
|
|
|
47
47
|
static shortName = "R";
|
|
48
48
|
static longName = "Revolve";
|
|
49
49
|
static inputParamsSchema = inputParamsSchema;
|
|
50
|
+
static showContexButton(selectedItems) {
|
|
51
|
+
const items = Array.isArray(selectedItems) ? selectedItems : [];
|
|
52
|
+
const profileObj = items.find((it) => {
|
|
53
|
+
const type = String(it?.type || '').toUpperCase();
|
|
54
|
+
return type === 'FACE' || type === 'SKETCH';
|
|
55
|
+
});
|
|
56
|
+
if (!profileObj) return false;
|
|
57
|
+
const profileName = profileObj?.name || profileObj?.userData?.faceName || null;
|
|
58
|
+
if (!profileName) return false;
|
|
59
|
+
const axisObj = items.find((it) => String(it?.type || '').toUpperCase() === 'EDGE');
|
|
60
|
+
const axisName = axisObj?.name || axisObj?.userData?.edgeName || null;
|
|
61
|
+
const params = { profile: profileName };
|
|
62
|
+
if (axisName) params.axis = axisName;
|
|
63
|
+
return { params };
|
|
64
|
+
}
|
|
50
65
|
|
|
51
66
|
constructor() {
|
|
52
67
|
this.inputParams = {};
|
|
@@ -82,6 +82,17 @@ export class SketchFeature {
|
|
|
82
82
|
static shortName = "S";
|
|
83
83
|
static longName = "Sketch";
|
|
84
84
|
static inputParamsSchema = inputParamsSchema;
|
|
85
|
+
static showContexButton(selectedItems) {
|
|
86
|
+
const items = Array.isArray(selectedItems) ? selectedItems : [];
|
|
87
|
+
const target = items.find((it) => {
|
|
88
|
+
const type = String(it?.type || '').toUpperCase();
|
|
89
|
+
return type === 'FACE' || type === 'PLANE';
|
|
90
|
+
});
|
|
91
|
+
if (!target) return false;
|
|
92
|
+
const name = target?.name || target?.userData?.faceName || null;
|
|
93
|
+
if (!name) return false;
|
|
94
|
+
return { field: 'sketchPlane', value: name };
|
|
95
|
+
}
|
|
85
96
|
|
|
86
97
|
constructor() {
|
|
87
98
|
this.inputParams = {};
|
|
@@ -48,6 +48,23 @@ export class SweepFeature {
|
|
|
48
48
|
static shortName = "SW";
|
|
49
49
|
static longName = "Sweep";
|
|
50
50
|
static inputParamsSchema = inputParamsSchema;
|
|
51
|
+
static showContexButton(selectedItems) {
|
|
52
|
+
const items = Array.isArray(selectedItems) ? selectedItems : [];
|
|
53
|
+
const profileObj = items.find((it) => {
|
|
54
|
+
const type = String(it?.type || '').toUpperCase();
|
|
55
|
+
return type === 'FACE' || type === 'SKETCH';
|
|
56
|
+
});
|
|
57
|
+
if (!profileObj) return false;
|
|
58
|
+
const profileName = profileObj?.name || profileObj?.userData?.faceName || null;
|
|
59
|
+
if (!profileName) return false;
|
|
60
|
+
const edges = items
|
|
61
|
+
.filter((it) => String(it?.type || '').toUpperCase() === 'EDGE')
|
|
62
|
+
.map((it) => it?.name || it?.userData?.edgeName)
|
|
63
|
+
.filter((name) => !!name);
|
|
64
|
+
const params = { profile: profileName };
|
|
65
|
+
if (edges.length) params.path = edges;
|
|
66
|
+
return { params };
|
|
67
|
+
}
|
|
51
68
|
|
|
52
69
|
constructor() {
|
|
53
70
|
this.inputParams = {};
|
|
@@ -57,6 +57,18 @@ export class TransformFeature {
|
|
|
57
57
|
static shortName = "XFORM";
|
|
58
58
|
static longName = "Transform";
|
|
59
59
|
static inputParamsSchema = inputParamsSchema;
|
|
60
|
+
static showContexButton(selectedItems) {
|
|
61
|
+
const items = Array.isArray(selectedItems) ? selectedItems : [];
|
|
62
|
+
const solids = items
|
|
63
|
+
.filter((it) => {
|
|
64
|
+
const type = String(it?.type || '').toUpperCase();
|
|
65
|
+
return type === 'SOLID';
|
|
66
|
+
})
|
|
67
|
+
.map((it) => it?.name)
|
|
68
|
+
.filter((name) => !!name);
|
|
69
|
+
if (!solids.length) return false;
|
|
70
|
+
return { params: { solids } };
|
|
71
|
+
}
|
|
60
72
|
|
|
61
73
|
constructor() {
|
|
62
74
|
this.inputParams = {};
|
|
@@ -106,10 +106,14 @@ function collectEdgePolylines(edges) {
|
|
|
106
106
|
return { polys, edges: validEdges };
|
|
107
107
|
}
|
|
108
108
|
|
|
109
|
-
function
|
|
110
|
-
const { polys } = collectEdgePolylines(edges);
|
|
111
|
-
if (polys.length === 0)
|
|
112
|
-
|
|
109
|
+
function combinePathPolylinesWithUsage(edges, tol = 1e-5) {
|
|
110
|
+
const { polys, edges: validEdges } = collectEdgePolylines(edges);
|
|
111
|
+
if (polys.length === 0) {
|
|
112
|
+
return { points: [], usedEdges: [], unusedEdges: validEdges };
|
|
113
|
+
}
|
|
114
|
+
if (polys.length === 1) {
|
|
115
|
+
return { points: polys[0], usedEdges: [validEdges[0]], unusedEdges: [] };
|
|
116
|
+
}
|
|
113
117
|
|
|
114
118
|
const effectiveTol = deriveTolerance(polys, tol);
|
|
115
119
|
const tol2 = effectiveTol * effectiveTol;
|
|
@@ -180,9 +184,12 @@ function combinePathPolylines(edges, tol = 1e-5) {
|
|
|
180
184
|
nextKey = tryConsumeFromNode(cursorKey);
|
|
181
185
|
}
|
|
182
186
|
|
|
187
|
+
const countUsed = (arr) => arr.reduce((sum, v) => sum + (v ? 1 : 0), 0);
|
|
183
188
|
let best = chain.slice();
|
|
189
|
+
let bestUsed = used.slice();
|
|
190
|
+
let bestCount = countUsed(bestUsed);
|
|
191
|
+
|
|
184
192
|
for (let s = 0; s < polys.length; s++) {
|
|
185
|
-
if (used[s]) continue;
|
|
186
193
|
const localUsed = new Array(polys.length).fill(false);
|
|
187
194
|
const localChain = [];
|
|
188
195
|
localUsed[s] = true;
|
|
@@ -222,7 +229,12 @@ function combinePathPolylines(edges, tol = 1e-5) {
|
|
|
222
229
|
}
|
|
223
230
|
}
|
|
224
231
|
}
|
|
225
|
-
|
|
232
|
+
const localCount = countUsed(localUsed);
|
|
233
|
+
if (localCount > bestCount || (localCount === bestCount && localChain.length > best.length)) {
|
|
234
|
+
best = localChain;
|
|
235
|
+
bestUsed = localUsed;
|
|
236
|
+
bestCount = localCount;
|
|
237
|
+
}
|
|
226
238
|
}
|
|
227
239
|
|
|
228
240
|
for (let i = best.length - 2; i >= 0; i--) {
|
|
@@ -230,7 +242,18 @@ function combinePathPolylines(edges, tol = 1e-5) {
|
|
|
230
242
|
const b = best[i + 1];
|
|
231
243
|
if (a[0] === b[0] && a[1] === b[1] && a[2] === b[2]) best.splice(i + 1, 1);
|
|
232
244
|
}
|
|
233
|
-
|
|
245
|
+
|
|
246
|
+
const usedEdges = [];
|
|
247
|
+
const unusedEdges = [];
|
|
248
|
+
for (let i = 0; i < validEdges.length; i++) {
|
|
249
|
+
if (bestUsed[i]) usedEdges.push(validEdges[i]);
|
|
250
|
+
else unusedEdges.push(validEdges[i]);
|
|
251
|
+
}
|
|
252
|
+
return { points: best, usedEdges, unusedEdges };
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
function combinePathPolylines(edges, tol = 1e-5) {
|
|
256
|
+
return combinePathPolylinesWithUsage(edges, tol).points;
|
|
234
257
|
}
|
|
235
258
|
|
|
236
259
|
function groupEdgesByConnectivity(edges, tol = 1e-5) {
|
|
@@ -332,6 +355,18 @@ export class TubeFeature {
|
|
|
332
355
|
static shortName = 'TU';
|
|
333
356
|
static longName = 'Tube';
|
|
334
357
|
static inputParamsSchema = inputParamsSchema;
|
|
358
|
+
static showContexButton(selectedItems) {
|
|
359
|
+
const items = Array.isArray(selectedItems) ? selectedItems : [];
|
|
360
|
+
if (items.some((it) => String(it?.type || '').toUpperCase() !== 'EDGE')) {
|
|
361
|
+
return false;
|
|
362
|
+
}
|
|
363
|
+
const edges = items
|
|
364
|
+
.filter((it) => String(it?.type || '').toUpperCase() === 'EDGE')
|
|
365
|
+
.map((it) => it?.name || it?.userData?.edgeName)
|
|
366
|
+
.filter((name) => !!name);
|
|
367
|
+
if (!edges.length) return false;
|
|
368
|
+
return { params: { path: edges } };
|
|
369
|
+
}
|
|
335
370
|
|
|
336
371
|
constructor() {
|
|
337
372
|
this.inputParams = {};
|
|
@@ -361,6 +396,26 @@ export class TubeFeature {
|
|
|
361
396
|
throw new Error('Unable to build a connected path for the tube.');
|
|
362
397
|
}
|
|
363
398
|
|
|
399
|
+
const tubeTasks = [];
|
|
400
|
+
for (const group of edgeGroups) {
|
|
401
|
+
const { points, unusedEdges } = combinePathPolylinesWithUsage(group);
|
|
402
|
+
if (Array.isArray(points) && points.length >= 2) {
|
|
403
|
+
tubeTasks.push({ points, edge: group[0] || null });
|
|
404
|
+
}
|
|
405
|
+
if (Array.isArray(unusedEdges) && unusedEdges.length) {
|
|
406
|
+
for (const edge of unusedEdges) {
|
|
407
|
+
const edgePoints = extractPathPolylineWorld(edge);
|
|
408
|
+
if (edgePoints.length >= 2) {
|
|
409
|
+
tubeTasks.push({ points: edgePoints, edge });
|
|
410
|
+
}
|
|
411
|
+
}
|
|
412
|
+
}
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
if (!tubeTasks.length) {
|
|
416
|
+
throw new Error('Unable to build a connected path for the tube.');
|
|
417
|
+
}
|
|
418
|
+
|
|
364
419
|
const baseResolution = Math.max(8, Math.floor(Number(resolution) || 32));
|
|
365
420
|
const modeSelection = typeof mode === 'string'
|
|
366
421
|
? mode
|
|
@@ -370,9 +425,9 @@ export class TubeFeature {
|
|
|
370
425
|
const outerSolids = [];
|
|
371
426
|
const innerSolids = [];
|
|
372
427
|
const debugExtras = [];
|
|
373
|
-
for (let i = 0; i <
|
|
374
|
-
const
|
|
375
|
-
const pathPoints = dedupePoints(
|
|
428
|
+
for (let i = 0; i < tubeTasks.length; i++) {
|
|
429
|
+
const task = tubeTasks[i];
|
|
430
|
+
const pathPoints = dedupePoints(task.points);
|
|
376
431
|
if (pathPoints.length < 2) {
|
|
377
432
|
throw new Error('Unable to build a connected path for the tube.');
|
|
378
433
|
}
|
|
@@ -392,12 +447,12 @@ export class TubeFeature {
|
|
|
392
447
|
const finalPoints = isClosedLoop ? pathPoints.slice(0, -1) : pathPoints;
|
|
393
448
|
const tubeName = (() => {
|
|
394
449
|
if (!featureID) return featureID;
|
|
395
|
-
if (
|
|
450
|
+
if (tubeTasks.length === 1) return featureID;
|
|
396
451
|
|
|
397
452
|
// get the name of the first edge in the group if possible
|
|
398
|
-
const
|
|
399
|
-
if (
|
|
400
|
-
const edgeName =
|
|
453
|
+
const edgeRef = task.edge;
|
|
454
|
+
if (edgeRef) {
|
|
455
|
+
const edgeName = edgeRef.name || edgeRef.id || edgeRef.userData?.edgeName;
|
|
401
456
|
if (edgeName) {
|
|
402
457
|
return `${featureID}_${edgeName}`;
|
|
403
458
|
}
|