mirror of
https://github.com/OFFIS-ESC/constellation-analyzer
synced 2026-03-13 12:08:46 +00:00
Fix pill shape self-loop geometry to follow cap curvature
Some checks failed
CI / test (push) Has been cancelled
Some checks failed
CI / test (push) Has been cancelled
Previously the pill branches behaved like rectangles: the target point was pinned to the rightmost cap point with a linearly growing y, and the vertical pill source started from the wrong end of the cap. - Horizontal pill: target now travels along the right cap surface via a cap angle (-PI/2 → 0), so both tx/ty stay on the curve - Horizontal pill: source clamped to the straight top section so it never crosses into the left cap area - Vertical pill: source now starts at the corner (angle=0, rightmost point of top cap) and rotates toward the top as loopOffset grows, matching the corner-anchoring used by other shapes Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
ed18b11dc9
commit
4322f3cf63
1 changed files with 23 additions and 12 deletions
|
|
@ -574,25 +574,36 @@ function getSelfLoopParams(
|
|||
const capRadius = isHorizontal ? nodeHeight / 2 : nodeWidth / 2;
|
||||
|
||||
if (isHorizontal) {
|
||||
// Horizontal pill: source on top straight edge (left of corner), target on right cap (below corner)
|
||||
sx = rightEdge - loopOffset * 0.8;
|
||||
// The top-right corner is where the top straight edge meets the right semicircle cap.
|
||||
// Source: spreads leftward along the top straight edge from the corner.
|
||||
// Target: spreads downward along the right cap surface from the top of the cap.
|
||||
const rightCapCenterX = nodePosition.x + nodeWidth - capRadius;
|
||||
|
||||
sx = Math.max(nodePosition.x + capRadius, rightCapCenterX - loopOffset * 0.6);
|
||||
sy = topEdge;
|
||||
sourceAngle = -Math.PI / 2;
|
||||
|
||||
const rightCapCenterX = nodePosition.x + nodeWidth - capRadius;
|
||||
tx = rightCapCenterX + capRadius + 2;
|
||||
ty = topEdge + loopOffset * 0.5;
|
||||
targetAngle = 0;
|
||||
// Angle on the right cap: -PI/2 = top of cap (corner), 0 = rightmost point.
|
||||
// Innermost loop targets near the top; outer loops rotate toward the right.
|
||||
const targetCapAngle = -Math.PI / 2 + Math.min(Math.PI / 2, (loopOffset / capRadius) * 0.8);
|
||||
tx = rightCapCenterX + Math.cos(targetCapAngle) * (capRadius + 2);
|
||||
ty = centerY + Math.sin(targetCapAngle) * (capRadius + 2);
|
||||
targetAngle = targetCapAngle;
|
||||
} else {
|
||||
// Vertical pill: source on top cap (near right), target on right straight edge (near top)
|
||||
// The top-right corner is where the right straight edge meets the top semicircle cap.
|
||||
// Source: spreads upward along the top cap from the corner.
|
||||
// Target: spreads downward along the right straight edge from the corner.
|
||||
const topCapCenterY = nodePosition.y + capRadius;
|
||||
const sourceAngleRad = -Math.PI / 2 + (loopOffset / nodeWidth) * Math.PI / 4;
|
||||
sx = centerX + Math.cos(sourceAngleRad) * (capRadius + 2);
|
||||
sy = topCapCenterY + Math.sin(sourceAngleRad) * (capRadius + 2);
|
||||
sourceAngle = sourceAngleRad;
|
||||
|
||||
// Angle on the top cap: 0 = rightmost point of cap (corner), -PI/2 = top of cap.
|
||||
// Innermost loop sources near the corner; outer loops rotate toward the top.
|
||||
const sourceCapAngle = Math.max(-Math.PI / 2, -(loopOffset / capRadius) * 0.8);
|
||||
sx = centerX + Math.cos(sourceCapAngle) * (capRadius + 2);
|
||||
sy = topCapCenterY + Math.sin(sourceCapAngle) * (capRadius + 2);
|
||||
sourceAngle = sourceCapAngle;
|
||||
|
||||
tx = rightEdge;
|
||||
ty = topEdge + loopOffset * 0.5;
|
||||
ty = topCapCenterY + loopOffset * 0.5;
|
||||
targetAngle = 0;
|
||||
}
|
||||
} else if (sourceShape === 'ellipse') {
|
||||
|
|
|
|||
Loading…
Reference in a new issue