/// <inheritdoc/>
protected override void UpdateConnectorOffset()
{
var hasTarget =
this.PlacementTarget?.IsVisible == true ||
!this.PlacementRectangle.IsEmpty;
if (this.IsVisible && this.RenderSize.Width > 0 && hasTarget)
{
if (!this.IsLoaded)
{
#pragma warning disable VSTHRD001 // Avoid legacy thread switching APIs
_ = this.Dispatcher.BeginInvoke(new Action(this.UpdateConnectorOffset), DispatcherPriority.Loaded);
#pragma warning restore VSTHRD001 // Avoid legacy thread switching APIs
return;
}
var selfRect = new Rect(new Point(0, 0).ToScreen(this), this.RenderSize).ToScreen(this);
var targetRect = this.GetTargetRect();
var ellipse = new Ellipse(selfRect);
var tp = this.PlacementOptions?.GetPointOnTarget(selfRect, targetRect);
if (tp is null || ellipse.Contains(tp.Value))
{
this.InvalidateProperty(ConnectorOffsetProperty);
return;
}
if (ellipse.Contains(tp.Value))
{
this.SetCurrentValue(ConnectorOffsetProperty, new Vector(0, 0));
return;
}
var mp = ellipse.CenterPoint;
var ip = new Ray(mp, mp.VectorTo(tp.Value)).FirstIntersectionWith(ellipse);
Debug.Assert(ip != null, "Did not find an intersection, bug in the library");
//// ReSharper disable once ConditionIsAlwaysTrueOrFalse
if (ip is null)
{
// failing silently in release
this.InvalidateProperty(ConnectorOffsetProperty);
}
else
{
var v = tp.Value - ip.Value;
// ReSharper disable once CompareOfFloatsByEqualityOperator
if (this.PlacementOptions != null && v.Length > 0 && this.PlacementOptions.Offset != 0)
{
v -= this.PlacementOptions.Offset * v.Normalized();
}
this.SetCurrentValue(ConnectorOffsetProperty, v);
}
}
else
{
this.InvalidateProperty(ConnectorOffsetProperty);
}
}