svg_path/offset
Path offset construction.
This module follows the same basic model as svgpathsio: lines and
circular arcs are offset exactly, while other curves are offset by fitted
cubic Beziers. Cubic approximations are checked by sampling the true normal
extrusion of the source curve and measuring its distance to the proposed
offset. If the error is too large, the source curve is split and each half
is offset recursively.
Subpath and path offsets first normalize the source, split it into stalled and not-stalled pieces, fit the offset pieces, heal their boundaries, add joins, and cull adjacent reversal loops. A trimmed single offset then nodes that walk with its final refined zero-offset source. For each closed source subpath, the arrangement dual floods the signed source-side faces and removes offside offset occurrences. A second arrangement classifies the remaining offset edges by their measured and expected winding pairs, removes winding mismatches, applies forced parity-capacity reductions, and reconstructs the survivors in source order.
Band construction shares source refinement between its two sides. Each
side is first noded against the zero-offset source and trimmed in source
order, retaining submerged runs that contain no reversed preimage. The two
surviving sides are then noded together; winding mismatches and forced
parity-capacity reductions are applied before the final band walks are
reconstructed.
Because trimming can split an offset or remove it entirely, subpath and
path offsets return Path.
The *_untrimmed helpers expose the untrimmed offset walk directly. It
is useful for debugging, drawing raw construction geometry, or implementing
a different trimming policy.
subpath_band and path_band construct two signed offset walks and trim
them together without adding endpoint caps to the arranged walks. Their
cap style closes the internal winding bands for open sources; disabling
in-band trimming returns that capped band outline. subpath_stroke and
path_stroke add endpoint caps to the arranged outline for open subpaths.
Closed strokes use capless per-subpath band construction.
Types
Trimming controls for a band.
inner_cusps and outer_cusps independently enable side-local cusp
trimming for the caller-designated inner and outer offsets. The names keep
those caller-designated roles even when inner_offset > outer_offset.
Each cusp-trimming region uses Butt closures, independently of the final cap.
in_band enables the final joint submerged trimming pass.
pub type BandTrimming {
BandTrimming(
inner_cusps: Bool,
outer_cusps: Bool,
in_band: Bool,
)
}
Constructors
-
BandTrimming(inner_cusps: Bool, outer_cusps: Bool, in_band: Bool)
Cap style used at open stroke endpoints and to close open-source winding bands.
pub type Cap {
Butt
Square
RoundCap
}
Constructors
-
ButtEnd the stroke exactly at the endpoint.
-
SquareExtend the stroke by half its width beyond the endpoint.
-
RoundCapAdd a semicircular endpoint cap.
pub type Error {
InvalidOffsetMapDistance(distance: Float, length: Float)
PathError(svg_path.Error)
InvalidTolerance(tolerance: Float)
InvalidSamples(samples: Int)
InvalidMaxDepth(max_depth: Int)
InvalidMiterLimit(miter_limit: Float)
InvalidStalledOffsetDiameter(diameter: Float)
InvalidTangentHealAngleDegrees(angle: Float)
DegenerateTangent(t: Float)
MaxDepthReached(divergence: Float)
NonFinite
ConstructionFailed
}
Constructors
-
InvalidOffsetMapDistance(distance: Float, length: Float)An offset-map distance lies outside the source length range.
-
PathError(svg_path.Error)An underlying path operation failed.
-
InvalidTolerance(tolerance: Float)The offset tolerance must be finite and greater than zero.
-
InvalidSamples(samples: Int)The number of divergence samples must be greater than zero.
-
InvalidMaxDepth(max_depth: Int)The recursive subdivision limit must be greater than zero.
-
InvalidMiterLimit(miter_limit: Float)The miter limit must be finite and greater than zero.
-
InvalidStalledOffsetDiameter(diameter: Float)The stalled offset diameter must be finite and non-negative.
-
InvalidTangentHealAngleDegrees(angle: Float)The tangent-healing angle must be finite and non-negative.
-
DegenerateTangent(t: Float)A segment tangent was too small to define a stable normal direction.
-
MaxDepthReached(divergence: Float)Refinement could not produce an offset within the requested tolerance.
-
NonFiniteA calculation produced a non-finite coordinate.
-
ConstructionFailedAn internal offset construction failure that has no stable public detail.
Cubic fitting controls used by the recursive offset builders.
tolerance bounds the sampled geometric error of a fitted offset curve,
samples controls the number of check samples, and max_depth limits
recursive subdivision. The offset pipeline additionally caps refinement at
five generations, so values above five do not increase refinement depth.
pub type FittingOptions {
FittingOptions(tolerance: Float, samples: Int, max_depth: Int)
}
Constructors
-
FittingOptions(tolerance: Float, samples: Int, max_depth: Int)
Join style used when offsetting adjacent subpath segments.
This covers the common SVG stroke-linejoin values bevel, miter, and
round. SVG 2 also describes miter-clip and arcs; those are not exposed
here yet.
pub type Join {
Bevel
Miter(miter_limit: Float)
Round
}
Constructors
-
BevelConnect adjacent offset segments with a straight line.
-
Miter(miter_limit: Float)Extend the offset tangents toward their intersection when the miter stays within
miter_limit; otherwise fall back toBevel. -
RoundConnect adjacent offset segments with a circular SVG arc.
Technical options for offset construction; styles are explicit parameters.
fitting controls offset approximation. distance_options controls
projection and root-finding used while pruning. stalled_offset_diameter
decides when the stalled-run builder treats an offset piece as too small to
keep as an ordinary independently fitted segment.
tangent_heal_angle_degrees is the maximum tangent direction mismatch, in
degrees, allowed by post-healing continuity checks at stable smooth
boundaries. single_offset_trimming and band_trimming select the public
trimming pipelines.
pub type Options {
Options(
fitting: FittingOptions,
distance_options: svg_path.DistanceOptions,
stalled_offset_diameter: Float,
tangent_heal_angle_degrees: Float,
single_offset_trimming: SingleOffsetTrimming,
band_trimming: BandTrimming,
)
}
Constructors
-
Options( fitting: FittingOptions, distance_options: svg_path.DistanceOptions, stalled_offset_diameter: Float, tangent_heal_angle_degrees: Float, single_offset_trimming: SingleOffsetTrimming, band_trimming: BandTrimming, )
Final trimming applied to a single offset after optional offside trimming.
CuspTrimming applies the side-local cusp trimmer independently to every
surviving offset walk. It can delete a walk, but a retained walk must keep
its original open/closed topology and, when open, its original endpoints.
InBandTrimming constructs the current zero-to-offset band arrangement and
performs the general winding and parity-capacity trim. It subsumes cusp
trimming and may return any number of reconstructed survivor subpaths.
NoTrimming returns the geometry surviving optional offside trimming.
pub type SingleOffsetFinalTrimming {
CuspTrimming
InBandTrimming
NoTrimming
}
Constructors
-
CuspTrimming -
InBandTrimming -
NoTrimming
Trimming controls for a single offset.
offside enables face-contamination trimming for each closed source
subpath independently. One closed input offset walk may become zero, one,
or several closed survivor walks. Open source subpaths pass through this
stage unchanged.
final_trimming selects the terminal operation. In-band trimming includes
cusp removal and is the default, more comprehensive operation.
pub type SingleOffsetTrimming {
SingleOffsetTrimming(
offside: Bool,
final_trimming: SingleOffsetFinalTrimming,
)
}
Constructors
-
SingleOffsetTrimming( offside: Bool, final_trimming: SingleOffsetFinalTrimming, )
Values
pub fn default_fitting_options() -> FittingOptions
Return default options for offset construction.
pub const default_miter_limit: Float
pub fn default_options() -> Options
Return default technical options for offset construction.
pub fn path(
path: svg_path.Path,
offset offset: Float,
join join: Join,
cap cap: Cap,
) -> Result(svg_path.Path, Error)
Offset every subpath in a path by a signed normal displacement.
pub fn path_band(
path: svg_path.Path,
inner_offset inner_offset: Float,
outer_offset outer_offset: Float,
join join: Join,
cap cap: Cap,
) -> Result(svg_path.Path, Error)
Offset every subpath at two signed normal displacements and trim each pair.
Exchanging inner_offset and outer_offset reverses each resulting band.
pub fn path_band_untrimmed(
path: svg_path.Path,
inner_offset inner_offset: Float,
outer_offset outer_offset: Float,
join join: Join,
) -> Result(svg_path.Path, Error)
Offset every subpath at two signed normal displacements without trimming any side.
pub fn path_band_untrimmed_with(
path path: svg_path.Path,
inner_offset inner_offset: Float,
outer_offset outer_offset: Float,
join join: Join,
options options: Options,
) -> Result(svg_path.Path, Error)
Offset every subpath at two signed normal displacements without trimming any side, using explicit options.
pub fn path_band_with(
path path: svg_path.Path,
inner_offset inner_offset: Float,
outer_offset outer_offset: Float,
join join: Join,
cap cap: Cap,
options options: Options,
) -> Result(svg_path.Path, Error)
Offset every subpath in a path at two signed normal displacements using options.
pub fn path_untrimmed(
path: svg_path.Path,
offset offset: Float,
join join: Join,
) -> Result(svg_path.Path, Error)
Stroke every subpath in a path using explicit join and cap styles. Stroke every subpath in a path using explicit join, cap, and technical options. Offset every subpath in a path without trimming self-intersections.
pub fn path_untrimmed_with(
path path: svg_path.Path,
offset offset: Float,
join join: Join,
options options: Options,
) -> Result(svg_path.Path, Error)
Offset every subpath in a path without trimming self-intersections using explicit options.
pub fn path_with(
path path: svg_path.Path,
offset offset: Float,
join join: Join,
cap cap: Cap,
options options: Options,
) -> Result(svg_path.Path, Error)
Offset every subpath by a signed normal displacement using explicit options.
pub fn segment(
segment: svg_path.Segment,
offset offset: Float,
join join: Join,
) -> Result(svg_path.Subpath, Error)
Offset one segment by a signed normal displacement.
Positive offsets point along the visual left normal. For a line
from (0, 0) to (10, 0), offset: 2.0 returns a line from (0, -2) to
(10, -2).
Curves return an open subpath because the result may need several pieces to
stay within tolerance. Circular arcs offset to circular arcs; non-circular
arcs and Beziers use cubic fitting.
join connects any separate traversals produced by degenerate normalization.
pub fn segment_with(
segment segment: svg_path.Segment,
offset offset: Float,
join join: Join,
options options: Options,
) -> Result(svg_path.Subpath, Error)
Offset one segment by a signed normal displacement using explicit options.
pub fn subpath(
subpath: svg_path.Subpath,
offset offset: Float,
join join: Join,
cap cap: Cap,
) -> Result(svg_path.Path, Error)
Offset a subpath by a signed normal displacement.
Positive offsets point along the visual left normal. Adjacent
offset segments are connected using join. The result is
a path because trimming self-intersections can split the offset into
multiple subpaths or remove it entirely.
Trimming nodes the untrimmed offset together with its final refined
zero-offset source pieces, removes zero-source-only and winding-mismatched
arrangement capacities, applies forced parity reductions, and reconstructs
surviving offset edges in untrimmed traversal order.
cap closes the internal winding bands at open source endpoints.
pub fn subpath_band(
subpath: svg_path.Subpath,
inner_offset inner_offset: Float,
outer_offset outer_offset: Float,
join join: Join,
cap cap: Cap,
) -> Result(svg_path.Path, Error)
pub fn subpath_band_untrimmed(
subpath: svg_path.Subpath,
inner_offset inner_offset: Float,
outer_offset outer_offset: Float,
join join: Join,
) -> Result(svg_path.Path, Error)
pub fn subpath_band_untrimmed_with(
subpath subpath: svg_path.Subpath,
inner_offset inner_offset: Float,
outer_offset outer_offset: Float,
join join: Join,
options options: Options,
) -> Result(svg_path.Path, Error)
Offset a subpath at two signed normal displacements without trimming, using explicit options.
pub fn subpath_band_with(
subpath subpath: svg_path.Subpath,
inner_offset inner_offset: Float,
outer_offset outer_offset: Float,
join join: Join,
cap cap: Cap,
options options: Options,
) -> Result(svg_path.Path, Error)
Offset a subpath at two signed normal displacements using explicit options.
Each synchronized side is first noded and trimmed on its own. A submerged run without any reversed source preimage is retained because it does not represent a reversal-generated fold. The surviving sides are then assembled into a band and trimmed together using their directed winding-side opinions.
pub fn subpath_offset_map(
subpath: svg_path.Subpath,
) -> Result(
fn(svg_path.Point) -> Result(svg_path.Point, Error),
Error,
)
Build a local coordinate map around a subpath.
The returned function interprets x as arc length along the source and y
as signed offset along its visual left normal. Open subpaths reject x
outside 0.0..subpath_length; closed subpaths wrap it modulo their length.
Empty and zero-length subpaths cannot define this map and return an error.
pub fn subpath_offset_map_with(
subpath: svg_path.Subpath,
options options: svg_path.LengthOptions,
) -> Result(
fn(svg_path.Point) -> Result(svg_path.Point, Error),
Error,
)
Build a local coordinate map around a subpath using explicit length options.
pub fn subpath_untrimmed(
subpath: svg_path.Subpath,
offset offset: Float,
join join: Join,
) -> Result(svg_path.Subpath, Error)
Offset a subpath without trimming self-intersections.
This returns the untrimmed one-sided offset walk. Adjacent segment offsets
are connected with join; the result may self-intersect or
contain sections that a trimmed offset would remove.
pub fn subpath_untrimmed_with(
subpath subpath: svg_path.Subpath,
offset offset: Float,
join join: Join,
options options: Options,
) -> Result(svg_path.Subpath, Error)
Offset a subpath without trimming self-intersections using explicit options.
pub fn subpath_with(
subpath subpath: svg_path.Subpath,
offset offset: Float,
join join: Join,
cap cap: Cap,
options options: Options,
) -> Result(svg_path.Path, Error)
Offset a subpath by a signed normal displacement using explicit options.