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.
@@ -249,7 +249,11 @@ function lineIntersection(p1, p2, p3, p4) {
249
249
  }
250
250
 
251
251
  // src/utils/debug.ts
252
- var DEBUG = typeof process !== "undefined" && process.env?.["DEBUG"] === "true";
252
+ var cliMode = false;
253
+ function isDebugEnabled() {
254
+ if (cliMode) return false;
255
+ return typeof process !== "undefined" && process.env?.["DEBUG"] === "true";
256
+ }
253
257
 
254
258
  // src/layout/edge-routing/edge-fixer.ts
255
259
  var EdgeFixer = class {
@@ -282,7 +286,7 @@ var EdgeFixer = class {
282
286
  const isFlowNode = flowNodePatterns.some((pattern) => pattern.test(id));
283
287
  const isPool = poolPatterns.some((pattern) => pattern.test(id));
284
288
  const bpmn = node.bpmn;
285
- if (DEBUG && (id.includes("lane") || id.includes("pool") || id.includes("end_fast") || id.includes("gateway_fast"))) {
289
+ if (isDebugEnabled() && (id.includes("lane") || id.includes("pool") || id.includes("end_fast") || id.includes("gateway_fast"))) {
286
290
  console.log(`[BPMN] EdgeFixer.collectNodePositions: id=${id}, offsetX=${offsetX}, offsetY=${offsetY}, bpmn=${JSON.stringify(bpmn)}`);
287
291
  console.log(`[BPMN] node.x=${node.x}, node.y=${node.y}, isFlowNode=${isFlowNode}, isPool=${isPool}`);
288
292
  }
@@ -320,6 +324,10 @@ var EdgeFixer = class {
320
324
  const containerNodes = nodesByContainer.get(currentContainerId) ?? /* @__PURE__ */ new Map();
321
325
  for (const edge of node.edges) {
322
326
  if (edge.sections && edge.sections.length > 0) {
327
+ const hasPoolRelativeCoords = edge._poolRelativeCoords === true;
328
+ if (hasPoolRelativeCoords) {
329
+ continue;
330
+ }
323
331
  this.fixEdgeIfCrossing(edge, containerNodes, containerOffsetX, containerOffsetY);
324
332
  }
325
333
  }
@@ -371,7 +379,7 @@ var EdgeFixer = class {
371
379
  }
372
380
  const targetPos = targetId ? nodePositions.get(targetId) : void 0;
373
381
  const sourcePos = sourceId ? nodePositions.get(sourceId) : void 0;
374
- if (DEBUG && edge.id?.includes("back")) {
382
+ if (isDebugEnabled() && edge.id?.includes("back")) {
375
383
  console.log(`[BPMN] Edge ${edge.id}: sourceId=${sourceId}, targetId=${targetId}`);
376
384
  console.log(`[BPMN] Edge ${edge.id}: sourcePos=${JSON.stringify(sourcePos)}, targetPos=${JSON.stringify(targetPos)}`);
377
385
  console.log(`[BPMN] Edge ${edge.id}: waypoints.length=${waypoints.length}`);
@@ -380,7 +388,7 @@ var EdgeFixer = class {
380
388
  const lastWaypoint = waypoints[waypoints.length - 1];
381
389
  const secondLastWaypoint = waypoints[waypoints.length - 2];
382
390
  const isReturnEdge2 = targetPos.y + targetPos.height < sourcePos.y;
383
- if (DEBUG && edge.id?.includes("back")) {
391
+ if (isDebugEnabled() && edge.id?.includes("back")) {
384
392
  console.log(`[BPMN] Edge ${edge.id}: isReturnEdge=${isReturnEdge2}`);
385
393
  if (lastWaypoint) {
386
394
  console.log(`[BPMN] Edge ${edge.id}: lastWaypoint=(${lastWaypoint.x},${lastWaypoint.y})`);
@@ -400,7 +408,7 @@ var EdgeFixer = class {
400
408
  }
401
409
  }
402
410
  if (crossedNodes.length === 0) return;
403
- if (DEBUG) {
411
+ if (isDebugEnabled()) {
404
412
  console.log(`[BPMN] Edge ${edge.id} crosses nodes: ${crossedNodes.join(", ")}`);
405
413
  }
406
414
  if (!sourcePos || !targetPos) return;
@@ -451,7 +459,7 @@ var EdgeFixer = class {
451
459
  y: bp.y - containerOffsetY
452
460
  }));
453
461
  section.bendPoints = relativeBendPoints.length > 0 ? relativeBendPoints : void 0;
454
- if (DEBUG) {
462
+ if (isDebugEnabled()) {
455
463
  console.log(`[BPMN] Fixed edge ${edge.id} with ${relativeBendPoints.length} bend points`);
456
464
  }
457
465
  }
@@ -1241,7 +1249,8 @@ function applyNodeMoves(graph, movedNodes) {
1241
1249
  }
1242
1250
 
1243
1251
  // src/layout/post-processing/boundary-event/edge-recalculator.ts
1244
- function recalculateEdgesForMovedNodes(graph, movedNodes, boundaryEventInfo, debug = false) {
1252
+ function recalculateEdgesForMovedNodes(graph, movedNodes, boundaryEventInfo) {
1253
+ const debug = isDebugEnabled();
1245
1254
  const nodeMap = /* @__PURE__ */ new Map();
1246
1255
  const buildNodeMap2 = (node) => {
1247
1256
  nodeMap.set(node.id, node);
@@ -1318,7 +1327,8 @@ function recalculateEdgesForMovedNodes(graph, movedNodes, boundaryEventInfo, deb
1318
1327
  };
1319
1328
  processEdges(graph);
1320
1329
  }
1321
- function recalculateEdgeWithObstacleAvoidance(edge, source, target, obstacleIds, nodeMap, debug = false) {
1330
+ function recalculateEdgeWithObstacleAvoidance(edge, source, target, obstacleIds, nodeMap) {
1331
+ const debug = isDebugEnabled();
1322
1332
  const sx = source.x ?? 0;
1323
1333
  const sy = source.y ?? 0;
1324
1334
  const sw = source.width ?? 100;
@@ -1539,8 +1549,8 @@ var BoundaryEventHandler = class {
1539
1549
  /**
1540
1550
  * Recalculate edge waypoints for edges connected to moved nodes
1541
1551
  */
1542
- recalculateEdgesForMovedNodes(graph, movedNodes, boundaryEventInfo, debug = false) {
1543
- recalculateEdgesForMovedNodes(graph, movedNodes, boundaryEventInfo, debug);
1552
+ recalculateEdgesForMovedNodes(graph, movedNodes, boundaryEventInfo) {
1553
+ recalculateEdgesForMovedNodes(graph, movedNodes, boundaryEventInfo);
1544
1554
  }
1545
1555
  };
1546
1556
 
@@ -2427,7 +2437,7 @@ var LaneArranger = class {
2427
2437
  const targetId = edge.targets?.[0];
2428
2438
  const sourcePos = sourceId ? nodePositions.get(sourceId) : void 0;
2429
2439
  const targetPos = targetId ? nodePositions.get(targetId) : void 0;
2430
- if (DEBUG) {
2440
+ if (isDebugEnabled()) {
2431
2441
  console.log(`[BPMN] recalculatePoolEdges ${edge.id}: source=${sourceId}, target=${targetId}`);
2432
2442
  console.log(`[BPMN] sourcePos=${JSON.stringify(sourcePos)}`);
2433
2443
  console.log(`[BPMN] targetPos=${JSON.stringify(targetPos)}`);
@@ -2437,18 +2447,26 @@ var LaneArranger = class {
2437
2447
  const startY = sourcePos.y + sourcePos.height / 2;
2438
2448
  const endX = targetPos.x;
2439
2449
  const endY = targetPos.y + targetPos.height / 2;
2440
- if (DEBUG) {
2450
+ if (isDebugEnabled()) {
2441
2451
  console.log(`[BPMN] startX=${startX}, startY=${startY}, endX=${endX}, endY=${endY}`);
2442
2452
  }
2443
2453
  const waypoints = [];
2444
2454
  waypoints.push({ x: startX, y: startY });
2445
2455
  if (Math.abs(startY - endY) > 10) {
2446
- const midX = (startX + endX) / 2;
2456
+ const midX = this.findClearMidX(
2457
+ startX,
2458
+ endX,
2459
+ startY,
2460
+ endY,
2461
+ sourceId,
2462
+ targetId,
2463
+ nodePositions
2464
+ );
2447
2465
  waypoints.push({ x: midX, y: startY });
2448
2466
  waypoints.push({ x: midX, y: endY });
2449
2467
  }
2450
2468
  waypoints.push({ x: endX, y: endY });
2451
- if (DEBUG) {
2469
+ if (isDebugEnabled()) {
2452
2470
  console.log(`[BPMN] waypoints=${JSON.stringify(waypoints)}`);
2453
2471
  }
2454
2472
  edge._poolRelativeCoords = true;
@@ -2461,6 +2479,109 @@ var LaneArranger = class {
2461
2479
  }
2462
2480
  }
2463
2481
  }
2482
+ /**
2483
+ * Find a clear X position for vertical edge segment that avoids obstacles.
2484
+ * Checks all three segments of the L-shaped path:
2485
+ * 1. Horizontal from (startX, startY) to (midX, startY)
2486
+ * 2. Vertical from (midX, startY) to (midX, endY)
2487
+ * 3. Horizontal from (midX, endY) to (endX, endY)
2488
+ */
2489
+ findClearMidX(startX, endX, startY, endY, sourceId, targetId, nodePositions) {
2490
+ const margin = 15;
2491
+ const minY = Math.min(startY, endY);
2492
+ const maxY = Math.max(startY, endY);
2493
+ const rangeMinX = Math.min(startX, endX);
2494
+ const rangeMaxX = Math.max(startX, endX);
2495
+ if (isDebugEnabled()) {
2496
+ console.log(`[BPMN] findClearMidX: startX=${startX}, endX=${endX}, startY=${startY}, endY=${endY}`);
2497
+ }
2498
+ const allObstacles = [];
2499
+ for (const [nodeId, pos] of nodePositions) {
2500
+ if (nodeId === sourceId || nodeId === targetId) continue;
2501
+ const nodeLeft = pos.x;
2502
+ const nodeRight = pos.x + pos.width;
2503
+ const nodeTop = pos.y;
2504
+ const nodeBottom = pos.y + pos.height;
2505
+ const xOverlap = nodeRight > rangeMinX && nodeLeft < rangeMaxX;
2506
+ const yOverlapVertical = nodeBottom > minY && nodeTop < maxY;
2507
+ const yContainsStartY = nodeTop <= startY && nodeBottom >= startY;
2508
+ const yContainsEndY = nodeTop <= endY && nodeBottom >= endY;
2509
+ if (xOverlap && (yOverlapVertical || yContainsStartY || yContainsEndY)) {
2510
+ allObstacles.push({
2511
+ x: nodeLeft,
2512
+ y: nodeTop,
2513
+ width: pos.width,
2514
+ height: pos.height,
2515
+ right: nodeRight,
2516
+ bottom: nodeBottom,
2517
+ id: nodeId
2518
+ });
2519
+ if (isDebugEnabled()) {
2520
+ console.log(`[BPMN] findClearMidX: obstacle ${nodeId}: x=[${nodeLeft}, ${nodeRight}], y=[${nodeTop}, ${nodeBottom}]`);
2521
+ }
2522
+ }
2523
+ }
2524
+ if (allObstacles.length === 0) {
2525
+ return (startX + endX) / 2;
2526
+ }
2527
+ const isValidMidX = (midX) => {
2528
+ for (const obs of allObstacles) {
2529
+ const seg1MinX = Math.min(startX, midX);
2530
+ const seg1MaxX = Math.max(startX, midX);
2531
+ if (obs.y <= startY && obs.bottom >= startY && // Y range contains startY
2532
+ obs.right > seg1MinX && obs.x < seg1MaxX) {
2533
+ return false;
2534
+ }
2535
+ if (obs.x <= midX && obs.right >= midX && // X range contains midX
2536
+ obs.bottom > minY && obs.y < maxY) {
2537
+ return false;
2538
+ }
2539
+ const seg2MinX = Math.min(midX, endX);
2540
+ const seg2MaxX = Math.max(midX, endX);
2541
+ if (obs.y <= endY && obs.bottom >= endY && // Y range contains endY
2542
+ obs.right > seg2MinX && obs.x < seg2MaxX) {
2543
+ return false;
2544
+ }
2545
+ }
2546
+ return true;
2547
+ };
2548
+ const candidates = [];
2549
+ candidates.push((startX + endX) / 2);
2550
+ candidates.push(startX + margin);
2551
+ candidates.push(endX - margin);
2552
+ for (const obs of allObstacles) {
2553
+ candidates.push(obs.x - margin);
2554
+ candidates.push(obs.right + margin);
2555
+ }
2556
+ const simpleMidX = (startX + endX) / 2;
2557
+ const validCandidates = candidates.filter((x) => x >= rangeMinX && x <= rangeMaxX).sort((a, b) => Math.abs(a - simpleMidX) - Math.abs(b - simpleMidX));
2558
+ for (const candidate of validCandidates) {
2559
+ if (isValidMidX(candidate)) {
2560
+ if (isDebugEnabled()) {
2561
+ console.log(`[BPMN] findClearMidX: found valid position ${candidate}`);
2562
+ }
2563
+ return candidate;
2564
+ }
2565
+ }
2566
+ const leftMost = Math.min(...allObstacles.map((o) => o.x)) - margin;
2567
+ const rightMost = Math.max(...allObstacles.map((o) => o.right)) + margin;
2568
+ if (leftMost >= rangeMinX && isValidMidX(leftMost)) {
2569
+ if (isDebugEnabled()) {
2570
+ console.log(`[BPMN] findClearMidX: routing left of all obstacles at ${leftMost}`);
2571
+ }
2572
+ return leftMost;
2573
+ }
2574
+ if (rightMost <= rangeMaxX && isValidMidX(rightMost)) {
2575
+ if (isDebugEnabled()) {
2576
+ console.log(`[BPMN] findClearMidX: routing right of all obstacles at ${rightMost}`);
2577
+ }
2578
+ return rightMost;
2579
+ }
2580
+ if (isDebugEnabled()) {
2581
+ console.log(`[BPMN] findClearMidX: no valid route found, using midpoint ${simpleMidX}`);
2582
+ }
2583
+ return simpleMidX;
2584
+ }
2464
2585
  };
2465
2586
 
2466
2587
  // src/layout/post-processing/pool-arranger.ts
@@ -2541,7 +2662,7 @@ var PoolArranger = class {
2541
2662
  pool.y = currentY;
2542
2663
  if (isBlackBox) {
2543
2664
  pool.width = maxPoolWidth;
2544
- pool.height = pool.height ?? 60;
2665
+ pool.height = 60;
2545
2666
  } else if (hasLanes) {
2546
2667
  pool.width = maxPoolWidth;
2547
2668
  } else {
@@ -2956,7 +3077,7 @@ var GatewayEdgeAdjuster = class {
2956
3077
  const gateways = /* @__PURE__ */ new Map();
2957
3078
  this.collectGateways(layoutedGraph, originalGraph, gateways, 0, 0);
2958
3079
  if (gateways.size === 0) return;
2959
- if (DEBUG) {
3080
+ if (isDebugEnabled()) {
2960
3081
  console.log(`[BPMN] GatewayEdgeAdjuster: Found ${gateways.size} gateways`);
2961
3082
  for (const [id, info] of gateways) {
2962
3083
  console.log(`[BPMN] - ${id}: bounds=(${info.bounds.x},${info.bounds.y},${info.bounds.width},${info.bounds.height})`);
@@ -3043,7 +3164,7 @@ var GatewayEdgeAdjuster = class {
3043
3164
  const section = edge.sections[0];
3044
3165
  const sourceId = edge.sources?.[0];
3045
3166
  const targetId = edge.targets?.[0];
3046
- if (DEBUG) {
3167
+ if (isDebugEnabled()) {
3047
3168
  console.log(`[BPMN] GatewayEdgeAdjuster: Processing edge ${edge.id}, offset=(${offsetX},${offsetY})`);
3048
3169
  console.log(`[BPMN] sourceId=${sourceId}, targetId=${targetId}`);
3049
3170
  console.log(`[BPMN] startPoint=(${section.startPoint.x},${section.startPoint.y}), endPoint=(${section.endPoint.x},${section.endPoint.y})`);
@@ -3055,7 +3176,7 @@ var GatewayEdgeAdjuster = class {
3055
3176
  }
3056
3177
  const targetGateway = targetId ? gateways.get(targetId) : void 0;
3057
3178
  if (targetGateway) {
3058
- if (DEBUG) {
3179
+ if (isDebugEnabled()) {
3059
3180
  console.log(`[BPMN] target gateway: ${targetId}, bounds=(${targetGateway.bounds.x},${targetGateway.bounds.y})`);
3060
3181
  console.log(`[BPMN] left corner: (${targetGateway.corners.left.x},${targetGateway.corners.left.y})`);
3061
3182
  }
@@ -3126,7 +3247,7 @@ var GatewayEdgeAdjuster = class {
3126
3247
  lastBend.x = newEnd.x;
3127
3248
  }
3128
3249
  }
3129
- if (DEBUG) {
3250
+ if (isDebugEnabled()) {
3130
3251
  console.log(`[BPMN] GatewayEdgeAdjuster: Adjusted edge ${edge.id} endpoint from (${endX},${endY}) to (${targetCorner.x},${targetCorner.y})`);
3131
3252
  }
3132
3253
  } else {
@@ -3140,7 +3261,7 @@ var GatewayEdgeAdjuster = class {
3140
3261
  x: intersectionPoint.x - offsetX,
3141
3262
  y: intersectionPoint.y - offsetY
3142
3263
  };
3143
- if (DEBUG) {
3264
+ if (isDebugEnabled()) {
3144
3265
  console.log(`[BPMN] GatewayEdgeAdjuster: Adjusted edge ${edge.id} endpoint to diamond intersection (${intersectionPoint.x},${intersectionPoint.y})`);
3145
3266
  }
3146
3267
  }
@@ -3400,7 +3521,7 @@ var ElkGraphPreparer = class {
3400
3521
  for (const startId of startEvents) {
3401
3522
  traverseMainFlow(startId);
3402
3523
  }
3403
- if (DEBUG) {
3524
+ if (isDebugEnabled()) {
3404
3525
  console.log(`[BPMN] Main flow nodes: ${Array.from(mainFlowNodes).join(", ")}`);
3405
3526
  }
3406
3527
  return mainFlowNodes;
@@ -3735,7 +3856,7 @@ var ResultMerger = class {
3735
3856
  return originalEdges.map((origEdge) => {
3736
3857
  const layoutedEdge = layoutedEdgeMap.get(origEdge.id);
3737
3858
  if (layoutedEdge) {
3738
- if (DEBUG && layoutedEdge.sections?.[0]?.bendPoints?.length) {
3859
+ if (isDebugEnabled() && layoutedEdge.sections?.[0]?.bendPoints?.length) {
3739
3860
  console.log(`[BPMN] Merge ${origEdge.id}: bendPoints=${JSON.stringify(layoutedEdge.sections[0].bendPoints)}`);
3740
3861
  }
3741
3862
  const mergedEdge = {
@@ -3873,7 +3994,7 @@ var MainFlowNormalizer = class {
3873
3994
  return;
3874
3995
  }
3875
3996
  const offsetY = currentMinY - TARGET_MAIN_FLOW_Y;
3876
- if (DEBUG) {
3997
+ if (isDebugEnabled()) {
3877
3998
  console.log(`[BPMN] Normalizing main flow: currentMinY=${currentMinY}, offsetY=${offsetY}`);
3878
3999
  console.log(`[BPMN] Upstream nodes: ${upstreamMainFlow.map((n) => n.id).join(", ")}`);
3879
4000
  console.log(`[BPMN] Downstream nodes: ${downstreamMainFlow.map((n) => n.id).join(", ")}`);
@@ -3881,7 +4002,7 @@ var MainFlowNormalizer = class {
3881
4002
  for (const node of otherUpstreamNodes) {
3882
4003
  if (node.y !== void 0) {
3883
4004
  node.y -= offsetY;
3884
- if (DEBUG) {
4005
+ if (isDebugEnabled()) {
3885
4006
  console.log(`[BPMN] Shifted upstream ${node.id} to y=${node.y}`);
3886
4007
  }
3887
4008
  }
@@ -3894,14 +4015,14 @@ var MainFlowNormalizer = class {
3894
4015
  const predecessorCenterY = predecessor.y + (predecessor.height ?? 80) / 2;
3895
4016
  const endNodeCenterY = (endNode.height ?? 36) / 2;
3896
4017
  endNode.y = predecessorCenterY - endNodeCenterY;
3897
- if (DEBUG) {
4018
+ if (isDebugEnabled()) {
3898
4019
  console.log(`[BPMN] Aligned endEvent ${endNode.id} with predecessor ${predecessorId}: y=${endNode.y}`);
3899
4020
  }
3900
4021
  }
3901
4022
  } else {
3902
4023
  if (endNode.y !== void 0) {
3903
4024
  endNode.y -= offsetY;
3904
- if (DEBUG) {
4025
+ if (isDebugEnabled()) {
3905
4026
  console.log(`[BPMN] Shifted upstream ${endNode.id} to y=${endNode.y} (no predecessor found)`);
3906
4027
  }
3907
4028
  }
@@ -3929,7 +4050,7 @@ var MainFlowNormalizer = class {
3929
4050
  const newY = prevBottom + MIN_SPACING;
3930
4051
  currNode.y = newY;
3931
4052
  adjustedEndEvents.set(currNode.id, newY);
3932
- if (DEBUG) {
4053
+ if (isDebugEnabled()) {
3933
4054
  console.log(`[BPMN] Adjusted overlapping endEvent ${currNode.id} at x=${x}: y=${currNode.y}`);
3934
4055
  }
3935
4056
  }
@@ -3953,7 +4074,7 @@ var MainFlowNormalizer = class {
3953
4074
  for (const node of downstreamMainFlow) {
3954
4075
  if (node.y !== void 0) {
3955
4076
  node.y -= downstreamOffsetY;
3956
- if (DEBUG) {
4077
+ if (isDebugEnabled()) {
3957
4078
  console.log(`[BPMN] Shifted downstream ${node.id} to y=${node.y}`);
3958
4079
  }
3959
4080
  }
@@ -4135,20 +4256,20 @@ var MainFlowNormalizer = class {
4135
4256
  lastBend.y = newTargetY;
4136
4257
  section.endPoint.y = newTargetY;
4137
4258
  edgesWithAdjustedEndpoint.add(edge.id);
4138
- if (DEBUG) {
4259
+ if (isDebugEnabled()) {
4139
4260
  console.log(`[BPMN] Updated edge ${edge.id} last bendPoint and endpoint to y=${newTargetY}`);
4140
4261
  }
4141
4262
  } else {
4142
4263
  section.endPoint.y = newTargetY;
4143
4264
  edgesWithAdjustedEndpoint.add(edge.id);
4144
- if (DEBUG) {
4265
+ if (isDebugEnabled()) {
4145
4266
  console.log(`[BPMN] Updated edge ${edge.id} endpoint to y=${newTargetY}`);
4146
4267
  }
4147
4268
  }
4148
4269
  } else if (section.endPoint) {
4149
4270
  section.endPoint.y = newTargetY;
4150
4271
  edgesWithAdjustedEndpoint.add(edge.id);
4151
- if (DEBUG) {
4272
+ if (isDebugEnabled()) {
4152
4273
  console.log(`[BPMN] Updated edge ${edge.id} endpoint to y=${newTargetY}`);
4153
4274
  }
4154
4275
  }
@@ -4262,7 +4383,7 @@ var GatewayPropagator = class {
4262
4383
  offset: 0,
4263
4384
  newX
4264
4385
  });
4265
- if (DEBUG) {
4386
+ if (isDebugEnabled()) {
4266
4387
  console.log(`[BPMN] Propagating gateway movement to ${targetId}: x ${currentX} -> ${newX}`);
4267
4388
  }
4268
4389
  this.propagateDownstreamX(targetId, newX, targetNode.width ?? 100, nodeMap, edgeMap, mainFlowNodes, gatewayMoves);
@@ -4290,7 +4411,7 @@ var GatewayPropagator = class {
4290
4411
  offset: 0,
4291
4412
  newX
4292
4413
  });
4293
- if (DEBUG) {
4414
+ if (isDebugEnabled()) {
4294
4415
  console.log(`[BPMN] Propagating X to ${targetId}: x ${currentX} -> ${newX}`);
4295
4416
  }
4296
4417
  this.propagateDownstreamX(targetId, newX, targetNode.width ?? 100, nodeMap, edgeMap, mainFlowNodes, moves);
@@ -4345,14 +4466,14 @@ var ElkLayouter = class {
4345
4466
  const layoutedElkGraph = await this.elk.layout(elkGraph);
4346
4467
  const mainFlowNodes = this.graphPreparer.identifyMainFlowNodes(sizedGraph, boundaryEventTargetIds);
4347
4468
  this.mainFlowNormalizer.normalize(layoutedElkGraph, mainFlowNodes, boundaryEventTargetIds, sizedGraph);
4348
- const movedNodes = this.boundaryEventHandler.identifyNodesToMove(layoutedElkGraph, boundaryEventInfo, sizedGraph, DEBUG);
4469
+ const movedNodes = this.boundaryEventHandler.identifyNodesToMove(layoutedElkGraph, boundaryEventInfo, sizedGraph, isDebugEnabled());
4349
4470
  if (movedNodes.size > 0) {
4350
4471
  this.boundaryEventHandler.applyNodeMoves(layoutedElkGraph, movedNodes);
4351
4472
  const gatewayMoves = this.boundaryEventHandler.repositionConvergingGateways(
4352
4473
  layoutedElkGraph,
4353
4474
  movedNodes,
4354
4475
  boundaryEventInfo,
4355
- DEBUG
4476
+ isDebugEnabled()
4356
4477
  );
4357
4478
  if (gatewayMoves.size > 0) {
4358
4479
  this.boundaryEventHandler.applyNodeMoves(layoutedElkGraph, gatewayMoves);
@@ -4361,7 +4482,7 @@ var ElkLayouter = class {
4361
4482
  for (const [id, move] of gatewayMoves) {
4362
4483
  movedNodes.set(id, move);
4363
4484
  }
4364
- this.boundaryEventHandler.recalculateEdgesForMovedNodes(layoutedElkGraph, movedNodes, boundaryEventInfo, DEBUG);
4485
+ this.boundaryEventHandler.recalculateEdgesForMovedNodes(layoutedElkGraph, movedNodes, boundaryEventInfo);
4365
4486
  }
4366
4487
  this.artifactPositioner.reposition(layoutedElkGraph, artifactInfo);
4367
4488
  this.laneArranger.rearrange(layoutedElkGraph, sizedGraph);
@@ -4635,7 +4756,7 @@ function adjustGatewayEndpoint(endpoint, adjacentPoint, gatewayBounds, isSource)
4635
4756
  const gatewayCenterX = gatewayBounds.x + gatewayBounds.width / 2;
4636
4757
  const gatewayCenterY = gatewayBounds.y + gatewayBounds.height / 2;
4637
4758
  const tolerance = 1;
4638
- if (DEBUG) {
4759
+ if (isDebugEnabled()) {
4639
4760
  console.log(`[BPMN] adjustGatewayEndpoint: isSource=${isSource}`);
4640
4761
  console.log(` endpoint: (${endpoint.x}, ${endpoint.y})`);
4641
4762
  console.log(` gatewayBounds: x=${gatewayBounds.x}, y=${gatewayBounds.y}, w=${gatewayBounds.width}, h=${gatewayBounds.height}`);
@@ -4647,22 +4768,22 @@ function adjustGatewayEndpoint(endpoint, adjacentPoint, gatewayBounds, isSource)
4647
4768
  const topCorner = { x: gatewayCenterX, y: gatewayBounds.y };
4648
4769
  const bottomCorner = { x: gatewayCenterX, y: gatewayBounds.y + gatewayBounds.height };
4649
4770
  if (Math.abs(endpoint.x - gatewayBounds.x) < tolerance && Math.abs(endpoint.y - gatewayCenterY) < tolerance) {
4650
- if (DEBUG) console.log(` -> Already at LEFT corner, no adjustment`);
4771
+ if (isDebugEnabled()) console.log(` -> Already at LEFT corner, no adjustment`);
4651
4772
  return endpoint;
4652
4773
  }
4653
4774
  if (Math.abs(endpoint.x - (gatewayBounds.x + gatewayBounds.width)) < tolerance && Math.abs(endpoint.y - gatewayCenterY) < tolerance) {
4654
- if (DEBUG) console.log(` -> Already at RIGHT corner, no adjustment`);
4775
+ if (isDebugEnabled()) console.log(` -> Already at RIGHT corner, no adjustment`);
4655
4776
  return endpoint;
4656
4777
  }
4657
4778
  if (Math.abs(endpoint.y - gatewayBounds.y) < tolerance && Math.abs(endpoint.x - gatewayCenterX) < tolerance) {
4658
- if (DEBUG) console.log(` -> Already at TOP corner, no adjustment`);
4779
+ if (isDebugEnabled()) console.log(` -> Already at TOP corner, no adjustment`);
4659
4780
  return endpoint;
4660
4781
  }
4661
4782
  if (Math.abs(endpoint.y - (gatewayBounds.y + gatewayBounds.height)) < tolerance && Math.abs(endpoint.x - gatewayCenterX) < tolerance) {
4662
- if (DEBUG) console.log(` -> Already at BOTTOM corner, no adjustment`);
4783
+ if (isDebugEnabled()) console.log(` -> Already at BOTTOM corner, no adjustment`);
4663
4784
  return endpoint;
4664
4785
  }
4665
- if (DEBUG) {
4786
+ if (isDebugEnabled()) {
4666
4787
  console.log(` -> NOT at corner, will adjust`);
4667
4788
  }
4668
4789
  const result = calculateDiamondIntersection(
@@ -4673,7 +4794,7 @@ function adjustGatewayEndpoint(endpoint, adjacentPoint, gatewayBounds, isSource)
4673
4794
  isSource,
4674
4795
  adjacentPoint
4675
4796
  );
4676
- if (DEBUG) {
4797
+ if (isDebugEnabled()) {
4677
4798
  console.log(` -> Adjusted to: (${result.x}, ${result.y})`);
4678
4799
  }
4679
4800
  return result;
@@ -4978,7 +5099,7 @@ var DiagramBuilder = class {
4978
5099
  const targetIsGateway = this.isGatewayType(targetNode?.type);
4979
5100
  let waypoints = [];
4980
5101
  const hasPreCalculatedSections = edge.sections && edge.sections.length > 0 && edge.sections[0]?.bendPoints && edge.sections[0].bendPoints.length > 0;
4981
- if (DEBUG && bePosition) {
5102
+ if (isDebugEnabled() && bePosition) {
4982
5103
  console.log(`[BPMN] buildEdge ${edge.id}: preCalculated=${hasPreCalculatedSections}`);
4983
5104
  }
4984
5105
  if (bePosition && targetPosition && !hasPreCalculatedSections) {
@@ -5053,6 +5174,7 @@ var DiagramBuilder = class {
5053
5174
  }
5054
5175
  }
5055
5176
  }
5177
+ this.ensureOrthogonalWaypoints(waypoints);
5056
5178
  const edgeModel = {
5057
5179
  id: `${edge.id}_di`,
5058
5180
  bpmnElement: edge.id,
@@ -5119,6 +5241,36 @@ var DiagramBuilder = class {
5119
5241
  y: (lastPoint?.y ?? 0) - labelHeight - 4
5120
5242
  };
5121
5243
  }
5244
+ /**
5245
+ * Ensure all waypoint segments are orthogonal (horizontal or vertical)
5246
+ * If a diagonal segment is found, insert intermediate bend points to create
5247
+ * an L-shaped orthogonal path.
5248
+ *
5249
+ * Strategy: For diagonal segments, we use "horizontal first" - go horizontally
5250
+ * to the target X, then vertically to the target Y.
5251
+ */
5252
+ ensureOrthogonalWaypoints(waypoints) {
5253
+ if (waypoints.length < 2) return;
5254
+ const tolerance = 1;
5255
+ let i = 0;
5256
+ while (i < waypoints.length - 1) {
5257
+ const current = waypoints[i];
5258
+ const next = waypoints[i + 1];
5259
+ if (!current || !next) {
5260
+ i++;
5261
+ continue;
5262
+ }
5263
+ const dx = Math.abs(next.x - current.x);
5264
+ const dy = Math.abs(next.y - current.y);
5265
+ if (dx > tolerance && dy > tolerance) {
5266
+ const bendPoint = { x: next.x, y: current.y };
5267
+ waypoints.splice(i + 1, 0, bendPoint);
5268
+ i++;
5269
+ } else {
5270
+ i++;
5271
+ }
5272
+ }
5273
+ }
5122
5274
  };
5123
5275
 
5124
5276
  // src/transform/model-builder.ts