brep-io-kernel 1.0.19 → 1.0.21

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.
@@ -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) {
@@ -373,6 +396,26 @@ export class TubeFeature {
373
396
  throw new Error('Unable to build a connected path for the tube.');
374
397
  }
375
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
+
376
419
  const baseResolution = Math.max(8, Math.floor(Number(resolution) || 32));
377
420
  const modeSelection = typeof mode === 'string'
378
421
  ? mode
@@ -382,9 +425,9 @@ export class TubeFeature {
382
425
  const outerSolids = [];
383
426
  const innerSolids = [];
384
427
  const debugExtras = [];
385
- for (let i = 0; i < edgeGroups.length; i++) {
386
- const group = edgeGroups[i];
387
- 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);
388
431
  if (pathPoints.length < 2) {
389
432
  throw new Error('Unable to build a connected path for the tube.');
390
433
  }
@@ -404,12 +447,12 @@ export class TubeFeature {
404
447
  const finalPoints = isClosedLoop ? pathPoints.slice(0, -1) : pathPoints;
405
448
  const tubeName = (() => {
406
449
  if (!featureID) return featureID;
407
- if (edgeGroups.length === 1) return featureID;
450
+ if (tubeTasks.length === 1) return featureID;
408
451
 
409
452
  // get the name of the first edge in the group if possible
410
- const firstEdge = group[0];
411
- if (firstEdge) {
412
- const edgeName = firstEdge.name || firstEdge.id;
453
+ const edgeRef = task.edge;
454
+ if (edgeRef) {
455
+ const edgeName = edgeRef.name || edgeRef.id || edgeRef.userData?.edgeName;
413
456
  if (edgeName) {
414
457
  return `${featureID}_${edgeName}`;
415
458
  }