Skip to content

Commit

Permalink
Merge pull request #69 from FugroRoames/tk/miguelraz/v1fixes
Browse files Browse the repository at this point in the history
More fixes for 1.0
  • Loading branch information
andyferris authored Aug 12, 2018
2 parents 47eef3d + 13bda80 commit 8f6890a
Show file tree
Hide file tree
Showing 13 changed files with 249 additions and 385 deletions.
6 changes: 3 additions & 3 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ os:
- linux
- osx
julia:
- 0.6
- 0.7
- 1.0
- nightly
addons:
apt:
Expand All @@ -23,6 +23,6 @@ matrix:
# - julia -e 'Pkg.clone(pwd()); Pkg.build("Rotations"); Pkg.test("Rotations"; coverage=true)'
after_success:
# - if [ $TRAVIS_JULIA_VERSION = "release" ] && [ $TRAVIS_OS_NAME = "linux" ]; then
- if [ $TRAVIS_JULIA_VERSION = "0.5" ] && [ $TRAVIS_OS_NAME = "linux" ]; then
julia -e 'cd(Pkg.dir("Rotations")); Pkg.add("Coverage"); using Coverage; Coveralls.submit(Coveralls.process_folder())';
- if [ $TRAVIS_OS_NAME = "linux" ]; then
julia -e 'using Pkg; Pkg.add("Coverage"); using Coverage; Coveralls.submit(Coveralls.process_folder())';
fi
5 changes: 2 additions & 3 deletions REQUIRE
Original file line number Diff line number Diff line change
@@ -1,3 +1,2 @@
julia 0.6
StaticArrays 0.6.5
Compat 0.70 # for norm
julia 0.7
StaticArrays 0.8.3
36 changes: 22 additions & 14 deletions appveyor.yml
Original file line number Diff line number Diff line change
@@ -1,7 +1,16 @@
environment:
matrix:
- JULIA_URL: "https://julialangnightlies-s3.julialang.org/bin/winnt/x86/julia-latest-win32.exe"
- JULIA_URL: "https://julialangnightlies-s3.julialang.org/bin/winnt/x64/julia-latest-win64.exe"
- julia_version: 0.7
- julia_version: 1
- julia_version: latest

platform:
- x86 # 32-bit
- x64 # 64-bit

matrix:
allow_failures:
- julia_version: latest

branches:
only:
Expand All @@ -15,19 +24,18 @@ notifications:
on_build_status_changed: false

install:
- ps: "[System.Net.ServicePointManager]::SecurityProtocol = [System.Net.SecurityProtocolType]::Tls12"
# Download most recent Julia Windows binary
- ps: (new-object net.webclient).DownloadFile(
$env:JULIA_URL,
"C:\projects\julia-binary.exe")
# Run installer silently, output to C:\projects\julia
- C:\projects\julia-binary.exe /S /D=C:\projects\julia
- ps: iex ((new-object net.webclient).DownloadString("https://raw.githubusercontent.com/JuliaCI/Appveyor.jl/version-1/bin/install.ps1"))

build_script:
# Need to convert from shallow to complete for Pkg.clone to work
- IF EXIST .git\shallow (git fetch --unshallow)
- C:\projects\julia\bin\julia -e "versioninfo();
Pkg.clone(pwd(), \"Rotations\"); Pkg.build(\"Rotations\")"
- echo "%JL_BUILD_SCRIPT%"
- C:\julia\bin\julia -e "%JL_BUILD_SCRIPT%"

test_script:
- C:\projects\julia\bin\julia --check-bounds=yes -e "Pkg.test(\"Rotations\")"
- echo "%JL_TEST_SCRIPT%"
- C:\julia\bin\julia -e "%JL_TEST_SCRIPT%"

# # Uncomment to support code coverage upload. Should only be enabled for packages
# # which would have coverage gaps without running on Windows
# on_success:
# - echo "%JL_CODECOV_SCRIPT%"
# - C:\julia\bin\julia -e "%JL_CODECOV_SCRIPT%"
21 changes: 5 additions & 16 deletions perf/runbenchmarks.jl
Original file line number Diff line number Diff line change
@@ -1,24 +1,18 @@
using Compat
using Rotations
using BenchmarkTools
import Base.Iterators: product
import Compat.Random: srand
import Random

const T = Float64

const suite = BenchmarkGroup()
srand(1)
Random.seed!(1)

noneuler = suite["Non-Euler conversions"] = BenchmarkGroup()
rotationtypes = [RotMatrix3{T}, Quat{T}, SPQuat{T}, AngleAxis{T}, RodriguesVec{T}]
for (from, to) in product(rotationtypes, rotationtypes)
if from != to
# TODO: drop the `Rotations.` part on 0.7. This is to maintain the same names between 0.6 and 0.7
name = if VERSION < v"0.7.0-"
"$(string(from)) -> $(string(to))"
else
"Rotations.$(string(from)) -> Rotations.$(string(to))"
end
name = "$(string(from)) -> $(string(to))"
# use eval here because of https://github.com/JuliaCI/BenchmarkTools.jl/issues/50#issuecomment-318673288
noneuler[name] = eval(:(@benchmarkable convert($to, rot) setup = rot = rand($from)))
end
Expand All @@ -32,12 +26,7 @@ eulertypes = [
RotXYZ{T}, RotYXZ{T}, RotZXY{T}, RotXZY{T}, RotYZX{T}, RotZYX{T}]
for from in eulertypes
to = RotMatrix3{T}
# TODO: drop the `Rotations.` part on 0.7. This is to maintain the same names between 0.6 and 0.7
name = if VERSION < v"0.7.0-"
"$(string(from)) -> $(string(to))"
else
"Rotations.$(string(from)) -> Rotations.$(string(to))"
end
name = "$(string(from)) -> $(string(to))"
# use eval here because of https://github.com/JuliaCI/BenchmarkTools.jl/issues/50#issuecomment-318673288
euler[name] = eval(:(@benchmarkable convert($to, rot) setup = rot = rand($from)))
end
Expand Down Expand Up @@ -65,7 +54,7 @@ for (groupname, groupresults) in results
max_name_length = maximum(length, keys(groupresults))
for (name, trial) in groupresults
if minimum(trial).allocs != 0
Compat.@warn("$name allocates!")
@warn("$name allocates!")
end
println(rpad(name, max_name_length), " ", BenchmarkTools.prettytime(minimum(trial).time))
end
Expand Down
18 changes: 2 additions & 16 deletions src/Rotations.jl
Original file line number Diff line number Diff line change
Expand Up @@ -3,24 +3,10 @@ __precompile__(true)

module Rotations

using Compat
using Compat.LinearAlgebra
using LinearAlgebra
using StaticArrays

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

if VERSION >= v"0.7.0-beta.85"
import Statistics: mean
else
import Base: mean
end

if isdefined(Base, :sincos)
const _sincos = sincos
else
_sincos(x) = (sin(x), cos(x))
end
import Statistics

include("util.jl")
include("core_types.jl")
Expand Down
28 changes: 6 additions & 22 deletions src/angleaxis_types.jl
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ end
# Rodrigues' rotation formula.
T = eltype(aa)

s, c = _sincos(aa.theta)
s, c = sincos(aa.theta)
c1 = one(T) - c

c1x2 = c1 * aa.axis_x^2
Expand All @@ -74,7 +74,7 @@ end
end

@inline function Base.convert(::Type{Q}, aa::AngleAxis) where Q <: Quat
s, c = _sincos(aa.theta / 2)
s, c = sincos(aa.theta / 2)
return Q(c, s * aa.axis_x, s * aa.axis_y, s * aa.axis_z, false)
end

Expand All @@ -93,7 +93,7 @@ function Base.:*(aa::AngleAxis, v::StaticVector)
end

w = rotation_axis(aa)
st, ct = _sincos(aa.theta)
st, ct = sincos(aa.theta)
w_cross_pt = cross(w, v)
m = dot(v, w) * (one(w_cross_pt[1]) - ct)
T = promote_type(eltype(aa), eltype(v))
Expand All @@ -110,7 +110,7 @@ end
@inline Base.:*(r::SPQuat, aa::AngleAxis) = r * Quat(aa)
@inline Base.:*(aa1::AngleAxis, aa2::AngleAxis) = Quat(aa1) * Quat(aa2)

@inline inv(aa::AngleAxis) = AngleAxis(-aa.theta, aa.axis_x, aa.axis_y, aa.axis_z)
@inline Base.inv(aa::AngleAxis) = AngleAxis(-aa.theta, aa.axis_x, aa.axis_y, aa.axis_z)
@inline Base.:^(aa::AngleAxis, t::Real) = AngleAxis(aa.theta*t, aa.axis_x, aa.axis_y, aa.axis_z)
@inline Base.:^(aa::AngleAxis, t::Integer) = AngleAxis(aa.theta*t, aa.axis_x, aa.axis_y, aa.axis_z) # to avoid ambiguity

Expand All @@ -119,14 +119,6 @@ end
@inline Base.one(::Type{AngleAxis}) = AngleAxis(0.0, 1.0, 0.0, 0.0)
@inline Base.one(::Type{AngleAxis{T}}) where {T} = AngleAxis{T}(zero(T), one(T), zero(T), zero(T))

if VERSION < v"0.7-"
eye(::Type{AngleAxis}) = one(AngleAxis)
eye(::Type{AngleAxis{T}}) where {T} = one(AngleAxis{T})
elseif isdefined(LinearAlgebra, :eye)
Base.@deprecate eye(::Type{AngleAxis}) one(AngleAxis)
Base.@deprecate eye(::Type{AngleAxis{T}}) where {T} one(AngleAxis{T})
end

# accessors
@inline rotation_angle(aa::AngleAxis) = aa.theta # - floor((aa.theta+pi) / (2*pi)) * 2*pi
@inline rotation_axis(aa::AngleAxis) = SVector(aa.axis_x, aa.axis_y, aa.axis_z)
Expand Down Expand Up @@ -155,7 +147,7 @@ end
# These functions are enough to satisfy the entire StaticArrays interface:
@inline (::Type{RV})(t::NTuple{9}) where {RV <: RodriguesVec} = convert(RV, Quat(t))
@inline Base.getindex(aa::RodriguesVec, i::Int) = convert(Quat, aa)[i]
@inline Tuple(rv::RodriguesVec) = Tuple(convert(Quat, rv))
@inline Base.Tuple(rv::RodriguesVec) = Tuple(convert(Quat, rv))

# define its interaction with other angle representations
@inline Base.convert(::Type{R}, rv::RodriguesVec) where {R <: RotMatrix} = convert(R, AngleAxis(rv))
Expand Down Expand Up @@ -213,7 +205,7 @@ end
@inline Base.:*(r::AngleAxis, rv::RodriguesVec) = r * Quat(rv)
@inline Base.:*(rv1::RodriguesVec, rv2::RodriguesVec) = Quat(rv1) * Quat(rv2)

@inline inv(rv::RodriguesVec) = RodriguesVec(-rv.sx, -rv.sy, -rv.sz)
@inline Base.inv(rv::RodriguesVec) = RodriguesVec(-rv.sx, -rv.sy, -rv.sz)
@inline Base.:^(rv::RodriguesVec, t::Real) = RodriguesVec(rv.sx*t, rv.sy*t, rv.sz*t)
@inline Base.:^(rv::RodriguesVec, t::Integer) = RodriguesVec(rv.sx*t, rv.sy*t, rv.sz*t) # to avoid ambiguity

Expand All @@ -230,11 +222,3 @@ end
# define null rotations for convenience
@inline Base.one(::Type{RodriguesVec}) = RodriguesVec(0.0, 0.0, 0.0)
@inline Base.one(::Type{RodriguesVec{T}}) where {T} = RodriguesVec{T}(zero(T), zero(T), zero(T))

if VERSION < v"0.7-"
eye(::Type{RodriguesVec}) = one(RodriguesVec)
eye(::Type{RodriguesVec{T}}) where {T} = one(RodriguesVec{T})
elseif isdefined(LinearAlgebra, :eye)
Base.@deprecate eye(::Type{RodriguesVec}) one(RodriguesVec)
Base.@deprecate eye(::Type{RodriguesVec{T}}) where {T} one(RodriguesVec{T})
end
114 changes: 31 additions & 83 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))
Compat.adjoint(r::Rotation) = inv(r)
Compat.transpose(r::Rotation{N,T}) where {N,T<:Real} = inv(r)
Base.adjoint(r::Rotation) = inv(r)
Base.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 @@ -95,37 +95,29 @@ for N = 2:3
end
end
Base.@propagate_inbounds Base.getindex(r::RotMatrix, i::Int) = r.mat[i]
@inline Tuple(r::RotMatrix) = Tuple(r.mat)
@inline Base.Tuple(r::RotMatrix) = Tuple(r.mat)

@inline RotMatrix::Real) = RotMatrix{2}(θ)
@inline function (::Type{RotMatrix{2}})(θ::Real)
s, c = _sincos(θ)
s, c = sincos(θ)
RotMatrix(@SMatrix [c -s; s c])
end
@inline function RotMatrix{2,T}::Real) where T
s, c = _sincos(θ)
s, c = sincos(θ)
RotMatrix(@SMatrix T[c -s; s c])
end

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

if VERSION < v"0.7-"
eye(::Type{RotMatrix{N}}) where {N} = one(RotMatrix{N})
eye(::Type{RotMatrix{N,T}}) where {N,T} = one(RotMatrix{N,T})
elseif isdefined(LinearAlgebra, :eye)
Base.@deprecate eye(::Type{RotMatrix{N}}) where {N} one(RotMatrix{N})
Base.@deprecate eye(::Type{RotMatrix{N,T}}) where {N,T} one(RotMatrix{N,T})
end
Base.inv(r::RotMatrix) = RotMatrix(r.mat')

# By default, composition of rotations will go through RotMatrix, unless overridden
@inline *(r1::Rotation, r2::Rotation) = RotMatrix(r1) * RotMatrix(r2)
@inline *(r1::RotMatrix, r2::Rotation) = r1 * RotMatrix(r2)
@inline *(r1::Rotation, r2::RotMatrix) = RotMatrix(r1) * r2
@inline *(r1::RotMatrix, r2::RotMatrix) = RotMatrix(r1.mat * r2.mat) # TODO check that this doesn't involve extra copying.
@inline Base.:*(r1::Rotation, r2::Rotation) = RotMatrix(r1) * RotMatrix(r2)
@inline Base.:*(r1::RotMatrix, r2::Rotation) = r1 * RotMatrix(r2)
@inline Base.:*(r1::Rotation, r2::RotMatrix) = RotMatrix(r1) * r2
@inline Base.:*(r1::RotMatrix, r2::RotMatrix) = RotMatrix(r1.mat * r2.mat) # TODO check that this doesn't involve extra copying.

# Special case multiplication of 3×3 rotation matrices: speedup using cross product
@inline function *(r1::RotMatrix{3}, r2::RotMatrix{3})
@inline function Base.:*(r1::RotMatrix{3}, r2::RotMatrix{3})
ret12 = r1 * r2[:, SVector(1, 2)]
ret3 = ret12[:, 1] × ret12[:, 2]
RotMatrix([ret12 ret3])
Expand All @@ -147,85 +139,41 @@ function isrotation(r::AbstractMatrix{T}, tol::Real = 1000 * eps(eltype(T))) whe
# Transpose is overloaded for many of our types, so we do it explicitly:
r_trans = @SMatrix [conj(r[1,1]) conj(r[2,1]);
conj(r[1,2]) conj(r[2,2])]
d = Compat.norm((r * r_trans) - one(SMatrix{2,2}))
d = norm((r * r_trans) - one(SMatrix{2,2}))
elseif size(r) == (3,3)
r_trans = @SMatrix [conj(r[1,1]) conj(r[2,1]) conj(r[3,1]);
conj(r[1,2]) conj(r[2,2]) conj(r[2,3]);
conj(r[1,3]) conj(r[2,3]) conj(r[3,3])]
d = Compat.norm((r * r_trans) - one(SMatrix{3,3}))
d = norm((r * r_trans) - one(SMatrix{3,3}))
else
return false
end

return d < tol
end

@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
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, ")")
end
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
# 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
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
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
print(io, ")")
end
print(io, ":")
println(io)
io = IOContext(io, :typeinfo => eltype(X))
Base.print_array(io, X)
print(io, ")")
end
print(io, ":")
println(io)
io = IOContext(io, :typeinfo => eltype(X))
Base.print_array(io, X)
end

# Removes module name from output, to match other types
Expand Down
Loading

0 comments on commit 8f6890a

Please sign in to comment.