Table of Contents

Class Stroke

Namespace
Egami.Drawing
Assembly
Egami.Drawing.dll

How a path is outlined: the pen's width, caps, joins and miter limit. The settings travel with the drawing call as data, so a vector backend can write them as they are (PDF's w, J, j and M). The pen is applied in the canvas's local space and then transformed, so a non-uniform scale gives an elliptical pen, as in PDF, SVG and Skia.

public sealed record Stroke : IEquatable<Stroke>
Inheritance
Stroke
Implements
Inherited Members

Examples

// The pen is data: width, caps, joins and miter limit. Width 1, butt caps and miter joins by default.
Stroke thick = new(12) { Cap = LineCap.Round, Join = LineJoin.Round };
canvas.DrawLine(new Vector2(20, 20), new Vector2(280, 20), thick, new Rgba8(30, 90, 200, 255));

Path zigzag = Path.Polygon([new(20, 120), new(80, 60), new(140, 120), new(200, 60), new(260, 120)], close: false);
canvas.StrokePath(zigzag, new Stroke(8) { Join = LineJoin.Miter, MiterLimit = 4 }, Rgba8.Black);

// A hairline is one device pixel wide whatever the transform.
canvas.StrokeCircle(new Vector2(150, 160), 30, Stroke.Hairline, Rgba8.Red);

Constructors

Stroke(float)

Initializes a new instance of the Stroke class.

public Stroke(float width = 1)

Parameters

width float

The pen's width in local units; 0 is a Hairline.

Exceptions

ArgumentOutOfRangeException

width is negative or not finite.

Properties

Cap

Gets how open contours end. Defaults to Butt.

public LineCap Cap { get; init; }

Property Value

LineCap

Exceptions

ArgumentOutOfRangeException

The value is not defined.

Dash

Gets the dashes, or null for a solid line. The pattern travels with the drawing call as data, so a vector backend writes it as it is (PDF's d, SVG's stroke-dasharray); the raster backend cuts the path into dashes before outlining it. Lengths are in local units, like the width. Defaults to null.

public DashPattern? Dash { get; init; }

Property Value

DashPattern

Effect

Gets an effect the canvas applies to the path before it is dashed and stroked, as Skia orders them, or null for none. Backends receive the effect's result as the path to stroke. Defaults to null.

public PathEffect? Effect { get; init; }

Property Value

PathEffect

Hairline

Gets a hairline: one device pixel wide whatever the transform, as PDF's thinnest line and Skia's width 0 are.

public static Stroke Hairline { get; }

Property Value

Stroke

IsHairline

Gets a value indicating whether this is a hairline: width 0.

public bool IsHairline { get; }

Property Value

bool

Join

Gets how corners are joined. Defaults to Miter.

public LineJoin Join { get; init; }

Property Value

LineJoin

Exceptions

ArgumentOutOfRangeException

The value is not defined.

MiterLimit

Gets the longest miter allowed, as a multiple of the width: a miter join whose point lies further out than this is drawn as a bevel, as SVG, PDF and Skia define it. Defaults to 4, as in SVG and Skia (PDF's default is 10).

public float MiterLimit { get; init; }

Property Value

float

Exceptions

ArgumentOutOfRangeException

The value is below 1 or not finite.

Width

Gets the pen's width in local units. 0 draws a hairline. Defaults to 1.

public float Width { get; init; }

Property Value

float

Exceptions

ArgumentOutOfRangeException

The value is negative or not finite.

Methods

ToPath(Path, float, bool)

Returns the outline this pen draws around a path, as a path to fill with the nonzero rule: the effect and dashes applied, then each piece offset by half the width with the joins and caps, as the raster backend fills it. Curves become straight pieces within a tenth of a unit divided by scale, so filling the outline at that scale gives exactly the pixels stroking does. The raw outline overlaps itself where the path turns sharply or crosses itself; with simplify the overlaps are removed by Simplify(float), for export or hit testing.

public Path ToPath(Path path, float scale = 1, bool simplify = false)

Parameters

path Path

The path to outline.

scale float

How much larger the outline will be drawn, which sets how finely curves are cut.

simplify bool

Whether to remove overlaps.

Returns

Path

The outline; empty for a hairline, which has no width in path units.

Examples

// A dashed route: the pattern travels with the stroke, so a PDF backend writes [8 4] 0 d instead of hundreds of pieces.
Path route = new PathBuilder().MoveTo(10, 90).CubicTo(60, 0, 140, 160, 190, 60).ToPath();
Stroke dashed = new(3) { Cap = LineCap.Round, Dash = new DashPattern([8, 4]) };
using Raster<Rgba8> map = Raster.Create(200, 120, Rgba8.White);
using (RasterCanvas<Rgba8> canvas = map.CreateCanvas())
{
    canvas.StrokePath(route, dashed, new Rgba8(200, 60, 30, 255));
}

// The outline the stroke fills, as a path: for hit testing, or to export without strokes.
Path outline = dashed.ToPath(route, simplify: true);

Exceptions

ArgumentOutOfRangeException

scale is not positive and finite.

ArgumentException

The outline does not fit in float coordinates.