mirror of
https://github.com/OFFIS-ESC/constellation-analyzer
synced 2026-01-26 23:43:40 +00:00
Add rounded rectangle intersection handling for proper edge routing
Rounded rectangles now have shape-aware edge intersections that follow the curved corners instead of treating them as sharp corners. Implementation: - Add getRoundedRectangleIntersection() function - Detects when intersection point is near a corner - Uses circular arc intersection for corners (24px radius) - Falls back to straight edge calculation for non-corner intersections - Ensures arrows smoothly follow the rounded contours Fixes issue where edge arrows didn't correctly follow rounded rectangle outer contours.
This commit is contained in:
parent
66d47fb022
commit
603c767403
1 changed files with 84 additions and 1 deletions
|
|
@ -195,6 +195,77 @@ function getPillIntersection(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calculate intersection point with a rounded rectangle
|
||||||
|
* Handles corners as circular arcs with specified radius
|
||||||
|
*/
|
||||||
|
function getRoundedRectangleIntersection(
|
||||||
|
centerX: number,
|
||||||
|
centerY: number,
|
||||||
|
width: number,
|
||||||
|
height: number,
|
||||||
|
targetX: number,
|
||||||
|
targetY: number,
|
||||||
|
cornerRadius: number = 24,
|
||||||
|
offset: number = 2
|
||||||
|
): { x: number; y: number; angle: number } {
|
||||||
|
const w = width / 2;
|
||||||
|
const h = height / 2;
|
||||||
|
|
||||||
|
// Calculate basic rectangle intersection first
|
||||||
|
const dx = targetX - centerX;
|
||||||
|
const dy = targetY - centerY;
|
||||||
|
|
||||||
|
const xx1 = dx / (2 * w) - dy / (2 * h);
|
||||||
|
const yy1 = dx / (2 * w) + dy / (2 * h);
|
||||||
|
const a = 1 / (Math.abs(xx1) + Math.abs(yy1));
|
||||||
|
const xx3 = a * xx1;
|
||||||
|
const yy3 = a * yy1;
|
||||||
|
const x = w * (xx3 + yy3) + centerX;
|
||||||
|
const y = h * (-xx3 + yy3) + centerY;
|
||||||
|
|
||||||
|
// Determine which edge the intersection is on
|
||||||
|
const leftEdge = centerX - w;
|
||||||
|
const rightEdge = centerX + w;
|
||||||
|
const topEdge = centerY - h;
|
||||||
|
const bottomEdge = centerY + h;
|
||||||
|
|
||||||
|
// Check if intersection is near a corner (within corner radius distance from corner)
|
||||||
|
const isNearTopLeft = x < leftEdge + cornerRadius && y < topEdge + cornerRadius;
|
||||||
|
const isNearTopRight = x > rightEdge - cornerRadius && y < topEdge + cornerRadius;
|
||||||
|
const isNearBottomLeft = x < leftEdge + cornerRadius && y > bottomEdge - cornerRadius;
|
||||||
|
const isNearBottomRight = x > rightEdge - cornerRadius && y > bottomEdge - cornerRadius;
|
||||||
|
|
||||||
|
if (isNearTopLeft) {
|
||||||
|
// Top-left corner - circular arc
|
||||||
|
const cornerCenterX = leftEdge + cornerRadius;
|
||||||
|
const cornerCenterY = topEdge + cornerRadius;
|
||||||
|
return getCircleIntersection(cornerCenterX, cornerCenterY, cornerRadius, targetX, targetY, offset);
|
||||||
|
} else if (isNearTopRight) {
|
||||||
|
// Top-right corner - circular arc
|
||||||
|
const cornerCenterX = rightEdge - cornerRadius;
|
||||||
|
const cornerCenterY = topEdge + cornerRadius;
|
||||||
|
return getCircleIntersection(cornerCenterX, cornerCenterY, cornerRadius, targetX, targetY, offset);
|
||||||
|
} else if (isNearBottomLeft) {
|
||||||
|
// Bottom-left corner - circular arc
|
||||||
|
const cornerCenterX = leftEdge + cornerRadius;
|
||||||
|
const cornerCenterY = bottomEdge - cornerRadius;
|
||||||
|
return getCircleIntersection(cornerCenterX, cornerCenterY, cornerRadius, targetX, targetY, offset);
|
||||||
|
} else if (isNearBottomRight) {
|
||||||
|
// Bottom-right corner - circular arc
|
||||||
|
const cornerCenterX = rightEdge - cornerRadius;
|
||||||
|
const cornerCenterY = bottomEdge - cornerRadius;
|
||||||
|
return getCircleIntersection(cornerCenterX, cornerCenterY, cornerRadius, targetX, targetY, offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Straight edge - use rectangle calculation
|
||||||
|
const angle = Math.atan2(y - centerY, x - centerX);
|
||||||
|
const offsetX = x + Math.cos(angle) * offset;
|
||||||
|
const offsetY = y + Math.sin(angle) * offset;
|
||||||
|
|
||||||
|
return { x: offsetX, y: offsetY, angle };
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Calculate the intersection point between a line and a node shape
|
* Calculate the intersection point between a line and a node shape
|
||||||
* Returns the intersection point and the normal angle at that point
|
* Returns the intersection point and the normal angle at that point
|
||||||
|
|
@ -267,8 +338,20 @@ function getNodeIntersection(
|
||||||
targetCenterY,
|
targetCenterY,
|
||||||
offset
|
offset
|
||||||
);
|
);
|
||||||
|
} else if (intersectionShape === 'roundedRectangle') {
|
||||||
|
// Rounded rectangle with circular corner arcs
|
||||||
|
return getRoundedRectangleIntersection(
|
||||||
|
intersectionCenterX,
|
||||||
|
intersectionCenterY,
|
||||||
|
intersectionNodeWidth,
|
||||||
|
intersectionNodeHeight,
|
||||||
|
targetCenterX,
|
||||||
|
targetCenterY,
|
||||||
|
24, // Corner radius matches RoundedRectangleShape component
|
||||||
|
offset
|
||||||
|
);
|
||||||
} else {
|
} else {
|
||||||
// Rectangle and roundedRectangle use the original algorithm with offset
|
// Rectangle uses the original algorithm with offset
|
||||||
const w = intersectionNodeWidth / 2;
|
const w = intersectionNodeWidth / 2;
|
||||||
const h = intersectionNodeHeight / 2;
|
const h = intersectionNodeHeight / 2;
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue