CompositionProToolkit v0.5.0 Holiday Edition released!

After a long gap, I am back with another update to CompositionProToolkit. This time I have added a few helper classes for the Win2d project.

CanvasPathBuilder extension methods

CanvasPathBuilder allows you to create a freeform path using lines, arcs, Quadratic Beziers and Cubic Beziers. You can then convert this path to a CanvasGeometry. Each path is composed of one or more figures. Each figure definition is encapsulated by the BeginFigure() and EndFigure() methods of CanvasPathBuilder.

If you want to add a circle(or ellipse) or a polygon figure to your path, you need to break the figure into curves or line segments and add them to the path one by one.

I have added the following extension methods to the CanvasPathBuilder to add a circle, ellipse or a polygon figure directly to your path

public static void AddCircleFigure (CanvasPathBuilder pathBuilder, Vector2 center, float radius);
public static void AddCircleFigure (CanvasPathBuilder pathBuilder, float x, float y, float radius);
public static void AddEllipseFigure(CanvasPathBuilder pathBuilder, Vector2 center, float radiusX, float radiusY);
public static void AddEllipseFigure(CanvasPathBuilder pathBuilder, float x, float y, float radiusX, float radiusY);
public static void AddPolygonFigure(CanvasPathBuilder pathBuilder, int numSides, Vector2 center, float radius);
public static void AddPolygonFigure(CanvasPathBuilder pathBuilder, int numSides, float x, float y, float radius);

In the AddPolygonFigure, the radius parameter indicates the distance between the center of the polygon and its vertices.

Note: These methods add the required curves or line segments to your path internally. Since these methods add a figure to your path, you can invoke them only after closing the current figure in the path. They must not be called in between BeginFigure() and EndFigure() calls, otherwise an ArgumentException will be raised. These extension methods call the BeginFigure() and EndFigure() CanvasPathBuilder methods internally.

CanvasGeometryParser

Last month, while working on my new UWP app, I was using Win2d extensively and found out that in Win2d there was no support for the Path Mini Langugage which is quite popular in WPF/Silverlight. It is a powerful and complex mini-language which you can use to specify path geometries more compactly using Extensible Application Markup Language (XAML). It is derived mainly from the SVG (Scalable Vector Graphics) Path language specification. Here is an example

    M8.64,223.948c0,0,143.468,3.431,185.777-181.808c2.673-11.702-1.23-20.154,1.316-33.146h16.287c0,0-3.14,17.248,1.095,30.848c21.392,68.692-4.179,242.343-204.227,196.59L8.64,223.948z

So I added the CanvasGeometryParser class which parses the above string and converts it into appropriate CanvasPathBuilder commands. It contains the following static methods

public static CanvasGeometry Parse(ICanvasResourceCreator resourceCreator, System.String pathData, StringBuilder logger = null);

The logger parameter in this method is an option argument of type StringBuilder which can be used to obtain the CanvasPathBuilder commands in text format. It is mainly intended for information/debugging purpose only.

Here is an example usage of the CanvasGeometryParser

private void OnCanvasDraw(CanvasControl sender, CanvasDrawEventArgs args)
{
    string data = "M8.64,223.948c0,0,143.468,3.431,185.777-181.808c2.673-11.702-1.23-20.154," + 
        "1.316-33.146h16.287c0,0-3.14,17.248,1.095,30.848c21.392,68.692-4.179,242.343-204.227,196.59L8.64,223.948z";
    var geometry = CanvasGeometryParser.Parse(sender, data);

    args.DrawingSession.FillGeometry(geometry, Colors.Yellow);
    args.DrawingSession.DrawGeometry(geometry, Colors.Black, 2f);
}

Check out the Sample Gallery project in GitHub where you can interact with the CanvasGeometryParser by providing the SVG/XAML path data and converting it to CanvasGeometry. You can alter the StrokeThickness, StrokeColor and FillColor of the rendered geometry.

canvasgeometryparser

You can view the CanvasPathBuilder commands called to create the parsed geometry.

CanvasGeometryParser_cmds.jpg

Based on the SVG (Scalable Vector Graphics) Path language specification, the following rules must be followed to create the path data

  • All instructions are expressed as one character (e.g., a moveto is expressed as an M).
  • Superfluous white space and separators such as commas can be eliminated (e.g., M 100 100 L 200 200 contains unnecessary spaces and could be expressed more compactly as M100 100L200 200).
  • The command letter can be eliminated on subsequent commands if the same command is used multiple times in a row (e.g., you can drop the second “L” in M 100 200 L 200 100 L -100 -200 and use M 100 200 L 200 100 -100 -200 instead).
  • Relative versions of all commands are available (uppercase means absolute coordinates, lowercase means relative coordinates).

In the table below, the following notation is used:

() indicates grouping of parameters.

+ indicates 1 or more of the given parameter(s) is required.

Command Command Letter Parameters Remarks
MoveTo M (x y)+ Starts a new sub-path at the given (x,y) coordinate. If a moveto is followed by multiple pairs of coordinates, the subsequent pairs are treated as implicit lineto commands.
ClosePath Z none Closes the current subpath by drawing a straight line from the current point to current subpath’s initial point.
LineTo L (x y)+ Draws a line from the current point to the given (x,y) coordinate which becomes the new current point.
HorizontalLineTo H (x)+ Draws a horizontal line from the current point (cpx, cpy) to (x, cpy).
VerticalLineTo V (y)+ Draws a vertical line from the current point (cpx, cpy) to (cpx, y).
CubicBezier C (x1 y1 x2 y2 x y)+ Draws a cubic Bézier curve from the current point to (x,y) using (x1,y1) as the control point at the beginning of the curve and (x2,y2) as the control point at the end of the curve.
SmoothCubicBezier S (x2 y2 x y)+ Draws a cubic Bézier curve from the current point to (x,y). The first control point is assumed to be the reflection of the second control point on the previous command relative to the current point. (If there is no previous command or if the previous command was not an C, c, S or s, assume the first control point is coincident with the current point.)
QuadraticBezier Q (x1 y1 x y)+ Draws a quadratic Bézier curve from the current point to (x,y) using (x1,y1) as the control point.
SmoothQuadraticBezier T (x y)+ Draws a quadratic Bézier curve from the current point to (x,y). The control point is assumed to be the reflection of the control point on the previous command relative to the current point. (If there is no previous command or if the previous command was not a Q, q, T or t, assume the control point is coincident with the current point.)
Arc A (radiusX radiusY angle isLargeFlag SweepDirection x y)+ Draws an elliptical arc from the current point to (x, y).
EllipseFigure O (radiusX radiusY x y)+ Adds an Ellipse Figure to the path. The current point remains unchanged.
PolygonFigure P (numSides radius x y)+ Adds an n-sided Polygon Figure to the path. The current point remains unchanged.

The latest code is available in GitHub and the Nuget package is available here.

Happy Holidays! 🙂

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s