-
Notifications
You must be signed in to change notification settings - Fork 43
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add RotationGenerator
and its subtypes
#203
Merged
hyrodium
merged 29 commits into
JuliaGeometry:master
from
hyrodium:feature/infinitesimal
Jan 13, 2022
Merged
Changes from 28 commits
Commits
Show all changes
29 commits
Select commit
Hold shift + click to select a range
034e2f6
add infinitesimal rotations
hyrodium 0c52741
update log with InfinitesimalRotation
hyrodium 498cb1c
rename log.jl to logexp.jl, and fix tests
hyrodium b3d2268
update infinitesimal
hyrodium 20a53e0
add tests for infinitesimal rotations
hyrodium bda9f38
update tests for infinitesimal
hyrodium f19e191
update src for infinitesimal
hyrodium 6106e07
fix typo
hyrodium 6e0e149
add tests for error
hyrodium fa141fb
update Base.:-
hyrodium 2c22177
add tests for type promotion
hyrodium c6bd658
update tests
hyrodium 95bcb18
update Base.ones
hyrodium 500a2d9
update tests
hyrodium b3aa8c0
update comments
hyrodium faa2b8a
update export
hyrodium 377294d
fix type parameter in test
hyrodium 173c282
update tests
hyrodium 71de499
add Base.:/(r::InfinitesimalRotation, t::Number)
hyrodium a859beb
update comments
hyrodium c6ce5cb
update 2d infinitesimal rotation
hyrodium af3f7b2
update tests
hyrodium 4faa473
update tests
hyrodium 50e98b3
rename InfinitesimalRotation to RotationGenerator
hyrodium 77b10f1
rename files
hyrodium aaf529d
add test fot exp(::RotMatrixGenerator)::RotMatrix
hyrodium c133d83
fix for exp(::RotMatrixGenerator)::RotMatrix
hyrodium 89d6a39
update tests to remove rand method
hyrodium b55c9ee
remove unnecessary Base.promote_op method
hyrodium File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,49 @@ | ||
## log | ||
# 3d | ||
function Base.log(R::RotationVec) | ||
x, y, z = params(R) | ||
return RotationVecGenerator(x,y,z) | ||
end | ||
|
||
function Base.log(R::Rotation{3}) | ||
log(RotationVec(R)) | ||
end | ||
|
||
|
||
# 2d | ||
function Base.log(R::Angle2d) | ||
θ, = params(R) | ||
return Angle2dGenerator(θ) | ||
end | ||
|
||
function Base.log(R::Rotation{2}) | ||
log(Angle2d(R)) | ||
end | ||
|
||
|
||
## exp | ||
# 3d | ||
function Base.exp(R::RotationVecGenerator) | ||
return RotationVec(R.x,R.y,R.z) | ||
end | ||
|
||
function Base.exp(R::RotationGenerator{3}) | ||
exp(RotationVecGenerator(R)) | ||
end | ||
|
||
function Base.exp(R::RotMatrixGenerator{3}) | ||
RotMatrix(exp(RotationVecGenerator(R))) | ||
end | ||
|
||
# 2d | ||
function Base.exp(R::Angle2dGenerator) | ||
return Angle2d(R.v) | ||
end | ||
|
||
function Base.exp(R::RotationGenerator{2}) | ||
exp(Angle2dGenerator(R)) | ||
end | ||
|
||
function Base.exp(R::RotMatrixGenerator{2}) | ||
RotMatrix(exp(Angle2dGenerator(R))) | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,258 @@ | ||
""" | ||
abstract type RotationGenerator{N,T} <: StaticMatrix{N,N,T} | ||
|
||
An abstract type representing `N`-dimensional rotation generator. More abstractly, they represent | ||
skew-symmetric real `N`×`N` matrices. | ||
""" | ||
abstract type RotationGenerator{N,T} <: StaticMatrix{N,N,T} end | ||
|
||
Base.@pure StaticArrays.Size(::Type{RotationGenerator{N}}) where {N} = Size(N,N) | ||
Base.@pure StaticArrays.Size(::Type{RotationGenerator{N,T}}) where {N,T} = Size(N,N) | ||
Base.@pure StaticArrays.Size(::Type{R}) where {R<:RotationGenerator} = Size(supertype(R)) | ||
Base.adjoint(r::RotationGenerator) = -r | ||
Base.transpose(r::RotationGenerator{N,T}) where {N,T<:Real} = -r | ||
|
||
# Generate identity-matrix with SMatrix | ||
# Note that ones(RotationGenerator3,dims...) is not Array{<:RotationGenerator} but Array{<:StaticMatrix{3,3}} | ||
Base.one(::RotationGenerator{N,T}) where {N,T} = one(SMatrix{N,N,T}) | ||
Base.one(::Type{RotationGenerator}) = error("The dimension of rotation is not specified.") | ||
Base.one(::Type{<:RotationGenerator{N}}) where N = one(SMatrix{N,N}) | ||
Base.one(::Type{<:RotationGenerator{N,T}}) where {N,T} = one(SMatrix{N,N,T}) | ||
Base.ones(::Type{R}) where {R<:RotationGenerator} = ones(R, ()) # avoid StaticArray constructor | ||
Base.ones(::Type{R}, dims::Base.DimOrInd...) where {R<:RotationGenerator} = ones(typeof(one(R)),dims...) | ||
Base.ones(::Type{R}, dims::NTuple{N, Integer}) where {R<:RotationGenerator, N} = ones(typeof(one(R)),dims) | ||
|
||
# Generate zero rotation matrix | ||
Base.zero(r::RotationGenerator) = zero(typeof(r)) | ||
|
||
# difference | ||
Base.:-(r1::RotationGenerator, r2::RotationGenerator) = r1 + (-r2) | ||
|
||
# `convert` goes through the constructors, similar to e.g. `Number` | ||
Base.convert(::Type{R}, rot::RotationGenerator{N}) where {N,R<:RotationGenerator{N}} = R(rot) | ||
|
||
# RotationGenerator matrices should be skew-symmetric. Only the operations we define, | ||
# like addition, will stay as RotationGenerators, otherwise users will get an | ||
# SMatrix{3,3} (e.g. rot1 * rot2 -> SMatrix) | ||
Base.@pure StaticArrays.similar_type(::Union{R,Type{R}}) where {R <: RotationGenerator} = SMatrix{size(R)..., eltype(R), prod(size(R))} | ||
Base.@pure StaticArrays.similar_type(::Union{R,Type{R}}, ::Type{T}) where {R <: RotationGenerator, T} = SMatrix{size(R)..., T, prod(size(R))} | ||
|
||
# Useful for converting arrays of rotations to another rotation eltype, for instance. | ||
# Only works because parameters of all the rotations are of a similar form | ||
# Would need to be more sophisticated if we have arbitrary dimensions, etc | ||
@inline function Base.promote_op(::Type{R1}, ::Type{R2}) where {R1 <: RotationGenerator, R2 <: RotationGenerator} | ||
size(R1) == size(R2) || throw(DimensionMismatch("cannot promote rotations of $(size(R1)[1]) and $(size(R2)[1]) dimensions")) | ||
if isleaftype(R1) | ||
return R1 | ||
else | ||
return R1{eltype(R2)} | ||
end | ||
end | ||
|
||
################################################################################ | ||
################################################################################ | ||
""" | ||
struct RotMatrixGenerator{N,T} <: RotationGenerator{N,T} | ||
|
||
A statically-sized, N×N skew-symmetric matrix. | ||
|
||
Note: the skew-symmetricity of the input matrix is *not* checked by the constructor. | ||
""" | ||
struct RotMatrixGenerator{N,T,L} <: RotationGenerator{N,T} # which is <: AbstractMatrix{T} | ||
mat::SMatrix{N, N, T, L} # The final parameter to SMatrix is the "length" of the matrix, 3 × 3 = 9 | ||
RotMatrixGenerator{N,T,L}(x::AbstractArray) where {N,T,L} = new{N,T,L}(convert(SMatrix{N,N,T,L}, x)) | ||
# fixes #49 ambiguity introduced in StaticArrays 0.6.5 | ||
RotMatrixGenerator{N,T,L}(x::StaticArray) where {N,T,L} = new{N,T,L}(convert(SMatrix{N,N,T,L}, x)) | ||
end | ||
RotMatrixGenerator(x::SMatrix{N,N,T,L}) where {N,T,L} = RotMatrixGenerator{N,T,L}(x) | ||
|
||
Base.zero(::Type{RotMatrixGenerator}) = error("The dimension of rotation is not specified.") | ||
|
||
# These functions (plus size) are enough to satisfy the entire StaticArrays interface: | ||
for N = 2:3 | ||
L = N*N | ||
RotMatrixGeneratorN = Symbol(:RotMatrixGenerator, N) | ||
@eval begin | ||
@inline RotMatrixGenerator(t::NTuple{$L}) = RotMatrixGenerator(SMatrix{$N,$N}(t)) | ||
@inline (::Type{RotMatrixGenerator{$N}})(t::NTuple{$L}) = RotMatrixGenerator(SMatrix{$N,$N}(t)) | ||
@inline RotMatrixGenerator{$N,T}(t::NTuple{$L}) where {T} = RotMatrixGenerator(SMatrix{$N,$N,T}(t)) | ||
@inline RotMatrixGenerator{$N,T,$L}(t::NTuple{$L}) where {T} = RotMatrixGenerator(SMatrix{$N,$N,T}(t)) | ||
const $RotMatrixGeneratorN{T} = RotMatrixGenerator{$N, T, $L} | ||
end | ||
end | ||
Base.@propagate_inbounds Base.getindex(r::RotMatrixGenerator, i::Int) = r.mat[i] | ||
@inline Base.Tuple(r::RotMatrixGenerator) = Tuple(r.mat) | ||
|
||
@inline RotMatrixGenerator(v::Number) = RotMatrixGenerator{2}(v) | ||
@inline function (::Type{RotMatrixGenerator{2}})(v::Number) | ||
RotMatrixGenerator(@SMatrix [zero(v) -v; v zero(v)]) | ||
end | ||
@inline function RotMatrixGenerator{2,T}(v::Number) where T | ||
RotMatrixGenerator(@SMatrix T[zero(v) -v; v zero(v)]) | ||
end | ||
|
||
# A rotation is more-or-less defined as being an orthogonal (or unitary) matrix | ||
Base.:-(r::RotMatrixGenerator) = RotMatrixGenerator(-r.mat) | ||
|
||
# By default, composition of rotations will go through RotMatrixGenerator, unless overridden | ||
@inline Base.:+(r1::RotationGenerator, r2::RotationGenerator) = RotMatrixGenerator(r1) + RotMatrixGenerator(r2) | ||
@inline Base.:+(r1::RotMatrixGenerator, r2::RotationGenerator) = r1 + RotMatrixGenerator(r2) | ||
@inline Base.:+(r1::RotationGenerator, r2::RotMatrixGenerator) = RotMatrixGenerator(r1) + r2 | ||
@inline Base.:+(r1::RotMatrixGenerator, r2::RotMatrixGenerator) = RotMatrixGenerator(r1.mat + r2.mat) | ||
|
||
@inline Base.:*(t::Number, r::RotMatrixGenerator) = RotMatrixGenerator(t*r.mat) | ||
@inline Base.:*(r::RotMatrixGenerator, t::Number) = t*r | ||
@inline Base.:/(r::RotMatrixGenerator, t::Number) = RotMatrixGenerator(r.mat/t) | ||
|
||
# Special case multiplication of 2×2 rotation matrices: speedup using skew-symmetricity | ||
@inline function Base.:+(r1::RotMatrixGenerator{2}, r2::RotMatrixGenerator{2}) | ||
v = r1[2,1]+r2[2,1] | ||
s = @SMatrix [0 -v | ||
v 0] | ||
return RotMatrixGenerator(s) | ||
end | ||
|
||
# Special case multiplication of 3×3 rotation matrices: speedup using skew-symmetricity | ||
@inline function Base.:+(r1::RotMatrixGenerator{3}, r2::RotMatrixGenerator{3}) | ||
x = r1[6]+r2[6] | ||
y = r1[7]+r2[7] | ||
z = r1[2]+r2[2] | ||
s = @SMatrix [ 0 -z y | ||
z 0 -x | ||
-y x 0] | ||
|
||
return RotMatrixGenerator(s) | ||
end | ||
|
||
""" | ||
struct Angle2dGenerator{T} <: RotationGenerator{2,T} | ||
v::T | ||
end | ||
|
||
A 2×2 rotation generator matrix (i.e. skew-symmetric matrix). | ||
[ 0 -v | ||
v 0 ] | ||
""" | ||
struct Angle2dGenerator{T} <: RotationGenerator{2,T} | ||
v::T | ||
Angle2dGenerator{T}(r) where T = new{T}(r) | ||
end | ||
|
||
@inline function Angle2dGenerator(r::T) where T <: Number | ||
Angle2dGenerator{T}(r) | ||
end | ||
|
||
@inline Angle2dGenerator(r::RotationGenerator{2}) = Angle2dGenerator(r[2,1]) | ||
@inline Angle2dGenerator{T}(r::RotationGenerator{2}) where {T} = Angle2dGenerator{T}(r[2,1]) | ||
|
||
@inline Base.zero(::Type{A}) where {A<: Angle2dGenerator} = A(0.0) | ||
|
||
@inline Base.:+(r1::Angle2dGenerator, r2::Angle2dGenerator) = Angle2dGenerator(r1.v + r2.v) | ||
@inline Base.:-(r1::Angle2dGenerator, r2::Angle2dGenerator) = Angle2dGenerator(r1.v - r2.v) | ||
@inline Base.:*(t::Number, r::Angle2dGenerator) = Angle2dGenerator(t*r.v) | ||
@inline Base.:*(r::Angle2dGenerator, t::Number) = t*r | ||
@inline Base.:/(r::Angle2dGenerator, t::Number) = Angle2dGenerator(r.v/t) | ||
@inline Base.:-(r::Angle2dGenerator) = Angle2dGenerator(-r.v) | ||
|
||
@inline function Base.getindex(r::Angle2dGenerator{T}, i::Int) where T | ||
if i == 1 | ||
zero(T) | ||
elseif i == 2 | ||
r.v | ||
elseif i == 3 | ||
-r.v | ||
elseif i == 4 | ||
zero(T) | ||
else | ||
throw(BoundsError(r,i)) | ||
end | ||
end | ||
|
||
|
||
""" | ||
struct RotationVecGenerator{T} <: RotationGenerator{2,T} | ||
x::T | ||
y::T | ||
z::T | ||
end | ||
|
||
A 3×3 rotation generator matrix (i.e. skew-symmetric matrix). | ||
[ 0 -z y | ||
z 0 -x | ||
-y x 0] | ||
""" | ||
struct RotationVecGenerator{T} <: RotationGenerator{3,T} | ||
x::T | ||
y::T | ||
z::T | ||
RotationVecGenerator{T}(x,y,z) where T = new{T}(x,y,z) | ||
end | ||
|
||
@inline function RotationVecGenerator(x::X,y::Y,z::Z) where {X<:Number, Y<:Number, Z<:Number} | ||
RotationVecGenerator{promote_type(X,Y,Z)}(x, y, z) | ||
end | ||
|
||
@inline RotationVecGenerator(r::RotationGenerator{3}) = RotationVecGenerator(r[6], r[7], r[2]) | ||
@inline RotationVecGenerator{T}(r::RotationGenerator{3}) where {T} = RotationVecGenerator{T}(r[6], r[7], r[2]) | ||
|
||
@inline Base.zero(::Type{R}) where {R<: RotationVecGenerator} = R(0.0,0.0,0.0) | ||
|
||
@inline Base.:+(r1::RotationVecGenerator, r2::RotationVecGenerator) = RotationVecGenerator(r1.x + r2.x, r1.y + r2.y, r1.z + r2.z) | ||
@inline Base.:-(r1::RotationVecGenerator, r2::RotationVecGenerator) = RotationVecGenerator(r1.x - r2.x, r1.y - r2.y, r1.z - r2.z) | ||
@inline Base.:*(t::Number, r::RotationVecGenerator) = RotationVecGenerator(t*r.x, t*r.y, t*r.z) | ||
@inline Base.:*(r::RotationVecGenerator, t::Number) = t*r | ||
@inline Base.:/(r::RotationVecGenerator, t::Number) = RotationVecGenerator(r.x/t, r.y/t, r.z/t) | ||
@inline Base.:-(r::RotationVecGenerator) = RotationVecGenerator(-r.x, -r.y, -r.z) | ||
|
||
@inline function Base.getindex(r::RotationVecGenerator{T}, i::Int) where T | ||
if i == 1 | ||
zero(T) | ||
elseif i == 2 | ||
r.z | ||
elseif i == 3 | ||
-r.y | ||
elseif i == 4 | ||
-r.z | ||
elseif i == 5 | ||
zero(T) | ||
elseif i == 6 | ||
r.x | ||
elseif i == 7 | ||
r.y | ||
elseif i == 8 | ||
-r.x | ||
elseif i == 9 | ||
zero(T) | ||
else | ||
throw(BoundsError(r,i)) | ||
end | ||
end | ||
|
||
|
||
################################################################################ | ||
################################################################################ | ||
|
||
|
||
# A simplification and specialization of the Base.show function for AbstractArray makes | ||
# everything sensible at the REPL. | ||
function Base.show(io::IO, ::MIME"text/plain", X::RotationGenerator) | ||
if !haskey(io, :compact) | ||
io = IOContext(io, :compact => true) | ||
end | ||
summary(io, X) | ||
if !isa(X, RotMatrixGenerator) | ||
n_fields = length(fieldnames(typeof(X))) | ||
print(io, "(") | ||
for i = 1:n_fields | ||
print(io, getfield(X, i)) | ||
if i < n_fields | ||
print(io, ", ") | ||
end | ||
end | ||
print(io, ")") | ||
end | ||
print(io, ":") | ||
println(io) | ||
io = IOContext(io, :typeinfo => eltype(X)) | ||
Base.print_array(io, X) | ||
end |
This file was deleted.
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this right? The operator is not defined. Did you mean
promote_rule
?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah, I was just referring to
src/core_types.jl
.0ccc876#diff-55fa94d9eb6d180ed431c8aae0ad29c7100a0ad88cbd35dfc81239882a614e8dR39
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've tried renaming
promote_op
->promote_rule
andisleaftype
->isconcretetype
, but it doesn't work well here.These seems unnecessary, so I've dropped both
promote_op
definitions fromsrc/core_types.jl
andsrc/rotation_generator.jl
.