Struct geo::algorithm::affine_ops::AffineTransform
source · pub struct AffineTransform<T: CoordNum = f64>(/* private fields */);
Expand description
A general affine transformation matrix, and associated operations.
Note that affine ops are already implemented on most geo-types
primitives, using this module.
Affine transforms using the same numeric type (e.g. CoordFloat
) can be composed,
and the result can be applied to geometries using e.g. MapCoords
. This allows the
efficient application of transforms: an arbitrary number of operations can be chained.
These are then composed, producing a final transformation matrix which is applied to the geometry coordinates.
AffineTransform
is a row-major matrix.
2D affine transforms require six matrix parameters:
[a, b, xoff, d, e, yoff]
these map onto the AffineTransform
rows as follows:
[[a, b, xoff],
[d, e, yoff],
[0, 0, 1]]
The equations for transforming coordinates (x, y) -> (x', y')
are given as follows:
x' = ax + by + xoff
y' = dx + ey + yoff
Usage
Two types of operation are provided: construction and mutation. Construction functions create a new transform
and are denoted by the use of the present tense: scale()
, translate()
, rotate()
, and skew()
.
Mutation methods add a transform to the existing AffineTransform
, and are denoted by the use of the past participle:
scaled()
, translated()
, rotated()
, and skewed()
.
Examples
Build up transforms by beginning with a constructor, then chaining mutation operations
use geo::{AffineOps, AffineTransform};
use geo::{line_string, BoundingRect, Point, LineString};
use approx::assert_relative_eq;
let ls: LineString = line_string![
(x: 0.0f64, y: 0.0f64),
(x: 0.0f64, y: 10.0f64),
];
let center = ls.bounding_rect().unwrap().center();
let transform = AffineTransform::skew(40.0, 40.0, center).rotated(45.0, center);
let skewed_rotated = ls.affine_transform(&transform);
assert_relative_eq!(skewed_rotated, line_string![
(x: 0.5688687f64, y: 4.4311312),
(x: -0.5688687, y: 5.5688687)
], max_relative = 1.0);
Implementations§
source§impl<T: CoordNum> AffineTransform<T>
impl<T: CoordNum> AffineTransform<T>
sourcepub fn compose(&self, other: &Self) -> Self
pub fn compose(&self, other: &Self) -> Self
Create a new affine transformation by composing two AffineTransform
s.
This is a cumulative operation; the new transform is added to the existing transform.
sourcepub fn is_identity(&self) -> bool
pub fn is_identity(&self) -> bool
Whether the transformation is equivalent to the identity matrix, that is, whether it’s application will be a a no-op.
use geo::AffineTransform;
let mut transform = AffineTransform::identity();
assert!(transform.is_identity());
// mutate the transform a bit
transform = transform.translated(1.0, 2.0);
assert!(!transform.is_identity());
// put it back
transform = transform.translated(-1.0, -2.0);
assert!(transform.is_identity());
sourcepub fn scale(xfact: T, yfact: T, origin: impl Into<Coord<T>>) -> Self
pub fn scale(xfact: T, yfact: T, origin: impl Into<Coord<T>>) -> Self
Create a new affine transform for scaling, scaled by factors along the x
and y
dimensions.
The point of origin is usually given as the 2D bounding box centre of the geometry, but
any coordinate may be specified.
Negative scale factors will mirror or reflect coordinates.
The matrix is:
[[xfact, 0, xoff],
[0, yfact, yoff],
[0, 0, 1]]
xoff = origin.x - (origin.x * xfact)
yoff = origin.y - (origin.y * yfact)
sourcepub fn scaled(self, xfact: T, yfact: T, origin: impl Into<Coord<T>>) -> Self
pub fn scaled(self, xfact: T, yfact: T, origin: impl Into<Coord<T>>) -> Self
Add an affine transform for scaling, scaled by factors along the x
and y
dimensions.
The point of origin is usually given as the 2D bounding box centre of the geometry, but
any coordinate may be specified.
Negative scale factors will mirror or reflect coordinates.
This is a cumulative operation; the new transform is added to the existing transform.
sourcepub fn translate(xoff: T, yoff: T) -> Self
pub fn translate(xoff: T, yoff: T) -> Self
Create an affine transform for translation, shifted by offsets along the x
and y
dimensions.
The matrix is:
[[1, 0, xoff],
[0, 1, yoff],
[0, 0, 1]]
sourcepub fn translated(self, xoff: T, yoff: T) -> Self
pub fn translated(self, xoff: T, yoff: T) -> Self
Add an affine transform for translation, shifted by offsets along the x
and y
dimensions
This is a cumulative operation; the new transform is added to the existing transform.
source§impl<T: CoordNum + Neg> AffineTransform<T>
impl<T: CoordNum + Neg> AffineTransform<T>
source§impl<U: CoordFloat> AffineTransform<U>
impl<U: CoordFloat> AffineTransform<U>
sourcepub fn rotate(degrees: U, origin: impl Into<Coord<U>>) -> Self
pub fn rotate(degrees: U, origin: impl Into<Coord<U>>) -> Self
Create an affine transform for rotation, using an arbitrary point as its centre.
Note that this operation is only available for geometries with floating point coordinates.
angle
is given in degrees.
The matrix (angle denoted as theta) is:
[[cos_theta, -sin_theta, xoff],
[sin_theta, cos_theta, yoff],
[0, 0, 1]]
xoff = origin.x - (origin.x * cos(theta)) + (origin.y * sin(theta))
yoff = origin.y - (origin.x * sin(theta)) + (origin.y * cos(theta))
sourcepub fn rotated(self, angle: U, origin: impl Into<Coord<U>>) -> Self
pub fn rotated(self, angle: U, origin: impl Into<Coord<U>>) -> Self
Add an affine transform for rotation, using an arbitrary point as its centre.
Note that this operation is only available for geometries with floating point coordinates.
angle
is given in degrees.
This is a cumulative operation; the new transform is added to the existing transform.
sourcepub fn skew(xs: U, ys: U, origin: impl Into<Coord<U>>) -> Self
pub fn skew(xs: U, ys: U, origin: impl Into<Coord<U>>) -> Self
Create an affine transform for skewing.
Note that this operation is only available for geometries with floating point coordinates.
Geometries are sheared by angles along x (xs
) and y (ys
) dimensions.
The point of origin is usually given as the 2D bounding box centre of the geometry, but
any coordinate may be specified. Angles are given in degrees.
The matrix is:
[[1, tan(x), xoff],
[tan(y), 1, yoff],
[0, 0, 1]]
xoff = -origin.y * tan(xs)
yoff = -origin.x * tan(ys)
sourcepub fn skewed(self, xs: U, ys: U, origin: impl Into<Coord<U>>) -> Self
pub fn skewed(self, xs: U, ys: U, origin: impl Into<Coord<U>>) -> Self
Add an affine transform for skewing.
Note that this operation is only available for geometries with floating point coordinates.
Geometries are sheared by angles along x (xs
) and y (ys
) dimensions.
The point of origin is usually given as the 2D bounding box centre of the geometry, but
any coordinate may be specified. Angles are given in degrees.
This is a cumulative operation; the new transform is added to the existing transform.
Trait Implementations§
source§impl<T: Clone + CoordNum> Clone for AffineTransform<T>
impl<T: Clone + CoordNum> Clone for AffineTransform<T>
source§fn clone(&self) -> AffineTransform<T>
fn clone(&self) -> AffineTransform<T>
1.0.0 · source§fn clone_from(&mut self, source: &Self)
fn clone_from(&mut self, source: &Self)
source
. Read moresource§impl<T: CoordNum> Debug for AffineTransform<T>
impl<T: CoordNum> Debug for AffineTransform<T>
source§impl<T: CoordNum> Default for AffineTransform<T>
impl<T: CoordNum> Default for AffineTransform<T>
source§impl<T: CoordNum> From<(T, T, T, T, T, T)> for AffineTransform<T>
impl<T: CoordNum> From<(T, T, T, T, T, T)> for AffineTransform<T>
source§fn from(tup: (T, T, T, T, T, T)) -> Self
fn from(tup: (T, T, T, T, T, T)) -> Self
source§impl<T: PartialEq + CoordNum> PartialEq for AffineTransform<T>
impl<T: PartialEq + CoordNum> PartialEq for AffineTransform<T>
source§fn eq(&self, other: &AffineTransform<T>) -> bool
fn eq(&self, other: &AffineTransform<T>) -> bool
self
and other
values to be equal, and is used
by ==
.