svg_path
Core SVG path data structures and constructors.
This module models paths as a list of subpaths, and subpaths as continuous
segment lists. Use svg_path/parse and svg_path/serialize when working
directly with SVG path data strings.
Types
Errors returned by path construction and editing helpers.
pub type Error {
AlreadyClosed
ClosedEmptySubpath
Discontinuous(
previous_index: Int,
next_index: Int,
expected: vec2.Vec2(Float),
got: vec2.Vec2(Float),
distance: Float,
)
EmptySubpath
IncompatibleHorizontalWiggle(
previous_end: vec2.Vec2(Float),
next_start: vec2.Vec2(Float),
)
IncompatibleVerticalWiggle(
previous_end: vec2.Vec2(Float),
next_start: vec2.Vec2(Float),
)
InvalidSplice(start: Int, delete: Int, length: Int)
MultipleNonemptySubpaths
NotCloseEnough(
expected: vec2.Vec2(Float),
got: vec2.Vec2(Float),
tolerance: Float,
)
}
Constructors
-
AlreadyClosedThe subpath is already closed and cannot accept more segments.
-
ClosedEmptySubpathAn operation would produce a closed subpath with no segments.
Empty open subpaths are valid, but this package does not represent a closed empty subpath.
-
Discontinuous( previous_index: Int, next_index: Int, expected: vec2.Vec2(Float), got: vec2.Vec2(Float), distance: Float, )A segment starts somewhere other than the previous segment’s end point.
previous_indexis the segment whose end point was expected.next_indexis the segment whose start point did not match.distanceis the distance betweenexpectedandgot. -
EmptySubpathThe operation requires a non-empty subpath.
-
A wiggle operation could not reconcile two horizontal line segments.
-
A wiggle operation could not reconcile two vertical line segments.
-
InvalidSplice(start: Int, delete: Int, length: Int)A splice was requested with invalid bounds.
This is returned when
startis negative,deleteis negative, orstartis greater than the subpath length. -
MultipleNonemptySubpathsThe path contains more than one non-empty subpath.
-
Two points were too far apart for a wiggle operation to merge them.
A 2D point.
This is a vec.Vec2(Float), so its coordinates are available as .x and
.y.
pub type Point =
vec2.Vec2(Float)
A single SVG path segment.
pub type Segment {
Line(start: vec2.Vec2(Float), end: vec2.Vec2(Float))
QuadraticBezier(
start: vec2.Vec2(Float),
control: vec2.Vec2(Float),
end: vec2.Vec2(Float),
)
CubicBezier(
start: vec2.Vec2(Float),
control1: vec2.Vec2(Float),
control2: vec2.Vec2(Float),
end: vec2.Vec2(Float),
)
Arc(
start: vec2.Vec2(Float),
radius: vec2.Vec2(Float),
x_axis_rotation: Float,
large_arc: Bool,
sweep: Bool,
end: vec2.Vec2(Float),
)
}
Constructors
-
A straight line segment.
-
A quadratic Bezier curve segment.
-
CubicBezier( start: vec2.Vec2(Float), control1: vec2.Vec2(Float), control2: vec2.Vec2(Float), end: vec2.Vec2(Float), )A cubic Bezier curve segment.
-
Arc( start: vec2.Vec2(Float), radius: vec2.Vec2(Float), x_axis_rotation: Float, large_arc: Bool, sweep: Bool, end: vec2.Vec2(Float), )An elliptical arc segment.
Subpath
opaqueA continuous sequence of path segments, optionally closed.
The constructor is opaque so that subpaths cannot be created in an invalid
discontinuous state. Use subpath, empty_subpath, append, or
force_append to build values.
pub opaque type Subpath
Values
pub fn append(
subpath: Subpath,
segment: Segment,
) -> Result(Subpath, Error)
Append a segment to an open subpath.
The new segment must start exactly at the current end point.
pub fn arc(
start start: vec2.Vec2(Float),
radius radius: vec2.Vec2(Float),
x_axis_rotation x_axis_rotation: Float,
large_arc large_arc: Bool,
sweep sweep: Bool,
end end: vec2.Vec2(Float),
) -> Segment
Create an elliptical arc segment.
pub fn as_subpath(path: Path) -> Result(Subpath, Error)
Convert a path with zero or one non-empty subpaths into a subpath.
Empty subpaths are ignored. If more than one non-empty subpath is present,
this returns MultipleNonemptySubpaths.
pub fn assert_close(subpath: Subpath) -> Subpath
Close a subpath if its start and end points already match, panicking if the subpath cannot be closed.
This is useful for hand-authored paths where invalid continuity would be a
programmer error. Use close when you want to handle closure errors.
pub fn assert_subpath(segments: List(Segment)) -> Subpath
Create an open subpath from a continuous list of segments, panicking if the segments are invalid.
This is useful for hand-authored paths where invalid continuity would be a
programmer error. Use subpath when you want to handle construction errors.
pub fn clean_subpath(subpath: Subpath) -> Subpath
Remove zero-length line segments from a subpath.
If the subpath contains only one zero-length line, it is preserved so the subpath does not become empty.
pub fn close(subpath: Subpath) -> Result(Subpath, Error)
Close a subpath if its start and end points already match.
pub fn cubic_bezier(
start start: vec2.Vec2(Float),
control1 control1: vec2.Vec2(Float),
control2 control2: vec2.Vec2(Float),
end end: vec2.Vec2(Float),
) -> Segment
Create a cubic Bezier segment.
pub fn end(subpath: Subpath) -> Result(vec2.Vec2(Float), Error)
Return the end point of a non-empty subpath.
pub fn force_append(
subpath: Subpath,
segment: Segment,
) -> Result(Subpath, Error)
Append a segment to an open subpath, inserting a connecting line if needed.
If the subpath is empty, this behaves like append. If the new segment does
not start at the current end point, a line segment is inserted between them.
pub fn force_close(subpath: Subpath) -> Result(Subpath, Error)
Close a subpath, inserting a line back to the start point if needed.
pub fn line(
start start: vec2.Vec2(Float),
end end: vec2.Vec2(Float),
) -> Segment
Create a straight line segment.
pub fn open(subpath: Subpath) -> Subpath
Return an open version of a subpath.
This only clears the semantic closed flag. It does not remove or alter any segments, including any final line back to the subpath start.
pub fn path_arcs_to_bezier(path: Path) -> Path
Convert every arc in a path to cubic Bezier curves.
This applies subpath_arcs_to_bezier to each subpath.
pub fn path_to_cubic_beziers(path: Path) -> Path
Convert every segment in a path to cubic Bezier curves.
This applies subpath_to_cubic_beziers to each subpath.
pub fn quadratic_bezier(
start start: vec2.Vec2(Float),
control control: vec2.Vec2(Float),
end end: vec2.Vec2(Float),
) -> Segment
Create a quadratic Bezier segment.
pub fn segment_arcs_to_bezier(segment: Segment) -> List(Segment)
Convert an arc segment to cubic Bezier curves, preserving other segments.
Non-arc segments are returned unchanged as a single-item list. An arc may become several cubic Bezier segments.
pub fn segment_to_cubic_beziers(
segment: Segment,
) -> List(Segment)
Convert a segment to one or more cubic Bezier curves.
Lines and quadratic Beziers are converted exactly. Cubic Beziers are returned unchanged. Arcs may become several cubic Bezier segments.
pub fn set_closed(
subpath: Subpath,
closed closed: Bool,
) -> Result(Subpath, Error)
Set a subpath’s semantic closed state.
Setting closed to False only clears the semantic closed flag. Setting it
to True requires the subpath’s end point to exactly match its start point.
pub fn splice(
subpath: Subpath,
start start: Int,
delete delete: Int,
insert insert: List(Segment),
) -> Result(Subpath, Error)
Replace a range of segments in a subpath.
start is a zero-based segment index and delete is the number of
segments to remove. If start + delete extends past the end of the subpath,
everything from start onward is deleted. Negative start, negative
delete, and start greater than the subpath length return
InvalidSplice.
The edited subpath must remain continuous. Closed subpaths preserve their
closed state; if the splice would make a closed subpath empty,
ClosedEmptySubpath is returned.
pub fn start(subpath: Subpath) -> Result(vec2.Vec2(Float), Error)
Return the start point of a non-empty subpath.
pub fn subpath(segments: List(Segment)) -> Result(Subpath, Error)
Create an open subpath from a continuous list of segments.
Returns Discontinuous if any segment starts somewhere other than the
previous segment’s end point. The error includes the two segment indices
that failed to meet.
pub fn subpath_arcs_to_bezier(subpath: Subpath) -> Subpath
Convert every arc in a subpath to cubic Bezier curves.
Lines, quadratic Beziers, and cubic Beziers are preserved. Elliptical arcs are approximated with one or more cubic Beziers, split into chunks of at most a quarter turn. Degenerate arcs fall back to a straight-line cubic Bezier between their endpoints.
pub fn subpath_to_cubic_beziers(subpath: Subpath) -> Subpath
Convert every segment in a subpath to cubic Bezier curves.
Lines and quadratic Beziers are converted exactly. Cubic Beziers are preserved. Elliptical arcs are approximated with one or more cubic Beziers, split into chunks of at most a quarter turn.
pub fn wiggle_close(subpath: Subpath) -> Result(Subpath, Error)
Close a subpath while gently reconciling tiny endpoint gaps.
This is useful after floating-point transformations that should preserve closure but leave endpoints off by a very small amount.
pub fn wiggle_set_closed(
subpath: Subpath,
closed closed: Bool,
) -> Result(Subpath, Error)
Set a subpath’s semantic closed state, reconciling tiny endpoint gaps.
Setting closed to False only clears the semantic closed flag. Setting it
to True uses wiggle_close, which may adjust endpoints within the default
wiggle tolerance.
pub fn wiggle_splice(
subpath: Subpath,
start start: Int,
delete delete: Int,
insert insert: List(Segment),
) -> Result(Subpath, Error)
Replace a range of segments, reconciling tiny endpoint gaps.
This has the same splice bounds behavior as splice, but validates the
edited subpath with wiggle_subpath and, for closed subpaths,
wiggle_close. Use this when the splice should preserve topology across
floating-point noise rather than requiring exact endpoint equality.
pub fn wiggle_subpath(
segments: List(Segment),
) -> Result(Subpath, Error)
Create an open subpath while gently reconciling tiny endpoint gaps.
This is useful after floating-point transformations. If adjacent segment endpoints are within the default wiggle tolerance, the overlap point is used to make the segments continuous.