pub struct AffineTransform<T: CoordNum = f64>(_);
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>

source

pub fn compose(&self, other: &Self) -> Self

Create a new affine transformation by composing two AffineTransforms.

This is a cumulative operation; the new transform is added to the existing transform.

source

pub fn identity() -> Self

Create the identity matrix

The matrix is:

[[1, 0, 0],
[0, 1, 0],
[0, 0, 1]]
source

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());
source

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)
source

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.

source

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]]
source

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

pub fn apply(&self, coord: Coord<T>) -> Coord<T>

Apply the current transform to a coordinate

source

pub fn new(a: T, b: T, xoff: T, d: T, e: T, yoff: T) -> Self

Create a new custom transform matrix

The argument order matches that of the affine transform matrix:

 [[a, b, xoff],
 [d, e, yoff],
 [0, 0, 1]] <-- not part of the input arguments
source§

impl<U: CoordFloat> AffineTransform<U>

source

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))
source

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.

source

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)
source

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>

source§

fn clone(&self) -> AffineTransform<T>

Returns a copy of the value. Read more
1.0.0 · source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
source§

impl<T: CoordNum> Debug for AffineTransform<T>

source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
source§

impl<T: CoordNum> Default for AffineTransform<T>

source§

fn default() -> Self

Returns the “default value” for a type. Read more
source§

impl<T: CoordNum> From<[T; 6]> for AffineTransform<T>

source§

fn from(arr: [T; 6]) -> Self

Converts to this type from the input type.
source§

impl<T: CoordNum> From<(T, T, T, T, T, T)> for AffineTransform<T>

source§

fn from(tup: (T, T, T, T, T, T)) -> Self

Converts to this type from the input type.
source§

impl<T: PartialEq + CoordNum> PartialEq<AffineTransform<T>> for AffineTransform<T>

source§

fn eq(&self, other: &AffineTransform<T>) -> bool

This method tests for self and other values to be equal, and is used by ==.
1.0.0 · source§

fn ne(&self, other: &Rhs) -> bool

This method tests for !=. The default implementation is almost always sufficient, and should not be overridden without very good reason.
source§

impl<T: Copy + CoordNum> Copy for AffineTransform<T>

source§

impl<T: Eq + CoordNum> Eq for AffineTransform<T>

source§

impl<T: CoordNum> StructuralEq for AffineTransform<T>

source§

impl<T: CoordNum> StructuralPartialEq for AffineTransform<T>

Auto Trait Implementations§

§

impl<T> RefUnwindSafe for AffineTransform<T>where T: RefUnwindSafe,

§

impl<T> Send for AffineTransform<T>where T: Send,

§

impl<T> Sync for AffineTransform<T>where T: Sync,

§

impl<T> Unpin for AffineTransform<T>where T: Unpin,

§

impl<T> UnwindSafe for AffineTransform<T>where T: UnwindSafe,

Blanket Implementations§

source§

impl<T> Any for Twhere T: 'static + ?Sized,

source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
source§

impl<T> Borrow<T> for Twhere T: ?Sized,

const: unstable · source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
source§

impl<T> BorrowMut<T> for Twhere T: ?Sized,

const: unstable · source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
source§

impl<T> From<T> for T

const: unstable · source§

fn from(t: T) -> T

Returns the argument unchanged.

source§

impl<T, U> Into<U> for Twhere U: From<T>,

const: unstable · source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

source§

impl<T> ToOwned for Twhere T: Clone,

§

type Owned = T

The resulting type after obtaining ownership.
source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
source§

impl<T, U> TryFrom<U> for Twhere U: Into<T>,

§

type Error = Infallible

The type returned in the event of a conversion error.
const: unstable · source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
source§

impl<T, U> TryInto<U> for Twhere U: TryFrom<T>,

§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
const: unstable · source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
source§

impl<G1, G2> Within<G2> for G1where G2: Contains<G1>,

source§

fn is_within(&self, b: &G2) -> bool