diff --git a/include/mapbox/geometry.hpp b/include/mapbox/geometry.hpp index b4206cc..e232453 100644 --- a/include/mapbox/geometry.hpp +++ b/include/mapbox/geometry.hpp @@ -9,3 +9,5 @@ #include #include #include +#include +#include diff --git a/include/mapbox/geometry/box.hpp b/include/mapbox/geometry/box.hpp new file mode 100644 index 0000000..173b519 --- /dev/null +++ b/include/mapbox/geometry/box.hpp @@ -0,0 +1,30 @@ +#pragma once + +namespace mapbox { namespace geometry { + +template +struct box +{ + using point_type = point; + + box(point_type const& min_, point_type const& max_) + : min(min_), max(max_) + {} + + point_type min; + point_type max; +}; + +template +bool operator==(box const& lhs, box const& rhs) +{ + return lhs.min == rhs.min && lhs.max == rhs.max; +} + +template +bool operator!=(box const& lhs, box const& rhs) +{ + return lhs.min != rhs.min || lhs.max != rhs.max; +} + +}} diff --git a/include/mapbox/geometry/envelope.hpp b/include/mapbox/geometry/envelope.hpp new file mode 100644 index 0000000..c2878f2 --- /dev/null +++ b/include/mapbox/geometry/envelope.hpp @@ -0,0 +1,31 @@ +#pragma once + +#include +#include + +#include + +namespace mapbox { namespace geometry { + +template +box envelope(G const& geometry) +{ + using limits = std::numeric_limits; + + T min_t = limits::has_infinity ? -limits::infinity() : limits::min(); + T max_t = limits::has_infinity ? limits::infinity() : limits::max(); + + point min(max_t, max_t); + point max(min_t, min_t); + + for_each_point(geometry, [&] (point const& point) { + if (min.x > point.x) min.x = point.x; + if (min.y > point.y) min.y = point.y; + if (max.x < point.x) max.x = point.x; + if (max.y < point.y) max.y = point.y; + }); + + return box(min, max); +} + +}} diff --git a/include/mapbox/geometry/for_each_point.hpp b/include/mapbox/geometry/for_each_point.hpp new file mode 100644 index 0000000..62198eb --- /dev/null +++ b/include/mapbox/geometry/for_each_point.hpp @@ -0,0 +1,27 @@ +#pragma once + +#include + +namespace mapbox { namespace geometry { + +template +void for_each_point(point const& point, F const& f) +{ + f(point); +} + +template +void for_each_point(geometry const& geom, F const& f) +{ + geometry::visit(geom, [&] (auto const& g) { for_each_point(g, f); }); +} + +template +void for_each_point(Container const& container, F const& f) +{ + for (auto const& e: container) { + for_each_point(e, f); + } +} + +}} diff --git a/tests/test.cpp b/tests/test.cpp index d27471d..1f16247 100644 --- a/tests/test.cpp +++ b/tests/test.cpp @@ -136,6 +136,19 @@ static void testFeatureCollection() { assert(fc1.size() == 0); } +static void testEnvelope() { + assert(envelope(point(0, 0)) == box({0, 0}, {0, 0})); + assert(envelope(line_string({{0, 1}, {2, 3}})) == box({0, 1}, {2, 3})); + assert(envelope(polygon({{{0, 1}, {2, 3}}})) == box({0, 1}, {2, 3})); + + assert(envelope(multi_point({{0, 0}})) == box({0, 0}, {0, 0})); + assert(envelope(multi_line_string({{{0, 1}, {2, 3}}})) == box({0, 1}, {2, 3})); + assert(envelope(multi_polygon({{{{0, 1}, {2, 3}}}})) == box({0, 1}, {2, 3})); + + assert(envelope(geometry(point(0, 0))) == box({0, 0}, {0, 0})); + assert(envelope(geometry_collection({point(0, 0)})) == box({0, 0}, {0, 0})); +} + int main() { testPoint(); testMultiPoint(); @@ -147,5 +160,7 @@ int main() { testGeometryCollection(); testFeature(); testFeatureCollection(); + + testEnvelope(); return 0; }