Skip to content

Commit

Permalink
Add envelope algorithm
Browse files Browse the repository at this point in the history
  • Loading branch information
jfirebaugh committed May 12, 2016
1 parent 87fef2a commit fed6140
Show file tree
Hide file tree
Showing 5 changed files with 105 additions and 0 deletions.
2 changes: 2 additions & 0 deletions include/mapbox/geometry.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,5 @@
#include <mapbox/geometry/geometry.hpp>
#include <mapbox/geometry/feature.hpp>
#include <mapbox/geometry/point_arithmetic.hpp>
#include <mapbox/geometry/for_each_point.hpp>
#include <mapbox/geometry/envelope.hpp>
30 changes: 30 additions & 0 deletions include/mapbox/geometry/box.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
#pragma once

namespace mapbox { namespace geometry {

template <typename T>
struct box
{
using point_type = point<T>;

box(point_type const& min_, point_type const& max_)
: min(min_), max(max_)
{}

point_type min;
point_type max;
};

template <typename T>
bool operator==(box<T> const& lhs, box<T> const& rhs)
{
return lhs.min == rhs.min && lhs.max == rhs.max;
}

template <typename T>
bool operator!=(box<T> const& lhs, box<T> const& rhs)
{
return lhs.min != rhs.min || lhs.max != rhs.max;
}

}}
31 changes: 31 additions & 0 deletions include/mapbox/geometry/envelope.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
#pragma once

#include <mapbox/geometry/box.hpp>
#include <mapbox/geometry/for_each_point.hpp>

#include <limits>

namespace mapbox { namespace geometry {

template <typename G, typename T = typename G::coordinate_type>
box<T> envelope(G const& geometry)
{
using limits = std::numeric_limits<T>;

T min_t = limits::has_infinity ? -limits::infinity() : limits::min();
T max_t = limits::has_infinity ? limits::infinity() : limits::max();

point<T> min(max_t, max_t);
point<T> max(min_t, min_t);

for_each_point(geometry, [&] (point<T> 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<T>(min, max);
}

}}
27 changes: 27 additions & 0 deletions include/mapbox/geometry/for_each_point.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
#pragma once

#include <mapbox/geometry/geometry.hpp>

namespace mapbox { namespace geometry {

template <typename T, typename F>
void for_each_point(point<T> const& point, F const& f)
{
f(point);
}

template <typename T, typename F>
void for_each_point(geometry<T> const& geom, F const& f)
{
geometry<T>::visit(geom, [&] (auto const& g) { for_each_point(g, f); });
}

template <typename Container, typename F>
void for_each_point(Container const& container, F const& f)
{
for (auto const& e: container) {
for_each_point(e, f);
}
}

}}
15 changes: 15 additions & 0 deletions tests/test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,19 @@ static void testFeatureCollection() {
assert(fc1.size() == 0);
}

static void testEnvelope() {
assert(envelope(point<double>(0, 0)) == box<double>({0, 0}, {0, 0}));
assert(envelope(line_string<double>({{0, 1}, {2, 3}})) == box<double>({0, 1}, {2, 3}));
assert(envelope(polygon<double>({{{0, 1}, {2, 3}}})) == box<double>({0, 1}, {2, 3}));

assert(envelope(multi_point<double>({{0, 0}})) == box<double>({0, 0}, {0, 0}));
assert(envelope(multi_line_string<double>({{{0, 1}, {2, 3}}})) == box<double>({0, 1}, {2, 3}));
assert(envelope(multi_polygon<double>({{{{0, 1}, {2, 3}}}})) == box<double>({0, 1}, {2, 3}));

assert(envelope(geometry<int>(point<int>(0, 0))) == box<int>({0, 0}, {0, 0}));
assert(envelope(geometry_collection<int>({point<int>(0, 0)})) == box<int>({0, 0}, {0, 0}));
}

int main() {
testPoint();
testMultiPoint();
Expand All @@ -147,5 +160,7 @@ int main() {
testGeometryCollection();
testFeature();
testFeatureCollection();

testEnvelope();
return 0;
}

0 comments on commit fed6140

Please sign in to comment.