struct Chem::Spatial::Transform

Overview

A Transform encodes an affine transformation in 3D space such as translation, scaling, rotation, reflection, and more.

An affine transformation is the composition of a linear map A (3x3 matrix) and a translation b (3x1 vector), which can be represented by the augmented 4x4 matrix:

[ A   b ]
[ 0   1 ]

where the bottom row is [0, 0, 0, 1]. This representation encodes the linear map and translation in a single matrix, which allows to combine and apply transformations by matrix multiplication. Additionally, the affine transformation matrix has some properties that allows for efficient code (see the multiplication operator with a vector). For further details, refer to the Wikipedia article.

The transformation is internally represented by a Mat3 (#linear_map) and Vec3 (#offset) instances.

Examples

scaling = Transform.scaling(2)
translation = Transform.translation(Vec3[1, 2, 3])
vec = Vec3[1, 0, 1]

# apply the transformation
scaling * vec     # => Vec3[2.0, 0.0, 2.0]
translation * vec # => Vec3[2.0, 2.0, 4.0]
# or
vec.transform(scaling)     # => Vec3[2.0, 0.0, 2.0]
vec.transform(translation) # => Vec3[2.0, 2.0, 4.0]

# note that multiplication is not commutative
scaling * vec # => Vec3[2.0, 0.0, 2.0]
vec * scaling # => Vec3[0.5, 0.0, 0.5] # inverse transformation

# combine transformations
translate_scale = scaling * translation # translates then scales
translate_scale * vec                   # => Vec3[4.0, 4.0, 8.0]
scale_translate = translation * scaling # scales than translates
scale_translate * vec                   # => Vec3[3.0, 2.0, 5.0]

# chain methods for composing a transformation
transform = Transform.scaling(2).translate(Vec3[1, 2, 3])
transform * vec # => Vec3[3.0, 2.0, 5.0]

Defined in:

chem/spatial/transform.cr:53
chem/spatial/transform.cr:275

Constructors

Instance Method Summary

Constructor Detail

def self.aligning(u : Tuple(Vec3, Vec3), to v : Tuple(Vec3, Vec3)) : self #

Returns a transformation encoding the rotation to align u[0] to v[0] and u[1] to v[1].

First compute the alignment of u[0] to v[0], then the alignment of the transformed u[1] to v[1] on the plane perpendicular to v[0] by taking their projections.


[View source]
def self.aligning(u : Vec3, to v : Vec3) : self #

Returns a transformation encoding the rotation operation to align u to v.


[View source]
def self.aligning(pos : CoordinatesProxy, to ref_pos : CoordinatesProxy) : self #

Returns the transformation encoding the rotation and traslation to align pos onto ref_pos. Raises ArgumentError if the two coordinate sets are of different size.

The optimal rotation matrix is computed by minimizing the root mean square deviation (RMSD) using the QCP method (refer to Spatial.qcp for details).


[View source]
def self.aligning(pos : AtomCollection, to ref_pos : AtomCollection) : self #

[View source]
def self.identity : self #

Returns the identity transformation.


[View source]
def self.new(linear_map : Mat3, offset : Vec3 = Vec3.zero) #

Creates a new transformation with linear_map and offset.


[View source]
def self.rotation(x : Number, y : Number, z : Number) : self #

Returns a transformation that rotates by the Euler angles in degrees. Delegates to Quat.rotation for computing the rotation.


[View source]
def self.rotation(about rotaxis : Vec3, by angle : Number) : self #

Returns a transformation that rotates about the axis vector rotaxis by angle degrees. Delegates to Quat.rotation for computing the rotation.


[View source]
def self.rotation(quat : Quat) : self #

Returns a transformation that applies the rotation encoded by the given quaternion.


[View source]
def self.scaling(sx : Number, sy : Number, sz : Number) : self #

Returns a transformation that scales by the given factors.


[View source]
def self.scaling(factor : Number) : self #

Returns a transformation that scales by factor.


[View source]
def self.translation(offset : Vec3) : self #

Returns a transformation that translates by offset.


[View source]

Instance Method Detail

def *(rhs : self) : self #

Returns the multiplication of the transformation by rhs. It effectively combines two transformation.

NOTE Multiplication of transformations is not commutative, i.e., a * b != b * a.

scaling = Transform.scaling(2)
translation = Transform.translation(Vec3[1, 2, 3])
vec = Vec3[1, 0, 1]

translate_scale = scaling * translation # translates then scales
translate_scale * vec                   # => Vec3[4.0, 4.0, 8.0]
scale_translate = translation * scaling # scales than translates
scale_translate * vec                   # => Vec3[3.0, 2.0, 5.0]

[View source]
def *(rhs : Vec3) : Vec3 #

Returns the multiplication of the transformation by rhs. It effectively applies the transformation to rhs.


[View source]
def ==(rhs : self) : Bool #

[View source]
def close_to?(rhs : self, delta : Float64 = Float64::EPSILON) : Bool #

Returns true if the elements of the quaternions are within delta from each other, else false.


[View source]
def inv : self #

Returns the inverse transformation.

The algorithm exploits the fact that the affine transformation matrix is defined as

[ A   b ]
[ 0   1 ]

where A is the linear map (3x3 matrix), b is the translation vector (3x1 vector), and the bottom row is [0, 0, 0, 1]. In such case, the inverse matrix can be computed as

[ inv(A)   -inv(A) * b ]
[   0            1     ]

where inv(A) is computed following the standard procedure (see Inversion of 3x3 matrices at Wikipedia).

Refer to the Affine Transformation Wikipedia article for a detailed explanation or this answer in Stack Overflow.


[View source]
def linear_map : Mat3 #

Linear map encoded as a 3x3 matrix.


[View source]
def offset : Vec3 #

Translation vector.


[View source]
def rotate(x : Number, y : Number, z : Number) : self #

Returns the transformation rotated by the given Euler angles in degrees. Delegates to Quat.rotation for computing the rotation.


[View source]
def rotate(about rotaxis : Vec3, by angle : Number) : self #

Returns the transformation rotated about rotaxis by angle degrees. Delegates to Quat.rotation for computing the rotation.


[View source]
def rotate(quat : Quat) : self #

Returns the transformation rotated by the given quaternion.


[View source]
def rotation : self #

Returns the rotation component of the transformation.


[View source]
def scale(sx : Number, sy : Number, sz : Number) : self #

Returns the transformation scaled by the given factors.


[View source]
def scale(by factor : Number) : self #

Returns the transformation scaled by factor.


[View source]
def to_s(io : IO) : Nil #
Description copied from struct Struct

Same as #inspect(io).


[View source]
def transform(by transform : self) : self #

Returns the transformation transformed by transform. It effectively combines two transformations.


[View source]
def translate(by offset : Vec3) : self #

Returns the transformation translated by the given offset.


[View source]
def translation : self #

Returns the translation component of the transformation.


[View source]