Skip to content

Commit 4e69168

Browse files
authored
Merge pull request #68 from JuliaGeometry/sjk/no_sarray1
Make interface generic, Drop StaticArrays as hard dependency
2 parents f41fd84 + 8afd0bc commit 4e69168

File tree

5 files changed

+31
-35
lines changed

5 files changed

+31
-35
lines changed

Project.toml

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,18 +2,15 @@ name = "Contour"
22
uuid = "d38c429a-6771-53c6-b99e-75d170b6e991"
33
version = "0.5.7"
44

5-
[deps]
6-
StaticArrays = "90137ffa-7385-5640-81b9-e52037218182"
7-
85
[compat]
9-
StaticArrays = "0.10,0.11,0.12, 1.0"
106
julia = "0.7, 1"
117

128
[extras]
139
LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e"
1410
OffsetArrays = "6fe1bfb0-de20-5000-8ca7-80f57d26f881"
11+
StaticArrays = "90137ffa-7385-5640-81b9-e52037218182"
1512
StatsBase = "2913bbd2-ae8a-5f71-8c99-4fb6c76f3a91"
1613
Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40"
1714

1815
[targets]
19-
test = ["LinearAlgebra", "StatsBase", "Test", "OffsetArrays"]
16+
test = ["LinearAlgebra", "StatsBase", "Test", "OffsetArrays", "StaticArrays"]

src/Contour.jl

Lines changed: 13 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
11
module Contour
22

3-
using StaticArrays
4-
53
include("interpolate.jl")
64

75
export
@@ -17,17 +15,17 @@ export
1715
import Base: push!, length, eltype, show
1816

1917
struct Curve2{T}
20-
vertices::Vector{SVector{2,T}}
18+
vertices::Vector{T}
2119
end
22-
Curve2(::Type{T}) where {T} = Curve2(SVector{2,T}[])
20+
Curve2(::Type{T}) where {T} = Curve2(T[])
2321
show(io::IO, ::MIME"text/plain", c2::Curve2) = write(io, "$(typeof(c2))\n with $(length(c2.vertices)-1) vertices")
2422
show(io::IO, ::MIME"text/plain", c2s::Vector{Curve2{T}}) where {T} = write(io, "$(typeof(c2s))\n $(length(c2s)) contour line(s)")
2523

26-
struct ContourLevel{T}
27-
level::T
24+
struct ContourLevel{T, L}
25+
level::L
2826
lines::Vector{Curve2{T}}
2927
end
30-
ContourLevel(h::T) where {T <: AbstractFloat} = ContourLevel(h, Curve2{T}[])
28+
ContourLevel(h::T) where {T <: AbstractFloat} = ContourLevel(h, Curve2{NTuple{2,T}}[])
3129
ContourLevel(h::T) where {T} = ContourLevel(Float64(h))
3230
show(io::IO, ::MIME"text/plain", cl::ContourLevel) = write(io, "$(typeof(cl))\n at $(level(cl)) with $(length(lines(cl))) line(s)")
3331
show(io::IO, ::MIME"text/plain", cls::Vector{ContourLevel{T}}) where {T} = write(io, "$(typeof(cls))\n $(length(cls)) contour level(s)")
@@ -62,11 +60,12 @@ argument `level`.
6260
You'll usually call [`lines`](@ref) on the output of `contour`, and then iterate
6361
over the result.
6462
"""
65-
function contour(x, y, z, level::Number)
63+
function contour(x, y, z, level::Number; VT=nothing)
6664
if !(axes(x) == (axes(z,1),) && axes(y) == (axes(z,2),) || axes(x) == axes(y) == axes(z))
6765
throw(ArgumentError("Incompatible input axes in `Contour.contour`."))
6866
end
69-
trace_contour(x, y, z, level, get_level_cells(z, level))
67+
VT = VT === nothing ? NTuple{2,promote_type(map(eltype, (x, y, z))...)} : VT
68+
trace_contour(x, y, z, level, get_level_cells(z, level), VT)
7069
end
7170

7271
"""
@@ -111,8 +110,9 @@ a tuple of lists.
111110
"""
112111
function coordinates(c::Curve2{T}) where {T}
113112
N = length(c.vertices)
114-
xlist = Vector{T}(undef, N)
115-
ylist = Vector{T}(undef, N)
113+
E = eltype(T)
114+
xlist = Vector{E}(undef, N)
115+
ylist = Vector{E}(undef, N)
116116

117117
for (i, v) in enumerate(c.vertices)
118118
xlist[i] = v[1]
@@ -264,17 +264,15 @@ function chase!(cells, curve, x, y, z, h, start, entry_edge, xi_range, yi_range,
264264
end
265265

266266

267-
function trace_contour(x, y, z, h::Number, cells::Dict)
267+
function trace_contour(x, y, z, h::Number, cells::Dict, VT)
268268

269-
contours = ContourLevel(h)
269+
contours = ContourLevel(h, Curve2{VT}[])
270270

271271
x_ax, y_ax = axes(z)
272272
xi_range = first(x_ax):last(x_ax)-1
273273
yi_range = first(y_ax):last(y_ax)-1
274274

275275

276-
VT = SVector{2,promote_type(map(eltype, (x, y, z))...)}
277-
278276
# When tracing out contours, this algorithm picks an arbitrary
279277
# starting cell, then first follows the contour in one direction
280278
# until it either ends up where it started # or at one of the boundaries.

src/interpolate.jl

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ function interpolate(x, y, z::AbstractMatrix, h::Number, ind, edge::UInt8, ::Typ
1717
x_interp = x[xi] + (x[xi + 1] - x[xi]) * (h - z[xi, yi]) / (z[xi + 1, yi] - z[xi, yi])
1818
end
1919

20-
return VT(x_interp, y_interp)
20+
return VT <: Tuple ? (x_interp, y_interp) : VT(x_interp, y_interp)
2121
end
2222

2323
function interpolate(x::AbstractRange, y::AbstractRange, z::AbstractMatrix, h::Number, ind, edge::UInt8, ::Type{VT}) where {VT}
@@ -36,7 +36,7 @@ function interpolate(x::AbstractRange, y::AbstractRange, z::AbstractMatrix, h::N
3636
x_interp = x[xi] + step(x) * (h - z[xi, yi]) / (z[xi + 1, yi] - z[xi, yi])
3737
end
3838

39-
return VT(x_interp, y_interp)
39+
return VT <: Tuple ? (x_interp, y_interp) : VT(x_interp, y_interp)
4040
end
4141

4242
function interpolate(x::AbstractMatrix, y::AbstractMatrix, z::AbstractMatrix, h::Number, ind, edge::UInt8, ::Type{VT}) where {VT}
@@ -59,5 +59,5 @@ function interpolate(x::AbstractMatrix, y::AbstractMatrix, z::AbstractMatrix, h:
5959
x_interp = x[xi,yi] + Δ[2]
6060
end
6161

62-
return VT(x_interp, y_interp)
62+
return VT <: Tuple ? (x_interp, y_interp) : VT(x_interp, y_interp)
6363
end

test/runtests.jl

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
11
using Contour, Test
22

3+
@test length(detect_ambiguities(Base, Contour)) == 0
4+
35
include("verify_vertices.jl")
46
include("interface.jl")
57

6-
# @show detect_ambiguities(Base, Contour) # should be zero but there are a few stragglers in the imports
78

89
#issue 59
910
@inferred collect(())

test/verify_vertices.jl

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ Y = collect(0:Δ:3) .+ φ
2121
Z = [(x^2 + y^2)::Float64 for x in X, y in Y]
2222
h = rand() * (maximum(Z) - minimum(Z)) + minimum(Z)
2323

24-
contourlevels = Contour.contour(X, Y, Z, h)
24+
contourlevels = Contour.contour(X, Y, Z, h; VT=SVector{2,Float64})
2525
for line in contourlevels.lines
2626
# Contour vertices lie on a circle around the origin
2727
for v in line.vertices
@@ -42,7 +42,7 @@ h = 1
4242
x0, y0 = (.5, -1.5)
4343
Z = Float64[(x - x0)^2 + (y - y0)^2 for x in X, y in Y]
4444

45-
contourlevels = Contour.contour(X, Y, Z, h)
45+
contourlevels = Contour.contour(X, Y, Z, h, VT=SVector{2,Float64})
4646
for line in contourlevels.lines
4747
for v in line.vertices
4848
@test isapprox((v[1] - x0)^2 + (v[2] - y0)^2, h, atol=0.01Δ)
@@ -65,7 +65,7 @@ lines = Contour.contour(X, Y, Z, h).lines
6565

6666
for line in lines
6767
@test length(line.vertices) == 2
68-
d = line.vertices[2] - line.vertices[1]
68+
d = line.vertices[2] .- line.vertices[1]
6969
@test d[2] / d[1] -1.0
7070
end
7171

@@ -80,7 +80,7 @@ lines = Contour.contour(X, Y, Z, h).lines
8080

8181
for line in lines
8282
@test length(line.vertices) == 2
83-
d = line.vertices[2] - line.vertices[1]
83+
d = line.vertices[2] .- line.vertices[1]
8484
@test d[2] / d[1] 1.0
8585
end
8686

@@ -94,7 +94,7 @@ lines = Contour.contour(X, Y, Z, h).lines
9494

9595
for line in lines
9696
@test length(line.vertices) == 2
97-
d = line.vertices[2] - line.vertices[1]
97+
d = line.vertices[2] .- line.vertices[1]
9898
@test d[2] / d[1] 1.0
9999
end
100100

@@ -104,12 +104,12 @@ Z = float([0 1;
104104
1 0])
105105
h = 0.9
106106

107-
lines = Contour.contour(X, Y, Z, h).lines
107+
lines = Contour.contour(X, Y, Z, h, VT=SVector{2, Float64}).lines
108108
@test length(lines) == 2
109109

110110
for line in lines
111111
@test length(line.vertices) == 2
112-
d = line.vertices[2] - line.vertices[1]
112+
d = line.vertices[2] .- line.vertices[1]
113113
@test d[2] / d[1] -1.0
114114
end
115115

@@ -120,7 +120,7 @@ R = range(1.0, stop=2.0, length=100)
120120
x, y, z = real.(ζ), imag.(ζ), abs.(ζ)
121121

122122
h = 1 + rand()
123-
xs, ys = coordinates(contour(x, y, z, h).lines[1])
123+
xs, ys = coordinates(contour(x, y, z, h, VT=SVector{2, Float64}).lines[1])
124124
@test all(xs.^2 + ys.^2 .≈ h^2)
125125

126126

@@ -131,8 +131,8 @@ zoff = OffsetArray(z, offset_x, offset_y)
131131

132132
x, y = axes(z)
133133
xoff, yoff = axes(zoff)
134-
curves = Contour.contour(x,y,z,0.5)
135-
curves_off = Contour.contour(xoff, yoff, zoff, 0.5)
134+
curves = Contour.contour(x,y,z,0.5, VT=SVector{2, Float64})
135+
curves_off = Contour.contour(xoff, yoff, zoff, 0.5,VT=SVector{2, Float64})
136136

137137
# sort offset and non-offset curves to the same order
138138
offset = SVector(offset_x, offset_y)
@@ -172,7 +172,7 @@ Y = collect(-3:Δ:3)
172172
Z = [(x^2 - y^2)::Float64 for x in X, y in Y]
173173
h = rand() * (maximum(Z) - minimum(Z)) + minimum(Z)
174174

175-
contourlevels = Contour.contour(X, Y, Z, h)
175+
contourlevels = Contour.contour(X, Y, Z, h) #, VT=SVector{2, Float64})
176176
for line in contourlevels.lines
177177
# Contour vertices lie on a circle around the origin
178178
for v in line.vertices

0 commit comments

Comments
 (0)