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. With default trimming, for each closed source subpath the 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. By
default, each side is 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.
SingleOffsetTrimming and BandTrimming allow these stages to be disabled
or, for a single offset, replaced by cusp-only trimming.
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. Open
bands connect them with the requested endpoint caps before final trimming;
closed bands have two contour sides and need no caps. The svg_path/stroke
module delegates nonzero stroke outlines to this same 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.
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.
Public failures from offset construction, fitting, and trimming.
pub type Error {
InvalidOffsetMapDistance(distance: Float, length: Float)
PathError(error: 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(error: 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. Carries the segment parameter where the tangent query failed.
-
MaxDepthReached(divergence: Float)Refinement could not produce an offset within the requested tolerance. Carries the remaining geometric divergence, not the recursion depth.
-
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)
Construction of a join on the inner side of a local source corner. This is independent of the caller-designated inner/outer band offsets.
pub type InnerJoin {
InnerBevel
InnerRound
}
Constructors
-
InnerBevel -
InnerRound
Join style used when offsetting adjacent subpath segments.
Supports SVG bevel, miter, miter-clip, round, and arcs.
pub type Join {
Arcs(miter_limit: Float)
Bevel
Miter(miter_limit: Float)
MiterClip(miter_limit: Float)
Round
}
Constructors
-
Arcs(miter_limit: Float)Continue source curvature with tangent circles, clipped at the limit. On the outer side, diverging rays and reversed source endpoints use Round. Straight/straight joins use MiterClip. The limit must be finite and positive.
-
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. -
MiterClip(miter_limit: Float)Keep the miter tip within the limit; otherwise clip it perpendicular to the pivot-to-tip direction at
miter_limit * abs(offset)from the pivot. The limit must be finite and positive. If the directed extensions do not meet, use the same bevel fallback asMiter. If the clipping plane would cut behind either join endpoint, useBevelrather than trim the adjacent segments. Limits below one are accepted with this same policy. -
RoundConnect adjacent offset segments with a circular SVG arc.
Offset construction options; the main join and cap are explicit parameters.
fitting controls offset approximation. 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.
inner_join overrides local inner-corner construction. None selects
InnerRound for Round joins and InnerBevel for every other join style.
It applies to each offset side independently, including single offsets.
pub type Options {
Options(
fitting: FittingOptions,
stalled_offset_diameter: Float,
tangent_heal_angle_degrees: Float,
inner_join: option.Option(InnerJoin),
single_offset_trimming: SingleOffsetTrimming,
band_trimming: BandTrimming,
)
}
Constructors
-
Options( fitting: FittingOptions, stalled_offset_diameter: Float, tangent_heal_angle_degrees: Float, inner_join: option.Option(InnerJoin), 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.
The resulting traversal is returned without a final nesting-based reversal
of closed contours into clockwise exteriors and counterclockwise holes.
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 cubic-fitting options for offset construction.
pub const default_miter_limit: Float
Conventional miter-limit ratio for Miter, MiterClip, and Arcs joins.
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.
Each pair is returned separately and uncapped; see subpath_band_untrimmed.
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)
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)
Construct a band between two signed visual-left-normal offsets.
Open sources receive the requested caps; closed sources need no caps.
Both offset orderings are accepted. Exchanging inner_offset and
outer_offset reverses the resulting band’s orientation.
Uses the default side-local cusp trimming and final in-band trimming.
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)
Return the two synchronized offset sides without side-local or final trimming.
Unlike subpath_band, this diagnostic form returns separate, uncapped
sides. Use subpath_band_with with trimming disabled for a capped band.
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.
The sides remain separate and uncapped, as in subpath_band_untrimmed.
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.
When its cusp trimming is enabled, 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. band_trimming.in_band controls final joint trimming using
their directed winding-side opinions. Open bands receive caps even when
final trimming is disabled.
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.