|
| 1 | +abstract AbstractAffineTransformation <: Transformation |
| 2 | + |
| 3 | +""" |
| 4 | + Translation(v) <: AbstractAffineTransformation |
| 5 | + Translation(dx, dy) (2D) |
| 6 | + Translation(dx, dy, dz) (3D) |
| 7 | +
|
| 8 | +Construct the `Translation` transformation for translating Cartesian points by |
| 9 | +an offset `v = (dx, dy, ...)` |
| 10 | +""" |
| 11 | +immutable Translation{V <: AbstractVector} <: AbstractAffineTransformation |
| 12 | + v::V |
| 13 | +end |
| 14 | +Translation(x::Tuple) = Translation(SVector(x)) |
| 15 | +Translation(x,y) = Translation(SVector(x,y)) |
| 16 | +Translation(x,y,z) = Translation(SVector(x,y,z)) |
| 17 | +Base.show(io::IO, trans::Translation) = print(io, "Translation$((trans.dx...))") |
| 18 | + |
| 19 | +function (trans::Translation{V}){V}(x) |
| 20 | + x + trans.v |
| 21 | +end |
| 22 | + |
| 23 | +Base.inv(trans::Translation) = Translation(-trans.v) |
| 24 | + |
| 25 | +function compose(trans1::Translation, trans2::Translation) |
| 26 | + Translation(trans1.v + trans2.v) |
| 27 | +end |
| 28 | + |
| 29 | +transform_deriv(trans::Translation, x) = I |
| 30 | +transform_deriv_params(trans::Translation, x) = I |
| 31 | + |
| 32 | +function Base.isapprox(t1::Translation, t2::Translation; kwargs...) |
| 33 | + isapprox(t1.v, t2.v; kwargs...) |
| 34 | +end |
| 35 | + |
| 36 | + |
| 37 | +""" |
| 38 | + LinearTransformation <: AbstractAffineTransformation |
| 39 | + LinearTransformation(M) |
| 40 | +
|
| 41 | +A general linear transformation, constructed using `LinearTransformation(M)` |
| 42 | +for any `AbstractMatrix` `M`. |
| 43 | +""" |
| 44 | +immutable LinearTransformation{M <: AbstractMatrix} <: AbstractAffineTransformation |
| 45 | + m::M |
| 46 | +end |
| 47 | +Base.show(io::IO, trans::LinearTransformation) = print(io, "LinearTransformation($(trans.M))") # TODO make this output more petite |
| 48 | + |
| 49 | +function (trans::LinearTransformation{M}){M}(x) |
| 50 | + trans.m * x |
| 51 | +end |
| 52 | + |
| 53 | +Base.inv(trans::LinearTransformation) = LinearTransformation(inv(trans.m)) |
| 54 | + |
| 55 | +compose(t1::LinearTransformation, t2::LinearTransformation) = LinearTransformation(t1.m * t2.m) |
| 56 | + |
| 57 | +function Base.isapprox(t1::LinearTransformation, t2::LinearTransformation; kwargs...) |
| 58 | + isapprox(t1.m, t2.m; kwargs...) |
| 59 | +end |
| 60 | + |
| 61 | +function Base.isapprox(t1::LinearTransformation, t2::Translation; kwargs...) |
| 62 | + isapprox(vecnorm(t1.m), 0; kwargs...) && |
| 63 | + isapprox(vecnorm(t2.v),0; kwargs...) |
| 64 | +end |
| 65 | + |
| 66 | +function Base.isapprox(t1::Translation, t2::LinearTransformation; kwargs...) |
| 67 | + isapprox(vecnorm(t1.v), 0; kwargs...) && |
| 68 | + isapprox(vecnorm(t2.m),0; kwargs...) |
| 69 | +end |
| 70 | + |
| 71 | +function Base.:(==)(t1::LinearTransformation, t2::Translation) |
| 72 | + vecnorm(t1.m) == 0 && |
| 73 | + 0 == vecnorm(t2.v) |
| 74 | +end |
| 75 | + |
| 76 | +function Base.:(==)(t1::Translation, t2::LinearTransformation) |
| 77 | + vecnorm(t1.v) == 0 && |
| 78 | + vecnorm(t2.m) == 0 |
| 79 | +end |
| 80 | + |
| 81 | +transform_deriv(trans::LinearTransformation, x) = trans.m |
| 82 | +# TODO transform_deriv_params |
| 83 | + |
| 84 | +""" |
| 85 | + AffineTransformation <: AbstractAffineTransformation |
| 86 | +
|
| 87 | +A concrete affine transformation. To construct the mapping `x -> M*x + v`, use |
| 88 | +
|
| 89 | + AffineTransformation(M, v) |
| 90 | +
|
| 91 | +where `M` is a matrix and `v` a vector. An arbitrary `Transformation` may be |
| 92 | +converted into an affine approximation by linearizing about a point `x` using |
| 93 | +
|
| 94 | + AffineTransformation(trans, [x]) |
| 95 | +
|
| 96 | +For transformations which are already affine, `x` may be omitted. |
| 97 | +""" |
| 98 | +immutable AffineTransformation{M <: AbstractMatrix, V <: AbstractVector} <: AbstractAffineTransformation |
| 99 | + m::M |
| 100 | + v::V |
| 101 | +end |
| 102 | + |
| 103 | +function (trans::AffineTransformation{M,V}){M,V}(x) |
| 104 | + trans.m * x + trans.v |
| 105 | +end |
| 106 | + |
| 107 | +# Note: the expression `Tx - dT*Tx` will have large cancellation error for |
| 108 | +# large Tx! However, changing the order of applying the matrix and |
| 109 | +# translation won't fix things, because then we'd have `Tx*(x-x0)` which |
| 110 | +# also can incur large cancellation error in `x-x0`. |
| 111 | +""" |
| 112 | + AffineTransformation(trans::Transformation, x0) |
| 113 | +
|
| 114 | +Create an Affine transformation corresponding to the differential transformation |
| 115 | +of `x0 + dx` according to `trans`, i.e. the Affine transformation that is |
| 116 | +locally most accurate in the vicinity of `x0`. |
| 117 | +""" |
| 118 | +function AffineTransformation(trans::Transformation, x0) |
| 119 | + dT = transform_deriv(trans, x0) |
| 120 | + Tx = trans(x0) |
| 121 | + AffineTransformation(dT, Tx - dT*x0) |
| 122 | +end |
| 123 | + |
| 124 | +Base.show(io::IO, trans::AffineTransformation) = print(io, "AffineTransformation($(trans.M), $(trans.v))") # TODO make this output more petite |
| 125 | + |
| 126 | +function compose(t1::Translation, t2::LinearTransformation) |
| 127 | + AffineTransformation(t2.m, t1.v) |
| 128 | +end |
| 129 | + |
| 130 | +function compose(t1::LinearTransformation, t2::Translation) |
| 131 | + AffineTransformation(t1.m, t1.m * t2.v) |
| 132 | +end |
| 133 | + |
| 134 | +function compose(t1::AffineTransformation, t2::AffineTransformation) |
| 135 | + AffineTransformation(t1.m * t2.m, t1.v + t1.m * t2.v) |
| 136 | +end |
| 137 | + |
| 138 | +function compose(t1::AffineTransformation, t2::LinearTransformation) |
| 139 | + AffineTransformation(t1.m * t2.m, t1.v) |
| 140 | +end |
| 141 | + |
| 142 | +function compose(t1::LinearTransformation, t2::AffineTransformation) |
| 143 | + AffineTransformation(t1.m * t2.m, t1.m * t2.v) |
| 144 | +end |
| 145 | + |
| 146 | +function compose(t1::AffineTransformation, t2::Translation) |
| 147 | + AffineTransformation(t1.m, t1.v + t1.m * t2.v) |
| 148 | +end |
| 149 | + |
| 150 | +function compose(t1::Translation, t2::AffineTransformation) |
| 151 | + AffineTransformation(t2.m, t1.v + t2.v) |
| 152 | +end |
| 153 | + |
| 154 | +function Base.inv(trans::AffineTransformation) |
| 155 | + m_inv = inv(trans.m) |
| 156 | + AffineTransformation(m_inv, m_inv * (-trans.v)) |
| 157 | +end |
| 158 | + |
| 159 | +function Base.isapprox(t1::AffineTransformation, t2::AffineTransformation; kwargs...) |
| 160 | + isapprox(t1.m, t2.m; kwargs...) && |
| 161 | + isapprox(t1.v, t2.v; kwargs...) |
| 162 | +end |
| 163 | + |
| 164 | +function Base.isapprox(t1::AffineTransformation, t2::Translation; kwargs...) |
| 165 | + isapprox(vecnorm(t1.m), 0; kwargs...) && |
| 166 | + isapprox(t1.v, t2.v; kwargs...) |
| 167 | +end |
| 168 | + |
| 169 | +function Base.isapprox(t1::Translation, t2::AffineTransformation; kwargs...) |
| 170 | + isapprox(vecnorm(t2.m), 0; kwargs...) && |
| 171 | + isapprox(t1.v, t2.v; kwargs...) |
| 172 | +end |
| 173 | + |
| 174 | +function Base.isapprox(t1::AffineTransformation, t2::LinearTransformation; kwargs...) |
| 175 | + isapprox(t1.m, t2.m; kwargs...) && |
| 176 | + isapprox(vecnorm(t1.v), 0; kwargs...) |
| 177 | +end |
| 178 | + |
| 179 | +function Base.isapprox(t1::LinearTransformation, t2::AffineTransformation; kwargs...) |
| 180 | + isapprox(t1.m, t2.m; kwargs...) && |
| 181 | + isapprox(0, vecnorm(t2.v); kwargs...) |
| 182 | +end |
| 183 | + |
| 184 | + |
| 185 | +function Base.:(==)(t1::AffineTransformation, t2::Translation) |
| 186 | + vecnorm(t1.m) == 0 && |
| 187 | + t1.v == t2.v |
| 188 | +end |
| 189 | + |
| 190 | +function Base.:(==)(t1::Translation, t2::AffineTransformation) |
| 191 | + vecnorm(t2.m) == 0 && |
| 192 | + t1.v == t2.v |
| 193 | +end |
| 194 | + |
| 195 | +function Base.:(==)(t1::AffineTransformation, t2::LinearTransformation) |
| 196 | + t1.m == t2.m && |
| 197 | + vecnorm(t1.v) == 0 |
| 198 | +end |
| 199 | + |
| 200 | +function Base.:(==)(t1::LinearTransformation, t2::AffineTransformation) |
| 201 | + t1.m == t2.m && |
| 202 | + 0 == vecnorm(t2.v) |
| 203 | +end |
| 204 | + |
| 205 | +transform_deriv(trans::AffineTransformation, x) = trans.m |
| 206 | +# TODO transform_deriv_params |
0 commit comments