Skip to content

Commit 5a5a3cf

Browse files
authored
Merge pull request #61 from yha/offset-arrays
Offset array support
2 parents 3f7e539 + 4f6ef0c commit 5a5a3cf

File tree

3 files changed

+49
-12
lines changed

3 files changed

+49
-12
lines changed

Project.toml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ julia = "0.7, 1"
1313
LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e"
1414
Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40"
1515
StatsBase = "2913bbd2-ae8a-5f71-8c99-4fb6c76f3a91"
16+
OffsetArrays = "6fe1bfb0-de20-5000-8ca7-80f57d26f881"
1617

1718
[targets]
18-
test = ["LinearAlgebra", "StatsBase", "Test"]
19+
test = ["LinearAlgebra", "StatsBase", "Test", "OffsetArrays"]

src/Contour.jl

Lines changed: 15 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,9 @@ You'll usually call [`lines`](@ref) on the output of `contour`, and then iterate
6363
over the result.
6464
"""
6565
function contour(x, y, z, level::Number)
66-
# Todo: size checking on x,y,z
66+
if !(axes(x) == (axes(z,1),) && axes(y) == (axes(z,2),) || axes(x) == axes(y) == axes(z))
67+
throw(ArgumentError("Incompatible input axes in `Contour.contour`."))
68+
end
6769
trace_contour(x, y, z, level, get_level_cells(z, level))
6870
end
6971

@@ -207,10 +209,10 @@ end
207209

208210
function get_level_cells(z, h::Number)
209211
cells = Dict{Tuple{Int,Int},UInt8}()
210-
xi_max, yi_max = size(z)
212+
x_ax, y_ax = axes(z)
211213

212-
@inbounds for xi in 1:xi_max - 1
213-
for yi in 1:yi_max - 1
214+
@inbounds for xi in first(x_ax):last(x_ax)-1
215+
for yi in first(y_ax):last(y_ax)-1
214216
elts = (z[xi, yi], z[xi + 1, yi], z[xi + 1, yi + 1], z[xi, yi + 1])
215217
case = _get_case(elts, h)
216218

@@ -237,7 +239,7 @@ end
237239

238240
# Given a cell and a starting edge, we follow the contour line until we either
239241
# hit the boundary of the input data, or we form a closed contour.
240-
function chase!(cells, curve, x, y, z, h, start, entry_edge, xi_max, yi_max, ::Type{VT}) where VT
242+
function chase!(cells, curve, x, y, z, h, start, entry_edge, xi_range, yi_range, ::Type{VT}) where VT
241243

242244
ind = start
243245

@@ -255,7 +257,7 @@ function chase!(cells, curve, x, y, z, h, start, entry_edge, xi_max, yi_max, ::T
255257
ind, entry_edge = advance_edge(ind, exit_edge)
256258

257259
!((ind[1], ind[2], entry_edge) != (start[1], start[2], loopback_edge) &&
258-
0 < ind[2] < yi_max && 0 < ind[1] < xi_max) && break
260+
ind[2] yi_range && ind[1] xi_range) && break
259261
end
260262

261263
return ind
@@ -266,7 +268,10 @@ function trace_contour(x, y, z, h::Number, cells::Dict)
266268

267269
contours = ContourLevel(h)
268270

269-
(xi_max, yi_max) = size(z)::Tuple{Int,Int}
271+
x_ax, y_ax = axes(z)
272+
xi_range = first(x_ax):last(x_ax)-1
273+
yi_range = first(y_ax):last(y_ax)-1
274+
270275

271276
VT = SVector{2,promote_type(map(eltype, (x, y, z))...)}
272277

@@ -289,7 +294,7 @@ function trace_contour(x, y, z, h::Number, cells::Dict)
289294
push!(contour_arr, interpolate(x, y, z, h, ind, starting_edge, VT))
290295

291296
# Start trace in forward direction
292-
ind_end = chase!(cells, contour_arr, x, y, z, h, ind, starting_edge, xi_max, yi_max, VT)
297+
ind_end = chase!(cells, contour_arr, x, y, z, h, ind, starting_edge, xi_range, yi_range, VT)
293298

294299
if ind == ind_end
295300
push!(contours.lines, Curve2(contour_arr))
@@ -298,9 +303,9 @@ function trace_contour(x, y, z, h::Number, cells::Dict)
298303

299304
ind, starting_edge = advance_edge(ind, starting_edge)
300305

301-
if 0 < ind[2] < yi_max && 0 < ind[1] < xi_max
306+
if ind[2] yi_range && ind[1] xi_range
302307
# Start trace in reverse direction
303-
chase!(cells, reverse!(contour_arr), x, y, z, h, ind, starting_edge, xi_max, yi_max, VT)
308+
chase!(cells, reverse!(contour_arr), x, y, z, h, ind, starting_edge, xi_range, yi_range, VT)
304309
end
305310

306311
push!(contours.lines, Curve2(contour_arr))

test/verify_vertices.jl

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@ module VerticesTests
33
using Contour, Test
44
using Base.MathConstants: π, φ
55
using LinearAlgebra: Diagonal
6+
using OffsetArrays
7+
using StaticArrays
68

79
# Setup test axes that will be shared among the tests
810

@@ -119,9 +121,38 @@ x, y, z = real.(ζ), imag.(ζ), abs.(ζ)
119121

120122
h = 1 + rand()
121123
xs, ys = coordinates(contour(x, y, z, h).lines[1])
122-
123124
@test all(xs.^2 + ys.^2 .≈ h^2)
124125

126+
127+
# Test offset arrays
128+
offset_x, offset_y = -10, 27
129+
z = cumsum(cumsum(randn(20,20); dims=1); dims=2)
130+
zoff = OffsetArray(z, offset_x, offset_y)
131+
132+
x, y = axes(z)
133+
xoff, yoff = axes(zoff)
134+
curves = Contour.contour(x,y,z,0.5)
135+
curves_off = Contour.contour(xoff, yoff, zoff, 0.5)
136+
137+
# sort offset and non-offset curves to the same order
138+
offset = SVector(offset_x, offset_y)
139+
lns = sort(Contour.lines(curves); by=c->sum(sum.(c.vertices.+[offset])))
140+
lns_off = sort(Contour.lines(curves_off); by=c->sum(sum.(c.vertices)))
141+
142+
# verify that each line matches a possibly circularly shifted or reversed
143+
# line from the offset array
144+
opencurve(a) = first(a) == last(a) ? a[1:end-1] : a
145+
for (c1, c2) in zip(lns, lns_off)
146+
o1 = opencurve(c1.vertices) .+ [offset]
147+
o2 = opencurve(c2.vertices)
148+
m = length(o1)
149+
@test m == length(o2)
150+
cshifts = [circshift(o2,i) for i=1:m]
151+
@test any(o1 c || o1 reverse(c) for c in cshifts)
152+
end
153+
154+
155+
125156
# Test Known Bugs
126157

127158
# Issue #12

0 commit comments

Comments
 (0)