Blendend.Path (blendend v0.2.0)
View SourceA path is a collection of contours built from commands such as
:move_to, :line_to, :quad_to, :cubic_to, and :close.
We typically:
- construct a path with
new/0(ornew!/0) - add segments with
move_to/3,line_to/3,quad_to/5,cubic_to/7,arc_quadrant_to/5,conic_to/6,arc_to/8,elliptic_arc_to/8, or geometry helpers likeadd_box/6,add_rect/6,add_circle/5,add_ellipse/6,add_round_rect/8,add_arc/8,add_chord/8,add_line/6,add_triangle/8,add_polyline/3, oradd_polygon/3 - optionally inspect or deform it with
vertex_count/1,vertex_at/2, andset_vertex_at/5 - derive straight segments or samples with
segments/1andsample/3 - compose shapes with
add_path/2andadd_path/3 - shift or warp them in-place via
translate/3,translate/4,transform/2, ortransform/3 - derive stroke outlines as geometry with
add_stroked_path/3 - render it with
Blendend.Canvas.Fill.path/3orBlendend.Canvas.Stroke.path/3 - apply blur/shadow effect on it via
Blendend.Effects.blur_path/4
You can also build paths with the DSL in Blendend.Draw:
use Blendend.Draw
path badge do
add_round_rect(20, 20, 140, 80, 12, 12)
add_circle(60, 60, 18)
add_line(20, 20, 160, 100)
end
stroke_path badgeSegment commands vs. shape helpers
There are two families of path builders:
*_tosegment commands (move_to/3,line_to/3,quad_to/5,cubic_to/7,arc_to/8,elliptic_arc_to/8, etc.) append to the current contour. They expect a current point (set bymove_to/3or a previous segment), do not auto-close, and keep the contour continuous. Reach for these when you need fine-grained control over how a path progresses or must preserve tangents between segments.add_*shape helpers (add_line/6,add_arc/8,add_circle/5,add_rect/6,add_polygon/3, etc.) drop one or more self-contained figures into the path. They start their own contour(s) regardless of the current point, handle their ownmove_to/closesequence, and accept:direction/:matrixoptions for winding and transforms. Use these when you just need standard geometry stamped into a path without worrying about continuity with the previous segment.
Summary
Types
Opaque path resource (sequence of lines/curves). Build via DSL or Path.*! helpers.
Functions
Adds an arc defined by (cx, cy, rx, ry, start, sweep).
Same as add_arc/8, but returns the path .
Adds a closed rectangular box defined by corners (x0, y0) and (x1, y1).
Same as add_box/6, but returns the path .
Adds a chord (closed arc) defined by (cx, cy, rx, ry, start, sweep).
Same as add_chord/8, but returns the path .
Adds a closed circular contour centered at (cx, cy) with radius r.
Same as add_circle/5, but returns the path .
Adds an ellipse centered at (cx, cy) with radii (rx, ry).
Same as add_ellipse/6, but returns the path .
Adds a line segment between (x0, y0) and (x1, y1) as a figure.
Same as add_line/6, but returns the path .
Appends all contours from src into dst.
Appends src into dst after applying an affine transform mtx.
Same as add_path/2, but returns dst .
Same as add_path/3, but returns dst .
Adds a polygon defined by points ([{x, y}, ...]).
Same as add_polygon/3, but returns the path .
Adds a polyline defined by points ([{x, y}, ...]).
Same as add_polyline/3, but returns the path .
Adds a closed rectangle (x, y, w, h).
Same as add_rect/6, but returns the path .
Adds a rounded rectangle (x, y, w, h, rx, ry).
Same as add_round_rect/8, but returns the path .
Runs Blend2D's stroker on src and appends the resulting outline
geometry to dst.
Same as add_stroked_path/4, but limits stroking to a vertex range
(tuple {start, stop} or Range, stop exclusive).
Same as add_stroked_path/4, but returns the path directly.
Same as add_stroked_path/5, but returns the path directly.
Adds a closed triangle (x0, y0), (x1, y1), (x2, y2).
Same as add_triangle/8, but returns the path .
Adds a single 90° arc segment between two points.
Same as arc_quadrant_to/5, but returns the path .
Adds a circular or elliptical arc segment to the path.
Same as arc_to/8, but returns the path .
Clears all vertices from the path.
Same as clear/1, but returns the path .
Closes the current contour (adds a :close command).
Same as close/1, but returns the path .
Adds a rational quadratic Bézier segment to the path.
Same as conic_to/6, but returns the path .
Adds a cubic Bézier curve to (x3, y3) with control points
(x1, y1) and (x2, y2).
Same as cubic_to/7, but returns the path .
Dumps internal path representation for debugging.
Same as debug_dump/1, but raises on error.
Adds an endpoint-based elliptical arc to the path.
Same as elliptic_arc_to/8, but returns the path .
Returns true if two paths are exactly equal.
Fits the path into the given rectangle {x, y, w, h}.
Same as fit_to/2, but on success, returns path.
Returns a new path where all curves have been approximated
by :line_to segments.
Hit-tests (x, y) against the path (fill rule: :non_zero).
Hit-tests (x, y) using the given fill rule (:non_zero | :even_odd).
Adds a straight line segment from the current point to (x, y).
Same as line_to/3, but returns the path .
Starts a new contour at (x, y).
Same as move_to/3, but returns the path.
Creates a new, empty path.
Adds a quadratic Bézier curve to (x2, y2) with a single control
point at (x1, y1).
Same as quad_to/5, but returns the path .
Samples points along a list of straight segments.
Returns a list of straight {{x0, y0}, {x1, y1}} segments for every contour.
set_vertex_at lets you mutate an existing path,
Same as set_vertex_at/5, but returns the path .
Normalizes a path in-place by removing redundant vertices and simplifying its data.
Same as shrink/1, but raises on error.
Continues a cubic Bézier smoothly from the previous segment.
Same as smooth_cubic_to/5, but returns the path .
Continues a quadratic Bézier smoothly from the previous segment.
Same as smooth_quad_to/3, but returns the path .
Transforms the whole path by matrix m.
Applies an affine transform matrix only to the vertices within range.
Same as transform/2, but returns the path .
Same as transform/3, but returns the path .
Translates all vertices in the path by (dx, dy) in-place.
Translates only the vertices within range by (dx, dy).
Same as translate/3, but returns the path .
Same as translate/4, but returns the path .
Returns the vertex at index idx.
Same as vertex_at/2, but returns {cmd, x, y} directly.
Returns the number of vertices stored in path.
Same as vertex_count/1, but returns the count directly.
Types
@type direction() :: :cw | :ccw | :none
@type hit_class() :: :in | :out | :part
@opaque t()
Opaque path resource (sequence of lines/curves). Build via DSL or Path.*! helpers.
Functions
@spec add_arc( t(), number(), number(), number(), number(), number(), number(), keyword() ) :: :ok | {:error, term()}
Adds an arc defined by (cx, cy, rx, ry, start, sweep).
Accepts the same optional opts as add_circle/5.
Same as add_arc/8, but returns the path .
Adds a closed rectangular box defined by corners (x0, y0) and (x1, y1).
Optional opts:
:matrix–Blendend.Matrix2D.t/0transform to apply:direction–:cw | :ccw | :none(default::cw)
On success, returns :ok.
On failure, returns {:error, reason}.
Same as add_box/6, but returns the path .
On success, returns path.
On failure, raises Blendend.Error.
@spec add_chord( t(), number(), number(), number(), number(), number(), number(), keyword() ) :: :ok | {:error, term()}
Adds a chord (closed arc) defined by (cx, cy, rx, ry, start, sweep).
Accepts the same optional opts as add_circle/5.
@spec add_chord!( t(), number(), number(), number(), number(), number(), number(), keyword() ) :: t()
Same as add_chord/8, but returns the path .
Adds a closed circular contour centered at (cx, cy) with radius r.
Optional opts:
:matrix–Blendend.Matrix2D.t/0transform to apply:direction–:cw | :ccw | :none(default::cw)
On success, returns :ok.
On failure, returns {:error, reason}.
Same as add_circle/5, but returns the path .
On success, returns path.
On failure, raises Blendend.Error.
Adds an ellipse centered at (cx, cy) with radii (rx, ry).
Accepts the same optional opts as add_circle/5.
Same as add_ellipse/6, but returns the path .
Adds a line segment between (x0, y0) and (x1, y1) as a figure.
Accepts the same optional opts as add_circle/5.
Same as add_line/6, but returns the path .
Appends all contours from src into dst.
Mutates dst in-place and leaves src unchanged.
On success, returns :ok.
On failure, returns {:error, reason}.
@spec add_path(t(), t(), Blendend.Matrix2D.t()) :: :ok | {:error, term()}
Appends src into dst after applying an affine transform mtx.
Mutates dst in-place and leaves src unchanged.
On success, returns :ok.
On failure, returns {:error, reason}.
Same as add_path/2, but returns dst .
On success, returns dst.
On failure, raises Blendend.Error.
@spec add_path!(t(), t(), Blendend.Matrix2D.t()) :: t()
Same as add_path/3, but returns dst .
On success, returns dst.
On failure, raises Blendend.Error.
Adds a polygon defined by points ([{x, y}, ...]).
Accepts the same optional opts as add_circle/5.
Same as add_polygon/3, but returns the path .
Adds a polyline defined by points ([{x, y}, ...]).
Accepts the same optional opts as add_circle/5.
Same as add_polyline/3, but returns the path .
Adds a closed rectangle (x, y, w, h).
Accepts the same optional opts as add_box/6.
On success, returns :ok.
On failure, returns {:error, reason}.
Same as add_rect/6, but returns the path .
On success, returns path.
On failure, raises Blendend.Error.
@spec add_round_rect( t(), number(), number(), number(), number(), number(), number(), keyword() ) :: :ok | {:error, term()}
Adds a rounded rectangle (x, y, w, h, rx, ry).
Accepts the same optional opts as add_circle/5.
@spec add_round_rect!( t(), number(), number(), number(), number(), number(), number(), keyword() ) :: t()
Same as add_round_rect/8, but returns the path .
Runs Blend2D's stroker on src and appends the resulting outline
geometry to dst.
This does not draw anything; it converts a stroke into fillable path geometry.
stroke_opts (keyword list) mirrors Blendend.Canvas.Stroke.path/2:
:width– stroke width (float, default1.0):miter_limit– miter limit (default4.0):start_cap/:end_cap–:butt | :round | :square | :round_rev | :triangle | :triangle_rev:join–:miter_clip | :miter_bevel | :miter_round | :bevel | :round:transform_order–:after | :before(default:after)
approx_opts (keyword list) maps to BLApproximationOptions:
:flatten_tolerance,:simplify_tolerance,:offset_parameter:flatten_mode–:default | :recursive:offset_mode–:default | :iterative
Examples
iex> alias Blendend.Path
iex> src = Path.new!() |> Path.move_to!(20, 20) |> Path.line_to!(80, 20)
iex> outline = Path.new!()
iex> :ok = Path.add_stroked_path(outline, src, width: 6.0, join: :round)
iex> Path.vertex_count!(outline) > Path.vertex_count!(src)
trueOn success, returns :ok. On failure, returns {:error, reason}.
@spec add_stroked_path( t(), t(), Range.t() | {non_neg_integer(), non_neg_integer()}, keyword(), keyword() ) :: :ok | {:error, term()}
Same as add_stroked_path/4, but limits stroking to a vertex range
(tuple {start, stop} or Range, stop exclusive).
Same as add_stroked_path/4, but returns the path directly.
@spec add_stroked_path!( t(), t(), Range.t() | {non_neg_integer(), non_neg_integer()}, keyword(), keyword() ) :: t()
Same as add_stroked_path/5, but returns the path directly.
@spec add_triangle( t(), number(), number(), number(), number(), number(), number(), keyword() ) :: :ok | {:error, term()}
Adds a closed triangle (x0, y0), (x1, y1), (x2, y2).
Accepts the same optional opts as add_circle/5.
@spec add_triangle!( t(), number(), number(), number(), number(), number(), number(), keyword() ) :: t()
Same as add_triangle/8, but returns the path .
Adds a single 90° arc segment between two points.
On success, returns :ok.
On failure, returns {:error, reason}.
Same as arc_quadrant_to/5, but returns the path .
On success, returns path.
On failure, raises Blendend.Error.
@spec arc_to( t(), number(), number(), number(), number(), number(), number(), boolean() ) :: :ok | {:error, term()}
Adds a circular or elliptical arc segment to the path.
Wraps blend2d's arcTo. Parameters:
cx, cy– center of the ellipserx, ry– radii in x and ystart– start angle in radianssweep– sweep angle in radiansforce_move?– whentrue, starts a new sub-path at the arc's start point instead of connecting from the current point
On success, returns :ok.
On failure, returns {:error, reason}.
Same as arc_to/8, but returns the path .
On success, returns path.
On failure, raises Blendend.Error.
Clears all vertices from the path.
On success, returns :ok.
On failure, returns {:error, reason}.
Same as clear/1, but returns the path .
On success, returns path.
On failure, raises Blendend.Error.
Closes the current contour (adds a :close command).
On success, returns :ok.
On failure, returns {:error, reason}.
Same as close/1, but returns the path .
On success, returns path.
On failure, raises Blendend.Error.
Adds a rational quadratic Bézier segment to the path.
Extends the current contour from the current point to (x2, y2) with a
quadratic curve that has control point (x1, y1) and a weight w.
- When
w == 1.0it behaves like a standard quadratic curve. - Other weights bend the curve closer to or further from the control point, which is useful for arcs and circular approximations.
The path must already have a current point.
On success, returns :ok.
On failure, returns {:error, reason}.
Same as conic_to/6, but returns the path .
On success, returns path.
On failure, raises Blendend.Error.
@spec cubic_to(t(), number(), number(), number(), number(), number(), number()) :: :ok | {:error, term()}
Adds a cubic Bézier curve to (x3, y3) with control points
(x1, y1) and (x2, y2).
On success, returns :ok.
On failure, returns {:error, reason}.
Same as cubic_to/7, but returns the path .
On success, returns path.
On failure, raises Blendend.Error.
Dumps internal path representation for debugging.
On success, returns :ok.
On failure, returns {:error, reason}.
@spec debug_dump!(t()) :: :ok
Same as debug_dump/1, but raises on error.
On success, returns :ok.
On failure, raises Blendend.Error.
Examples
iex> p = Blendend.Path.new!()
iex> p = Blendend.Path.move_to!(p, 247, 97)
iex> Path.debug_dump!(p)
:ok
# prints:
# [path_debug_dump] path size = 1
# [ 0] cmd=0 x=247.000000 y=97.000000
@spec elliptic_arc_to( t(), number(), number(), number(), boolean(), boolean(), number(), number() ) :: :ok | {:error, term()}
Adds an endpoint-based elliptical arc to the path.
Wraps blend2d's ellipticArcTo (similar to SVG A):
rx, ry– ellipse radiirot– x-axis rotation in radianslarge?– large-arc flagsweep?– sweep direction flagx1, y1– endpoint of the arc
The start point is the current point in the path.
On success, returns :ok.
On failure, returns {:error, reason}.
@spec elliptic_arc_to!( t(), number(), number(), number(), boolean(), boolean(), number(), number() ) :: t()
Same as elliptic_arc_to/8, but returns the path .
On success, returns path.
On failure, raises Blendend.Error.
Returns true if two paths are exactly equal.
This is a strict, bit-for-bit comparison of the underlying data. Tiny
floating point differences will make it return false.
Fits the path into the given rectangle {x, y, w, h}.
Mutates the path in-place so its bounds fit inside the rectangle.
On success, returns :ok.
On failure, returns {:error, reason}.
Same as fit_to/2, but on success, returns path.
On failure, raises Blendend.Error.
Returns a new path where all curves have been approximated
by :line_to segments.
The resulting path only contains :move_to, :line_to, and :close
commands. The tolerance argument controls the approximation accuracy
(default 0.25 user units).
On success returns {:ok, new_path}.
Hit-tests (x, y) against the path (fill rule: :non_zero).
Returns :in | :out | :part on success.
Raises Blendend.Error if the NIF reports :invalid (bad args, NaNs, etc.)
or if an error tuple is returned.
Hit-tests (x, y) using the given fill rule (:non_zero | :even_odd).
Returns :in | :out | :part on success.
Raises Blendend.Error if the NIF reports :invalid or an error.
Adds a straight line segment from the current point to (x, y).
The path must already have a current point (for example from a
previous move_to/3 or other drawing command).
On success, returns :ok.
On failure, returns {:error, reason}.
Same as line_to/3, but returns the path .
On success, returns the same path.
On failure, raises Blendend.Error.
Starts a new contour at (x, y).
This is equivalent to a :move_to command in the underlying path.
On success, returns :ok.
On failure, returns {:error, reason}.
Same as move_to/3, but returns the path.
On failure, raises Blendend.Error.
Creates a new, empty path.
On success, returns {:ok, path}.
On failure, returns {:error, reason}.
@spec new!() :: t()
Same as new/0, but returns the path directly.
On success, returns the path.
On failure, raises Blendend.Error.
Adds a quadratic Bézier curve to (x2, y2) with a single control
point at (x1, y1).
This is equivalent to a :quad_to command.
On success, returns :ok.
On failure, returns {:error, reason}.
Same as quad_to/5, but returns the path .
On success, returns path.
On failure, raises Blendend.Error.
@spec sample([segment()], number(), Keyword.t()) :: [sampled_point()]
Samples points along a list of straight segments.
Each returned item is {{x, y}, {nx, ny}} where {nx, ny} is the
unit-length left-hand normal for the directed segment {p0 -> p1}
({-dy/len, dx/len}).
Options:
:include_ends?(default:true) – include segment endpoints in sampling
spacing must be positive. Zero-length segments are skipped.
Returns a list of straight {{x0, y0}, {x1, y1}} segments for every contour.
Assumes the path only contains :move_to, :line_to, and :close
commands. Call flatten!/1 first if your path has curves. When a :close
is seen, the last point is connected back to the contour start.
Raises ArgumentError if a curve command (:quad_to, :cubic_to, etc.)
is encountered or if the path is malformed (for example :line_to before
any :move_to).
set_vertex_at lets you mutate an existing path,
idx is zero-based; cmd controls how the vertex is interpreted.
On success, returns :ok.
On failure, returns {:error, reason}.
Same as set_vertex_at/5, but returns the path .
On success, returns path.
On failure, raises Blendend.Error.
Normalizes a path in-place by removing redundant vertices and simplifying its data.
Wraps BLPath.shrink/0. Useful after stroking or bulk edits to compact the path buffer.
Same as shrink/1, but raises on error.
Continues a cubic Bézier smoothly from the previous segment.
Wraps blend2d smoothCubicTo (like SVG S):
- If the previous segment was cubic, the first control point of this segment is the mirror of the previous segment's second control point across the current point.
- This gives a visually smooth tangent across the join.
The segment ends at (x3, y3) and uses (x2, y2) as the second control
point.
On success, returns :ok.
On failure, returns {:error, reason}.
Same as smooth_cubic_to/5, but returns the path .
On success, returns path.
On failure, raises Blendend.Error.
Continues a quadratic Bézier smoothly from the previous segment.
Wraps blend2d smoothQuadTo (like SVG T):
- If the previous segment was a quadratic curve, the missing control point is mirrored across the current point to keep the curve smooth.
- If there is no previous quadratic, the current point is used as the control point.
The segment ends at (x2, y2).
On success, returns :ok.
On failure, returns {:error, reason}.
Same as smooth_quad_to/3, but returns the path .
On success, returns path.
On failure, raises Blendend.Error.
@spec transform(t(), Blendend.Matrix2D.t()) :: :ok | {:error, term()}
Transforms the whole path by matrix m.
Mutates the path in-place. Wraps BLPath::transform(matrix).
@spec transform( t(), Range.t() | {non_neg_integer(), non_neg_integer()}, Blendend.Matrix2D.t() ) :: :ok | {:error, term()}
Applies an affine transform matrix only to the vertices within range.
range accepts a two-tuple {start, stop} (zero-based, stop exclusive)
or an Elixir Range.
@spec transform!(t(), Blendend.Matrix2D.t()) :: t()
Same as transform/2, but returns the path .
@spec transform!( t(), Range.t() | {non_neg_integer(), non_neg_integer()}, Blendend.Matrix2D.t() ) :: t()
Same as transform/3, but returns the path .
Translates all vertices in the path by (dx, dy) in-place.
On success, returns :ok.
On failure, returns {:error, reason}.
@spec translate( t(), Range.t() | {non_neg_integer(), non_neg_integer()}, number(), number() ) :: :ok | {:error, term()}
Translates only the vertices within range by (dx, dy).
range can be either a two-tuple {start, stop} (zero-based, stop is
exclusive) or an Elixir Range struct.
On success, returns :ok.
On failure, returns {:error, reason}.
Same as translate/3, but returns the path .
On success, returns path.
On failure, raises Blendend.Error.
@spec translate!( t(), Range.t() | {non_neg_integer(), non_neg_integer()}, number(), number() ) :: t()
Same as translate/4, but returns the path .
On success, returns path.
On failure, raises Blendend.Error.
Returns the vertex at index idx.
On success, returns {:ok, {cmd, x, y}} where:
cmd– atom like:move_to,:line_to,:quad_to,:cubic_to,:closex,y– coordinates as floats
On failure, returns {:error, reason}.
@spec vertex_at!(t(), non_neg_integer()) :: {atom(), float(), float()}
Same as vertex_at/2, but returns {cmd, x, y} directly.
On success, returns {cmd, x, y}.
On failure, raises Blendend.Error.
@spec vertex_count(t()) :: {:ok, non_neg_integer()} | {:error, term()}
Returns the number of vertices stored in path.
On success, returns {:ok, count}.
On failure, returns {:error, reason}.
@spec vertex_count!(t()) :: non_neg_integer()
Same as vertex_count/1, but returns the count directly.
On success, returns count.
On failure, raises Blendend.Error.