184 lines
		
	
	
		
			6.2 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			184 lines
		
	
	
		
			6.2 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| #ifndef RECTANGLE_HPP
 | |
| #define RECTANGLE_HPP
 | |
| 
 | |
| #include "util/coordinate_calculation.hpp"
 | |
| 
 | |
| #include <boost/assert.hpp>
 | |
| 
 | |
| #include "osrm/coordinate.hpp"
 | |
| 
 | |
| #include <algorithm>
 | |
| #include <cstdint>
 | |
| #include <limits>
 | |
| 
 | |
| namespace osrm
 | |
| {
 | |
| namespace util
 | |
| {
 | |
| 
 | |
| // TODO: Make template type, add tests
 | |
| struct RectangleInt2D
 | |
| {
 | |
|     RectangleInt2D()
 | |
|         : min_lon(std::numeric_limits<int32_t>::max()),
 | |
|           max_lon(std::numeric_limits<int32_t>::min()),
 | |
|           min_lat(std::numeric_limits<int32_t>::max()), max_lat(std::numeric_limits<int32_t>::min())
 | |
|     {
 | |
|     }
 | |
| 
 | |
|     int32_t min_lon, max_lon;
 | |
|     int32_t min_lat, max_lat;
 | |
| 
 | |
|     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<int32_t>::min());
 | |
|         BOOST_ASSERT(min_lon != std::numeric_limits<int32_t>::min());
 | |
|         BOOST_ASSERT(max_lat != std::numeric_limits<int32_t>::min());
 | |
|         BOOST_ASSERT(max_lon != std::numeric_limits<int32_t>::min());
 | |
|     }
 | |
| 
 | |
|     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;
 | |
|     }
 | |
| 
 | |
|     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));
 | |
|     }
 | |
| 
 | |
|     double GetMinDist(const FixedPointCoordinate &location) const
 | |
|     {
 | |
|         const bool is_contained = Contains(location);
 | |
|         if (is_contained)
 | |
|         {
 | |
|             return 0.0f;
 | |
|         }
 | |
| 
 | |
|         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);
 | |
| 
 | |
|         double min_dist = std::numeric_limits<double>::max();
 | |
|         switch (d)
 | |
|         {
 | |
|         case NORTH:
 | |
|             min_dist = coordinate_calculation::greatCircleDistance(
 | |
|                 location, FixedPointCoordinate(max_lat, location.lon));
 | |
|             break;
 | |
|         case SOUTH:
 | |
|             min_dist = coordinate_calculation::greatCircleDistance(
 | |
|                 location, FixedPointCoordinate(min_lat, location.lon));
 | |
|             break;
 | |
|         case WEST:
 | |
|             min_dist = coordinate_calculation::greatCircleDistance(
 | |
|                 location, FixedPointCoordinate(location.lat, min_lon));
 | |
|             break;
 | |
|         case EAST:
 | |
|             min_dist = coordinate_calculation::greatCircleDistance(
 | |
|                 location, FixedPointCoordinate(location.lat, max_lon));
 | |
|             break;
 | |
|         case NORTH_EAST:
 | |
|             min_dist = coordinate_calculation::greatCircleDistance(
 | |
|                 location, FixedPointCoordinate(max_lat, max_lon));
 | |
|             break;
 | |
|         case NORTH_WEST:
 | |
|             min_dist = coordinate_calculation::greatCircleDistance(
 | |
|                 location, FixedPointCoordinate(max_lat, min_lon));
 | |
|             break;
 | |
|         case SOUTH_EAST:
 | |
|             min_dist = coordinate_calculation::greatCircleDistance(
 | |
|                 location, FixedPointCoordinate(min_lat, max_lon));
 | |
|             break;
 | |
|         case SOUTH_WEST:
 | |
|             min_dist = coordinate_calculation::greatCircleDistance(
 | |
|                 location, FixedPointCoordinate(min_lat, min_lon));
 | |
|             break;
 | |
|         default:
 | |
|             break;
 | |
|         }
 | |
| 
 | |
|         BOOST_ASSERT(min_dist < std::numeric_limits<double>::max());
 | |
| 
 | |
|         return min_dist;
 | |
|     }
 | |
| 
 | |
|     double GetMinMaxDist(const FixedPointCoordinate &location) const
 | |
|     {
 | |
|         double min_max_dist = std::numeric_limits<double>::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(coordinate_calculation::greatCircleDistance(location, upper_left),
 | |
|                               coordinate_calculation::greatCircleDistance(location, upper_right)));
 | |
| 
 | |
|         min_max_dist =
 | |
|             std::min(min_max_dist,
 | |
|                      std::max(coordinate_calculation::greatCircleDistance(location, upper_right),
 | |
|                               coordinate_calculation::greatCircleDistance(location, lower_right)));
 | |
| 
 | |
|         min_max_dist =
 | |
|             std::min(min_max_dist,
 | |
|                      std::max(coordinate_calculation::greatCircleDistance(location, lower_right),
 | |
|                               coordinate_calculation::greatCircleDistance(location, lower_left)));
 | |
| 
 | |
|         min_max_dist =
 | |
|             std::min(min_max_dist,
 | |
|                      std::max(coordinate_calculation::greatCircleDistance(location, lower_left),
 | |
|                               coordinate_calculation::greatCircleDistance(location, upper_left)));
 | |
|         return min_max_dist;
 | |
|     }
 | |
| 
 | |
|     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;
 | |
|     }
 | |
| };
 | |
| }
 | |
| }
 | |
| 
 | |
| #endif
 |