Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
test/.cpenv
.CondaPkg
*.arrow
*.arrows

# pixi environments
.pixi
Expand Down
62 changes: 43 additions & 19 deletions src/arrow.jl
Original file line number Diff line number Diff line change
Expand Up @@ -10,20 +10,34 @@ WKB = Symbol("geoarrow.wkb")
WKT = Symbol("geoarrow.wkt")
BOX = Symbol("geoarrow.box")

function ArrowTypes.JuliaType(::Val{POINT}, x, metadata)
D = length(x.types)
T = x.types[1]
return Geometry{PointTrait,D,T}
# Helper to unwrap Union{Missing, T} to get T
_unwrap_type(::Type{Union{Missing,T}}) where {T} = T
_unwrap_type(::Type{T}) where {T} = T

# Helper to get number of dimensions from a type
_ndims(::Type{<:NTuple{N,T}}) where {N,T} = N
_ndims(::Type{<:NamedTuple{names}}) where {names} = length(names)

# Helper to get element type from a type
_eltype(::Type{<:NTuple{N,T}}) where {N,T} = T
_eltype(::Type{<:NamedTuple{names,<:Tuple{Vararg{T}}}}) where {names,T} = T

function ArrowTypes.JuliaType(::Val{POINT}, x::Type, metadata)
T = _unwrap_type(x)
D = _ndims(T)
ET = _eltype(T)
return Geometry{PointTrait,D,ET}
end
ArrowTypes.JuliaType(::Val{LINESTRING}, x, metadata) = Geometry{LineStringTrait}
ArrowTypes.JuliaType(::Val{POLYGON}, x, metadata) = Geometry{PolygonTrait}
ArrowTypes.JuliaType(::Val{MULTIPOINT}, x, metadata) = Geometry{MultiPointTrait}
ArrowTypes.JuliaType(::Val{MULTILINESTRING}, x, metadata) = Geometry{MultiLineStringTrait}
ArrowTypes.JuliaType(::Val{MULTIPOLYGON}, x, metadata) = Geometry{MultiPolygonTrait}
ArrowTypes.JuliaType(::Val{WKB}, x, metadata) = GeoFormatTypes.WellKnownBinary
ArrowTypes.JuliaType(::Val{WKT}, x, metadata) = GeoFormatTypes.WellKnownText
function ArrowTypes.JuliaType(::Val{BOX}, x, metadata)
D = length(x.types)
ArrowTypes.JuliaType(::Val{LINESTRING}, x::Type, metadata) = Geometry{LineStringTrait}
ArrowTypes.JuliaType(::Val{POLYGON}, x::Type, metadata) = Geometry{PolygonTrait}
ArrowTypes.JuliaType(::Val{MULTIPOINT}, x::Type, metadata) = Geometry{MultiPointTrait}
ArrowTypes.JuliaType(::Val{MULTILINESTRING}, x::Type, metadata) = Geometry{MultiLineStringTrait}
ArrowTypes.JuliaType(::Val{MULTIPOLYGON}, x::Type, metadata) = Geometry{MultiPolygonTrait}
ArrowTypes.JuliaType(::Val{WKB}, x::Type, metadata) = GeoFormatTypes.WellKnownBinary
ArrowTypes.JuliaType(::Val{WKT}, x::Type, metadata) = GeoFormatTypes.WellKnownText
function ArrowTypes.JuliaType(::Val{BOX}, x::Type, metadata)
T = _unwrap_type(x)
D = _ndims(T)
if D == 4
Extents.Extent{(:X, :Y)}
elseif D == 6
Expand Down Expand Up @@ -65,8 +79,8 @@ ArrowTypes.arrowname(::Type{Geometry{PolygonTrait}}) = POLYGON
ArrowTypes.arrowname(::Type{Geometry{MultiPointTrait}}) = MULTIPOINT
ArrowTypes.arrowname(::Type{Geometry{MultiLineStringTrait}}) = MULTILINESTRING
ArrowTypes.arrowname(::Type{Geometry{MultiPolygonTrait}}) = MULTIPOLYGON
ArrowTypes.arrowname(::Type{Wrapper{WellKnownBinary,T,N,G}}) where {T,N,G} = WKB
ArrowTypes.arrowname(::Type{Wrapper{WellKnownText,T,N,G}}) where {T,N,G} = WKT
ArrowTypes.arrowname(::Type{GeoFormatTypes.WellKnownBinary}) = WKB
ArrowTypes.arrowname(::Type{GeoFormatTypes.WellKnownText}) = WKT
ArrowTypes.arrowname(::Type{Wrapper{E,PointTrait,N,G}}) where {E<:AbstractNativeEncoding,N,G} = POINT
ArrowTypes.arrowname(::Type{Wrapper{E,LineStringTrait,N,G}}) where {E<:AbstractNativeEncoding,N,G} = LINESTRING
ArrowTypes.arrowname(::Type{Wrapper{E,PolygonTrait,N,G}}) where {E<:AbstractNativeEncoding,N,G} = POLYGON
Expand All @@ -81,18 +95,28 @@ ArrowTypes.toarrow(x::Wrapper) = data(x)
ArrowTypes.toarrow(ex::Extents.Extent{(:X, :Y)}) = (; xmin=ex.X[1], ymin=ex.Y[1], xmax=ex.X[2], ymax=ex.Y[2])
ArrowTypes.toarrow(ex::Extents.Extent{(:X, :Y, :Z)}) = (; xmin=ex.X[1], ymin=ex.Y[1], zmin=ex.Z[1], xmax=ex.X[2], ymax=ex.Y[2], zmax=ex.Z[2])
ArrowTypes.toarrow(ex::Extents.Extent{(:X, :Y, :Z, :M)}) = (; xmin=ex.X[1], ymin=ex.Y[1], zmin=ex.Z[1], mmin=ex.M[1], xmax=ex.X[2], ymax=ex.Y[2], zmax=ex.Z[2], mmax=ex.M[2])
ArrowTypes.toarrow(geom::GeoFormatTypes.WellKnownBinary{GeoFormatTypes.Geom}) = GeoFormatTypes.val(geom)
ArrowTypes.toarrow(geom::GeoFormatTypes.WellKnownText{GeoFormatTypes.Geom}) = GeoFormatTypes.val(geom)

ArrowTypes.fromarrow(::Type{GeoFormatTypes.WellKnownBinary}, x) = GeoFormatTypes.WellKnownBinary(GeoFormatTypes.Geom(), x)
ArrowTypes.fromarrow(::Type{GeoFormatTypes.WellKnownText}, x) = GeoFormatTypes.WellKnownText(GeoFormatTypes.Geom(), String(x)) # should be StringView

# fromarrow for list-based encodings (interleaved)
function ArrowTypes.fromarrow(::Type{Geometry{X}}, x) where {X}
nt = nested_eltype(x)
D = length(nt.types)
return Geometry{X,D,Float64}(x)
end
function fromarrow(::Type{GeoArrow.Geometry{X}}, nt::NamedTuple) where X
return Geometry{X,length(nt),Float64}(nt)
end
ArrowTypes.fromarrow(::Type{Extents.Extent}, x) = Extents.Extent(X=(x.xmin, x.xmax), Y=(x.ymin, x.ymax))

# fromarrow for separated Point encoding (Struct with x, y, [z, [m]] fields)
ArrowTypes.fromarrow(::Type{Geometry{PointTrait,2,T}}, x, y) where {T} = Geometry{PointTrait,2,T}((x, y))
ArrowTypes.fromarrow(::Type{Geometry{PointTrait,3,T}}, x, y, z) where {T} = Geometry{PointTrait,3,T}((x, y, z))
ArrowTypes.fromarrow(::Type{Geometry{PointTrait,4,T}}, x, y, z, m) where {T} = Geometry{PointTrait,4,T}((x, y, z, m))

# fromarrow for Box/Extent (Struct with xmin, ymin, xmax, ymax, [zmin, zmax, [mmin, mmax]] fields)
ArrowTypes.fromarrow(::Type{Extents.Extent{(:X, :Y)}}, xmin, ymin, xmax, ymax) = Extents.Extent(X=(xmin, xmax), Y=(ymin, ymax))
ArrowTypes.fromarrow(::Type{Extents.Extent{(:X, :Y, :Z)}}, xmin, ymin, zmin, xmax, ymax, zmax) = Extents.Extent(X=(xmin, xmax), Y=(ymin, ymax), Z=(zmin, zmax))
ArrowTypes.fromarrow(::Type{Extents.Extent{(:X, :Y, :Z, :M)}}, xmin, ymin, zmin, mmin, xmax, ymax, zmax, mmax) = Extents.Extent(X=(xmin, xmax), Y=(ymin, ymax), Z=(zmin, zmax), M=(mmin, mmax))

nested_eltype(x) = nested_eltype(typeof(x))
nested_eltype(::Type{Union{Missing,T}}) where {T} = nested_eltype(T)
Expand Down
7 changes: 4 additions & 3 deletions src/io.jl
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,10 @@ function write(path, t; geocolumns=GeoInterface.geometrycolumns(t), crs=GeoInter
column in Tables.columnnames(t) || error("Geometry column $column not found in table")
data = Tables.getcolumn(t, column)
T = nonmissingtype(Tables.columntype(t, column))
GeoInterface.isgeometry(T) || error("Geometry in $column must support the GeoInterface")
ct = merge(ct, NamedTuple{(column,)}((Wrapper.(Ref(encoding), data),)))

if ArrowTypes.arrowname(T) == Symbol("")
GeoInterface.isgeometry(T) || error("Geometry in $column must support the GeoInterface")
ct = merge(ct, NamedTuple{(column,)}((Wrapper.(Ref(encoding), data),)))
end
geometa = Dict("ARROW:extension:metadata" => JSON3.write(dcrs))
if haskey(colmetadata, column)
merge!(colmetadata[column], geometa)
Expand Down
2 changes: 2 additions & 0 deletions src/type.jl
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ Base.:(==)(x::Geometry{X,D,T,G}, y::Geometry{X,D,T,G}) where {X,D,T,G} = x.geom
Base.show(io::IO, x::Geometry{X,D,T}) where {X,D,T} = print(io, "$X geometry in $(D)D with eltype $T")
Geometry{X,D,T}(x) where {X,D,T} = Geometry{X,D,T,typeof(x)}(x)
Geometry{PointTrait}(x::Vararg{T,D}) where {T,D} = Geometry{PointTrait,D,T}(reinterpret(NTuple{D,T}, x))
Geometry{PointTrait,D,T}(x, y, z, m) where {T,D} = Geometry{PointTrait,D,T}((x, y, z, m))
Geometry{PointTrait,D,T}(x, y, z) where {T,D} = Geometry{PointTrait,D,T}((x, y, z))
Geometry{PointTrait,D,T}(x, y) where {T,D} = Geometry{PointTrait,D,T}((x, y))

Expand Down Expand Up @@ -53,6 +54,7 @@ end
Base.:(==)(x::Wrapper{E,T,N,G}, y::Wrapper{E,T,N,G}) where {E,T,N,G} = x.geom == y.geom
Base.show(io::IO, ::Wrapper{E,T,G}) where {E,T,G} = print(io, "$T geometry encoded as $E")
Wrapper(e::AbstractEncoding, x) = Wrapper{typeof(e),typeof(GeoInterface.geomtrait(x)),GeoInterface.ncoord(x),typeof(x)}(x)
Wrapper(::AbstractEncoding, ::Missing) = missing
Wrapper(x) = Wrapper(Interleaved(), x)

data(x::Wrapper{E,T,N,G}) where {E,T,N,G} = _coordinates(E(), T(), Val{N}(), x.geom)
Expand Down
Loading
Loading