diff --git a/include/mapnik/wkb.hpp b/include/mapnik/wkb.hpp index fe6a36b25..a42514a30 100644 --- a/include/mapnik/wkb.hpp +++ b/include/mapnik/wkb.hpp @@ -24,8 +24,7 @@ #define MAPNIK_WKB_HPP // mapnik -#include -#include +#include #include namespace mapnik @@ -53,11 +52,11 @@ class MAPNIK_DECL geometry_utils : private util::noncopyable { public: - static bool from_wkb(mapnik::geometry_container& paths, - const char* wkb, - unsigned size, - wkbFormat format = wkbGeneric); + static mapnik::new_geometry::geometry from_wkb(const char* wkb, + unsigned size, + wkbFormat format = wkbGeneric); }; + } #endif // MAPNIK_WKB_HPP diff --git a/src/wkb.cpp b/src/wkb.cpp index 8e7bf62d7..c685e5b15 100644 --- a/src/wkb.cpp +++ b/src/wkb.cpp @@ -26,7 +26,6 @@ #include #include #include -#include #include #include @@ -38,7 +37,8 @@ using CoordinateArray = coord_array; struct wkb_reader : util::noncopyable { private: - enum wkbByteOrder { + enum wkbByteOrder + { wkbXDR=0, wkbNDR=1 }; @@ -84,7 +84,7 @@ public: wkbMultiLineStringZM=3005, wkbMultiPolygonZM=3006, wkbGeometryCollectionZM=3007 - }; + }; wkb_reader(const char* wkb, std::size_t size, wkbFormat format) : wkb_(wkb), @@ -125,83 +125,66 @@ public: needSwap_ = byteOrder_ ? wkbXDR : wkbNDR; } - void read(geometry_container & paths) + mapnik::new_geometry::geometry read() { int type = read_integer(); - switch (type) { case wkbPoint: - read_point(paths); - break; + return std::move(mapnik::new_geometry::geometry(read_point())); case wkbLineString: - read_linestring(paths); - break; + return std::move(mapnik::new_geometry::geometry(read_linestring())); case wkbPolygon: - read_polygon(paths); - break; + return std::move(mapnik::new_geometry::geometry(read_polygon())); case wkbMultiPoint: - read_multipoint(paths); - break; + return std::move(mapnik::new_geometry::geometry(read_multipoint())); case wkbMultiLineString: - read_multilinestring(paths); - break; + return std::move(mapnik::new_geometry::geometry(read_multilinestring())); case wkbMultiPolygon: - read_multipolygon(paths); - break; + return std::move(mapnik::new_geometry::geometry(read_multipolygon())); case wkbGeometryCollection: - read_collection(paths); - break; + throw std::runtime_error("GeometryCollection"); + break; // TODO: should we drop geometry collection ? case wkbPointZ: case wkbPointM: - read_point_xyz(paths); - break; + return std::move(mapnik::new_geometry::geometry(read_point())); case wkbPointZM: - read_point_xyzm(paths); - break; + return std::move(mapnik::new_geometry::geometry(read_point())); case wkbLineStringZ: case wkbLineStringM: - read_linestring_xyz(paths); - break; + return std::move(mapnik::new_geometry::geometry(read_linestring())); case wkbLineStringZM: - read_linestring_xyzm(paths); - break; + return std::move(mapnik::new_geometry::geometry(read_linestring())); case wkbPolygonZ: case wkbPolygonM: - read_polygon_xyz(paths); - break; + return std::move(mapnik::new_geometry::geometry(read_polygon())); case wkbPolygonZM: - read_polygon_xyzm(paths); - break; + return std::move(mapnik::new_geometry::geometry(read_polygon())); case wkbMultiPointZ: case wkbMultiPointM: - read_multipoint_xyz(paths); - break; + return std::move(mapnik::new_geometry::geometry(read_multipoint())); case wkbMultiPointZM: - read_multipoint_xyzm(paths); - break; + return std::move(mapnik::new_geometry::geometry(read_multipoint())); case wkbMultiLineStringZ: case wkbMultiLineStringM: - read_multilinestring_xyz(paths); - break; + return std::move(mapnik::new_geometry::geometry(read_multilinestring())); case wkbMultiLineStringZM: - read_multilinestring_xyzm(paths); - break; + return std::move(mapnik::new_geometry::geometry(read_multilinestring())); case wkbMultiPolygonZ: case wkbMultiPolygonM: - read_multipolygon_xyz(paths); - break; + return std::move(mapnik::new_geometry::geometry(read_multipolygon())); case wkbMultiPolygonZM: - read_multipolygon_xyzm(paths); - break; + return std::move(mapnik::new_geometry::geometry(read_multipolygon())); case wkbGeometryCollectionZ: case wkbGeometryCollectionM: case wkbGeometryCollectionZM: - read_collection(paths); + // TODO ?? + throw std::runtime_error("GeometryCollection Z|M|ZM"); break; default: break; } + throw std::runtime_error("Uknown"); } private: @@ -238,6 +221,7 @@ private: return d; } + template void read_coords(CoordinateArray& ar) { if (! needSwap_) @@ -247,6 +231,8 @@ private: read_double_ndr(wkb_ + pos_, coord.x); read_double_ndr(wkb_ + pos_ + 8, coord.y); pos_ += 16; // skip XY + if (Z) pos_ += 8; + if (M) pos_ += 8; } } else @@ -256,310 +242,110 @@ private: read_double_xdr(wkb_ + pos_, coord.x); read_double_xdr(wkb_ + pos_ + 8, coord.y); pos_ += 16; // skip XY + if (Z) pos_ += 8; + if (M) pos_ += 8; } } } - void read_coords_xyz(CoordinateArray& ar) - { - if (! needSwap_) - { - for (auto & coord : ar) - { - read_double_ndr(wkb_ + pos_, coord.x); - read_double_ndr(wkb_ + pos_ + 8, coord.y); - pos_ += 24; // skip XYZ - } - } - else - { - for (auto & coord : ar) - { - read_double_xdr(wkb_ + pos_, coord.x); - read_double_xdr(wkb_ + pos_ + 8, coord.y); - pos_ += 24; // skip XYZ - } - } - } - - void read_coords_xyzm(CoordinateArray& ar) - { - if (! needSwap_) - { - for (auto & coord : ar) - { - read_double_ndr(wkb_ + pos_, coord.x); - read_double_ndr(wkb_ + pos_ + 8, coord.y); - pos_ += 32; // skip XYZM - } - } - else - { - for (auto & coord : ar) - { - read_double_xdr(wkb_ + pos_, coord.x); - read_double_xdr(wkb_ + pos_ + 8, coord.y); - pos_ += 32; // skip XYZM - } - } - } - - void read_point(geometry_container & paths) + template + mapnik::new_geometry::point read_point() { double x = read_double(); double y = read_double(); - auto pt = std::make_unique(geometry_type::types::Point); - pt->move_to(x, y); - paths.push_back(pt.release()); + if (Z) pos_ += 8; + if (M) pos_ += 8; + return mapnik::new_geometry::point(x, y); } - void read_multipoint(geometry_container & paths) + template + mapnik::new_geometry::multi_point read_multipoint() { + mapnik::new_geometry::multi_point multi_point; int num_points = read_integer(); + multi_point.reserve(num_points); for (int i = 0; i < num_points; ++i) { pos_ += 5; - read_point(paths); + multi_point.emplace_back(read_point()); } + return multi_point; } - void read_point_xyz(geometry_container & paths) - { - double x = read_double(); - double y = read_double(); - auto pt = std::make_unique(geometry_type::types::Point); - pos_ += 8; // double z = read_double(); - pt->move_to(x, y); - paths.push_back(pt.release()); - } - - void read_point_xyzm(geometry_container & paths) - { - double x = read_double(); - double y = read_double(); - auto pt = std::make_unique(geometry_type::types::Point); - pos_ += 16; - pt->move_to(x, y); - paths.push_back(pt.release()); - } - - void read_multipoint_xyz(geometry_container & paths) - { - int num_points = read_integer(); - for (int i = 0; i < num_points; ++i) - { - pos_ += 5; - read_point_xyz(paths); - } - } - - void read_multipoint_xyzm(geometry_container & paths) - { - int num_points = read_integer(); - for (int i = 0; i < num_points; ++i) - { - pos_ += 5; - read_point_xyzm(paths); - } - } - - void read_linestring(geometry_container & paths) + template + mapnik::new_geometry::line_string read_linestring() { + mapnik::new_geometry::line_string line; int num_points = read_integer(); if (num_points > 0) { CoordinateArray ar(num_points); - read_coords(ar); - auto line = std::make_unique(geometry_type::types::LineString); - line->move_to(ar[0].x, ar[0].y); - for (int i = 1; i < num_points; ++i) + read_coords(ar); + + line.reserve(num_points); + for (int i = 0; i < num_points; ++i) { - line->line_to(ar[i].x, ar[i].y); + line.add_coord(ar[i].x, ar[i].y); } - paths.push_back(line.release()); } + return line; } - void read_multilinestring(geometry_container & paths) + template + mapnik::new_geometry::multi_line_string read_multilinestring() { int num_lines = read_integer(); + mapnik::new_geometry::multi_line_string multi_line; + multi_line.reserve(num_lines); for (int i = 0; i < num_lines; ++i) { pos_ += 5; - read_linestring(paths); + multi_line.push_back(std::move(read_linestring())); } + return multi_line; } - void read_linestring_xyz(geometry_container & paths) - { - int num_points = read_integer(); - if (num_points > 0) - { - CoordinateArray ar(num_points); - read_coords_xyz(ar); - auto line = std::make_unique(geometry_type::types::LineString); - line->move_to(ar[0].x, ar[0].y); - for (int i = 1; i < num_points; ++i) - { - line->line_to(ar[i].x, ar[i].y); - } - paths.push_back(line.release()); - } - } - - void read_linestring_xyzm(geometry_container & paths) - { - int num_points = read_integer(); - if (num_points > 0) - { - CoordinateArray ar(num_points); - read_coords_xyzm(ar); - auto line = std::make_unique(geometry_type::types::LineString); - line->move_to(ar[0].x, ar[0].y); - for (int i = 1; i < num_points; ++i) - { - line->line_to(ar[i].x, ar[i].y); - } - paths.push_back(line.release()); - } - } - - void read_multilinestring_xyz(geometry_container & paths) - { - int num_lines = read_integer(); - for (int i = 0; i < num_lines; ++i) - { - pos_ += 5; - read_linestring_xyz(paths); - } - } - - void read_multilinestring_xyzm(geometry_container & paths) - { - int num_lines = read_integer(); - for (int i = 0; i < num_lines; ++i) - { - pos_ += 5; - read_linestring_xyzm(paths); - } - } - - void read_polygon(geometry_container & paths) + template + mapnik::new_geometry::polygon3 read_polygon() { int num_rings = read_integer(); - if (num_rings > 0) + mapnik::new_geometry::polygon3 poly; + if (num_rings > 1) { - auto poly = std::make_unique(geometry_type::types::Polygon); - for (int i = 0; i < num_rings; ++i) + poly.interior_rings.reserve(num_rings - 1); + } + + for (int i = 0; i < num_rings; ++i) + { + mapnik::new_geometry::linear_ring ring; + int num_points = read_integer(); + if (num_points > 0) { - int num_points = read_integer(); - if (num_points > 0) + ring.reserve(num_points); + CoordinateArray ar(num_points); + read_coords(ar); + for (int j = 0; j < num_points ; ++j) { - CoordinateArray ar(num_points); - read_coords(ar); - poly->move_to(ar[0].x, ar[0].y); - for (int j = 1; j < num_points ; ++j) - { - poly->line_to(ar[j].x, ar[j].y); - } - poly->close_path(); + ring.emplace_back(ar[j].x, ar[j].y); } } - if (poly->size() > 3) // ignore if polygon has less than (3 + close_path) vertices - paths.push_back(poly.release()); + if ( i == 0) poly.set_exterior_ring(std::move(ring)); + else poly.add_hole(std::move(ring)); } + return poly; } - void read_multipolygon(geometry_container & paths) + template + mapnik::new_geometry::multi_polygon read_multipolygon() { int num_polys = read_integer(); + mapnik::new_geometry::multi_polygon multi_poly; for (int i = 0; i < num_polys; ++i) { pos_ += 5; - read_polygon(paths); - } - } - - void read_polygon_xyz(geometry_container & paths) - { - int num_rings = read_integer(); - if (num_rings > 0) - { - auto poly = std::make_unique(geometry_type::types::Polygon); - for (int i = 0; i < num_rings; ++i) - { - int num_points = read_integer(); - if (num_points > 0) - { - CoordinateArray ar(num_points); - read_coords_xyz(ar); - poly->move_to(ar[0].x, ar[0].y); - for (int j = 1; j < num_points; ++j) - { - poly->line_to(ar[j].x, ar[j].y); - } - poly->close_path(); - } - } - if (poly->size() > 2) // ignore if polygon has less than 3 vertices - paths.push_back(poly.release()); - } - } - - void read_polygon_xyzm(geometry_container & paths) - { - int num_rings = read_integer(); - if (num_rings > 0) - { - auto poly = std::make_unique(geometry_type::types::Polygon); - for (int i = 0; i < num_rings; ++i) - { - int num_points = read_integer(); - if (num_points > 0) - { - CoordinateArray ar(num_points); - read_coords_xyzm(ar); - poly->move_to(ar[0].x, ar[0].y); - for (int j = 1; j < num_points; ++j) - { - poly->line_to(ar[j].x, ar[j].y); - } - poly->close_path(); - } - } - if (poly->size() > 2) // ignore if polygon has less than 3 vertices - paths.push_back(poly.release()); - } - } - - void read_multipolygon_xyz(geometry_container & paths) - { - int num_polys = read_integer(); - for (int i = 0; i < num_polys; ++i) - { - pos_ += 5; - read_polygon_xyz(paths); - } - } - - void read_multipolygon_xyzm(geometry_container & paths) - { - int num_polys = read_integer(); - for (int i = 0; i < num_polys; ++i) - { - pos_ += 5; - read_polygon_xyzm(paths); - } - } - - void read_collection(geometry_container & paths) - { - int num_geometries = read_integer(); - for (int i = 0; i < num_geometries; ++i) - { - pos_ += 1; // skip byte order - read(paths); + multi_poly.push_back(std::move(read_polygon())); } + return multi_poly; } std::string wkb_geometry_type_string(int type) @@ -595,7 +381,7 @@ private: case wkbGeometryCollection: s << "GeometryCollection"; break; case wkbGeometryCollectionZ: s << "GeometryCollectionZ"; break; case wkbGeometryCollectionM: s << "GeometryCollectionM"; break; - case wkbGeometryCollectionZM: s << "GeometryCollectionZM"; break; + case wkbGeometryCollectionZM:s << "GeometryCollectionZM"; break; default: s << "wkbUnknown(" << type << ")"; break; } @@ -604,17 +390,12 @@ private: }; -bool geometry_utils::from_wkb(geometry_container& paths, - const char* wkb, - unsigned size, - wkbFormat format) +mapnik::new_geometry::geometry geometry_utils::from_wkb(const char* wkb, + unsigned size, + wkbFormat format) { - std::size_t geom_count = paths.size(); wkb_reader reader(wkb, size, format); - reader.read(paths); - if (paths.size() > geom_count) - return true; - return false; + return mapnik::new_geometry::geometry(reader.read()); } -} +} // namespace mapnik