From e18d06da92b6cee236e2cffe01064e2f61a3ebfe Mon Sep 17 00:00:00 2001 From: BenCurran98 Date: Sat, 13 Jul 2024 13:01:42 +0200 Subject: [PATCH 1/8] Define show methods for wrapper geoms --- src/wrappers.jl | 67 +++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 65 insertions(+), 2 deletions(-) diff --git a/src/wrappers.jl b/src/wrappers.jl index 5fbcb527..398b18ab 100644 --- a/src/wrappers.jl +++ b/src/wrappers.jl @@ -88,7 +88,7 @@ function ngeom(trait::AbstractGeometryTrait, geom::WrapperGeometry{<:Any,<:Any,T isgeometry(T) ? ngeom(parent(geom)) : length(parent(geom)) end -# We eefine all the types in a loop so we have standardised docs and behaviour +# We define all the types in a loop so we have standardised docs and behaviour # without too much repetition of code. # `child_trait` and `child_type` define the trait and type of child geometries # a geometry can be constructed from. @@ -171,6 +171,40 @@ for (geomtype, trait, childtype, child_trait, length_check, nesting) in ( convert(::Type{$geomtype}, ::$trait, geom) = $geomtype(geom) # But not if geom is already a WrapperGeometry convert(::Type{$geomtype}, ::$trait, geom::$geomtype) = geom + + function Base.show(io::IO, ::MIME"text/plain", geom::$geomtype{Z, M, T, E, C}; show_mz::Bool = true) where {Z, M, T, E <: Union{Nothing,Extents.Extent}, C} + compact = get(io, :compact, false) + print(io, $geomtype) + if show_mz + print(io, "{$Z, $M}") + end + print(io, "(") + this_geom = getgeom(trait(geom), geom) + if this_geom isa AbstractVector + print(io, "[") + for (i, g) ∈ enumerate(this_geom) + _nice_print_geom(io, g, false) + if i != length(this_geom) + print(io, ",$(compact ? "" : " ")") + end + end + print(io, "]") + else + show(io, g; show_mz = false) + end + if compact + print(io, ")") + else + if !isnothing(geom.extent) + print(", extent = $(geom.extent)") + end + if !isnothing(geom.crs) + print(", crs = $(geom.crs)") + end + print(")") + end + return nothing + end end @eval function $geomtype{Z,M}(geom::T; extent::E=nothing, crs::C=nothing) where {Z,M,T,E,C} Z isa Union{Bool,Nothing} || throw(ArgumentError("Z Parameter must be `true`, `false` or `nothing`")) @@ -228,6 +262,9 @@ for (geomtype, trait, childtype, child_trait, length_check, nesting) in ( end end +_nice_print_geom(io::IO, geom, ::Bool) = show(io, MIME("text/plain"), geom) +_nice_print_geom(io::IO, geom::WrapperGeometry, show_mz::Bool) = Base.show(io, MIME("text/plain"), geom; show_mz = show_mz) + @noinline _wrong_child_error(geomtype, C, child) = throw(ArgumentError("$geomtype must have child objects with trait $C, got $(typeof(child)) with trait $(geomtrait(child))")) @noinline _argument_error(T, A) = throw(ArgumentError("$T does not have $A")) @noinline _length_error(T, f, x) = throw(ArgumentError("Length of array must be $(f.f) $(f.x) for $T")) @@ -333,6 +370,32 @@ function Base.:(==)(g1::Point, g2::Point) end Base.:(!=)(g1::Point, g2::Point) = !(g1 == g2) +function Base.show(io::IO, ::MIME"text/plain", point::Point{Z, M, T, C}) where {Z,M,T,C} + if get(io, :compact, false) + print(io, "Point(") + _print_coords(io, point) + else + print(io, "Point((") + _print_coords(io, point) + print(io, ", Z:$(Z), M:$(M)") + this_crs = crs(point) + if !isnothing(this_crs) + print(io, ", CRS: $(crs(point))") + end + print(io, ")") + end + return nothing +end + +function _print_coords(io::IO, point::Point{Z}) where Z + trait = geomtrait(point) + print(io, "$(x(trait, point)), $(y(trait, point))") + if Z + print(io, "$(z(trait, point))") + end + print(io, ")") +end + @noinline _coord_length_error(Z, M, l) = throw(ArgumentError("Number of coordinates must be $(2 + Z + M) when `Z` is $Z and `M` is $M. Got $l")) @noinline _no_z_error() = throw(ArgumentError("Point has no `Z` coordinate")) @@ -455,4 +518,4 @@ crs(fc::FeatureCollection) = _parent_is_fc(x) = isfeaturecollection(parent(x)) -end # module +end # module \ No newline at end of file From 6792168f157317f46226ab2b9927f2410c2020cb Mon Sep 17 00:00:00 2001 From: BenCurran98 Date: Sat, 13 Jul 2024 14:09:35 +0200 Subject: [PATCH 2/8] Display method for features --- src/wrappers.jl | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/src/wrappers.jl b/src/wrappers.jl index 398b18ab..2cc8642d 100644 --- a/src/wrappers.jl +++ b/src/wrappers.jl @@ -440,6 +440,30 @@ function Feature(geometry=nothing; properties=nothing, crs=nothing, extent=nothi end end +function Base.show(io::IO, ::MIME"text/plain", f::Feature) + print(io, "Feature(") + show(io, MIME("text/plain"), f.parent.geometry) + non_geom_props = filter(!=(:geometry), propertynames(f.parent)) + if !isempty(non_geom_props) + print(io, ", properties = (") + for (i, property) ∈ enumerate(non_geom_props) + print(io, "$(property) = ") + Base.show(io, getproperty(f.parent, property)) + if i != length(non_geom_props) + print(io, ", ") + end + end + print(io, ")") + end + if !isnothing(f.extent) + print(io, ", extent = $(f.extent)") + end + if !isnothing(f.crs) + print(io, ", crs = $(f.crs)") + end + print(io, ")") +end + Base.parent(f::Feature) = f.parent isfeature(::Type{<:Feature}) = true From ce9c806d9d07a7c7c1e7a32b2bfdb740dc45adff Mon Sep 17 00:00:00 2001 From: BenCurran98 Date: Sat, 13 Jul 2024 14:33:51 +0200 Subject: [PATCH 3/8] Vetter show for feature collection --- src/wrappers.jl | 73 +++++++++++++++++++++++++++++++++---------------- 1 file changed, 49 insertions(+), 24 deletions(-) diff --git a/src/wrappers.jl b/src/wrappers.jl index 2cc8642d..62900a29 100644 --- a/src/wrappers.jl +++ b/src/wrappers.jl @@ -370,30 +370,30 @@ function Base.:(==)(g1::Point, g2::Point) end Base.:(!=)(g1::Point, g2::Point) = !(g1 == g2) -function Base.show(io::IO, ::MIME"text/plain", point::Point{Z, M, T, C}) where {Z,M,T,C} - if get(io, :compact, false) - print(io, "Point(") - _print_coords(io, point) - else - print(io, "Point((") - _print_coords(io, point) - print(io, ", Z:$(Z), M:$(M)") - this_crs = crs(point) - if !isnothing(this_crs) - print(io, ", CRS: $(crs(point))") - end - print(io, ")") - end - return nothing -end +function Base.show(io::IO, ::MIME"text/plain", point::Point{Z, M, T, C}; show_mz::Bool = true) where {Z,M,T,C} + print(io, "Point") + this_crs = crs(point) -function _print_coords(io::IO, point::Point{Z}) where Z + compact = get(io, :compact, false) + spacing = compact ? "" : " " + + if !compact && show_mz + print(io, "{$Z, $M}") + end + print(io, "(") trait = geomtrait(point) - print(io, "$(x(trait, point)), $(y(trait, point))") + print(io, "($(x(trait, point)),$(spacing)$(y(trait, point))") if Z - print(io, "$(z(trait, point))") + print(io, ",$(spacing)$(z(trait, point))") + end + print(io, ")") + + if !isnothing(this_crs) + print(io, ",$(spacing)crs$(spacing)=$(spacing)$(this_crs)") end print(io, ")") + + return nothing end @noinline _coord_length_error(Z, M, l) = @@ -441,25 +441,27 @@ function Feature(geometry=nothing; properties=nothing, crs=nothing, extent=nothi end function Base.show(io::IO, ::MIME"text/plain", f::Feature) + compact = get(io, :compact, false) + spacing = compact ? "" : " " print(io, "Feature(") show(io, MIME("text/plain"), f.parent.geometry) non_geom_props = filter(!=(:geometry), propertynames(f.parent)) if !isempty(non_geom_props) - print(io, ", properties = (") + print(io, ", properties$(spacing)=$(spacing)(") for (i, property) ∈ enumerate(non_geom_props) - print(io, "$(property) = ") + print(io, "$(property)$(spacing)=$(spacing)") Base.show(io, getproperty(f.parent, property)) if i != length(non_geom_props) - print(io, ", ") + print(io, ",$(spacing)") end end print(io, ")") end if !isnothing(f.extent) - print(io, ", extent = $(f.extent)") + print(io, ", extent$(spacing)=$(spacing)$(f.extent)") end if !isnothing(f.crs) - print(io, ", crs = $(f.crs)") + print(io, ", crs$(spacing)=$(spacing)$(f.crs)") end print(io, ")") end @@ -522,6 +524,29 @@ function FeatureCollection(parent; crs=nothing, extent=nothing) end end +function Base.show(io::IO, ::MIME"text/plain", fc::FeatureCollection) + print(io, "FeatureCollection(") + compact = get(io, :compact, false) + spacing = compact ? "" : " " + features = _parent_is_fc(fc) ? getfeature(trait(fc), parent(fc)) : parent(fc) + print(io, "[") + for (i, f) ∈ enumerate(features) + show(io, MIME("text/plain"), f) + if i != length(features) + print(io, ",$(spacing)") + end + end + print(io, "]") + if !isnothing(fc.crs) + print(io, ",$(spacing)crs=$(fc.crs)") + end + if !isnothing(fc.extent) + print(io, ",$(spacing)extent=$(fc.extent)") + end + print(io, ")") + return nothing +end + Base.parent(fc::FeatureCollection) = fc.parent _child_feature_error() = throw(ArgumentError("child objects must be features")) From eb545dcee0cc6dd16f0f16d0a53e531a806482cb Mon Sep 17 00:00:00 2001 From: BenCurran98 Date: Sat, 13 Jul 2024 15:01:36 +0200 Subject: [PATCH 4/8] Fix compactness handling in collections --- src/wrappers.jl | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/wrappers.jl b/src/wrappers.jl index 62900a29..f2a2c272 100644 --- a/src/wrappers.jl +++ b/src/wrappers.jl @@ -386,6 +386,9 @@ function Base.show(io::IO, ::MIME"text/plain", point::Point{Z, M, T, C}; show_mz if Z print(io, ",$(spacing)$(z(trait, point))") end + if M + print(io, ",$(spacing)$(m(trait, point))") + end print(io, ")") if !isnothing(this_crs) @@ -440,11 +443,11 @@ function Feature(geometry=nothing; properties=nothing, crs=nothing, extent=nothi end end -function Base.show(io::IO, ::MIME"text/plain", f::Feature) +function Base.show(io::IO, ::MIME"text/plain", f::Feature; show_mz::Bool = true) compact = get(io, :compact, false) spacing = compact ? "" : " " print(io, "Feature(") - show(io, MIME("text/plain"), f.parent.geometry) + Base.show(io, MIME("text/plain"), f.parent.geometry; show_mz = show_mz) non_geom_props = filter(!=(:geometry), propertynames(f.parent)) if !isempty(non_geom_props) print(io, ", properties$(spacing)=$(spacing)(") @@ -531,7 +534,7 @@ function Base.show(io::IO, ::MIME"text/plain", fc::FeatureCollection) features = _parent_is_fc(fc) ? getfeature(trait(fc), parent(fc)) : parent(fc) print(io, "[") for (i, f) ∈ enumerate(features) - show(io, MIME("text/plain"), f) + show(io, MIME("text/plain"), f; show_mz = compact) if i != length(features) print(io, ",$(spacing)") end From e098c3601450606b979a86148e00d1c1adf9955b Mon Sep 17 00:00:00 2001 From: BenCurran98 Date: Sat, 13 Jul 2024 15:25:57 +0200 Subject: [PATCH 5/8] Only show extent/crs when not compact --- src/wrappers.jl | 48 ++++++++++++++++++++++++++++++------------------ 1 file changed, 30 insertions(+), 18 deletions(-) diff --git a/src/wrappers.jl b/src/wrappers.jl index f2a2c272..6630a7ec 100644 --- a/src/wrappers.jl +++ b/src/wrappers.jl @@ -174,9 +174,10 @@ for (geomtype, trait, childtype, child_trait, length_check, nesting) in ( function Base.show(io::IO, ::MIME"text/plain", geom::$geomtype{Z, M, T, E, C}; show_mz::Bool = true) where {Z, M, T, E <: Union{Nothing,Extents.Extent}, C} compact = get(io, :compact, false) + spacing = compact ? "" : " " print(io, $geomtype) if show_mz - print(io, "{$Z, $M}") + print(io, "{$Z,$(spacing)$M}") end print(io, "(") this_geom = getgeom(trait(geom), geom) @@ -185,7 +186,7 @@ for (geomtype, trait, childtype, child_trait, length_check, nesting) in ( for (i, g) ∈ enumerate(this_geom) _nice_print_geom(io, g, false) if i != length(this_geom) - print(io, ",$(compact ? "" : " ")") + print(io, ",$(spacing)") end end print(io, "]") @@ -196,10 +197,12 @@ for (geomtype, trait, childtype, child_trait, length_check, nesting) in ( print(io, ")") else if !isnothing(geom.extent) - print(", extent = $(geom.extent)") + print(",$(spacing)extent$(spacing)=$(spacing)") + show(io, MIME("text/plain"), geom.extent) end if !isnothing(geom.crs) - print(", crs = $(geom.crs)") + print(",$(spacing)crs$(spacing)=$(spacing)") + show(io, MIME("text/plain"), geom.crs) end print(")") end @@ -391,8 +394,9 @@ function Base.show(io::IO, ::MIME"text/plain", point::Point{Z, M, T, C}; show_mz end print(io, ")") - if !isnothing(this_crs) - print(io, ",$(spacing)crs$(spacing)=$(spacing)$(this_crs)") + if !compact && !isnothing(this_crs) + print(io, ",$(spacing)crs$(spacing)=$(spacing)") + show(io, MIME("text/plain"), this_crs) end print(io, ")") @@ -450,7 +454,7 @@ function Base.show(io::IO, ::MIME"text/plain", f::Feature; show_mz::Bool = true) Base.show(io, MIME("text/plain"), f.parent.geometry; show_mz = show_mz) non_geom_props = filter(!=(:geometry), propertynames(f.parent)) if !isempty(non_geom_props) - print(io, ", properties$(spacing)=$(spacing)(") + print(io, ",$(spacing)properties$(spacing)=$(spacing)(") for (i, property) ∈ enumerate(non_geom_props) print(io, "$(property)$(spacing)=$(spacing)") Base.show(io, getproperty(f.parent, property)) @@ -460,11 +464,15 @@ function Base.show(io::IO, ::MIME"text/plain", f::Feature; show_mz::Bool = true) end print(io, ")") end - if !isnothing(f.extent) - print(io, ", extent$(spacing)=$(spacing)$(f.extent)") - end - if !isnothing(f.crs) - print(io, ", crs$(spacing)=$(spacing)$(f.crs)") + if !compact + if !isnothing(f.extent) + print(io, ", extent$(spacing)=$(spacing)") + show(io, MIME("text/plain"), f.extent) + end + if !isnothing(f.crs) + print(io, ", crs$(spacing)=$(spacing)") + show(io, MIME("text/plain"), f.crs) + end end print(io, ")") end @@ -534,17 +542,21 @@ function Base.show(io::IO, ::MIME"text/plain", fc::FeatureCollection) features = _parent_is_fc(fc) ? getfeature(trait(fc), parent(fc)) : parent(fc) print(io, "[") for (i, f) ∈ enumerate(features) - show(io, MIME("text/plain"), f; show_mz = compact) + show(io, MIME("text/plain"), f; show_mz = !compact) if i != length(features) print(io, ",$(spacing)") end end print(io, "]") - if !isnothing(fc.crs) - print(io, ",$(spacing)crs=$(fc.crs)") - end - if !isnothing(fc.extent) - print(io, ",$(spacing)extent=$(fc.extent)") + if !compact + if !isnothing(fc.crs) + print(io, ",$(spacing)crs$(spacing)=$(spacing)") + show(io, MIME("text/plain"), fc.crs) + end + if !isnothing(fc.extent) + print(io, ",$(spacing)extent$(spacing)=$(spacing)") + show(io, MIME("text/plain"), fc.extent) + end end print(io, ")") return nothing From dbc68ca959bc46a28fd9197a69cf89add03bb9bc Mon Sep 17 00:00:00 2001 From: BenCurran98 Date: Fri, 26 Jul 2024 09:06:06 +1000 Subject: [PATCH 6/8] Add tests for display methods --- src/wrappers.jl | 34 +++++++++++++++++---- test/test_wrappers.jl | 71 ++++++++++++++++++++++++++++++++++++++++--- 2 files changed, 95 insertions(+), 10 deletions(-) diff --git a/src/wrappers.jl b/src/wrappers.jl index 6630a7ec..2509d4da 100644 --- a/src/wrappers.jl +++ b/src/wrappers.jl @@ -175,6 +175,7 @@ for (geomtype, trait, childtype, child_trait, length_check, nesting) in ( function Base.show(io::IO, ::MIME"text/plain", geom::$geomtype{Z, M, T, E, C}; show_mz::Bool = true) where {Z, M, T, E <: Union{Nothing,Extents.Extent}, C} compact = get(io, :compact, false) spacing = compact ? "" : " " + show_mz &= !compact print(io, $geomtype) if show_mz print(io, "{$Z,$(spacing)$M}") @@ -193,19 +194,17 @@ for (geomtype, trait, childtype, child_trait, length_check, nesting) in ( else show(io, g; show_mz = false) end - if compact - print(io, ")") - else + if !compact if !isnothing(geom.extent) - print(",$(spacing)extent$(spacing)=$(spacing)") + print(io, ",$(spacing)extent$(spacing)=$(spacing)") show(io, MIME("text/plain"), geom.extent) end if !isnothing(geom.crs) - print(",$(spacing)crs$(spacing)=$(spacing)") + print(io, ",$(spacing)crs$(spacing)=$(spacing)") show(io, MIME("text/plain"), geom.crs) end - print(")") end + print(io, ")") return nothing end end @@ -267,6 +266,29 @@ end _nice_print_geom(io::IO, geom, ::Bool) = show(io, MIME("text/plain"), geom) _nice_print_geom(io::IO, geom::WrapperGeometry, show_mz::Bool) = Base.show(io, MIME("text/plain"), geom; show_mz = show_mz) +# handle tuples/vectors explicitly +function _nice_print_geom(io::IO, geom::AbstractVector, ::Bool) + compact = get(io, :compact, false) + spacing = compact ? "" : " " + print(io, "[") + _print_elements_with_spacing(io, geom, spacing) + print(io, "]") +end + +function _nice_print_geom(io::IO, geom::Tuple, ::Bool) + compact = get(io, :compact, false) + spacing = compact ? "" : " " + print(io, "(") + _print_elements_with_spacing(io, geom, spacing) + print(io, ")") +end + +function _print_elements_with_spacing(io::IO, itr, spacing::String = "") + for x ∈ itr[1:end - 1] + print(io, "$(x),$(spacing)") + end + print(io, itr[end]) +end @noinline _wrong_child_error(geomtype, C, child) = throw(ArgumentError("$geomtype must have child objects with trait $C, got $(typeof(child)) with trait $(geomtrait(child))")) @noinline _argument_error(T, A) = throw(ArgumentError("$T does not have $A")) diff --git a/test/test_wrappers.jl b/test/test_wrappers.jl index f5b77fde..6c374986 100644 --- a/test/test_wrappers.jl +++ b/test/test_wrappers.jl @@ -1,5 +1,20 @@ using Test, GeoFormatTypes, Extents import GeoInterface as GI +using GeoInterface.Wrappers + +# use this to test our string representations for geoms +buf = IOBuffer() +compact_buf = IOContext(buf, :compact => true) + +# checks that our string display for geoms in regular/compact form is as expected +function test_display(geom, expected_str, expected_compact_str) + # checks non-compact string repr + show(buf, MIME"text/plain"(), geom) + @test expected_str == String(take!(buf)) + # checks compact string repr + show(compact_buf, MIME"text/plain"(), geom) + @test expected_compact_str == String(take!(buf)) +end # Point point = GI.Point(1, 2) @@ -16,9 +31,11 @@ GI.getcoord(point, 1) @test_throws ArgumentError GI.Point(1, 2, 3, 4, 5) @test GI.testgeometry(point) @test GI.convert(GI, (1, 2)) isa GI.Point +test_display(point, "Point{false, false}((1, 2))", "Point((1,2))") point_crs = GI.Point(point; crs=EPSG(4326)) @test parent(point_crs) === parent(point) @test GI.crs(point_crs) === EPSG(4326) +test_display(point_crs, "Point{false, false}((1, 2), crs = EPSG{1}((4326,)))", "Point((1,2))") # 3D Point pointz = GI.Point(1, 2, 3) @@ -29,6 +46,7 @@ pointz = GI.Point(1, 2, 3) @test GI.testgeometry(pointz) @test GI.convert(GI, pointz) === pointz @test GI.extent(pointz) == Extents.Extent(X=(1, 1), Y=(2, 2), Z=(3, 3)) +test_display(pointz, "Point{true, false}((1, 2, 3))", "Point((1,2,3))") # 3D measured point pointzm = GI.Point(; X=1, Y=2, Z=3, M=4) @@ -45,6 +63,7 @@ pointzm = GI.Point(; X=1, Y=2, Z=3, M=4) pointzm_crs = GI.Point(; X=1, Y=2, Z=3, M=4, crs=EPSG(4326)) @test parent(pointzm_crs) === parent(pointzm) @test GI.crs(pointzm_crs) === EPSG(4326) +test_display(pointzm, "Point{true, true}((1, 2, 3, 4))", "Point((1,2,3,4))") # Measured point pointm = GI.Point((X=1, Y=2, M=3)) @@ -57,11 +76,13 @@ pointm = GI.Point((X=1, Y=2, M=3)) @test (GI.x(pointm), GI.y(pointm), GI.m(pointm)) == (1, 2, 3) @test_throws ArgumentError GI.z(pointm) @test GI.testgeometry(pointm) +test_display(pointm, "Point{false, true}((1, 2, 3))", "Point((1,2,3))") pointm_crs = GI.Point((X=1, Y=2, M=3); crs=EPSG(4326)) @test parent(pointm_crs) === parent(pointm) @test GI.crs(pointm_crs) === EPSG(4326) +test_display(pointm_crs, "Point{false, true}((1, 2, 3), crs = EPSG{1}((4326,)))", "Point((1,2,3))") -# Foreced measured point with a tuple +# Forced measured point with a tuple pointtm = GI.Point{false,true}(1, 2, 3) @test_throws ArgumentError GI.Point{false,true}(1, 2, 3, 4) @test GI.ismeasured(pointtm) @@ -70,9 +91,11 @@ pointtm = GI.Point{false,true}(1, 2, 3) @test (GI.x(pointtm), GI.y(pointtm), GI.m(pointtm)) == (1, 2, 3) @test_throws ArgumentError GI.z(pointtm) @test GI.testgeometry(pointtm) +test_display(pointtm, "Point{false, true}((1, 2, 3))", "Point((1,2,3))") pointtm_crs = GI.Point{false,true}(1, 2, 3; crs=EPSG(4326)) @test parent(pointtm_crs) === parent(pointtm) @test GI.crs(pointtm_crs) === EPSG(4326) +test_display(pointtm_crs, "Point{false, true}((1, 2, 3), crs = EPSG{1}((4326,)))", "Point((1,2,3))") # Point made from an array pointa = GI.Point([1, 2]) @@ -81,6 +104,7 @@ pointa = GI.Point([1, 2]) @test GI.ncoord(pointa) == 2 @test (GI.x(pointa), GI.y(pointa)) == (1, 2) @test GI.testgeometry(pointa) +test_display(pointa, "Point{false, false}((1, 2))", "Point((1,2))") pointaz = GI.Point([1, 2, 3]) @test !GI.ismeasured(pointaz) @@ -88,6 +112,7 @@ pointaz = GI.Point([1, 2, 3]) @test GI.ncoord(pointaz) == 3 @test (GI.x(pointaz), GI.y(pointaz), GI.z(pointaz)) == (1, 2, 3) @test GI.testgeometry(pointaz) +test_display(pointaz, "Point{true, false}((1, 2, 3))", "Point((1,2,3))") pointazm = GI.Point([1, 2, 3, 4]) @test GI.ismeasured(pointazm) @@ -95,6 +120,7 @@ pointazm = GI.Point([1, 2, 3, 4]) @test GI.ncoord(pointazm) == 4 @test (GI.x(pointazm), GI.y(pointazm), GI.z(pointazm), GI.m(pointazm)) == (1, 2, 3, 4) @test GI.testgeometry(pointazm) +test_display(pointazm, "Point{true, true}((1, 2, 3, 4))", "Point((1,2,3,4))") # We can force a vector point to be measured pointam = GI.Point{false,true}([1, 2, 3]) @@ -104,6 +130,7 @@ pointam = GI.Point{false,true}([1, 2, 3]) @test (GI.x(pointam), GI.y(pointam), GI.m(pointam)) == (1, 2, 3) @test_throws ArgumentError GI.z(pointam) @test GI.testgeometry(pointam) +test_display(pointam, "Point{false, true}((1, 2, 3))", "Point((1,2,3))") @test_throws ArgumentError GI.Point(1, 2, 3, 4, 5) # Line @@ -115,12 +142,14 @@ line = GI.Line([(1, 2), (3, 4)]) @test !GI.is3d(line) @test GI.ncoord(line) == 2 @test GI.extent(line) == Extent(X=(1, 3), Y=(2, 4)) +test_display(line, "Line{false, false}([(1, 2), (3, 4)])", "Line([(1,2),(3,4)])") @test_throws ArgumentError GI.Line(point) @test_throws ArgumentError GI.Line([(1, 2)]) @test_throws ArgumentError GI.Line([line, line]) line_crs = GI.Line(line; crs=EPSG(4326)) @test parent(line_crs) === parent(line) @test GI.crs(line_crs) === EPSG(4326) +test_display(line_crs, "Line{false, false}([(1, 2), (3, 4)], crs = EPSG{1}((4326,)))", "Line([(1,2),(3,4)])") # LineString linestring = GI.LineString([(1, 2), (3, 4)]) @@ -130,11 +159,13 @@ linestring = GI.LineString([(1, 2), (3, 4)]) @test GI.testgeometry(linestring) @test !GI.is3d(linestring) @test GI.ncoord(linestring) == 2 +test_display(linestring, "LineString{false, false}([(1, 2), (3, 4)])", "LineString([(1,2),(3,4)])") @test @inferred(GI.extent(linestring)) == Extent(X=(1, 3), Y=(2, 4)) @test_throws ArgumentError GI.LineString([(1, 2)]) linestring_crs = GI.LineString(linestring; crs=EPSG(4326)) @test parent(linestring_crs) === parent(linestring) @test GI.crs(linestring_crs) === EPSG(4326) +test_display(linestring_crs, "LineString{false, false}([(1, 2), (3, 4)], crs = EPSG{1}((4326,)))", "LineString([(1,2),(3,4)])") # LinearRing linearring = GI.LinearRing([(1, 2), (3, 4), (5, 6), (1, 2)]) @@ -144,11 +175,13 @@ linearring = GI.LinearRing([(1, 2), (3, 4), (5, 6), (1, 2)]) @test GI.testgeometry(linearring) @test !GI.is3d(linearring) @test GI.ncoord(linearring) == 2 +test_display(linearring, "LinearRing{false, false}([(1, 2), (3, 4), (5, 6), (1, 2)])", "LinearRing([(1,2),(3,4),(5,6),(1,2)])") @test @inferred(GI.extent(linearring)) == Extent(X=(1, 5), Y=(2, 6)) @test_throws ArgumentError GI.LinearRing([(1, 2)]) linearring_crs = GI.LinearRing(linearring; crs=EPSG(4326)) @test parent(linearring_crs) === parent(linearring) @test GI.crs(linearring_crs) === EPSG(4326) +test_display(linearring_crs, "LinearRing{false, false}([(1, 2), (3, 4), (5, 6), (1, 2)], crs = EPSG{1}((4326,)))", "LinearRing([(1,2),(3,4),(5,6),(1,2)])") # Polygon polygon = GI.Polygon([linearring, linearring]) @@ -162,19 +195,26 @@ polygon = GI.Polygon([linearring, linearring]) @test @inferred(GI.extent(polygon)) == Extent(X=(1, 5), Y=(2, 6)) @test GI.convert(GI, MyPolygon()) isa GI.Polygon @test GI.convert(GI, polygon) === polygon +test_display(polygon, "Polygon{false, false}([LinearRing([(1, 2), (3, 4), (5, 6), (1, 2)]), LinearRing([(1, 2), (3, 4), (5, 6), (1, 2)])])", + "Polygon([LinearRing([(1,2),(3,4),(5,6),(1,2)]),LinearRing([(1,2),(3,4),(5,6),(1,2)])])") polygon_crs = GI.Polygon(polygon; crs=EPSG(4326)) @test parent(polygon_crs) === parent(polygon) @test GI.crs(polygon_crs) === EPSG(4326) +test_display(polygon_crs, "Polygon{false, false}([LinearRing([(1, 2), (3, 4), (5, 6), (1, 2)]), LinearRing([(1, 2), (3, 4), (5, 6), (1, 2)])], crs = EPSG{1}((4326,)))", + "Polygon([LinearRing([(1,2),(3,4),(5,6),(1,2)]),LinearRing([(1,2),(3,4),(5,6),(1,2)])])") # Make sure `linestring` is also ok in polygons polygon = GI.Polygon([linestring, linestring]) @test GI.getgeom(polygon, 1) === linestring @test collect(GI.getgeom(polygon)) == [linestring, linestring] +test_display(polygon, "Polygon{false, false}([LineString([(1, 2), (3, 4)]), LineString([(1, 2), (3, 4)])])", + "Polygon([LineString([(1,2),(3,4)]),LineString([(1,2),(3,4)])])") linearring3d = GI.LinearRing([(1, 2, 3), (3, 4, 5), (5, 6, 7), (1, 2, 3)]) polygon3d = GI.Polygon([linearring3d, linearring3d]) @test GI.is3d(polygon3d) @test GI.ncoord(polygon3d) == 3 @test GI.extent(polygon3d) == Extents.Extent(X=(1, 5), Y=(2, 6), Z=(3, 7)) +test_display(linearring3d, "LinearRing{true, false}([(1, 2, 3), (3, 4, 5), (5, 6, 7), (1, 2, 3)])", "LinearRing([(1,2,3),(3,4,5),(5,6,7),(1,2,3)])") # MultiPoint multipoint = GI.MultiPoint([(1, 2), (3, 4), (3, 2), (1, 4), (7, 8), (9, 10)]) @@ -185,9 +225,11 @@ multipoint = GI.MultiPoint([(1, 2), (3, 4), (3, 2), (1, 4), (7, 8), (9, 10)]) @test @inferred(GI.extent(multipoint)) == Extent(X=(1, 9), Y=(2, 10)) @test_throws ArgumentError GI.MultiPoint([[(1, 2), (3, 4), (3, 2), (1, 4), (7, 8), (9, 10)]]) @test GI.testgeometry(multipoint) +test_display(multipoint, "MultiPoint{false, false}([(1, 2), (3, 4), (3, 2), (1, 4), (7, 8), (9, 10)])", "MultiPoint([(1,2),(3,4),(3,2),(1,4),(7,8),(9,10)])") multipoint_crs = GI.MultiPoint(multipoint; crs=EPSG(4326)) @test parent(multipoint_crs) == parent(multipoint) @test GI.crs(multipoint_crs) === EPSG(4326) +test_display(multipoint_crs, "MultiPoint{false, false}([(1, 2), (3, 4), (3, 2), (1, 4), (7, 8), (9, 10)], crs = EPSG{1}((4326,)))", "MultiPoint([(1,2),(3,4),(3,2),(1,4),(7,8),(9,10)])") # GeometryCollection geoms = [line, linestring, linearring, multipoint, (1, 2)] @@ -198,9 +240,13 @@ collection = GI.GeometryCollection(geoms) @test !GI.is3d(collection) @test GI.ncoord(collection) == 2 @test GI.extent(collection) == reduce(Extents.union, map(GI.extent, geoms)) +test_display(collection, "GeometryCollection{false, false}([Line([(1, 2), (3, 4)]), LineString([(1, 2), (3, 4)]), LinearRing([(1, 2), (3, 4), (5, 6), (1, 2)]), MultiPoint([(1, 2), (3, 4), (3, 2), (1, 4), (7, 8), (9, 10)]), (1, 2)])", + "GeometryCollection([Line([(1,2),(3,4)]),LineString([(1,2),(3,4)]),LinearRing([(1,2),(3,4),(5,6),(1,2)]),MultiPoint([(1,2),(3,4),(3,2),(1,4),(7,8),(9,10)]),(1,2)])") collection_crs = GI.GeometryCollection(collection; crs=EPSG(4326)) @test parent(collection_crs) == parent(collection) @test GI.crs(collection_crs) === EPSG(4326) +test_display(collection_crs, "GeometryCollection{false, false}([Line([(1, 2), (3, 4)]), LineString([(1, 2), (3, 4)]), LinearRing([(1, 2), (3, 4), (5, 6), (1, 2)]), MultiPoint([(1, 2), (3, 4), (3, 2), (1, 4), (7, 8), (9, 10)]), (1, 2)], crs = EPSG{1}((4326,)))", + "GeometryCollection([Line([(1,2),(3,4)]),LineString([(1,2),(3,4)]),LinearRing([(1,2),(3,4),(5,6),(1,2)]),MultiPoint([(1,2),(3,4),(3,2),(1,4),(7,8),(9,10)]),(1,2)])") # MultiCurve multicurve = GI.MultiCurve([linestring, linearring]) @@ -212,10 +258,13 @@ multicurve = GI.MultiCurve([linestring, linearring]) @test GI.extent(multicurve) == Extent(X=(1, 5), Y=(2, 6)) @test_throws ArgumentError GI.MultiCurve([pointz, polygon]) @test GI.testgeometry(multicurve) +test_display(multicurve, "MultiCurve{false, false}([LineString([(1, 2), (3, 4)]), LinearRing([(1, 2), (3, 4), (5, 6), (1, 2)])])", + "MultiCurve([LineString([(1,2),(3,4)]),LinearRing([(1,2),(3,4),(5,6),(1,2)])])") multicurve_crs = GI.MultiCurve(multicurve; crs=EPSG(4326)) @test parent(multicurve_crs) == parent(multicurve) @test GI.crs(multicurve_crs) === EPSG(4326) - +test_display(multicurve_crs, "MultiCurve{false, false}([LineString([(1, 2), (3, 4)]), LinearRing([(1, 2), (3, 4), (5, 6), (1, 2)])], crs = EPSG{1}((4326,)))", + "MultiCurve([LineString([(1,2),(3,4)]),LinearRing([(1,2),(3,4),(5,6),(1,2)])])") # MultiPolygon polygon = GI.Polygon([linearring, linearring]) @@ -224,8 +273,8 @@ multipolygon = GI.MultiPolygon([polygon]) @test GI.getgeom(multipolygon, 1) === polygon @test !GI.is3d(multipolygon) @test GI.ncoord(multipolygon) == 2 -@show polygon -@show GI.getgeom(polygon, 1) +test_display(multipolygon, "MultiPolygon{false, false}([Polygon([LinearRing([(1, 2), (3, 4), (5, 6), (1, 2)]), LinearRing([(1, 2), (3, 4), (5, 6), (1, 2)])])])", + "MultiPolygon([Polygon([LinearRing([(1,2),(3,4),(5,6),(1,2)]),LinearRing([(1,2),(3,4),(5,6),(1,2)])])])") # MultiPolygon extent does not infer, maybe due to nesting @test GI.extent(multipolygon) == Extent(X=(1, 5), Y=(2, 6)) @test collect(GI.getpoint(multipolygon)) == collect(GI.getpoint(polygon)) @@ -234,6 +283,8 @@ multipolygon = GI.MultiPolygon([polygon]) multipolygon_crs = GI.MultiPolygon(multipolygon; crs=EPSG(4326)) @test parent(multipolygon_crs) == parent(multipolygon) @test GI.crs(multipolygon_crs) === EPSG(4326) +test_display(multipolygon_crs, "MultiPolygon{false, false}([Polygon([LinearRing([(1, 2), (3, 4), (5, 6), (1, 2)]), LinearRing([(1, 2), (3, 4), (5, 6), (1, 2)])])], crs = EPSG{1}((4326,)))", + "MultiPolygon([Polygon([LinearRing([(1,2),(3,4),(5,6),(1,2)]),LinearRing([(1,2),(3,4),(5,6),(1,2)])])])") # PolyhedralSurface polyhedralsurface = GI.PolyhedralSurface([polygon, polygon]) @@ -246,14 +297,20 @@ polyhedralsurface = GI.PolyhedralSurface([polygon, polygon]) @test GI.getgeom(polyhedralsurface, 1) == polygon @test collect(GI.getpoint(polyhedralsurface)) == vcat(collect(GI.getpoint(polygon)), collect(GI.getpoint(polygon))) @test GI.testgeometry(polyhedralsurface) +test_display(polyhedralsurface, "PolyhedralSurface{false, false}([Polygon([LinearRing([(1, 2), (3, 4), (5, 6), (1, 2)]), LinearRing([(1, 2), (3, 4), (5, 6), (1, 2)])]), Polygon([LinearRing([(1, 2), (3, 4), (5, 6), (1, 2)]), LinearRing([(1, 2), (3, 4), (5, 6), (1, 2)])])])", + "PolyhedralSurface([Polygon([LinearRing([(1,2),(3,4),(5,6),(1,2)]),LinearRing([(1,2),(3,4),(5,6),(1,2)])]),Polygon([LinearRing([(1,2),(3,4),(5,6),(1,2)]),LinearRing([(1,2),(3,4),(5,6),(1,2)])])])") polyhedralsurface_crs = GI.PolyhedralSurface(polyhedralsurface; crs=EPSG(4326)) @test parent(polyhedralsurface_crs) == parent(polyhedralsurface) @test GI.crs(polyhedralsurface_crs) === EPSG(4326) +test_display(polyhedralsurface_crs, "PolyhedralSurface{false, false}([Polygon([LinearRing([(1, 2), (3, 4), (5, 6), (1, 2)]), LinearRing([(1, 2), (3, 4), (5, 6), (1, 2)])]), Polygon([LinearRing([(1, 2), (3, 4), (5, 6), (1, 2)]), LinearRing([(1, 2), (3, 4), (5, 6), (1, 2)])])], crs = EPSG{1}((4326,)))", + "PolyhedralSurface([Polygon([LinearRing([(1,2),(3,4),(5,6),(1,2)]),LinearRing([(1,2),(3,4),(5,6),(1,2)])]),Polygon([LinearRing([(1,2),(3,4),(5,6),(1,2)]),LinearRing([(1,2),(3,4),(5,6),(1,2)])])])") # Round-trip coordinates multipolygon_coords = [[[[1, 2], [3, 4], [3, 2], [1, 4]]]] multipolygon = GI.MultiPolygon(multipolygon_coords) @test GI.coordinates(multipolygon) == multipolygon_coords +test_display(multipolygon, "MultiPolygon{false, false}([Polygon([LinearRing([[1, 2], [3, 4], [3, 2], [1, 4]])])])", + "MultiPolygon([Polygon([LinearRing([[1,2],[3,4],[3,2],[1,4]])])])") # Wrong parent type @test_throws ArgumentError GI.Point(nothing) @@ -270,9 +327,13 @@ feature = GI.Feature(multipolygon; properties=(x=1, y=2, z=3)) @test GI.crs(feature) == nothing @test GI.extent(feature) == GI.extent(multipolygon) @test GI.testfeature(feature) +test_display(feature, "Feature(MultiPolygon{false, false}([Polygon([LinearRing([[1, 2], [3, 4], [3, 2], [1, 4]])])]), properties = (x = 1, y = 2, z = 3))", + "Feature(MultiPolygon([Polygon([LinearRing([[1,2],[3,4],[3,2],[1,4]])])]),properties=(x=1,y=2,z=3))") feature = GI.Feature(multipolygon; properties=(x=1, y=2, z=3), crs=EPSG(4326), extent=extent(multipolygon) ) +test_display(feature, "Feature(MultiPolygon{false, false}([Polygon([LinearRing([[1, 2], [3, 4], [3, 2], [1, 4]])])]), properties = (x = 1, y = 2, z = 3), crs = EPSG{1}((4326,)))", + "Feature(MultiPolygon([Polygon([LinearRing([[1,2],[3,4],[3,2],[1,4]])])]),properties=(x=1,y=2,z=3))") @test GI.geometry(feature) === multipolygon @test GI.properties(feature) === (x=1, y=2, z=3) @test GI.crs(feature) == EPSG(4326) @@ -287,6 +348,8 @@ fc = GI.FeatureCollection([feature]; crs=EPSG(4326), extent=GI.extent(feature)) @test GI.extent(fc) == fc.extent @test first(GI.getfeature(fc)) == GI.getfeature(fc, 1) === feature @test GI.testfeaturecollection(fc) +test_display(fc, "FeatureCollection([Feature(MultiPolygon{false, false}([Polygon([LinearRing([[1, 2], [3, 4], [3, 2], [1, 4]])])]), properties = (x = 1, y = 2, z = 3), crs = EPSG{1}((4326,)))], crs = EPSG{1}((4326,)), extent = Extent(X = (1, 3), Y = (2, 4)))", + "FeatureCollection([Feature(MultiPolygon([Polygon([LinearRing([[1,2],[3,4],[3,2],[1,4]])])]),properties=(x=1,y=2,z=3))])") @test_throws ArgumentError GI.FeatureCollection([1]) vecfc = GI.FeatureCollection([(geometry=(1,2), a=1, b=2)]) @test GI.getfeature(vecfc, 1) == (geometry=(1,2), a=1, b=2) From 5dde3092b0898878950d6b6aea01a1a648f6688b Mon Sep 17 00:00:00 2001 From: BenCurran98 Date: Fri, 2 Aug 2024 15:47:48 +1000 Subject: [PATCH 7/8] Attempt at compressing string length --- src/wrappers.jl | 110 ++++++++++++++++++++++++++++++++---------------- 1 file changed, 74 insertions(+), 36 deletions(-) diff --git a/src/wrappers.jl b/src/wrappers.jl index 2509d4da..56834867 100644 --- a/src/wrappers.jl +++ b/src/wrappers.jl @@ -176,35 +176,61 @@ for (geomtype, trait, childtype, child_trait, length_check, nesting) in ( compact = get(io, :compact, false) spacing = compact ? "" : " " show_mz &= !compact - print(io, $geomtype) + screen_nrows, screen_ncols = displaysize(io) + + extent_str = "" + crs_str = "" + if !compact + if !isnothing(geom.extent) + extent_str = ",$(spacing)extent$(spacing)=$(spacing)$(repr(MIME("text/plain"), geom.extent))" + end + if !isnothing(geom.crs) + crs_str = ",$(spacing)crs$(spacing)=$(spacing)$(repr(MIME("text/plain"), geom.crs))" + end + end + + str = "$($geomtype)" if show_mz - print(io, "{$Z,$(spacing)$M}") + str *= "{$Z,$(spacing)$M}" end - print(io, "(") + str *= "(" this_geom = getgeom(trait(geom), geom) if this_geom isa AbstractVector - print(io, "[") - for (i, g) ∈ enumerate(this_geom) - _nice_print_geom(io, g, false) - if i != length(this_geom) - print(io, ",$(spacing)") - end + # check here if we have enough room to display the whole object or if we need to condense the string + str *= "[" + currently_used_space = textwidth(str) + textwidth(extent_str) + textwidth(crs_str) + 2 # +2 for brackets + length_of_one_object_in_chars = textwidth(_nice_geom_str(this_geom[1], false, compact)) + num_objects_to_show = min(length(this_geom), floor(Int, (screen_ncols - currently_used_space - 1 #=triple dot character =#) / length_of_one_object_in_chars)) + + num_shown_each_side = ceil(Int, num_objects_to_show/2) + num_missing = length(this_geom) - num_objects_to_show + + for i ∈ 1:num_shown_each_side + str *= "$(_nice_geom_str(this_geom[i], false, compact)),$(spacing)" end - print(io, "]") - else - show(io, g; show_mz = false) - end - if !compact - if !isnothing(geom.extent) - print(io, ",$(spacing)extent$(spacing)=$(spacing)") - show(io, MIME("text/plain"), geom.extent) + + if num_missing > 0 + # report how many geometries aren't shown here + str *= " … ($(num_missing)) … " end - if !isnothing(geom.crs) - print(io, ",$(spacing)crs$(spacing)=$(spacing)") - show(io, MIME("text/plain"), geom.crs) + + for i ∈ 1:num_shown_each_side + str *= _nice_geom_str(this_geom[end - num_shown_each_side + i], false, compact) + if i != num_shown_each_side + str *= ",$(spacing)" + end end + + str *= "]" + else + str *= _nice_geom_str(g, false, compact) end - print(io, ")") + + str *= extent_str + str *= crs_str + + str *= ")" + print(io, str) return nothing end end @@ -264,30 +290,42 @@ for (geomtype, trait, childtype, child_trait, length_check, nesting) in ( end end -_nice_print_geom(io::IO, geom, ::Bool) = show(io, MIME("text/plain"), geom) -_nice_print_geom(io::IO, geom::WrapperGeometry, show_mz::Bool) = Base.show(io, MIME("text/plain"), geom; show_mz = show_mz) +function _nice_geom_str(geom, ::Bool, ::Bool) + io = IOBuffer() + show(io, MIME("text/plain"), geom) + return String(take!(io)) +end + +# need a work around to pass the show_mz variable through - put string to a temp IOBuffer then read it +function _nice_geom_str(geom::WrapperGeometry, show_mz::Bool, ::Bool) + io = IOBuffer() + show(io, MIME("text/plain"), geom; show_mz = show_mz) + return String(take!(io)) +end + # handle tuples/vectors explicitly -function _nice_print_geom(io::IO, geom::AbstractVector, ::Bool) - compact = get(io, :compact, false) +function _nice_geom_str(geom::AbstractVector, ::Bool, compact::Bool) spacing = compact ? "" : " " - print(io, "[") - _print_elements_with_spacing(io, geom, spacing) - print(io, "]") + str = "[" + str *= _add_elements_with_spacing(geom, spacing) + str *= "]" + return str end -function _nice_print_geom(io::IO, geom::Tuple, ::Bool) - compact = get(io, :compact, false) +function _nice_geom_str(geom::Tuple, ::Bool, compact::Bool) spacing = compact ? "" : " " - print(io, "(") - _print_elements_with_spacing(io, geom, spacing) - print(io, ")") + str = "(" + str *= _add_elements_with_spacing(geom, spacing) + str *= ")" + return str end -function _print_elements_with_spacing(io::IO, itr, spacing::String = "") +function _add_elements_with_spacing(itr, spacing::String = "") + str = "" for x ∈ itr[1:end - 1] - print(io, "$(x),$(spacing)") + str *= "$(x),$(spacing)" end - print(io, itr[end]) + str *= "$(itr[end])" end @noinline _wrong_child_error(geomtype, C, child) = throw(ArgumentError("$geomtype must have child objects with trait $C, got $(typeof(child)) with trait $(geomtrait(child))")) From 640bfca41ed084124230b408c2c50f865d40f1ad Mon Sep 17 00:00:00 2001 From: BenCurran98 Date: Mon, 4 Nov 2024 12:50:52 +1000 Subject: [PATCH 8/8] Make logic to skip entries smarter for nested geoms --- src/wrappers.jl | 54 ++++++++++++++++++++++++++----------------- test/test_wrappers.jl | 38 +++++++++++++++--------------- 2 files changed, 52 insertions(+), 40 deletions(-) diff --git a/src/wrappers.jl b/src/wrappers.jl index 56834867..7aaa8628 100644 --- a/src/wrappers.jl +++ b/src/wrappers.jl @@ -172,11 +172,10 @@ for (geomtype, trait, childtype, child_trait, length_check, nesting) in ( # But not if geom is already a WrapperGeometry convert(::Type{$geomtype}, ::$trait, geom::$geomtype) = geom - function Base.show(io::IO, ::MIME"text/plain", geom::$geomtype{Z, M, T, E, C}; show_mz::Bool = true) where {Z, M, T, E <: Union{Nothing,Extents.Extent}, C} + function Base.show(io::IO, ::MIME"text/plain", geom::$geomtype{Z, M, T, E, C}; show_mz::Bool = true, screen_ncols::Int = displaysize(io)[2]) where {Z, M, T, E <: Union{Nothing,Extents.Extent}, C} compact = get(io, :compact, false) spacing = compact ? "" : " " show_mz &= !compact - screen_nrows, screen_ncols = displaysize(io) extent_str = "" crs_str = "" @@ -195,35 +194,47 @@ for (geomtype, trait, childtype, child_trait, length_check, nesting) in ( end str *= "(" this_geom = getgeom(trait(geom), geom) + # keep track of how much space we've used + make sure we give this info to any child geoms so they don't go over the limit + currently_used_space = textwidth(str) + textwidth(extent_str) + textwidth(crs_str) if this_geom isa AbstractVector # check here if we have enough room to display the whole object or if we need to condense the string str *= "[" - currently_used_space = textwidth(str) + textwidth(extent_str) + textwidth(crs_str) + 2 # +2 for brackets - length_of_one_object_in_chars = textwidth(_nice_geom_str(this_geom[1], false, compact)) - num_objects_to_show = min(length(this_geom), floor(Int, (screen_ncols - currently_used_space - 1 #=triple dot character =#) / length_of_one_object_in_chars)) + currently_used_space += 2 # +2 for brackets + available_space = screen_ncols - currently_used_space + + space_per_object = floor(Int, available_space / length(this_geom)) + + length_of_one_object_in_chars = textwidth(_nice_geom_str(this_geom[1], false, compact, space_per_object)) + + # this makes sure that if we have 1 or 2 geometries here, we show both, but any more and we skip them + num_objects_to_show = min(length(this_geom), max(2, floor(Int, (available_space - 1 #=triple dot character =#) / length_of_one_object_in_chars))) + + # separately track how many objects to show to the left and right of the ...()... + num_objects_left = num_objects_to_show == 1 ? 0 : ceil(Int, num_objects_to_show/2) + num_objects_right = max(1, floor(Int, num_objects_to_show/2)) - num_shown_each_side = ceil(Int, num_objects_to_show/2) - num_missing = length(this_geom) - num_objects_to_show + # how many objects are we skipping? + num_missing = length(this_geom) - (num_objects_left + num_objects_right) - for i ∈ 1:num_shown_each_side - str *= "$(_nice_geom_str(this_geom[i], false, compact)),$(spacing)" + for i ∈ 1:num_objects_left + str *= "$(_nice_geom_str(this_geom[i], false, compact, space_per_object)),$(spacing)" end if num_missing > 0 # report how many geometries aren't shown here - str *= " … ($(num_missing)) … " + str *= "…$(spacing)($(num_missing))$(spacing)…$(spacing),$(spacing)" end - for i ∈ 1:num_shown_each_side - str *= _nice_geom_str(this_geom[end - num_shown_each_side + i], false, compact) - if i != num_shown_each_side + for i ∈ 1:num_objects_right + str *= _nice_geom_str(this_geom[end - num_objects_right + i], false, compact, space_per_object) + if i != num_objects_right str *= ",$(spacing)" end end str *= "]" else - str *= _nice_geom_str(g, false, compact) + str *= _nice_geom_str(g, false, compact, screen_ncols - currently_used_space) end str *= extent_str @@ -290,21 +301,22 @@ for (geomtype, trait, childtype, child_trait, length_check, nesting) in ( end end -function _nice_geom_str(geom, ::Bool, ::Bool) +function _nice_geom_str(geom, ::Bool, ::Bool, ::Int) io = IOBuffer() show(io, MIME("text/plain"), geom) return String(take!(io)) end # need a work around to pass the show_mz variable through - put string to a temp IOBuffer then read it -function _nice_geom_str(geom::WrapperGeometry, show_mz::Bool, ::Bool) - io = IOBuffer() - show(io, MIME("text/plain"), geom; show_mz = show_mz) - return String(take!(io)) +function _nice_geom_str(geom::WrapperGeometry, show_mz::Bool, compact::Bool, screen_ncols::Int) + buf = IOBuffer() + io = IOContext(IOContext(buf, :compact => compact)) + show(io, MIME("text/plain"), geom; show_mz = show_mz, screen_ncols = screen_ncols) + return String(take!(buf)) end # handle tuples/vectors explicitly -function _nice_geom_str(geom::AbstractVector, ::Bool, compact::Bool) +function _nice_geom_str(geom::AbstractVector, ::Bool, compact::Bool, ::Int) spacing = compact ? "" : " " str = "[" str *= _add_elements_with_spacing(geom, spacing) @@ -312,7 +324,7 @@ function _nice_geom_str(geom::AbstractVector, ::Bool, compact::Bool) return str end -function _nice_geom_str(geom::Tuple, ::Bool, compact::Bool) +function _nice_geom_str(geom::Tuple, ::Bool, compact::Bool, ::Int) spacing = compact ? "" : " " str = "(" str *= _add_elements_with_spacing(geom, spacing) diff --git a/test/test_wrappers.jl b/test/test_wrappers.jl index 6c374986..e7764b6a 100644 --- a/test/test_wrappers.jl +++ b/test/test_wrappers.jl @@ -195,12 +195,12 @@ polygon = GI.Polygon([linearring, linearring]) @test @inferred(GI.extent(polygon)) == Extent(X=(1, 5), Y=(2, 6)) @test GI.convert(GI, MyPolygon()) isa GI.Polygon @test GI.convert(GI, polygon) === polygon -test_display(polygon, "Polygon{false, false}([LinearRing([(1, 2), (3, 4), (5, 6), (1, 2)]), LinearRing([(1, 2), (3, 4), (5, 6), (1, 2)])])", +test_display(polygon, "Polygon{false, false}([LinearRing([(1, 2), … (2) … , (1, 2)]), LinearRing([(1, 2), … (2) … , (1, 2)])])", "Polygon([LinearRing([(1,2),(3,4),(5,6),(1,2)]),LinearRing([(1,2),(3,4),(5,6),(1,2)])])") polygon_crs = GI.Polygon(polygon; crs=EPSG(4326)) @test parent(polygon_crs) === parent(polygon) @test GI.crs(polygon_crs) === EPSG(4326) -test_display(polygon_crs, "Polygon{false, false}([LinearRing([(1, 2), (3, 4), (5, 6), (1, 2)]), LinearRing([(1, 2), (3, 4), (5, 6), (1, 2)])], crs = EPSG{1}((4326,)))", +test_display(polygon_crs, "Polygon{false, false}([LinearRing([(1, 2), … (2) … , (1, 2)]), LinearRing([(1, 2), … (2) … , (1, 2)])], crs = EPSG{1}((4326,)))", "Polygon([LinearRing([(1,2),(3,4),(5,6),(1,2)]),LinearRing([(1,2),(3,4),(5,6),(1,2)])])") # Make sure `linestring` is also ok in polygons polygon = GI.Polygon([linestring, linestring]) @@ -229,7 +229,7 @@ test_display(multipoint, "MultiPoint{false, false}([(1, 2), (3, 4), (3, 2), (1, multipoint_crs = GI.MultiPoint(multipoint; crs=EPSG(4326)) @test parent(multipoint_crs) == parent(multipoint) @test GI.crs(multipoint_crs) === EPSG(4326) -test_display(multipoint_crs, "MultiPoint{false, false}([(1, 2), (3, 4), (3, 2), (1, 4), (7, 8), (9, 10)], crs = EPSG{1}((4326,)))", "MultiPoint([(1,2),(3,4),(3,2),(1,4),(7,8),(9,10)])") +test_display(multipoint_crs, "MultiPoint{false, false}([(1, 2), (3, 4), … (2) … , (7, 8), (9, 10)], crs = EPSG{1}((4326,)))", "MultiPoint([(1,2),(3,4),(3,2),(1,4),(7,8),(9,10)])") # GeometryCollection geoms = [line, linestring, linearring, multipoint, (1, 2)] @@ -240,13 +240,13 @@ collection = GI.GeometryCollection(geoms) @test !GI.is3d(collection) @test GI.ncoord(collection) == 2 @test GI.extent(collection) == reduce(Extents.union, map(GI.extent, geoms)) -test_display(collection, "GeometryCollection{false, false}([Line([(1, 2), (3, 4)]), LineString([(1, 2), (3, 4)]), LinearRing([(1, 2), (3, 4), (5, 6), (1, 2)]), MultiPoint([(1, 2), (3, 4), (3, 2), (1, 4), (7, 8), (9, 10)]), (1, 2)])", - "GeometryCollection([Line([(1,2),(3,4)]),LineString([(1,2),(3,4)]),LinearRing([(1,2),(3,4),(5,6),(1,2)]),MultiPoint([(1,2),(3,4),(3,2),(1,4),(7,8),(9,10)]),(1,2)])") +test_display(collection, "GeometryCollection{false, false}([Line([(1, 2), (3, 4)]), … (3) … , (1, 2)])", + "GeometryCollection([Line([(1,2),(3,4)]),LineString([(1,2),(3,4)]),…(2)…,(1,2)])") collection_crs = GI.GeometryCollection(collection; crs=EPSG(4326)) @test parent(collection_crs) == parent(collection) @test GI.crs(collection_crs) === EPSG(4326) -test_display(collection_crs, "GeometryCollection{false, false}([Line([(1, 2), (3, 4)]), LineString([(1, 2), (3, 4)]), LinearRing([(1, 2), (3, 4), (5, 6), (1, 2)]), MultiPoint([(1, 2), (3, 4), (3, 2), (1, 4), (7, 8), (9, 10)]), (1, 2)], crs = EPSG{1}((4326,)))", - "GeometryCollection([Line([(1,2),(3,4)]),LineString([(1,2),(3,4)]),LinearRing([(1,2),(3,4),(5,6),(1,2)]),MultiPoint([(1,2),(3,4),(3,2),(1,4),(7,8),(9,10)]),(1,2)])") +test_display(collection_crs, "GeometryCollection{false, false}([Line([(1, 2), (3, 4)]), … (3) … , (1, 2)], crs = EPSG{1}((4326,)))", + "GeometryCollection([Line([(1,2),(3,4)]),LineString([(1,2),(3,4)]),…(2)…,(1,2)])") # MultiCurve multicurve = GI.MultiCurve([linestring, linearring]) @@ -258,13 +258,13 @@ multicurve = GI.MultiCurve([linestring, linearring]) @test GI.extent(multicurve) == Extent(X=(1, 5), Y=(2, 6)) @test_throws ArgumentError GI.MultiCurve([pointz, polygon]) @test GI.testgeometry(multicurve) -test_display(multicurve, "MultiCurve{false, false}([LineString([(1, 2), (3, 4)]), LinearRing([(1, 2), (3, 4), (5, 6), (1, 2)])])", - "MultiCurve([LineString([(1,2),(3,4)]),LinearRing([(1,2),(3,4),(5,6),(1,2)])])") +test_display(multicurve, "MultiCurve{false, false}([LineString([(1, 2), (3, 4)]), LinearRing([(1, 2), … (2) … , (1, 2)])])", + "MultiCurve([LineString([(1,2),(3,4)]),LinearRing([(1,2),(3,4),…(1)…,(1,2)])])") multicurve_crs = GI.MultiCurve(multicurve; crs=EPSG(4326)) @test parent(multicurve_crs) == parent(multicurve) @test GI.crs(multicurve_crs) === EPSG(4326) -test_display(multicurve_crs, "MultiCurve{false, false}([LineString([(1, 2), (3, 4)]), LinearRing([(1, 2), (3, 4), (5, 6), (1, 2)])], crs = EPSG{1}((4326,)))", - "MultiCurve([LineString([(1,2),(3,4)]),LinearRing([(1,2),(3,4),(5,6),(1,2)])])") +test_display(multicurve_crs, "MultiCurve{false, false}([LineString([(1, 2), (3, 4)]), LinearRing([(1, 2), … (2) … , (1, 2)])], crs = EPSG{1}((4326,)))", + "MultiCurve([LineString([(1,2),(3,4)]),LinearRing([(1,2),(3,4),…(1)…,(1,2)])])") # MultiPolygon polygon = GI.Polygon([linearring, linearring]) @@ -273,8 +273,8 @@ multipolygon = GI.MultiPolygon([polygon]) @test GI.getgeom(multipolygon, 1) === polygon @test !GI.is3d(multipolygon) @test GI.ncoord(multipolygon) == 2 -test_display(multipolygon, "MultiPolygon{false, false}([Polygon([LinearRing([(1, 2), (3, 4), (5, 6), (1, 2)]), LinearRing([(1, 2), (3, 4), (5, 6), (1, 2)])])])", - "MultiPolygon([Polygon([LinearRing([(1,2),(3,4),(5,6),(1,2)]),LinearRing([(1,2),(3,4),(5,6),(1,2)])])])") +test_display(multipolygon, "MultiPolygon{false, false}([Polygon([LinearRing([(1, 2), … (2) … , (1, 2)]), LinearRing([(1, 2), … (2) … , (1, 2)])])])", + "MultiPolygon([Polygon([LinearRing([(1,2),…(2)…,(1,2)]),LinearRing([(1,2),…(2)…,(1,2)])])])") # MultiPolygon extent does not infer, maybe due to nesting @test GI.extent(multipolygon) == Extent(X=(1, 5), Y=(2, 6)) @test collect(GI.getpoint(multipolygon)) == collect(GI.getpoint(polygon)) @@ -283,8 +283,8 @@ test_display(multipolygon, "MultiPolygon{false, false}([Polygon([LinearRing([(1, multipolygon_crs = GI.MultiPolygon(multipolygon; crs=EPSG(4326)) @test parent(multipolygon_crs) == parent(multipolygon) @test GI.crs(multipolygon_crs) === EPSG(4326) -test_display(multipolygon_crs, "MultiPolygon{false, false}([Polygon([LinearRing([(1, 2), (3, 4), (5, 6), (1, 2)]), LinearRing([(1, 2), (3, 4), (5, 6), (1, 2)])])], crs = EPSG{1}((4326,)))", - "MultiPolygon([Polygon([LinearRing([(1,2),(3,4),(5,6),(1,2)]),LinearRing([(1,2),(3,4),(5,6),(1,2)])])])") +test_display(multipolygon_crs, "MultiPolygon{false, false}([Polygon([LinearRing([(1, 2), … (2) … , (1, 2)]), LinearRing([(1, 2), … (2) … , (1, 2)])])], crs = EPSG{1}((4326,)))", + "MultiPolygon([Polygon([LinearRing([(1,2),…(2)…,(1,2)]),LinearRing([(1,2),…(2)…,(1,2)])])])") # PolyhedralSurface polyhedralsurface = GI.PolyhedralSurface([polygon, polygon]) @@ -297,13 +297,13 @@ polyhedralsurface = GI.PolyhedralSurface([polygon, polygon]) @test GI.getgeom(polyhedralsurface, 1) == polygon @test collect(GI.getpoint(polyhedralsurface)) == vcat(collect(GI.getpoint(polygon)), collect(GI.getpoint(polygon))) @test GI.testgeometry(polyhedralsurface) -test_display(polyhedralsurface, "PolyhedralSurface{false, false}([Polygon([LinearRing([(1, 2), (3, 4), (5, 6), (1, 2)]), LinearRing([(1, 2), (3, 4), (5, 6), (1, 2)])]), Polygon([LinearRing([(1, 2), (3, 4), (5, 6), (1, 2)]), LinearRing([(1, 2), (3, 4), (5, 6), (1, 2)])])])", - "PolyhedralSurface([Polygon([LinearRing([(1,2),(3,4),(5,6),(1,2)]),LinearRing([(1,2),(3,4),(5,6),(1,2)])]),Polygon([LinearRing([(1,2),(3,4),(5,6),(1,2)]),LinearRing([(1,2),(3,4),(5,6),(1,2)])])])") +test_display(polyhedralsurface, "PolyhedralSurface{false, false}([Polygon([LinearRing([(1, 2), … (2) … , (1, 2)]), LinearRing([(1, 2), … (2) … , (1, 2)])]), Polygon([LinearRing([(1, 2), … (2) … , (1, 2)]), LinearRing([(1, 2), … (2) … , (1, 2)])])])", + "PolyhedralSurface([Polygon([LinearRing([(1,2),…(2)…,(1,2)]),LinearRing([(1,2),…(2)…,(1,2)])]),Polygon([LinearRing([(1,2),…(2)…,(1,2)]),LinearRing([(1,2),…(2)…,(1,2)])])])") polyhedralsurface_crs = GI.PolyhedralSurface(polyhedralsurface; crs=EPSG(4326)) @test parent(polyhedralsurface_crs) == parent(polyhedralsurface) @test GI.crs(polyhedralsurface_crs) === EPSG(4326) -test_display(polyhedralsurface_crs, "PolyhedralSurface{false, false}([Polygon([LinearRing([(1, 2), (3, 4), (5, 6), (1, 2)]), LinearRing([(1, 2), (3, 4), (5, 6), (1, 2)])]), Polygon([LinearRing([(1, 2), (3, 4), (5, 6), (1, 2)]), LinearRing([(1, 2), (3, 4), (5, 6), (1, 2)])])], crs = EPSG{1}((4326,)))", - "PolyhedralSurface([Polygon([LinearRing([(1,2),(3,4),(5,6),(1,2)]),LinearRing([(1,2),(3,4),(5,6),(1,2)])]),Polygon([LinearRing([(1,2),(3,4),(5,6),(1,2)]),LinearRing([(1,2),(3,4),(5,6),(1,2)])])])") +test_display(polyhedralsurface_crs, "PolyhedralSurface{false, false}([Polygon([LinearRing([(1, 2), … (2) … , (1, 2)]), LinearRing([(1, 2), … (2) … , (1, 2)])]), Polygon([LinearRing([(1, 2), … (2) … , (1, 2)]), LinearRing([(1, 2), … (2) … , (1, 2)])])], crs = EPSG{1}((4326,)))", + "PolyhedralSurface([Polygon([LinearRing([(1,2),…(2)…,(1,2)]),LinearRing([(1,2),…(2)…,(1,2)])]),Polygon([LinearRing([(1,2),…(2)…,(1,2)]),LinearRing([(1,2),…(2)…,(1,2)])])])") # Round-trip coordinates multipolygon_coords = [[[[1, 2], [3, 4], [3, 2], [1, 4]]]]