Skip to content

Commit 40fe887

Browse files
author
Andy Ferris
committed
WIP: Interfaces for AbstractAffineTransformation and AbstractLinearTransformations
1 parent cf3ca22 commit 40fe887

File tree

1 file changed

+91
-94
lines changed

1 file changed

+91
-94
lines changed

src/commontransformations.jl

Lines changed: 91 additions & 94 deletions
Original file line numberDiff line numberDiff line change
@@ -1,61 +1,110 @@
1-
abstract AbstractAffineTransformation <: Transformation
2-
abstract AbstractLinearTransformation <: AbstractAffineTransformation
1+
"""
2+
abstract AbstractAffineTransformation <: Transformation
33
4-
# Helper to compute a zeroed input point for an affine transformation
5-
# FIXME: deal with general input dimension and type.
6-
zeroed_input(trans::AbstractAffineTransformation) = Vec(0,0,0)
4+
Provides an interface for implementing Affine transformations of Cartesian
5+
coordinates. To implement an AbstractAffineTransformation, you must define
76
8-
# transform_deriv for AbstractAffineTransformation is independent of the point
9-
# about which we're linearizing.
10-
function transform_deriv(trans::AbstractAffineTransformation)
11-
transform_deriv(trans, zeroed_input(trans))
12-
end
7+
matrix(trans)
8+
translation(trans)
139
10+
where the resulting transformation is (equivalent to)
1411
15-
#-------------------------------------------------------------------------------
16-
# Linear Transformations
12+
trans(x) -> matrix(trans) * x + translation(trans)
1713
18-
"""
19-
LinearTransformation <: AbstractLinearTransformation
14+
Specific implementations may provide equivalent specializations of `call`, etc,
15+
for optimization purposes. The function `translation_reverse()` is provided,
16+
such that
2017
21-
A general linear transformation, constructed using `LinearTransformation(M)`
22-
for any matrix `M`. Other abstract linear transformations can be converted
23-
into a general linear transformation using `LinearTransformation(trans)`
18+
trans(x) -> matrix(trans) * (x + translation_reverse(trans))
19+
20+
(See also AffineTransformation, AbstractLinearTransformation, Translation)
2421
"""
25-
immutable LinearTransformation{MatrixT} <: AbstractLinearTransformation
26-
M::MatrixT
22+
abstract AbstractAffineTransformation <: Transformation
23+
24+
matrix(::AbstractAffineTransform) = error("AbstractAffineTransformation's must implement matrix()")
25+
translation(::AbstractAffineTransform) = error("AbstractAffineTransformation's must implement translation()")
26+
translation_reverse(::AbstractAffineTransformation) = matrix(trans) \ translation(trans)
27+
28+
# Default implementations
29+
@compat function (trans::AbstractAffineTransformation)(x)
30+
matrix(trans) * x + translation(trans)
2731
end
2832

29-
LinearTransformation(trans::LinearTransformation) = trans
33+
transform_deriv(trans::AbstractAffineTransformation) = matrix(trans)
34+
35+
# Could try do similar for transform_deriv_params()?
3036

31-
function LinearTransformation(trans::AbstractLinearTransformation)
32-
LinearTransformation(transform_deriv(trans, zeroed_input(trans)))
37+
@compat function (trans::AbstractAffineTransformation)(x)
38+
matrix(trans) * x + translation(x)
3339
end
3440

35-
Base.show(io::IO, trans::LinearTransformation) = print(io, "LinearTransformation($(trans.M))")
41+
function Base.inv(trans::AbstractAffineTransformation)
42+
Minv = inv(matrix(trans))
43+
AffineTransformation(Minv, -Minv * translation(trans))
44+
end
3645

37-
@compat function (trans::LinearTransformation)(x)
38-
trans.M*x
46+
function compose(t1::AbstractAffineTransformation, t2::AbstractAffineTransformation)
47+
AffineTransformation(matrix(t1) * matrix(t2), translation(t1) + matrix(t1) * translation(t2))
3948
end
4049

41-
Base.inv(trans::LinearTransformation) = LinearTransformation(inv(trans.M))
4250

43-
compose(t1::LinearTransformation, t2::LinearTransformation) = LinearTransformation(t1.M*t2.M)
51+
"""
52+
abstract AbstractLinearTransformation <: AbstractAffineTransformation
53+
54+
Provides an interface for implementing linear transformations of Cartesian
55+
coordinates. To implement an AbstractLinearTransformation, you must define
56+
57+
matrix(trans)
58+
59+
where the resulting transformation is (equivalent to)
60+
61+
trans(x) -> matrix(trans) * x
4462
45-
transform_deriv(trans::LinearTransformation, x) = trans.M
63+
Specific implementations may provide equivalent specializations of `call`, etc,
64+
for optimization purposes.
4665
66+
(See also LinearTransformation, AbstractAffineTransformation)
67+
"""
68+
abstract AbstractLinearTransformation <: AbstractAffineTransformation
4769

48-
function compose(t1::AbstractLinearTransformation, t2::AbstractLinearTransformation)
49-
LinearTransformation(t1) LinearTransformation(t2)
70+
matrix(::AbstractLinearTransformation) = error("AbstractLinearTransformation's must implement matrix()")
71+
@inline translation(::AbstractLinearTransformation) = 0 # Does this make sense?
72+
@inline translation_reverse(::AbstractLinearTransformation) = 0
73+
74+
# Default implementations
75+
@compat function (trans::AbstractLinearTransformation)(x)
76+
matrix(trans) * x
5077
end
5178

79+
# transform_deriv() provided by AbstractAffineTransformation
80+
81+
Base.inv(trans::AbstractLinearTransformation) = LinearTransformation(inv(matrix(trans))
82+
83+
compose(t1::AbstractLinearTransformation, t2::AbstractLinearTransformation) = LinearTransformation(matrix(t1) * matrix(t2))
84+
85+
86+
"""
87+
LinearTransformation <: AbstractLinearTransformation
88+
89+
A general linear transformation, constructed using `LinearTransformation(M)`
90+
for any matrix-like object `M`. Other abstract linear transformations can be
91+
converted into a general linear transformation using `LinearTransformation(trans)`
92+
"""
93+
immutable LinearTransformation{MatrixT} <: AbstractLinearTransformation
94+
M::MatrixT
95+
end
96+
97+
LinearTransformation(trans::AbstractLinearTransformation) = LinearTransformation(matrix(trans))
98+
99+
Base.show(io::IO, trans::LinearTransformation) = print(io, "LinearTransformation($(trans.M))") # TODO make this output more petite
100+
101+
@inline matrix(trans::LinearTransformation) = trans.M
102+
52103

53-
#-------------------------------------------------------------------------------
54-
# General Affine Transformations
55104
"""
56105
AffineTransformation <: AbstractAffineTransformation
57106
58-
A concrete affine transformation. To construct the mapping `v + M*x`, use
107+
A concrete affine transformation. To construct the mapping `x -> M*x + v`, use
59108
60109
AffineTransformation(M, v)
61110
@@ -72,67 +121,17 @@ immutable AffineTransformation{MatrixT, VectorT} <: AbstractAffineTransformation
72121
end
73122

74123
function AffineTransformation(trans::AbstractAffineTransformation)
75-
x = zeroed_input(trans)
76-
AffineTransformation(transform_deriv(trans, x), trans(x))
124+
AffineTransformation(matrix(trans), translation(trans))
77125
end
78126

79-
function AffineTransformation(trans::AbstractLinearTransformation)
80-
x = zeroed_input(trans)
81-
AffineTransformation(transform_deriv(trans, x), x)
82-
end
83-
84-
function AffineTransformation(trans::Transformation, x)
127+
# We can create an Affine transformation corresponding to the differential
128+
# transformation of x + dx
129+
function AffineTransformation(trans::AbstractTransformation, x)
85130
AffineTransformation(transform_deriv(trans, x), trans(x))
86131
end
87132

88-
Base.show(io::IO, trans::AffineTransformation) = print(io, "AffineTransformation($(trans.M), $(trans.v))")
89-
90-
@compat function (trans::AffineTransformation)(x)
91-
trans.M*x + trans.v
92-
end
93-
94-
function Base.inv(trans::AffineTransformation)
95-
Minv = inv(trans.M)
96-
AffineTransformation(Minv, -Minv*trans.v)
97-
end
133+
Base.show(io::IO, trans::AffineTransformation) = print(io, "AffineTransformation($(trans.M), $(trans.v))") # TODO make this output more petite
98134

99-
function transform_deriv(trans::AffineTransformation, x)
100-
trans.M
101-
end
102-
103-
function compose(t1::AffineTransformation, t2::AffineTransformation)
104-
AffineTransformation(t1.M*t2.M, t1.v + t1.M*t2.v)
105-
end
106-
107-
function compose(t1::AbstractAffineTransformation, t2::AbstractAffineTransformation)
108-
AffineTransformation(t1) AffineTransformation(t2)
109-
end
110-
111-
"""
112-
affine_decomposition_T_of_L(trans)
113-
114-
Decompose an affine transformation into a translation and linear part,
115-
returning `(v,M)` such that
116-
117-
trans(p) == (Translation(v) ∘ LinearTransformation(M))(p)
118-
"""
119-
function affine_decomposition_T_of_L(trans::AbstractAffineTransformation)
120-
A = AffineTransformation(trans)
121-
(A.v, A.M)
122-
end
123-
124-
"""
125-
affine_decomposition_L_of_T(trans)
126-
127-
Decompose an affine transformation into a translation and linear part,
128-
returning `(M,v)` such that
129-
130-
trans(x) == LinearTransformation(M) ∘ Translation(v)
131-
"""
132-
function affine_decomposition_L_of_T(trans::AbstractAffineTransformation)
133-
A = AffineTransformation(trans)
134-
(A.M, A.M\A.v)
135-
end
136135

137136

138137
###################
@@ -153,6 +152,10 @@ Translation(x,y) = Translation(Vec(x,y))
153152
Translation(x,y,z) = Translation(Vec(x,y,z))
154153
Base.show(io::IO, trans::Translation) = print(io, "Translation$((trans.dx...))")
155154

155+
@inline matrix(::Translation) = I
156+
@inline translation(trans::Translation) = trans.dx
157+
@inline translation(trans::Translation) = trans.dx
158+
156159
@compat function (trans::Translation)(x)
157160
x + trans.dx
158161
end
@@ -165,10 +168,6 @@ function compose(trans1::Translation, trans2::Translation)
165168
Translation(trans1.dx + trans2.dx)
166169
end
167170

168-
function transform_deriv(trans::Translation, x)
169-
I
170-
end
171-
172171
function transform_deriv_params(trans::Translation, x)
173172
I
174173
end
@@ -608,5 +607,3 @@ end
608607
function euler_rotation(θ₁, θ₂, θ₃, order::Union{Rotations.EulerXZX, Type{Rotations.EulerXZX}})
609608
RotationYZ(θ₁) RotationXY(θ₂) RotationYZ(θ₃)
610609
end
611-
612-

0 commit comments

Comments
 (0)