Does anyone know how e.Graphics.DrawArc is implemented?
Graphics.DrawArc calls the built-in function GdipDrawArcI in gdiplus.dll. This function calls the arc2polybezier function in the same DLL. Apparently, the Bezier curve is used to approximate the elliptical arc. To get the same endpoint that you are looking for, we would have to reconstruct this function and find out how it works.
Fortunately, the good people at Wine have already done for us .
Here is the arc2polybezier method, roughly translated from C to C # (note that since it was translated from Wine, this code is licensed under LGPL ):
internal class GdiPlus { public const int MAX_ARC_PTS = 13; public static int arc2polybezier(Point[] points, double x1, double y1, double x2, double y2, double startAngle, double sweepAngle) { int i; double end_angle, start_angle, endAngle; endAngle = startAngle + sweepAngle; unstretch_angle(ref startAngle, x2/2.0, y2/2.0); unstretch_angle(ref endAngle, x2/2.0, y2/2.0); start_angle = startAngle; for(i = 0; i < MAX_ARC_PTS - 1; i += 3) { if(sweepAngle > 0.0) { if(start_angle >= endAngle) break; end_angle = Math.Min(start_angle + Math.PI/2, endAngle); } else { if(start_angle <= endAngle) break; end_angle = Math.Max(start_angle - Math.PI/2, endAngle); } if(points != null) { Point[] returnedPoints = add_arc_part(x1, y1, x2, y2, start_angle, end_angle, i == 0);
Using this code as a guide, as well as some math, I wrote this class of endpoint calculator (not LGPL):
using System; using System.Windows; internal class DrawArcEndPointCalculator { public Point GetFinalPoint(Point startPoint, double width, double height, double startAngle, double sweepAngle) { Point radius = new Point(width / 2.0, height / 2.0); double endAngle = startAngle + sweepAngle; int sweepDirection = (sweepAngle < 0 ? -1 : 1);
Here are some examples. Please note that the first example you cited is incorrect - for these initial values DrawArc() will have an endpoint (0.58, 0.97), not (0.92, 0.33).
Point startPoint = new Point(0, 0); double width = 100; double height = 200; double startAngle = 180; double sweepAngle = 135; DrawArcEndPointCalculator _endPointCalculator = new DrawArcEndPointCalculator(); Point lastPoint = _endPointCalculator.GetFinalPoint(startPoint, width, height, startAngle, sweepAngle); Console.WriteLine("X = {0}, Y = {1}", lastPoint.X, lastPoint.Y);