Drawing arbitrary shapes
Table of contents
In addition to rectangle, it is possible to fill or stroke arbitrary shapes. This is achieved by using the FillPath
and StrokePath
methods of the Graphics
object. These methods accept a GraphicsPath
parameter, which describes the shape that will be drawn.
Various methods of the GraphicsPath
class can be used to create any kind of shape. To set the starting point of the path, you should always start by using the MoveTo
method. Then, different methods let you add different kinds of segments to the path; for example, LineTo
adds a straight line, while CubicBezierTo
adds a cubic Bézier segment.
All these methods return the GraphicsPath
itself, which makes it possible to chain the calls. For example, the following two examples are perfectly equivalent:
Drawing a line
As explained above, a straight line can be drawn by setting the start point with the MoveTo
method, and the end point with the LineTo
method. Like most methods of the GraphicsPath
class, these methods have an overload that accepts the coordinates of the points as two double
s (i.e., x
and y
), as well as an overload that accepts a single Point
argument containing both coordinates.
The following example shows how a straight line can be stroked (of course, there is no point in filling a line):
Drawing a curve
In addition to drawing straight lines, VectSharp can be used to draw cubic Bézier curve segments.
A cubic Bézier curve is identified by four points: the start point (P0), the end point (P3), and two control points (P1 and P2). The start point is the end point of the previous segment in the path (as always, if the Bézier curve is the first segment in the path, you should use the MoveTo
method to set it), while the other three points are supplied as parameters to the CubicBezierTo
method. Like before, each point can be specified either by a pair of double
s, or by a single Point
object.
The following example shows how to fill and stroke a cubic Bézier curve:
Drawing a circular arc
The Arc
method of the GraphicsPath
class can be used to add a circular arc segment to the path.
The parameters of this method specify the circular arc by providing the centre of the circle (as usual, either as a couple of double
values, or as a single Point
), the radius, the start angle of the arc and the end angle of the arc. Angles are specified in radiants. An angle of 0 corresponds to the positive X direction.
The start and end point of the arc are determined by these parameters, i.e. they are independent from the last point in the path (unlike the start point of lines and Bézier curves). Therefore, if the starting point of the arc does not coincide with the last point in the path, a line segment is also added to the path, connecting the last point to the starting point of the arc.
The following example shows how to fill and stroke a circular arc. Note that filling the arc only fills the circular segment (⌓); if you wish to fill the circular sector (⌔, i.e. the “pie slice”) instead, you will need to add a MoveTo
call that sets the starting point of the path to the centre of the circle.
If the coordinates of the start and end point of the arc are needed, they can be obtained with some simple trigonometric formulae:
\[x_0 = x_c + r \cdot \cos{\theta_0} \\ y_0 = y_c + r \cdot \sin{\theta_0}\] \[x_1 = x_c + r \cdot \cos{\theta_1} \\ y_1 = y_c + r \cdot \sin{\theta_1}\]Where $x_0$ and $y_0$ are the coordinates of the start point, $x_1$ and $y_1$ are the coordinates of the end point, $x_c$ and $y_c$ are the coordinates of the centre of the circle, $r$ is the radius, $\theta_0$ is the start angle and $\theta_1$ is the end angle.
Drawing an elliptical arc
A more complex way to draw an arc is by using an elliptical arc. This can be achieved with the EllipticalArc
method.
The parameters for this method are:
- Two
double
s that specify the length of the two semi-axes of the ellipse. - Another
double
specifying the angle between the first axis of the ellipse and the horizontal axis of the coordinate system. - A
bool
indicating whether the large or small arc should be drawn. - Another
bool
determining whether the arc is drawn in a clockwise or counter-clockwise direction. - A
Point
specifying the end point of the arc.
The method uses these parameters to draw an elliptical arc connecting the last point in the path (i.e., the end point of the previous segment) with the Point
specified in the last parameter. The algorithms used are the same as described in Appendix B.2 of the SVG specification.
The following example shows how this method can be used to fill and stroke an elliptical arc.
Drawing a smooth spline
Sometimes, it might be necessary to create a path that passes through a set of points “smoothly”, i.e. without any sharp edges. The AddSmoothSpline
method uses Bézier segments to create a smooth path that passes through the specified points. This method accepts a variable number of Point
arguments that correspond to the points though which the path should pass, or a Point[]
array with the same function.
The following example illustrates how this method can be used.
Path figures
All the elements described above can be combined in order to produce a complex shape. If you want to draw a closed shape, you should call the Close
method after adding the last segment. This will finish off the path by adding a straight segment to the path’s starting point.
This action completes a “path figure”. A single GraphicsPath
can contain multiple path figures; to add a new figure after closing the previous one, you should just call the MoveTo
method again.
When a path contains multiple figures that overlap each other, VectSharp uses the non-zero winding rule to determine whether a point is inside or outside the path.
The following example shows how to produce a path with or without a “hole”.
Stroke options
Like the StrokeRectangle
method described in Fill and stroke, the StrokePath
method takes a number of arguments that make it possible to customise the appearance of the stroke, including the line thickness, the line caps, the line joints, and the dash style.
The following example demonstrates the effect of these parameters. In particular, note how the line cap options interact with dashed lines.