Skip to content

Commit a2d47b1

Browse files
author
Andy Ferris
committed
Finalize API for abstract affine, linear, etc transforms
* Now use translation_vector() and transformation_matrix() * Removing tuple support for Translation * Compositions should function OK. * My plan for rotations is to implement them as a special kind of static matrix in Rotations.jl, which have fast specialized multiplication, etc. All the rotations here could potentially be removed.
1 parent af50a13 commit a2d47b1

File tree

3 files changed

+144
-86
lines changed

3 files changed

+144
-86
lines changed

src/CoordinateTransformations.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ export SphericalFromCartesian, CartesianFromSpherical,
4141

4242
# Common transformations
4343
export AbstractAffineTransformation
44-
export AffineTransformation, LinearTransformation, Translation, matrix, translation, translation_reverse
44+
export AffineTransformation, LinearTransformation, Translation, transformation_matrix, translation_vector, translation_vector_reverse
4545
export affine_decomposition_T_of_L, affine_decomposition_L_of_T
4646
export RotationPolar, Rotation2D
4747
export Rotation, RotationXY, RotationYZ, RotationZX

src/commontransformations.jl

Lines changed: 143 additions & 84 deletions
Original file line numberDiff line numberDiff line change
@@ -4,48 +4,44 @@
44
Provides an interface for implementing Affine transformations of Cartesian
55
coordinates. To implement an AbstractAffineTransformation, you must define
66
7-
matrix(trans)
8-
translation(trans)
7+
transformation_matrix(trans)
8+
translation_vector(trans)
99
1010
where the resulting transformation is (equivalent to)
1111
12-
trans(x) -> matrix(trans) * x + translation(trans)
12+
trans(x) -> transformation_matrix(trans) * x + translation_vector(trans)
1313
1414
Specific implementations may provide equivalent specializations of `call`, etc,
15-
for optimization purposes. The function `translation_reverse()` is provided,
15+
for optimization purposes. The function `translation_vector_reverse()` is provided,
1616
such that
1717
18-
trans(x) -> matrix(trans) * (x + translation_reverse(trans))
18+
trans(x) -> transformation_matrix(trans) * (x + translation_vector_reverse(trans))
1919
2020
(See also AffineTransformation, AbstractLinearTransformation, Translation)
2121
"""
2222
abstract AbstractAffineTransformation <: Transformation
2323

24-
matrix(trans::AbstractAffineTransformation) = error("AbstractAffineTransformation $(typeof(trans)) must implement matrix()")
25-
translation(trans::AbstractAffineTransformation) = error("AbstractAffineTransformation $(typeof(trans)) must implement translation()")
26-
translation_reverse(::AbstractAffineTransformation) = matrix(trans) \ translation(trans)
24+
transformation_matrix(trans::AbstractAffineTransformation) = error("AbstractAffineTransformation $(typeof(trans)) must implement transformation_matrix()")
25+
translation_vector(trans::AbstractAffineTransformation) = error("AbstractAffineTransformation $(typeof(trans)) must implement translation_vector()")
26+
translation_vector_reverse(::AbstractAffineTransformation) = transformation_matrix(trans) \ translation_vector(trans)
2727

2828
# Default implementations
2929
@compat function (trans::AbstractAffineTransformation)(x)
30-
matrix(trans) * x + translation(trans)
30+
transformation_matrix(trans) * x + translation_vector(trans)
3131
end
3232

3333
# Could try do similar for transform_deriv_params()?
3434

35-
transform_deriv(trans::AbstractAffineTransformation, x) = matrix(trans)
35+
transform_deriv(trans::AbstractAffineTransformation, x) = transformation_matrix(trans)
3636

3737
function Base.inv(trans::AbstractAffineTransformation)
38-
Minv = inv(matrix(trans))
39-
AffineTransformation(Minv, -Minv * translation(trans))
40-
end
41-
42-
function compose(t1::AbstractAffineTransformation, t2::AbstractAffineTransformation)
43-
AffineTransformation(matrix(t1) * matrix(t2), translation(t1) + matrix(t1) * translation(t2))
38+
Minv = inv(transformation_matrix(trans))
39+
AffineTransformation(Minv, -Minv * translation_vector(trans))
4440
end
4541

4642
function Base.isapprox(t1::AbstractAffineTransformation, t2::AbstractAffineTransformation, kwargs...)
47-
isapprox(matrix(t1), matrix(t2); kwargs...) &&
48-
isapprox(translation(t1), translation(t2); kwargs...)
43+
isapprox(transformation_matrix(t1), transformation_matrix(t2); kwargs...) &&
44+
isapprox(translation_vector(t1), translation_vector(t2); kwargs...)
4945
end
5046

5147
"""
@@ -54,11 +50,11 @@ end
5450
Provides an interface for implementing linear transformations of Cartesian
5551
coordinates. To implement an AbstractLinearTransformation, you must define
5652
57-
matrix(trans)
53+
transformation_matrix(trans)
5854
5955
where the resulting transformation is (equivalent to)
6056
61-
trans(x) -> matrix(trans) * x
57+
trans(x) -> transformation_matrix(trans) * x
6258
6359
Specific implementations may provide equivalent specializations of `call`, etc,
6460
for optimization purposes.
@@ -67,59 +63,127 @@ for optimization purposes.
6763
"""
6864
abstract AbstractLinearTransformation <: AbstractAffineTransformation
6965

70-
matrix(trans::AbstractLinearTransformation) = error("AbstractLinearTransformation $(typeof(trans)) must implement matrix()")
71-
function translation(trans::AbstractLinearTransformation)
72-
m = matrix(trans)
66+
transformation_matrix(trans::AbstractLinearTransformation) = error("AbstractLinearTransformation $(typeof(trans)) must implement transformation_matrix()")
67+
function translation_vector(trans::AbstractLinearTransformation)
68+
m = transformation_matrix(trans)
7369
s = size(m, 1)
7470
T = eltype(m)
7571
return zeros(T, s)
7672
end
77-
function translation_reverse(trans::AbstractLinearTransformation)
78-
m = matrix(trans)
73+
function translation_vector_reverse(trans::AbstractLinearTransformation)
74+
m = transformation_matrix(trans)
7975
s = size(m, 2)
8076
T = eltype(m)
8177
return zeros(T, s)
8278
end
8379

8480
# Default implementations
8581
@compat function (trans::AbstractLinearTransformation)(x)
86-
matrix(trans) * x
82+
transformation_matrix(trans) * x
8783
end
8884

8985
# transform_deriv() identical to that provided by AbstractAffineTransformation
9086

91-
Base.inv(trans::AbstractLinearTransformation) = LinearTransformation(inv(matrix(trans)))
87+
function Base.isapprox(t1::AbstractLinearTransformation, t2::AbstractLinearTransformation, kwargs...)
88+
isapprox(transformation_matrix(t1), transformation_matrix(t2); kwargs...)
89+
end
9290

93-
compose(t1::AbstractLinearTransformation, t2::AbstractLinearTransformation) = LinearTransformation(matrix(t1) * matrix(t2))
91+
# These functions are remove any reference to unnecessary calls to
92+
# translation_vector(::LinearTransformation) from the AbstractAffineTransformations
93+
# interface:
9494

95-
function Base.isapprox(t1::AbstractLinearTransformation, t2::AbstractLinearTransformation, kwargs...)
96-
isapprox(matrix(t1), matrix(t2); kwargs...)
95+
function Base.isapprox(t1::AbstractAffineTransformation, t2::AbstractLinearTransformation, kwargs...)
96+
isapprox(transformation_matrix(t1), transformation_matrix(t2); kwargs...) &&
97+
isapprox(norm(translation_vector(t1)), 0; kwargs...)
98+
end
99+
100+
function Base.isapprox(t1::AbstractLinearTransformation, t2::AbstractAffineTransformation, kwargs...)
101+
isapprox(transformation_matrix(t1), transformation_matrix(t2); kwargs...) &&
102+
isapprox(norm(translation_vector(t2)), 0; kwargs...)
97103
end
98104

105+
#=
106+
"""
107+
abstract AbstractRotation <: AbstractLinearTransformation
99108
109+
Provides an interface for implementing rotations of Cartesian coordinates. To
110+
implement an AbstractRotation, you must define
100111
101-
# These functions are remove any reference to unnecessary calls to
102-
# translation(::LinearTransformation) from the AbstractAffineTransformations
103-
# interface:
112+
transformation_matrix(trans)
104113
105-
function compose(t1::AbstractAffineTransformation, t2::AbstractLinearTransformation)
106-
AffineTransformation(matrix(t1) * matrix(t2), translation(t1))
114+
where the resulting transformation is (equivalent to)
115+
116+
trans(x) -> transformation_matrix(trans) * x
117+
118+
Specific implementations may provide equivalent specializations of `call`, etc,
119+
for optimization purposes. The major difference with AbstractLinearTransformation
120+
is that the matrix is assumed to be orthogonal/unitary for the purpose of
121+
inverting the transformation.
122+
123+
(See also Rotation, AxisRotation, AbstractLinearTransformation)
124+
"""
125+
abstract AbstractRotation <: AbstractLinearTransformation
126+
127+
transformation_matrix(trans::AbstractRotation) = error("AbstractRotation $(typeof(trans)) must implement transformation_matrix()")
128+
=#
129+
130+
131+
"""
132+
abstract AbstractTranslation <: AbstractAffineTransformation
133+
134+
A transformation that encapsulates the translation of Cartesian points.
135+
Implementations must define:
136+
137+
translation_vector(trans)
138+
139+
where the translation goes as
140+
141+
trans(x) -> x + translation_vector(trans)
142+
143+
(See also Translation, AbstractAffineTransformation, AffineTransformation)
144+
"""
145+
abstract AbstractTranslation <: AbstractAffineTransformation
146+
147+
@inline transformation_matrix(::AbstractTranslation) = I
148+
149+
@compat function (trans::AbstractTranslation)(x)
150+
x + translation_vector(trans)
107151
end
108152

109-
function compose(t1::AbstractLinearTransformation, t2::AbstractAffineTransformation)
110-
AffineTransformation(matrix(t1) * matrix(t2), matrix(t1) * translation(t2))
153+
154+
###################
155+
### Translation ###
156+
###################
157+
"""
158+
Translation(dv) <: AbstractAffineTransformation
159+
Translation(dx, dy) (2D)
160+
Translation(dx, dy, dz) (3D)
161+
162+
Construct the `Translation` transformation for translating Cartesian points.
163+
"""
164+
immutable Translation{T} <: AbstractTranslation
165+
dx::T
111166
end
167+
Translation(x::Tuple) = Translation(Vec(x))
168+
Translation(x,y) = Translation(Vec(x,y))
169+
Translation(x,y,z) = Translation(Vec(x,y,z))
170+
Base.show(io::IO, trans::Translation) = print(io, "Translation$((trans.dx...))")
112171

113-
function Base.isapprox(t1::AbstractAffineTransformation, t2::AbstractLinearTransformation, kwargs...)
114-
isapprox(matrix(t1), matrix(t2); kwargs...) &&
115-
isapprox(norm(translation(t1)), 0; kwargs...)
172+
translation_vector(trans::Translation) = trans.dx
173+
174+
# Generic definitions that capture all `Translation`s.
175+
Base.inv(trans::AbstractTranslation) = Translation(-translation_vector(trans))
176+
177+
function compose(trans1::AbstractTranslation, trans2::AbstractTranslation)
178+
Translation(translation_vector(trans1) + translation_vector(trans2))
116179
end
117180

118-
function Base.isapprox(t1::AbstractLinearTransformation, t2::AbstractAffineTransformation, kwargs...)
119-
isapprox(matrix(t1), matrix(t2); kwargs...) &&
120-
isapprox(norm(translation(t2)), 0; kwargs...)
181+
function transform_deriv_params(trans::Translation, x)
182+
I
121183
end
122184

185+
186+
123187
"""
124188
LinearTransformation <: AbstractLinearTransformation
125189
@@ -131,11 +195,17 @@ immutable LinearTransformation{MatrixT} <: AbstractLinearTransformation
131195
M::MatrixT
132196
end
133197

134-
LinearTransformation(trans::AbstractLinearTransformation) = LinearTransformation(matrix(trans))
198+
LinearTransformation(trans::AbstractLinearTransformation) = LinearTransformation(transformation_matrix(trans))
135199

136200
Base.show(io::IO, trans::LinearTransformation) = print(io, "LinearTransformation($(trans.M))") # TODO make this output more petite
137201

138-
@inline matrix(trans::LinearTransformation) = trans.M
202+
@inline transformation_matrix(trans::LinearTransformation) = trans.M
203+
204+
# Generic definitions
205+
206+
Base.inv(trans::AbstractLinearTransformation) = LinearTransformation(inv(transformation_matrix(trans)))
207+
208+
compose(t1::AbstractLinearTransformation, t2::AbstractLinearTransformation) = LinearTransformation(transformation_matrix(t1) * transformation_matrix(t2))
139209

140210

141211
"""
@@ -157,11 +227,11 @@ immutable AffineTransformation{MatrixT, VectorT} <: AbstractAffineTransformation
157227
v::VectorT
158228
end
159229

160-
matrix(trans::AffineTransformation) = trans.M
161-
translation(trans::AffineTransformation) = trans.v
230+
transformation_matrix(trans::AffineTransformation) = trans.M
231+
translation_vector(trans::AffineTransformation) = trans.v
162232

163233
function AffineTransformation(trans::AbstractAffineTransformation)
164-
AffineTransformation(matrix(trans), translation(trans))
234+
AffineTransformation(transformation_matrix(trans), translation_vector(trans))
165235
end
166236

167237
# We can create an Affine transformation corresponding to the differential
@@ -179,46 +249,35 @@ end
179249

180250
Base.show(io::IO, trans::AffineTransformation) = print(io, "AffineTransformation($(trans.M), $(trans.v))") # TODO make this output more petite
181251

182-
183-
184-
###################
185-
### Translation ###
186-
###################
187-
"""
188-
Translation(dv) <: AbstractAffineTransformation
189-
Translation(dx, dy) (2D)
190-
Translation(dx, dy, dz) (3D)
191-
192-
Construct the `Translation` transformation for translating Cartesian points.
193-
"""
194-
immutable Translation{T} <: AbstractAffineTransformation
195-
dx::T
252+
function compose(t1::AbstractTranslation, t2::AbstractLinearTransformation)
253+
AffineTransformation(transformation_matrix(t2), translation_vector(t1))
196254
end
197-
Translation(x::Tuple) = Translation(Vec(x))
198-
Translation(x,y) = Translation(Vec(x,y))
199-
Translation(x,y,z) = Translation(Vec(x,y,z))
200-
Base.show(io::IO, trans::Translation) = print(io, "Translation$((trans.dx...))")
201255

202-
@inline matrix(::Translation) = I
203-
@inline translation(trans::Translation) = trans.dx
204-
@inline translation(trans::Translation) = trans.dx
256+
function compose(t1::AbstractLinearTransformation, t2::AbstractTranslation)
257+
AffineTransformation(transformation_matrix(t1), transformation_matrix(t1) * translation_vector(t2))
258+
end
205259

206-
@compat function (trans::Translation)(x)
207-
x + trans.dx
260+
function compose(t1::AbstractAffineTransformation, t2::AbstractAffineTransformation)
261+
AffineTransformation(transformation_matrix(t1) * transformation_matrix(t2), translation_vector(t1) + transformation_matrix(t1) * translation_vector(t2))
208262
end
209263

210-
@compat (trans::Translation)(x::Tuple) = Tuple(Vec(x) + trans.dx)
264+
function compose(t1::AbstractAffineTransformation, t2::AbstractLinearTransformation)
265+
AffineTransformation(transformation_matrix(t1) * transformation_matrix(t2), translation_vector(t1))
266+
end
211267

212-
Base.inv(trans::Translation) = Translation(-trans.dx)
268+
function compose(t1::AbstractLinearTransformation, t2::AbstractAffineTransformation)
269+
AffineTransformation(transformation_matrix(t1) * transformation_matrix(t2), transformation_matrix(t1) * translation_vector(t2))
270+
end
213271

214-
function compose(trans1::Translation, trans2::Translation)
215-
Translation(trans1.dx + trans2.dx)
272+
function compose(t1::AbstractAffineTransformation, t2::AbstractTranslation)
273+
AffineTransformation(transformation_matrix(t1), translation_vector(t1) + transformation_matrix(t1) * translation_vector(t2))
216274
end
217275

218-
function transform_deriv_params(trans::Translation, x)
219-
I
276+
function compose(t1::AbstractTranslation, t2::AbstractAffineTransformation)
277+
AffineTransformation(transformation_matrix(t2), translation_vector(t1) + translation_vector(t2))
220278
end
221279

280+
222281
####################
223282
### 2D Rotations ###
224283
####################
@@ -268,12 +327,12 @@ end
268327
Polar(x.r, x.θ + trans.angle)
269328
end
270329

271-
function matrix(trans::Rotation2D)
330+
function transformation_matrix(trans::Rotation2D)
272331
@fsa [ trans.cos -trans.sin;
273332
trans.sin trans.cos ]
274333
end
275334

276-
function matrix(trans::Rotation2D)
335+
function transformation_matrix(trans::Rotation2D)
277336
@fsa [ trans.cos -trans.sin;
278337
trans.sin trans.cos ]
279338
end
@@ -284,7 +343,7 @@ function transform_deriv{T}(trans::Rotation2D, x::Polar{T})
284343
end
285344

286345
function transform_deriv_params(trans::Rotation2D, x)
287-
# 2x1 transformation matrix
346+
# 2x1 transformation transformation_matrix
288347
Mat(-trans.sin*x[1] - trans.cos*x[2],
289348
trans.cos*x[1] - trans.sin*x[2] )
290349
end
@@ -362,7 +421,7 @@ end
362421

363422
@compat (trans::Rotation)(x::Tuple) = Tuple(trans(Vec(x)))
364423

365-
matrix(trans::Rotation) = trans.matrix
424+
transformation_matrix(trans::Rotation) = trans.matrix
366425
@inline matrix(trans::Rotation2D) = trans.matrix
367426

368427

@@ -565,7 +624,7 @@ function transform_deriv(trans::RotationXY, x)
565624
trans.sin trans.cos Z;
566625
Z Z I]
567626
end
568-
function matrix(trans::RotationXY)
627+
function transformation_matrix(trans::RotationXY)
569628
Z = zero(trans.cos)
570629
I = one(trans.cos)
571630
@fsa [ trans.cos -trans.sin Z;
@@ -580,7 +639,7 @@ function transform_deriv(trans::RotationYZ, x)
580639
Z trans.cos -trans.sin;
581640
Z trans.sin trans.cos ]
582641
end
583-
function matrix(trans::RotationYZ)
642+
function transformation_matrix(trans::RotationYZ)
584643
Z = zero(trans.cos)
585644
I = one(trans.cos)
586645
@fsa [ I Z Z;
@@ -595,7 +654,7 @@ function transform_deriv(trans::RotationZX, x)
595654
Z I Z ;
596655
-trans.sin Z trans.cos ]
597656
end
598-
function matrix(trans::RotationZX)
657+
function transformation_matrix(trans::RotationZX)
599658
Z = zero(trans.cos)
600659
I = one(trans.cos)
601660
@fsa [ trans.cos Z trans.sin;

0 commit comments

Comments
 (0)