-
Notifications
You must be signed in to change notification settings - Fork 99
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #541 from eyal0/to_geos_no_wkt
perf: to_geos without using WKT
- Loading branch information
Showing
360 changed files
with
98,596 additions
and
98,348 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,57 +1,142 @@ | ||
#ifdef GEOS_VERSION | ||
|
||
#include "geos_helpers.hpp" | ||
#include "geometry.hpp" | ||
#include <geos/io/WKTReader.h> | ||
#include <geos/io/WKTReader.inl> | ||
#include <geos/io/WKTWriter.h> | ||
#include <geos/geom/CoordinateSequenceFactory.h> | ||
#include <geos/geom/Coordinate.h> | ||
#include <geos/geom/Coordinate.inl> | ||
#include <geos/geom/GeometryFactory.h> | ||
#include <geos/geom/GeometryFactory.inl> | ||
#include <boost/pointer_cast.hpp> | ||
|
||
template <typename T> | ||
std::unique_ptr<geos::geom::Geometry> to_geos(const T& mp) { | ||
geos::io::WKTReader reader; | ||
std::stringstream ss; | ||
ss << bg::wkt(mp); | ||
return reader.read(ss.str()); | ||
linestring_type_fp from_geos(const geos::geom::LineString* ls) { | ||
linestring_type_fp ret; | ||
ret.reserve(ls->getNumPoints()); | ||
for (size_t i = 0; i < ls->getNumPoints(); i++) { | ||
const auto& p = ls->getPointN(i); | ||
ret.push_back(point_type_fp(p->getX(), p->getY())); | ||
} | ||
return ret; | ||
} | ||
template std::unique_ptr<geos::geom::Geometry> to_geos(const multi_polygon_type_fp& mp); | ||
template std::unique_ptr<geos::geom::Geometry> to_geos(const multi_linestring_type_fp& mls); | ||
template std::unique_ptr<geos::geom::Geometry> to_geos(const linestring_type_fp& mls); | ||
|
||
linestring_type_fp from_geos(const std::unique_ptr<geos::geom::LineString>& ls) { | ||
return from_geos(ls.get()); | ||
} | ||
|
||
template <typename T> | ||
T from_geos(const std::unique_ptr<geos::geom::Geometry>& g); | ||
ring_type_fp from_geos(const geos::geom::LinearRing* ring) { | ||
ring_type_fp ret; | ||
ret.reserve(ring->getNumPoints()); | ||
for (size_t i = 0; i < ring->getNumPoints(); i++) { | ||
const auto& p = ring->getPointN(i); | ||
ret.push_back(point_type_fp(p->getX(), p->getY())); | ||
} | ||
return ret; | ||
} | ||
|
||
template <> | ||
multi_polygon_type_fp from_geos(const std::unique_ptr<geos::geom::Geometry>& g) { | ||
geos::io::WKTWriter writer; | ||
std::string geos_wkt = writer.write(g.get()); | ||
boost::replace_all(geos_wkt, "EMPTY, ", ""); | ||
boost::replace_all(geos_wkt, ", EMPTY", ""); | ||
ring_type_fp from_geos(const std::unique_ptr<geos::geom::LinearRing>& ring) { | ||
return from_geos(ring.get()); | ||
} | ||
|
||
polygon_type_fp from_geos(const geos::geom::Polygon* poly) { | ||
polygon_type_fp ret; | ||
ret.outer() = from_geos(poly->getExteriorRing()); | ||
ret.inners().reserve(poly->getNumInteriorRing()); | ||
for (size_t i = 0; i < poly->getNumInteriorRing(); i++) { | ||
ret.inners().push_back(from_geos(poly->getInteriorRingN(i))); | ||
} | ||
return ret; | ||
} | ||
|
||
polygon_type_fp from_geos(const std::unique_ptr<geos::geom::Polygon>& poly) { | ||
return from_geos(poly.get()); | ||
} | ||
|
||
multi_polygon_type_fp from_geos(const std::unique_ptr<geos::geom::MultiPolygon>& mpoly) { | ||
multi_polygon_type_fp ret; | ||
if (strncmp(geos_wkt.c_str(), "MULTIPOLYGON", 12) == 0) { | ||
bg::read_wkt(geos_wkt, ret); | ||
} else { | ||
polygon_type_fp poly; | ||
bg::read_wkt(geos_wkt, poly); | ||
ret.push_back(poly); | ||
ret.reserve(mpoly->getNumGeometries()); | ||
for (size_t i = 0; i < mpoly->getNumGeometries(); i++) { | ||
ret.push_back(from_geos(mpoly->getGeometryN(i))); | ||
} | ||
return ret; | ||
} | ||
|
||
template <> | ||
multi_linestring_type_fp from_geos(const std::unique_ptr<geos::geom::Geometry>& g) { | ||
geos::io::WKTWriter writer; | ||
std::string geos_wkt = writer.write(g.get()); | ||
boost::replace_all(geos_wkt, "EMPTY, ", ""); | ||
boost::replace_all(geos_wkt, ", EMPTY", ""); | ||
multi_linestring_type_fp from_geos(const std::unique_ptr<geos::geom::MultiLineString>& mls) { | ||
multi_linestring_type_fp ret; | ||
if (strncmp(geos_wkt.c_str(), "MULTILINESTRING", 12) == 0) { | ||
bg::read_wkt(geos_wkt, ret); | ||
} else { | ||
linestring_type_fp ls; | ||
bg::read_wkt(geos_wkt, ls); | ||
ret.push_back(ls); | ||
ret.reserve(mls->getNumGeometries()); | ||
for (size_t i = 0; i < mls->getNumGeometries(); i++) { | ||
ret.push_back(from_geos(mls->getGeometryN(i))); | ||
} | ||
return ret; | ||
} | ||
|
||
template <> | ||
multi_polygon_type_fp from_geos(const std::unique_ptr<geos::geom::Geometry>& g) { | ||
if (dynamic_cast<geos::geom::MultiPolygon*>(g.get())) { | ||
auto mp = boost::dynamic_pointer_cast<geos::geom::MultiPolygon>(g->clone()); | ||
return from_geos(mp); | ||
} | ||
if (dynamic_cast<geos::geom::Polygon*>(g.get())) { | ||
auto p = boost::dynamic_pointer_cast<geos::geom::Polygon>(g->clone()); | ||
return multi_polygon_type_fp{from_geos(p)}; | ||
} | ||
geos::io::WKTWriter writer; | ||
throw std::logic_error("Can't convert to multi_polygon_type_fp: " + writer.write(g.get())); | ||
} | ||
|
||
std::unique_ptr<geos::geom::LineString> to_geos( | ||
const linestring_type_fp& ls) { | ||
auto geom_factory = geos::geom::GeometryFactory::create(); | ||
auto coord_factory = geom_factory->getCoordinateSequenceFactory(); | ||
auto coords = coord_factory->create(ls.size(), 2 /* dimensions */); | ||
for (size_t i = 0; i < ls.size(); i++) { | ||
coords->setAt(geos::geom::Coordinate(ls[i].x(), ls[i].y()), i); | ||
} | ||
return geom_factory->createLineString(std::move(coords)); | ||
} | ||
|
||
std::unique_ptr<geos::geom::LinearRing> to_geos(const ring_type_fp& ring) { | ||
auto geom_factory = geos::geom::GeometryFactory::create(); | ||
auto coord_factory = geom_factory->getCoordinateSequenceFactory(); | ||
auto coords = coord_factory->create(ring.size(), 2 /* dimensions */); | ||
for (size_t i = 0; i < ring.size(); i++) { | ||
// reverse rings for geos. | ||
coords->setAt(geos::geom::Coordinate(ring[i].x(), ring[i].y()), i); | ||
} | ||
return geom_factory->createLinearRing(std::move(coords)); | ||
} | ||
|
||
std::unique_ptr<geos::geom::Polygon> to_geos(const polygon_type_fp& poly) { | ||
auto shell = to_geos(poly.outer()); | ||
std::vector<std::unique_ptr<geos::geom::LinearRing>> holes; | ||
holes.reserve(poly.inners().size()); | ||
for (const auto& inner : poly.inners()) { | ||
holes.push_back(to_geos(inner)); | ||
} | ||
auto geom_factory = geos::geom::GeometryFactory::create(); | ||
return geom_factory->createPolygon(std::move(shell), std::move(holes)); | ||
} | ||
|
||
std::unique_ptr<geos::geom::MultiPolygon> to_geos(const multi_polygon_type_fp& mpoly) { | ||
std::vector<std::unique_ptr<geos::geom::Polygon>> polys; | ||
polys.reserve(mpoly.size()); | ||
for (const auto& p : mpoly) { | ||
polys.push_back(to_geos(p)); | ||
} | ||
auto geom_factory = geos::geom::GeometryFactory::create(); | ||
return geom_factory->createMultiPolygon(std::move(polys)); | ||
} | ||
|
||
std::unique_ptr<geos::geom::MultiLineString> to_geos(const multi_linestring_type_fp& mls) { | ||
std::vector<std::unique_ptr<geos::geom::LineString>> polys; | ||
polys.reserve(mls.size()); | ||
for (const auto& p : mls) { | ||
polys.push_back(to_geos(p)); | ||
} | ||
auto geom_factory = geos::geom::GeometryFactory::create(); | ||
return geom_factory->createMultiLineString(std::move(polys)); | ||
} | ||
|
||
#endif //GEOS_VERSION |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,97 @@ | ||
#define BOOST_TEST_MODULE geos helpers tests | ||
#include <boost/test/unit_test.hpp> | ||
|
||
#include "geometry.hpp" | ||
#include "geos_helpers.hpp" | ||
#include "bg_operators.hpp" | ||
#ifdef GEOS_VERSION | ||
#include <geos/io/WKTReader.h> | ||
#endif // GEOS_VERSION | ||
#include <boost/pointer_cast.hpp> | ||
|
||
BOOST_AUTO_TEST_SUITE(geos_helpers_tests) | ||
|
||
BOOST_AUTO_TEST_SUITE(boost_geometry) | ||
|
||
// Holes are counter-clockwise | ||
BOOST_AUTO_TEST_CASE(polygon_with_holes_direction) { | ||
auto box = bg::return_envelope<box_type_fp>(point_type_fp(0,0)); | ||
bg::expand(box, point_type_fp(10,10)); | ||
auto hole = bg::return_envelope<box_type_fp>(point_type_fp(3,3)); | ||
bg::expand(hole, point_type_fp(7,7)); | ||
multi_polygon_type_fp mpoly; | ||
bg::convert(box, mpoly); | ||
mpoly = mpoly - hole; | ||
BOOST_CHECK_EQUAL(mpoly[0].outer()[1], point_type_fp(0,10)); | ||
BOOST_CHECK_EQUAL(mpoly[0].inners()[0][1], point_type_fp(7,3)); | ||
bg::reverse(mpoly); | ||
BOOST_CHECK_EQUAL(mpoly[0].outer()[1], point_type_fp(10,0)); | ||
BOOST_CHECK_EQUAL(mpoly[0].inners()[0][1], point_type_fp(3,7)); | ||
bg::correct(mpoly); | ||
BOOST_CHECK_EQUAL(mpoly[0].outer()[1], point_type_fp(0,10)); | ||
BOOST_CHECK_EQUAL(mpoly[0].inners()[0][1], point_type_fp(7,3)); | ||
} | ||
|
||
BOOST_AUTO_TEST_SUITE_END() | ||
|
||
#ifdef GEOS_VERSION | ||
|
||
BOOST_AUTO_TEST_SUITE(geos_geometry) | ||
|
||
BOOST_AUTO_TEST_CASE(polygon_with_holes_direction) { | ||
// Convert it through well-known text, which is sure to create a | ||
// valid polygon in geos. | ||
geos::io::WKTReader reader; | ||
auto geos_geo = reader.read("MULTIPOLYGON(((0 0,0 10,10 10,10 0,0 0),(3 3,7 3,7 7,3 7,3 3)))"); | ||
auto* geos_poly = dynamic_cast<geos::geom::MultiPolygon*>(geos_geo.get()); | ||
geos_poly->normalize(); | ||
BOOST_CHECK_EQUAL(geos_poly->getGeometryN(0)->getExteriorRing()->getPointN(1)->getX(), 0); | ||
BOOST_CHECK_EQUAL(geos_poly->getGeometryN(0)->getExteriorRing()->getPointN(1)->getY(), 10); | ||
BOOST_CHECK_EQUAL(geos_poly->getGeometryN(0)->getInteriorRingN(0)->getPointN(1)->getX(), 7); | ||
BOOST_CHECK_EQUAL(geos_poly->getGeometryN(0)->getInteriorRingN(0)->getPointN(1)->getY(), 3); | ||
|
||
// Now convert a reversed version. | ||
geos_geo = reader.read("MULTIPOLYGON(((0 0,10 0,10 10,0 10,0 0),(3 3,3 7,7 7,7 3,3 3)))"); | ||
geos_poly = dynamic_cast<geos::geom::MultiPolygon*>(geos_geo.get()); | ||
geos_poly->normalize(); | ||
BOOST_CHECK_EQUAL(geos_poly->getGeometryN(0)->getExteriorRing()->getPointN(1)->getX(), 0); | ||
BOOST_CHECK_EQUAL(geos_poly->getGeometryN(0)->getExteriorRing()->getPointN(1)->getY(), 10); | ||
BOOST_CHECK_EQUAL(geos_poly->getGeometryN(0)->getInteriorRingN(0)->getPointN(1)->getX(), 7); | ||
BOOST_CHECK_EQUAL(geos_poly->getGeometryN(0)->getInteriorRingN(0)->getPointN(1)->getY(), 3); | ||
} | ||
|
||
BOOST_AUTO_TEST_SUITE(roundtrip) | ||
|
||
BOOST_AUTO_TEST_CASE(multi_linestring) { | ||
multi_linestring_type_fp mls{{{0,0}, {1,1}}, {{2,2},{3,3}}}; | ||
BOOST_CHECK_EQUAL(from_geos(to_geos(mls)), mls); | ||
} | ||
|
||
BOOST_AUTO_TEST_CASE(linestring) { | ||
linestring_type_fp ls{{0,0}, {1,1}}; | ||
BOOST_CHECK_EQUAL(from_geos(to_geos(ls)), ls); | ||
} | ||
|
||
BOOST_AUTO_TEST_CASE(polygon) { | ||
polygon_type_fp poly{{{0,0}, {0,10}, {10,10}, {10,0}, {0,0}}}; | ||
BOOST_CHECK(bg::equals(from_geos(to_geos(poly)), poly)); | ||
} | ||
|
||
BOOST_AUTO_TEST_CASE(ring) { | ||
ring_type_fp ring{{0,0}, {0,10}, {10,10}, {10,0}, {0,0}}; | ||
BOOST_CHECK_EQUAL(from_geos(to_geos(ring)), ring); | ||
} | ||
|
||
BOOST_AUTO_TEST_SUITE_END() | ||
|
||
BOOST_AUTO_TEST_CASE(convert_multi_polygon_exception) { | ||
linestring_type_fp ls{{0,0}, {1,1}}; | ||
auto geos_ls = boost::dynamic_pointer_cast<geos::geom::Geometry>(to_geos(ls)); | ||
BOOST_CHECK_THROW(from_geos<multi_polygon_type_fp>(geos_ls), std::logic_error); | ||
} | ||
|
||
BOOST_AUTO_TEST_SUITE_END() | ||
|
||
#endif // GEOS_VERSION | ||
|
||
BOOST_AUTO_TEST_SUITE_END() |
Oops, something went wrong.