The following function allows you to obtain (x,y) coordinates within a 3d perspective pie slice by specifying the pie dimensions, the radius (Distance from the pie origin out) and the inner angle (Degrees from the pie start angle, clockwise). The first step is to inverse our angle since our trig functions assume that degrees increase counter-clockwise from the x axis. The .NET pie function works in the opposite way, with degrees increasing clockwise from the x axis. Next we convert the degrees into radians. Then calulate the absolute coordinates of the pie origin so we can transform the relative corrdinates returned by the trig functions. Next we do the math; the the cosine of the target radian multipled by the radius gives us the X coordinate and the sine of the same gives us the Y coordinate. We need to inverse the Y coordinate since the trig functions assume a grid with an ascending Y axis above the X axis and Windows is the oppisite; ascending Y axis below the X axis. Note: This method does not work for the default pie behavior. This method only works when angles are transformed to a 3d perspective.
The Get3dPiePoint and support functions:
Private Function Get3dPiePoint(ByVal Bounds As System.Drawing.Rectangle, _ ByVal Angle As Single, _ ByVal SweepAngle As Single, _ ByVal XRadius As Integer, ByVal YRadius As Integer, _ ByVal InnerAngle As Single) As Point Dim MidRadian As Single = ToRadian(GetInverseAngle(Angle, InnerAngle)) Dim TransformX As Integer = Bounds.X + (Bounds.Width / 2) Dim TransformY As Integer = Bounds.Y + (Bounds.Height / 2) Return New Point((Math.Cos(MidRadian) * XRadius) + TransformX, (Math.Sin(MidRadian) * YRadius * -1) + TransformY)End Function
Private Function GetInverseAngle(ByVal StartAngle As Single, _ ByVal InnerAngle As Single) As Single Return 360 - (StartAngle + InnerAngle)End Function
Private Function ToRadian(ByVal Angle As Single) As Single Return (Math.PI * Angle) / 180End Function
The following code snippet demonstrates how to draw a text label in the center of a 3d perspective pie slice.
Private Sub Form1_Paint(ByVal sender As Object, _ ByVal e As System.Windows.Forms.PaintEventArgs) Handles Me.Paint Dim PieBounds As New Rectangle(20, 20, 400, 100) Dim PieAngle As Single = 150 Dim PieSweepAngle As Single = 100 Dim PieText As String = "Strongbadia (28%)" Dim PieTextFont As New Font("Arial", 10, FontStyle.Bold) Dim PieTextPoint As Point Dim PieTextXRadius As Single = PieBounds.Width / 4 Dim PieTextYRadius As Single = PieBounds.Height / 4 Dim PieTextAngle As Single = PieSweepAngle / 2 Dim PieTextBounds As SizeF '--> Grab the centerline of the pie slice (Sweep angle div 2) '--> and half the radius (Diameter div 4) PieTextPoint = Get3dPiePoint(PieBounds, PieAngle, PieSweepAngle, PieTextXRadius, PieTextYRadius, PieTextAngle) '--> Grab the dimensions of the text PieTextBounds = e.Graphics.MeasureString(PieText, PieTextFont) '--> Determine the 3d angles PieSweepAngle = To3dSweepAngle(PieBounds, PieAngle, PieSweepAngle) PieAngle = To3dAngle(PieBounds, PieAngle) '--> Draw the pie e.Graphics.FillPie(Brushes.SteelBlue, PieBounds, PieAngle, PieSweepAngle) '--> Center the text over the mid point PieTextPoint.X -= PieTextBounds.Width / 2 PieTextPoint.Y -= PieTextBounds.Height / 2 '--> Draw the text e.Graphics.DrawString(PieText, PieTextFont, Brushes.White, PieTextPoint)End SubPrivate Function To3dSweepAngle(ByVal Bounds As Rectangle, _ ByVal Angle As Single, _ ByVal SweepAngle As Single) As Single If SweepAngle Mod 180 <> 0 Then Dim Angle3d As Single = To3dAngle(Bounds, Angle) SweepAngle = To3dAngle(Bounds, Angle + SweepAngle) - Angle3d End If If SweepAngle < 0 Then SweepAngle += 360 End If Return SweepAngleEnd FunctionPrivate Function To3dAngle(ByVal Bounds As System.Drawing.Rectangle, _ ByVal Angle As Single) As Single Dim Radians As Single = ToRadian(Angle) Dim X As Double = Bounds.Width * Math.Cos(Radians) Dim Y As Double = Bounds.Height * Math.Sin(Radians) Dim Angle3D As Single = Math.Atan2(Y, X) * 180 / Math.PI If Angle3D < 0 Then Return Angle3D + 360 Else Return Angle3D End IfEnd Function