bpmn-elk-layout 1.0.1 → 1.1.2

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/index.js CHANGED
@@ -298,7 +298,11 @@ function lineIntersection(p1, p2, p3, p4) {
298
298
  }
299
299
 
300
300
  // src/utils/debug.ts
301
- var DEBUG = typeof process !== "undefined" && process.env?.["DEBUG"] === "true";
301
+ var cliMode = false;
302
+ function isDebugEnabled() {
303
+ if (cliMode) return false;
304
+ return typeof process !== "undefined" && process.env?.["DEBUG"] === "true";
305
+ }
302
306
 
303
307
  // src/layout/edge-routing/edge-fixer.ts
304
308
  var EdgeFixer = class {
@@ -331,7 +335,7 @@ var EdgeFixer = class {
331
335
  const isFlowNode = flowNodePatterns.some((pattern) => pattern.test(id));
332
336
  const isPool = poolPatterns.some((pattern) => pattern.test(id));
333
337
  const bpmn = node.bpmn;
334
- if (DEBUG && (id.includes("lane") || id.includes("pool") || id.includes("end_fast") || id.includes("gateway_fast"))) {
338
+ if (isDebugEnabled() && (id.includes("lane") || id.includes("pool") || id.includes("end_fast") || id.includes("gateway_fast"))) {
335
339
  console.log(`[BPMN] EdgeFixer.collectNodePositions: id=${id}, offsetX=${offsetX}, offsetY=${offsetY}, bpmn=${JSON.stringify(bpmn)}`);
336
340
  console.log(`[BPMN] node.x=${node.x}, node.y=${node.y}, isFlowNode=${isFlowNode}, isPool=${isPool}`);
337
341
  }
@@ -369,6 +373,10 @@ var EdgeFixer = class {
369
373
  const containerNodes = nodesByContainer.get(currentContainerId) ?? /* @__PURE__ */ new Map();
370
374
  for (const edge of node.edges) {
371
375
  if (edge.sections && edge.sections.length > 0) {
376
+ const hasPoolRelativeCoords = edge._poolRelativeCoords === true;
377
+ if (hasPoolRelativeCoords) {
378
+ continue;
379
+ }
372
380
  this.fixEdgeIfCrossing(edge, containerNodes, containerOffsetX, containerOffsetY);
373
381
  }
374
382
  }
@@ -420,7 +428,7 @@ var EdgeFixer = class {
420
428
  }
421
429
  const targetPos = targetId ? nodePositions.get(targetId) : void 0;
422
430
  const sourcePos = sourceId ? nodePositions.get(sourceId) : void 0;
423
- if (DEBUG && edge.id?.includes("back")) {
431
+ if (isDebugEnabled() && edge.id?.includes("back")) {
424
432
  console.log(`[BPMN] Edge ${edge.id}: sourceId=${sourceId}, targetId=${targetId}`);
425
433
  console.log(`[BPMN] Edge ${edge.id}: sourcePos=${JSON.stringify(sourcePos)}, targetPos=${JSON.stringify(targetPos)}`);
426
434
  console.log(`[BPMN] Edge ${edge.id}: waypoints.length=${waypoints.length}`);
@@ -429,7 +437,7 @@ var EdgeFixer = class {
429
437
  const lastWaypoint = waypoints[waypoints.length - 1];
430
438
  const secondLastWaypoint = waypoints[waypoints.length - 2];
431
439
  const isReturnEdge2 = targetPos.y + targetPos.height < sourcePos.y;
432
- if (DEBUG && edge.id?.includes("back")) {
440
+ if (isDebugEnabled() && edge.id?.includes("back")) {
433
441
  console.log(`[BPMN] Edge ${edge.id}: isReturnEdge=${isReturnEdge2}`);
434
442
  if (lastWaypoint) {
435
443
  console.log(`[BPMN] Edge ${edge.id}: lastWaypoint=(${lastWaypoint.x},${lastWaypoint.y})`);
@@ -449,7 +457,7 @@ var EdgeFixer = class {
449
457
  }
450
458
  }
451
459
  if (crossedNodes.length === 0) return;
452
- if (DEBUG) {
460
+ if (isDebugEnabled()) {
453
461
  console.log(`[BPMN] Edge ${edge.id} crosses nodes: ${crossedNodes.join(", ")}`);
454
462
  }
455
463
  if (!sourcePos || !targetPos) return;
@@ -500,7 +508,7 @@ var EdgeFixer = class {
500
508
  y: bp.y - containerOffsetY
501
509
  }));
502
510
  section.bendPoints = relativeBendPoints.length > 0 ? relativeBendPoints : void 0;
503
- if (DEBUG) {
511
+ if (isDebugEnabled()) {
504
512
  console.log(`[BPMN] Fixed edge ${edge.id} with ${relativeBendPoints.length} bend points`);
505
513
  }
506
514
  }
@@ -1290,7 +1298,8 @@ function applyNodeMoves(graph, movedNodes) {
1290
1298
  }
1291
1299
 
1292
1300
  // src/layout/post-processing/boundary-event/edge-recalculator.ts
1293
- function recalculateEdgesForMovedNodes(graph, movedNodes, boundaryEventInfo, debug = false) {
1301
+ function recalculateEdgesForMovedNodes(graph, movedNodes, boundaryEventInfo) {
1302
+ const debug = isDebugEnabled();
1294
1303
  const nodeMap = /* @__PURE__ */ new Map();
1295
1304
  const buildNodeMap2 = (node) => {
1296
1305
  nodeMap.set(node.id, node);
@@ -1367,7 +1376,8 @@ function recalculateEdgesForMovedNodes(graph, movedNodes, boundaryEventInfo, deb
1367
1376
  };
1368
1377
  processEdges(graph);
1369
1378
  }
1370
- function recalculateEdgeWithObstacleAvoidance(edge, source, target, obstacleIds, nodeMap, debug = false) {
1379
+ function recalculateEdgeWithObstacleAvoidance(edge, source, target, obstacleIds, nodeMap) {
1380
+ const debug = isDebugEnabled();
1371
1381
  const sx = source.x ?? 0;
1372
1382
  const sy = source.y ?? 0;
1373
1383
  const sw = source.width ?? 100;
@@ -1588,8 +1598,8 @@ var BoundaryEventHandler = class {
1588
1598
  /**
1589
1599
  * Recalculate edge waypoints for edges connected to moved nodes
1590
1600
  */
1591
- recalculateEdgesForMovedNodes(graph, movedNodes, boundaryEventInfo, debug = false) {
1592
- recalculateEdgesForMovedNodes(graph, movedNodes, boundaryEventInfo, debug);
1601
+ recalculateEdgesForMovedNodes(graph, movedNodes, boundaryEventInfo) {
1602
+ recalculateEdgesForMovedNodes(graph, movedNodes, boundaryEventInfo);
1593
1603
  }
1594
1604
  };
1595
1605
 
@@ -2476,7 +2486,7 @@ var LaneArranger = class {
2476
2486
  const targetId = edge.targets?.[0];
2477
2487
  const sourcePos = sourceId ? nodePositions.get(sourceId) : void 0;
2478
2488
  const targetPos = targetId ? nodePositions.get(targetId) : void 0;
2479
- if (DEBUG) {
2489
+ if (isDebugEnabled()) {
2480
2490
  console.log(`[BPMN] recalculatePoolEdges ${edge.id}: source=${sourceId}, target=${targetId}`);
2481
2491
  console.log(`[BPMN] sourcePos=${JSON.stringify(sourcePos)}`);
2482
2492
  console.log(`[BPMN] targetPos=${JSON.stringify(targetPos)}`);
@@ -2486,18 +2496,26 @@ var LaneArranger = class {
2486
2496
  const startY = sourcePos.y + sourcePos.height / 2;
2487
2497
  const endX = targetPos.x;
2488
2498
  const endY = targetPos.y + targetPos.height / 2;
2489
- if (DEBUG) {
2499
+ if (isDebugEnabled()) {
2490
2500
  console.log(`[BPMN] startX=${startX}, startY=${startY}, endX=${endX}, endY=${endY}`);
2491
2501
  }
2492
2502
  const waypoints = [];
2493
2503
  waypoints.push({ x: startX, y: startY });
2494
2504
  if (Math.abs(startY - endY) > 10) {
2495
- const midX = (startX + endX) / 2;
2505
+ const midX = this.findClearMidX(
2506
+ startX,
2507
+ endX,
2508
+ startY,
2509
+ endY,
2510
+ sourceId,
2511
+ targetId,
2512
+ nodePositions
2513
+ );
2496
2514
  waypoints.push({ x: midX, y: startY });
2497
2515
  waypoints.push({ x: midX, y: endY });
2498
2516
  }
2499
2517
  waypoints.push({ x: endX, y: endY });
2500
- if (DEBUG) {
2518
+ if (isDebugEnabled()) {
2501
2519
  console.log(`[BPMN] waypoints=${JSON.stringify(waypoints)}`);
2502
2520
  }
2503
2521
  edge._poolRelativeCoords = true;
@@ -2510,6 +2528,109 @@ var LaneArranger = class {
2510
2528
  }
2511
2529
  }
2512
2530
  }
2531
+ /**
2532
+ * Find a clear X position for vertical edge segment that avoids obstacles.
2533
+ * Checks all three segments of the L-shaped path:
2534
+ * 1. Horizontal from (startX, startY) to (midX, startY)
2535
+ * 2. Vertical from (midX, startY) to (midX, endY)
2536
+ * 3. Horizontal from (midX, endY) to (endX, endY)
2537
+ */
2538
+ findClearMidX(startX, endX, startY, endY, sourceId, targetId, nodePositions) {
2539
+ const margin = 15;
2540
+ const minY = Math.min(startY, endY);
2541
+ const maxY = Math.max(startY, endY);
2542
+ const rangeMinX = Math.min(startX, endX);
2543
+ const rangeMaxX = Math.max(startX, endX);
2544
+ if (isDebugEnabled()) {
2545
+ console.log(`[BPMN] findClearMidX: startX=${startX}, endX=${endX}, startY=${startY}, endY=${endY}`);
2546
+ }
2547
+ const allObstacles = [];
2548
+ for (const [nodeId, pos] of nodePositions) {
2549
+ if (nodeId === sourceId || nodeId === targetId) continue;
2550
+ const nodeLeft = pos.x;
2551
+ const nodeRight = pos.x + pos.width;
2552
+ const nodeTop = pos.y;
2553
+ const nodeBottom = pos.y + pos.height;
2554
+ const xOverlap = nodeRight > rangeMinX && nodeLeft < rangeMaxX;
2555
+ const yOverlapVertical = nodeBottom > minY && nodeTop < maxY;
2556
+ const yContainsStartY = nodeTop <= startY && nodeBottom >= startY;
2557
+ const yContainsEndY = nodeTop <= endY && nodeBottom >= endY;
2558
+ if (xOverlap && (yOverlapVertical || yContainsStartY || yContainsEndY)) {
2559
+ allObstacles.push({
2560
+ x: nodeLeft,
2561
+ y: nodeTop,
2562
+ width: pos.width,
2563
+ height: pos.height,
2564
+ right: nodeRight,
2565
+ bottom: nodeBottom,
2566
+ id: nodeId
2567
+ });
2568
+ if (isDebugEnabled()) {
2569
+ console.log(`[BPMN] findClearMidX: obstacle ${nodeId}: x=[${nodeLeft}, ${nodeRight}], y=[${nodeTop}, ${nodeBottom}]`);
2570
+ }
2571
+ }
2572
+ }
2573
+ if (allObstacles.length === 0) {
2574
+ return (startX + endX) / 2;
2575
+ }
2576
+ const isValidMidX = (midX) => {
2577
+ for (const obs of allObstacles) {
2578
+ const seg1MinX = Math.min(startX, midX);
2579
+ const seg1MaxX = Math.max(startX, midX);
2580
+ if (obs.y <= startY && obs.bottom >= startY && // Y range contains startY
2581
+ obs.right > seg1MinX && obs.x < seg1MaxX) {
2582
+ return false;
2583
+ }
2584
+ if (obs.x <= midX && obs.right >= midX && // X range contains midX
2585
+ obs.bottom > minY && obs.y < maxY) {
2586
+ return false;
2587
+ }
2588
+ const seg2MinX = Math.min(midX, endX);
2589
+ const seg2MaxX = Math.max(midX, endX);
2590
+ if (obs.y <= endY && obs.bottom >= endY && // Y range contains endY
2591
+ obs.right > seg2MinX && obs.x < seg2MaxX) {
2592
+ return false;
2593
+ }
2594
+ }
2595
+ return true;
2596
+ };
2597
+ const candidates = [];
2598
+ candidates.push((startX + endX) / 2);
2599
+ candidates.push(startX + margin);
2600
+ candidates.push(endX - margin);
2601
+ for (const obs of allObstacles) {
2602
+ candidates.push(obs.x - margin);
2603
+ candidates.push(obs.right + margin);
2604
+ }
2605
+ const simpleMidX = (startX + endX) / 2;
2606
+ const validCandidates = candidates.filter((x) => x >= rangeMinX && x <= rangeMaxX).sort((a, b) => Math.abs(a - simpleMidX) - Math.abs(b - simpleMidX));
2607
+ for (const candidate of validCandidates) {
2608
+ if (isValidMidX(candidate)) {
2609
+ if (isDebugEnabled()) {
2610
+ console.log(`[BPMN] findClearMidX: found valid position ${candidate}`);
2611
+ }
2612
+ return candidate;
2613
+ }
2614
+ }
2615
+ const leftMost = Math.min(...allObstacles.map((o) => o.x)) - margin;
2616
+ const rightMost = Math.max(...allObstacles.map((o) => o.right)) + margin;
2617
+ if (leftMost >= rangeMinX && isValidMidX(leftMost)) {
2618
+ if (isDebugEnabled()) {
2619
+ console.log(`[BPMN] findClearMidX: routing left of all obstacles at ${leftMost}`);
2620
+ }
2621
+ return leftMost;
2622
+ }
2623
+ if (rightMost <= rangeMaxX && isValidMidX(rightMost)) {
2624
+ if (isDebugEnabled()) {
2625
+ console.log(`[BPMN] findClearMidX: routing right of all obstacles at ${rightMost}`);
2626
+ }
2627
+ return rightMost;
2628
+ }
2629
+ if (isDebugEnabled()) {
2630
+ console.log(`[BPMN] findClearMidX: no valid route found, using midpoint ${simpleMidX}`);
2631
+ }
2632
+ return simpleMidX;
2633
+ }
2513
2634
  };
2514
2635
 
2515
2636
  // src/layout/post-processing/pool-arranger.ts
@@ -2590,7 +2711,7 @@ var PoolArranger = class {
2590
2711
  pool.y = currentY;
2591
2712
  if (isBlackBox) {
2592
2713
  pool.width = maxPoolWidth;
2593
- pool.height = pool.height ?? 60;
2714
+ pool.height = 60;
2594
2715
  } else if (hasLanes) {
2595
2716
  pool.width = maxPoolWidth;
2596
2717
  } else {
@@ -3005,7 +3126,7 @@ var GatewayEdgeAdjuster = class {
3005
3126
  const gateways = /* @__PURE__ */ new Map();
3006
3127
  this.collectGateways(layoutedGraph, originalGraph, gateways, 0, 0);
3007
3128
  if (gateways.size === 0) return;
3008
- if (DEBUG) {
3129
+ if (isDebugEnabled()) {
3009
3130
  console.log(`[BPMN] GatewayEdgeAdjuster: Found ${gateways.size} gateways`);
3010
3131
  for (const [id, info] of gateways) {
3011
3132
  console.log(`[BPMN] - ${id}: bounds=(${info.bounds.x},${info.bounds.y},${info.bounds.width},${info.bounds.height})`);
@@ -3092,7 +3213,7 @@ var GatewayEdgeAdjuster = class {
3092
3213
  const section = edge.sections[0];
3093
3214
  const sourceId = edge.sources?.[0];
3094
3215
  const targetId = edge.targets?.[0];
3095
- if (DEBUG) {
3216
+ if (isDebugEnabled()) {
3096
3217
  console.log(`[BPMN] GatewayEdgeAdjuster: Processing edge ${edge.id}, offset=(${offsetX},${offsetY})`);
3097
3218
  console.log(`[BPMN] sourceId=${sourceId}, targetId=${targetId}`);
3098
3219
  console.log(`[BPMN] startPoint=(${section.startPoint.x},${section.startPoint.y}), endPoint=(${section.endPoint.x},${section.endPoint.y})`);
@@ -3104,7 +3225,7 @@ var GatewayEdgeAdjuster = class {
3104
3225
  }
3105
3226
  const targetGateway = targetId ? gateways.get(targetId) : void 0;
3106
3227
  if (targetGateway) {
3107
- if (DEBUG) {
3228
+ if (isDebugEnabled()) {
3108
3229
  console.log(`[BPMN] target gateway: ${targetId}, bounds=(${targetGateway.bounds.x},${targetGateway.bounds.y})`);
3109
3230
  console.log(`[BPMN] left corner: (${targetGateway.corners.left.x},${targetGateway.corners.left.y})`);
3110
3231
  }
@@ -3175,7 +3296,7 @@ var GatewayEdgeAdjuster = class {
3175
3296
  lastBend.x = newEnd.x;
3176
3297
  }
3177
3298
  }
3178
- if (DEBUG) {
3299
+ if (isDebugEnabled()) {
3179
3300
  console.log(`[BPMN] GatewayEdgeAdjuster: Adjusted edge ${edge.id} endpoint from (${endX},${endY}) to (${targetCorner.x},${targetCorner.y})`);
3180
3301
  }
3181
3302
  } else {
@@ -3189,7 +3310,7 @@ var GatewayEdgeAdjuster = class {
3189
3310
  x: intersectionPoint.x - offsetX,
3190
3311
  y: intersectionPoint.y - offsetY
3191
3312
  };
3192
- if (DEBUG) {
3313
+ if (isDebugEnabled()) {
3193
3314
  console.log(`[BPMN] GatewayEdgeAdjuster: Adjusted edge ${edge.id} endpoint to diamond intersection (${intersectionPoint.x},${intersectionPoint.y})`);
3194
3315
  }
3195
3316
  }
@@ -3449,7 +3570,7 @@ var ElkGraphPreparer = class {
3449
3570
  for (const startId of startEvents) {
3450
3571
  traverseMainFlow(startId);
3451
3572
  }
3452
- if (DEBUG) {
3573
+ if (isDebugEnabled()) {
3453
3574
  console.log(`[BPMN] Main flow nodes: ${Array.from(mainFlowNodes).join(", ")}`);
3454
3575
  }
3455
3576
  return mainFlowNodes;
@@ -3784,7 +3905,7 @@ var ResultMerger = class {
3784
3905
  return originalEdges.map((origEdge) => {
3785
3906
  const layoutedEdge = layoutedEdgeMap.get(origEdge.id);
3786
3907
  if (layoutedEdge) {
3787
- if (DEBUG && layoutedEdge.sections?.[0]?.bendPoints?.length) {
3908
+ if (isDebugEnabled() && layoutedEdge.sections?.[0]?.bendPoints?.length) {
3788
3909
  console.log(`[BPMN] Merge ${origEdge.id}: bendPoints=${JSON.stringify(layoutedEdge.sections[0].bendPoints)}`);
3789
3910
  }
3790
3911
  const mergedEdge = {
@@ -3922,7 +4043,7 @@ var MainFlowNormalizer = class {
3922
4043
  return;
3923
4044
  }
3924
4045
  const offsetY = currentMinY - TARGET_MAIN_FLOW_Y;
3925
- if (DEBUG) {
4046
+ if (isDebugEnabled()) {
3926
4047
  console.log(`[BPMN] Normalizing main flow: currentMinY=${currentMinY}, offsetY=${offsetY}`);
3927
4048
  console.log(`[BPMN] Upstream nodes: ${upstreamMainFlow.map((n) => n.id).join(", ")}`);
3928
4049
  console.log(`[BPMN] Downstream nodes: ${downstreamMainFlow.map((n) => n.id).join(", ")}`);
@@ -3930,7 +4051,7 @@ var MainFlowNormalizer = class {
3930
4051
  for (const node of otherUpstreamNodes) {
3931
4052
  if (node.y !== void 0) {
3932
4053
  node.y -= offsetY;
3933
- if (DEBUG) {
4054
+ if (isDebugEnabled()) {
3934
4055
  console.log(`[BPMN] Shifted upstream ${node.id} to y=${node.y}`);
3935
4056
  }
3936
4057
  }
@@ -3943,14 +4064,14 @@ var MainFlowNormalizer = class {
3943
4064
  const predecessorCenterY = predecessor.y + (predecessor.height ?? 80) / 2;
3944
4065
  const endNodeCenterY = (endNode.height ?? 36) / 2;
3945
4066
  endNode.y = predecessorCenterY - endNodeCenterY;
3946
- if (DEBUG) {
4067
+ if (isDebugEnabled()) {
3947
4068
  console.log(`[BPMN] Aligned endEvent ${endNode.id} with predecessor ${predecessorId}: y=${endNode.y}`);
3948
4069
  }
3949
4070
  }
3950
4071
  } else {
3951
4072
  if (endNode.y !== void 0) {
3952
4073
  endNode.y -= offsetY;
3953
- if (DEBUG) {
4074
+ if (isDebugEnabled()) {
3954
4075
  console.log(`[BPMN] Shifted upstream ${endNode.id} to y=${endNode.y} (no predecessor found)`);
3955
4076
  }
3956
4077
  }
@@ -3978,7 +4099,7 @@ var MainFlowNormalizer = class {
3978
4099
  const newY = prevBottom + MIN_SPACING;
3979
4100
  currNode.y = newY;
3980
4101
  adjustedEndEvents.set(currNode.id, newY);
3981
- if (DEBUG) {
4102
+ if (isDebugEnabled()) {
3982
4103
  console.log(`[BPMN] Adjusted overlapping endEvent ${currNode.id} at x=${x}: y=${currNode.y}`);
3983
4104
  }
3984
4105
  }
@@ -4002,7 +4123,7 @@ var MainFlowNormalizer = class {
4002
4123
  for (const node of downstreamMainFlow) {
4003
4124
  if (node.y !== void 0) {
4004
4125
  node.y -= downstreamOffsetY;
4005
- if (DEBUG) {
4126
+ if (isDebugEnabled()) {
4006
4127
  console.log(`[BPMN] Shifted downstream ${node.id} to y=${node.y}`);
4007
4128
  }
4008
4129
  }
@@ -4184,20 +4305,20 @@ var MainFlowNormalizer = class {
4184
4305
  lastBend.y = newTargetY;
4185
4306
  section.endPoint.y = newTargetY;
4186
4307
  edgesWithAdjustedEndpoint.add(edge.id);
4187
- if (DEBUG) {
4308
+ if (isDebugEnabled()) {
4188
4309
  console.log(`[BPMN] Updated edge ${edge.id} last bendPoint and endpoint to y=${newTargetY}`);
4189
4310
  }
4190
4311
  } else {
4191
4312
  section.endPoint.y = newTargetY;
4192
4313
  edgesWithAdjustedEndpoint.add(edge.id);
4193
- if (DEBUG) {
4314
+ if (isDebugEnabled()) {
4194
4315
  console.log(`[BPMN] Updated edge ${edge.id} endpoint to y=${newTargetY}`);
4195
4316
  }
4196
4317
  }
4197
4318
  } else if (section.endPoint) {
4198
4319
  section.endPoint.y = newTargetY;
4199
4320
  edgesWithAdjustedEndpoint.add(edge.id);
4200
- if (DEBUG) {
4321
+ if (isDebugEnabled()) {
4201
4322
  console.log(`[BPMN] Updated edge ${edge.id} endpoint to y=${newTargetY}`);
4202
4323
  }
4203
4324
  }
@@ -4311,7 +4432,7 @@ var GatewayPropagator = class {
4311
4432
  offset: 0,
4312
4433
  newX
4313
4434
  });
4314
- if (DEBUG) {
4435
+ if (isDebugEnabled()) {
4315
4436
  console.log(`[BPMN] Propagating gateway movement to ${targetId}: x ${currentX} -> ${newX}`);
4316
4437
  }
4317
4438
  this.propagateDownstreamX(targetId, newX, targetNode.width ?? 100, nodeMap, edgeMap, mainFlowNodes, gatewayMoves);
@@ -4339,7 +4460,7 @@ var GatewayPropagator = class {
4339
4460
  offset: 0,
4340
4461
  newX
4341
4462
  });
4342
- if (DEBUG) {
4463
+ if (isDebugEnabled()) {
4343
4464
  console.log(`[BPMN] Propagating X to ${targetId}: x ${currentX} -> ${newX}`);
4344
4465
  }
4345
4466
  this.propagateDownstreamX(targetId, newX, targetNode.width ?? 100, nodeMap, edgeMap, mainFlowNodes, moves);
@@ -4394,14 +4515,14 @@ var ElkLayouter = class {
4394
4515
  const layoutedElkGraph = await this.elk.layout(elkGraph);
4395
4516
  const mainFlowNodes = this.graphPreparer.identifyMainFlowNodes(sizedGraph, boundaryEventTargetIds);
4396
4517
  this.mainFlowNormalizer.normalize(layoutedElkGraph, mainFlowNodes, boundaryEventTargetIds, sizedGraph);
4397
- const movedNodes = this.boundaryEventHandler.identifyNodesToMove(layoutedElkGraph, boundaryEventInfo, sizedGraph, DEBUG);
4518
+ const movedNodes = this.boundaryEventHandler.identifyNodesToMove(layoutedElkGraph, boundaryEventInfo, sizedGraph, isDebugEnabled());
4398
4519
  if (movedNodes.size > 0) {
4399
4520
  this.boundaryEventHandler.applyNodeMoves(layoutedElkGraph, movedNodes);
4400
4521
  const gatewayMoves = this.boundaryEventHandler.repositionConvergingGateways(
4401
4522
  layoutedElkGraph,
4402
4523
  movedNodes,
4403
4524
  boundaryEventInfo,
4404
- DEBUG
4525
+ isDebugEnabled()
4405
4526
  );
4406
4527
  if (gatewayMoves.size > 0) {
4407
4528
  this.boundaryEventHandler.applyNodeMoves(layoutedElkGraph, gatewayMoves);
@@ -4410,7 +4531,7 @@ var ElkLayouter = class {
4410
4531
  for (const [id, move] of gatewayMoves) {
4411
4532
  movedNodes.set(id, move);
4412
4533
  }
4413
- this.boundaryEventHandler.recalculateEdgesForMovedNodes(layoutedElkGraph, movedNodes, boundaryEventInfo, DEBUG);
4534
+ this.boundaryEventHandler.recalculateEdgesForMovedNodes(layoutedElkGraph, movedNodes, boundaryEventInfo);
4414
4535
  }
4415
4536
  this.artifactPositioner.reposition(layoutedElkGraph, artifactInfo);
4416
4537
  this.laneArranger.rearrange(layoutedElkGraph, sizedGraph);
@@ -4684,7 +4805,7 @@ function adjustGatewayEndpoint(endpoint, adjacentPoint, gatewayBounds, isSource)
4684
4805
  const gatewayCenterX = gatewayBounds.x + gatewayBounds.width / 2;
4685
4806
  const gatewayCenterY = gatewayBounds.y + gatewayBounds.height / 2;
4686
4807
  const tolerance = 1;
4687
- if (DEBUG) {
4808
+ if (isDebugEnabled()) {
4688
4809
  console.log(`[BPMN] adjustGatewayEndpoint: isSource=${isSource}`);
4689
4810
  console.log(` endpoint: (${endpoint.x}, ${endpoint.y})`);
4690
4811
  console.log(` gatewayBounds: x=${gatewayBounds.x}, y=${gatewayBounds.y}, w=${gatewayBounds.width}, h=${gatewayBounds.height}`);
@@ -4696,22 +4817,22 @@ function adjustGatewayEndpoint(endpoint, adjacentPoint, gatewayBounds, isSource)
4696
4817
  const topCorner = { x: gatewayCenterX, y: gatewayBounds.y };
4697
4818
  const bottomCorner = { x: gatewayCenterX, y: gatewayBounds.y + gatewayBounds.height };
4698
4819
  if (Math.abs(endpoint.x - gatewayBounds.x) < tolerance && Math.abs(endpoint.y - gatewayCenterY) < tolerance) {
4699
- if (DEBUG) console.log(` -> Already at LEFT corner, no adjustment`);
4820
+ if (isDebugEnabled()) console.log(` -> Already at LEFT corner, no adjustment`);
4700
4821
  return endpoint;
4701
4822
  }
4702
4823
  if (Math.abs(endpoint.x - (gatewayBounds.x + gatewayBounds.width)) < tolerance && Math.abs(endpoint.y - gatewayCenterY) < tolerance) {
4703
- if (DEBUG) console.log(` -> Already at RIGHT corner, no adjustment`);
4824
+ if (isDebugEnabled()) console.log(` -> Already at RIGHT corner, no adjustment`);
4704
4825
  return endpoint;
4705
4826
  }
4706
4827
  if (Math.abs(endpoint.y - gatewayBounds.y) < tolerance && Math.abs(endpoint.x - gatewayCenterX) < tolerance) {
4707
- if (DEBUG) console.log(` -> Already at TOP corner, no adjustment`);
4828
+ if (isDebugEnabled()) console.log(` -> Already at TOP corner, no adjustment`);
4708
4829
  return endpoint;
4709
4830
  }
4710
4831
  if (Math.abs(endpoint.y - (gatewayBounds.y + gatewayBounds.height)) < tolerance && Math.abs(endpoint.x - gatewayCenterX) < tolerance) {
4711
- if (DEBUG) console.log(` -> Already at BOTTOM corner, no adjustment`);
4832
+ if (isDebugEnabled()) console.log(` -> Already at BOTTOM corner, no adjustment`);
4712
4833
  return endpoint;
4713
4834
  }
4714
- if (DEBUG) {
4835
+ if (isDebugEnabled()) {
4715
4836
  console.log(` -> NOT at corner, will adjust`);
4716
4837
  }
4717
4838
  const result = calculateDiamondIntersection(
@@ -4722,7 +4843,7 @@ function adjustGatewayEndpoint(endpoint, adjacentPoint, gatewayBounds, isSource)
4722
4843
  isSource,
4723
4844
  adjacentPoint
4724
4845
  );
4725
- if (DEBUG) {
4846
+ if (isDebugEnabled()) {
4726
4847
  console.log(` -> Adjusted to: (${result.x}, ${result.y})`);
4727
4848
  }
4728
4849
  return result;
@@ -5027,7 +5148,7 @@ var DiagramBuilder = class {
5027
5148
  const targetIsGateway = this.isGatewayType(targetNode?.type);
5028
5149
  let waypoints = [];
5029
5150
  const hasPreCalculatedSections = edge.sections && edge.sections.length > 0 && edge.sections[0]?.bendPoints && edge.sections[0].bendPoints.length > 0;
5030
- if (DEBUG && bePosition) {
5151
+ if (isDebugEnabled() && bePosition) {
5031
5152
  console.log(`[BPMN] buildEdge ${edge.id}: preCalculated=${hasPreCalculatedSections}`);
5032
5153
  }
5033
5154
  if (bePosition && targetPosition && !hasPreCalculatedSections) {
@@ -5102,6 +5223,7 @@ var DiagramBuilder = class {
5102
5223
  }
5103
5224
  }
5104
5225
  }
5226
+ this.ensureOrthogonalWaypoints(waypoints);
5105
5227
  const edgeModel = {
5106
5228
  id: `${edge.id}_di`,
5107
5229
  bpmnElement: edge.id,
@@ -5168,6 +5290,36 @@ var DiagramBuilder = class {
5168
5290
  y: (lastPoint?.y ?? 0) - labelHeight - 4
5169
5291
  };
5170
5292
  }
5293
+ /**
5294
+ * Ensure all waypoint segments are orthogonal (horizontal or vertical)
5295
+ * If a diagonal segment is found, insert intermediate bend points to create
5296
+ * an L-shaped orthogonal path.
5297
+ *
5298
+ * Strategy: For diagonal segments, we use "horizontal first" - go horizontally
5299
+ * to the target X, then vertically to the target Y.
5300
+ */
5301
+ ensureOrthogonalWaypoints(waypoints) {
5302
+ if (waypoints.length < 2) return;
5303
+ const tolerance = 1;
5304
+ let i = 0;
5305
+ while (i < waypoints.length - 1) {
5306
+ const current = waypoints[i];
5307
+ const next = waypoints[i + 1];
5308
+ if (!current || !next) {
5309
+ i++;
5310
+ continue;
5311
+ }
5312
+ const dx = Math.abs(next.x - current.x);
5313
+ const dy = Math.abs(next.y - current.y);
5314
+ if (dx > tolerance && dy > tolerance) {
5315
+ const bendPoint = { x: next.x, y: current.y };
5316
+ waypoints.splice(i + 1, 0, bendPoint);
5317
+ i++;
5318
+ } else {
5319
+ i++;
5320
+ }
5321
+ }
5322
+ }
5171
5323
  };
5172
5324
 
5173
5325
  // src/transform/model-builder.ts