svg_path/curvature

Signed curvature, radius, inflection points, and offset-cusp diagnostics.

Signs refer to the visual left normal in SVG coordinates (positive y down). Curvature has inverse-length units; radius, target distances, and margins have length units. Parameters refer to the segment’s 0.0..1.0 interval.

Pointwise queries evaluate segment derivatives directly. Cusp discovery partitions at curvature extrema before bisection. Individual contracts describe numerical limitations.

Types

First and second derivative data at a segment parameter.

pub type Derivatives {
  Derivatives(first: svg_path.Point, second: svg_path.Point)
}

Constructors

Error returned by curvature helpers.

Cases distinguish invalid options (carrying the supplied value), underlying path-operation failures, and degenerate or infinite curvature geometry.

pub type Error {
  PathError(error: svg_path.Error)
  InvalidCurvatureTolerance(tolerance: Float)
  InvalidCurvatureMaxDepth(max_depth: Int)
  InvalidCurvatureMargin(margin: Float)
  DegenerateCurvatureDerivative
  InfiniteRadiusOfCurvature
  CurvatureRootIsolationFailed
  CurvatureMaxDepthReached(lower: Float, upper: Float)
}

Constructors

  • PathError(error: svg_path.Error)

    An underlying segment derivative query failed, for example arc conversion.

  • InvalidCurvatureTolerance(tolerance: Float)

    A curvature tolerance option was invalid (not finite or negative).

  • InvalidCurvatureMaxDepth(max_depth: Int)

    A curvature max_depth option was invalid (not positive).

  • InvalidCurvatureMargin(margin: Float)

    A curvature margin argument was invalid (not finite or negative).

  • DegenerateCurvatureDerivative

    The segment has a degenerate zero-speed parameter, so its curvature is undefined there.

  • InfiniteRadiusOfCurvature

    The radius of curvature is infinite at this parameter (a line or an inflection/flat point).

  • CurvatureRootIsolationFailed

    Polynomial isolation could not determine the curvature partition points.

  • CurvatureMaxDepthReached(lower: Float, upper: Float)

    Cusp bisection exhausted its depth before satisfying the parameter tolerance or finding an exact root. Bounds are the remaining bracket.

Options for cusp discovery. All fields are validated by discovery functions. Inflection discovery is algebraic and uses none of these fields after validation.

pub type Options {
  Options(tolerance: Float, max_depth: Int)
}

Constructors

  • Options(tolerance: Float, max_depth: Int)

    Arguments

    tolerance

    Numeric tolerance for roots and interval widths in parameter space.

    max_depth

    Maximum bisection/subdivision depth.

Values

pub fn default_options() -> Options

Return default curvature options.

pub fn segment_derivatives(
  segment: svg_path.Segment,
  at t: Float,
) -> Result(Derivatives, svg_path.Error)

Return first and second parameter derivatives for a segment at t.

Lines return zero second derivative. Arcs use exact ellipse derivatives.

pub fn segment_inflection_parameters(
  segment: svg_path.Segment,
  options options: Options,
) -> Result(List(Float), Error)

Return algebraically computed interior inflection parameters.

This solves cross(p'(t), p''(t)) = 0. Lines and identically flat pieces return an empty list. Roots at the segment endpoints are filtered out. Cubics use the Bezier inflection solver; lines, quadratics, and arcs return an empty list. Options are validated but do not affect the algebraic solve.

pub fn segment_left_normal_curvature(
  segment: svg_path.Segment,
  at t: Float,
) -> Result(Float, Error)

Return visual-left-normal signed curvature at a segment parameter.

Positive values mean the curve bends toward the visual left of its tangent; negative values mean it bends toward the visual right. Directional words use SVG page coordinates, where positive y points down. Lines return 0.0. Degenerate zero-speed parameters return an error.

pub fn segment_left_normal_cusp_parameters(
  segment: svg_path.Segment,
  distance distance: Float,
  options options: Options,
) -> Result(List(Float), Error)

Find parameters where visual-left-normal signed radius equals distance.

Polynomial curvature extrema (degree at most five for cubics) and zero-speed parameters partition Beziers into monotone-curvature intervals. Ellipses use their axis extrema. Partition points are checked for touching roots, and crossings are bisected.

Touches use a 1e-12 relative cancellation threshold in the cusp residual; sufficiently close misses cannot be distinguished from exact touches. Completeness is subject to polynomial isolation and floating-point accuracy. Zero-speed parameters are excluded, using one-sided residual signs to search their neighboring intervals. Lines and zero offsets return []. A circular arc whose entire radius matches the target returns [0.0, 1.0]. Bisection returns CurvatureMaxDepthReached with the remaining bracket if max_depth is exhausted before convergence. An exact midpoint root or an interval within tolerance still succeeds at the depth limit. Polynomial-isolation failures and arc-conversion errors also propagate. Results are sorted and merged within options.tolerance in parameter space.

pub fn segment_left_normal_cusp_residual(
  segment: svg_path.Segment,
  distance distance: Float,
  at t: Float,
) -> Result(Float, Error)

Return the visual-left-normal cusp residual |p'|^3 + distance * cross(p', p'').

A zero residual means the visual-left-normal signed radius equals distance, assuming finite nonzero curvature. Its magnitude depends on parameter speed: it has cubed-length units for a dimensionless parameter and is not a geometric distance error. Lines return |p'|^3; zero-speed parameters return DegenerateCurvatureDerivative.

pub fn segment_left_normal_radius(
  segment: svg_path.Segment,
  at t: Float,
) -> Result(Float, Error)

Return visual-left-normal signed radius of curvature at a segment parameter.

Lines and inflection points return Error(InfiniteRadiusOfCurvature) because their radius is infinite. Degenerate zero-speed parameters return Error(DegenerateCurvatureDerivative).

pub fn segment_left_normal_radius_close_to(
  segment: svg_path.Segment,
  distance distance: Float,
  margin margin: Float,
  at t: Float,
) -> Result(Bool, Error)

Return abs(R_left(t) - distance) < margin without evaluating R_left(t) directly.

Algebraically, for finite nonzero curvature this is equivalent to:

abs(|p'|^3 + distance * cross(p', p'')) < margin * abs(cross(p', p'')).

Search Document