diff --git a/DataStructures/Rectangle.h b/DataStructures/Rectangle.h new file mode 100644 index 000000000..beaf0b1df --- /dev/null +++ b/DataStructures/Rectangle.h @@ -0,0 +1,164 @@ +#ifndef RECTANGLE_H +#define RECTANGLE_H + +// TODO: Make template type +struct RectangleInt2D +{ + RectangleInt2D() : min_lon(INT_MAX), max_lon(INT_MIN), min_lat(INT_MAX), max_lat(INT_MIN) {} + + int32_t min_lon, max_lon; + int32_t min_lat, max_lat; + + + inline void MergeBoundingBoxes(const RectangleInt2D &other) + { + min_lon = std::min(min_lon, other.min_lon); + max_lon = std::max(max_lon, other.max_lon); + min_lat = std::min(min_lat, other.min_lat); + max_lat = std::max(max_lat, other.max_lat); + BOOST_ASSERT(min_lat != std::numeric_limits::min()); + BOOST_ASSERT(min_lon != std::numeric_limits::min()); + BOOST_ASSERT(max_lat != std::numeric_limits::min()); + BOOST_ASSERT(max_lon != std::numeric_limits::min()); + } + + inline FixedPointCoordinate Centroid() const + { + FixedPointCoordinate centroid; + // The coordinates of the midpoints are given by: + // x = (x1 + x2) /2 and y = (y1 + y2) /2. + centroid.lon = (min_lon + max_lon) / 2; + centroid.lat = (min_lat + max_lat) / 2; + return centroid; + } + + inline bool Intersects(const RectangleInt2D &other) const + { + FixedPointCoordinate upper_left(other.max_lat, other.min_lon); + FixedPointCoordinate upper_right(other.max_lat, other.max_lon); + FixedPointCoordinate lower_right(other.min_lat, other.max_lon); + FixedPointCoordinate lower_left(other.min_lat, other.min_lon); + + return (Contains(upper_left) || Contains(upper_right) || Contains(lower_right) || + Contains(lower_left)); + } + + inline float GetMinDist(const FixedPointCoordinate &location) const + { + const bool is_contained = Contains(location); + if (is_contained) + { + return 0.; + } + + enum Direction + { + INVALID = 0, + NORTH = 1, + SOUTH = 2, + EAST = 4, + NORTH_EAST = 5, + SOUTH_EAST = 6, + WEST = 8, + NORTH_WEST = 9, + SOUTH_WEST = 10 + }; + + Direction d = INVALID; + if (location.lat > max_lat) + d = (Direction) (d | NORTH); + else if (location.lat < min_lat) + d = (Direction) (d | SOUTH); + if (location.lon > max_lon) + d = (Direction) (d | EAST); + else if (location.lon < min_lon) + d = (Direction) (d | WEST); + + BOOST_ASSERT(d != INVALID); + + float min_dist = std::numeric_limits::max(); + switch (d) + { + case NORTH: + min_dist = FixedPointCoordinate::ApproximateEuclideanDistance(location, FixedPointCoordinate(max_lat, location.lon)); + break; + case SOUTH: + min_dist = FixedPointCoordinate::ApproximateEuclideanDistance(location, FixedPointCoordinate(min_lat, location.lon)); + break; + case WEST: + min_dist = FixedPointCoordinate::ApproximateEuclideanDistance(location, FixedPointCoordinate(location.lat, min_lon)); + break; + case EAST: + min_dist = FixedPointCoordinate::ApproximateEuclideanDistance(location, FixedPointCoordinate(location.lat, max_lon)); + break; + case NORTH_EAST: + min_dist = FixedPointCoordinate::ApproximateEuclideanDistance(location, FixedPointCoordinate(max_lat, max_lon)); + break; + case NORTH_WEST: + min_dist = FixedPointCoordinate::ApproximateEuclideanDistance(location, FixedPointCoordinate(max_lat, min_lon)); + break; + case SOUTH_EAST: + min_dist = FixedPointCoordinate::ApproximateEuclideanDistance(location, FixedPointCoordinate(min_lat, max_lon)); + break; + case SOUTH_WEST: + min_dist = FixedPointCoordinate::ApproximateEuclideanDistance(location, FixedPointCoordinate(min_lat, min_lon)); + break; + default: + break; + } + + BOOST_ASSERT(min_dist != std::numeric_limits::max()); + + return min_dist; + } + + inline float GetMinMaxDist(const FixedPointCoordinate &location) const + { + float min_max_dist = std::numeric_limits::max(); + // Get minmax distance to each of the four sides + const FixedPointCoordinate upper_left(max_lat, min_lon); + const FixedPointCoordinate upper_right(max_lat, max_lon); + const FixedPointCoordinate lower_right(min_lat, max_lon); + const FixedPointCoordinate lower_left(min_lat, min_lon); + + min_max_dist = std::min( + min_max_dist, + std::max( + FixedPointCoordinate::ApproximateEuclideanDistance(location, upper_left), + FixedPointCoordinate::ApproximateEuclideanDistance(location, upper_right))); + + min_max_dist = std::min( + min_max_dist, + std::max( + FixedPointCoordinate::ApproximateEuclideanDistance(location, upper_right), + FixedPointCoordinate::ApproximateEuclideanDistance(location, lower_right))); + + min_max_dist = std::min( + min_max_dist, + std::max(FixedPointCoordinate::ApproximateEuclideanDistance(location, lower_right), + FixedPointCoordinate::ApproximateEuclideanDistance(location, lower_left))); + + min_max_dist = std::min( + min_max_dist, + std::max(FixedPointCoordinate::ApproximateEuclideanDistance(location, lower_left), + FixedPointCoordinate::ApproximateEuclideanDistance(location, upper_left))); + return min_max_dist; + } + + inline bool Contains(const FixedPointCoordinate &location) const + { + const bool lats_contained = (location.lat >= min_lat) && (location.lat <= max_lat); + const bool lons_contained = (location.lon >= min_lon) && (location.lon <= max_lon); + return lats_contained && lons_contained; + } + + inline friend std::ostream &operator<<(std::ostream &out, const RectangleInt2D &rect) + { + out << rect.min_lat / COORDINATE_PRECISION << "," << rect.min_lon / COORDINATE_PRECISION + << " " << rect.max_lat / COORDINATE_PRECISION << "," + << rect.max_lon / COORDINATE_PRECISION; + return out; + } +}; + +#endif diff --git a/DataStructures/StaticRTree.h b/DataStructures/StaticRTree.h index 62e194e66..59ae17f61 100644 --- a/DataStructures/StaticRTree.h +++ b/DataStructures/StaticRTree.h @@ -34,6 +34,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "QueryNode.h" #include "SharedMemoryFactory.h" #include "SharedMemoryVectorWrapper.h" +#include "Rectangle.h" #include "../ThirdParty/variant/variant.hpp" #include "../Util/floating_point.hpp" @@ -70,190 +71,6 @@ template &objects, - const uint32_t element_count, - const std::vector &coordinate_list) - { - for (uint32_t i = 0; i < element_count; ++i) - { - min_lon = std::min(min_lon, - std::min(coordinate_list.at(objects[i].u).lon, - coordinate_list.at(objects[i].v).lon)); - max_lon = std::max(max_lon, - std::max(coordinate_list.at(objects[i].u).lon, - coordinate_list.at(objects[i].v).lon)); - - min_lat = std::min(min_lat, - std::min(coordinate_list.at(objects[i].u).lat, - coordinate_list.at(objects[i].v).lat)); - max_lat = std::max(max_lat, - std::max(coordinate_list.at(objects[i].u).lat, - coordinate_list.at(objects[i].v).lat)); - } - BOOST_ASSERT(min_lat != std::numeric_limits::min()); - BOOST_ASSERT(min_lon != std::numeric_limits::min()); - BOOST_ASSERT(max_lat != std::numeric_limits::min()); - BOOST_ASSERT(max_lon != std::numeric_limits::min()); - } - - inline void MergeBoundingBoxes(const RectangleInt2D &other) - { - min_lon = std::min(min_lon, other.min_lon); - max_lon = std::max(max_lon, other.max_lon); - min_lat = std::min(min_lat, other.min_lat); - max_lat = std::max(max_lat, other.max_lat); - BOOST_ASSERT(min_lat != std::numeric_limits::min()); - BOOST_ASSERT(min_lon != std::numeric_limits::min()); - BOOST_ASSERT(max_lat != std::numeric_limits::min()); - BOOST_ASSERT(max_lon != std::numeric_limits::min()); - } - - inline FixedPointCoordinate Centroid() const - { - FixedPointCoordinate centroid; - // The coordinates of the midpoints are given by: - // x = (x1 + x2) /2 and y = (y1 + y2) /2. - centroid.lon = (min_lon + max_lon) / 2; - centroid.lat = (min_lat + max_lat) / 2; - return centroid; - } - - inline bool Intersects(const RectangleInt2D &other) const - { - FixedPointCoordinate upper_left(other.max_lat, other.min_lon); - FixedPointCoordinate upper_right(other.max_lat, other.max_lon); - FixedPointCoordinate lower_right(other.min_lat, other.max_lon); - FixedPointCoordinate lower_left(other.min_lat, other.min_lon); - - return (Contains(upper_left) || Contains(upper_right) || Contains(lower_right) || - Contains(lower_left)); - } - - inline float GetMinDist(const FixedPointCoordinate &location) const - { - const bool is_contained = Contains(location); - if (is_contained) - { - return 0.; - } - - enum Direction - { - INVALID = 0, - NORTH = 1, - SOUTH = 2, - EAST = 4, - NORTH_EAST = 5, - SOUTH_EAST = 6, - WEST = 8, - NORTH_WEST = 9, - SOUTH_WEST = 10 - }; - - Direction d = INVALID; - if (location.lat > max_lat) - d = (Direction) (d | NORTH); - else if (location.lat < min_lat) - d = (Direction) (d | SOUTH); - if (location.lon > max_lon) - d = (Direction) (d | EAST); - else if (location.lon < min_lon) - d = (Direction) (d | WEST); - - BOOST_ASSERT(d != INVALID); - - float min_dist = std::numeric_limits::max(); - switch (d) - { - case NORTH: - min_dist = FixedPointCoordinate::ApproximateEuclideanDistance(location, FixedPointCoordinate(max_lat, location.lon)); - break; - case SOUTH: - min_dist = FixedPointCoordinate::ApproximateEuclideanDistance(location, FixedPointCoordinate(min_lat, location.lon)); - break; - case WEST: - min_dist = FixedPointCoordinate::ApproximateEuclideanDistance(location, FixedPointCoordinate(location.lat, min_lon)); - break; - case EAST: - min_dist = FixedPointCoordinate::ApproximateEuclideanDistance(location, FixedPointCoordinate(location.lat, max_lon)); - break; - case NORTH_EAST: - min_dist = FixedPointCoordinate::ApproximateEuclideanDistance(location, FixedPointCoordinate(max_lat, max_lon)); - break; - case NORTH_WEST: - min_dist = FixedPointCoordinate::ApproximateEuclideanDistance(location, FixedPointCoordinate(max_lat, min_lon)); - break; - case SOUTH_EAST: - min_dist = FixedPointCoordinate::ApproximateEuclideanDistance(location, FixedPointCoordinate(min_lat, max_lon)); - break; - case SOUTH_WEST: - min_dist = FixedPointCoordinate::ApproximateEuclideanDistance(location, FixedPointCoordinate(min_lat, min_lon)); - break; - default: - break; - } - - BOOST_ASSERT(min_dist != std::numeric_limits::max()); - - return min_dist; - } - - inline float GetMinMaxDist(const FixedPointCoordinate &location) const - { - float min_max_dist = std::numeric_limits::max(); - // Get minmax distance to each of the four sides - const FixedPointCoordinate upper_left(max_lat, min_lon); - const FixedPointCoordinate upper_right(max_lat, max_lon); - const FixedPointCoordinate lower_right(min_lat, max_lon); - const FixedPointCoordinate lower_left(min_lat, min_lon); - - min_max_dist = std::min( - min_max_dist, - std::max( - FixedPointCoordinate::ApproximateEuclideanDistance(location, upper_left), - FixedPointCoordinate::ApproximateEuclideanDistance(location, upper_right))); - - min_max_dist = std::min( - min_max_dist, - std::max( - FixedPointCoordinate::ApproximateEuclideanDistance(location, upper_right), - FixedPointCoordinate::ApproximateEuclideanDistance(location, lower_right))); - - min_max_dist = std::min( - min_max_dist, - std::max(FixedPointCoordinate::ApproximateEuclideanDistance(location, lower_right), - FixedPointCoordinate::ApproximateEuclideanDistance(location, lower_left))); - - min_max_dist = std::min( - min_max_dist, - std::max(FixedPointCoordinate::ApproximateEuclideanDistance(location, lower_left), - FixedPointCoordinate::ApproximateEuclideanDistance(location, upper_left))); - return min_max_dist; - } - - inline bool Contains(const FixedPointCoordinate &location) const - { - const bool lats_contained = (location.lat >= min_lat) && (location.lat <= max_lat); - const bool lons_contained = (location.lon >= min_lon) && (location.lon <= max_lon); - return lats_contained && lons_contained; - } - - inline friend std::ostream &operator<<(std::ostream &out, const RectangleInt2D &rect) - { - out << rect.min_lat / COORDINATE_PRECISION << "," << rect.min_lon / COORDINATE_PRECISION - << " " << rect.max_lat / COORDINATE_PRECISION << "," - << rect.max_lon / COORDINATE_PRECISION; - return out; - } - }; - using RectangleT = RectangleInt2D; struct TreeNode @@ -412,7 +229,7 @@ class StaticRTree } // generate tree node that resemble the objects in leaf and store it for next level - current_node.minimum_bounding_rectangle.InitializeMBRectangle( + InitializeMBRectangle(current_node.minimum_bounding_rectangle, current_leaf.objects, current_leaf.object_count, coordinate_list); current_node.child_is_on_disk = true; current_node.children[0] = tree_nodes_in_level.size(); @@ -1199,6 +1016,33 @@ class StaticRTree { return (a == b && c == d) || (a == c && b == d) || (a == d && b == c); } + + inline void InitializeMBRectangle(RectangleT& rectangle, + const std::array &objects, + const uint32_t element_count, + const std::vector &coordinate_list) + { + for (uint32_t i = 0; i < element_count; ++i) + { + rectangle.min_lon = std::min(rectangle.min_lon, + std::min(coordinate_list.at(objects[i].u).lon, + coordinate_list.at(objects[i].v).lon)); + rectangle.max_lon = std::max(rectangle.max_lon, + std::max(coordinate_list.at(objects[i].u).lon, + coordinate_list.at(objects[i].v).lon)); + + rectangle.min_lat = std::min(rectangle.min_lat, + std::min(coordinate_list.at(objects[i].u).lat, + coordinate_list.at(objects[i].v).lat)); + rectangle.max_lat = std::max(rectangle.max_lat, + std::max(coordinate_list.at(objects[i].u).lat, + coordinate_list.at(objects[i].v).lat)); + } + BOOST_ASSERT(rectangle.min_lat != std::numeric_limits::min()); + BOOST_ASSERT(rectangle.min_lon != std::numeric_limits::min()); + BOOST_ASSERT(rectangle.max_lat != std::numeric_limits::min()); + BOOST_ASSERT(rectangle.max_lon != std::numeric_limits::min()); + } }; //[1] "On Packing R-Trees"; I. Kamel, C. Faloutsos; 1993; DOI: 10.1145/170088.170403