forked from postgis/postgis
FlatGeobuf format input/output
parent
3083021ce2
commit
3ae2c58440
|
@ -9,3 +9,4 @@ coverage:
|
|||
comment: false
|
||||
ignore:
|
||||
- "deps/wagyu/include/**/*" # Ignore wagyu library files
|
||||
- "deps/flatgeobuf/**/*" # Ignore FlatGeobuf library files
|
||||
|
|
|
@ -196,3 +196,4 @@ postgis/uninstall_sfcgal.sql
|
|||
deps/Makefile
|
||||
deps/wagyu/Makefile
|
||||
deps/ryu/Makefile
|
||||
deps/flatgeobuf/Makefile
|
||||
|
|
70
configure.ac
70
configure.ac
|
@ -1548,6 +1548,73 @@ DEPS_MAKEFILE_LIST="$DEPS_MAKEFILE_LIST
|
|||
deps/ryu/Makefile"
|
||||
|
||||
|
||||
dnl ===========================================================================
|
||||
dnl FlatGeobuf
|
||||
dnl ===========================================================================
|
||||
|
||||
DEPS_SUBDIR="deps"
|
||||
AC_SUBST([DEPS_SUBDIR])
|
||||
|
||||
FLATGEOBUF_LIB=libflatgeobuf.la
|
||||
AC_SUBST([FLATGEOBUF_LIB])
|
||||
|
||||
dnl ============================================================
|
||||
dnl We force to use the same compiler as Postgresql
|
||||
dnl ============================================================
|
||||
CXX_SAVE="$CXX"
|
||||
CC_SAVE="$CC"
|
||||
CFLAGS_SAVE="$CFLAGS"
|
||||
CXXFLAGS_SAVE="$CXXFLAGS"
|
||||
CPPFLAGS_SAVE="$CPPFLAGS"
|
||||
LDFLAGS_SAVE="$LDFLAGS"
|
||||
LIBS_SAVE="$LIBS"
|
||||
|
||||
FLATGEOBUF_CXX=`"$PG_CONFIG" --cc`
|
||||
CPPFLAGS="-x c++"
|
||||
CFLAGS=""
|
||||
LDFLAGS=""
|
||||
LIBS=""
|
||||
CXX="$FLATGEOBUF_CXX"
|
||||
AC_PROG_CXX
|
||||
AX_CXX_COMPILE_STDCXX(11, noext, mandatory)
|
||||
FLATGEOBUF_CXX="$CXX -x c++"
|
||||
|
||||
dnl ============================================================
|
||||
dnl Check if we can declare the c++ stdlib
|
||||
dnl ============================================================
|
||||
CC="$FLATGEOBUF_CXX"
|
||||
|
||||
AC_CHECK_LIB(c++, main, [HAVE_CPP=yes], [HAVE_CPP=no])
|
||||
AC_CHECK_LIB(stdc++, main, [HAVE_STDCPP=yes], [HAVE_STDCPP=no])
|
||||
|
||||
if test "x$HAVE_CPP" = "xyes"; then
|
||||
WFLATGEOBUF_LDFLAGS="-lc++"
|
||||
elif test "x$HAVE_STDCPP" = "xyes"; then
|
||||
FLATGEOBUF_LDFLAGS="-lstdc++"
|
||||
else
|
||||
AC_MSG_WARN("Could not find a C++ standard library")
|
||||
FLATGEOBUF_LDFLAGS=""
|
||||
fi
|
||||
|
||||
CXX="$CXX_SAVE"
|
||||
CC="$CC_SAVE"
|
||||
CFLAGS="$CFLAGS_SAVE"
|
||||
CXXFLAGS="$CXXFLAGS_SAVE"
|
||||
CPPFLAGS="$CPPFLAGS_SAVE"
|
||||
LDFLAGS="$LDFLAGS_SAVE"
|
||||
LIBS="$LIBS_SAVE"
|
||||
|
||||
HAVE_FLATGEOBUF=yes
|
||||
AC_DEFINE([HAVE_FLATGEOBUF], [1], [Define to 1 if FlatGeobuf is being built])
|
||||
AC_SUBST([HAVE_FLATGEOBUF])
|
||||
AC_SUBST([FLATGEOBUF_CXX])
|
||||
AC_SUBST([FLATGEOBUF_LDFLAGS])
|
||||
|
||||
DEPS_MAKEFILE_LIST="$DEPS_MAKEFILE_LIST
|
||||
deps/flatgeobuf/Makefile"
|
||||
|
||||
|
||||
|
||||
dnl ===========================================================================
|
||||
dnl See if we have the requirements for building the extensions, namely
|
||||
dnl the xlstproc tool for generating the comments SQL file.
|
||||
|
@ -1614,6 +1681,9 @@ AC_MSG_RESULT([ C compiler: ${CC} ${CFLAGS}])
|
|||
if test "x$HAVE_WAGYU" = "xyes"; then
|
||||
AC_MSG_RESULT([ C++ compiler (Wagyu): ${WAGYU_CXX} ${CXXFLAGS}])
|
||||
fi
|
||||
if test "x$HAVE_FLATGEOBUF" = "xyes"; then
|
||||
AC_MSG_RESULT([ C++ compiler (FlatGeobuf): ${FLATGEOBUF_CXX} ${CXXFLAGS}])
|
||||
fi
|
||||
AC_MSG_RESULT([ CPPFLAGS: $CPPFLAGS])
|
||||
AC_MSG_RESULT([ LDFLAGS: $LDFLAGS])
|
||||
AC_MSG_RESULT([ SQL preprocessor: ${SQLPP}])
|
||||
|
|
|
@ -31,7 +31,7 @@ top_builddir = @top_builddir@
|
|||
libdir = @libdir@
|
||||
LIBTOOL = @LIBTOOL@
|
||||
|
||||
all: @WAGYU_LIB@ @RYU_LIB@
|
||||
all: @WAGYU_LIB@ @RYU_LIB@ @FLATGEOBUF_LIB@
|
||||
|
||||
@WAGYU_LIB@:
|
||||
$(MAKE) -C wagyu $@
|
||||
|
@ -39,13 +39,18 @@ all: @WAGYU_LIB@ @RYU_LIB@
|
|||
@RYU_LIB@:
|
||||
$(MAKE) -C ryu $@
|
||||
|
||||
@FLATGEOBUF_LIB@:
|
||||
$(MAKE) -C flatgeobuf $@
|
||||
|
||||
clean:
|
||||
$(MAKE) -C wagyu $@
|
||||
$(MAKE) -C ryu $@
|
||||
$(MAKE) -C flatgeobuf $@
|
||||
|
||||
distclean: clean
|
||||
$(MAKE) -C wagyu $@
|
||||
$(MAKE) -C ryu $@
|
||||
$(MAKE) -C flatgeobuf $@
|
||||
rm -f Makefile
|
||||
|
||||
.PHONY: install uninstall check check-unit check-regress
|
||||
|
|
|
@ -0,0 +1,68 @@
|
|||
#/**********************************************************************
|
||||
# *
|
||||
# * PostGIS - Spatial Types for PostgreSQL
|
||||
# * http://postgis.net
|
||||
# *
|
||||
# * PostGIS is free software: you can redistribute it and/or modify
|
||||
# * it under the terms of the GNU General Public License as published by
|
||||
# * the Free Software Foundation, either version 2 of the License, or
|
||||
# * (at your option) any later version.
|
||||
# *
|
||||
# * PostGIS is distributed in the hope that it will be useful,
|
||||
# * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# * GNU General Public License for more details.
|
||||
# *
|
||||
# * You should have received a copy of the GNU General Public License
|
||||
# * along with PostGIS. If not, see <http://www.gnu.org/licenses/>.
|
||||
# *
|
||||
# **********************************************************************
|
||||
# *
|
||||
# * Copyright 2021 Björn Harrtell
|
||||
# *
|
||||
# **********************************************************************/
|
||||
|
||||
CXX = @FLATGEOBUF_CXX@
|
||||
CXXFLAGS =-I../../liblwgeom -Iinclude @CPPFLAGS@ @CXXFLAGS@ @PICFLAGS@
|
||||
LDFLAGS = @LDFLAGS@
|
||||
top_builddir = @top_builddir@
|
||||
libdir = @libdir@
|
||||
LIBTOOL = @LIBTOOL@
|
||||
|
||||
FLATGEOBUF_OBJS = \
|
||||
flatgeobuf_c.o geometrywriter.o geometryreader.o packedrtree.o
|
||||
|
||||
FLATGEOBUF_HEADERS = \
|
||||
flatgeobuf_c.h \
|
||||
geometrywriter.h \
|
||||
geometryreader.h \
|
||||
packedrtree.h \
|
||||
include/flatbuffers/flatbuffers.h \
|
||||
include/flatbuffers/base.h \
|
||||
include/flatbuffers/stl_emulation.h
|
||||
|
||||
all: @FLATGEOBUF_LIB@
|
||||
|
||||
@FLATGEOBUF_LIB@: $(FLATGEOBUF_OBJS)
|
||||
ar rs @FLATGEOBUF_LIB@ $(FLATGEOBUF_OBJS)
|
||||
|
||||
$(FLATGEOBUF_OBJS): %.o: %.cpp ../../liblwgeom/liblwgeom.h $(FLATGEOBUF_HEADERS)
|
||||
$(CXX) $(CXXFLAGS) -c -o $@ $<
|
||||
|
||||
../../liblwgeom/liblwgeom.h:
|
||||
$(MAKE) -C ../../liblwgeom liblwgeom.h
|
||||
|
||||
clean:
|
||||
rm -f @FLATGEOBUF_LIB@ $(FLATGEOBUF_OBJS)
|
||||
|
||||
distclean: clean
|
||||
rm -f Makefile
|
||||
|
||||
|
||||
install:
|
||||
|
||||
uninstall:
|
||||
|
||||
check:
|
||||
|
||||
.PHONY: clean distclean install uninstall check
|
|
@ -0,0 +1,278 @@
|
|||
// automatically generated by the FlatBuffers compiler, do not modify
|
||||
|
||||
|
||||
#ifndef FLATBUFFERS_GENERATED_FEATURE_FLATGEOBUF_H_
|
||||
#define FLATBUFFERS_GENERATED_FEATURE_FLATGEOBUF_H_
|
||||
|
||||
#include "flatbuffers/flatbuffers.h"
|
||||
|
||||
#include "header_generated.h"
|
||||
|
||||
namespace FlatGeobuf {
|
||||
|
||||
struct Geometry;
|
||||
struct GeometryBuilder;
|
||||
|
||||
struct Feature;
|
||||
struct FeatureBuilder;
|
||||
|
||||
struct Geometry FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
|
||||
typedef GeometryBuilder Builder;
|
||||
enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE {
|
||||
VT_ENDS = 4,
|
||||
VT_XY = 6,
|
||||
VT_Z = 8,
|
||||
VT_M = 10,
|
||||
VT_T = 12,
|
||||
VT_TM = 14,
|
||||
VT_TYPE = 16,
|
||||
VT_PARTS = 18
|
||||
};
|
||||
const flatbuffers::Vector<uint32_t> *ends() const {
|
||||
return GetPointer<const flatbuffers::Vector<uint32_t> *>(VT_ENDS);
|
||||
}
|
||||
const flatbuffers::Vector<double> *xy() const {
|
||||
return GetPointer<const flatbuffers::Vector<double> *>(VT_XY);
|
||||
}
|
||||
const flatbuffers::Vector<double> *z() const {
|
||||
return GetPointer<const flatbuffers::Vector<double> *>(VT_Z);
|
||||
}
|
||||
const flatbuffers::Vector<double> *m() const {
|
||||
return GetPointer<const flatbuffers::Vector<double> *>(VT_M);
|
||||
}
|
||||
const flatbuffers::Vector<double> *t() const {
|
||||
return GetPointer<const flatbuffers::Vector<double> *>(VT_T);
|
||||
}
|
||||
const flatbuffers::Vector<uint64_t> *tm() const {
|
||||
return GetPointer<const flatbuffers::Vector<uint64_t> *>(VT_TM);
|
||||
}
|
||||
FlatGeobuf::GeometryType type() const {
|
||||
return static_cast<FlatGeobuf::GeometryType>(GetField<uint8_t>(VT_TYPE, 0));
|
||||
}
|
||||
const flatbuffers::Vector<flatbuffers::Offset<FlatGeobuf::Geometry>> *parts() const {
|
||||
return GetPointer<const flatbuffers::Vector<flatbuffers::Offset<FlatGeobuf::Geometry>> *>(VT_PARTS);
|
||||
}
|
||||
bool Verify(flatbuffers::Verifier &verifier) const {
|
||||
return VerifyTableStart(verifier) &&
|
||||
VerifyOffset(verifier, VT_ENDS) &&
|
||||
verifier.VerifyVector(ends()) &&
|
||||
VerifyOffset(verifier, VT_XY) &&
|
||||
verifier.VerifyVector(xy()) &&
|
||||
VerifyOffset(verifier, VT_Z) &&
|
||||
verifier.VerifyVector(z()) &&
|
||||
VerifyOffset(verifier, VT_M) &&
|
||||
verifier.VerifyVector(m()) &&
|
||||
VerifyOffset(verifier, VT_T) &&
|
||||
verifier.VerifyVector(t()) &&
|
||||
VerifyOffset(verifier, VT_TM) &&
|
||||
verifier.VerifyVector(tm()) &&
|
||||
VerifyField<uint8_t>(verifier, VT_TYPE) &&
|
||||
VerifyOffset(verifier, VT_PARTS) &&
|
||||
verifier.VerifyVector(parts()) &&
|
||||
verifier.VerifyVectorOfTables(parts()) &&
|
||||
verifier.EndTable();
|
||||
}
|
||||
};
|
||||
|
||||
struct GeometryBuilder {
|
||||
typedef Geometry Table;
|
||||
flatbuffers::FlatBufferBuilder &fbb_;
|
||||
flatbuffers::uoffset_t start_;
|
||||
void add_ends(flatbuffers::Offset<flatbuffers::Vector<uint32_t>> ends) {
|
||||
fbb_.AddOffset(Geometry::VT_ENDS, ends);
|
||||
}
|
||||
void add_xy(flatbuffers::Offset<flatbuffers::Vector<double>> xy) {
|
||||
fbb_.AddOffset(Geometry::VT_XY, xy);
|
||||
}
|
||||
void add_z(flatbuffers::Offset<flatbuffers::Vector<double>> z) {
|
||||
fbb_.AddOffset(Geometry::VT_Z, z);
|
||||
}
|
||||
void add_m(flatbuffers::Offset<flatbuffers::Vector<double>> m) {
|
||||
fbb_.AddOffset(Geometry::VT_M, m);
|
||||
}
|
||||
void add_t(flatbuffers::Offset<flatbuffers::Vector<double>> t) {
|
||||
fbb_.AddOffset(Geometry::VT_T, t);
|
||||
}
|
||||
void add_tm(flatbuffers::Offset<flatbuffers::Vector<uint64_t>> tm) {
|
||||
fbb_.AddOffset(Geometry::VT_TM, tm);
|
||||
}
|
||||
void add_type(FlatGeobuf::GeometryType type) {
|
||||
fbb_.AddElement<uint8_t>(Geometry::VT_TYPE, static_cast<uint8_t>(type), 0);
|
||||
}
|
||||
void add_parts(flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<FlatGeobuf::Geometry>>> parts) {
|
||||
fbb_.AddOffset(Geometry::VT_PARTS, parts);
|
||||
}
|
||||
explicit GeometryBuilder(flatbuffers::FlatBufferBuilder &_fbb)
|
||||
: fbb_(_fbb) {
|
||||
start_ = fbb_.StartTable();
|
||||
}
|
||||
flatbuffers::Offset<Geometry> Finish() {
|
||||
const auto end = fbb_.EndTable(start_);
|
||||
auto o = flatbuffers::Offset<Geometry>(end);
|
||||
return o;
|
||||
}
|
||||
};
|
||||
|
||||
inline flatbuffers::Offset<Geometry> CreateGeometry(
|
||||
flatbuffers::FlatBufferBuilder &_fbb,
|
||||
flatbuffers::Offset<flatbuffers::Vector<uint32_t>> ends = 0,
|
||||
flatbuffers::Offset<flatbuffers::Vector<double>> xy = 0,
|
||||
flatbuffers::Offset<flatbuffers::Vector<double>> z = 0,
|
||||
flatbuffers::Offset<flatbuffers::Vector<double>> m = 0,
|
||||
flatbuffers::Offset<flatbuffers::Vector<double>> t = 0,
|
||||
flatbuffers::Offset<flatbuffers::Vector<uint64_t>> tm = 0,
|
||||
FlatGeobuf::GeometryType type = FlatGeobuf::GeometryType::Unknown,
|
||||
flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<FlatGeobuf::Geometry>>> parts = 0) {
|
||||
GeometryBuilder builder_(_fbb);
|
||||
builder_.add_parts(parts);
|
||||
builder_.add_tm(tm);
|
||||
builder_.add_t(t);
|
||||
builder_.add_m(m);
|
||||
builder_.add_z(z);
|
||||
builder_.add_xy(xy);
|
||||
builder_.add_ends(ends);
|
||||
builder_.add_type(type);
|
||||
return builder_.Finish();
|
||||
}
|
||||
|
||||
inline flatbuffers::Offset<Geometry> CreateGeometryDirect(
|
||||
flatbuffers::FlatBufferBuilder &_fbb,
|
||||
const std::vector<uint32_t> *ends = nullptr,
|
||||
const std::vector<double> *xy = nullptr,
|
||||
const std::vector<double> *z = nullptr,
|
||||
const std::vector<double> *m = nullptr,
|
||||
const std::vector<double> *t = nullptr,
|
||||
const std::vector<uint64_t> *tm = nullptr,
|
||||
FlatGeobuf::GeometryType type = FlatGeobuf::GeometryType::Unknown,
|
||||
const std::vector<flatbuffers::Offset<FlatGeobuf::Geometry>> *parts = nullptr) {
|
||||
auto ends__ = ends ? _fbb.CreateVector<uint32_t>(*ends) : 0;
|
||||
auto xy__ = xy ? _fbb.CreateVector<double>(*xy) : 0;
|
||||
auto z__ = z ? _fbb.CreateVector<double>(*z) : 0;
|
||||
auto m__ = m ? _fbb.CreateVector<double>(*m) : 0;
|
||||
auto t__ = t ? _fbb.CreateVector<double>(*t) : 0;
|
||||
auto tm__ = tm ? _fbb.CreateVector<uint64_t>(*tm) : 0;
|
||||
auto parts__ = parts ? _fbb.CreateVector<flatbuffers::Offset<FlatGeobuf::Geometry>>(*parts) : 0;
|
||||
return FlatGeobuf::CreateGeometry(
|
||||
_fbb,
|
||||
ends__,
|
||||
xy__,
|
||||
z__,
|
||||
m__,
|
||||
t__,
|
||||
tm__,
|
||||
type,
|
||||
parts__);
|
||||
}
|
||||
|
||||
struct Feature FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
|
||||
typedef FeatureBuilder Builder;
|
||||
enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE {
|
||||
VT_GEOMETRY = 4,
|
||||
VT_PROPERTIES = 6,
|
||||
VT_COLUMNS = 8
|
||||
};
|
||||
const FlatGeobuf::Geometry *geometry() const {
|
||||
return GetPointer<const FlatGeobuf::Geometry *>(VT_GEOMETRY);
|
||||
}
|
||||
const flatbuffers::Vector<uint8_t> *properties() const {
|
||||
return GetPointer<const flatbuffers::Vector<uint8_t> *>(VT_PROPERTIES);
|
||||
}
|
||||
const flatbuffers::Vector<flatbuffers::Offset<FlatGeobuf::Column>> *columns() const {
|
||||
return GetPointer<const flatbuffers::Vector<flatbuffers::Offset<FlatGeobuf::Column>> *>(VT_COLUMNS);
|
||||
}
|
||||
bool Verify(flatbuffers::Verifier &verifier) const {
|
||||
return VerifyTableStart(verifier) &&
|
||||
VerifyOffset(verifier, VT_GEOMETRY) &&
|
||||
verifier.VerifyTable(geometry()) &&
|
||||
VerifyOffset(verifier, VT_PROPERTIES) &&
|
||||
verifier.VerifyVector(properties()) &&
|
||||
VerifyOffset(verifier, VT_COLUMNS) &&
|
||||
verifier.VerifyVector(columns()) &&
|
||||
verifier.VerifyVectorOfTables(columns()) &&
|
||||
verifier.EndTable();
|
||||
}
|
||||
};
|
||||
|
||||
struct FeatureBuilder {
|
||||
typedef Feature Table;
|
||||
flatbuffers::FlatBufferBuilder &fbb_;
|
||||
flatbuffers::uoffset_t start_;
|
||||
void add_geometry(flatbuffers::Offset<FlatGeobuf::Geometry> geometry) {
|
||||
fbb_.AddOffset(Feature::VT_GEOMETRY, geometry);
|
||||
}
|
||||
void add_properties(flatbuffers::Offset<flatbuffers::Vector<uint8_t>> properties) {
|
||||
fbb_.AddOffset(Feature::VT_PROPERTIES, properties);
|
||||
}
|
||||
void add_columns(flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<FlatGeobuf::Column>>> columns) {
|
||||
fbb_.AddOffset(Feature::VT_COLUMNS, columns);
|
||||
}
|
||||
explicit FeatureBuilder(flatbuffers::FlatBufferBuilder &_fbb)
|
||||
: fbb_(_fbb) {
|
||||
start_ = fbb_.StartTable();
|
||||
}
|
||||
flatbuffers::Offset<Feature> Finish() {
|
||||
const auto end = fbb_.EndTable(start_);
|
||||
auto o = flatbuffers::Offset<Feature>(end);
|
||||
return o;
|
||||
}
|
||||
};
|
||||
|
||||
inline flatbuffers::Offset<Feature> CreateFeature(
|
||||
flatbuffers::FlatBufferBuilder &_fbb,
|
||||
flatbuffers::Offset<FlatGeobuf::Geometry> geometry = 0,
|
||||
flatbuffers::Offset<flatbuffers::Vector<uint8_t>> properties = 0,
|
||||
flatbuffers::Offset<flatbuffers::Vector<flatbuffers::Offset<FlatGeobuf::Column>>> columns = 0) {
|
||||
FeatureBuilder builder_(_fbb);
|
||||
builder_.add_columns(columns);
|
||||
builder_.add_properties(properties);
|
||||
builder_.add_geometry(geometry);
|
||||
return builder_.Finish();
|
||||
}
|
||||
|
||||
inline flatbuffers::Offset<Feature> CreateFeatureDirect(
|
||||
flatbuffers::FlatBufferBuilder &_fbb,
|
||||
flatbuffers::Offset<FlatGeobuf::Geometry> geometry = 0,
|
||||
const std::vector<uint8_t> *properties = nullptr,
|
||||
const std::vector<flatbuffers::Offset<FlatGeobuf::Column>> *columns = nullptr) {
|
||||
auto properties__ = properties ? _fbb.CreateVector<uint8_t>(*properties) : 0;
|
||||
auto columns__ = columns ? _fbb.CreateVector<flatbuffers::Offset<FlatGeobuf::Column>>(*columns) : 0;
|
||||
return FlatGeobuf::CreateFeature(
|
||||
_fbb,
|
||||
geometry,
|
||||
properties__,
|
||||
columns__);
|
||||
}
|
||||
|
||||
inline const FlatGeobuf::Feature *GetFeature(const void *buf) {
|
||||
return flatbuffers::GetRoot<FlatGeobuf::Feature>(buf);
|
||||
}
|
||||
|
||||
inline const FlatGeobuf::Feature *GetSizePrefixedFeature(const void *buf) {
|
||||
return flatbuffers::GetSizePrefixedRoot<FlatGeobuf::Feature>(buf);
|
||||
}
|
||||
|
||||
inline bool VerifyFeatureBuffer(
|
||||
flatbuffers::Verifier &verifier) {
|
||||
return verifier.VerifyBuffer<FlatGeobuf::Feature>(nullptr);
|
||||
}
|
||||
|
||||
inline bool VerifySizePrefixedFeatureBuffer(
|
||||
flatbuffers::Verifier &verifier) {
|
||||
return verifier.VerifySizePrefixedBuffer<FlatGeobuf::Feature>(nullptr);
|
||||
}
|
||||
|
||||
inline void FinishFeatureBuffer(
|
||||
flatbuffers::FlatBufferBuilder &fbb,
|
||||
flatbuffers::Offset<FlatGeobuf::Feature> root) {
|
||||
fbb.Finish(root);
|
||||
}
|
||||
|
||||
inline void FinishSizePrefixedFeatureBuffer(
|
||||
flatbuffers::FlatBufferBuilder &fbb,
|
||||
flatbuffers::Offset<FlatGeobuf::Feature> root) {
|
||||
fbb.FinishSizePrefixed(root);
|
||||
}
|
||||
|
||||
} // namespace FlatGeobuf
|
||||
|
||||
#endif // FLATBUFFERS_GENERATED_FEATURE_FLATGEOBUF_H_
|
|
@ -0,0 +1,306 @@
|
|||
/**********************************************************************
|
||||
*
|
||||
* PostGIS - Spatial Types for PostgreSQL
|
||||
* http://postgis.net
|
||||
*
|
||||
* PostGIS is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* PostGIS is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with PostGIS. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
**********************************************************************
|
||||
*
|
||||
* Copyright 2021 Björn Harrtell
|
||||
*
|
||||
**********************************************************************/
|
||||
|
||||
#include "flatgeobuf_c.h"
|
||||
#include "feature_generated.h"
|
||||
#include "geometrywriter.h"
|
||||
#include "geometryreader.h"
|
||||
#include "packedrtree.h"
|
||||
|
||||
using namespace flatbuffers;
|
||||
using namespace FlatGeobuf;
|
||||
|
||||
typedef flatgeobuf_ctx ctx;
|
||||
|
||||
uint8_t flatgeobuf_magicbytes[] = { 0x66, 0x67, 0x62, 0x03, 0x66, 0x67, 0x62, 0x00 };
|
||||
uint8_t FLATGEOBUF_MAGICBYTES_SIZE = sizeof(flatgeobuf_magicbytes);
|
||||
uint8_t FLATGEOBUF_MAGICBYTES_LEN = (sizeof(flatgeobuf_magicbytes) / sizeof((flatgeobuf_magicbytes)[0]));
|
||||
|
||||
struct FeatureItem : FlatGeobuf::Item {
|
||||
uoffset_t size;
|
||||
uint64_t offset;
|
||||
};
|
||||
|
||||
int flatgeobuf_encode_header(ctx *ctx)
|
||||
{
|
||||
FlatBufferBuilder fbb;
|
||||
|
||||
// inspect first geometry
|
||||
if (ctx->lwgeom != NULL) {
|
||||
if (lwgeom_has_srid(ctx->lwgeom))
|
||||
ctx->srid = ctx->lwgeom->srid;
|
||||
ctx->has_z = lwgeom_has_z(ctx->lwgeom);
|
||||
ctx->has_m = lwgeom_has_m(ctx->lwgeom);
|
||||
ctx->geometry_type = (uint8_t) GeometryWriter::get_geometrytype(ctx->lwgeom);
|
||||
} else {
|
||||
LWDEBUG(2, "ctx->lwgeom is null");
|
||||
ctx->geometry_type = 0;
|
||||
}
|
||||
|
||||
LWDEBUGF(2, "ctx->geometry_type %d", ctx->geometry_type);
|
||||
|
||||
std::vector<flatbuffers::Offset<FlatGeobuf::Column>> columns;
|
||||
std::vector<flatbuffers::Offset<FlatGeobuf::Column>> *pColumns = nullptr;
|
||||
|
||||
if (ctx->columns_size > 0) {
|
||||
for (uint16_t i = 0; i < ctx->columns_size; i++) {
|
||||
auto c = ctx->columns[i];
|
||||
columns.push_back(CreateColumnDirect(fbb, c->name, (ColumnType) c->type));
|
||||
}
|
||||
}
|
||||
|
||||
if (columns.size() > 0)
|
||||
pColumns = &columns;
|
||||
|
||||
flatbuffers::Offset<Crs> crs = 0;
|
||||
if (ctx->srid > 0)
|
||||
crs = CreateCrsDirect(fbb, nullptr, ctx->srid);
|
||||
|
||||
std::vector<double> *pEnvelope = nullptr;
|
||||
if (ctx->has_extent) {
|
||||
std::vector<double> envelope = { ctx->xmin, ctx->ymin, ctx->xmax, ctx->ymax };
|
||||
pEnvelope = &envelope;
|
||||
}
|
||||
|
||||
const auto header = CreateHeaderDirect(
|
||||
fbb, ctx->name, pEnvelope, (GeometryType) ctx->geometry_type, ctx->has_z, ctx->has_m, ctx->has_t, ctx->has_tm, pColumns, ctx->features_count, ctx->index_node_size, crs);
|
||||
fbb.FinishSizePrefixed(header);
|
||||
const auto buffer = fbb.GetBufferPointer();
|
||||
const auto size = fbb.GetSize();
|
||||
|
||||
LWDEBUGF(2, "header size %d (with size prefix)", size);
|
||||
|
||||
Verifier verifier(buffer, size - sizeof(uoffset_t));
|
||||
if (VerifySizePrefixedHeaderBuffer(verifier)) {
|
||||
lwerror("buffer did not pass verification");
|
||||
return -1;
|
||||
}
|
||||
|
||||
ctx->buf = (uint8_t *) lwrealloc(ctx->buf, ctx->offset + size);
|
||||
LWDEBUGF(2, "copying to ctx->buf at offset %ld", ctx->offset);
|
||||
memcpy(ctx->buf + ctx->offset, buffer, size);
|
||||
|
||||
ctx->offset += size;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int flatgeobuf_encode_feature(ctx *ctx)
|
||||
{
|
||||
FlatBufferBuilder fbb;
|
||||
Offset<Geometry> geometry = 0;
|
||||
Offset<Vector<uint8_t>> properties = 0;
|
||||
|
||||
if (ctx->lwgeom != NULL) {
|
||||
LWDEBUGG(3, ctx->lwgeom, "GeometryWriter input LWGEOM");
|
||||
GeometryWriter writer(fbb, ctx->lwgeom, (GeometryType) ctx->geometry_type, ctx->has_z, ctx->has_m);
|
||||
geometry = writer.write(0);
|
||||
}
|
||||
if (ctx->properties_len > 0)
|
||||
properties = fbb.CreateVector<uint8_t>(ctx->properties, ctx->properties_len);
|
||||
FeatureBuilder builder(fbb);
|
||||
builder.add_geometry(geometry);
|
||||
builder.add_properties(properties);
|
||||
auto feature = builder.Finish();
|
||||
fbb.FinishSizePrefixed(feature);
|
||||
const auto buffer = fbb.GetBufferPointer();
|
||||
const auto size = fbb.GetSize();
|
||||
|
||||
LWDEBUGF(3, "encode_feature size %ld", size);
|
||||
|
||||
Verifier verifier(buffer, size - sizeof(uoffset_t));
|
||||
if (VerifySizePrefixedFeatureBuffer(verifier)) {
|
||||
lwerror("buffer did not pass verification");
|
||||
return -1;
|
||||
}
|
||||
|
||||
LWDEBUGF(3, "reallocating ctx->buf to size %ld", ctx->offset + size);
|
||||
ctx->buf = (uint8_t * ) lwrealloc(ctx->buf, ctx->offset + size);
|
||||
LWDEBUGF(3, "copying feature to ctx->buf at offset %ld", ctx->offset);
|
||||
memcpy(ctx->buf + ctx->offset, buffer, size);
|
||||
|
||||
if (ctx->create_index) {
|
||||
auto item = (flatgeobuf_item *) lwalloc(sizeof(flatgeobuf_item));
|
||||
auto gbox = lwgeom_get_bbox(ctx->lwgeom);
|
||||
item->xmin = gbox->xmin;
|
||||
item->xmax = gbox->xmax;
|
||||
item->ymin = gbox->ymin;
|
||||
item->ymax = gbox->ymax;
|
||||
item->offset = ctx->offset;
|
||||
item->size = size;
|
||||
ctx->items[ctx->features_count] = item;
|
||||
}
|
||||
ctx->offset += size;
|
||||
ctx->features_count++;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void flatgeobuf_create_index(ctx *ctx)
|
||||
{
|
||||
// convert to structure expected by packedrtree
|
||||
std::vector<std::shared_ptr<Item>> items;
|
||||
for (uint64_t i = 0; i < ctx->features_count; i++) {
|
||||
const auto item = std::make_shared<FeatureItem>();
|
||||
item->nodeItem = {
|
||||
ctx->items[i]->xmin, ctx->items[i]->ymin, ctx->items[i]->xmax, ctx->items[i]->ymax
|
||||
};
|
||||
item->offset = ctx->items[i]->offset;
|
||||
item->size = ctx->items[i]->size;
|
||||
items.push_back(item);
|
||||
}
|
||||
// sort items
|
||||
hilbertSort(items);
|
||||
// calc extent
|
||||
auto extent = calcExtent(items);
|
||||
ctx->has_extent = true;
|
||||
ctx->xmin = extent.minX;
|
||||
ctx->ymin = extent.minY;
|
||||
ctx->xmax = extent.maxX;
|
||||
ctx->ymax = extent.maxY;
|
||||
// allocate new buffer and write magicbytes
|
||||
auto oldbuf = ctx->buf;
|
||||
auto oldoffset = ctx->offset;
|
||||
ctx->buf = (uint8_t *) lwalloc(sizeof(signed int) + sizeof(flatgeobuf_magicbytes));
|
||||
memcpy(ctx->buf + sizeof(signed int), flatgeobuf_magicbytes, sizeof(flatgeobuf_magicbytes));
|
||||
ctx->offset = sizeof(signed int) + sizeof(flatgeobuf_magicbytes);
|
||||
// write new header
|
||||
flatgeobuf_encode_header(ctx);
|
||||
// create and write index
|
||||
const auto writeData = [&ctx] (const void *data, const size_t size) {
|
||||
ctx->buf = (uint8_t *) lwrealloc(ctx->buf, ctx->offset + size);
|
||||
memcpy(ctx->buf + ctx->offset, data, size);
|
||||
};
|
||||
PackedRTree tree(items, extent, ctx->index_node_size);
|
||||
tree.streamWrite(writeData);
|
||||
ctx->offset += tree.size();
|
||||
// read items and write in sorted order
|
||||
for (auto item : items) {
|
||||
auto featureItem = std::static_pointer_cast<FeatureItem>(item);
|
||||
ctx->buf = (uint8_t *) lwrealloc(ctx->buf, ctx->offset + featureItem->size);
|
||||
LWDEBUGF(2, "copy from offset %ld", featureItem->offset);
|
||||
memcpy(ctx->buf + ctx->offset, oldbuf + featureItem->offset, featureItem->size);
|
||||
ctx->offset += featureItem->size;
|
||||
}
|
||||
lwfree(oldbuf);
|
||||
}
|
||||
|
||||
int flatgeobuf_decode_feature(ctx *ctx)
|
||||
{
|
||||
LWDEBUGF(2, "reading size prefix at %ld", ctx->offset);
|
||||
auto size = flatbuffers::GetPrefixedSize(ctx->buf + ctx->offset);
|
||||
LWDEBUGF(2, "size is %ld (without size prefix)", size);
|
||||
|
||||
Verifier verifier(ctx->buf + ctx->offset, size);
|
||||
if (VerifySizePrefixedFeatureBuffer(verifier)) {
|
||||
lwerror("buffer did not pass verification");
|
||||
return -1;
|
||||
}
|
||||
|
||||
ctx->offset += sizeof(uoffset_t);
|
||||
|
||||
auto feature = GetFeature(ctx->buf + ctx->offset);
|
||||
ctx->offset += size;
|
||||
|
||||
const auto geometry = feature->geometry();
|
||||
if (geometry != nullptr) {
|
||||
if (geometry->ends() != nullptr) {
|
||||
LWDEBUGF(3, "ENDS: %d", geometry->ends()->size());
|
||||
for (uint32_t i = 0; i < geometry->ends()->size(); i++) {
|
||||
LWDEBUGF(3, "ENDS: %d", geometry->ends()->Get(i));
|
||||
}
|
||||
}
|
||||
|
||||
LWDEBUGF(3, "Constructing GeometryReader with geometry_type %d has_z %d haz_m %d", ctx->geometry_type, ctx->has_z, ctx->has_m);
|
||||
GeometryReader reader(geometry, (GeometryType) ctx->geometry_type, ctx->has_z, ctx->has_m);
|
||||
ctx->lwgeom = reader.read();
|
||||
if (ctx->srid > 0)
|
||||
lwgeom_set_srid(ctx->lwgeom, ctx->srid);
|
||||
LWDEBUGG(3, ctx->lwgeom, "GeometryReader output LWGEOM");
|
||||
} else {
|
||||
ctx->lwgeom = NULL;
|
||||
}
|
||||
if (feature->properties() != nullptr && feature->properties()->size() != 0) {
|
||||
ctx->properties = (uint8_t *) feature->properties()->data();
|
||||
ctx->properties_len = feature->properties()->size();
|
||||
} else {
|
||||
ctx->properties_len = 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int flatgeobuf_decode_header(ctx *ctx)
|
||||
{
|
||||
LWDEBUGF(2, "reading size prefix at %ld", ctx->offset);
|
||||
auto size = flatbuffers::GetPrefixedSize(ctx->buf + ctx->offset);
|
||||
LWDEBUGF(2, "size is %ld (without size prefix)", size);
|
||||
|
||||
Verifier verifier(ctx->buf + ctx->offset, size);
|
||||
if (VerifySizePrefixedHeaderBuffer(verifier)) {
|
||||
lwerror("buffer did not pass verification");
|
||||
return -1;
|
||||
}
|
||||
|
||||
ctx->offset += sizeof(uoffset_t);
|
||||
|
||||
LWDEBUGF(2, "reading header at %ld with size %ld", ctx->offset, size);
|
||||
auto header = GetHeader(ctx->buf + ctx->offset);
|
||||
ctx->offset += size;
|
||||
|
||||
ctx->geometry_type = (uint8_t) header->geometry_type();
|
||||
ctx->features_count = header->features_count();
|
||||
ctx->has_z = header->has_z();
|
||||
ctx->has_m = header->has_m();
|
||||
ctx->has_t = header->has_t();
|
||||
ctx->has_tm = header->has_tm();
|
||||
ctx->index_node_size = header->index_node_size();
|
||||
auto crs = header->crs();
|
||||
if (crs != nullptr)
|
||||
ctx->srid = crs->code();
|
||||
auto columns = header->columns();
|
||||
if (columns != nullptr) {
|
||||
auto size = columns->size();
|
||||
ctx->columns = (flatgeobuf_column **) lwalloc(sizeof(flatgeobuf_column *) * size);
|
||||
ctx->columns_size = size;
|
||||
for (uint32_t i = 0; i < size; i++) {
|
||||
auto column = columns->Get(i);
|
||||
ctx->columns[i] = (flatgeobuf_column *) lwalloc(sizeof(flatgeobuf_column));
|
||||
memset(ctx->columns[i], 0, sizeof(flatgeobuf_column));
|
||||
ctx->columns[i]->name = column->name()->c_str();
|
||||
ctx->columns[i]->type = (uint8_t) column->type();
|
||||
}
|
||||
}
|
||||
|
||||
LWDEBUGF(2, "ctx->geometry_type: %d", ctx->geometry_type);
|
||||
LWDEBUGF(2, "ctx->columns_len: %d", ctx->columns_size);
|
||||
|
||||
if (ctx->index_node_size > 0 && ctx->features_count > 0) {
|
||||
auto treeSize = PackedRTree::size(ctx->features_count, ctx->index_node_size);
|
||||
LWDEBUGF(2, "Adding tree size %ld to offset", treeSize);
|
||||
ctx->offset += treeSize;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,132 @@
|
|||
/**********************************************************************
|
||||
*
|
||||
* PostGIS - Spatial Types for PostgreSQL
|
||||
* http://postgis.net
|
||||
*
|
||||
* PostGIS is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* PostGIS is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with PostGIS. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
**********************************************************************
|
||||
*
|
||||
* Copyright 2021 Björn Harrtell
|
||||
*
|
||||
**********************************************************************/
|
||||
|
||||
#ifndef FLATGEOBUF_C_H
|
||||
#define FLATGEOBUF_C_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include "liblwgeom.h"
|
||||
#include "lwgeom_log.h"
|
||||
|
||||
extern uint8_t flatgeobuf_magicbytes[];
|
||||
extern uint8_t FLATGEOBUF_MAGICBYTES_SIZE;
|
||||
extern uint8_t FLATGEOBUF_MAGICBYTES_LEN;
|
||||
|
||||
// need c compatible variant of this enum
|
||||
#define flatgeobuf_column_type_byte UINT8_C(0)
|
||||
#define flatgeobuf_column_type_ubyte UINT8_C(1)
|
||||
#define flatgeobuf_column_type_bool UINT8_C(2)
|
||||
#define flatgeobuf_column_type_short UINT8_C(3)
|
||||
#define flatgeobuf_column_type_ushort UINT8_C(4)
|
||||
#define flatgeobuf_column_type_int UINT8_C(5)
|
||||
#define flatgeobuf_column_type_uint UINT8_C(6)
|
||||
#define flatgeobuf_column_type_long UINT8_C(7)
|
||||
#define flatgeobuf_column_type_ulong UINT8_C(8)
|
||||
#define flatgeobuf_column_type_float UINT8_C(9)
|
||||
#define flatgeobuf_column_type_double UINT8_C(10)
|
||||
#define flatgeobuf_column_type_string UINT8_C(11)
|
||||
#define flatgeobuf_column_type_json UINT8_C(12)
|
||||
#define flatgeobuf_column_type_datetime UINT8_C(13)
|
||||
#define flatgeobuf_column_type_binary UINT8_C(14)
|
||||
|
||||
typedef struct flatgeobuf_column
|
||||
{
|
||||
const char *name;
|
||||
uint8_t type;
|
||||
const char *title;
|
||||
const char *description;
|
||||
uint32_t width;
|
||||
uint32_t precision;
|
||||
uint32_t scale;
|
||||
bool nullable;
|
||||
bool unique;
|
||||
bool primary_key;
|
||||
const char * metadata;
|
||||
} flatgeobuf_column;
|
||||
|
||||
typedef struct flatgeobuf_item
|
||||
{
|
||||
double xmin;
|
||||
double xmax;
|
||||
double ymin;
|
||||
double ymax;
|
||||
uint32_t size;
|
||||
uint64_t offset;
|
||||
} flatgeobuf_item;
|
||||
|
||||
typedef struct flatgeobuf_ctx
|
||||
{
|
||||
// header contents
|
||||
const char *name;
|
||||
uint64_t features_count;
|
||||
uint8_t geometry_type;
|
||||
bool has_extent;
|
||||
double xmin;
|
||||
double xmax;
|
||||
double ymin;
|
||||
double ymax;
|
||||
bool has_z;
|
||||
bool has_m;
|
||||
bool has_t;
|
||||
bool has_tm;
|
||||
uint16_t index_node_size;
|
||||
int32_t srid;
|
||||
flatgeobuf_column **columns;
|
||||
uint16_t columns_size;
|
||||
|
||||
// encode/decode buffers
|
||||
uint8_t *buf;
|
||||
uint64_t offset;
|
||||
uint64_t size;
|
||||
|
||||
LWGEOM *lwgeom;
|
||||
uint8_t *properties;
|
||||
uint32_t properties_len;
|
||||
uint32_t properties_size;
|
||||
|
||||
// encode input
|
||||
const char *geom_name;
|
||||
uint32_t geom_index;
|
||||
|
||||
// encode spatial index bookkeeping
|
||||
bool create_index;
|
||||
flatgeobuf_item **items;
|
||||
uint64_t items_len;
|
||||
} flatgeobuf_ctx;
|
||||
|
||||
int flatgeobuf_encode_header(flatgeobuf_ctx *ctx);
|
||||
int flatgeobuf_encode_feature(flatgeobuf_ctx *ctx);
|
||||
void flatgeobuf_create_index(flatgeobuf_ctx *ctx);
|
||||
|
||||
int flatgeobuf_decode_header(flatgeobuf_ctx *ctx);
|
||||
int flatgeobuf_decode_feature(flatgeobuf_ctx *ctx);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* LWGEOM_WAGYU_H */
|
|
@ -0,0 +1,205 @@
|
|||
/**********************************************************************
|
||||
*
|
||||
* PostGIS - Spatial Types for PostgreSQL
|
||||
* http://postgis.net
|
||||
*
|
||||
* PostGIS is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* PostGIS is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with PostGIS. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
**********************************************************************
|
||||
*
|
||||
* Copyright 2021 Björn Harrtell
|
||||
*
|
||||
**********************************************************************/
|
||||
|
||||
#include "geometryreader.h"
|
||||
|
||||
using namespace flatbuffers;
|
||||
using namespace FlatGeobuf;
|
||||
|
||||
LWPOINT *GeometryReader::readPoint()
|
||||
{
|
||||
POINTARRAY *pa;
|
||||
POINT4D pt;
|
||||
|
||||
pa = ptarray_construct_empty(m_has_z, m_has_m, 1);
|
||||
|
||||
if (m_geometry->xy() == nullptr || m_geometry->xy()->size() == 0) {
|
||||
return lwpoint_construct(0, NULL, pa);
|
||||
}
|
||||
|
||||
const auto xy = m_geometry->xy()->data();
|
||||
|
||||
double x = xy[m_offset + 0];
|
||||
double y = xy[m_offset + 1];
|
||||
double z = 0;
|
||||
double m = 0;
|
||||
|
||||
if (m_has_z)
|
||||
z = m_geometry->z()->data()[m_offset];
|
||||
if (m_has_m)
|
||||
m = m_geometry->m()->data()[m_offset];
|
||||
|
||||
pt = (POINT4D) { x, y, z, m };
|
||||
ptarray_append_point(pa, &pt, LW_TRUE);
|
||||
return lwpoint_construct(0, NULL, pa);
|
||||
}
|
||||
|
||||
POINTARRAY *GeometryReader::readPA()
|
||||
{
|
||||
POINTARRAY *pa;
|
||||
POINT4D pt;
|
||||
uint32_t npoints;
|
||||
|
||||
const double *xy = m_geometry->xy()->data();
|
||||
const double *z = m_has_z ? m_geometry->z()->data() : nullptr;
|
||||
const double *m = m_has_m ? m_geometry->m()->data() : nullptr;
|
||||
|
||||
pa = ptarray_construct_empty(m_has_z, m_has_m, m_length);
|
||||
|
||||
for (uint32_t i = m_offset; i < m_offset + m_length; i++) {
|
||||
double xv = xy[i * 2 + 0];
|
||||
double yv = xy[i * 2 + 1];
|
||||
double zv = 0;
|
||||
double mv = 0;
|
||||
if (m_has_z)
|
||||
zv = z[i];
|
||||
if (m_has_m)
|
||||
mv = m[i];
|
||||
pt = (POINT4D) { xv, yv, zv, mv };
|
||||
ptarray_append_point(pa, &pt, LW_TRUE);
|
||||
}
|
||||
|
||||
return pa;
|
||||
}
|
||||
|
||||
LWMPOINT *GeometryReader::readMultiPoint()
|
||||
{
|
||||
POINTARRAY *pa = readPA();
|
||||
return lwmpoint_construct(0, pa);
|
||||
}
|
||||
|
||||
LWLINE *GeometryReader::readLineString()
|
||||
{
|
||||
POINTARRAY *pa = readPA();
|
||||
return lwline_construct(0, NULL, pa);
|
||||
}
|
||||
|
||||
LWMLINE *GeometryReader::readMultiLineString()
|
||||
{
|
||||
auto ends = m_geometry->ends();
|
||||
|
||||
uint32_t ngeoms = 1;
|
||||
if (ends != nullptr && ends->size() > 1)
|
||||
ngeoms = ends->size();
|
||||
|
||||
auto *lwmline = lwmline_construct_empty(0, m_has_z, m_has_m);
|
||||
if (ngeoms > 1) {
|
||||
for (uint32_t i = 0; i < ngeoms; i++) {
|
||||
const auto e = ends->Get(i);
|
||||
m_length = e - m_offset;
|
||||
POINTARRAY *pa = readPA();
|
||||
lwmline_add_lwline(lwmline, lwline_construct(0, NULL, pa));
|
||||
m_offset = e;
|
||||
}
|
||||
} else {
|
||||
POINTARRAY *pa = readPA();
|
||||
lwmline_add_lwline(lwmline, lwline_construct(0, NULL, pa));
|
||||
}
|
||||
|
||||
return lwmline;
|
||||
}
|
||||
|
||||
LWPOLY *GeometryReader::readPolygon()
|
||||
{
|
||||
const auto ends = m_geometry->ends();
|
||||
|
||||
uint32_t nrings = 1;
|
||||
if (ends != nullptr && ends->size() > 1)
|
||||
nrings = ends->size();
|
||||
|
||||
auto **ppa = (POINTARRAY **) lwalloc(sizeof(POINTARRAY *) * nrings);
|
||||
if (nrings > 1) {
|
||||
for (uint32_t i = 0; i < nrings; i++) {
|
||||
const auto e = ends->Get(i);
|
||||
m_length = e - m_offset;
|
||||
ppa[i] = readPA();
|
||||
m_offset = e;
|
||||
}
|
||||
} else {
|
||||
ppa[0] = readPA();
|
||||
}
|
||||
|
||||
return lwpoly_construct(0, NULL, nrings, ppa);
|
||||
}
|
||||
|
||||
LWMPOLY *GeometryReader::readMultiPolygon()
|
||||
{
|
||||
auto parts = m_geometry->parts();
|
||||
auto *mp = lwmpoly_construct_empty(0, m_has_z, m_has_m);
|
||||
for (uoffset_t i = 0; i < parts->size(); i++) {
|
||||
GeometryReader reader { parts->Get(i), GeometryType::Polygon, m_has_z, m_has_m };
|
||||
const auto p = (LWPOLY *) reader.read();
|
||||
lwmpoly_add_lwpoly(mp, p);
|
||||
}
|
||||
return mp;
|
||||
}
|
||||
|
||||
LWCOLLECTION *GeometryReader::readGeometryCollection()
|
||||
{
|
||||
auto parts = m_geometry->parts();
|
||||
auto *gc = lwcollection_construct_empty(COLLECTIONTYPE, 0, m_has_z, m_has_m);
|
||||
for (uoffset_t i = 0; i < parts->size(); i++) {
|
||||
auto part = parts->Get(i);
|
||||
GeometryReader reader { part, part->type(), m_has_z, m_has_m };
|
||||
const auto g = reader.read();
|
||||
lwcollection_add_lwgeom(gc, g);
|
||||
}
|
||||
return gc;
|
||||
}
|
||||
|
||||
LWGEOM *GeometryReader::read()
|
||||
{
|
||||
// nested types
|
||||
switch (m_geometry_type) {
|
||||
case GeometryType::GeometryCollection: return (LWGEOM *) readGeometryCollection();
|
||||
case GeometryType::MultiPolygon: return (LWGEOM *) readMultiPolygon();
|
||||
/*case GeometryType::CompoundCurve: return readCompoundCurve();
|
||||
case GeometryType::CurvePolygon: return readCurvePolygon();
|
||||
case GeometryType::MultiCurve: return readMultiCurve();
|
||||
case GeometryType::MultiSurface: return readMultiSurface();
|
||||
case GeometryType::PolyhedralSurface: return readPolyhedralSurface();*/
|
||||
default: break;
|
||||
}
|
||||
|
||||
// if not nested must have geometry data
|
||||
const auto pXy = m_geometry->xy();
|
||||
const auto xySize = pXy->size();
|
||||
m_length = xySize / 2;
|
||||
|
||||
switch (m_geometry_type) {
|
||||
case GeometryType::Point: return (LWGEOM *) readPoint();
|
||||
case GeometryType::MultiPoint: return (LWGEOM *) readMultiPoint();
|
||||
case GeometryType::LineString: return (LWGEOM *) readLineString();
|
||||
case GeometryType::MultiLineString: return (LWGEOM *) readMultiLineString();
|
||||
case GeometryType::Polygon: return (LWGEOM *) readPolygon();
|
||||
/*
|
||||
case GeometryType::CircularString: return readSimpleCurve<OGRCircularString>(true);
|
||||
case GeometryType::Triangle: return readTriangle();
|
||||
case GeometryType::TIN: return readTIN();
|
||||
*/
|
||||
default:
|
||||
lwerror("flatgeobuf: GeometryReader::read: Unknown type %d", (int) m_geometry_type);
|
||||
}
|
||||
return nullptr;
|
||||
}
|
|
@ -0,0 +1,80 @@
|
|||
/**********************************************************************
|
||||
*
|
||||
* PostGIS - Spatial Types for PostgreSQL
|
||||
* http://postgis.net
|
||||
*
|
||||
* PostGIS is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* PostGIS is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with PostGIS. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
**********************************************************************
|
||||
*
|
||||
* Copyright 2021 Björn Harrtell
|
||||
*
|
||||
**********************************************************************/
|
||||
|
||||
#ifndef FLATGEOBUF_GEOMETRYREADER_H
|
||||
#define FLATGEOBUF_GEOMETRYREADER_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include "lwgeom_log.h"
|
||||
#include "liblwgeom.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#include "feature_generated.h"
|
||||
|
||||
namespace FlatGeobuf {
|
||||
|
||||
class GeometryReader {
|
||||
private:
|
||||
const FlatGeobuf::Geometry *m_geometry;
|
||||
FlatGeobuf::GeometryType m_geometry_type;
|
||||
bool m_has_z;
|
||||
bool m_has_m;
|
||||
|
||||
uint32_t m_length = 0;
|
||||
uint32_t m_offset = 0;
|
||||
|
||||
LWPOINT *readPoint();
|
||||
LWMPOINT *readMultiPoint();
|
||||
LWLINE *readLineString();
|
||||
LWMLINE *readMultiLineString();
|
||||
LWPOLY *readPolygon();
|
||||
LWMPOLY *readMultiPolygon();
|
||||
LWCOLLECTION *readGeometryCollection();
|
||||
|
||||
POINTARRAY *readPA();
|
||||
|
||||
public:
|
||||
GeometryReader(
|
||||
const FlatGeobuf::Geometry *geometry,
|
||||
FlatGeobuf::GeometryType geometry_type,
|
||||
bool has_z,
|
||||
bool has_m) :
|
||||
m_geometry (geometry),
|
||||
m_geometry_type (geometry_type),
|
||||
m_has_z (has_z),
|
||||
m_has_m (has_m)
|
||||
{ }
|
||||
LWGEOM *read();
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
|
||||
#endif /* FLATGEOBUF_GEOMETRYREADER_H */
|
|
@ -0,0 +1,198 @@
|
|||
/**********************************************************************
|
||||
*
|
||||
* PostGIS - Spatial Types for PostgreSQL
|
||||
* http://postgis.net
|
||||
*
|
||||
* PostGIS is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* PostGIS is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with PostGIS. If not, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
**********************************************************************
|
||||
*
|
||||
* Copyright 2021 Björn Harrtell
|
||||
*
|
||||
**********************************************************************/
|
||||
|
||||
#include "geometrywriter.h"
|
||||
|
||||
using namespace FlatGeobuf;
|
||||
using namespace flatbuffers;
|
||||
|
||||
const GeometryType GeometryWriter::get_geometrytype(const LWGEOM *lwgeom)
|
||||
{
|
||||
int type = lwgeom->type;
|
||||
switch (type)
|
||||
{
|
||||
case POINTTYPE:
|
||||
return GeometryType::Point;
|
||||
case LINETYPE:
|
||||
return GeometryType::LineString;
|
||||
case TRIANGLETYPE:
|
||||
return GeometryType::Triangle;
|
||||
case POLYGONTYPE:
|
||||
return GeometryType::Polygon;
|
||||
case MULTIPOINTTYPE:
|
||||
return GeometryType::MultiPoint;
|
||||
case MULTILINETYPE:
|
||||
return GeometryType::MultiLineString;
|
||||
case MULTIPOLYGONTYPE:
|
||||
return GeometryType::MultiPolygon;
|
||||
case TINTYPE:
|
||||
case COLLECTIONTYPE:
|
||||
return GeometryType::GeometryCollection;
|
||||
default:
|
||||
lwerror("flatgeobuf: get_geometrytype: '%s' geometry type not supported",
|
||||
lwtype_name(type));
|
||||
return GeometryType::Unknown;
|
||||
}
|
||||
}
|
||||
|
||||
void GeometryWriter::writePoint(const LWPOINT *p)
|
||||
{
|
||||
writePA(p->point);
|
||||
}
|
||||
|
||||
void GeometryWriter::writeMultiPoint(const LWMPOINT *mp)
|
||||
{
|
||||
writePA(lwline_from_lwmpoint(0, mp)->points);
|
||||
}
|
||||
|
||||
void GeometryWriter::writeLineString(const LWLINE *l)
|
||||
{
|
||||
writePA(l->points);
|
||||
}
|
||||
|
||||
void GeometryWriter::writeMultiLineString(const LWMLINE *ml)
|
||||
{
|
||||
uint32_t ngeoms = ml->ngeoms;
|
||||
if (ngeoms == 1)
|
||||
return writePA(ml->geoms[0]->points);
|
||||
POINTARRAY **ppa = (POINTARRAY **) lwalloc(sizeof(POINTARRAY *) * ngeoms);
|
||||
for (uint32_t i = 0; i < ngeoms; i++)
|
||||
ppa[i] = ml->geoms[i]->points;
|
||||
writePPA(ppa, ngeoms);
|
||||
}
|
||||
|
||||
void GeometryWriter::writePolygon(const LWPOLY *p)
|
||||
{
|
||||
writePPA(p->rings, p->nrings);
|
||||
}
|
||||
|
||||
const Offset<Geometry> GeometryWriter::writeMultiPolygon(const LWMPOLY *mp, int depth)
|
||||
{
|
||||
std::vector<Offset<Geometry>> parts;
|
||||
for (uint32_t i = 0; i < mp->ngeoms; i++)
|
||||
{
|
||||
auto part = mp->geoms[i];
|
||||
if (part->nrings != 0)
|
||||
{
|
||||
GeometryWriter writer { m_fbb, (LWGEOM *) part, GeometryType::Polygon, m_has_z, m_has_m };
|
||||
parts.push_back(writer.write(depth + 1));
|
||||
}
|
||||
}
|
||||
return CreateGeometryDirect(m_fbb, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, m_geometry_type, &parts);
|
||||
}
|
||||
|
||||
const Offset<Geometry> GeometryWriter::writeGeometryCollection(const LWCOLLECTION *gc, int depth)
|
||||
{
|
||||
std::vector<Offset<Geometry>> parts;
|
||||
for (uint32_t i = 0; i < gc->ngeoms; i++)
|
||||
{
|
||||
auto part = gc->geoms[i];
|
||||
auto geometry_type = get_geometrytype(part);
|
||||
GeometryWriter writer { m_fbb, part, geometry_type, m_has_z, m_has_m };
|
||||
parts.push_back(writer.write(depth + 1));
|
||||
}
|
||||
return CreateGeometryDirect(m_fbb, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, m_geometry_type, &parts);
|
||||
}
|
||||
|
||||
void GeometryWriter::writePA(POINTARRAY *pa)
|
||||
{
|
||||
POINT4D pt;
|
||||
for (uint32_t i = 0; i < pa->npoints; i++) {
|
||||
getPoint4d_p(pa, i, &pt);
|
||||
m_xy.push_back(pt.x);
|
||||
m_xy.push_back(pt.y);
|
||||
if (m_has_z)
|
||||
m_z.push_back(pt.z);
|
||||
if (m_has_m)
|
||||
m_m.push_back(pt.m);
|
||||
}
|
||||
}
|
||||
|
||||
void GeometryWriter::writePPA(POINTARRAY **ppa, uint32_t len)
|
||||
{
|
||||
if (len == 0)
|
||||
return;
|
||||
POINTARRAY *pa = ppa[0];
|
||||
writePA(pa);
|
||||
if (len > 1) {
|
||||
uint32_t e = pa->npoints;
|
||||
m_ends.push_back(e);
|
||||
for (uint32_t i = 1; i < len; i++) {
|
||||
pa = ppa[i];
|
||||
writePA(pa);
|
||||
m_ends.push_back(e += pa->npoints);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const Offset<Geometry> GeometryWriter::write(int depth)
|
||||
{
|
||||
bool unknownGeometryType = false;
|
||||
if (depth == 0 && m_geometry_type == GeometryType::Unknown) {
|
||||
m_geometry_type = get_geometrytype(m_lwgeom);
|
||||
unknownGeometryType = true;
|
||||
}
|
||||
switch (m_geometry_type) {
|
||||
case GeometryType::Point:
|
||||
writePoint((LWPOINT *) m_lwgeom); break;
|
||||
case GeometryType::MultiPoint:
|
||||
writeMultiPoint((LWMPOINT *) m_lwgeom); break;
|
||||
case GeometryType::LineString:
|
||||
writeLineString((LWLINE *) m_lwgeom); break;
|
||||
case GeometryType::MultiLineString:
|
||||
writeMultiLineString((LWMLINE *) m_lwgeom); break;
|
||||
case GeometryType::Polygon:
|
||||
writePolygon((LWPOLY *) m_lwgeom); break;
|
||||
case GeometryType::MultiPolygon:
|
||||
return writeMultiPolygon((LWMPOLY *) m_lwgeom, depth);
|
||||
case GeometryType::GeometryCollection:
|
||||
return writeGeometryCollection((LWCOLLECTION *) m_lwgeom, depth);
|
||||
/*case GeometryType::CircularString:
|
||||
writeSimpleCurve(m_ogrGeometry->toCircularString()); break;
|
||||
case GeometryType::CompoundCurve:
|
||||
return writeCompoundCurve(m_ogrGeometry->toCompoundCurve(), depth);
|
||||
case GeometryType::CurvePolygon:
|
||||
return writeCurvePolygon(m_ogrGeometry->toCurvePolygon(), depth);
|
||||
case GeometryType::MultiCurve:
|
||||
return writeGeometryCollection(m_ogrGeometry->toMultiCurve(), depth);
|
||||
case GeometryType::MultiSurface:
|
||||
return writeGeometryCollection(m_ogrGeometry->toMultiSurface(), depth);
|
||||
case GeometryType::PolyhedralSurface:
|
||||
return writePolyhedralSurface(m_ogrGeometry->toPolyhedralSurface(), depth);
|
||||
case GeometryType::Triangle:
|
||||
writePolygon(m_ogrGeometry->toTriangle()); break;
|
||||
case GeometryType::TIN:
|
||||
writeTIN(m_ogrGeometry->toTriangulatedSurface()); break;*/
|
||||
default:
|
||||
lwerror("flatgeobuf: GeometryWriter::write: '%s' geometry type not supported",
|
||||
lwtype_name(m_lwgeom->type));
|
||||
return 0;
|
||||
}
|
||||
const auto pEnds = m_ends.empty() ? nullptr : &m_ends;
|
||||
const auto pXy = m_xy.empty() ? nullptr : &m_xy;
|
||||
const auto pZ = m_z.empty() ? nullptr : &m_z;
|
||||
const auto pM = m_m.empty() ? nullptr : &m_m;
|
||||
const auto geometryType = depth > 0 || unknownGeometryType ? m_geometry_type : GeometryType::Unknown;
|
||||
return FlatGeobuf::CreateGeometryDirect(m_fbb, pEnds, pXy, pZ, pM, nullptr, nullptr, geometryType);
|
||||
}
|
|
@ -0,0 +1,92 @@
|
|||
/**********************************************************************
|
||||
*
|
||||
* PostGIS - Spatial Types for PostgreSQL
|
||||
* http://postgis.net
|
||||
*
|
||||
* PostGIS is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of |