VectorPath Class

An immutable sequence of contours made of straight segments, Bézier curves and arcs of ellipses, built with a VectorPathBuilder and drawn with DrawingCanvas.Fill or DrawingCanvas.Stroke.

public sealed class VectorPath

Remarks

A path is thread-safe and independent of any image: create it once and draw it as many times as needed. Coordinates are canvas coordinates (see PointD).

Properties

NameDescription
BoundsGets the smallest rectangle containing every point and control point of the path (a curve lies inside the box of its control points; the control point of an arc of a quarter turn at most is where the tangents at its ends meet). It does not account for the width of a stroke. Empty for an empty path.
IsEmptyGets a value indicating whether the path has no element.

Gets the smallest rectangle containing every point and control point of the path (a curve lies inside the box of its control points; the control point of an arc of a quarter turn at most is where the tangents at its ends meet). It does not account for the width of a stroke. Empty for an empty path.

public RectangleD Bounds { get; }

Property value

RectangleD

Gets a value indicating whether the path has no element.

public bool IsEmpty { get; }

Property value

bool

Methods

NameDescription
Combine(VectorPath, PathCombineMode, FillRule, FillRule, CancellationToken)Creates the outline of what this path and another one fill, combined, each path filling what its own fill rule says.
Combine(VectorPath, PathCombineMode, FillRule, CancellationToken)Creates the outline of what this path and another one fill, combined: their union, what they have in common, or what one has and the other has not.
Contains(PointD, FillRule)Gets a value indicating whether a point is inside the path: whether a fill of the path paints it.
EnumerateSegments()Enumerates the elements of the path, in the order they were added to it.
GetBounds(Pen)Gets a rectangle that contains everything a pen paints when it strokes the path.
GetLength()Gets the length of the path: the sum of the lengths of its contours.
GetTightBounds()Gets the smallest rectangle containing the path itself: unlike VectorPath.Bounds, a curve counts for the points it reaches, not for its control points.
Offset(double, LineJoin, double, FillRule, CancellationToken)Creates the outline of what this path fills, moved outward or inward by a distance: a shape made larger or smaller by the same margin all around.
ParseSvgPathData(ReadOnlySpan<char>)Creates a path from the path data of SVG: the d attribute of a path element.
ParseSvgPathData(string)Creates a path from the path data of SVG: the d attribute of a path element.
Reverse()Creates the path that goes through the points of this one from its end to its start.
RoundCorners(double)Creates the path whose corners between two straight segments are replaced by arcs of a circle: a polygon, a star or an arrow with soft corners.
Simplify(FillRule, CancellationToken)Creates the outline of what this path fills: contours that do not cross each other or themselves.
StrokeContains(PointD, Pen)Gets a value indicating whether a point is inside the stroke of the path: whether a pen that strokes the path paints it.
ToSvgPathData()Writes the path as the path data of SVG: the d attribute of a path element.
Transform(AffineTransform)Creates the path every point of this one becomes when a transformation is applied to it.
Trim(double, double)Creates the part of the path between two distances from its start: what is left of a stroke that is drawn progressively.
TryGetClosestPoint(PointD, PointD, double)Finds the point of the path that is the nearest to a position: what a pointer snaps to, or the place of a path a click is at.
TryGetPointAtDistance(double, PointD, PointD)Finds the point at a distance from the start of the path, and the direction of the path there.
TryParseSvgPathData(ReadOnlySpan<char>, VectorPath?)Creates a path from the path data of SVG, without throwing when the text is not valid.
TryParseSvgPathData(string?, VectorPath?)Creates a path from the path data of SVG, without throwing when the text is not valid.
Widen(Pen)Creates the path a pen draws when it strokes this path: filling the result paints what the stroke paints.

Combine overloads

Combine(VectorPath, PathCombineMode, FillRule, FillRule, CancellationToken)

VectorPath.cs

Creates the outline of what this path and another one fill, combined, each path filling what its own fill rule says.

public VectorPath Combine(VectorPath other, PathCombineMode mode, FillRule fillRule, FillRule otherFillRule, CancellationToken cancellationToken = default)
Parameters
other VectorPath
The other path.
mode PathCombineMode
What is kept of the areas the two paths fill.
fillRule FillRule
The rule deciding what this path fills.
otherFillRule FillRule
The rule deciding what other fills.
cancellationToken CancellationToken
A token to cancel the operation.
Returns

VectorPath The outline; an empty path when nothing is kept.

Exceptions
ArgumentNullException
other is null.
ArgumentOutOfRangeException
mode is not a defined PathCombineMode, or fillRule or otherFillRule is not a defined FillRule.
InvalidOperationException
The segments of the paths could not be cut so that they only meet at their ends: no outline is returned rather than a wrong one.
OperationCanceledException
The operation was canceled.
Remarks

The result is the one of VectorPath.Combine, with the area of each path decided by its own rule: a star drawn as one contour that crosses itself can be filled with its center (FillRule.NonZero) or without it (FillRule.EvenOdd) whatever the rule of the shape it is combined with.

Combine(VectorPath, PathCombineMode, FillRule, CancellationToken)

VectorPath.cs

Creates the outline of what this path and another one fill, combined: their union, what they have in common, or what one has and the other has not.

public VectorPath Combine(VectorPath other, PathCombineMode mode, FillRule fillRule = FillRule.NonZero, CancellationToken cancellationToken = default)
Parameters
other VectorPath
The other path.
mode PathCombineMode
What is kept of the areas the two paths fill.
fillRule FillRule
The rule deciding what each of the two paths fills.
cancellationToken CancellationToken
A token to cancel the operation.
Returns

VectorPath The outline; an empty path when nothing is kept.

Exceptions
ArgumentNullException
other is null.
ArgumentOutOfRangeException
mode is not a defined PathCombineMode, or fillRule is not a defined FillRule.
InvalidOperationException
The segments of the paths could not be cut so that they only meet at their ends: no outline is returned rather than a wrong one.
OperationCanceledException
The operation was canceled.
Remarks

The result is the boundary of an area: closed contours that do not cross each other or themselves, around the area and around its holes. Its outer contours turn clockwise on the image and its holes the other way, so that both fill rules paint the same pixels; stroking it outlines the area.

The result is made of straight segments: the chords the paths are drawn with, which stay within 1/16 of a pixel of their curves at the size the paths have, with their vertices moved to the nearest 1/1024 of a pixel. Transform the paths before combining them, not the result after. An open contour is closed by a straight segment, as when it is filled.

The time grows with the number of segments of the paths and of the points where they cross, and with the square of the number of segments when they are stacked on each other: pass a cancellationToken when the paths come from untrusted input.

Contains(PointD, FillRule)

VectorPath.cs

Gets a value indicating whether a point is inside the path: whether a fill of the path paints it.

public bool Contains(PointD point, FillRule fillRule = FillRule.NonZero)

Parameters

point PointD
The point.
fillRule FillRule
The rule deciding what is inside when contours overlap.

Returns

bool true if the point is inside; false for a point that is not a finite position.

Exceptions

ArgumentOutOfRangeException
fillRule is not a defined FillRule.

Remarks

The path is the one that is drawn: its curves are their chords, within 1/16 of a pixel of the curve, and an open contour is closed by a straight segment. A point on the outline itself may be reported either way.

EnumerateSegments()

VectorPath.cs

Enumerates the elements of the path, in the order they were added to it.

public PathSegmentEnumerator EnumerateSegments()

Returns

PathSegmentEnumerator An enumerator, to use with foreach. It does not allocate.

Remarks

A segment is what a method of VectorPathBuilder adds: the path can be written in another format, or built again, from its segments. Every contour starts with a PathSegmentKind.MoveTo.

An arc is given as the arc of SVG paths that VectorPathBuilder.ArcTo takes, in pieces of at most a quarter turn, and an ellipse as two arcs of half a turn in a closed contour: the radii and the rotation are computed from the ellipse the path stores, and are those that were given to the builder to a few units of the last place only (exactly for an ellipse that is not turned). An arc of an ellipse that a transformation flattened to a segment is a PathSegmentKind.LineTo.

GetBounds(Pen)

VectorPath.cs

Gets a rectangle that contains everything a pen paints when it strokes the path.

public RectangleD GetBounds(Pen pen)

Parameters

pen Pen
The stroke. Its brush is not used.

Returns

RectangleD The rectangle; an empty rectangle when the path is empty.

Exceptions

ArgumentNullException
pen is null.
ArgumentOutOfRangeException
The stroke goes beyond the largest coordinate (16777216).

Remarks

The rectangle is VectorPath.GetTightBounds spread by how far the stroke can reach from the path: half the width of the pen, its miters up to Pen.MiterLimit (with LineJoin.Miter), and the corners of square caps. It contains the stroke without computing it, and is larger than the stroke where the path has no sharp corner at its extremes; VectorPath.Widen then VectorPath.GetTightBounds gives the exact one. A pen with markers is widened: the result is then exact, and computing it allocates.

The stroke of PenAlignment.Inside stays within what the path fills; the one of PenAlignment.Outside reaches a whole width beyond the path. The units are those of the path: a pen that does not scale with the transformation of the canvas (Pen.ScalesWithTransform), and a hairline (a width of 0, one pixel of the canvas), reach that far only when the canvas is not scaled.

GetLength()

VectorPath.cs

Gets the length of the path: the sum of the lengths of its contours.

public double GetLength()

Returns

double The length, in pixels.

Remarks

The path is measured as it is drawn: by the chords of its curves, within 1/16 of a pixel of the curve. A closed contour includes its closing segment; the gap between two contours is not counted. Each call walks the whole path: VectorPathMeasure walks it once for many questions.

GetTightBounds()

VectorPath.cs

Gets the smallest rectangle containing the path itself: unlike VectorPath.Bounds, a curve counts for the points it reaches, not for its control points.

public RectangleD GetTightBounds()

Returns

RectangleD The rectangle.

Remarks

The rectangle is computed from the curves, not from their chords: it contains everything a fill of the path paints. It does not account for the width of a stroke: see VectorPath.Widen. Empty for an empty path.

Offset(double, LineJoin, double, FillRule, CancellationToken)

VectorPath.cs

Creates the outline of what this path fills, moved outward or inward by a distance: a shape made larger or smaller by the same margin all around.

public VectorPath Offset(double distance, LineJoin join = LineJoin.Miter, double miterLimit = 4d, FillRule fillRule = FillRule.NonZero, CancellationToken cancellationToken = default)

Parameters

distance double
The distance, in pixels: positive to make the shape larger, negative to make it smaller, 0 for its outline (see VectorPath.Simplify).
join LineJoin
The shape of the corners the sides move away from.
miterLimit double
The limit of LineJoin.Miter corners, as Pen.MiterLimit: the largest ratio between the length of a miter and twice the distance, beyond which a corner is beveled.
fillRule FillRule
The rule deciding what this path fills.
cancellationToken CancellationToken
A token to cancel the operation.

Returns

VectorPath The outline; an empty path when nothing is left.

Exceptions

ArgumentException
distance is not a finite number.
ArgumentOutOfRangeException
The magnitude of distance exceeds 16777216, join or fillRule is not defined, miterLimit is not between 1 and 1048576, or the result goes beyond the largest coordinate (16777216).
InvalidOperationException
The segments of the path could not be cut so that they only meet at their ends: no outline is returned rather than a wrong one.
OperationCanceledException
The operation was canceled.

Remarks

A positive distance gives the outline of what the path fills together with what a pen twice as wide as the distance strokes along its boundary: every side moves outward by the distance, and a hole gets smaller. A negative distance gives what the path fills less that stroke: every side moves inward, a hole gets larger, and a part of the shape that is narrower than twice the distance disappears. join is the shape of the corners that the sides move away from: the corners of a shape that grows, the corners of a hole, and the notches of a shape that shrinks; with LineJoin.Round, the result is what is within the distance of the shape. A curve of the path stays round whatever the join.

What moves is the boundary of the area, not each contour: contours that overlap are moved as the one shape they fill, and an open contour is closed by a straight segment, as when it is filled. A path that fills nothing (a line) has no outline to move: VectorPath.Widen gives the outline of its stroke.

The result is made as VectorPath.Combine makes it: closed contours of straight segments that do not cross, on a grid of 1/1024 of a pixel, for the size the path has. Transform a path before moving its outline, not after. Pass a cancellationToken when the path comes from untrusted input.

ParseSvgPathData overloads

ParseSvgPathData(ReadOnlySpan<char>)

VectorPath.cs

Creates a path from the path data of SVG: the d attribute of a path element.

public static VectorPath ParseSvgPathData(ReadOnlySpan<char> svgPathData)
Parameters
svgPathData ReadOnlySpan<char>
The path data. An empty text is an empty path.
Returns

VectorPath The path.

Exceptions
FormatException
The text is not valid path data, or a coordinate is beyond the limit of a path.
Remarks

ParseSvgPathData(string)

VectorPath.cs

Creates a path from the path data of SVG: the d attribute of a path element.

public static VectorPath ParseSvgPathData(string svgPathData)
Parameters
svgPathData string
The path data. An empty text is an empty path.
Returns

VectorPath The path.

Exceptions
ArgumentNullException
svgPathData is null.
FormatException
The text is not valid path data, or a coordinate is beyond the limit of a path.
Remarks

Every command of SVG is read (M L H V C S Q T A Z and their relative forms), with the grammar of SVG: numbers separated by white space, by a comma or by nothing where there is no doubt, and the arguments of a command repeated without its letter. The coordinates are those of the canvas: Y grows downward, as in SVG.

The whole text must be valid: nothing is drawn of path data that has an error, where a browser draws what comes before it. Every coordinate must be within the limit of a path (16777216 in magnitude).

Reverse()

VectorPath.cs

Creates the path that goes through the points of this one from its end to its start.

public VectorPath Reverse()

Returns

VectorPath The reversed path; this instance when the path is empty.

Remarks

The contours come in the opposite order, and each one is followed the other way: an open contour starts where it ended, and a closed contour keeps its first point. The result paints the same pixels when it is filled or stroked; what follows a path in its direction changes side: the dashes of a pen, the points at a distance, a text on the path, and what FillRule.NonZero counts when the path is combined with another one.

RoundCorners(double)

VectorPath.cs

Creates the path whose corners between two straight segments are replaced by arcs of a circle: a polygon, a star or an arrow with soft corners.

public VectorPath RoundCorners(double radius)

Parameters

radius double
The radius of the corners, in pixels: 0 keeps the path as it is.

Returns

VectorPath The path with round corners; this instance when the radius is 0 or the path is empty.

Exceptions

ArgumentException
radius is not a finite number.
ArgumentOutOfRangeException
radius is negative or exceeds 16777216.

Remarks

A corner is a vertex between two straight segments of a contour: the vertices of an open contour between its ends, and every vertex of a closed contour, the one it starts at included. It becomes the arc of the circle of radius radius that touches both segments. Where a segment is too short for the circle to touch it before its middle, the circle is the smaller one that touches both segments at half the length of the shorter one: two corners never meet on a segment, and a rectangle gets the corners of VectorPathBuilder.AddRoundedRectangle.

The other vertices are kept: those where a curve or an arc starts or ends, and those where a contour goes back on itself. The result has arcs where the path had corners: it stays smooth when it is enlarged.

Simplify(FillRule, CancellationToken)

VectorPath.cs

Creates the outline of what this path fills: contours that do not cross each other or themselves.

public VectorPath Simplify(FillRule fillRule = FillRule.NonZero, CancellationToken cancellationToken = default)

Parameters

fillRule FillRule
The rule deciding what this path fills.
cancellationToken CancellationToken
A token to cancel the operation.

Returns

VectorPath The outline; an empty path when the path fills nothing.

Exceptions

ArgumentOutOfRangeException
fillRule is not a defined FillRule.
InvalidOperationException
The segments of the path could not be cut so that they only meet at their ends: no outline is returned rather than a wrong one.
OperationCanceledException
The operation was canceled.

Remarks

Filling the result paints what filling this path paints, with either fill rule: a path that crosses itself, or whose contours overlap, becomes the boundary of its area. This turns the pieces VectorPath.Widen gives into the outline of a stroke, which can be stroked in turn.

The result is made as VectorPath.Combine makes it, with the same precision and the same cost.

StrokeContains(PointD, Pen)

VectorPath.cs

Gets a value indicating whether a point is inside the stroke of the path: whether a pen that strokes the path paints it.

public bool StrokeContains(PointD point, Pen pen)

Parameters

point PointD
The point.
pen Pen
The stroke. Its brush is not used.

Returns

bool true if the stroke contains the point; false for a point that is not a finite position.

Exceptions

ArgumentNullException
pen is null.

Remarks

The stroke is the one VectorPath.Widen gives, caps, joins, miter limit, dashes, markers and Pen.Alignment included, and the answer is the one of VectorPath.Contains on it, without creating it: only the parts of the path that are within the reach of the pen from the point are stroked, and their pieces are tested against the point as they are computed. A point on the outline of the stroke may be reported either way; with an Pen.Alignment that is not PenAlignment.Center, the side of the path is decided without the grid of 1/1024 of a pixel that VectorPath.Widen moves the outline to.

The point is a point of the path, not of a canvas: as with VectorPath.Widen, the transformation of a canvas and Pen.ScalesWithTransform do not apply, and a hairline (a width of 0) is one unit wide. Each call flattens the whole path and measures the distance of each of its chords to the point, and the dashes are cut along the whole path; a point outside VectorPath.GetBounds is rejected without walking it.

ToSvgPathData()

VectorPath.cs

Writes the path as the path data of SVG: the d attribute of a path element.

public string ToSvgPathData()

Returns

string The path data; an empty text for an empty path.

Remarks

The text has the segments of VectorPath.EnumerateSegments, with absolute coordinates, and numbers written so that reading them gives the same values, whatever the culture. Lines and Bézier curves are read back exactly; an arc is read back as the same arc to a few units of the last place.

Transform(AffineTransform)

VectorPath.cs

Creates the path every point of this one becomes when a transformation is applied to it.

public VectorPath Transform(AffineTransform transform)

Parameters

transform AffineTransform
The transformation.

Returns

VectorPath The transformed path; this instance when the transformation is the identity.

Exceptions

ArgumentOutOfRangeException
The magnitude of a coordinate of the result exceeds 16777216.

Remarks

The result is exact: curves are transformed as curves, and an ellipse stays an ellipse, whatever the transformation. Flattening happens when the result is drawn, so a path that is enlarged stays smooth.

Trim(double, double)

VectorPath.cs

Creates the part of the path between two distances from its start: what is left of a stroke that is drawn progressively.

public VectorPath Trim(double start, double end)

Parameters

start double
The distance from the start of the path at which the part starts, in pixels.
end double
The distance from the start of the path at which the part ends, in pixels.

Returns

VectorPath The part of the path; an empty path when end is not after start.

Exceptions

ArgumentException
start or end is not a number.

Remarks

The distances are those of VectorPath.GetLength and VectorPath.TryGetPointAtDistance: the contours follow each other, without the gap between them. A distance before the start of the path is its start, a distance beyond its end is its end.

The result is made of the chords the path is drawn with, which stay within 1/16 of a pixel of its curves at the size the path has: transform a path before taking a part of it, not after. The vertices of these chords are vertices of the result: a pen joins them as it joins any corner, where the stroke of the path itself is always round (the two only differ on curves a few pixels wide; LineJoin.Round makes them the same). A contour that is cut becomes an open contour; a closed contour that is kept entirely stays closed. A contour without length is not kept.

TryGetClosestPoint(PointD, PointD, double)

VectorPath.cs

Finds the point of the path that is the nearest to a position: what a pointer snaps to, or the place of a path a click is at.

public bool TryGetClosestPoint(PointD point, out PointD closest, out double distanceAlongPath)

Parameters

point PointD
The position.
closest PointD
The nearest point of the path.
distanceAlongPath double
The distance from the start of the path to that point, along the path, in pixels.

Returns

bool false when the path has no length: there is no point to find.

Exceptions

ArgumentException
A coordinate of point is not a finite number.

Remarks

The path is the one that is drawn: its curves are their chords, within 1/16 of a pixel of the curve, a closed contour includes its closing segment, and the gap between two contours is no part of it. The distance along the path is the one VectorPath.TryGetPointAtDistance and VectorPath.Trim take. When several points are as near, the first one along the path is given. Each call walks the whole path: VectorPathMeasure walks it once for many positions.

TryGetPointAtDistance(double, PointD, PointD)

VectorPath.cs

Finds the point at a distance from the start of the path, and the direction of the path there.

public bool TryGetPointAtDistance(double distance, out PointD point, out PointD tangent)

Parameters

distance double
The distance from the start of the path, in pixels.
point PointD
The point of the path at that distance.
tangent PointD
The direction of the path at that point, as a vector of length 1.

Returns

bool false when the path has no length: there is no point to find, and no direction.

Exceptions

ArgumentException
distance is not a number.

Remarks

The distance is measured as VectorPath.GetLength measures the path: the contours follow each other, without the gap between them. A distance before the start gives the first point, a distance beyond the end the last one. At a corner, the direction is the one of the segment that starts there. Each call walks the path from its start: VectorPathMeasure walks it once for many distances.

TryParseSvgPathData overloads

TryParseSvgPathData(ReadOnlySpan<char>, VectorPath?)

VectorPath.cs

Creates a path from the path data of SVG, without throwing when the text is not valid.

public static bool TryParseSvgPathData(ReadOnlySpan<char> svgPathData, out VectorPath? path)
Parameters
svgPathData ReadOnlySpan<char>
The path data. An empty text is an empty path.
path VectorPath?
The path, or null when the text is not valid.
Returns

bool false when the text is not valid path data, or has a coordinate beyond the limit of a path.

Remarks

TryParseSvgPathData(string?, VectorPath?)

VectorPath.cs

Creates a path from the path data of SVG, without throwing when the text is not valid.

public static bool TryParseSvgPathData(string? svgPathData, out VectorPath? path)
Parameters
svgPathData string?
The path data. An empty text is an empty path.
path VectorPath?
The path, or null when the text is not valid.
Returns

bool false when the text is null, is not valid path data, or has a coordinate beyond the limit of a path.

Remarks

Widen(Pen)

VectorPath.cs

Creates the path a pen draws when it strokes this path: filling the result paints what the stroke paints.

public VectorPath Widen(Pen pen)

Parameters

pen Pen
The stroke.

Returns

VectorPath The path of the stroke; an empty path when this path is empty.

Exceptions

ArgumentNullException
pen is null.
ArgumentOutOfRangeException
The stroke goes beyond the largest coordinate (16777216).

Remarks

The result is the stroke as the library draws it: one closed convex contour for each segment, each join and each cap. The contours overlap and all turn the same way: fill them with FillRule.NonZero. It is not the outline of the stroke as a single contour, so stroking the result outlines every piece: VectorPath.Simplify makes that outline of it.

Curves are widened along their chords, which stay within 1/16 of a pixel of the curve at the size the path has: transform a path before widening it, not after. The brush of the pen is not used.

A dashed pen gives the contours of every dash: the size of the result grows with the length of the path divided by the length of the pattern, and nothing limits it.

The markers of the pen are contours of the result, like the pieces of the stroke. With an Pen.Alignment that is not PenAlignment.Center, the result is the outline of the side of the stroke that is kept (what VectorPath.Combine gives of the stroke of a pen twice as wide and of this path): closed contours of straight segments that do not overlap.