private static Line ClosestLine(Rect rect, Point p) { var angle = new Vector(1, 1).AngleTo(p.VectorTo(rect.CenterPoint())); if (angle >= 0 && angle <= 90) { return rect.TopLine(); } if (angle >= 90 && angle <= 180) { return rect.RightLine(); } if (angle >= -90 && angle <= 0) { return rect.LeftLine(); } if (angle >= -180 && angle <= -90) { return rect.BottomLine(); } throw new InvalidOperationException("Could not find closest line"); }
internal Point? FirstIntersectionWith(Rect rectangle) { var quadrant = rectangle.Contains(this.Point) ? this.Direction.Quadrant() : this.Direction.Negated().Quadrant(); switch (quadrant) { case Quadrant.NegativeXPositiveY: return IntersectionPoint(this, rectangle.LeftLine(), true) ?? IntersectionPoint(this, rectangle.BottomLine(), true); case Quadrant.PositiveXPositiveY: return IntersectionPoint(this, rectangle.RightLine(), true) ?? IntersectionPoint(this, rectangle.BottomLine(), true); case Quadrant.PositiveXNegativeY: return IntersectionPoint(this, rectangle.RightLine(), true) ?? IntersectionPoint(this, rectangle.TopLine(), true); case Quadrant.NegativeXNegativeY: return IntersectionPoint(this, rectangle.LeftLine(), true) ?? IntersectionPoint(this, rectangle.TopLine(), true); default: throw new ArgumentOutOfRangeException(); } }
private Point? GetPointOnTarget(Point sourceMidPoint, Rect target) { switch (this.Vertical) { case VerticalPlacement.Auto: switch (this.Horizontal) { case HorizontalPlacement.Auto: var closestLine = ClosestLine(target, sourceMidPoint); return AutoPoint(sourceMidPoint.LineTo(target.CenterPoint()), closestLine); case HorizontalPlacement.Left: return AutoPoint(sourceMidPoint.LineTo(target.CenterPoint()), target.LeftLine()); case HorizontalPlacement.Center: return sourceMidPoint.Closest(target.BottomLine(), target.TopLine()) .MidPoint; case HorizontalPlacement.Right: return AutoPoint(sourceMidPoint.LineTo(target.CenterPoint()), target.RightLine()); default: throw new ArgumentOutOfRangeException(); } case VerticalPlacement.Top: switch (this.Horizontal) { case HorizontalPlacement.Auto: return AutoPoint(sourceMidPoint.LineTo(target.CenterPoint()), target.TopLine()); case HorizontalPlacement.Left: return target.TopLeft; case HorizontalPlacement.Center: return PointExt.MidPoint(target.TopLeft, target.TopRight); case HorizontalPlacement.Right: return target.TopRight; default: throw new ArgumentOutOfRangeException(); } case VerticalPlacement.Center: switch (this.Horizontal) { case HorizontalPlacement.Auto: return sourceMidPoint.Closest(target.LeftLine(), target.RightLine()) .MidPoint; case HorizontalPlacement.Left: return PointExt.MidPoint(target.BottomLeft, target.TopLeft); case HorizontalPlacement.Center: return PointExt.MidPoint(target.TopLeft, target.BottomRight); case HorizontalPlacement.Right: return PointExt.MidPoint(target.BottomRight, target.TopRight); default: throw new ArgumentOutOfRangeException(); } case VerticalPlacement.Bottom: switch (this.Horizontal) { case HorizontalPlacement.Auto: return AutoPoint(sourceMidPoint.LineTo(target.CenterPoint()), target.BottomLine()); case HorizontalPlacement.Left: return target.BottomLeft; case HorizontalPlacement.Center: return PointExt.MidPoint(target.BottomLeft, target.BottomRight); case HorizontalPlacement.Right: return target.BottomRight; default: throw new ArgumentOutOfRangeException(); } default: throw new ArgumentOutOfRangeException(); } }