Private Function GetPointsForArrowCallout(centerX As Double, centerY As Double, rectWidth As Double, rectHeight As Double) As PointCollection
Dim points = New PointCollection()
Dim rectLeft As Double = centerX - rectWidth / 2
Dim rectRight As Double = centerX + rectWidth / 2
Dim rectTop As Double = centerY - rectHeight / 2
Dim rectBottom As Double = centerY + rectHeight / 2
Dim angle As Double = Math.Atan2(-centerY, centerX)
Dim angleOffset1 As Double = 0.4
Dim angleOffset2 As Double = 0.04
Dim arrowHeight As Double = 0.4 * rectHeight
Dim hypotenuse As Double = arrowHeight / Math.Cos(angleOffset1)
Dim subHypotenuse As Double = arrowHeight / Math.Cos(angleOffset2)
Dim isNearBottom As Boolean = Math.Abs(rectTop) > Math.Abs(rectBottom)
Dim nearHorizontalEdge As Double = If(isNearBottom, rectBottom, rectTop)
Dim isNearRight As Boolean = Math.Abs(rectLeft) > Math.Abs(rectRight)
Dim nearVerticalEdge As Double = If(isNearRight, rectRight, rectLeft)
Dim isHorizontalCrossed As Boolean = Math.Abs(nearHorizontalEdge) > Math.Abs(nearVerticalEdge)
Dim nearEdge As Double = If(isHorizontalCrossed, nearHorizontalEdge, nearVerticalEdge)
Dim factor As Integer = If(nearEdge > 0, -1, 1)
Dim crossedPointOffsetToCenter As Double = If(isHorizontalCrossed, rectHeight / (2 * Math.Tan(angle)) * factor, rectWidth * Math.Tan(angle) * factor / 2)
' Arrow points
points.Add(New Point(0, 0))
points.Add(New Point(Math.Cos(angle + angleOffset1) * hypotenuse, -Math.Sin(angle + angleOffset1) * hypotenuse))
points.Add(New Point(Math.Cos(angle + angleOffset2) * subHypotenuse, -Math.Sin(angle + angleOffset2) * subHypotenuse))
' Rectangle points
If isHorizontalCrossed Then
points.Add(New Point(-nearEdge / Math.Tan(angle + angleOffset2), nearEdge))
If isNearBottom Then
points.Add(New Point(rectLeft, rectBottom))
points.Add(New Point(rectLeft, rectTop))
points.Add(New Point(rectRight, rectTop))
points.Add(New Point(rectRight, rectBottom))
Else
points.Add(New Point(rectRight, rectTop))
points.Add(New Point(rectRight, rectBottom))
points.Add(New Point(rectLeft, rectBottom))
points.Add(New Point(rectLeft, rectTop))
End If
points.Add(New Point(-nearEdge / Math.Tan(angle - angleOffset2), nearEdge))
Else
points.Add(New Point(nearEdge, -nearEdge * Math.Tan(angle + angleOffset2)))
If isNearRight Then
points.Add(New Point(rectRight, rectBottom))
points.Add(New Point(rectLeft, rectBottom))
points.Add(New Point(rectLeft, rectTop))
points.Add(New Point(rectRight, rectTop))
Else
points.Add(New Point(rectLeft, rectTop))
points.Add(New Point(rectRight, rectTop))
points.Add(New Point(rectRight, rectBottom))
points.Add(New Point(rectLeft, rectBottom))
End If
points.Add(New Point(nearEdge, -nearEdge * Math.Tan(angle - angleOffset2)))
End If
' Arrow points
points.Add(New Point(Math.Cos(angle - angleOffset2) * subHypotenuse, -Math.Sin(angle - angleOffset2) * subHypotenuse))
points.Add(New Point(Math.Cos(angle - angleOffset1) * hypotenuse, -Math.Sin(angle - angleOffset1) * hypotenuse))
Return points
End Function