Skip to content

Commit 9c97cf9

Browse files
committed
add tests for Rect constructors and refactor constructors
1 parent 46ea52a commit 9c97cf9

File tree

3 files changed

+136
-83
lines changed

3 files changed

+136
-83
lines changed

src/GeometryBasics.jl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ export uv_mesh, normal_mesh, uv_normal_mesh
5858
export height, origin, radius, width, widths
5959
export HyperSphere, Circle, Sphere
6060
export Cylinder, Pyramid, extremity
61-
export HyperRectangle, Rect, Rect2, Rect3, Recti, Rect2i, Rect3i, Rectf, Rect2f, Rect3f, Rectd, Rect2d, Rect3d
61+
export HyperRectangle, Rect, Rect2, Rect3, Recti, Rect2i, Rect3i, Rectf, Rect2f, Rect3f, Rectd, Rect2d, Rect3d, RectT
6262
export before, during, meets, overlaps, intersects, finishes
6363
export centered, direction, area, volume, update
6464
export max_dist_dim, max_euclidean, max_euclideansq, min_dist_dim, min_euclidean

src/primitives/rectangles.jl

Lines changed: 53 additions & 82 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,10 @@ const Recti{N} = Rect{N,Int}
4848
const Rect2i = Rect2{Int}
4949
const Rect3i = Rect3{Int}
5050

51+
52+
# Constructors
53+
54+
5155
Rect() = Rect{2,Float32}()
5256
RectT{T}() where {T} = Rect{2,T}()
5357
Rect{N}() where {N} = Rect{N,Float32}()
@@ -57,116 +61,83 @@ function Rect{N,T}() where {T,N}
5761
return Rect{N,T}(Vec{N,T}(typemax(T)), Vec{N,T}(typemin(T)))
5862
end
5963

60-
# conversion from other Rects
61-
function Rect{N,T1}(a::Rect{N,T2}) where {N,T1,T2}
62-
return Rect(Vec{N,T1}(minimum(a)), Vec{N,T1}(widths(a)))
63-
end
64-
65-
function Rect(v1::VecTypes{N,T1}, v2::VecTypes{N,T2}) where {N,T1,T2}
66-
T = promote_type(T1, T2)
67-
return Rect{N,T}(Vec{N,T}(v1), Vec{N,T}(v2))
68-
end
69-
70-
function RectT{T}(v1::VecTypes{N}, v2::VecTypes{N}) where {N,T}
71-
return if T <: Integer
72-
Rect{N,T}(round.(T, v1), round.(T, v2))
73-
else
74-
return Rect{N,T}(Vec{N,T}(v1), Vec{N,T}(v2))
75-
end
76-
end
77-
78-
function Rect{N}(v1::VecTypes{N}, v2::VecTypes{N}) where {N}
79-
T = promote_type(eltype(v1), eltype(v2))
80-
return Rect{N,T}(Vec{N,T}(v1), Vec{N,T}(v2))
81-
end
64+
# Rect(numbers...)
65+
Rect(args::Vararg{Number, N}) where {N} = Rect{div(N, 2), promote_type(typeof.(args)...)}(args...)
66+
RectT{T}(args::Vararg{Number, N}) where {N, T} = Rect{div(N, 2), T}(args...)
67+
Rect{N}(args::Vararg{Number}) where {N} = Rect{N, promote_type(typeof.(args)...)}(args...)
8268

8369
"""
8470
Rect(vals::Number...)
8571
86-
```
87-
Rect(vals::Number...)
88-
```
8972
Rect constructor for individually specified intervals.
9073
e.g. Rect(0,0,1,2) has origin == Vec(0,0) and
9174
width == Vec(1,2)
9275
"""
93-
function Rect(vals::Vararg{Number, N}) where {N}
94-
M, r = fldmod(N, 2)
95-
(r == 0) || throw(ArgumentError("number of arguments must be even"))
96-
origin, widths = ntuple(i -> vals[i], M), ntuple(i -> vals[i+M], M)
97-
return Rect(Vec(origin), Vec(widths))
76+
function Rect{N, T}(vals::Vararg{Number, M}) where {N, M, T}
77+
n, r = fldmod(M, 2)
78+
if r != 0 || n != N
79+
throw(ArgumentError("Number of arguments must be compatible with given or derived Rect size. Got $M arguments for a Rect{$N} expecting $(2 * N)."))
80+
end
81+
origin, widths = ntuple(i -> vals[i], N), ntuple(i -> vals[i+N], N)
82+
return Rect{N, T}(Vec(origin), Vec(widths))
9883
end
9984

100-
Rect3(a::Vararg{Number,6}) = Rect3(Vec{3}(a[1], a[2], a[3]), Vec{3}(a[4], a[5], a[6]))
101-
Rect3(args::Vararg{Number,4}) = Rect3(Rect{2}(args...))
102-
#=
103-
From different args
104-
=#
105-
function (Rect)(args::Vararg{Number,4})
106-
args_prom = promote(args...)
107-
return Rect2{typeof(args_prom[1])}(args_prom...)
108-
end
85+
# VecTypes
10986

110-
function (Rect2)(args::Vararg{Number,4})
111-
args_prom = promote(args...)
112-
return Rect2{typeof(args_prom[1])}(args_prom...)
113-
end
87+
Rect(o::VecTypes{N, T1}, w::VecTypes{N, T2}) where {N, T1, T2} = Rect{N, promote_type(T1, T2)}(o, w)
88+
RectT{ T}(o::VecTypes{N}, w::VecTypes{N}) where {N, T} = Rect{N, T}(o, w)
89+
Rect{N }(o::VecTypes{N, T1}, w::VecTypes{N, T2}) where {N, T1, T2} = Rect{N, promote_type(T1, T2)}(o, w)
11490

115-
function (Rect{2,T})(args::Vararg{Number,4}) where {T}
116-
x, y, w, h = T <: Integer ? round.(T, args) : args
117-
return Rect2{T}(Vec{2,T}(x, y), Vec{2,T}(w, h))
118-
end
91+
# mixed number - vectype
11992

120-
function RectT{T}(args::Vararg{Number,4}) where {T}
121-
x, y, w, h = T <: Integer ? round.(T, args) : args
122-
return Rect2{T}(Vec{2,T}(x, y), Vec{2,T}(w, h))
123-
end
93+
Rect(o::VecTypes{N, <:Number}, args::Vararg{Number, N}) where {N} = Rect{N }(o, promote(args...))
94+
RectT{ T}(o::VecTypes{N, <:Number}, args::Vararg{Number, N}) where {N, T} = Rect{N, T}(o, promote(args...))
95+
Rect{N }(o::VecTypes{N, <:Number}, args::Vararg{Number, N}) where {N} = Rect{N }(o, promote(args...))
96+
Rect{N, T}(o::VecTypes{N, <:Number}, args::Vararg{Number, N}) where {N, T} = Rect{N, T}(o, promote(args...))
12497

125-
function Rect3f(x::Rect2{T}) where {T}
126-
return Rect{3,T}(Vec{3,T}(minimum(x)..., 0), Vec{3,T}(widths(x)..., 0.0))
127-
end
98+
Rect(x::Number, y::Number, w::VecTypes{2, <:Number}) = Rect{2 }(Vec(x, y), w)
99+
RectT{ T}(x::Number, y::Number, w::VecTypes{2, <:Number}) where {T} = Rect{2, T}(Vec(x, y), w)
100+
Rect{2 }(x::Number, y::Number, w::VecTypes{2, <:Number}) = Rect{2 }(Vec(x, y), w)
101+
Rect{2, T}(x::Number, y::Number, w::VecTypes{2, <:Number}) where {T} = Rect{2, T}(Vec(x, y), w)
128102

129-
function Rect2{T}(a::Rect2) where {T}
130-
return Rect2{T}(minimum(a), widths(a))
131-
end
103+
Rect(x::Number, y::Number, z::Number, w::VecTypes{3, <:Number}) = Rect{3 }(Vec(x, y, z), w)
104+
RectT{ T}(x::Number, y::Number, z::Number, w::VecTypes{3, <:Number}) where {T} = Rect{3, T}(Vec(x, y, z), w)
105+
Rect{3 }(x::Number, y::Number, z::Number, w::VecTypes{3, <:Number}) = Rect{3 }(Vec(x, y, z), w)
106+
Rect{3, T}(x::Number, y::Number, z::Number, w::VecTypes{3, <:Number}) where {T} = Rect{3, T}(Vec(x, y, z), w)
132107

133-
function RectT{T}(a::Rect2) where {T}
134-
return Rect2{T}(minimum(a), widths(a))
135-
end
108+
# copy constructors
136109

137-
function Rect{N,T}(a::GeometryPrimitive) where {N,T}
138-
return Rect{N,T}(Vec{N,T}(minimum(a)), Vec{N,T}(widths(a)))
139-
end
110+
Rect(r::Rect{N, T}) where {N, T} = Rect{N, T}(origin(r), widths(r))
111+
RectT{ T}(r::Rect{N}) where {N, T} = Rect{N, T}(origin(r), widths(r))
112+
Rect{N }(r::Rect{N, T}) where {N, T} = Rect{N, T}(origin(r), widths(r))
113+
Rect{N, T}(r::Rect{N}) where {N, T} = Rect{N, T}(origin(r), widths(r))
140114

141-
function Rect2(xy::VecTypes{2}, w::Number, h::Number)
142-
return Rect2(xy..., w, h)
143-
end
115+
# dimensional promotion
144116

145-
function Rect2(x::Number, y::Number, wh::VecTypes{2})
146-
return Rect2(x, y, wh...)
147-
end
117+
Rect{3, T}(o::VecTypes{2}, w::VecTypes{3}) where {T} = Rect{3, T}(Vec(o..., 0), w)
118+
Rect{3, T}(o::VecTypes{3}, w::VecTypes{2}) where {T} = Rect{3, T}(o, Vec(w..., 0))
119+
Rect{3, T}(o::VecTypes{2}, w::VecTypes{2}) where {T} = Rect{3, T}(Vec(o..., 0), Vec(w..., 0))
148120

149-
function RectT{T}(xy::VecTypes{2}, w::Number, h::Number) where {T}
150-
return Rect2{T}(xy..., w, h)
151-
end
121+
# Boundingbox-like constructors
152122

153-
function RectT{T}(x::Number, y::Number, wh::VecTypes{2}) where {T}
154-
return Rect2{T}(x, y, wh...)
155-
end
123+
# Rect(r::GeometryPrimitive{N, T}) where {N, T} = Rect{N, T}(minimum(r), widths(r)) # in boundingboxes.jl
124+
RectT{T}(r::GeometryPrimitive{N}) where {N, T} = Rect{N, T}(minimum(r), widths(r))
125+
Rect{N}(r::GeometryPrimitive{_N, T}) where {N, _N, T} = Rect{N, T}(minimum(r), widths(r))
126+
Rect{N, T}(r::GeometryPrimitive) where {N, T} = Rect{N, T}(minimum(r), widths(r))
156127

157128
# TODO These are kinda silly
158129
function Rect2(xy::NamedTuple{(:x, :y)}, wh::NamedTuple{(:width, :height)})
159130
return Rect2(xy.x, xy.y, wh.width, wh.height)
160131
end
161132

162-
function Rect3f(x::Tuple{Tuple{<:Number,<:Number},Tuple{<:Number,<:Number}})
163-
return Rect3f(Vec3f(x[1]..., 0), Vec3f(x[2]..., 0))
164-
end
133+
Rect(ow::Tuple) = Rect(ow...)
134+
RectT{T}(ow::Tuple) where {T} = RectT{T}(ow...)
135+
Rect{N}(ow::Tuple) where {N} = Rect{N}(ow...)
136+
Rect{N, T}(ow::Tuple) where {N, T} = Rect{N, T}(ow...)
137+
138+
139+
# Utilities
165140

166-
function Rect3f(x::Tuple{Tuple{<:Number,<:Number,<:Number},
167-
Tuple{<:Number,<:Number,<:Number}})
168-
return Rect3f(Vec3f(x[1]...), Vec3f(x[2]...))
169-
end
170141

171142
# allow auto-conversion between different eltypes
172143
Base.convert(::Type{Rect{N, T}}, r::Rect{N}) where {N, T} = Rect{N, T}(r)

test/geometrytypes.jl

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,88 @@ using Test, GeometryBasics
7777
end
7878

7979
@testset "HyperRectangles" begin
80+
@testset "Constructors" begin
81+
# TODO: Do these actually make sense?
82+
# Should they not be Rect(NaN..., 0...)?
83+
@testset "Empty Constructors" begin
84+
for constructor in [Rect, Rect{2}, Rect2, RectT, Rect2f]
85+
@test constructor() == Rect{2, Float32}(Inf, Inf, -Inf, -Inf)
86+
end
87+
for constructor in [Rect{3}, Rect3, Rect3f]
88+
@test constructor() == Rect{3, Float32}((Inf, Inf, Inf), (-Inf, -Inf, -Inf))
89+
end
90+
91+
for T in [UInt32, Int16, Float64]
92+
a = typemax(T)
93+
b = typemin(T)
94+
for constructor in [Rect{2, T}, Rect2{T}, RectT{T, 2}]
95+
@test constructor() == Rect{2, T}(a, a, b, b)
96+
end
97+
for constructor in [Rect{3, T}, Rect3{T}, RectT{T, 3}]
98+
@test constructor() == Rect{3, T}(Point(a, a, a), Vec(b, b, b))
99+
end
100+
end
101+
end
102+
103+
@testset "Constructor arg conversions" begin
104+
function expected_rect(::Type{<: Rect}, arg1, arg2)
105+
return Rect{min(length(arg1), length(arg2)), promote_type(eltype(arg1), eltype(arg2))}(arg1, arg2)
106+
end
107+
function expected_rect(::Type{<: Rect{N}}, arg1, arg2) where {N}
108+
return Rect{N, promote_type(eltype(arg1), eltype(arg2))}(arg1, arg2)
109+
end
110+
function expected_rect(::Type{<: Rect{N, T}}, arg1, arg2) where {N, T}
111+
return Rect{N, T}(arg1, arg2)
112+
end
113+
114+
@testset "2D args -> 2D Rect" begin
115+
for constructor in [Rect, RectT, Rect2, Rect{2}, RectT{Int32},
116+
Rect2f, Rect{2, Float16}, Rect2{UInt32}, RectT{Float64, 2}]
117+
@testset "$constructor" begin
118+
@test constructor(1,2,3,4) == expected_rect(constructor, Point(1,2), Vec(3,4))
119+
@test constructor(1.0,2,3,4) == expected_rect(constructor, Point(1.0,2), Vec(3,4))
120+
@test constructor(Point2f(1,2),3,4) == expected_rect(constructor, Point2f(1,2), Vec(3,4))
121+
@test constructor(Vec2(1,2),3,4.0) == expected_rect(constructor, Point(1,2), Vec(3,4.0))
122+
@test constructor((1,2),Point2(3,4)) == expected_rect(constructor, Point(1,2), Vec(3,4))
123+
@test constructor(1.0,2,Vec2(3,4)) == expected_rect(constructor, Point(1,2), Vec(3,4))
124+
end
125+
end
126+
end
127+
128+
@testset "3D args -> 3D Rect" begin
129+
for constructor in [Rect, RectT, Rect3, Rect{3}, RectT{Float64},
130+
Rect3d, Rect{3, Int16}, Rect3{UInt8}, RectT{Float32, 3}]
131+
@testset "$constructor" begin
132+
@test constructor(1,2,3,4,5,6) == expected_rect(constructor, Point(1,2,3), Vec(4,5,6))
133+
@test constructor(1,2,3,4,5,6.0) == expected_rect(constructor, Point(1,2,3), Vec(4,5,6.0))
134+
@test constructor(1,2.0,3,Vec3f(4,5,6)) == expected_rect(constructor, Point(1,2,3), Vec3f(4,5,6))
135+
@test constructor(Vec3(1,2,3),4,5,6) == expected_rect(constructor, Point3(1,2,3), Vec(4,5,6))
136+
@test constructor((1,2,3),Point3(4,5,6)) == expected_rect(constructor, Point(1,2,3), Vec(4,5,6))
137+
@test constructor(Vec3(1,2,3),4,5,6) == expected_rect(constructor, Point(1,2,3), Vec(4,5,6))
138+
end
139+
end
140+
end
141+
end
142+
143+
@testset "Copy Constructors" begin
144+
r = Rect2i(0,0,1,1)
145+
for constructor in [Rect, Rect2f, Rect3f, RectT{Float64}]
146+
@test constructor(r) == constructor(Point2(0), Vec2(1))
147+
end
148+
end
149+
150+
@testset "Special Constructors" begin
151+
@test Rect3f((1, 2, 3, Vec(1,2,3))) == Rect3f(1,2,3, Vec(1,2,3))
152+
@test Rect2(((1, 2), 3, 4)) == Rect2f((1,2), 3, 4)
153+
@test Rect((1, 2, 3, 4)) == Rect2f(1, 2, 3, 4)
154+
@test Rect2((x = 1, y = 2), (width = 3, height = 4)) == Rect2f(1, 2, 3, 4)
155+
end
156+
157+
# TODO: test/check for Rect(::GeometryPrimitive) for all primitives
158+
end
159+
160+
# TODO: origin, minimum, maximum, width, height, widths, area, volume with empty constructed Rects
161+
80162
a = Rect(Vec(0, 0), Vec(1, 1))
81163
pt_expa = Point{2,Int}[(0, 0), (1, 0), (1, 1), (0, 1)]
82164
@test decompose(Point{2,Int}, a) == pt_expa

0 commit comments

Comments
 (0)