Skip to content

Commit

Permalink
Merge pull request #54 from FugroRoames/tk/julia-master
Browse files Browse the repository at this point in the history
WIP: support for Julia 0.7
  • Loading branch information
andyferris authored Mar 26, 2018
2 parents 8a97a9e + d7763e0 commit a405b90
Show file tree
Hide file tree
Showing 11 changed files with 115 additions and 67 deletions.
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ q2 = rand(Quat)
q3 = q * q2

# Take the inverse (equivalent to transpose)
q_inv = q'
q_inv = transpose(q)
q_inv == inv(q)
p q_inv * (q * p)
q4 = q3 / q2 # q4 = q3 * inv(q2)
Expand Down Expand Up @@ -102,7 +102,7 @@ j2 = Rotations.jacobian(q, p) # How does the rotated point q*p change w.r.t. the

4. **Rodrigues Vector** `RodriguesVec{T}`

A 3D rotation encoded by an angle-axis representation as `angle * axis`.
A 3D rotation encoded by an angle-axis representation as `angle * axis`.
This type is used in packages such as [OpenCV](http://docs.opencv.org/2.4/modules/calib3d/doc/camera_calibration_and_3d_reconstruction.html#void%20Rodrigues%28InputArray%20src,%20OutputArray%20dst,%20OutputArray%20jacobian%29).

Note: If you're differentiating a Rodrigues Vector check the result is what
Expand Down
1 change: 1 addition & 0 deletions REQUIRE
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
julia 0.6
StaticArrays 0.6.5
Compat
14 changes: 11 additions & 3 deletions perf/runbenchmarks.jl
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
using Rotations
using BenchmarkTools
import Base.Iterators: product
import Compat.Random: srand

const T = Float64

Expand All @@ -11,16 +12,23 @@ suite["conversions"] = BenchmarkGroup()
rotationtypes = (RotMatrix3{T}, Quat{T}, SPQuat{T}, AngleAxis{T}, RodriguesVec{T})
for (from, to) in product(rotationtypes, rotationtypes)
if from != to
name = "$(string(from)) -> $(string(to))"
name = if VERSION < v"0.7.0-"
"$(string(from)) -> $(string(to))"
else
"Rotations.$(string(from)) -> Rotations.$(string(to))"
end
# use eval here because of https://github.com/JuliaCI/BenchmarkTools.jl/issues/50#issuecomment-318673288
suite["conversions"][name] = eval(:(@benchmarkable convert($to, rot) setup = rot = rand($from)))
end
end

suite["composition"] = BenchmarkGroup()
suite["composition"]["RotMatrix{3} * RotMatrix{3}"] = @benchmarkable r1 * r2 setup = (r1 = rand(RotMatrix3{T}); r2 = rand(RotMatrix3{T}))
suite["composition"]["RotMatrix{3} * RotMatrix{3}"] = @benchmarkable(
r1 * r2,
setup = (r1 = rand(RotMatrix3{T}); r2 = rand(RotMatrix3{T}))
)

paramspath = joinpath(dirname(@__FILE__), "benchmarkparams.json")
paramspath = joinpath(@__DIR__, "benchmarkparams.json")
if isfile(paramspath)
loadparams!(suite, BenchmarkTools.load(paramspath)[1], :evals, :samples);
else
Expand Down
5 changes: 4 additions & 1 deletion src/Rotations.jl
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,12 @@ __precompile__(true)

module Rotations

using Compat
using Compat.LinearAlgebra
using StaticArrays

import Base: convert, eltype, size, length, getindex, inv, *, Tuple, eye
import Base: convert, eltype, size, length, getindex, *, Tuple
import Compat.LinearAlgebra: inv, eye

include("util.jl")
include("core_types.jl")
Expand Down
95 changes: 61 additions & 34 deletions src/core_types.jl
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@ abstract type Rotation{N,T} <: StaticMatrix{N,N,T} end
Base.@pure StaticArrays.Size(::Type{Rotation{N}}) where {N} = Size(N,N)
Base.@pure StaticArrays.Size(::Type{Rotation{N,T}}) where {N,T} = Size(N,N)
Base.@pure StaticArrays.Size(::Type{R}) where {R<:Rotation} = Size(supertype(R))
Base.ctranspose(r::Rotation) = inv(r)
Base.transpose(r::Rotation{N,T}) where {N,T<:Real} = inv(r)
Compat.adjoint(r::Rotation) = inv(r)
Compat.transpose(r::Rotation{N,T}) where {N,T<:Real} = inv(r)

# Rotation angles and axes can be obtained by converting to the AngleAxis type
rotation_angle(r::Rotation) = rotation_angle(AngleAxis(r))
Expand Down Expand Up @@ -102,11 +102,11 @@ Base.@propagate_inbounds Base.getindex(r::RotMatrix, i::Int) = r.mat[i]
@inline (::Type{RotMatrix{2,T}})(θ::Real) where {T} = RotMatrix(@SMatrix T[cos(θ) -sin(θ); sin(θ) cos(θ)])

# A rotation is more-or-less defined as being an orthogonal (or unitary) matrix
Base.inv(r::RotMatrix) = RotMatrix(r.mat')
inv(r::RotMatrix) = RotMatrix(r.mat')

# A useful constructor for identity rotation (eye is already provided by StaticArrays, but needs an eltype)
@inline Base.eye(::Type{RotMatrix{N}}) where {N} = RotMatrix((eye(SMatrix{N,N,Float64})))
@inline Base.eye(::Type{RotMatrix{N,T}}) where {N,T} = RotMatrix((eye(SMatrix{N,N,T})))
@inline eye(::Type{RotMatrix{N}}) where {N} = RotMatrix((eye(SMatrix{N,N,Float64})))
@inline eye(::Type{RotMatrix{N,T}}) where {N,T} = RotMatrix((eye(SMatrix{N,N,T})))

# By default, composition of rotations will go through RotMatrix, unless overridden
@inline *(r1::Rotation, r2::Rotation) = RotMatrix(r1) * RotMatrix(r2)
Expand Down Expand Up @@ -150,32 +150,18 @@ function isrotation(r::AbstractMatrix{T}, tol::Real = 1000 * eps(eltype(T))) whe
return d < tol
end


# A simplification and specialization of the Base.showarray() function makes
# everything sensible at the REPL.
function Base.showarray(io::IO, X::Rotation, repr::Bool = true; header = true)
if !haskey(io, :compact)
io = IOContext(io, compact=true)
end
if repr
if isa(X, RotMatrix)
Base.print_matrix_repr(io, X)
else
print(io, typeof(X).name.name)
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, ")")
@static if VERSION < v"0.7-"
# A simplification and specialization of the Base.showarray() function makes
# everything sensible at the REPL.
function Base.showarray(io::IO, X::Rotation, repr::Bool = true; header = true)
if !haskey(io, :compact)
io = IOContext(io, compact=true)
end
else
if header
print(io, summary(X))
if !isa(X, RotMatrix)
if repr
if isa(X, RotMatrix)
Base.print_matrix_repr(io, X)
else
print(io, typeof(X).name.name)
n_fields = length(fieldnames(typeof(X)))
print(io, "(")
for i = 1:n_fields
Expand All @@ -186,14 +172,55 @@ function Base.showarray(io::IO, X::Rotation, repr::Bool = true; header = true)
end
print(io, ")")
end
println(io, ":")
else
if header
print(io, summary(X))
if !isa(X, RotMatrix)
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
println(io, ":")
end
punct = (" ", " ", "")
Base.print_matrix(io, X, punct...)
end
end
else
# 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::Rotation)
if !haskey(io, :compact)
io = IOContext(io, :compact => true)
end
summary(io, X)
if !isa(X, RotMatrix)
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
punct = (" ", " ", "")
Base.print_matrix(io, X, punct...)
print(io, ":")
println(io)
io = IOContext(io, :typeinfo => eltype(X))
Base.print_array(io, X)
end
end

# Removes module name from output, to match other types
function Base.summary(r::Rotation{N,T}) where {T,N}
"$N×$N $(typeof(r).name.name){$(eltype(r))}"
inds = indices(r)
typestring = last(split(string(typeof(r)), '.'; limit = 2))
string(Base.dims2string(length.(inds)), " ", typestring)
end
4 changes: 2 additions & 2 deletions src/derivatives.jl
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ function jacobian(::Type{RotMatrix}, q::Quat)
# = (dR(s*q)/dQ*s - s*R(q) * ds/dQ) / s^2
# = (dR(s*q)/dQ - R(q) * ds/dQ) / s

jac = dsRdQ - R * dsdQ.'
jac = dsRdQ - R * transpose(dsdQ)

# now reformat for output. TODO: is the the best expression?
# return Vec{4,Mat{3,3,T}}(ith_partial(jac, 1), ith_partial(jac, 2), ith_partial(jac, 3), ith_partial(jac, 4))
Expand Down Expand Up @@ -198,7 +198,7 @@ function jacobian(q::Quat, X::AbstractVector)

# and finalize with the quotient rule
Xo = q * X # N.B. g(x) = s * Xo, with dG/dx = dRdQs
Xom = Xo * dSdQ.'
Xom = Xo * transpose(dSdQ)
return dRdQs - Xom
end

Expand Down
14 changes: 7 additions & 7 deletions src/quaternion_types.jl
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ function (::Type{Q})(t::NTuple{9}) where Q<:Quat
not_orthogonal = randn(3,3)
u,s,v = svd(not_orthogonal)
is_orthogoral = u * diagm([1, 1, sign(det(u * v.'))]) * v.'
is_orthogoral = u * diagm([1, 1, sign(det(u * transpose(v)))]) * transpose(v)
=#

a = 1 + t[1] + t[5] + t[9]
Expand Down Expand Up @@ -188,12 +188,12 @@ function Base.:*(q1::Quat, q2::Quat)
q1.w*q2.z + q1.x*q2.y - q1.y*q2.x + q1.z*q2.w)
end

function Base.inv(q::Quat)
function inv(q::Quat)
Quat(q.w, -q.x, -q.y, -q.z)
end

@inline Base.eye(::Type{Quat}) = Quat(1.0, 0.0, 0.0, 0.0)
@inline Base.eye(::Type{Quat{T}}) where {T} = Quat{T}(one(T), zero(T), zero(T), zero(T))
@inline eye(::Type{Quat}) = Quat(1.0, 0.0, 0.0, 0.0)
@inline eye(::Type{Quat{T}}) where {T} = Quat{T}(one(T), zero(T), zero(T), zero(T))

"""
rotation_between(from, to)
Expand Down Expand Up @@ -274,10 +274,10 @@ end
@inline Base.:*(r::RotMatrix, spq::SPQuat) = r * Quat(spq)
@inline Base.:*(spq1::SPQuat, spq2::SPQuat) = Quat(spq1) * Quat(spq2)

@inline Base.inv(spq::SPQuat) = SPQuat(-spq.x, -spq.y, -spq.z)
@inline inv(spq::SPQuat) = SPQuat(-spq.x, -spq.y, -spq.z)

@inline Base.eye(::Type{SPQuat}) = SPQuat(0.0, 0.0, 0.0)
@inline Base.eye(::Type{SPQuat{T}}) where {T} = SPQuat{T}(zero(T), zero(T), zero(T))
@inline eye(::Type{SPQuat}) = SPQuat(0.0, 0.0, 0.0)
@inline eye(::Type{SPQuat{T}}) where {T} = SPQuat{T}(zero(T), zero(T), zero(T))

# rotation properties
@inline rotation_angle(spq::SPQuat) = rotation_angle(Quat(spq))
Expand Down
4 changes: 2 additions & 2 deletions src/util.jl
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,9 @@ function perpendicular_vector(vec::SVector{3})

# find indices of the two elements of vec with the largest absolute values:
absvec = abs.(vec)
ind1 = indmax(absvec) # index of largest element
ind1 = argmax(absvec) # index of largest element
@inbounds absvec2 = @SVector [ifelse(i == ind1, typemin(T), absvec[i]) for i = 1 : 3] # set largest element to typemin(T)
ind2 = indmax(absvec2) # index of second-largest element
ind2 = argmax(absvec2) # index of second-largest element

# perp[ind1] = -vec[ind2], perp[ind2] = vec[ind1], set remaining element to zero:
@inbounds perpind1 = -vec[ind2]
Expand Down
14 changes: 3 additions & 11 deletions test/2d.jl
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
using Rotations, StaticArrays, Base.Test
using Rotations, StaticArrays, Compat.Test

@testset "2d Rotations" begin

Expand Down Expand Up @@ -38,8 +38,8 @@ using Rotations, StaticArrays, Base.Test
for i = 1:repeats
r = rand(R)
@test isrotation(r)
@test inv(r) == r'
@test inv(r) == r.'
@test inv(r) == adjoint(r)
@test inv(r) == transpose(r)
@test inv(r)*r I
@test r*inv(r) I
end
Expand Down Expand Up @@ -112,14 +112,6 @@ using Rotations, StaticArrays, Base.Test
@test R * R T[0 -1; 1 0]
end
end

@testset "show" begin
io = IOBuffer()
r = rand(RotMatrix{2})
show(io, MIME("text/plain"), r)
str = String(take!(io))
@test startswith(str, "2×2 RotMatrix{Float64}:")
end
end

nothing
19 changes: 16 additions & 3 deletions test/rotation_tests.jl
Original file line number Diff line number Diff line change
Expand Up @@ -108,8 +108,8 @@ all_types = (RotMatrix{3}, Quat, SPQuat, AngleAxis, RodriguesVec,
srand(0)
for i = 1:repeats
r = rand(R)
@test inv(r) == r'
@test inv(r) == r.'
@test inv(r) == adjoint(r)
@test inv(r) == transpose(r)
@test inv(r)*r I
@test r*inv(r) I
end
Expand Down Expand Up @@ -183,7 +183,7 @@ all_types = (RotMatrix{3}, Quat, SPQuat, AngleAxis, RodriguesVec,
#########################################################################
function nearest_orthonormal(not_orthonormal)
u,s,v = svd(not_orthonormal)
return u * diagm([1, 1, sign(det(u * v.'))]) * v.'
return u * Diagonal([1, 1, sign(det(u * transpose(v)))]) * transpose(v)
end

@testset "DCM to Quat" begin
Expand Down Expand Up @@ -302,4 +302,17 @@ all_types = (RotMatrix{3}, Quat, SPQuat, AngleAxis, RodriguesVec,
rot = eye(RotMatrix{3, Float64})
@inferred Tuple(rot)
end

@testset "Testing show" begin
io = IOBuffer()
r = rand(RotMatrix{2})
show(io, MIME("text/plain"), r)
str = String(take!(io))
@test startswith(str, "2×2 RotMatrix{2,Float64,4}:")

rxyz = RotXYZ(1.0, 2.0, 3.0)
show(io, MIME("text/plain"), rxyz)
str = String(take!(io))
@test startswith(str, "3×3 RotXYZ{Float64}(1.0, 2.0, 3.0):")
end
end
8 changes: 6 additions & 2 deletions test/runtests.jl
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
using Base.Test
using Compat
using Compat.Test
using Compat.LinearAlgebra
using Rotations
using StaticArrays

import Compat.Random: srand

# Check that there are no ambiguities beyond those present in StaticArrays
ramb = detect_ambiguities(Rotations, Base, Core)
samb = detect_ambiguities(StaticArrays, Base, Core)
Expand All @@ -14,4 +18,4 @@ include("2d.jl")
include("rotation_tests.jl")
include("derivative_tests.jl")

include(joinpath("..", "perf", "runbenchmarks.jl"))
include(joinpath(@__DIR__, "..", "perf", "runbenchmarks.jl"))

0 comments on commit a405b90

Please sign in to comment.