ArcTo / ArcSegment like GraphicsPath.AddArc

This article gives a simpler interface (facade) to use the ArcTo Method… Providing a GraphicsPath AddArc like method.

public static GeometryDrawing GetArc(Rect rect, Angle start, Angle sweep){}

Today I implemented an adapter for GDI+ and WPF to draw similar objects. Simple ons like line, rectangle, ellipse,.. but I kinda struggled with arc??!!

public abstract void ArcTo(
	Point point,
	Size size,
	double rotationAngle,
	bool isLargeArc,
	SweepDirection sweepDirection,
	bool isStroked,
	bool isSmoothJoin
)

This is an Api that has way to much parameters if you ask me. All I need (and want) was a api like the AddArc on the GDI+ GraphicsPath which looks like :

public void AddArc(
	RectangleF rect,
	float startAngle,
	float sweepAngle
)

Which is all I need anyway.

In My Code I’m using the ArcTo method on a StreamGeometryContext instance (ArcSegment has a similair api so I’mmentioning it). First you have to move to the first point (which is done by calling BeginFigure) then you have to add a second point. Next argument Size has an interesting description on the MSDN documentation:

The width and height of an oval whose perimeter is used to draw the angle. If the oval is very rounded in all directions, the arc will be rounded, if it is nearly flat, so will the arc. For example, a very large width and height would represent a very large oval, which would give a slight curvature for the angle.

Ehh.. right.. how about just saying radius?

The next argument, rotationangle, can be done with a Matrix transform (rotate),.. so why it it there?

well the others make sense…

Well here is my facade to the ArcTo:

public static GeometryDrawing GetArc(Rect rect, Angle start, Angle sweep)

the way i like it,.. nice and simple.

public static GeometryDrawing GetArc(Rect rect, Angle start, Angle sweep)
        {
            GeometryDrawing ret = new GeometryDrawing();
            StreamGeometry geo = new StreamGeometry();

            //Set correct parameters
            SweepDirection sweepDir = sweep.Degrees < 0 ? SweepDirection.Counterclockwise : SweepDirection.Clockwise;
            bool isLargeArc = Math.Abs(sweep.Degrees) > 180;

            double cx = rect.Width / 2;
            double cy = rect.Height / 2;
            //Calculate start point
            double x1 = rect.X + cx + (Math.Cos(start.Radians) * cx);
            double y1 = rect.Y + cy + (Math.Sin(start.Radians) * cy);
            //Calculate end point
            double x2 = rect.X + cx + (Math.Cos(start.Radians + sweep.Radians) * cx);
            double y2 = rect.Y + cy + (Math.Sin(start.Radians + sweep.Radians) * cy);

            using (StreamGeometryContext ctx = geo.Open())
            {
                ctx.BeginFigure(new Point(x1, y1), false, false);
                ctx.ArcTo(new Point(x2, y2), new Size(cx,cy), 0, isLargeArc, sweepDir, true, false);
            }

            ret.Geometry = geo;
            return ret;
        }

!NOTE! The Angle class is just a simple converter form degrees to radians Nothing to worry about….

Here you can download a sample solution to get the demo working.

Or use this Extention Method in a static class..

public static void AddArc(this StreamGeometryContext ctx, Rect rect, double startRad, double sweepRad)
{
SweepDirection sweepDir = sweepRad < 0 ? SweepDirection.Counterclockwise : SweepDirection.Clockwise;
bool isLargeArc = Math.Abs(sweepRad) > Math.PI;
double cx = rect.Width / 2;
double cy = rect.Height / 2;
double x1 = rect.X + cx + (Math.Cos(startRad) * cx);
double y1 = rect.Y + cy + (Math.Sin(startRad) * cy);
double x2 = rect.X + cx + (Math.Cos(startRad + sweepRad) * cx);
double y2 = rect.Y + cy + (Math.Sin(startRad + sweepRad) * cy);
ctx.BeginFigure(new Point(x1, y1), false, false);
ctx.ArcTo(new Point(x2, y2), new Size(cx, cy), 0, isLargeArc, sweepDir, true, false);
}

4 Responses to “ArcTo / ArcSegment like GraphicsPath.AddArc”

Leave a Reply