svg_path/affine

Low-level two-dimensional affine matrix helpers.

Matrices use SVG’s six-value affine form matrix(a b c d e f) and are applied to column vectors: x' = a*x + c*y + e, y' = b*x + d*y + f.

Types

A two-dimensional affine transform in SVG’s six-value matrix form.

pub type Affine {
  Affine(
    a: Float,
    b: Float,
    c: Float,
    d: Float,
    e: Float,
    f: Float,
  )
}

Constructors

  • Affine(
      a: Float,
      b: Float,
      c: Float,
      d: Float,
      e: Float,
      f: Float,
    )

Numerical factors with their algebraic order retained for recomposition. shear_x is the coefficient in [[1,h],[0,1]], not a skew angle. Rotation is in degrees. See decompose_with_order for sign conventions.

pub type Decomposition {
  Decomposition(
    order: DecompositionOrder,
    translation_x: Float,
    translation_y: Float,
    rotation_degrees: Float,
    shear_x: Float,
    scale_x: Float,
    scale_y: Float,
  )
}

Constructors

  • Decomposition(
      order: DecompositionOrder,
      translation_x: Float,
      translation_y: Float,
      rotation_degrees: Float,
      shear_x: Float,
      scale_x: Float,
      scale_y: Float,
    )

Failures while factoring an affine matrix in a requested order.

pub type DecompositionError {
  NoFactorizationInOrder(order: DecompositionOrder)
  DecompositionNonFinite
  DecompositionUnstable
}

Constructors

  • NoFactorizationInOrder(order: DecompositionOrder)

    The requested order has no finite real factorization under the computed rank/solvability conditions, including incompatible singular translation.

  • DecompositionNonFinite

    Input or a required factor/intermediate is not finite.

  • DecompositionUnstable

    Numerical range or conditioning prevented certified reconstruction.

Algebraic factor order (the rightmost factor acts on a point first). Each variant contains exactly one translation, rotation, x-shear and scale.

pub type DecompositionOrder {
  TranslationRotationShearXScale
  TranslationRotationScaleShearX
  TranslationShearXRotationScale
  TranslationShearXScaleRotation
  TranslationScaleRotationShearX
  TranslationScaleShearXRotation
  RotationTranslationShearXScale
  RotationTranslationScaleShearX
  RotationShearXTranslationScale
  RotationShearXScaleTranslation
  RotationScaleTranslationShearX
  RotationScaleShearXTranslation
  ShearXTranslationRotationScale
  ShearXTranslationScaleRotation
  ShearXRotationTranslationScale
  ShearXRotationScaleTranslation
  ShearXScaleTranslationRotation
  ShearXScaleRotationTranslation
  ScaleTranslationRotationShearX
  ScaleTranslationShearXRotation
  ScaleRotationTranslationShearX
  ScaleRotationShearXTranslation
  ScaleShearXTranslationRotation
  ScaleShearXRotationTranslation
}

Constructors

  • TranslationRotationShearXScale
  • TranslationRotationScaleShearX
  • TranslationShearXRotationScale
  • TranslationShearXScaleRotation
  • TranslationScaleRotationShearX
  • TranslationScaleShearXRotation
  • RotationTranslationShearXScale
  • RotationTranslationScaleShearX
  • RotationShearXTranslationScale
  • RotationShearXScaleTranslation
  • RotationScaleTranslationShearX
  • RotationScaleShearXTranslation
  • ShearXTranslationRotationScale
  • ShearXTranslationScaleRotation
  • ShearXRotationTranslationScale
  • ShearXRotationScaleTranslation
  • ShearXScaleTranslationRotation
  • ShearXScaleRotationTranslation
  • ScaleTranslationRotationShearX
  • ScaleTranslationShearXRotation
  • ScaleRotationTranslationShearX
  • ScaleRotationShearXTranslation
  • ScaleShearXTranslationRotation
  • ScaleShearXRotationTranslation

Failures while constructing a transform from point correspondences.

pub type Error {
  DegenerateSourcePair
  DegenerateSourceTriple
  NonFiniteTransform
}

Constructors

  • DegenerateSourcePair

    The source pair has zero separation in the scaled calculation.

  • DegenerateSourceTriple

    The source triple has zero determinant in the calculation, for example when its points are collinear or repeated.

  • NonFiniteTransform

    Construction produced a non-finite denominator or matrix coefficient.

Values

pub fn about_point(
  transform transform: Affine,
  x x: Float,
  y y: Float,
) -> Affine

Create a matrix that applies a transform about a point.

pub fn chain(first first: Affine, then second: Affine) -> Affine

Chain two transforms in application order.

chain(first: a, then: b) creates a matrix that applies a first and b second. In algebraic matrix order, this is b * a.

pub fn decompose(
  transform: Affine,
) -> Result(Decomposition, DecompositionError)

Factor using the default algebraic order T * R * Hx * S. For invertible matrices x-scale is positive; y-scale carries reflections.

pub fn decompose_with_order(
  transform: Affine,
  order order: DecompositionOrder,
) -> Result(Decomposition, DecompositionError)

Factor in a requested algebraic order, without falling back to another order.

RHS and RSH use positive x-scale; their reversed counterparts SHR and HSR use positive y-scale. For SRH, x-scale is positive and the valid quadratic branch with the smallest absolute rotation is preferred (then signed angle). HRS uses the dual convention with positive y-scale. Degenerate branches use zero shear where possible and nonnegative remaining scale. Rotation lies in (-180,180], with signed zero canonicalized. These are deterministic choices, not continuity guarantees for animation or an enumeration of all solutions.

All six coefficients are checked by recomposition. Each linear column and the translation vector must have relative max-norm error at most 1e-12; an exactly zero column/vector must reconstruct as zero. This backward-error bound does not bound relative error in ill-conditioned factors. No geometric tolerance is used to snap small scales to zero. Computed rank and quadratic discriminant tests are floating-point tests, not exact arithmetic proofs.

Singular maps are supported when the order permits them. Translation after a singular scale must lie in the image of the factors to its left. One free translation coordinate is set to zero, using the largest matrix entry as pivot. Near quadratic double roots are tried and accepted only if certified. Consequently, Ok certifies a nearby reconstruction, not exact algebraic solvability: a slightly negative computed discriminant can be accepted within a relative boundary allowance of 1e-14. A clearly negative discriminant is rejected. Rank lost through normalization underflow is a numerical failure; cancellation in rank tests is still not an exact singularity certificate. Finite extreme inputs may return a numerical error instead of factors.

pub fn determinant(transform: Affine) -> Float

Return the determinant of the linear part.

pub fn from_tuple(
  values: #(Float, Float, Float, Float, Float, Float),
) -> Affine

Create an affine matrix from SVG’s six matrix values as a tuple.

pub fn identity() -> Affine

The identity transform.

pub fn is_finite(transform: Affine) -> Bool

Return true when all six matrix entries are finite.

pub fn linear_point(
  transform: Affine,
  x x: Float,
  y y: Float,
) -> #(Float, Float)

Apply only the linear part of the matrix to raw coordinates.

pub fn matrix(
  a a: Float,
  b b: Float,
  c c: Float,
  d d: Float,
  e e: Float,
  f f: Float,
) -> Affine

Create an affine matrix from SVG’s six matrix values.

pub fn multiply(left left: Affine, right right: Affine) -> Affine

Multiply two matrices in algebraic order.

multiply(left: a, right: b) returns a * b.

pub fn point(
  transform: Affine,
  x x: Float,
  y y: Float,
) -> #(Float, Float)

Apply the full affine matrix to raw coordinates.

pub fn point_pair_similarity(
  source_start source_start: #(Float, Float),
  source_end source_end: #(Float, Float),
  target_start target_start: #(Float, Float),
  target_end target_end: #(Float, Float),
) -> Result(Affine, Error)

Find a translation, rotation, and uniform scale mapping one point pair to another.

Points are represented as raw coordinate tuples. Returns DegenerateSourcePair for zero computed source separation, or NonFiniteTransform when construction produces non-finite values.

pub fn point_triple_map(
  source_a source_a: #(Float, Float),
  source_b source_b: #(Float, Float),
  source_c source_c: #(Float, Float),
  target_a target_a: #(Float, Float),
  target_b target_b: #(Float, Float),
  target_c target_c: #(Float, Float),
) -> Result(Affine, Error)

Find an affine transform mapping one point triple to another.

Points are represented as raw coordinate tuples. Returns DegenerateSourceTriple for a zero computed source determinant, or NonFiniteTransform when construction produces non-finite values.

pub fn recompose(factors: Decomposition) -> Affine

Recompose using the stored algebraic order. Like raw matrix constructors, this does not validate user-supplied factors or catch arithmetic overflow.

pub fn rotate(degrees degrees: Float) -> Affine

Create a rotation matrix from an angle in degrees. Positive angles rotate visually clockwise in SVG coordinates (y down).

pub fn scale(factor factor: Float) -> Affine

Create a uniform scale matrix.

pub fn scale_xy(x x: Float, y y: Float) -> Affine

Create a non-uniform scale matrix.

pub fn skew_x(degrees degrees: Float) -> Affine

Create an x-axis skew matrix from an angle in degrees.

pub fn skew_y(degrees degrees: Float) -> Affine

Create a y-axis skew matrix from an angle in degrees.

pub fn to_tuple(
  transform: Affine,
) -> #(Float, Float, Float, Float, Float, Float)

Return SVG’s six matrix values as #(a, b, c, d, e, f).

pub fn translate(x x: Float, y y: Float) -> Affine

Create a translation matrix.

✨ Search Document