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.
@@ -304,7 +304,11 @@ function lineIntersection(p1, p2, p3, p4) {
304
304
  }
305
305
 
306
306
  // src/utils/debug.ts
307
- var DEBUG = typeof process !== "undefined" && process.env?.["DEBUG"] === "true";
307
+ var cliMode = false;
308
+ function isDebugEnabled() {
309
+ if (cliMode) return false;
310
+ return typeof process !== "undefined" && process.env?.["DEBUG"] === "true";
311
+ }
308
312
 
309
313
  // src/layout/edge-routing/edge-fixer.ts
310
314
  var EdgeFixer = class {
@@ -337,7 +341,7 @@ var EdgeFixer = class {
337
341
  const isFlowNode = flowNodePatterns.some((pattern) => pattern.test(id));
338
342
  const isPool = poolPatterns.some((pattern) => pattern.test(id));
339
343
  const bpmn = node.bpmn;
340
- if (DEBUG && (id.includes("lane") || id.includes("pool") || id.includes("end_fast") || id.includes("gateway_fast"))) {
344
+ if (isDebugEnabled() && (id.includes("lane") || id.includes("pool") || id.includes("end_fast") || id.includes("gateway_fast"))) {
341
345
  console.log(`[BPMN] EdgeFixer.collectNodePositions: id=${id}, offsetX=${offsetX}, offsetY=${offsetY}, bpmn=${JSON.stringify(bpmn)}`);
342
346
  console.log(`[BPMN] node.x=${node.x}, node.y=${node.y}, isFlowNode=${isFlowNode}, isPool=${isPool}`);
343
347
  }
@@ -375,6 +379,10 @@ var EdgeFixer = class {
375
379
  const containerNodes = nodesByContainer.get(currentContainerId) ?? /* @__PURE__ */ new Map();
376
380
  for (const edge of node.edges) {
377
381
  if (edge.sections && edge.sections.length > 0) {
382
+ const hasPoolRelativeCoords = edge._poolRelativeCoords === true;
383
+ if (hasPoolRelativeCoords) {
384
+ continue;
385
+ }
378
386
  this.fixEdgeIfCrossing(edge, containerNodes, containerOffsetX, containerOffsetY);
379
387
  }
380
388
  }
@@ -426,7 +434,7 @@ var EdgeFixer = class {
426
434
  }
427
435
  const targetPos = targetId ? nodePositions.get(targetId) : void 0;
428
436
  const sourcePos = sourceId ? nodePositions.get(sourceId) : void 0;
429
- if (DEBUG && edge.id?.includes("back")) {
437
+ if (isDebugEnabled() && edge.id?.includes("back")) {
430
438
  console.log(`[BPMN] Edge ${edge.id}: sourceId=${sourceId}, targetId=${targetId}`);
431
439
  console.log(`[BPMN] Edge ${edge.id}: sourcePos=${JSON.stringify(sourcePos)}, targetPos=${JSON.stringify(targetPos)}`);
432
440
  console.log(`[BPMN] Edge ${edge.id}: waypoints.length=${waypoints.length}`);
@@ -435,7 +443,7 @@ var EdgeFixer = class {
435
443
  const lastWaypoint = waypoints[waypoints.length - 1];
436
444
  const secondLastWaypoint = waypoints[waypoints.length - 2];
437
445
  const isReturnEdge2 = targetPos.y + targetPos.height < sourcePos.y;
438
- if (DEBUG && edge.id?.includes("back")) {
446
+ if (isDebugEnabled() && edge.id?.includes("back")) {
439
447
  console.log(`[BPMN] Edge ${edge.id}: isReturnEdge=${isReturnEdge2}`);
440
448
  if (lastWaypoint) {
441
449
  console.log(`[BPMN] Edge ${edge.id}: lastWaypoint=(${lastWaypoint.x},${lastWaypoint.y})`);
@@ -455,7 +463,7 @@ var EdgeFixer = class {
455
463
  }
456
464
  }
457
465
  if (crossedNodes.length === 0) return;
458
- if (DEBUG) {
466
+ if (isDebugEnabled()) {
459
467
  console.log(`[BPMN] Edge ${edge.id} crosses nodes: ${crossedNodes.join(", ")}`);
460
468
  }
461
469
  if (!sourcePos || !targetPos) return;
@@ -506,7 +514,7 @@ var EdgeFixer = class {
506
514
  y: bp.y - containerOffsetY
507
515
  }));
508
516
  section.bendPoints = relativeBendPoints.length > 0 ? relativeBendPoints : void 0;
509
- if (DEBUG) {
517
+ if (isDebugEnabled()) {
510
518
  console.log(`[BPMN] Fixed edge ${edge.id} with ${relativeBendPoints.length} bend points`);
511
519
  }
512
520
  }
@@ -1296,7 +1304,8 @@ function applyNodeMoves(graph, movedNodes) {
1296
1304
  }
1297
1305
 
1298
1306
  // src/layout/post-processing/boundary-event/edge-recalculator.ts
1299
- function recalculateEdgesForMovedNodes(graph, movedNodes, boundaryEventInfo, debug = false) {
1307
+ function recalculateEdgesForMovedNodes(graph, movedNodes, boundaryEventInfo) {
1308
+ const debug = isDebugEnabled();
1300
1309
  const nodeMap = /* @__PURE__ */ new Map();
1301
1310
  const buildNodeMap2 = (node) => {
1302
1311
  nodeMap.set(node.id, node);
@@ -1373,7 +1382,8 @@ function recalculateEdgesForMovedNodes(graph, movedNodes, boundaryEventInfo, deb
1373
1382
  };
1374
1383
  processEdges(graph);
1375
1384
  }
1376
- function recalculateEdgeWithObstacleAvoidance(edge, source, target, obstacleIds, nodeMap, debug = false) {
1385
+ function recalculateEdgeWithObstacleAvoidance(edge, source, target, obstacleIds, nodeMap) {
1386
+ const debug = isDebugEnabled();
1377
1387
  const sx = source.x ?? 0;
1378
1388
  const sy = source.y ?? 0;
1379
1389
  const sw = source.width ?? 100;
@@ -1594,8 +1604,8 @@ var BoundaryEventHandler = class {
1594
1604
  /**
1595
1605
  * Recalculate edge waypoints for edges connected to moved nodes
1596
1606
  */
1597
- recalculateEdgesForMovedNodes(graph, movedNodes, boundaryEventInfo, debug = false) {
1598
- recalculateEdgesForMovedNodes(graph, movedNodes, boundaryEventInfo, debug);
1607
+ recalculateEdgesForMovedNodes(graph, movedNodes, boundaryEventInfo) {
1608
+ recalculateEdgesForMovedNodes(graph, movedNodes, boundaryEventInfo);
1599
1609
  }
1600
1610
  };
1601
1611
 
@@ -2482,7 +2492,7 @@ var LaneArranger = class {
2482
2492
  const targetId = edge.targets?.[0];
2483
2493
  const sourcePos = sourceId ? nodePositions.get(sourceId) : void 0;
2484
2494
  const targetPos = targetId ? nodePositions.get(targetId) : void 0;
2485
- if (DEBUG) {
2495
+ if (isDebugEnabled()) {
2486
2496
  console.log(`[BPMN] recalculatePoolEdges ${edge.id}: source=${sourceId}, target=${targetId}`);
2487
2497
  console.log(`[BPMN] sourcePos=${JSON.stringify(sourcePos)}`);
2488
2498
  console.log(`[BPMN] targetPos=${JSON.stringify(targetPos)}`);
@@ -2492,18 +2502,26 @@ var LaneArranger = class {
2492
2502
  const startY = sourcePos.y + sourcePos.height / 2;
2493
2503
  const endX = targetPos.x;
2494
2504
  const endY = targetPos.y + targetPos.height / 2;
2495
- if (DEBUG) {
2505
+ if (isDebugEnabled()) {
2496
2506
  console.log(`[BPMN] startX=${startX}, startY=${startY}, endX=${endX}, endY=${endY}`);
2497
2507
  }
2498
2508
  const waypoints = [];
2499
2509
  waypoints.push({ x: startX, y: startY });
2500
2510
  if (Math.abs(startY - endY) > 10) {
2501
- const midX = (startX + endX) / 2;
2511
+ const midX = this.findClearMidX(
2512
+ startX,
2513
+ endX,
2514
+ startY,
2515
+ endY,
2516
+ sourceId,
2517
+ targetId,
2518
+ nodePositions
2519
+ );
2502
2520
  waypoints.push({ x: midX, y: startY });
2503
2521
  waypoints.push({ x: midX, y: endY });
2504
2522
  }
2505
2523
  waypoints.push({ x: endX, y: endY });
2506
- if (DEBUG) {
2524
+ if (isDebugEnabled()) {
2507
2525
  console.log(`[BPMN] waypoints=${JSON.stringify(waypoints)}`);
2508
2526
  }
2509
2527
  edge._poolRelativeCoords = true;
@@ -2516,6 +2534,109 @@ var LaneArranger = class {
2516
2534
  }
2517
2535
  }
2518
2536
  }
2537
+ /**
2538
+ * Find a clear X position for vertical edge segment that avoids obstacles.
2539
+ * Checks all three segments of the L-shaped path:
2540
+ * 1. Horizontal from (startX, startY) to (midX, startY)
2541
+ * 2. Vertical from (midX, startY) to (midX, endY)
2542
+ * 3. Horizontal from (midX, endY) to (endX, endY)
2543
+ */
2544
+ findClearMidX(startX, endX, startY, endY, sourceId, targetId, nodePositions) {
2545
+ const margin = 15;
2546
+ const minY = Math.min(startY, endY);
2547
+ const maxY = Math.max(startY, endY);
2548
+ const rangeMinX = Math.min(startX, endX);
2549
+ const rangeMaxX = Math.max(startX, endX);
2550
+ if (isDebugEnabled()) {
2551
+ console.log(`[BPMN] findClearMidX: startX=${startX}, endX=${endX}, startY=${startY}, endY=${endY}`);
2552
+ }
2553
+ const allObstacles = [];
2554
+ for (const [nodeId, pos] of nodePositions) {
2555
+ if (nodeId === sourceId || nodeId === targetId) continue;
2556
+ const nodeLeft = pos.x;
2557
+ const nodeRight = pos.x + pos.width;
2558
+ const nodeTop = pos.y;
2559
+ const nodeBottom = pos.y + pos.height;
2560
+ const xOverlap = nodeRight > rangeMinX && nodeLeft < rangeMaxX;
2561
+ const yOverlapVertical = nodeBottom > minY && nodeTop < maxY;
2562
+ const yContainsStartY = nodeTop <= startY && nodeBottom >= startY;
2563
+ const yContainsEndY = nodeTop <= endY && nodeBottom >= endY;
2564
+ if (xOverlap && (yOverlapVertical || yContainsStartY || yContainsEndY)) {
2565
+ allObstacles.push({
2566
+ x: nodeLeft,
2567
+ y: nodeTop,
2568
+ width: pos.width,
2569
+ height: pos.height,
2570
+ right: nodeRight,
2571
+ bottom: nodeBottom,
2572
+ id: nodeId
2573
+ });
2574
+ if (isDebugEnabled()) {
2575
+ console.log(`[BPMN] findClearMidX: obstacle ${nodeId}: x=[${nodeLeft}, ${nodeRight}], y=[${nodeTop}, ${nodeBottom}]`);
2576
+ }
2577
+ }
2578
+ }
2579
+ if (allObstacles.length === 0) {
2580
+ return (startX + endX) / 2;
2581
+ }
2582
+ const isValidMidX = (midX) => {
2583
+ for (const obs of allObstacles) {
2584
+ const seg1MinX = Math.min(startX, midX);
2585
+ const seg1MaxX = Math.max(startX, midX);
2586
+ if (obs.y <= startY && obs.bottom >= startY && // Y range contains startY
2587
+ obs.right > seg1MinX && obs.x < seg1MaxX) {
2588
+ return false;
2589
+ }
2590
+ if (obs.x <= midX && obs.right >= midX && // X range contains midX
2591
+ obs.bottom > minY && obs.y < maxY) {
2592
+ return false;
2593
+ }
2594
+ const seg2MinX = Math.min(midX, endX);
2595
+ const seg2MaxX = Math.max(midX, endX);
2596
+ if (obs.y <= endY && obs.bottom >= endY && // Y range contains endY
2597
+ obs.right > seg2MinX && obs.x < seg2MaxX) {
2598
+ return false;
2599
+ }
2600
+ }
2601
+ return true;
2602
+ };
2603
+ const candidates = [];
2604
+ candidates.push((startX + endX) / 2);
2605
+ candidates.push(startX + margin);
2606
+ candidates.push(endX - margin);
2607
+ for (const obs of allObstacles) {
2608
+ candidates.push(obs.x - margin);
2609
+ candidates.push(obs.right + margin);
2610
+ }
2611
+ const simpleMidX = (startX + endX) / 2;
2612
+ const validCandidates = candidates.filter((x) => x >= rangeMinX && x <= rangeMaxX).sort((a, b) => Math.abs(a - simpleMidX) - Math.abs(b - simpleMidX));
2613
+ for (const candidate of validCandidates) {
2614
+ if (isValidMidX(candidate)) {
2615
+ if (isDebugEnabled()) {
2616
+ console.log(`[BPMN] findClearMidX: found valid position ${candidate}`);
2617
+ }
2618
+ return candidate;
2619
+ }
2620
+ }
2621
+ const leftMost = Math.min(...allObstacles.map((o) => o.x)) - margin;
2622
+ const rightMost = Math.max(...allObstacles.map((o) => o.right)) + margin;
2623
+ if (leftMost >= rangeMinX && isValidMidX(leftMost)) {
2624
+ if (isDebugEnabled()) {
2625
+ console.log(`[BPMN] findClearMidX: routing left of all obstacles at ${leftMost}`);
2626
+ }
2627
+ return leftMost;
2628
+ }
2629
+ if (rightMost <= rangeMaxX && isValidMidX(rightMost)) {
2630
+ if (isDebugEnabled()) {
2631
+ console.log(`[BPMN] findClearMidX: routing right of all obstacles at ${rightMost}`);
2632
+ }
2633
+ return rightMost;
2634
+ }
2635
+ if (isDebugEnabled()) {
2636
+ console.log(`[BPMN] findClearMidX: no valid route found, using midpoint ${simpleMidX}`);
2637
+ }
2638
+ return simpleMidX;
2639
+ }
2519
2640
  };
2520
2641
 
2521
2642
  // src/layout/post-processing/pool-arranger.ts
@@ -2596,7 +2717,7 @@ var PoolArranger = class {
2596
2717
  pool.y = currentY;
2597
2718
  if (isBlackBox) {
2598
2719
  pool.width = maxPoolWidth;
2599
- pool.height = pool.height ?? 60;
2720
+ pool.height = 60;
2600
2721
  } else if (hasLanes) {
2601
2722
  pool.width = maxPoolWidth;
2602
2723
  } else {
@@ -3011,7 +3132,7 @@ var GatewayEdgeAdjuster = class {
3011
3132
  const gateways = /* @__PURE__ */ new Map();
3012
3133
  this.collectGateways(layoutedGraph, originalGraph, gateways, 0, 0);
3013
3134
  if (gateways.size === 0) return;
3014
- if (DEBUG) {
3135
+ if (isDebugEnabled()) {
3015
3136
  console.log(`[BPMN] GatewayEdgeAdjuster: Found ${gateways.size} gateways`);
3016
3137
  for (const [id, info] of gateways) {
3017
3138
  console.log(`[BPMN] - ${id}: bounds=(${info.bounds.x},${info.bounds.y},${info.bounds.width},${info.bounds.height})`);
@@ -3098,7 +3219,7 @@ var GatewayEdgeAdjuster = class {
3098
3219
  const section = edge.sections[0];
3099
3220
  const sourceId = edge.sources?.[0];
3100
3221
  const targetId = edge.targets?.[0];
3101
- if (DEBUG) {
3222
+ if (isDebugEnabled()) {
3102
3223
  console.log(`[BPMN] GatewayEdgeAdjuster: Processing edge ${edge.id}, offset=(${offsetX},${offsetY})`);
3103
3224
  console.log(`[BPMN] sourceId=${sourceId}, targetId=${targetId}`);
3104
3225
  console.log(`[BPMN] startPoint=(${section.startPoint.x},${section.startPoint.y}), endPoint=(${section.endPoint.x},${section.endPoint.y})`);
@@ -3110,7 +3231,7 @@ var GatewayEdgeAdjuster = class {
3110
3231
  }
3111
3232
  const targetGateway = targetId ? gateways.get(targetId) : void 0;
3112
3233
  if (targetGateway) {
3113
- if (DEBUG) {
3234
+ if (isDebugEnabled()) {
3114
3235
  console.log(`[BPMN] target gateway: ${targetId}, bounds=(${targetGateway.bounds.x},${targetGateway.bounds.y})`);
3115
3236
  console.log(`[BPMN] left corner: (${targetGateway.corners.left.x},${targetGateway.corners.left.y})`);
3116
3237
  }
@@ -3181,7 +3302,7 @@ var GatewayEdgeAdjuster = class {
3181
3302
  lastBend.x = newEnd.x;
3182
3303
  }
3183
3304
  }
3184
- if (DEBUG) {
3305
+ if (isDebugEnabled()) {
3185
3306
  console.log(`[BPMN] GatewayEdgeAdjuster: Adjusted edge ${edge.id} endpoint from (${endX},${endY}) to (${targetCorner.x},${targetCorner.y})`);
3186
3307
  }
3187
3308
  } else {
@@ -3195,7 +3316,7 @@ var GatewayEdgeAdjuster = class {
3195
3316
  x: intersectionPoint.x - offsetX,
3196
3317
  y: intersectionPoint.y - offsetY
3197
3318
  };
3198
- if (DEBUG) {
3319
+ if (isDebugEnabled()) {
3199
3320
  console.log(`[BPMN] GatewayEdgeAdjuster: Adjusted edge ${edge.id} endpoint to diamond intersection (${intersectionPoint.x},${intersectionPoint.y})`);
3200
3321
  }
3201
3322
  }
@@ -3455,7 +3576,7 @@ var ElkGraphPreparer = class {
3455
3576
  for (const startId of startEvents) {
3456
3577
  traverseMainFlow(startId);
3457
3578
  }
3458
- if (DEBUG) {
3579
+ if (isDebugEnabled()) {
3459
3580
  console.log(`[BPMN] Main flow nodes: ${Array.from(mainFlowNodes).join(", ")}`);
3460
3581
  }
3461
3582
  return mainFlowNodes;
@@ -3790,7 +3911,7 @@ var ResultMerger = class {
3790
3911
  return originalEdges.map((origEdge) => {
3791
3912
  const layoutedEdge = layoutedEdgeMap.get(origEdge.id);
3792
3913
  if (layoutedEdge) {
3793
- if (DEBUG && layoutedEdge.sections?.[0]?.bendPoints?.length) {
3914
+ if (isDebugEnabled() && layoutedEdge.sections?.[0]?.bendPoints?.length) {
3794
3915
  console.log(`[BPMN] Merge ${origEdge.id}: bendPoints=${JSON.stringify(layoutedEdge.sections[0].bendPoints)}`);
3795
3916
  }
3796
3917
  const mergedEdge = {
@@ -3928,7 +4049,7 @@ var MainFlowNormalizer = class {
3928
4049
  return;
3929
4050
  }
3930
4051
  const offsetY = currentMinY - TARGET_MAIN_FLOW_Y;
3931
- if (DEBUG) {
4052
+ if (isDebugEnabled()) {
3932
4053
  console.log(`[BPMN] Normalizing main flow: currentMinY=${currentMinY}, offsetY=${offsetY}`);
3933
4054
  console.log(`[BPMN] Upstream nodes: ${upstreamMainFlow.map((n) => n.id).join(", ")}`);
3934
4055
  console.log(`[BPMN] Downstream nodes: ${downstreamMainFlow.map((n) => n.id).join(", ")}`);
@@ -3936,7 +4057,7 @@ var MainFlowNormalizer = class {
3936
4057
  for (const node of otherUpstreamNodes) {
3937
4058
  if (node.y !== void 0) {
3938
4059
  node.y -= offsetY;
3939
- if (DEBUG) {
4060
+ if (isDebugEnabled()) {
3940
4061
  console.log(`[BPMN] Shifted upstream ${node.id} to y=${node.y}`);
3941
4062
  }
3942
4063
  }
@@ -3949,14 +4070,14 @@ var MainFlowNormalizer = class {
3949
4070
  const predecessorCenterY = predecessor.y + (predecessor.height ?? 80) / 2;
3950
4071
  const endNodeCenterY = (endNode.height ?? 36) / 2;
3951
4072
  endNode.y = predecessorCenterY - endNodeCenterY;
3952
- if (DEBUG) {
4073
+ if (isDebugEnabled()) {
3953
4074
  console.log(`[BPMN] Aligned endEvent ${endNode.id} with predecessor ${predecessorId}: y=${endNode.y}`);
3954
4075
  }
3955
4076
  }
3956
4077
  } else {
3957
4078
  if (endNode.y !== void 0) {
3958
4079
  endNode.y -= offsetY;
3959
- if (DEBUG) {
4080
+ if (isDebugEnabled()) {
3960
4081
  console.log(`[BPMN] Shifted upstream ${endNode.id} to y=${endNode.y} (no predecessor found)`);
3961
4082
  }
3962
4083
  }
@@ -3984,7 +4105,7 @@ var MainFlowNormalizer = class {
3984
4105
  const newY = prevBottom + MIN_SPACING;
3985
4106
  currNode.y = newY;
3986
4107
  adjustedEndEvents.set(currNode.id, newY);
3987
- if (DEBUG) {
4108
+ if (isDebugEnabled()) {
3988
4109
  console.log(`[BPMN] Adjusted overlapping endEvent ${currNode.id} at x=${x}: y=${currNode.y}`);
3989
4110
  }
3990
4111
  }
@@ -4008,7 +4129,7 @@ var MainFlowNormalizer = class {
4008
4129
  for (const node of downstreamMainFlow) {
4009
4130
  if (node.y !== void 0) {
4010
4131
  node.y -= downstreamOffsetY;
4011
- if (DEBUG) {
4132
+ if (isDebugEnabled()) {
4012
4133
  console.log(`[BPMN] Shifted downstream ${node.id} to y=${node.y}`);
4013
4134
  }
4014
4135
  }
@@ -4190,20 +4311,20 @@ var MainFlowNormalizer = class {
4190
4311
  lastBend.y = newTargetY;
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} last bendPoint and endpoint to y=${newTargetY}`);
4195
4316
  }
4196
4317
  } else {
4197
4318
  section.endPoint.y = newTargetY;
4198
4319
  edgesWithAdjustedEndpoint.add(edge.id);
4199
- if (DEBUG) {
4320
+ if (isDebugEnabled()) {
4200
4321
  console.log(`[BPMN] Updated edge ${edge.id} endpoint to y=${newTargetY}`);
4201
4322
  }
4202
4323
  }
4203
4324
  } else if (section.endPoint) {
4204
4325
  section.endPoint.y = newTargetY;
4205
4326
  edgesWithAdjustedEndpoint.add(edge.id);
4206
- if (DEBUG) {
4327
+ if (isDebugEnabled()) {
4207
4328
  console.log(`[BPMN] Updated edge ${edge.id} endpoint to y=${newTargetY}`);
4208
4329
  }
4209
4330
  }
@@ -4317,7 +4438,7 @@ var GatewayPropagator = class {
4317
4438
  offset: 0,
4318
4439
  newX
4319
4440
  });
4320
- if (DEBUG) {
4441
+ if (isDebugEnabled()) {
4321
4442
  console.log(`[BPMN] Propagating gateway movement to ${targetId}: x ${currentX} -> ${newX}`);
4322
4443
  }
4323
4444
  this.propagateDownstreamX(targetId, newX, targetNode.width ?? 100, nodeMap, edgeMap, mainFlowNodes, gatewayMoves);
@@ -4345,7 +4466,7 @@ var GatewayPropagator = class {
4345
4466
  offset: 0,
4346
4467
  newX
4347
4468
  });
4348
- if (DEBUG) {
4469
+ if (isDebugEnabled()) {
4349
4470
  console.log(`[BPMN] Propagating X to ${targetId}: x ${currentX} -> ${newX}`);
4350
4471
  }
4351
4472
  this.propagateDownstreamX(targetId, newX, targetNode.width ?? 100, nodeMap, edgeMap, mainFlowNodes, moves);
@@ -4400,14 +4521,14 @@ var ElkLayouter = class {
4400
4521
  const layoutedElkGraph = await this.elk.layout(elkGraph);
4401
4522
  const mainFlowNodes = this.graphPreparer.identifyMainFlowNodes(sizedGraph, boundaryEventTargetIds);
4402
4523
  this.mainFlowNormalizer.normalize(layoutedElkGraph, mainFlowNodes, boundaryEventTargetIds, sizedGraph);
4403
- const movedNodes = this.boundaryEventHandler.identifyNodesToMove(layoutedElkGraph, boundaryEventInfo, sizedGraph, DEBUG);
4524
+ const movedNodes = this.boundaryEventHandler.identifyNodesToMove(layoutedElkGraph, boundaryEventInfo, sizedGraph, isDebugEnabled());
4404
4525
  if (movedNodes.size > 0) {
4405
4526
  this.boundaryEventHandler.applyNodeMoves(layoutedElkGraph, movedNodes);
4406
4527
  const gatewayMoves = this.boundaryEventHandler.repositionConvergingGateways(
4407
4528
  layoutedElkGraph,
4408
4529
  movedNodes,
4409
4530
  boundaryEventInfo,
4410
- DEBUG
4531
+ isDebugEnabled()
4411
4532
  );
4412
4533
  if (gatewayMoves.size > 0) {
4413
4534
  this.boundaryEventHandler.applyNodeMoves(layoutedElkGraph, gatewayMoves);
@@ -4416,7 +4537,7 @@ var ElkLayouter = class {
4416
4537
  for (const [id, move] of gatewayMoves) {
4417
4538
  movedNodes.set(id, move);
4418
4539
  }
4419
- this.boundaryEventHandler.recalculateEdgesForMovedNodes(layoutedElkGraph, movedNodes, boundaryEventInfo, DEBUG);
4540
+ this.boundaryEventHandler.recalculateEdgesForMovedNodes(layoutedElkGraph, movedNodes, boundaryEventInfo);
4420
4541
  }
4421
4542
  this.artifactPositioner.reposition(layoutedElkGraph, artifactInfo);
4422
4543
  this.laneArranger.rearrange(layoutedElkGraph, sizedGraph);
@@ -4690,7 +4811,7 @@ function adjustGatewayEndpoint(endpoint, adjacentPoint, gatewayBounds, isSource)
4690
4811
  const gatewayCenterX = gatewayBounds.x + gatewayBounds.width / 2;
4691
4812
  const gatewayCenterY = gatewayBounds.y + gatewayBounds.height / 2;
4692
4813
  const tolerance = 1;
4693
- if (DEBUG) {
4814
+ if (isDebugEnabled()) {
4694
4815
  console.log(`[BPMN] adjustGatewayEndpoint: isSource=${isSource}`);
4695
4816
  console.log(` endpoint: (${endpoint.x}, ${endpoint.y})`);
4696
4817
  console.log(` gatewayBounds: x=${gatewayBounds.x}, y=${gatewayBounds.y}, w=${gatewayBounds.width}, h=${gatewayBounds.height}`);
@@ -4702,22 +4823,22 @@ function adjustGatewayEndpoint(endpoint, adjacentPoint, gatewayBounds, isSource)
4702
4823
  const topCorner = { x: gatewayCenterX, y: gatewayBounds.y };
4703
4824
  const bottomCorner = { x: gatewayCenterX, y: gatewayBounds.y + gatewayBounds.height };
4704
4825
  if (Math.abs(endpoint.x - gatewayBounds.x) < tolerance && Math.abs(endpoint.y - gatewayCenterY) < tolerance) {
4705
- if (DEBUG) console.log(` -> Already at LEFT corner, no adjustment`);
4826
+ if (isDebugEnabled()) console.log(` -> Already at LEFT corner, no adjustment`);
4706
4827
  return endpoint;
4707
4828
  }
4708
4829
  if (Math.abs(endpoint.x - (gatewayBounds.x + gatewayBounds.width)) < tolerance && Math.abs(endpoint.y - gatewayCenterY) < tolerance) {
4709
- if (DEBUG) console.log(` -> Already at RIGHT corner, no adjustment`);
4830
+ if (isDebugEnabled()) console.log(` -> Already at RIGHT corner, no adjustment`);
4710
4831
  return endpoint;
4711
4832
  }
4712
4833
  if (Math.abs(endpoint.y - gatewayBounds.y) < tolerance && Math.abs(endpoint.x - gatewayCenterX) < tolerance) {
4713
- if (DEBUG) console.log(` -> Already at TOP corner, no adjustment`);
4834
+ if (isDebugEnabled()) console.log(` -> Already at TOP corner, no adjustment`);
4714
4835
  return endpoint;
4715
4836
  }
4716
4837
  if (Math.abs(endpoint.y - (gatewayBounds.y + gatewayBounds.height)) < tolerance && Math.abs(endpoint.x - gatewayCenterX) < tolerance) {
4717
- if (DEBUG) console.log(` -> Already at BOTTOM corner, no adjustment`);
4838
+ if (isDebugEnabled()) console.log(` -> Already at BOTTOM corner, no adjustment`);
4718
4839
  return endpoint;
4719
4840
  }
4720
- if (DEBUG) {
4841
+ if (isDebugEnabled()) {
4721
4842
  console.log(` -> NOT at corner, will adjust`);
4722
4843
  }
4723
4844
  const result = calculateDiamondIntersection(
@@ -4728,7 +4849,7 @@ function adjustGatewayEndpoint(endpoint, adjacentPoint, gatewayBounds, isSource)
4728
4849
  isSource,
4729
4850
  adjacentPoint
4730
4851
  );
4731
- if (DEBUG) {
4852
+ if (isDebugEnabled()) {
4732
4853
  console.log(` -> Adjusted to: (${result.x}, ${result.y})`);
4733
4854
  }
4734
4855
  return result;
@@ -5033,7 +5154,7 @@ var DiagramBuilder = class {
5033
5154
  const targetIsGateway = this.isGatewayType(targetNode?.type);
5034
5155
  let waypoints = [];
5035
5156
  const hasPreCalculatedSections = edge.sections && edge.sections.length > 0 && edge.sections[0]?.bendPoints && edge.sections[0].bendPoints.length > 0;
5036
- if (DEBUG && bePosition) {
5157
+ if (isDebugEnabled() && bePosition) {
5037
5158
  console.log(`[BPMN] buildEdge ${edge.id}: preCalculated=${hasPreCalculatedSections}`);
5038
5159
  }
5039
5160
  if (bePosition && targetPosition && !hasPreCalculatedSections) {
@@ -5108,6 +5229,7 @@ var DiagramBuilder = class {
5108
5229
  }
5109
5230
  }
5110
5231
  }
5232
+ this.ensureOrthogonalWaypoints(waypoints);
5111
5233
  const edgeModel = {
5112
5234
  id: `${edge.id}_di`,
5113
5235
  bpmnElement: edge.id,
@@ -5174,6 +5296,36 @@ var DiagramBuilder = class {
5174
5296
  y: (lastPoint?.y ?? 0) - labelHeight - 4
5175
5297
  };
5176
5298
  }
5299
+ /**
5300
+ * Ensure all waypoint segments are orthogonal (horizontal or vertical)
5301
+ * If a diagonal segment is found, insert intermediate bend points to create
5302
+ * an L-shaped orthogonal path.
5303
+ *
5304
+ * Strategy: For diagonal segments, we use "horizontal first" - go horizontally
5305
+ * to the target X, then vertically to the target Y.
5306
+ */
5307
+ ensureOrthogonalWaypoints(waypoints) {
5308
+ if (waypoints.length < 2) return;
5309
+ const tolerance = 1;
5310
+ let i = 0;
5311
+ while (i < waypoints.length - 1) {
5312
+ const current = waypoints[i];
5313
+ const next = waypoints[i + 1];
5314
+ if (!current || !next) {
5315
+ i++;
5316
+ continue;
5317
+ }
5318
+ const dx = Math.abs(next.x - current.x);
5319
+ const dy = Math.abs(next.y - current.y);
5320
+ if (dx > tolerance && dy > tolerance) {
5321
+ const bendPoint = { x: next.x, y: current.y };
5322
+ waypoints.splice(i + 1, 0, bendPoint);
5323
+ i++;
5324
+ } else {
5325
+ i++;
5326
+ }
5327
+ }
5328
+ }
5177
5329
  };
5178
5330
 
5179
5331
  // src/transform/model-builder.ts