From f0fd7e3ca43227d7d764fc48bd3589d8bc214bef Mon Sep 17 00:00:00 2001 From: ARSH SHARMA <184517@nith.ac.in> Date: Mon, 27 Jul 2020 21:12:21 +0530 Subject: [PATCH 01/24] Test out meta --- src/GeometryBasics.jl | 1 + src/metatest.jl | 20 ++++++++++++++++++++ 2 files changed, 21 insertions(+) create mode 100644 src/metatest.jl diff --git a/src/GeometryBasics.jl b/src/GeometryBasics.jl index 9dcef8b2..41111d3f 100644 --- a/src/GeometryBasics.jl +++ b/src/GeometryBasics.jl @@ -16,6 +16,7 @@ module GeometryBasics include("meshes.jl") include("lines.jl") include("boundingboxes.jl") + include("metatest.jl") export AbstractGeometry, GeometryPrimitive export Mat, Point, Vec diff --git a/src/metatest.jl b/src/metatest.jl new file mode 100644 index 00000000..8e2fa962 --- /dev/null +++ b/src/metatest.jl @@ -0,0 +1,20 @@ +struct metag{T, Names, Types} + data::T + rest::NamedTuple{Names, Types} +end + +metag(x; kwargs...) = metag(x, values(kwargs)) + +Base.getproperty(mg::metag, s::Symbol) = s == :data ? getfield(mg, 1) : getproperty(getfield(mg, 2), s) + +getnamestypes(::Type{metag{T, Names, Types}}) where {T, Names, Types} = (T, Names, Types) + +function StructArrays.staticschema(::Type{mg}) where {mg<:metag} + T, names, types = getnamestypes(mg) + NamedTuple{(:data, names...), Base.tuple_type_cons(T, types)} +end + +function StructArrays.createinstance(::Type{mg}, x, args...) where {mg<:metag} + T, names, types = getnamestypes(mg) + metag(x, NamedTuple{names, types}(args)) +end From cc44ac0a1d46c7ba0c19ae207b466c4f44337b4d Mon Sep 17 00:00:00 2001 From: ARSH SHARMA <184517@nith.ac.in> Date: Tue, 28 Jul 2020 20:46:48 +0530 Subject: [PATCH 02/24] Add new implementation --- src/GeometryBasics.jl | 2 -- src/metadata.jl | 32 ++++++++++++++++++++++++++++++++ 2 files changed, 32 insertions(+), 2 deletions(-) diff --git a/src/GeometryBasics.jl b/src/GeometryBasics.jl index 41111d3f..b1ed1e51 100644 --- a/src/GeometryBasics.jl +++ b/src/GeometryBasics.jl @@ -16,7 +16,6 @@ module GeometryBasics include("meshes.jl") include("lines.jl") include("boundingboxes.jl") - include("metatest.jl") export AbstractGeometry, GeometryPrimitive export Mat, Point, Vec @@ -30,7 +29,6 @@ module GeometryBasics export OffsetInteger, ZeroIndex, OneIndex, GLIndex export FaceView, SimpleFaceView export AbstractPoint, PointMeta, PointWithUV - export PolygonMeta, MultiPointMeta, MultiLineStringMeta, MeshMeta, LineStringMeta, MultiPolygonMeta export decompose, coordinates, faces, normals, decompose_uv, decompose_normals, texturecoordinates export Tesselation, pointmeta, Normal, UV, UVW export GLTriangleFace, GLNormalMesh3D, GLPlainTriangleMesh, GLUVMesh3D, GLUVNormalMesh3D diff --git a/src/metadata.jl b/src/metadata.jl index 16983a73..246bfca2 100644 --- a/src/metadata.jl +++ b/src/metadata.jl @@ -1,3 +1,30 @@ +struct Feature{T, Names, Types} #have a better name? + data::T + rest::NamedTuple{Names, Types} +end + +Feature(x; kwargs...) = Feature(x, values(kwargs)) + +Base.getproperty(f::Feature, s::Symbol) = s == :data ? getfield(f, 1) : s == :rest ? getfield(f, 2) : getproperty(getfield(f, 2), s) +Base.propertynames(f::Feature) = (:data, propertynames(f.rest)...) + +getnamestypes(::Type{Feature{T, Names, Types}}) where {T, Names, Types} = (T, Names, Types) + +function StructArrays.staticschema(::Type{f}) where {f<:Feature} + T, names, types = getnamestypes(f) + NamedTuple{(:data, names...), Base.tuple_type_cons(T, types)} +end + +function StructArrays.createinstance(::Type{f}, x, args...) where {f<:Feature} + T, names, types = getnamestypes(f) + Feature(x, NamedTuple{names, types}(args)) +end + +#=--------------------------------------------------------------------------------------------- +---------------------------------------------------------------------------------------------- +Old meta +----------------------------------------------------------------------------------------------=# + #= Helper functions that works around the fact, that there is no generic Table interface for this functionality. Once this is in e.g. Tables.jl, @@ -190,3 +217,8 @@ Base.size(x::MultiPolygonMeta) = size(metafree(x)) @meta_type(Mesh, mesh, AbstractMesh, Element <: Polytope) Base.getindex(x::MeshMeta, idx::Int) = getindex(metafree(x), idx) Base.size(x::MeshMeta) = size(metafree(x)) + + +# function Base.getproperty(b::F, s::Symbol) +# s == :data ? getfield(b, 1) : getproperty(getfield(b, 2), s) +# end \ No newline at end of file From 0aa4ae195b5f8d14fce9a3adc498c6ba6d9341a0 Mon Sep 17 00:00:00 2001 From: ARSH SHARMA <184517@nith.ac.in> Date: Tue, 28 Jul 2020 20:46:54 +0530 Subject: [PATCH 03/24] Add tests --- test/runtests.jl | 121 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 121 insertions(+) diff --git a/test/runtests.jl b/test/runtests.jl index 6e4ff6aa..ec4989eb 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -5,6 +5,7 @@ using GeometryBasics: attributes @testset "GeometryBasics" begin +#= This left till meta is removed completely @testset "embedding metadata" begin @testset "Meshes" begin @@ -130,6 +131,126 @@ using GeometryBasics: attributes @test propertynames(m_meta) == (:mesh, :boundingbox) end end +=# +@testset "embedding metadata(new)" begin + # @testset "Meshes" begin + + # @testset "per vertex attributes" begin + # points = rand(Point{3, Float64}, 8) + # tfaces = TetrahedronFace{Int}[(1, 2, 3, 4), (5, 6, 7, 8)] + # normals = rand(SVector{3, Float64}, 8) + # stress = LinRange(0, 1, 8) + # mesh = Mesh(meta(points, normals = normals, stress = stress), tfaces) + + # @test hasproperty(coordinates(mesh), :stress) + # @test hasproperty(coordinates(mesh), :normals) + # @test coordinates(mesh).stress === stress + # @test coordinates(mesh).normals === normals + # @test coordinates(mesh).normals === normals + # @test GeometryBasics.faces(mesh) === tfaces + # @test propertynames(coordinates(mesh)) == (:position, :normals, :stress) + + # end + + # @testset "per face attributes" begin + + # # Construct a cube out of Quads + # points = Point{3, Float64}[ + # (0.0, 0.0, 0.0), (2.0, 0.0, 0.0), + # (2.0, 2.0, 0.0), (0.0, 2.0, 0.0), + # (0.0, 0.0, 12.0), (2.0, 0.0, 12.0), + # (2.0, 2.0, 12.0), (0.0, 2.0, 12.0) + # ] + + # facets = QuadFace{Cint}[ + # 1:4, + # 5:8, + # [1,5,6,2], + # [2,6,7,3], + # [3, 7, 8, 4], + # [4, 8, 5, 1] + # ] + + # markers = Cint[-1, -2, 0, 0, 0, 0] + # # attach some additional information to our faces! + # mesh = Mesh(points, meta(facets, markers = markers)) + # @test hasproperty(GeometryBasics.faces(mesh), :markers) + # # test with === to assert we're not doing any copies + # @test GeometryBasics.faces(mesh).markers === markers + # @test coordinates(mesh) === points + # @test metafree(GeometryBasics.faces(mesh)) === facets + + # end + + # end + + @testset "polygon with metadata" begin + polys = [Polygon(rand(Point{2, Float32}, 20)) for i in 1:10] + multipol = MultiPolygon(polys) + pnames = [randstring(4) for i in 1:10] + numbers = LinRange(0.0, 1.0, 10) + bin = rand(Bool, 10) + # create a polygon + poly = GeometryBasics.Feature(polys[1], name = pnames[1], value = numbers[1], category = bin[1]) + # create a MultiPolygon with the right type & meta information! + multipoly = GeometryBasics.Feature(multipol, name = pnames, value = numbers, category = bin) + @test multipoly isa GeometryBasics.Feature + @test poly isa GeometryBasics.Feature + + @test GeometryBasics.getcolumn(poly, :name) == pnames[1] + @test GeometryBasics.getcolumn(multipoly, :name) == pnames + + meta_p = GeometryBasics.Feature(polys[1], boundingbox=Rect(0, 0, 2, 2)) + @test meta_p.boundingbox === Rect(0, 0, 2, 2) + end + @testset "point with metadata" begin + p = Point(1.1, 2.2) + @test p isa AbstractVector{Float64} + pm = GeometryBasics.Feature(Point(1.1, 2.2); a=1, b=2) + p1 = Point(2.2, 3.6) + p2 = [p, p1] + @test coordinates(p2) == p2 + @test pm.rest === (a=1, b=2) + @test pm.data === p + @test propertynames(pm) == (:data, :a, :b) + end + + @testset "MultiPoint with metadata" begin + p = collect(Point{2, Float64}(x, x+1) for x in 1:5) + @test p isa AbstractVector + mpm = GeometryBasics.Feature(MultiPoint(p), a=1, b=2) + @test coordinates(mpm.data) == Point{2, Float64}[(x, x+1) for x in 1:5] + @test mpm.rest === (a=1, b=2) + @test mpm.data == p + @test propertynames(mpm) == (:data, :a, :b) + end + + @testset "LineString with metadata" begin + linestring = GeometryBasics.Feature(LineString(Point{2, Int}[(10, 10), (20, 20), (10, 40)]), a = 1, b = 2) + @test linestring isa GeometryBasics.Feature + @test linestring.rest === (a = 1, b = 2) + @test propertynames(linestring) == (:data, :a, :b) + end + + @testset "MultiLineString with metadata" begin + linestring1 = LineString(Point{2, Int}[(10, 10), (20, 20), (10, 40)]) + linestring2 = LineString(Point{2, Int}[(40, 40), (30, 30), (40, 20), (30, 10)]) + multilinestring = MultiLineString([linestring1, linestring2]) + multilinestringmeta = GeometryBasics.Feature(MultiLineString([linestring1, linestring2]); boundingbox = Rect(1.0, 1.0, 2.0, 2.0)) + @test multilinestringmeta isa GeometryBasics.Feature + @test multilinestringmeta.rest === (boundingbox = Rect(1.0, 1.0, 2.0, 2.0),) + @test multilinestringmeta.data == multilinestring + @test propertynames(multilinestringmeta) == (:data, :boundingbox) + end + +# @testset "Mesh with metadata" begin +# m = triangle_mesh(Sphere(Point3f0(0), 1)) +# m_meta = MeshMeta(m; boundingbox=Rect(1.0, 1.0, 2.0, 2.0)) +# @test meta(m_meta) === (boundingbox = Rect(1.0, 1.0, 2.0, 2.0),) +# @test metafree(m_meta) === m +# @test propertynames(m_meta) == (:mesh, :boundingbox) +# end +end @testset "view" begin @testset "TupleView" begin From bd792e8a8e4d37eb412dcbb7bc40a51e691a6e96 Mon Sep 17 00:00:00 2001 From: Arsh Sharma <43717431+Sov-trotter@users.noreply.github.com> Date: Tue, 28 Jul 2020 20:50:25 +0530 Subject: [PATCH 04/24] Delete metatest.jl --- src/metatest.jl | 20 -------------------- 1 file changed, 20 deletions(-) delete mode 100644 src/metatest.jl diff --git a/src/metatest.jl b/src/metatest.jl deleted file mode 100644 index 8e2fa962..00000000 --- a/src/metatest.jl +++ /dev/null @@ -1,20 +0,0 @@ -struct metag{T, Names, Types} - data::T - rest::NamedTuple{Names, Types} -end - -metag(x; kwargs...) = metag(x, values(kwargs)) - -Base.getproperty(mg::metag, s::Symbol) = s == :data ? getfield(mg, 1) : getproperty(getfield(mg, 2), s) - -getnamestypes(::Type{metag{T, Names, Types}}) where {T, Names, Types} = (T, Names, Types) - -function StructArrays.staticschema(::Type{mg}) where {mg<:metag} - T, names, types = getnamestypes(mg) - NamedTuple{(:data, names...), Base.tuple_type_cons(T, types)} -end - -function StructArrays.createinstance(::Type{mg}, x, args...) where {mg<:metag} - T, names, types = getnamestypes(mg) - metag(x, NamedTuple{names, types}(args)) -end From c2119c4099b4e5881d9c99b503c82a45b2e80c72 Mon Sep 17 00:00:00 2001 From: ARSH SHARMA <184517@nith.ac.in> Date: Wed, 29 Jul 2020 19:19:35 +0530 Subject: [PATCH 05/24] Add method for collection of Features as StructArray --- src/metadata.jl | 43 +++++++++++++++++++++++++++++-------------- 1 file changed, 29 insertions(+), 14 deletions(-) diff --git a/src/metadata.jl b/src/metadata.jl index 246bfca2..e3c8cabf 100644 --- a/src/metadata.jl +++ b/src/metadata.jl @@ -8,16 +8,36 @@ Feature(x; kwargs...) = Feature(x, values(kwargs)) Base.getproperty(f::Feature, s::Symbol) = s == :data ? getfield(f, 1) : s == :rest ? getfield(f, 2) : getproperty(getfield(f, 2), s) Base.propertynames(f::Feature) = (:data, propertynames(f.rest)...) -getnamestypes(::Type{Feature{T, Names, Types}}) where {T, Names, Types} = (T, Names, Types) - -function StructArrays.staticschema(::Type{f}) where {f<:Feature} - T, names, types = getnamestypes(f) - NamedTuple{(:data, names...), Base.tuple_type_cons(T, types)} +#todo better function names +""" +Put a collection(Array) of Features in a StructArray +""" +function s_coll(iter::Array) + unnested_iter = Base.Generator(iter) do geom_meta + geom = getfield(geom_meta, :data) # well, the public accessor for this + metadata = getfield(geom_meta, :rest) + (; geometry=geom, metadata...) # I think the GeometryBasics name for this field is `:position` + end + soa = fieldarrays(StructArray(unnested_iter)) + return Feature(soa.geometry; Base.tail(soa)...) end -function StructArrays.createinstance(::Type{f}, x, args...) where {f<:Feature} - T, names, types = getnamestypes(f) - Feature(x, NamedTuple{names, types}(args)) +function GeometryBasics.Feature(elements::AbstractVector{XX}; rest...) where {XX} + isempty(rest) && return elements # no meta to add! + n = length(elements) + for (k, v) in rest + if v isa AbstractVector + mn = length(v) + mn != n && error("Metadata array needs to have same length as data. + Found $(n) data items, and $mn metadata items") + else + error("Metadata needs to be an array with the same length as data items. Found: $(typeof(v))") + end + end + nt = values(rest) + # get the first element to get the per element named tuple type + ElementNT = typeof(map(first, nt)) + return StructArray((geometry = elements, nt...)) end #=--------------------------------------------------------------------------------------------- @@ -216,9 +236,4 @@ Base.size(x::MultiPolygonMeta) = size(metafree(x)) @meta_type(Mesh, mesh, AbstractMesh, Element <: Polytope) Base.getindex(x::MeshMeta, idx::Int) = getindex(metafree(x), idx) -Base.size(x::MeshMeta) = size(metafree(x)) - - -# function Base.getproperty(b::F, s::Symbol) -# s == :data ? getfield(b, 1) : getproperty(getfield(b, 2), s) -# end \ No newline at end of file +Base.size(x::MeshMeta) = size(metafree(x)) \ No newline at end of file From 82d257792c45e028026a8ddecc2cd1c64c21d54d Mon Sep 17 00:00:00 2001 From: ARSH SHARMA <184517@nith.ac.in> Date: Wed, 29 Jul 2020 22:11:40 +0530 Subject: [PATCH 06/24] Add method for collection of Features as StructArray- --- src/metadata.jl | 46 ++++++++++++++++++---------------------------- 1 file changed, 18 insertions(+), 28 deletions(-) diff --git a/src/metadata.jl b/src/metadata.jl index e3c8cabf..d426f33e 100644 --- a/src/metadata.jl +++ b/src/metadata.jl @@ -8,36 +8,26 @@ Feature(x; kwargs...) = Feature(x, values(kwargs)) Base.getproperty(f::Feature, s::Symbol) = s == :data ? getfield(f, 1) : s == :rest ? getfield(f, 2) : getproperty(getfield(f, 2), s) Base.propertynames(f::Feature) = (:data, propertynames(f.rest)...) -#todo better function names -""" -Put a collection(Array) of Features in a StructArray -""" -function s_coll(iter::Array) - unnested_iter = Base.Generator(iter) do geom_meta - geom = getfield(geom_meta, :data) # well, the public accessor for this - metadata = getfield(geom_meta, :rest) - (; geometry=geom, metadata...) # I think the GeometryBasics name for this field is `:position` - end - soa = fieldarrays(StructArray(unnested_iter)) - return Feature(soa.geometry; Base.tail(soa)...) +getnamestypes(::Type{Feature{T, Names, Types}}) where {T, Names, Types} = (T, Names, Types) + +function StructArrays.staticschema(::Type{F}) where {F<:Feature} #explicitly give the "schema" of the object to StructArrays + T, names, types = getnamestypes(F) + NamedTuple{(:data, names...), Base.tuple_type_cons(T, types)} end -function GeometryBasics.Feature(elements::AbstractVector{XX}; rest...) where {XX} - isempty(rest) && return elements # no meta to add! - n = length(elements) - for (k, v) in rest - if v isa AbstractVector - mn = length(v) - mn != n && error("Metadata array needs to have same length as data. - Found $(n) data items, and $mn metadata items") - else - error("Metadata needs to be an array with the same length as data items. Found: $(typeof(v))") - end - end - nt = values(rest) - # get the first element to get the per element named tuple type - ElementNT = typeof(map(first, nt)) - return StructArray((geometry = elements, nt...)) +function StructArrays.createinstance(::Type{F}, x, args...) where {F<:Feature} #generate an instance of Feature type + T , names, types = getnamestypes(F) + Feature(x, NamedTuple{names, types}(args)) +end + +function structarray(iter) + cols = Tables.columntable(iter) + structarray(first(cols), Base.tail(cols)) +end + +function structarray(data, rest::NamedTuple{names, types}) where {names, types} + F = Feature{eltype(data), names, StructArrays.eltypes(types)} + return StructArray{F}(; data=data, rest...) end #=--------------------------------------------------------------------------------------------- From cd8d0af12d20fe03afef358b6efdfbb80ce37f03 Mon Sep 17 00:00:00 2001 From: ARSH SHARMA <184517@nith.ac.in> Date: Wed, 29 Jul 2020 22:11:50 +0530 Subject: [PATCH 07/24] Add tests --- test/runtests.jl | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/test/runtests.jl b/test/runtests.jl index ec4989eb..522b59c2 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -626,6 +626,23 @@ end @test <(x, x1) end +@testset "New Meta Methods" + ls = [LineString([Point(i, (i+1)^2/6), Point(i*0.86,i+5), Point(i/3, i/7)]) for i in 1:10] + mls = MultiLineString([LineString([Point(i+1, (i)^2/6), Point(i*0.75,i+8), Point(i/2.5, i/6.79)]) for i in 5:10]) + poly = Polygon(Point{2, Int}[(40, 40), (20, 45), (45, 30), (40, 40)]) + geom = [ls..., mls, poly] + prop = [(country_states = "India$(i)", rainfall = i*10) for i in 1:12] + + feat = [GeometryBasics.Feature(i, j) for (i,j) = zip(geom, prop)] + sa = GeometryBasics.structarray(feat) + + @test nameof(eltype(feat)) == :Feature + @test eltype(sa) === GeometryBasics.Feature{Any,(:country_states, :rainfall),Tuple{String,Int64}} + @test propertynames(sa) === (:data, :country_states, :rainfall) + @test getproperty(sa, :country_states) isa Array{String} + @test getproperty(sa, :data) == geom +end + @testset "Tests from GeometryTypes" begin include("geometrytypes.jl") end From 4e0efc730edf7cc8c9b29199c4868b170b71289a Mon Sep 17 00:00:00 2001 From: ARSH SHARMA <184517@nith.ac.in> Date: Wed, 29 Jul 2020 22:23:13 +0530 Subject: [PATCH 08/24] minor fix --- test/runtests.jl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/runtests.jl b/test/runtests.jl index 522b59c2..24ab5847 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -626,7 +626,7 @@ end @test <(x, x1) end -@testset "New Meta Methods" +@testset "New Meta Methods" begin ls = [LineString([Point(i, (i+1)^2/6), Point(i*0.86,i+5), Point(i/3, i/7)]) for i in 1:10] mls = MultiLineString([LineString([Point(i+1, (i)^2/6), Point(i*0.75,i+8), Point(i/2.5, i/6.79)]) for i in 5:10]) poly = Polygon(Point{2, Int}[(40, 40), (20, 45), (45, 30), (40, 40)]) From 0b4e78a4de5f33da0782951df7d90068e56d4ae4 Mon Sep 17 00:00:00 2001 From: ARSH SHARMA <184517@nith.ac.in> Date: Wed, 29 Jul 2020 23:15:38 +0530 Subject: [PATCH 09/24] Add meta(), metafree() methods --- src/metadata.jl | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/metadata.jl b/src/metadata.jl index d426f33e..9a8d5a2e 100644 --- a/src/metadata.jl +++ b/src/metadata.jl @@ -5,6 +5,12 @@ end Feature(x; kwargs...) = Feature(x, values(kwargs)) +#can change names? +GeometryBasics.metafree(F::Feature) = getproperty(F, :data) +GeometryBasics.metafree(x::AbstractVector{<: Feature}) = [getproperty(i, :data) for i in x] +GeometryBasics.meta(x::Feature) = getfield(x, :rest) +GeometryBasics.meta(x::AbstractVector{<: Feature}) = [getproperty(i, :rest) for i in x] + Base.getproperty(f::Feature, s::Symbol) = s == :data ? getfield(f, 1) : s == :rest ? getfield(f, 2) : getproperty(getfield(f, 2), s) Base.propertynames(f::Feature) = (:data, propertynames(f.rest)...) From 46220f8b1a3f8405a5d64cf7ea9bab993283bb16 Mon Sep 17 00:00:00 2001 From: ARSH SHARMA <184517@nith.ac.in> Date: Wed, 29 Jul 2020 23:18:35 +0530 Subject: [PATCH 10/24] Add tests --- test/runtests.jl | 259 +++++++++++++++++++++++++---------------------- 1 file changed, 137 insertions(+), 122 deletions(-) diff --git a/test/runtests.jl b/test/runtests.jl index 24ab5847..930d3af2 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -6,131 +6,131 @@ using GeometryBasics: attributes @testset "GeometryBasics" begin #= This left till meta is removed completely -@testset "embedding metadata" begin - @testset "Meshes" begin - - @testset "per vertex attributes" begin - points = rand(Point{3, Float64}, 8) - tfaces = TetrahedronFace{Int}[(1, 2, 3, 4), (5, 6, 7, 8)] - normals = rand(SVector{3, Float64}, 8) - stress = LinRange(0, 1, 8) - mesh = Mesh(meta(points, normals = normals, stress = stress), tfaces) - - @test hasproperty(coordinates(mesh), :stress) - @test hasproperty(coordinates(mesh), :normals) - @test coordinates(mesh).stress === stress - @test coordinates(mesh).normals === normals - @test coordinates(mesh).normals === normals - @test GeometryBasics.faces(mesh) === tfaces - @test propertynames(coordinates(mesh)) == (:position, :normals, :stress) - - end - - @testset "per face attributes" begin - - # Construct a cube out of Quads - points = Point{3, Float64}[ - (0.0, 0.0, 0.0), (2.0, 0.0, 0.0), - (2.0, 2.0, 0.0), (0.0, 2.0, 0.0), - (0.0, 0.0, 12.0), (2.0, 0.0, 12.0), - (2.0, 2.0, 12.0), (0.0, 2.0, 12.0) - ] - - facets = QuadFace{Cint}[ - 1:4, - 5:8, - [1,5,6,2], - [2,6,7,3], - [3, 7, 8, 4], - [4, 8, 5, 1] - ] - - markers = Cint[-1, -2, 0, 0, 0, 0] - # attach some additional information to our faces! - mesh = Mesh(points, meta(facets, markers = markers)) - @test hasproperty(GeometryBasics.faces(mesh), :markers) - # test with === to assert we're not doing any copies - @test GeometryBasics.faces(mesh).markers === markers - @test coordinates(mesh) === points - @test metafree(GeometryBasics.faces(mesh)) === facets - - end - - end +# @testset "embedding metadata" begin +# @testset "Meshes" begin + +# @testset "per vertex attributes" begin +# points = rand(Point{3, Float64}, 8) +# tfaces = TetrahedronFace{Int}[(1, 2, 3, 4), (5, 6, 7, 8)] +# normals = rand(SVector{3, Float64}, 8) +# stress = LinRange(0, 1, 8) +# mesh = Mesh(meta(points, normals = normals, stress = stress), tfaces) + +# @test hasproperty(coordinates(mesh), :stress) +# @test hasproperty(coordinates(mesh), :normals) +# @test coordinates(mesh).stress === stress +# @test coordinates(mesh).normals === normals +# @test coordinates(mesh).normals === normals +# @test GeometryBasics.faces(mesh) === tfaces +# @test propertynames(coordinates(mesh)) == (:position, :normals, :stress) + +# end + +# @testset "per face attributes" begin + +# # Construct a cube out of Quads +# points = Point{3, Float64}[ +# (0.0, 0.0, 0.0), (2.0, 0.0, 0.0), +# (2.0, 2.0, 0.0), (0.0, 2.0, 0.0), +# (0.0, 0.0, 12.0), (2.0, 0.0, 12.0), +# (2.0, 2.0, 12.0), (0.0, 2.0, 12.0) +# ] + +# facets = QuadFace{Cint}[ +# 1:4, +# 5:8, +# [1,5,6,2], +# [2,6,7,3], +# [3, 7, 8, 4], +# [4, 8, 5, 1] +# ] + +# markers = Cint[-1, -2, 0, 0, 0, 0] +# # attach some additional information to our faces! +# mesh = Mesh(points, meta(facets, markers = markers)) +# @test hasproperty(GeometryBasics.faces(mesh), :markers) +# # test with === to assert we're not doing any copies +# @test GeometryBasics.faces(mesh).markers === markers +# @test coordinates(mesh) === points +# @test metafree(GeometryBasics.faces(mesh)) === facets + +# end + +# end - @testset "polygon with metadata" begin - polys = [Polygon(rand(Point{2, Float32}, 20)) for i in 1:10] - pnames = [randstring(4) for i in 1:10] - numbers = LinRange(0.0, 1.0, 10) - bin = rand(Bool, 10) - # create a polygon - poly = PolygonMeta(polys[1], name = pnames[1], value = numbers[1], category = bin[1]) - # create a MultiPolygon with the right type & meta information! - multipoly = MultiPolygonMeta(polys, name = pnames, value = numbers, category = bin) - @test multipoly isa AbstractVector - @test poly isa GeometryBasics.AbstractPolygon +# @testset "polygon with metadata" begin +# polys = [Polygon(rand(Point{2, Float32}, 20)) for i in 1:10] +# pnames = [randstring(4) for i in 1:10] +# numbers = LinRange(0.0, 1.0, 10) +# bin = rand(Bool, 10) +# # create a polygon +# poly = PolygonMeta(polys[1], name = pnames[1], value = numbers[1], category = bin[1]) +# # create a MultiPolygon with the right type & meta information! +# multipoly = MultiPolygonMeta(polys, name = pnames, value = numbers, category = bin) +# @test multipoly isa AbstractVector +# @test poly isa GeometryBasics.AbstractPolygon - @test GeometryBasics.getcolumn(poly, :name) == pnames[1] - @test GeometryBasics.MetaFree(PolygonMeta) == Polygon - - @test GeometryBasics.getcolumn(multipoly, :name) == pnames - @test GeometryBasics.MetaFree(MultiPolygonMeta) == MultiPolygon - - meta_p = meta(polys[1], boundingbox=Rect(0, 0, 2, 2)) - @test meta_p.boundingbox === Rect(0, 0, 2, 2) - @test metafree(meta_p) === polys[1] - attributes(meta_p) == Dict{Symbol, Any}(:boundingbox => meta_p.boundingbox, - :polygon => polys[1]) - end - @testset "point with metadata" begin - p = Point(1.1, 2.2) - @test p isa AbstractVector{Float64} - pm = GeometryBasics.PointMeta(1.1, 2.2; a=1, b=2) - p1 = Point(2.2, 3.6) - p2 = [p, p1] - @test coordinates(p2) == p2 - @test meta(pm) === (a=1, b=2) - @test metafree(pm) === p - @test propertynames(pm) == (:position, :a, :b) - end +# @test GeometryBasics.getcolumn(poly, :name) == pnames[1] +# @test GeometryBasics.MetaFree(PolygonMeta) == Polygon + +# @test GeometryBasics.getcolumn(multipoly, :name) == pnames +# @test GeometryBasics.MetaFree(MultiPolygonMeta) == MultiPolygon + +# meta_p = meta(polys[1], boundingbox=Rect(0, 0, 2, 2)) +# @test meta_p.boundingbox === Rect(0, 0, 2, 2) +# @test metafree(meta_p) === polys[1] +# attributes(meta_p) == Dict{Symbol, Any}(:boundingbox => meta_p.boundingbox, +# :polygon => polys[1]) +# end +# @testset "point with metadata" begin +# p = Point(1.1, 2.2) +# @test p isa AbstractVector{Float64} +# pm = GeometryBasics.PointMeta(1.1, 2.2; a=1, b=2) +# p1 = Point(2.2, 3.6) +# p2 = [p, p1] +# @test coordinates(p2) == p2 +# @test meta(pm) === (a=1, b=2) +# @test metafree(pm) === p +# @test propertynames(pm) == (:position, :a, :b) +# end - @testset "MultiPoint with metadata" begin - p = collect(Point{2, Float64}(x, x+1) for x in 1:5) - @test p isa AbstractVector - mpm = MultiPointMeta(p, a=1, b=2) - @test coordinates(mpm) == mpm - @test meta(mpm) === (a=1, b=2) - @test metafree(mpm) == p - @test propertynames(mpm) == (:points, :a, :b) - end - - @testset "LineString with metadata" begin - linestring = LineStringMeta(Point{2, Int}[(10, 10), (20, 20), (10, 40)], a = 1, b = 2) - @test linestring isa AbstractVector - @test meta(linestring) === (a = 1, b = 2) - @test metafree(linestring) == linestring - @test propertynames(linestring) == (:lines, :a, :b) - end - - @testset "MultiLineString with metadata" begin - linestring1 = LineString(Point{2, Int}[(10, 10), (20, 20), (10, 40)]) - linestring2 = LineString(Point{2, Int}[(40, 40), (30, 30), (40, 20), (30, 10)]) - multilinestring = MultiLineString([linestring1, linestring2]) - multilinestringmeta = MultiLineStringMeta([linestring1, linestring2]; boundingbox = Rect(1.0, 1.0, 2.0, 2.0)) - @test multilinestringmeta isa AbstractVector - @test meta(multilinestringmeta) === (boundingbox = Rect(1.0, 1.0, 2.0, 2.0),) - @test metafree(multilinestringmeta) == multilinestring - @test propertynames(multilinestringmeta) == (:linestrings, :boundingbox) - end +# @testset "MultiPoint with metadata" begin +# p = collect(Point{2, Float64}(x, x+1) for x in 1:5) +# @test p isa AbstractVector +# mpm = MultiPointMeta(p, a=1, b=2) +# @test coordinates(mpm) == mpm +# @test meta(mpm) === (a=1, b=2) +# @test metafree(mpm) == p +# @test propertynames(mpm) == (:points, :a, :b) +# end + +# @testset "LineString with metadata" begin +# linestring = LineStringMeta(Point{2, Int}[(10, 10), (20, 20), (10, 40)], a = 1, b = 2) +# @test linestring isa AbstractVector +# @test meta(linestring) === (a = 1, b = 2) +# @test metafree(linestring) == linestring +# @test propertynames(linestring) == (:lines, :a, :b) +# end + +# @testset "MultiLineString with metadata" begin +# linestring1 = LineString(Point{2, Int}[(10, 10), (20, 20), (10, 40)]) +# linestring2 = LineString(Point{2, Int}[(40, 40), (30, 30), (40, 20), (30, 10)]) +# multilinestring = MultiLineString([linestring1, linestring2]) +# multilinestringmeta = MultiLineStringMeta([linestring1, linestring2]; boundingbox = Rect(1.0, 1.0, 2.0, 2.0)) +# @test multilinestringmeta isa AbstractVector +# @test meta(multilinestringmeta) === (boundingbox = Rect(1.0, 1.0, 2.0, 2.0),) +# @test metafree(multilinestringmeta) == multilinestring +# @test propertynames(multilinestringmeta) == (:linestrings, :boundingbox) +# end - @testset "Mesh with metadata" begin - m = triangle_mesh(Sphere(Point3f0(0), 1)) - m_meta = MeshMeta(m; boundingbox=Rect(1.0, 1.0, 2.0, 2.0)) - @test meta(m_meta) === (boundingbox = Rect(1.0, 1.0, 2.0, 2.0),) - @test metafree(m_meta) === m - @test propertynames(m_meta) == (:mesh, :boundingbox) - end -end +# @testset "Mesh with metadata" begin +# m = triangle_mesh(Sphere(Point3f0(0), 1)) +# m_meta = MeshMeta(m; boundingbox=Rect(1.0, 1.0, 2.0, 2.0)) +# @test meta(m_meta) === (boundingbox = Rect(1.0, 1.0, 2.0, 2.0),) +# @test metafree(m_meta) === m +# @test propertynames(m_meta) == (:mesh, :boundingbox) +# end +# end =# @testset "embedding metadata(new)" begin # @testset "Meshes" begin @@ -202,7 +202,14 @@ end meta_p = GeometryBasics.Feature(polys[1], boundingbox=Rect(0, 0, 2, 2)) @test meta_p.boundingbox === Rect(0, 0, 2, 2) + @test GeometryBasics.metafree(meta_p) == polys[1] + @test GeometryBasics.metafree(poly) == polys[1] + @test GeometryBasics.metafree(multipoly) == multipol + @test GeometryBasics.meta(meta_p) == (boundingbox = GeometryBasics.HyperRectangle{2,Int64}([0, 0], [2, 2]),) + @test GeometryBasics.meta(poly) == (name = "cMlR", value = 0.0, category = true) + @test GeometryBasics.meta(multipoly) == (name = pnames, value = numbers, category = bin) end + @testset "point with metadata" begin p = Point(1.1, 2.2) @test p isa AbstractVector{Float64} @@ -213,16 +220,20 @@ end @test pm.rest === (a=1, b=2) @test pm.data === p @test propertynames(pm) == (:data, :a, :b) + @test GeometryBasics.metafree(pm) == p + @test GeometryBasics.meta(pm) == (a = 1, b = 2) end @testset "MultiPoint with metadata" begin p = collect(Point{2, Float64}(x, x+1) for x in 1:5) @test p isa AbstractVector - mpm = GeometryBasics.Feature(MultiPoint(p), a=1, b=2) + mpm = GeometryBasics.Feature(MultiPoint(p); a=1, b=2) @test coordinates(mpm.data) == Point{2, Float64}[(x, x+1) for x in 1:5] @test mpm.rest === (a=1, b=2) @test mpm.data == p @test propertynames(mpm) == (:data, :a, :b) + @test GeometryBasics.metafree(mpm) == p + @test GeometryBasics.meta(mpm) == (a = 1, b = 2) end @testset "LineString with metadata" begin @@ -230,6 +241,8 @@ end @test linestring isa GeometryBasics.Feature @test linestring.rest === (a = 1, b = 2) @test propertynames(linestring) == (:data, :a, :b) + @test GeometryBasics.metafree(linestring) == LineString(Point{2, Int}[(10, 10), (20, 20), (10, 40)]) + @test GeometryBasics.meta(linestring) == (a = 1, b = 2) end @testset "MultiLineString with metadata" begin @@ -241,6 +254,8 @@ end @test multilinestringmeta.rest === (boundingbox = Rect(1.0, 1.0, 2.0, 2.0),) @test multilinestringmeta.data == multilinestring @test propertynames(multilinestringmeta) == (:data, :boundingbox) + @test GeometryBasics.metafree(multilinestringmeta) == multilinestring + @test GeometryBasics.meta(multilinestringmeta) == (boundingbox = GeometryBasics.HyperRectangle{2,Float64}([1.0, 1.0], [2.0, 2.0]),) end # @testset "Mesh with metadata" begin From d0ea0a0510dc6a2a3a4e01bc847fbd5b5ca2e525 Mon Sep 17 00:00:00 2001 From: ARSH SHARMA <184517@nith.ac.in> Date: Wed, 29 Jul 2020 23:22:44 +0530 Subject: [PATCH 11/24] Minor Refactor --- src/metadata.jl | 13 ++- test/runtests.jl | 239 ++++++++++++++++++++++++----------------------- 2 files changed, 129 insertions(+), 123 deletions(-) diff --git a/src/metadata.jl b/src/metadata.jl index 9a8d5a2e..36eb20b6 100644 --- a/src/metadata.jl +++ b/src/metadata.jl @@ -6,10 +6,15 @@ end Feature(x; kwargs...) = Feature(x, values(kwargs)) #can change names? -GeometryBasics.metafree(F::Feature) = getproperty(F, :data) -GeometryBasics.metafree(x::AbstractVector{<: Feature}) = [getproperty(i, :data) for i in x] -GeometryBasics.meta(x::Feature) = getfield(x, :rest) -GeometryBasics.meta(x::AbstractVector{<: Feature}) = [getproperty(i, :rest) for i in x] +function metafree(F::Feature) + getproperty(F, :data) +end +metafree(x::AbstractVector{<: Feature}) = [getproperty(i, :data) for i in x] + +function meta(x::Feature) + getfield(x, :rest) +end +meta(x::AbstractVector{<: Feature}) = [getproperty(i, :rest) for i in x] Base.getproperty(f::Feature, s::Symbol) = s == :data ? getfield(f, 1) : s == :rest ? getfield(f, 2) : getproperty(getfield(f, 2), s) Base.propertynames(f::Feature) = (:data, propertynames(f.rest)...) diff --git a/test/runtests.jl b/test/runtests.jl index 930d3af2..3f798a9c 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -7,131 +7,132 @@ using GeometryBasics: attributes #= This left till meta is removed completely # @testset "embedding metadata" begin -# @testset "Meshes" begin - -# @testset "per vertex attributes" begin -# points = rand(Point{3, Float64}, 8) -# tfaces = TetrahedronFace{Int}[(1, 2, 3, 4), (5, 6, 7, 8)] -# normals = rand(SVector{3, Float64}, 8) -# stress = LinRange(0, 1, 8) -# mesh = Mesh(meta(points, normals = normals, stress = stress), tfaces) - -# @test hasproperty(coordinates(mesh), :stress) -# @test hasproperty(coordinates(mesh), :normals) -# @test coordinates(mesh).stress === stress -# @test coordinates(mesh).normals === normals -# @test coordinates(mesh).normals === normals -# @test GeometryBasics.faces(mesh) === tfaces -# @test propertynames(coordinates(mesh)) == (:position, :normals, :stress) - -# end - -# @testset "per face attributes" begin - -# # Construct a cube out of Quads -# points = Point{3, Float64}[ -# (0.0, 0.0, 0.0), (2.0, 0.0, 0.0), -# (2.0, 2.0, 0.0), (0.0, 2.0, 0.0), -# (0.0, 0.0, 12.0), (2.0, 0.0, 12.0), -# (2.0, 2.0, 12.0), (0.0, 2.0, 12.0) -# ] - -# facets = QuadFace{Cint}[ -# 1:4, -# 5:8, -# [1,5,6,2], -# [2,6,7,3], -# [3, 7, 8, 4], -# [4, 8, 5, 1] -# ] - -# markers = Cint[-1, -2, 0, 0, 0, 0] -# # attach some additional information to our faces! -# mesh = Mesh(points, meta(facets, markers = markers)) -# @test hasproperty(GeometryBasics.faces(mesh), :markers) -# # test with === to assert we're not doing any copies -# @test GeometryBasics.faces(mesh).markers === markers -# @test coordinates(mesh) === points -# @test metafree(GeometryBasics.faces(mesh)) === facets - -# end - -# end + @testset "Meshes" begin + + @testset "per vertex attributes" begin + points = rand(Point{3, Float64}, 8) + tfaces = TetrahedronFace{Int}[(1, 2, 3, 4), (5, 6, 7, 8)] + normals = rand(SVector{3, Float64}, 8) + stress = LinRange(0, 1, 8) + mesh = Mesh(meta(points, normals = normals, stress = stress), tfaces) + + @test hasproperty(coordinates(mesh), :stress) + @test hasproperty(coordinates(mesh), :normals) + @test coordinates(mesh).stress === stress + @test coordinates(mesh).normals === normals + @test coordinates(mesh).normals === normals + @test GeometryBasics.faces(mesh) === tfaces + @test propertynames(coordinates(mesh)) == (:position, :normals, :stress) + + end + + @testset "per face attributes" begin + + # Construct a cube out of Quads + points = Point{3, Float64}[ + (0.0, 0.0, 0.0), (2.0, 0.0, 0.0), + (2.0, 2.0, 0.0), (0.0, 2.0, 0.0), + (0.0, 0.0, 12.0), (2.0, 0.0, 12.0), + (2.0, 2.0, 12.0), (0.0, 2.0, 12.0) + ] + + facets = QuadFace{Cint}[ + 1:4, + 5:8, + [1,5,6,2], + [2,6,7,3], + [3, 7, 8, 4], + [4, 8, 5, 1] + ] + + markers = Cint[-1, -2, 0, 0, 0, 0] + # attach some additional information to our faces! + mesh = Mesh(points, meta(facets, markers = markers)) + @test hasproperty(GeometryBasics.faces(mesh), :markers) + # test with === to assert we're not doing any copies + @test GeometryBasics.faces(mesh).markers === markers + @test coordinates(mesh) === points + @test metafree(GeometryBasics.faces(mesh)) === facets + + end + + end -# @testset "polygon with metadata" begin -# polys = [Polygon(rand(Point{2, Float32}, 20)) for i in 1:10] -# pnames = [randstring(4) for i in 1:10] -# numbers = LinRange(0.0, 1.0, 10) -# bin = rand(Bool, 10) -# # create a polygon -# poly = PolygonMeta(polys[1], name = pnames[1], value = numbers[1], category = bin[1]) -# # create a MultiPolygon with the right type & meta information! -# multipoly = MultiPolygonMeta(polys, name = pnames, value = numbers, category = bin) -# @test multipoly isa AbstractVector -# @test poly isa GeometryBasics.AbstractPolygon + @testset "polygon with metadata" begin + polys = [Polygon(rand(Point{2, Float32}, 20)) for i in 1:10] + pnames = [randstring(4) for i in 1:10] + numbers = LinRange(0.0, 1.0, 10) + bin = rand(Bool, 10) + # create a polygon + poly = PolygonMeta(polys[1], name = pnames[1], value = numbers[1], category = bin[1]) + # create a MultiPolygon with the right type & meta information! + multipoly = MultiPolygonMeta(polys, name = pnames, value = numbers, category = bin) + @test multipoly isa AbstractVector + @test poly isa GeometryBasics.AbstractPolygon -# @test GeometryBasics.getcolumn(poly, :name) == pnames[1] -# @test GeometryBasics.MetaFree(PolygonMeta) == Polygon - -# @test GeometryBasics.getcolumn(multipoly, :name) == pnames -# @test GeometryBasics.MetaFree(MultiPolygonMeta) == MultiPolygon - -# meta_p = meta(polys[1], boundingbox=Rect(0, 0, 2, 2)) -# @test meta_p.boundingbox === Rect(0, 0, 2, 2) -# @test metafree(meta_p) === polys[1] -# attributes(meta_p) == Dict{Symbol, Any}(:boundingbox => meta_p.boundingbox, -# :polygon => polys[1]) -# end -# @testset "point with metadata" begin -# p = Point(1.1, 2.2) -# @test p isa AbstractVector{Float64} -# pm = GeometryBasics.PointMeta(1.1, 2.2; a=1, b=2) -# p1 = Point(2.2, 3.6) -# p2 = [p, p1] -# @test coordinates(p2) == p2 -# @test meta(pm) === (a=1, b=2) -# @test metafree(pm) === p -# @test propertynames(pm) == (:position, :a, :b) -# end + @test GeometryBasics.getcolumn(poly, :name) == pnames[1] + @test GeometryBasics.MetaFree(PolygonMeta) == Polygon + + @test GeometryBasics.getcolumn(multipoly, :name) == pnames + @test GeometryBasics.MetaFree(MultiPolygonMeta) == MultiPolygon + + meta_p = meta(polys[1], boundingbox=Rect(0, 0, 2, 2)) + @test meta_p.boundingbox === Rect(0, 0, 2, 2) + @test metafree(meta_p) === polys[1] + attributes(meta_p) == Dict{Symbol, Any}(:boundingbox => meta_p.boundingbox, + :polygon => polys[1]) + end + @testset "point with metadata" begin + p = Point(1.1, 2.2) + @test p isa AbstractVector{Float64} + pm = GeometryBasics.PointMeta(1.1, 2.2; a=1, b=2) + p1 = Point(2.2, 3.6) + p2 = [p, p1] + @test coordinates(p2) == p2 + @test meta(pm) === (a=1, b=2) + @test metafree(pm) === p + @test propertynames(pm) == (:position, :a, :b) + end -# @testset "MultiPoint with metadata" begin -# p = collect(Point{2, Float64}(x, x+1) for x in 1:5) -# @test p isa AbstractVector -# mpm = MultiPointMeta(p, a=1, b=2) -# @test coordinates(mpm) == mpm -# @test meta(mpm) === (a=1, b=2) -# @test metafree(mpm) == p -# @test propertynames(mpm) == (:points, :a, :b) -# end - -# @testset "LineString with metadata" begin -# linestring = LineStringMeta(Point{2, Int}[(10, 10), (20, 20), (10, 40)], a = 1, b = 2) -# @test linestring isa AbstractVector -# @test meta(linestring) === (a = 1, b = 2) -# @test metafree(linestring) == linestring -# @test propertynames(linestring) == (:lines, :a, :b) -# end - -# @testset "MultiLineString with metadata" begin -# linestring1 = LineString(Point{2, Int}[(10, 10), (20, 20), (10, 40)]) -# linestring2 = LineString(Point{2, Int}[(40, 40), (30, 30), (40, 20), (30, 10)]) -# multilinestring = MultiLineString([linestring1, linestring2]) -# multilinestringmeta = MultiLineStringMeta([linestring1, linestring2]; boundingbox = Rect(1.0, 1.0, 2.0, 2.0)) -# @test multilinestringmeta isa AbstractVector -# @test meta(multilinestringmeta) === (boundingbox = Rect(1.0, 1.0, 2.0, 2.0),) -# @test metafree(multilinestringmeta) == multilinestring -# @test propertynames(multilinestringmeta) == (:linestrings, :boundingbox) -# end + @testset "MultiPoint with metadata" begin + p = collect(Point{2, Float64}(x, x+1) for x in 1:5) + @test p isa AbstractVector + mpm = MultiPointMeta(p, a=1, b=2) + @test coordinates(mpm) == mpm + @test meta(mpm) === (a=1, b=2) + @test metafree(mpm) == p + @test propertynames(mpm) == (:points, :a, :b) + end -# @testset "Mesh with metadata" begin -# m = triangle_mesh(Sphere(Point3f0(0), 1)) -# m_meta = MeshMeta(m; boundingbox=Rect(1.0, 1.0, 2.0, 2.0)) -# @test meta(m_meta) === (boundingbox = Rect(1.0, 1.0, 2.0, 2.0),) -# @test metafree(m_meta) === m -# @test propertynames(m_meta) == (:mesh, :boundingbox) -# end + @testset "LineString with metadata" begin + linestring = LineStringMeta(Point{2, Int}[(10, 10), (20, 20), (10, 40)], a = 1, b = 2) + @test linestring isa AbstractVector + @test meta(linestring) === (a = 1, b = 2) + @test metafree(linestring) == linestring + @test propertynames(linestring) == (:lines, :a, :b) + end + + @testset "MultiLineString with metadata" begin + linestring1 = LineString(Point{2, Int}[(10, 10), (20, 20), (10, 40)]) + linestring2 = LineString(Point{2, Int}[(40, 40), (30, 30), (40, 20), (30, 10)]) + multilinestring = MultiLineString([linestring1, linestring2]) + multilinestringmeta = MultiLineStringMeta([linestring1, linestring2]; boundingbox = Rect(1.0, 1.0, 2.0, 2.0)) + @test multilinestringmeta isa AbstractVector + @test meta(multilinestringmeta) === (boundingbox = Rect(1.0, 1.0, 2.0, 2.0),) + @test metafree(multilinestringmeta) == multilinestring + @test propertynames(multilinestringmeta) == (:linestrings, :boundingbox) + end + + @testset "Mesh with metadata" begin + m = triangle_mesh(Sphere(Point3f0(0), 1)) + m_meta = MeshMeta(m; boundingbox=Rect(1.0, 1.0, 2.0, 2.0)) + @test meta(m_meta) === (boundingbox = Rect(1.0, 1.0, 2.0, 2.0),) + @test metafree(m_meta) === m + @test propertynames(m_meta) == (:mesh, :boundingbox) + end # end =# + @testset "embedding metadata(new)" begin # @testset "Meshes" begin From 4076f51c407d4eebd7bceb61b67347013e0e2f3f Mon Sep 17 00:00:00 2001 From: ARSH SHARMA <184517@nith.ac.in> Date: Fri, 31 Jul 2020 00:51:52 +0530 Subject: [PATCH 12/24] Some Cleanup --- src/metadata.jl | 18 +++++++++++++++--- test/runtests.jl | 2 +- 2 files changed, 16 insertions(+), 4 deletions(-) diff --git a/src/metadata.jl b/src/metadata.jl index 36eb20b6..8a2a77ce 100644 --- a/src/metadata.jl +++ b/src/metadata.jl @@ -6,31 +6,43 @@ end Feature(x; kwargs...) = Feature(x, values(kwargs)) #can change names? +""" +Frees the Feature out of metadata +i.e. returns and array of geometries +""" function metafree(F::Feature) getproperty(F, :data) end metafree(x::AbstractVector{<: Feature}) = [getproperty(i, :data) for i in x] +""" +Returns the metadata of a Feature +""" function meta(x::Feature) getfield(x, :rest) end meta(x::AbstractVector{<: Feature}) = [getproperty(i, :rest) for i in x] +# helper methods Base.getproperty(f::Feature, s::Symbol) = s == :data ? getfield(f, 1) : s == :rest ? getfield(f, 2) : getproperty(getfield(f, 2), s) Base.propertynames(f::Feature) = (:data, propertynames(f.rest)...) - getnamestypes(::Type{Feature{T, Names, Types}}) where {T, Names, Types} = (T, Names, Types) -function StructArrays.staticschema(::Type{F}) where {F<:Feature} #explicitly give the "schema" of the object to StructArrays +# explicitly give the "schema" of the object to StructArrays +function StructArrays.staticschema(::Type{F}) where {F<:Feature} T, names, types = getnamestypes(F) NamedTuple{(:data, names...), Base.tuple_type_cons(T, types)} end -function StructArrays.createinstance(::Type{F}, x, args...) where {F<:Feature} #generate an instance of Feature type +# generate an instance of Feature type +function StructArrays.createinstance(::Type{F}, x, args...) where {F<:Feature} T , names, types = getnamestypes(F) Feature(x, NamedTuple{names, types}(args)) end +""" +Accepts an Array/iterator of Features and put it into a StructArray +""" function structarray(iter) cols = Tables.columntable(iter) structarray(first(cols), Base.tail(cols)) diff --git a/test/runtests.jl b/test/runtests.jl index 3f798a9c..73f1767c 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -207,7 +207,7 @@ using GeometryBasics: attributes @test GeometryBasics.metafree(poly) == polys[1] @test GeometryBasics.metafree(multipoly) == multipol @test GeometryBasics.meta(meta_p) == (boundingbox = GeometryBasics.HyperRectangle{2,Int64}([0, 0], [2, 2]),) - @test GeometryBasics.meta(poly) == (name = "cMlR", value = 0.0, category = true) + @test GeometryBasics.meta(poly) == (name = pnames[1], value = 0.0, category = bin[1]) @test GeometryBasics.meta(multipoly) == (name = pnames, value = numbers, category = bin) end From 3003c07cab2fb038b767a1c17788b5e003126f35 Mon Sep 17 00:00:00 2001 From: ARSH SHARMA <184517@nith.ac.in> Date: Tue, 4 Aug 2020 00:55:01 +0530 Subject: [PATCH 13/24] Not replace meta --- src/GeometryBasics.jl | 3 +- src/metadata.jl | 125 +++++++++++++++++++++-------------------- test/runtests.jl | 128 +++++++++++++++--------------------------- 3 files changed, 111 insertions(+), 145 deletions(-) diff --git a/src/GeometryBasics.jl b/src/GeometryBasics.jl index b1ed1e51..5d50dbc8 100644 --- a/src/GeometryBasics.jl +++ b/src/GeometryBasics.jl @@ -29,12 +29,13 @@ module GeometryBasics export OffsetInteger, ZeroIndex, OneIndex, GLIndex export FaceView, SimpleFaceView export AbstractPoint, PointMeta, PointWithUV + export PolygonMeta, MultiPointMeta, MultiLineStringMeta, MeshMeta, LineStringMeta, MultiPolygonMeta export decompose, coordinates, faces, normals, decompose_uv, decompose_normals, texturecoordinates export Tesselation, pointmeta, Normal, UV, UVW export GLTriangleFace, GLNormalMesh3D, GLPlainTriangleMesh, GLUVMesh3D, GLUVNormalMesh3D export AbstractMesh, Mesh, TriangleMesh export GLNormalMesh2D, PlainTriangleMesh - + export Feature, collect_feature # all the different predefined mesh types # Note: meshes can contain arbitrary meta information, export AbstractMesh, TriangleMesh, PlainMesh, GLPlainMesh, GLPlainMesh2D, GLPlainMesh3D diff --git a/src/metadata.jl b/src/metadata.jl index 8a2a77ce..8b6a5315 100644 --- a/src/metadata.jl +++ b/src/metadata.jl @@ -1,63 +1,3 @@ -struct Feature{T, Names, Types} #have a better name? - data::T - rest::NamedTuple{Names, Types} -end - -Feature(x; kwargs...) = Feature(x, values(kwargs)) - -#can change names? -""" -Frees the Feature out of metadata -i.e. returns and array of geometries -""" -function metafree(F::Feature) - getproperty(F, :data) -end -metafree(x::AbstractVector{<: Feature}) = [getproperty(i, :data) for i in x] - -""" -Returns the metadata of a Feature -""" -function meta(x::Feature) - getfield(x, :rest) -end -meta(x::AbstractVector{<: Feature}) = [getproperty(i, :rest) for i in x] - -# helper methods -Base.getproperty(f::Feature, s::Symbol) = s == :data ? getfield(f, 1) : s == :rest ? getfield(f, 2) : getproperty(getfield(f, 2), s) -Base.propertynames(f::Feature) = (:data, propertynames(f.rest)...) -getnamestypes(::Type{Feature{T, Names, Types}}) where {T, Names, Types} = (T, Names, Types) - -# explicitly give the "schema" of the object to StructArrays -function StructArrays.staticschema(::Type{F}) where {F<:Feature} - T, names, types = getnamestypes(F) - NamedTuple{(:data, names...), Base.tuple_type_cons(T, types)} -end - -# generate an instance of Feature type -function StructArrays.createinstance(::Type{F}, x, args...) where {F<:Feature} - T , names, types = getnamestypes(F) - Feature(x, NamedTuple{names, types}(args)) -end - -""" -Accepts an Array/iterator of Features and put it into a StructArray -""" -function structarray(iter) - cols = Tables.columntable(iter) - structarray(first(cols), Base.tail(cols)) -end - -function structarray(data, rest::NamedTuple{names, types}) where {names, types} - F = Feature{eltype(data), names, StructArrays.eltypes(types)} - return StructArray{F}(; data=data, rest...) -end - -#=--------------------------------------------------------------------------------------------- ----------------------------------------------------------------------------------------------- -Old meta -----------------------------------------------------------------------------------------------=# - #= Helper functions that works around the fact, that there is no generic Table interface for this functionality. Once this is in e.g. Tables.jl, @@ -249,4 +189,67 @@ Base.size(x::MultiPolygonMeta) = size(metafree(x)) @meta_type(Mesh, mesh, AbstractMesh, Element <: Polytope) Base.getindex(x::MeshMeta, idx::Int) = getindex(metafree(x), idx) -Base.size(x::MeshMeta) = size(metafree(x)) \ No newline at end of file +Base.size(x::MeshMeta) = size(metafree(x)) + + +#= +`Feature` type acts same as Meta method +The difference lies in the fact that it is designed to handle +heterogeneous types. +=# +struct Feature{T, Names, Types} #<:AbstractVector{T} + data::T + rest::NamedTuple{Names, Types} +end + +Feature(x; kwargs...) = Feature(x, values(kwargs)) + +""" +Frees the Feature out of metadata +i.e. returns and array of geometries +""" +function metafree(F::Feature) + getproperty(F, :data) +end +metafree(x::AbstractVector{<: Feature}) = [getproperty(i, :data) for i in x] + +""" +Returns the metadata of a Feature +""" +function meta(x::Feature) + getfield(x, :rest) +end +meta(x::AbstractVector{<: Feature}) = [getproperty(i, :rest) for i in x] + +# helper methods +Base.getproperty(f::Feature, s::Symbol) = s == :data ? getfield(f, 1) : s == :rest ? getfield(f, 2) : getproperty(getfield(f, 2), s) +Base.propertynames(f::Feature) = (:data, propertynames(f.rest)...) +getnamestypes(::Type{Feature{T, Names, Types}}) where {T, Names, Types} = (T, Names, Types) + +# explicitly give the "schema" of the object to StructArrays +function StructArrays.staticschema(::Type{F}) where {F<:Feature} + T, names, types = getnamestypes(F) + NamedTuple{(:data, names...), Base.tuple_type_cons(T, types)} +end + +# generate an instance of Feature type +function StructArrays.createinstance(::Type{F}, x, args...) where {F<:Feature} + T , names, types = getnamestypes(F) + Feature(x, NamedTuple{names, types}(args)) +end + +""" +Accepts an Array/iterator of Features and put it into a StructArray +""" +function collect_feature(iter) + cols = Tables.columntable(iter) + collect_feature(first(cols), Base.tail(cols)) +end + +function collect_feature(data, rest::NamedTuple{names, types}) where {names, types} + F = Feature{eltype(data), names, StructArrays.eltypes(types)} + return StructArray{F}(; data=data, rest...) +end + +Base.getindex(f::Feature, idx::Int) = getindex(metafree(f), idx) +Base.size(f::Feature) = size(metafree(f)) diff --git a/test/runtests.jl b/test/runtests.jl index 73f1767c..1cd8919b 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -5,8 +5,7 @@ using GeometryBasics: attributes @testset "GeometryBasics" begin -#= This left till meta is removed completely -# @testset "embedding metadata" begin +@testset "embedding metadata" begin @testset "Meshes" begin @testset "per vertex attributes" begin @@ -130,78 +129,26 @@ using GeometryBasics: attributes @test metafree(m_meta) === m @test propertynames(m_meta) == (:mesh, :boundingbox) end -# end -=# - -@testset "embedding metadata(new)" begin - # @testset "Meshes" begin - - # @testset "per vertex attributes" begin - # points = rand(Point{3, Float64}, 8) - # tfaces = TetrahedronFace{Int}[(1, 2, 3, 4), (5, 6, 7, 8)] - # normals = rand(SVector{3, Float64}, 8) - # stress = LinRange(0, 1, 8) - # mesh = Mesh(meta(points, normals = normals, stress = stress), tfaces) - - # @test hasproperty(coordinates(mesh), :stress) - # @test hasproperty(coordinates(mesh), :normals) - # @test coordinates(mesh).stress === stress - # @test coordinates(mesh).normals === normals - # @test coordinates(mesh).normals === normals - # @test GeometryBasics.faces(mesh) === tfaces - # @test propertynames(coordinates(mesh)) == (:position, :normals, :stress) - - # end - - # @testset "per face attributes" begin - - # # Construct a cube out of Quads - # points = Point{3, Float64}[ - # (0.0, 0.0, 0.0), (2.0, 0.0, 0.0), - # (2.0, 2.0, 0.0), (0.0, 2.0, 0.0), - # (0.0, 0.0, 12.0), (2.0, 0.0, 12.0), - # (2.0, 2.0, 12.0), (0.0, 2.0, 12.0) - # ] - - # facets = QuadFace{Cint}[ - # 1:4, - # 5:8, - # [1,5,6,2], - # [2,6,7,3], - # [3, 7, 8, 4], - # [4, 8, 5, 1] - # ] - - # markers = Cint[-1, -2, 0, 0, 0, 0] - # # attach some additional information to our faces! - # mesh = Mesh(points, meta(facets, markers = markers)) - # @test hasproperty(GeometryBasics.faces(mesh), :markers) - # # test with === to assert we're not doing any copies - # @test GeometryBasics.faces(mesh).markers === markers - # @test coordinates(mesh) === points - # @test metafree(GeometryBasics.faces(mesh)) === facets - - # end - - # end - - @testset "polygon with metadata" begin +end + +@testset "embedding Feature" begin + @testset "Feature{Polygon}" begin polys = [Polygon(rand(Point{2, Float32}, 20)) for i in 1:10] multipol = MultiPolygon(polys) pnames = [randstring(4) for i in 1:10] numbers = LinRange(0.0, 1.0, 10) bin = rand(Bool, 10) # create a polygon - poly = GeometryBasics.Feature(polys[1], name = pnames[1], value = numbers[1], category = bin[1]) + poly = Feature(polys[1], name = pnames[1], value = numbers[1], category = bin[1]) # create a MultiPolygon with the right type & meta information! - multipoly = GeometryBasics.Feature(multipol, name = pnames, value = numbers, category = bin) - @test multipoly isa GeometryBasics.Feature - @test poly isa GeometryBasics.Feature + multipoly = Feature(multipol, name = pnames, value = numbers, category = bin) + @test multipoly isa Feature + @test poly isa Feature @test GeometryBasics.getcolumn(poly, :name) == pnames[1] @test GeometryBasics.getcolumn(multipoly, :name) == pnames - meta_p = GeometryBasics.Feature(polys[1], boundingbox=Rect(0, 0, 2, 2)) + meta_p = Feature(polys[1], boundingbox=Rect(0, 0, 2, 2)) @test meta_p.boundingbox === Rect(0, 0, 2, 2) @test GeometryBasics.metafree(meta_p) == polys[1] @test GeometryBasics.metafree(poly) == polys[1] @@ -211,10 +158,10 @@ using GeometryBasics: attributes @test GeometryBasics.meta(multipoly) == (name = pnames, value = numbers, category = bin) end - @testset "point with metadata" begin + @testset "Feature{Point}" begin p = Point(1.1, 2.2) @test p isa AbstractVector{Float64} - pm = GeometryBasics.Feature(Point(1.1, 2.2); a=1, b=2) + pm = Feature(Point(1.1, 2.2); a=1, b=2) p1 = Point(2.2, 3.6) p2 = [p, p1] @test coordinates(p2) == p2 @@ -225,10 +172,10 @@ using GeometryBasics: attributes @test GeometryBasics.meta(pm) == (a = 1, b = 2) end - @testset "MultiPoint with metadata" begin + @testset "Feature{MultiPoint}" begin p = collect(Point{2, Float64}(x, x+1) for x in 1:5) @test p isa AbstractVector - mpm = GeometryBasics.Feature(MultiPoint(p); a=1, b=2) + mpm = Feature(MultiPoint(p); a=1, b=2) @test coordinates(mpm.data) == Point{2, Float64}[(x, x+1) for x in 1:5] @test mpm.rest === (a=1, b=2) @test mpm.data == p @@ -237,21 +184,21 @@ using GeometryBasics: attributes @test GeometryBasics.meta(mpm) == (a = 1, b = 2) end - @testset "LineString with metadata" begin - linestring = GeometryBasics.Feature(LineString(Point{2, Int}[(10, 10), (20, 20), (10, 40)]), a = 1, b = 2) - @test linestring isa GeometryBasics.Feature + @testset "Feature{LineString}" begin + linestring = Feature(LineString(Point{2, Int}[(10, 10), (20, 20), (10, 40)]), a = 1, b = 2) + @test linestring isa Feature @test linestring.rest === (a = 1, b = 2) @test propertynames(linestring) == (:data, :a, :b) @test GeometryBasics.metafree(linestring) == LineString(Point{2, Int}[(10, 10), (20, 20), (10, 40)]) @test GeometryBasics.meta(linestring) == (a = 1, b = 2) end - @testset "MultiLineString with metadata" begin + @testset "Feature{MultiLineString}" begin linestring1 = LineString(Point{2, Int}[(10, 10), (20, 20), (10, 40)]) linestring2 = LineString(Point{2, Int}[(40, 40), (30, 30), (40, 20), (30, 10)]) multilinestring = MultiLineString([linestring1, linestring2]) - multilinestringmeta = GeometryBasics.Feature(MultiLineString([linestring1, linestring2]); boundingbox = Rect(1.0, 1.0, 2.0, 2.0)) - @test multilinestringmeta isa GeometryBasics.Feature + multilinestringmeta = Feature(MultiLineString([linestring1, linestring2]); boundingbox = Rect(1.0, 1.0, 2.0, 2.0)) + @test multilinestringmeta isa Feature @test multilinestringmeta.rest === (boundingbox = Rect(1.0, 1.0, 2.0, 2.0),) @test multilinestringmeta.data == multilinestring @test propertynames(multilinestringmeta) == (:data, :boundingbox) @@ -259,13 +206,28 @@ using GeometryBasics: attributes @test GeometryBasics.meta(multilinestringmeta) == (boundingbox = GeometryBasics.HyperRectangle{2,Float64}([1.0, 1.0], [2.0, 2.0]),) end -# @testset "Mesh with metadata" begin -# m = triangle_mesh(Sphere(Point3f0(0), 1)) -# m_meta = MeshMeta(m; boundingbox=Rect(1.0, 1.0, 2.0, 2.0)) -# @test meta(m_meta) === (boundingbox = Rect(1.0, 1.0, 2.0, 2.0),) -# @test metafree(m_meta) === m -# @test propertynames(m_meta) == (:mesh, :boundingbox) -# end + #= + So mesh works differently for Feature + since `Feature{Point}` not subtyped to `AbstractPoint` + =# + + @testset "Feature{Mesh}" begin + @testset "per vertex attributes" begin + points = rand(Point{3, Float64}, 8) + tfaces = TetrahedronFace{Int}[(1, 2, 3, 4), (5, 6, 7, 8)] + normals = rand(SVector{3, Float64}, 8) + stress = LinRange(0, 1, 8) + mesh_nometa = Mesh(points, tfaces) + mesh = Feature(mesh_nometa, normals = normals, stress = stress) + + @test hasproperty(mesh, :stress) + @test hasproperty(mesh, :normals) + @test mesh.stress == stress + @test mesh.normals == normals + @test GeometryBasics.faces(mesh.data) == tfaces + @test propertynames(mesh) == (:data, :normals, :stress) + end + end end @testset "view" begin @@ -649,11 +611,11 @@ end geom = [ls..., mls, poly] prop = [(country_states = "India$(i)", rainfall = i*10) for i in 1:12] - feat = [GeometryBasics.Feature(i, j) for (i,j) = zip(geom, prop)] - sa = GeometryBasics.structarray(feat) + feat = [Feature(i, j) for (i,j) = zip(geom, prop)] + sa = collect_feature(feat) @test nameof(eltype(feat)) == :Feature - @test eltype(sa) === GeometryBasics.Feature{Any,(:country_states, :rainfall),Tuple{String,Int64}} + @test eltype(sa) === Feature{Any,(:country_states, :rainfall),Tuple{String,Int64}} @test propertynames(sa) === (:data, :country_states, :rainfall) @test getproperty(sa, :country_states) isa Array{String} @test getproperty(sa, :data) == geom From 1212783e905a97f4879e0df2b7afc34540a749ad Mon Sep 17 00:00:00 2001 From: ARSH SHARMA <184517@nith.ac.in> Date: Tue, 4 Aug 2020 16:32:21 +0530 Subject: [PATCH 14/24] Minor refactoring --- src/GeometryBasics.jl | 1 + src/metadata.jl | 10 +++++++--- test/runtests.jl | 13 +++++++------ 3 files changed, 15 insertions(+), 9 deletions(-) diff --git a/src/GeometryBasics.jl b/src/GeometryBasics.jl index 5d50dbc8..bd5e300e 100644 --- a/src/GeometryBasics.jl +++ b/src/GeometryBasics.jl @@ -36,6 +36,7 @@ module GeometryBasics export AbstractMesh, Mesh, TriangleMesh export GLNormalMesh2D, PlainTriangleMesh export Feature, collect_feature + # all the different predefined mesh types # Note: meshes can contain arbitrary meta information, export AbstractMesh, TriangleMesh, PlainMesh, GLPlainMesh, GLPlainMesh2D, GLPlainMesh3D diff --git a/src/metadata.jl b/src/metadata.jl index 8b6a5315..118a009f 100644 --- a/src/metadata.jl +++ b/src/metadata.jl @@ -192,12 +192,15 @@ Base.getindex(x::MeshMeta, idx::Int) = getindex(metafree(x), idx) Base.size(x::MeshMeta) = size(metafree(x)) -#= +""" `Feature` type acts same as Meta method The difference lies in the fact that it is designed to handle heterogeneous types. -=# -struct Feature{T, Names, Types} #<:AbstractVector{T} + +eg: A Point MetaGeometry is a `PointMeta` +But a feature is represented as `Feature{Point}` +""" +struct Feature{T, Names, Types} data::T rest::NamedTuple{Names, Types} end @@ -253,3 +256,4 @@ end Base.getindex(f::Feature, idx::Int) = getindex(metafree(f), idx) Base.size(f::Feature) = size(metafree(f)) + diff --git a/test/runtests.jl b/test/runtests.jl index 1cd8919b..3d1d3e85 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -604,20 +604,21 @@ end @test <(x, x1) end -@testset "New Meta Methods" begin +@testset "Feature and heterogeneous data" begin ls = [LineString([Point(i, (i+1)^2/6), Point(i*0.86,i+5), Point(i/3, i/7)]) for i in 1:10] mls = MultiLineString([LineString([Point(i+1, (i)^2/6), Point(i*0.75,i+8), Point(i/2.5, i/6.79)]) for i in 5:10]) poly = Polygon(Point{2, Int}[(40, 40), (20, 45), (45, 30), (40, 40)]) geom = [ls..., mls, poly] - prop = [(country_states = "India$(i)", rainfall = i*10) for i in 1:12] - - feat = [Feature(i, j) for (i,j) = zip(geom, prop)] + prop = Any[(country_states = "India$(i)", rainfall = (i*9)/2) for i in 1:11] + push!(prop, (country_states = 12, rainfall = 1000)) # a pinch of heterogeneity + + feat = [Feature(i, j) for (i,j) = zip(geom, prop)] sa = collect_feature(feat) @test nameof(eltype(feat)) == :Feature - @test eltype(sa) === Feature{Any,(:country_states, :rainfall),Tuple{String,Int64}} + @test eltype(sa) === Feature{Any,(:country_states, :rainfall),Tuple{Any,Float64}} @test propertynames(sa) === (:data, :country_states, :rainfall) - @test getproperty(sa, :country_states) isa Array{String} + @test getproperty(sa, :country_states) isa Array{Any} @test getproperty(sa, :data) == geom end From f92fe69bc89bafac4f76006739edcca1d4f5f52d Mon Sep 17 00:00:00 2001 From: ARSH SHARMA <184517@nith.ac.in> Date: Tue, 4 Aug 2020 21:13:26 +0530 Subject: [PATCH 15/24] Make Field names consistent with existing meta --- src/metadata.jl | 24 ++++++++++++------------ test/runtests.jl | 32 ++++++++++++++++---------------- 2 files changed, 28 insertions(+), 28 deletions(-) diff --git a/src/metadata.jl b/src/metadata.jl index 118a009f..d742bf77 100644 --- a/src/metadata.jl +++ b/src/metadata.jl @@ -201,8 +201,8 @@ eg: A Point MetaGeometry is a `PointMeta` But a feature is represented as `Feature{Point}` """ struct Feature{T, Names, Types} - data::T - rest::NamedTuple{Names, Types} + main::T + meta::NamedTuple{Names, Types} end Feature(x; kwargs...) = Feature(x, values(kwargs)) @@ -212,27 +212,27 @@ Frees the Feature out of metadata i.e. returns and array of geometries """ function metafree(F::Feature) - getproperty(F, :data) + getproperty(F, :main) end -metafree(x::AbstractVector{<: Feature}) = [getproperty(i, :data) for i in x] +metafree(x::AbstractVector{<: Feature}) = [getproperty(i, :main) for i in x] """ Returns the metadata of a Feature """ function meta(x::Feature) - getfield(x, :rest) + getfield(x, :meta) end -meta(x::AbstractVector{<: Feature}) = [getproperty(i, :rest) for i in x] +meta(x::AbstractVector{<: Feature}) = [getproperty(i, :meta) for i in x] # helper methods -Base.getproperty(f::Feature, s::Symbol) = s == :data ? getfield(f, 1) : s == :rest ? getfield(f, 2) : getproperty(getfield(f, 2), s) -Base.propertynames(f::Feature) = (:data, propertynames(f.rest)...) +Base.getproperty(f::Feature, s::Symbol) = s == :main ? getfield(f, 1) : s == :meta ? getfield(f, 2) : getproperty(getfield(f, 2), s) +Base.propertynames(f::Feature) = (:main, propertynames(f.meta)...) getnamestypes(::Type{Feature{T, Names, Types}}) where {T, Names, Types} = (T, Names, Types) # explicitly give the "schema" of the object to StructArrays function StructArrays.staticschema(::Type{F}) where {F<:Feature} T, names, types = getnamestypes(F) - NamedTuple{(:data, names...), Base.tuple_type_cons(T, types)} + NamedTuple{(:main, names...), Base.tuple_type_cons(T, types)} end # generate an instance of Feature type @@ -249,9 +249,9 @@ function collect_feature(iter) collect_feature(first(cols), Base.tail(cols)) end -function collect_feature(data, rest::NamedTuple{names, types}) where {names, types} - F = Feature{eltype(data), names, StructArrays.eltypes(types)} - return StructArray{F}(; data=data, rest...) +function collect_feature(main, meta::NamedTuple{names, types}) where {names, types} + F = Feature{eltype(main), names, StructArrays.eltypes(types)} + return StructArray{F}(; main=main, meta...) end Base.getindex(f::Feature, idx::Int) = getindex(metafree(f), idx) diff --git a/test/runtests.jl b/test/runtests.jl index 3d1d3e85..dafd3649 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -165,9 +165,9 @@ end p1 = Point(2.2, 3.6) p2 = [p, p1] @test coordinates(p2) == p2 - @test pm.rest === (a=1, b=2) - @test pm.data === p - @test propertynames(pm) == (:data, :a, :b) + @test pm.meta === (a=1, b=2) + @test pm.main === p + @test propertynames(pm) == (:main, :a, :b) @test GeometryBasics.metafree(pm) == p @test GeometryBasics.meta(pm) == (a = 1, b = 2) end @@ -176,10 +176,10 @@ end p = collect(Point{2, Float64}(x, x+1) for x in 1:5) @test p isa AbstractVector mpm = Feature(MultiPoint(p); a=1, b=2) - @test coordinates(mpm.data) == Point{2, Float64}[(x, x+1) for x in 1:5] - @test mpm.rest === (a=1, b=2) - @test mpm.data == p - @test propertynames(mpm) == (:data, :a, :b) + @test coordinates(mpm.main) == Point{2, Float64}[(x, x+1) for x in 1:5] + @test mpm.meta === (a=1, b=2) + @test mpm.main == p + @test propertynames(mpm) == (:main, :a, :b) @test GeometryBasics.metafree(mpm) == p @test GeometryBasics.meta(mpm) == (a = 1, b = 2) end @@ -187,8 +187,8 @@ end @testset "Feature{LineString}" begin linestring = Feature(LineString(Point{2, Int}[(10, 10), (20, 20), (10, 40)]), a = 1, b = 2) @test linestring isa Feature - @test linestring.rest === (a = 1, b = 2) - @test propertynames(linestring) == (:data, :a, :b) + @test linestring.meta === (a = 1, b = 2) + @test propertynames(linestring) == (:main, :a, :b) @test GeometryBasics.metafree(linestring) == LineString(Point{2, Int}[(10, 10), (20, 20), (10, 40)]) @test GeometryBasics.meta(linestring) == (a = 1, b = 2) end @@ -199,9 +199,9 @@ end multilinestring = MultiLineString([linestring1, linestring2]) multilinestringmeta = Feature(MultiLineString([linestring1, linestring2]); boundingbox = Rect(1.0, 1.0, 2.0, 2.0)) @test multilinestringmeta isa Feature - @test multilinestringmeta.rest === (boundingbox = Rect(1.0, 1.0, 2.0, 2.0),) - @test multilinestringmeta.data == multilinestring - @test propertynames(multilinestringmeta) == (:data, :boundingbox) + @test multilinestringmeta.meta === (boundingbox = Rect(1.0, 1.0, 2.0, 2.0),) + @test multilinestringmeta.main == multilinestring + @test propertynames(multilinestringmeta) == (:main, :boundingbox) @test GeometryBasics.metafree(multilinestringmeta) == multilinestring @test GeometryBasics.meta(multilinestringmeta) == (boundingbox = GeometryBasics.HyperRectangle{2,Float64}([1.0, 1.0], [2.0, 2.0]),) end @@ -224,8 +224,8 @@ end @test hasproperty(mesh, :normals) @test mesh.stress == stress @test mesh.normals == normals - @test GeometryBasics.faces(mesh.data) == tfaces - @test propertynames(mesh) == (:data, :normals, :stress) + @test GeometryBasics.faces(mesh.main) == tfaces + @test propertynames(mesh) == (:main, :normals, :stress) end end end @@ -617,9 +617,9 @@ end @test nameof(eltype(feat)) == :Feature @test eltype(sa) === Feature{Any,(:country_states, :rainfall),Tuple{Any,Float64}} - @test propertynames(sa) === (:data, :country_states, :rainfall) + @test propertynames(sa) === (:main, :country_states, :rainfall) @test getproperty(sa, :country_states) isa Array{Any} - @test getproperty(sa, :data) == geom + @test getproperty(sa, :main) == geom end @testset "Tests from GeometryTypes" begin From a29b9a9ad6d74031cac77394b3f00c6fc8b498bb Mon Sep 17 00:00:00 2001 From: ARSH SHARMA <184517@nith.ac.in> Date: Fri, 7 Aug 2020 23:01:41 +0530 Subject: [PATCH 16/24] End docstrings in old meta methods --- src/metadata.jl | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/metadata.jl b/src/metadata.jl index d742bf77..acda148e 100644 --- a/src/metadata.jl +++ b/src/metadata.jl @@ -37,6 +37,7 @@ Returns the Meta Type corresponding to `T` E.g: ```julia MetaType(Point) == PointMeta +``` """ MetaType(::Type{T}) where T = error("No Meta Type for $T") @@ -47,6 +48,7 @@ Returns the original type containing no metadata for `T` E.g: ```julia MetaFree(PointMeta) == Point +``` """ MetaFree(::Type{T}) where T = error("No meta free Type for $T") From 7394b6a8d003b32bf75377c4a5f644bfb5ee8382 Mon Sep 17 00:00:00 2001 From: ARSH SHARMA <184517@nith.ac.in> Date: Fri, 7 Aug 2020 23:03:16 +0530 Subject: [PATCH 17/24] use variable name x --- src/metadata.jl | 25 ++++++++++++++++++------- 1 file changed, 18 insertions(+), 7 deletions(-) diff --git a/src/metadata.jl b/src/metadata.jl index acda148e..8c9401d6 100644 --- a/src/metadata.jl +++ b/src/metadata.jl @@ -195,12 +195,23 @@ Base.size(x::MeshMeta) = size(metafree(x)) """ -`Feature` type acts same as Meta method + + Feature(::type{T}, Names, Types) + +Returns a `Feature` that holds a geometry and it's metadata + +`Feature` acts the same as `Meta` method. The difference lies in the fact that it is designed to handle -heterogeneous types. +geometries and metadata of different/heterogeneous types. + +eg: While a Point MetaGeometry is a `PointMeta`, the Feature representation is `Feature{Point}` +The downside being it's not subtyped to `AbstractPoint` like a `PointMeta` is. -eg: A Point MetaGeometry is a `PointMeta` -But a feature is represented as `Feature{Point}` +Example: +```julia +julia> Feature(Point(1, 2), city = "Mumbai") +Feature{Point{2,Int64},(:city,),Tuple{String}}([1, 2], (city = "Mumbai",)) +``` """ struct Feature{T, Names, Types} main::T @@ -244,7 +255,7 @@ function StructArrays.createinstance(::Type{F}, x, args...) where {F<:Feature} end """ -Accepts an Array/iterator of Features and put it into a StructArray +Accepts an iterable of Features and put it into a StructArray """ function collect_feature(iter) cols = Tables.columntable(iter) @@ -256,6 +267,6 @@ function collect_feature(main, meta::NamedTuple{names, types}) where {names, typ return StructArray{F}(; main=main, meta...) end -Base.getindex(f::Feature, idx::Int) = getindex(metafree(f), idx) -Base.size(f::Feature) = size(metafree(f)) +Base.getindex(x::Feature, idx::Int) = getindex(metafree(x), idx) +Base.size(x::Feature) = size(metafree(x)) From 9828a5a8a55581e06155697a777c7878fe1d8d9f Mon Sep 17 00:00:00 2001 From: ARSH SHARMA <184517@nith.ac.in> Date: Fri, 7 Aug 2020 23:04:24 +0530 Subject: [PATCH 18/24] Docstring changes; refactor getproperty; use getfield in metafree --- src/metadata.jl | 37 +++++++++++++++++++++++++++---------- 1 file changed, 27 insertions(+), 10 deletions(-) diff --git a/src/metadata.jl b/src/metadata.jl index 8c9401d6..67d11a08 100644 --- a/src/metadata.jl +++ b/src/metadata.jl @@ -221,25 +221,42 @@ end Feature(x; kwargs...) = Feature(x, values(kwargs)) """ -Frees the Feature out of metadata -i.e. returns and array of geometries + + metafree(x::Feature) + metafree(x::Array{Feature}) + +Free the Feature from metadata +i.e. returns the geometry/array of geometries """ -function metafree(F::Feature) - getproperty(F, :main) +function metafree(x::Feature) + getfield(x, 1) end -metafree(x::AbstractVector{<: Feature}) = [getproperty(i, :main) for i in x] +metafree(x::AbstractVector{<: Feature}) = map(metafree, x) """ -Returns the metadata of a Feature + + meta(x::Feature) + meta(x::Array{Feature}) + +Returns the metadata of a `Feature` """ function meta(x::Feature) - getfield(x, :meta) + getfield(x, 2) end -meta(x::AbstractVector{<: Feature}) = [getproperty(i, :meta) for i in x] +meta(x::AbstractVector{<: Feature}) = map(meta, x) # helper methods -Base.getproperty(f::Feature, s::Symbol) = s == :main ? getfield(f, 1) : s == :meta ? getfield(f, 2) : getproperty(getfield(f, 2), s) -Base.propertynames(f::Feature) = (:main, propertynames(f.meta)...) +function Base.getproperty(x::Feature, field::Symbol) + if field == :main + metafree(x) + elseif field == :meta + meta(x) + else + getproperty(meta(x), field) + end +end + +Base.propertynames(x::Feature) = (:main, propertynames(meta(x))...) getnamestypes(::Type{Feature{T, Names, Types}}) where {T, Names, Types} = (T, Names, Types) # explicitly give the "schema" of the object to StructArrays From 9dfd7584af6e31b02778e6b1ab1a41dc7a60b7be Mon Sep 17 00:00:00 2001 From: ARSH SHARMA <184517@nith.ac.in> Date: Fri, 7 Aug 2020 23:37:39 +0530 Subject: [PATCH 19/24] Add tests for internal methods --- test/runtests.jl | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/test/runtests.jl b/test/runtests.jl index dafd3649..eafdb130 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -620,6 +620,17 @@ end @test propertynames(sa) === (:main, :country_states, :rainfall) @test getproperty(sa, :country_states) isa Array{Any} @test getproperty(sa, :main) == geom + + @test GeometryBasics.getnamestypes(typeof(feat[1])) == + (LineString{2,Float64,Point{2,Float64},Base.ReinterpretArray{GeometryBasics.Ngon{2,Float64,2,Point{2,Float64}},1,Tuple{Point{2,Float64},Point{2,Float64}},TupleView{Tuple{Point{2,Float64},Point{2,Float64}},2,1,Array{Point{2,Float64},1}}}}, + (:country_states, :rainfall), Tuple{String,Float64}) + + @test StructArrays.staticschema(typeof(feat[1])) == + NamedTuple{(:main, :country_states, :rainfall),Tuple{LineString{2,Float64,Point{2,Float64},Base.ReinterpretArray{GeometryBasics.Ngon{2,Float64,2,Point{2,Float64}},1,Tuple{Point{2,Float64},Point{2,Float64}},TupleView{Tuple{Point{2,Float64},Point{2,Float64}},2,1,Array{Point{2,Float64},1}}}}, + String,Float64}} + + @test Base.getindex(feat[1], 1) isa Line + @test Base.size(feat[1]) == (2,) end @testset "Tests from GeometryTypes" begin From 630b9c10403eebee2a7cc74afe8e4d2444044590 Mon Sep 17 00:00:00 2001 From: ARSH SHARMA <184517@nith.ac.in> Date: Fri, 7 Aug 2020 23:52:25 +0530 Subject: [PATCH 20/24] Test for createinstance --- test/runtests.jl | 2 ++ 1 file changed, 2 insertions(+) diff --git a/test/runtests.jl b/test/runtests.jl index eafdb130..91beeb98 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -629,6 +629,8 @@ end NamedTuple{(:main, :country_states, :rainfall),Tuple{LineString{2,Float64,Point{2,Float64},Base.ReinterpretArray{GeometryBasics.Ngon{2,Float64,2,Point{2,Float64}},1,Tuple{Point{2,Float64},Point{2,Float64}},TupleView{Tuple{Point{2,Float64},Point{2,Float64}},2,1,Array{Point{2,Float64},1}}}}, String,Float64}} + @test StructArrays.createinstance(typeof(feat[1]), LineString([Point(1, (2)^2/6), Point(1*0.86,6), Point(1/3, 1/7)]), "Mumbai", 100) isa typeof(feat[1]) + @test Base.getindex(feat[1], 1) isa Line @test Base.size(feat[1]) == (2,) end From e6cd046813139d5aad85181c81721a0b57288fd1 Mon Sep 17 00:00:00 2001 From: ARSH SHARMA <184517@nith.ac.in> Date: Sat, 8 Aug 2020 00:11:26 +0530 Subject: [PATCH 21/24] Rename Feature to MetaT --- src/GeometryBasics.jl | 2 +- src/metadata.jl | 64 +++++++++++++++++++++---------------------- test/runtests.jl | 52 +++++++++++++++++------------------ 3 files changed, 59 insertions(+), 59 deletions(-) diff --git a/src/GeometryBasics.jl b/src/GeometryBasics.jl index bd5e300e..03472445 100644 --- a/src/GeometryBasics.jl +++ b/src/GeometryBasics.jl @@ -35,7 +35,7 @@ module GeometryBasics export GLTriangleFace, GLNormalMesh3D, GLPlainTriangleMesh, GLUVMesh3D, GLUVNormalMesh3D export AbstractMesh, Mesh, TriangleMesh export GLNormalMesh2D, PlainTriangleMesh - export Feature, collect_feature + export MetaT, collect_MetaT # all the different predefined mesh types # Note: meshes can contain arbitrary meta information, diff --git a/src/metadata.jl b/src/metadata.jl index 67d11a08..73b77a21 100644 --- a/src/metadata.jl +++ b/src/metadata.jl @@ -196,57 +196,57 @@ Base.size(x::MeshMeta) = size(metafree(x)) """ - Feature(::type{T}, Names, Types) + MetaT(::type{T}, Names, Types) -Returns a `Feature` that holds a geometry and it's metadata +Returns a `MetaT` that holds a geometry and it's metadata -`Feature` acts the same as `Meta` method. +`MetaT` acts the same as `Meta` method. The difference lies in the fact that it is designed to handle geometries and metadata of different/heterogeneous types. -eg: While a Point MetaGeometry is a `PointMeta`, the Feature representation is `Feature{Point}` +eg: While a Point MetaGeometry is a `PointMeta`, the MetaT representation is `MetaT{Point}` The downside being it's not subtyped to `AbstractPoint` like a `PointMeta` is. Example: ```julia -julia> Feature(Point(1, 2), city = "Mumbai") -Feature{Point{2,Int64},(:city,),Tuple{String}}([1, 2], (city = "Mumbai",)) +julia> MetaT(Point(1, 2), city = "Mumbai") +MetaT{Point{2,Int64},(:city,),Tuple{String}}([1, 2], (city = "Mumbai",)) ``` """ -struct Feature{T, Names, Types} +struct MetaT{T, Names, Types} main::T meta::NamedTuple{Names, Types} end -Feature(x; kwargs...) = Feature(x, values(kwargs)) +MetaT(x; kwargs...) = MetaT(x, values(kwargs)) """ - metafree(x::Feature) - metafree(x::Array{Feature}) + metafree(x::MetaT) + metafree(x::Array{MetaT}) -Free the Feature from metadata +Free the MetaT from metadata i.e. returns the geometry/array of geometries """ -function metafree(x::Feature) +function metafree(x::MetaT) getfield(x, 1) end -metafree(x::AbstractVector{<: Feature}) = map(metafree, x) +metafree(x::AbstractVector{<: MetaT}) = map(metafree, x) """ - meta(x::Feature) - meta(x::Array{Feature}) + meta(x::MetaT) + meta(x::Array{MetaT}) -Returns the metadata of a `Feature` +Returns the metadata of a `MetaT` """ -function meta(x::Feature) +function meta(x::MetaT) getfield(x, 2) end -meta(x::AbstractVector{<: Feature}) = map(meta, x) +meta(x::AbstractVector{<: MetaT}) = map(meta, x) # helper methods -function Base.getproperty(x::Feature, field::Symbol) +function Base.getproperty(x::MetaT, field::Symbol) if field == :main metafree(x) elseif field == :meta @@ -256,34 +256,34 @@ function Base.getproperty(x::Feature, field::Symbol) end end -Base.propertynames(x::Feature) = (:main, propertynames(meta(x))...) -getnamestypes(::Type{Feature{T, Names, Types}}) where {T, Names, Types} = (T, Names, Types) +Base.propertynames(x::MetaT) = (:main, propertynames(meta(x))...) +getnamestypes(::Type{MetaT{T, Names, Types}}) where {T, Names, Types} = (T, Names, Types) # explicitly give the "schema" of the object to StructArrays -function StructArrays.staticschema(::Type{F}) where {F<:Feature} +function StructArrays.staticschema(::Type{F}) where {F<:MetaT} T, names, types = getnamestypes(F) NamedTuple{(:main, names...), Base.tuple_type_cons(T, types)} end -# generate an instance of Feature type -function StructArrays.createinstance(::Type{F}, x, args...) where {F<:Feature} +# generate an instance of MetaT type +function StructArrays.createinstance(::Type{F}, x, args...) where {F<:MetaT} T , names, types = getnamestypes(F) - Feature(x, NamedTuple{names, types}(args)) + MetaT(x, NamedTuple{names, types}(args)) end """ -Accepts an iterable of Features and put it into a StructArray +Accepts an iterable of MetaTs and put it into a StructArray """ -function collect_feature(iter) +function collect_MetaT(iter) cols = Tables.columntable(iter) - collect_feature(first(cols), Base.tail(cols)) + collect_MetaT(first(cols), Base.tail(cols)) end -function collect_feature(main, meta::NamedTuple{names, types}) where {names, types} - F = Feature{eltype(main), names, StructArrays.eltypes(types)} +function collect_MetaT(main, meta::NamedTuple{names, types}) where {names, types} + F = MetaT{eltype(main), names, StructArrays.eltypes(types)} return StructArray{F}(; main=main, meta...) end -Base.getindex(x::Feature, idx::Int) = getindex(metafree(x), idx) -Base.size(x::Feature) = size(metafree(x)) +Base.getindex(x::MetaT, idx::Int) = getindex(metafree(x), idx) +Base.size(x::MetaT) = size(metafree(x)) diff --git a/test/runtests.jl b/test/runtests.jl index 91beeb98..082f0d4a 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -131,24 +131,24 @@ using GeometryBasics: attributes end end -@testset "embedding Feature" begin - @testset "Feature{Polygon}" begin +@testset "embedding MetaT" begin + @testset "MetaT{Polygon}" begin polys = [Polygon(rand(Point{2, Float32}, 20)) for i in 1:10] multipol = MultiPolygon(polys) pnames = [randstring(4) for i in 1:10] numbers = LinRange(0.0, 1.0, 10) bin = rand(Bool, 10) # create a polygon - poly = Feature(polys[1], name = pnames[1], value = numbers[1], category = bin[1]) + poly = MetaT(polys[1], name = pnames[1], value = numbers[1], category = bin[1]) # create a MultiPolygon with the right type & meta information! - multipoly = Feature(multipol, name = pnames, value = numbers, category = bin) - @test multipoly isa Feature - @test poly isa Feature + multipoly = MetaT(multipol, name = pnames, value = numbers, category = bin) + @test multipoly isa MetaT + @test poly isa MetaT @test GeometryBasics.getcolumn(poly, :name) == pnames[1] @test GeometryBasics.getcolumn(multipoly, :name) == pnames - meta_p = Feature(polys[1], boundingbox=Rect(0, 0, 2, 2)) + meta_p = MetaT(polys[1], boundingbox=Rect(0, 0, 2, 2)) @test meta_p.boundingbox === Rect(0, 0, 2, 2) @test GeometryBasics.metafree(meta_p) == polys[1] @test GeometryBasics.metafree(poly) == polys[1] @@ -158,10 +158,10 @@ end @test GeometryBasics.meta(multipoly) == (name = pnames, value = numbers, category = bin) end - @testset "Feature{Point}" begin + @testset "MetaT{Point}" begin p = Point(1.1, 2.2) @test p isa AbstractVector{Float64} - pm = Feature(Point(1.1, 2.2); a=1, b=2) + pm = MetaT(Point(1.1, 2.2); a=1, b=2) p1 = Point(2.2, 3.6) p2 = [p, p1] @test coordinates(p2) == p2 @@ -172,10 +172,10 @@ end @test GeometryBasics.meta(pm) == (a = 1, b = 2) end - @testset "Feature{MultiPoint}" begin + @testset "MetaT{MultiPoint}" begin p = collect(Point{2, Float64}(x, x+1) for x in 1:5) @test p isa AbstractVector - mpm = Feature(MultiPoint(p); a=1, b=2) + mpm = MetaT(MultiPoint(p); a=1, b=2) @test coordinates(mpm.main) == Point{2, Float64}[(x, x+1) for x in 1:5] @test mpm.meta === (a=1, b=2) @test mpm.main == p @@ -184,21 +184,21 @@ end @test GeometryBasics.meta(mpm) == (a = 1, b = 2) end - @testset "Feature{LineString}" begin - linestring = Feature(LineString(Point{2, Int}[(10, 10), (20, 20), (10, 40)]), a = 1, b = 2) - @test linestring isa Feature + @testset "MetaT{LineString}" begin + linestring = MetaT(LineString(Point{2, Int}[(10, 10), (20, 20), (10, 40)]), a = 1, b = 2) + @test linestring isa MetaT @test linestring.meta === (a = 1, b = 2) @test propertynames(linestring) == (:main, :a, :b) @test GeometryBasics.metafree(linestring) == LineString(Point{2, Int}[(10, 10), (20, 20), (10, 40)]) @test GeometryBasics.meta(linestring) == (a = 1, b = 2) end - @testset "Feature{MultiLineString}" begin + @testset "MetaT{MultiLineString}" begin linestring1 = LineString(Point{2, Int}[(10, 10), (20, 20), (10, 40)]) linestring2 = LineString(Point{2, Int}[(40, 40), (30, 30), (40, 20), (30, 10)]) multilinestring = MultiLineString([linestring1, linestring2]) - multilinestringmeta = Feature(MultiLineString([linestring1, linestring2]); boundingbox = Rect(1.0, 1.0, 2.0, 2.0)) - @test multilinestringmeta isa Feature + multilinestringmeta = MetaT(MultiLineString([linestring1, linestring2]); boundingbox = Rect(1.0, 1.0, 2.0, 2.0)) + @test multilinestringmeta isa MetaT @test multilinestringmeta.meta === (boundingbox = Rect(1.0, 1.0, 2.0, 2.0),) @test multilinestringmeta.main == multilinestring @test propertynames(multilinestringmeta) == (:main, :boundingbox) @@ -207,18 +207,18 @@ end end #= - So mesh works differently for Feature - since `Feature{Point}` not subtyped to `AbstractPoint` + So mesh works differently for MetaT + since `MetaT{Point}` not subtyped to `AbstractPoint` =# - @testset "Feature{Mesh}" begin + @testset "MetaT{Mesh}" begin @testset "per vertex attributes" begin points = rand(Point{3, Float64}, 8) tfaces = TetrahedronFace{Int}[(1, 2, 3, 4), (5, 6, 7, 8)] normals = rand(SVector{3, Float64}, 8) stress = LinRange(0, 1, 8) mesh_nometa = Mesh(points, tfaces) - mesh = Feature(mesh_nometa, normals = normals, stress = stress) + mesh = MetaT(mesh_nometa, normals = normals, stress = stress) @test hasproperty(mesh, :stress) @test hasproperty(mesh, :normals) @@ -604,7 +604,7 @@ end @test <(x, x1) end -@testset "Feature and heterogeneous data" begin +@testset "MetaT and heterogeneous data" begin ls = [LineString([Point(i, (i+1)^2/6), Point(i*0.86,i+5), Point(i/3, i/7)]) for i in 1:10] mls = MultiLineString([LineString([Point(i+1, (i)^2/6), Point(i*0.75,i+8), Point(i/2.5, i/6.79)]) for i in 5:10]) poly = Polygon(Point{2, Int}[(40, 40), (20, 45), (45, 30), (40, 40)]) @@ -612,11 +612,11 @@ end prop = Any[(country_states = "India$(i)", rainfall = (i*9)/2) for i in 1:11] push!(prop, (country_states = 12, rainfall = 1000)) # a pinch of heterogeneity - feat = [Feature(i, j) for (i,j) = zip(geom, prop)] - sa = collect_feature(feat) + feat = [MetaT(i, j) for (i,j) = zip(geom, prop)] + sa = collect_MetaT(feat) - @test nameof(eltype(feat)) == :Feature - @test eltype(sa) === Feature{Any,(:country_states, :rainfall),Tuple{Any,Float64}} + @test nameof(eltype(feat)) == :MetaT + @test eltype(sa) === MetaT{Any,(:country_states, :rainfall),Tuple{Any,Float64}} @test propertynames(sa) === (:main, :country_states, :rainfall) @test getproperty(sa, :country_states) isa Array{Any} @test getproperty(sa, :main) == geom From 196c162ba83280fe690e974bec64fa3c6e5fcb3c Mon Sep 17 00:00:00 2001 From: ARSH SHARMA <184517@nith.ac.in> Date: Sat, 8 Aug 2020 10:16:17 +0530 Subject: [PATCH 22/24] Use meta_table instead of collect_metat --- src/GeometryBasics.jl | 2 +- src/metadata.jl | 8 ++++---- test/runtests.jl | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/GeometryBasics.jl b/src/GeometryBasics.jl index 03472445..b8fc88ee 100644 --- a/src/GeometryBasics.jl +++ b/src/GeometryBasics.jl @@ -35,7 +35,7 @@ module GeometryBasics export GLTriangleFace, GLNormalMesh3D, GLPlainTriangleMesh, GLUVMesh3D, GLUVNormalMesh3D export AbstractMesh, Mesh, TriangleMesh export GLNormalMesh2D, PlainTriangleMesh - export MetaT, collect_MetaT + export MetaT, meta_table # all the different predefined mesh types # Note: meshes can contain arbitrary meta information, diff --git a/src/metadata.jl b/src/metadata.jl index 73b77a21..1d5f7430 100644 --- a/src/metadata.jl +++ b/src/metadata.jl @@ -272,14 +272,14 @@ function StructArrays.createinstance(::Type{F}, x, args...) where {F<:MetaT} end """ -Accepts an iterable of MetaTs and put it into a StructArray +Puts an iterable of MetaT's into a StructArray """ -function collect_MetaT(iter) +function meta_table(iter) cols = Tables.columntable(iter) - collect_MetaT(first(cols), Base.tail(cols)) + meta_table(first(cols), Base.tail(cols)) end -function collect_MetaT(main, meta::NamedTuple{names, types}) where {names, types} +function meta_table(main, meta::NamedTuple{names, types}) where {names, types} F = MetaT{eltype(main), names, StructArrays.eltypes(types)} return StructArray{F}(; main=main, meta...) end diff --git a/test/runtests.jl b/test/runtests.jl index 082f0d4a..3b550265 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -613,7 +613,7 @@ end push!(prop, (country_states = 12, rainfall = 1000)) # a pinch of heterogeneity feat = [MetaT(i, j) for (i,j) = zip(geom, prop)] - sa = collect_MetaT(feat) + sa = meta_table(feat) @test nameof(eltype(feat)) == :MetaT @test eltype(sa) === MetaT{Any,(:country_states, :rainfall),Tuple{Any,Float64}} From 6e8a93ec6558267b857e85049b2f0c8b61c6ee32 Mon Sep 17 00:00:00 2001 From: ARSH SHARMA <184517@nith.ac.in> Date: Sat, 8 Aug 2020 10:16:53 +0530 Subject: [PATCH 23/24] Field names rather than numbers in getfield --- src/metadata.jl | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/metadata.jl b/src/metadata.jl index 1d5f7430..cf8610e1 100644 --- a/src/metadata.jl +++ b/src/metadata.jl @@ -229,7 +229,7 @@ Free the MetaT from metadata i.e. returns the geometry/array of geometries """ function metafree(x::MetaT) - getfield(x, 1) + getfield(x, :main) end metafree(x::AbstractVector{<: MetaT}) = map(metafree, x) @@ -241,7 +241,7 @@ metafree(x::AbstractVector{<: MetaT}) = map(metafree, x) Returns the metadata of a `MetaT` """ function meta(x::MetaT) - getfield(x, 2) + getfield(x, :meta) end meta(x::AbstractVector{<: MetaT}) = map(meta, x) From 170b2ac051fbb14c37410b5b1260c8e57c93d190 Mon Sep 17 00:00:00 2001 From: ARSH SHARMA <184517@nith.ac.in> Date: Sat, 8 Aug 2020 10:17:08 +0530 Subject: [PATCH 24/24] Refactor function signature --- src/metadata.jl | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/metadata.jl b/src/metadata.jl index cf8610e1..4badeb16 100644 --- a/src/metadata.jl +++ b/src/metadata.jl @@ -196,9 +196,10 @@ Base.size(x::MeshMeta) = size(metafree(x)) """ - MetaT(::type{T}, Names, Types) + MetaT(geometry, meta::NamedTuple) + MetaT(geometry; meta...) -Returns a `MetaT` that holds a geometry and it's metadata +Returns a `MetaT` that holds a geometry and its metadata `MetaT` acts the same as `Meta` method. The difference lies in the fact that it is designed to handle