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.
-
DecompositionNonFiniteInput or a required factor/intermediate is not finite.
-
DecompositionUnstableNumerical 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
-
DegenerateSourcePairThe source pair has zero separation in the scaled calculation.
-
DegenerateSourceTripleThe source triple has zero determinant in the calculation, for example when its points are collinear or repeated.
-
NonFiniteTransformConstruction 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 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 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).