Documentation
¶
Overview ¶
Package stroke provides stroke expansion algorithms for converting stroked paths to filled outlines.
This package implements CPU-side stroke expansion following tiny-skia and kurbo patterns. The algorithm converts a path with stroke style into a filled path suitable for GPU rasterization.
Algorithm Overview ¶
Stroke expansion works by building two parallel offset paths:
- Forward path: Offset by +width/2 perpendicular to the tangent
- Backward path: Offset by -width/2 perpendicular to the tangent
The final filled path is constructed by:
- Forward path goes forward
- End cap connects forward to backward
- Backward path is reversed
- Start cap connects backward to forward and closes
Line Caps ¶
Line caps define the shape of stroke endpoints:
- LineCapButt: Flat cap ending exactly at the endpoint
- LineCapRound: Semicircular cap with radius = width/2
- LineCapSquare: Square cap extending width/2 beyond the endpoint
Line Joins ¶
Line joins define how stroke segments connect:
- LineJoinMiter: Sharp corner (limited by miter limit)
- LineJoinRound: Circular arc at corners
- LineJoinBevel: Straight line across the corner
Usage ¶
style := stroke.Stroke{
Width: 2.0,
Cap: stroke.LineCapRound,
Join: stroke.LineJoinMiter,
MiterLimit: 4.0,
}
expander := stroke.NewStrokeExpander(style)
expander.SetTolerance(0.1) // Optional: adjust curve flattening
verbs := []stroke.PathVerb{stroke.VerbMoveTo, stroke.VerbLineTo, stroke.VerbLineTo}
coords := []float64{0, 0, 100, 0, 100, 100}
outVerbs, outCoords := expander.Expand(verbs, coords)
Performance ¶
The expander is optimized for typical use cases:
- Simple lines: ~2 microseconds
- Complex paths (100 segments): ~50-60 microseconds
- Cubic curves are flattened to line segments based on tolerance
References ¶
The algorithm is based on:
- tiny-skia (Rust): path/src/stroker.rs
- kurbo (Rust): src/stroke.rs
See GPU-STK-001 in docs/dev/kanban/ for the full task specification.
Package stroke provides stroke expansion algorithms for converting stroked paths to filled outlines.
This package implements CPU-side stroke expansion following tiny-skia and kurbo patterns. The algorithm converts a path with stroke style into a filled path suitable for GPU rasterization.
Key algorithm insight: A stroke is converted to a FILL path where:
- The outer offset path goes forward
- The inner offset path is reversed
- Line caps connect the endpoints
- Line joins connect the segments
Index ¶
- type LineCap
- type LineJoin
- type PathVerb
- type Point
- type Stroke
- type StrokeExpander
- type Vec2
- func (v Vec2) Add(w Vec2) Vec2
- func (v Vec2) Angle() float64
- func (v Vec2) Cross(w Vec2) float64
- func (v Vec2) Dot(w Vec2) float64
- func (v Vec2) Length() float64
- func (v Vec2) LengthSquared() float64
- func (v Vec2) Neg() Vec2
- func (v Vec2) Normalize() Vec2
- func (v Vec2) Perp() Vec2
- func (v Vec2) Scale(s float64) Vec2
- func (v Vec2) Sub(w Vec2) Vec2
- func (v Vec2) ToPoint() Point
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
type PathVerb ¶ added in v0.39.0
type PathVerb byte
PathVerb represents a path construction command. Values match gg.PathVerb for zero-cost conversion.
const ( // VerbMoveTo moves the current point without drawing. Consumes 2 coords (x, y). VerbMoveTo PathVerb = iota // VerbLineTo draws a line to the specified point. Consumes 2 coords (x, y). VerbLineTo // VerbQuadTo draws a quadratic Bezier curve. Consumes 4 coords (cx, cy, x, y). VerbQuadTo // VerbCubicTo draws a cubic Bezier curve. Consumes 6 coords (c1x, c1y, c2x, c2y, x, y). VerbCubicTo // VerbClose closes the current subpath. Consumes 0 coords. VerbClose )
type Point ¶
type Point struct {
X, Y float64
}
Point represents a 2D point (internal copy to avoid import cycle).
type Stroke ¶
Stroke defines the style for stroke expansion.
func DefaultStroke ¶
func DefaultStroke() Stroke
DefaultStroke returns a stroke with default settings.
type StrokeExpander ¶
type StrokeExpander struct {
// contains filtered or unexported fields
}
StrokeExpander converts stroked paths to filled paths. This follows the kurbo stroke expansion algorithm.
StrokeExpander is designed for reuse: call Expand() multiple times on the same instance. Internal buffers are retained and reused between calls to minimize heap allocations.
func NewStrokeExpander ¶
func NewStrokeExpander(style Stroke) *StrokeExpander
NewStrokeExpander creates a new stroke expander with the given style.
func (*StrokeExpander) Expand ¶
func (e *StrokeExpander) Expand(verbs []PathVerb, coords []float64) ([]PathVerb, []float64)
Expand converts a stroked path (given as SOA verb+coords) to a filled path. Returns the expanded path as (verbs, coords) slices.
func (*StrokeExpander) SetTolerance ¶
func (e *StrokeExpander) SetTolerance(tolerance float64)
SetTolerance sets the curve flattening tolerance.
type Vec2 ¶
type Vec2 struct {
X, Y float64
}
Vec2 represents a 2D vector.
func (Vec2) LengthSquared ¶
LengthSquared returns the squared length of the vector.