diff --git a/include/geopackage/wkb/reader.hpp b/include/geopackage/wkb/reader.hpp index cf773a425e..9964781bc3 100644 --- a/include/geopackage/wkb/reader.hpp +++ b/include/geopackage/wkb/reader.hpp @@ -113,6 +113,21 @@ inline READ_WKB_INTERNAL_SIG(geojson::polygon_t) return polygon; } +template +inline T read_multi_wkb_internal(const byte_vector& buffer, int& index, uint32_t expected_type) { + const byte_t new_order = buffer[index]; + index++; + + uint32_t type; + copy_from(buffer, index, type, new_order); + + if (type != expected_type) { + throw std::runtime_error("expected type " + std::to_string(expected_type) + ", but found type: " + std::to_string(type)); + } + + return read_wkb_internal(buffer, index, new_order); +}; + template<> inline READ_WKB_INTERNAL_SIG(geojson::multipoint_t) { @@ -121,8 +136,9 @@ inline READ_WKB_INTERNAL_SIG(geojson::multipoint_t) geojson::multipoint_t mp; mp.resize(count); + for (auto& point : mp) { - point = read_wkb_internal(buffer, index, order); + point = read_multi_wkb_internal(buffer, index, 1); } return mp; @@ -137,8 +153,7 @@ inline READ_WKB_INTERNAL_SIG(geojson::multilinestring_t) geojson::multilinestring_t ml; ml.resize(count); for (auto& line : ml) { - auto l = read_wkb_internal(buffer, index, order); - + line = read_multi_wkb_internal(buffer, index, 2); } return ml; @@ -153,7 +168,7 @@ inline READ_WKB_INTERNAL_SIG(geojson::multipolygon_t) geojson::multipolygon_t mpl; mpl.resize(count); for (auto& polygon : mpl) { - polygon = read_wkb_internal(buffer, index, order); + polygon = read_multi_wkb_internal(buffer, index, 3); } return mpl; diff --git a/test/geopackage/WKB_Test.cpp b/test/geopackage/WKB_Test.cpp index 0f495e4a1a..7bb5c90287 100644 --- a/test/geopackage/WKB_Test.cpp +++ b/test/geopackage/WKB_Test.cpp @@ -1,5 +1,4 @@ #include "JSONGeometry.hpp" -#include #include #include @@ -14,46 +13,137 @@ class WKB_Test : public ::testing::Test ~WKB_Test() override {} void SetUp() override { - this->wkb = { - 0x01, 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, - 0x00, 0x05, 0x00, 0x00, 0x00, 0x54, 0xE3, 0xA5, - 0x9B, 0xC4, 0x60, 0x25, 0x40, 0x64, 0x3B, 0xDF, - 0x4F, 0x8D, 0x17, 0x39, 0xC0, 0x5C, 0x8F, 0xC2, - 0xF5, 0x28, 0x4C, 0x41, 0x40, 0xEC, 0x51, 0xB8, - 0x1E, 0x85, 0x2B, 0x34, 0xC0, 0xD5, 0x78, 0xE9, - 0x26, 0x31, 0x68, 0x43, 0x40, 0x6F, 0x12, 0x83, - 0xC0, 0xCA, 0xD1, 0x41, 0xC0, 0x1B, 0x2F, 0xDD, - 0x24, 0x06, 0x01, 0x2B, 0x40, 0xA4, 0x70, 0x3D, - 0x0A, 0xD7, 0x93, 0x43, 0xC0, 0x54, 0xE3, 0xA5, - 0x9B, 0xC4, 0x60, 0x25, 0x40, 0x64, 0x3B, 0xDF, - 0x4F, 0x8D, 0x17, 0x39, 0xC0, - }; - - this->little_endian = { + this->wkb["point"] = { 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x40 }; - this->big_endian = { + this->wkb["point_big"] = { 0x00, 0x00, 0x00, 0x00, 0x01, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; + + // LINESTRING(30 10, 10 30, 40 40) + this->wkb["linestring"] = { + 0x01, + 0x02, 0x00, 0x00, 0x00, + 0x03, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x40, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x24, 0x40, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x24, 0x40, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x40, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x44, 0x40, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x44, 0x40 + }; + + this->wkb["polygon"] = { + 0x01, + 0x03, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, + 0x05, 0x00, 0x00, 0x00, + 0x54, 0xE3, 0xA5, 0x9B, 0xC4, 0x60, 0x25, 0x40, + 0x64, 0x3B, 0xDF, 0x4F, 0x8D, 0x17, 0x39, 0xC0, + 0x5C, 0x8F, 0xC2, 0xF5, 0x28, 0x4C, 0x41, 0x40, + 0xEC, 0x51, 0xB8, 0x1E, 0x85, 0x2B, 0x34, 0xC0, + 0xD5, 0x78, 0xE9, 0x26, 0x31, 0x68, 0x43, 0x40, + 0x6F, 0x12, 0x83, 0xC0, 0xCA, 0xD1, 0x41, 0xC0, + 0x1B, 0x2F, 0xDD, 0x24, 0x06, 0x01, 0x2B, 0x40, + 0xA4, 0x70, 0x3D, 0x0A, 0xD7, 0x93, 0x43, 0xC0, + 0x54, 0xE3, 0xA5, 0x9B, 0xC4, 0x60, 0x25, 0x40, + 0x64, 0x3B, 0xDF, 0x4F, 0x8D, 0x17, 0x39, 0xC0 + }; + + // MULTIPOINT(10 40,40 30,20 20,30 10) + this->wkb["multipoint"] = { + 0x01, + 0x04, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, + 0x01, + 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x24, 0x40, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x44, 0x40, + 0x01, + 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x44, 0x40, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x40, + 0x01, + 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x34, 0x40, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x34, 0x40, + 0x01, + 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x40, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x24, 0x40 + }; + + // MULTILINESTRING((10 10,20 20,10 40),(40 40,30 30,40 20,30 10)) + this->wkb["multilinestring"] = { + 0x01, + 0x05, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x00, + 0x01, + 0x02, 0x00, 0x00, 0x00, + 0x03, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x24, 0x40, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x24, 0x40, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x34, 0x40, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x34, 0x40, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x24, 0x40, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x44, 0x40, + 0x01, + 0x02, 0x00, 0x00, 0x00, + 0x04, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x44, 0x40, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x44, 0x40, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x40, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x40, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x44, 0x40, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x34, 0x40, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, 0x40, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x24, 0x40 + }; } void TearDown() override {} - std::vector wkb; - std::vector little_endian; - std::vector big_endian; + std::map> wkb; }; -TEST_F(WKB_Test, wkb_read_test) +TEST_F(WKB_Test, wkb_point_test) // also tests endianness +{ + const auto geom_big = wkb::read_known_wkb(this->wkb["point_big"]); + const auto geom_little = wkb::read_known_wkb(this->wkb["point"]); + EXPECT_NEAR(geom_big.get<0>(), geom_little.get<0>(), 0.000001); + EXPECT_NEAR(geom_big.get<1>(), geom_little.get<1>(), 0.000001); + EXPECT_NEAR(geom_big.get<0>(), 2.0, 0.000001); + EXPECT_NEAR(geom_big.get<1>(), 4.0, 0.000001); + EXPECT_NEAR(geom_big.get<0>(), 2.0, 0.000001); + EXPECT_NEAR(geom_big.get<1>(), 4.0, 0.000001); +} + +TEST_F(WKB_Test, wkb_linestring_test) +{ + const geojson::geometry geom = wkb::read_wkb(this->wkb["linestring"]); + EXPECT_EQ(geom.which() + 1, 2); + + const geojson::linestring_t& line = boost::get(geom); + const std::vector> expected_coordinates = { + {30, 10}, {10, 30}, {40, 40} + }; + + for (int i = 0; i < expected_coordinates.size(); i++) { + EXPECT_NEAR(line[i].get<0>(), expected_coordinates[i].first, 0.0001); + EXPECT_NEAR(line[i].get<1>(), expected_coordinates[i].second, 0.0001); + } +} + +TEST_F(WKB_Test, wkb_polygon_test) { - const geojson::geometry geom = wkb::read_wkb(this->wkb); + const geojson::geometry geom = wkb::read_wkb(this->wkb["polygon"]); EXPECT_EQ(geom.which() + 1, 3); // +1 since variant.which() is 0-based const geojson::polygon_t& poly = boost::get(geom); @@ -71,14 +161,37 @@ TEST_F(WKB_Test, wkb_read_test) } } -TEST_F(WKB_Test, wkb_endianness_test) +TEST_F(WKB_Test, wkb_multipoint_test) { - const auto geom_big = wkb::read_known_wkb(this->big_endian); - const auto geom_little = wkb::read_known_wkb(this->little_endian); - EXPECT_NEAR(geom_big.get<0>(), geom_little.get<0>(), 0.000001); - EXPECT_NEAR(geom_big.get<1>(), geom_little.get<1>(), 0.000001); - EXPECT_NEAR(geom_big.get<0>(), 2.0, 0.000001); - EXPECT_NEAR(geom_big.get<1>(), 4.0, 0.000001); - EXPECT_NEAR(geom_big.get<0>(), 2.0, 0.000001); - EXPECT_NEAR(geom_big.get<1>(), 4.0, 0.000001); + const geojson::geometry geom = wkb::read_wkb(this->wkb["multipoint"]); + EXPECT_EQ(geom.which() + 1, 4); + + const geojson::multipoint_t& mp = boost::get(geom); + const std::vector> expected_coordinates = { + {10, 40}, {40, 30}, {20, 20}, {30, 10} + }; + + for (int i = 0; i < expected_coordinates.size(); i++) { + EXPECT_NEAR(mp[i].get<0>(), expected_coordinates[i].first, 0.0001); + EXPECT_NEAR(mp[i].get<1>(), expected_coordinates[i].second, 0.0001); + } +} + +TEST_F(WKB_Test, wkb_multilinestring_test) +{ + const geojson::geometry geom = wkb::read_wkb(this->wkb["multilinestring"]); + EXPECT_EQ(geom.which() + 1, 5); + + const geojson::multilinestring_t& mp = boost::get(geom); + const std::vector>> expected_coordinates = { + { {10, 10}, {20, 20}, {10, 40} }, + { {40, 40}, {30, 30}, {40, 20}, {30, 10} } + }; + + for (int i = 0; i < expected_coordinates.size(); i++) { + for (int j = 0; j < expected_coordinates[i].size(); j++) { + EXPECT_NEAR(mp[i][j].get<0>(), expected_coordinates[i][j].first, 0.0001); + EXPECT_NEAR(mp[i][j].get<1>(), expected_coordinates[i][j].second, 0.0001); + } + } }