35#ifndef OPENSWMM_GPKG_GEOMETRY_HPP
36#define OPENSWMM_GPKG_GEOMETRY_HPP
78inline void append_u8(std::vector<uint8_t>& buf, uint8_t v) {
92inline void append_u32(std::vector<uint8_t>& buf, uint32_t v) {
93 buf.insert(buf.end(),
reinterpret_cast<const uint8_t*
>(&v),
94 reinterpret_cast<const uint8_t*
>(&v) + 4);
108 buf.insert(buf.end(),
reinterpret_cast<const uint8_t*
>(&v),
109 reinterpret_cast<const uint8_t*
>(&v) + 8);
127inline void write_gp_header(std::vector<uint8_t>& buf, int32_t srs_id,
double min_x,
double min_y,
128 double max_x,
double max_y) {
134 uint8_t flags = 0x00;
139 buf.insert(buf.end(),
reinterpret_cast<const uint8_t*
>(&srs_id),
140 reinterpret_cast<const uint8_t*
>(&srs_id) + 4);
165 buf.insert(buf.end(),
reinterpret_cast<const uint8_t*
>(&srs_id),
166 reinterpret_cast<const uint8_t*
>(&srs_id) + 4);
185inline std::vector<uint8_t>
encode_point(
double x,
double y, int32_t srs_id) {
186 std::vector<uint8_t> buf;
187 buf.reserve(8 + 32 + 21);
210 const std::vector<double>& ys, int32_t srs_id) {
212 std::vector<uint8_t> buf;
219 double min_x = xs[0], max_x = xs[0], min_y = ys[0], max_y = ys[0];
220 for (
size_t i = 1; i < xs.size(); ++i) {
221 min_x = std::min(min_x, xs[i]);
222 max_x = std::max(max_x, xs[i]);
223 min_y = std::min(min_y, ys[i]);
224 max_y = std::max(max_y, ys[i]);
226 std::vector<uint8_t> buf;
227 buf.reserve(8 + 32 + 9 + xs.size() * 16);
232 for (
size_t i = 0; i < xs.size(); ++i) {
255 const std::vector<double>& ys, int32_t srs_id) {
257 std::vector<uint8_t> buf;
267 std::vector<int> depth(rings.size(), 0), parent(rings.size(), -1);
268 for (
size_t i = 0; i < rings.size(); ++i)
269 for (
size_t j = 0; j < rings.size(); ++j)
273 for (
size_t i = 0; i < rings.size(); ++i)
275 for (
size_t j = 0; j < rings.size(); ++j)
276 if (depth[j] == depth[i] - 1 &&
278 parent[i] =
static_cast<int>(j);
282 const auto minmax_x = std::minmax_element(xs.begin(), xs.end());
283 const auto minmax_y = std::minmax_element(ys.begin(), ys.end());
284 std::vector<uint8_t> buf;
286 *minmax_x.second, *minmax_y.second);
289 const auto polygon_count = std::count_if(depth.begin(), depth.end(),
290 [](
int d) { return d % 2 == 0; });
294 for (
size_t k = 0; k <= ring.count; ++k) {
295 const auto v = ring.first + k % ring.count;
300 for (
size_t i = 0; i < rings.size(); ++i) {
306 std::count(parent.begin(), parent.end(),
static_cast<int>(i))));
307 write_ring(rings[i]);
308 for (
size_t j = 0; j < rings.size(); ++j)
309 if (parent[j] ==
static_cast<int>(i))
310 write_ring(rings[j]);
330 const std::vector<double>& ys, int32_t srs_id) {
332 std::vector<uint8_t> buf;
340 bool closed = (xs.front() == xs.back() && ys.front() == ys.back());
341 uint32_t n_pts =
static_cast<uint32_t
>(xs.size()) + (closed ? 0 : 1);
343 double min_x = xs[0], max_x = xs[0], min_y = ys[0], max_y = ys[0];
344 for (
size_t i = 1; i < xs.size(); ++i) {
345 min_x = std::min(min_x, xs[i]);
346 max_x = std::max(max_x, xs[i]);
347 min_y = std::min(min_y, ys[i]);
348 max_y = std::max(max_y, ys[i]);
351 std::vector<uint8_t> buf;
352 buf.reserve(8 + 32 + 30 + n_pts * 16);
360 for (
size_t i = 0; i < xs.size(); ++i) {
376 double x = 0.0,
y = 0.0;
413 throw std::runtime_error(
"GeoPackage binary too short");
415 throw std::runtime_error(
"Invalid GeoPackage binary magic");
416 uint8_t flags = data[3];
417 std::memcpy(&srs_id, data + 4, 4);
419 int envelope_type = (flags >> 1) & 0x07;
420 size_t envelope_size = 0;
421 switch (envelope_type) {
438 throw std::runtime_error(
"Unknown envelope type");
440 return 8 + envelope_size;
454template <
typename T>
inline T
read_val(
const uint8_t* data,
size_t& offset) {
456 std::memcpy(&val, data + offset,
sizeof(T));
482 throw std::runtime_error(
"Expected WKB POINT");
507 throw std::runtime_error(
"Expected WKB LINESTRING");
511 for (uint32_t i = 0; i < n; ++i) {
539 throw std::runtime_error(
"Expected WKB MULTIPOLYGON");
543 const auto require = [&](
size_t bytes) {
544 if (offset > blob.size() || bytes > blob.size() - offset)
545 throw std::runtime_error(
"Truncated WKB MULTIPOLYGON");
547 for (uint32_t p = 0; p < n_polys; ++p) {
552 throw std::runtime_error(
"Expected WKB POLYGON member");
554 for (uint32_t r = 0; r < n_rings; ++r) {
557 if (n_pts > (blob.size() - offset) / (2 *
sizeof(
double)))
558 throw std::runtime_error(
"Truncated WKB polygon ring");
559 const auto first = mp.
xs.size();
560 for (uint32_t i = 0; i < n_pts; ++i) {
564 if (n_pts && (mp.
xs.back() != mp.
xs[first] || mp.
ys.back() != mp.
ys[first])) {
565 mp.
xs.push_back(mp.
xs[first]);
566 mp.
ys.push_back(mp.
ys[first]);
Definition GpkgGeometry.hpp:67
void append_u32(std::vector< uint8_t > &buf, uint32_t v)
Append 4 native representation bytes.
Definition GpkgGeometry.hpp:92
void write_gp_header_empty(std::vector< uint8_t > &buf, int32_t srs_id)
Append an empty GP header without an envelope.
Definition GpkgGeometry.hpp:159
size_t parse_gp_header(const uint8_t *data, size_t size, int32_t &srs_id)
Read GP magic and envelope kind to locate the WKB payload.
Definition GpkgGeometry.hpp:411
T read_val(const uint8_t *data, size_t &offset)
Read an unchecked native scalar and advance a byte offset.
Definition GpkgGeometry.hpp:454
void append_u8(std::vector< uint8_t > &buf, uint8_t v)
Append 1 native representation byte.
Definition GpkgGeometry.hpp:78
void append_f64(std::vector< uint8_t > &buf, double v)
Append 8 native representation bytes.
Definition GpkgGeometry.hpp:107
void write_gp_header(std::vector< uint8_t > &buf, int32_t srs_id, double min_x, double min_y, double max_x, double max_y)
Append a version-zero nonempty GP header with XY envelope.
Definition GpkgGeometry.hpp:127
Definition ExternalContentReader.cpp:50
std::vector< uint8_t > encode_point(double x, double y, int32_t srs_id)
Encode an XY point with a matching XY envelope.
Definition GpkgGeometry.hpp:185
DecodedMultipolygon decode_multipolygon(const std::vector< uint8_t > &blob)
Decode MULTIPOLYGON coordinates from a prevalidated native-endian GP blob.
Definition GpkgGeometry.hpp:533
DecodedPoint decode_point(const std::vector< uint8_t > &blob)
Decode POINT coordinates from a prevalidated native-endian GP blob.
Definition GpkgGeometry.hpp:476
std::vector< uint8_t > encode_polygon(const std::vector< double > &xs, const std::vector< double > &ys, int32_t srs_id)
Encode a single exterior ring in POLYGON form.
Definition GpkgGeometry.hpp:329
constexpr uint8_t WKB_LITTLE_ENDIAN
Definition GpkgGeometry.hpp:57
DecodedLinestring decode_linestring(const std::vector< uint8_t > &blob)
Decode LINESTRING coordinates from a prevalidated native-endian GP blob.
Definition GpkgGeometry.hpp:501
std::vector< uint8_t > encode_linestring(const std::vector< double > &xs, const std::vector< double > &ys, int32_t srs_id)
Encode an XY LINESTRING.
Definition GpkgGeometry.hpp:209
constexpr uint8_t GP_MAGIC_2
Definition GpkgGeometry.hpp:61
WkbType
Definition GpkgGeometry.hpp:49
@ WKB_POINT
Definition GpkgGeometry.hpp:50
@ WKB_POLYGON
Definition GpkgGeometry.hpp:52
@ WKB_MULTIPOLYGON
Definition GpkgGeometry.hpp:53
@ WKB_LINESTRING
Definition GpkgGeometry.hpp:51
constexpr uint8_t GP_MAGIC_1
Definition GpkgGeometry.hpp:60
std::vector< uint8_t > encode_multipolygon(const std::vector< double > &xs, const std::vector< double > &ys, int32_t srs_id)
Encode closed-ring spatial coordinates in MULTIPOLYGON form.
Definition GpkgGeometry.hpp:254
bool contains(const std::vector< double > &x, const std::vector< double > &y, Ring ring, double px, double py)
Definition PolygonRings.hpp:31
std::vector< Ring > rings(const std::vector< double > &x, const std::vector< double > &y)
Definition PolygonRings.hpp:15
double * y
Definition odesolve.c:37
Definition GpkgGeometry.hpp:380
std::vector< double > xs
Definition GpkgGeometry.hpp:381
std::vector< double > ys
Definition GpkgGeometry.hpp:381
int32_t srs_id
Definition GpkgGeometry.hpp:382
Definition GpkgGeometry.hpp:385
int32_t srs_id
Definition GpkgGeometry.hpp:388
std::vector< double > ys
Definition GpkgGeometry.hpp:387
std::vector< double > xs
Definition GpkgGeometry.hpp:387
Definition GpkgGeometry.hpp:375
double y
Definition GpkgGeometry.hpp:376
int32_t srs_id
Definition GpkgGeometry.hpp:377
double x
Definition GpkgGeometry.hpp:376
Definition PolygonRings.hpp:9