Skip to content

fix(connection): symmetric bezier handles and NaN-safe rectangle offset - #291

Open
marko1olo wants to merge 4 commits into
miroiu:masterfrom
marko1olo:fix/bezier-control-point-halving
Open

marko1olo wants to merge 4 commits into
miroiu:masterfrom
marko1olo:fix/bezier-control-point-halving

Conversation

@marko1olo

Copy link
Copy Markdown
Contributor

Fixes two geometry bugs in connection rendering:

1. Asymmetric bezier handles for opposite orientations (fixes #281)

controlPointVertical was computed from controlPoint before the *= 0.5 scale, so when SourceOrientation != TargetOrientation only one of the two Bézier handles was halved — the other kept the full-length vector, producing an asymmetric curve.

Root cause: System.Windows.Vector is a struct; assigning it copies by value. The vertical copy captured the pre-halved value.

// Before fix
Source=(0,0) Target=(200,100) SourceOrientation=Vertical, TargetOrientation=Horizontal
  expected  p1=(0,50)   p2=(150,100)   (both handles = 50)
  actual    p1=(0,100)  p2=(150,100)   (source handle = 100, target handle = 50)

Fix: derive controlPointVertical after the scale so both handles share the same magnitude.

2. NaN offset in ConnectionOffsetMode.Rectangle for axis-aligned connections (fixes #284)

For a horizontal connection with the default offset Size(14, 0), the face-selection condition evaluates to 0 < 0 (false), so the vertical branch runs and computes:

result.Y = Sign(0) * 0   = 0
result.X = 1/Tan(0) * 0  = Infinity * 0  = NaN

WPF draws nothing for a non-finite geometry and raises no exception, making the connection invisibly disappear.

Fix: change < to <= so ties (both sides zero) prefer the horizontal face; add an IsFinite guard to catch any remaining degenerate combos.

marko1olo and others added 4 commits July 29, 2026 23:53
Two geometry fixes:

1. fix(bezier): symmetric control-point halving for opposite orientations (miroiu#281)
   controlPointVertical was computed from controlPoint *before* the 0.5 scale,
   so when SourceOrientation != TargetOrientation only one handle was halved.
   Moving the vertical copy after the scale makes both handles equal.

2. fix(offset): NaN-free GetRectangleModeOffset for axis-aligned connections (miroiu#284)
   For a horizontal connection with the default offset (Width=14, Height=0):
   both sides of the face-selection condition are zero, so < was false and the
   vertical branch ran, producing 1/Tan(0)*0 = Inf*0 = NaN — causing the
   connection to disappear silently. Changing < to <= prefers the horizontal
   face in ties, and an IsFinite guard stops any remaining degenerate NaNs.
@slivingston

Copy link
Copy Markdown

I am not involved in this project, but I want to give a heads up that we recently banned this user from our project (https://github.com/python-control/python-control). They were also banned from another unrelated project: terrazzoapp/terrazzo#825 (comment)

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

2 participants