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.
@@ -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 combinePathPolylines(edges, tol = 1e-5) {
110
- const { polys } = collectEdgePolylines(edges);
111
- if (polys.length === 0) return [];
112
- if (polys.length === 1) return polys[0];
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
- if (localChain.length > best.length) best = localChain;
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
- return best;
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 < edgeGroups.length; i++) {
374
- const group = edgeGroups[i];
375
- const pathPoints = dedupePoints(combinePathPolylines(group));
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 (edgeGroups.length === 1) return featureID;
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 firstEdge = group[0];
399
- if (firstEdge) {
400
- const edgeName = firstEdge.name || firstEdge.id;
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
  }