occupation_info.hpp 9.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329
  1. // Boost.Geometry (aka GGL, Generic Geometry Library)
  2. // Copyright (c) 2012 Barend Gehrels, Amsterdam, the Netherlands.
  3. // Use, modification and distribution is subject to the Boost Software License,
  4. // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
  5. // http://www.boost.org/LICENSE_1_0.txt)
  6. #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_OCCUPATION_INFO_HPP
  7. #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OCCUPATION_INFO_HPP
  8. #if ! defined(NDEBUG)
  9. // #define BOOST_GEOMETRY_DEBUG_BUFFER_OCCUPATION
  10. #endif
  11. #include <algorithm>
  12. #include <boost/range.hpp>
  13. #include <boost/geometry/core/coordinate_type.hpp>
  14. #include <boost/geometry/core/point_type.hpp>
  15. #include <boost/geometry/algorithms/equals.hpp>
  16. #include <boost/geometry/iterators/closing_iterator.hpp>
  17. #include <boost/geometry/algorithms/detail/get_left_turns.hpp>
  18. namespace boost { namespace geometry
  19. {
  20. #ifndef DOXYGEN_NO_DETAIL
  21. namespace detail
  22. {
  23. template <typename P>
  24. class relaxed_less
  25. {
  26. typedef typename geometry::coordinate_type<P>::type coordinate_type;
  27. coordinate_type epsilon;
  28. public :
  29. inline relaxed_less()
  30. {
  31. // TODO: adapt for ttmath, and maybe build the map in another way
  32. // (e.g. exact constellations of segment-id's), maybe adaptive.
  33. epsilon = std::numeric_limits<double>::epsilon() * 100.0;
  34. }
  35. inline bool operator()(P const& a, P const& b) const
  36. {
  37. coordinate_type const dx = math::abs(geometry::get<0>(a) - geometry::get<0>(b));
  38. coordinate_type const dy = math::abs(geometry::get<1>(a) - geometry::get<1>(b));
  39. if (dx < epsilon && dy < epsilon)
  40. {
  41. return false;
  42. }
  43. if (dx < epsilon)
  44. {
  45. return geometry::get<1>(a) < geometry::get<1>(b);
  46. }
  47. return geometry::get<0>(a) < geometry::get<0>(b);
  48. }
  49. inline bool equals(P const& a, P const& b) const
  50. {
  51. typedef typename geometry::coordinate_type<P>::type coordinate_type;
  52. coordinate_type const dx = math::abs(geometry::get<0>(a) - geometry::get<0>(b));
  53. coordinate_type const dy = math::abs(geometry::get<1>(a) - geometry::get<1>(b));
  54. return dx < epsilon && dy < epsilon;
  55. };
  56. };
  57. template <typename T, typename P1, typename P2>
  58. inline T calculate_angle(P1 const& from_point, P2 const& to_point)
  59. {
  60. typedef P1 vector_type;
  61. vector_type v = from_point;
  62. geometry::subtract_point(v, to_point);
  63. return atan2(geometry::get<1>(v), geometry::get<0>(v));
  64. }
  65. template <typename Iterator, typename Vector>
  66. inline Iterator advance_circular(Iterator it, Vector const& vector, segment_identifier& seg_id, bool forward = true)
  67. {
  68. int const increment = forward ? 1 : -1;
  69. if (it == boost::begin(vector) && increment < 0)
  70. {
  71. it = boost::end(vector);
  72. seg_id.segment_index = boost::size(vector);
  73. }
  74. it += increment;
  75. seg_id.segment_index += increment;
  76. if (it == boost::end(vector))
  77. {
  78. seg_id.segment_index = 0;
  79. it = boost::begin(vector);
  80. }
  81. return it;
  82. }
  83. template <typename Point, typename T>
  84. struct angle_info
  85. {
  86. typedef T angle_type;
  87. typedef Point point_type;
  88. segment_identifier seg_id;
  89. int turn_index;
  90. int operation_index;
  91. Point intersection_point;
  92. Point direction_point;
  93. T angle;
  94. bool incoming;
  95. };
  96. template <typename AngleInfo>
  97. class occupation_info
  98. {
  99. typedef std::vector<AngleInfo> collection_type;
  100. struct angle_sort
  101. {
  102. inline bool operator()(AngleInfo const& left, AngleInfo const& right) const
  103. {
  104. // In this case we can compare even double using equals
  105. // return geometry::math::equals(left.angle, right.angle)
  106. return left.angle == right.angle
  107. ? int(left.incoming) < int(right.incoming)
  108. : left.angle < right.angle
  109. ;
  110. }
  111. };
  112. public :
  113. collection_type angles;
  114. private :
  115. bool m_occupied;
  116. bool m_calculated;
  117. inline bool is_occupied()
  118. {
  119. if (boost::size(angles) <= 1)
  120. {
  121. return false;
  122. }
  123. std::sort(angles.begin(), angles.end(), angle_sort());
  124. typedef geometry::closing_iterator<collection_type const> closing_iterator;
  125. closing_iterator vit(angles);
  126. closing_iterator end(angles, true);
  127. closing_iterator prev = vit++;
  128. for( ; vit != end; prev = vit++)
  129. {
  130. if (! geometry::math::equals(prev->angle, vit->angle)
  131. && ! prev->incoming
  132. && vit->incoming)
  133. {
  134. return false;
  135. }
  136. }
  137. return true;
  138. }
  139. public :
  140. inline occupation_info()
  141. : m_occupied(false)
  142. , m_calculated(false)
  143. {}
  144. template <typename PointC, typename Point1, typename Point2>
  145. inline void add(PointC const& map_point, Point1 const& direction_point, Point2 const& intersection_point,
  146. int turn_index, int operation_index,
  147. segment_identifier const& seg_id, bool incoming)
  148. {
  149. //std::cout << "-> adding angle " << geometry::wkt(direction_point) << " .. " << geometry::wkt(intersection_point) << " " << int(incoming) << std::endl;
  150. if (geometry::equals(direction_point, intersection_point))
  151. {
  152. //std::cout << "EQUAL! Skipping" << std::endl;
  153. return;
  154. }
  155. AngleInfo info;
  156. info.incoming = incoming;
  157. info.angle = calculate_angle<typename AngleInfo::angle_type>(direction_point, map_point);
  158. info.seg_id = seg_id;
  159. info.turn_index = turn_index;
  160. info.operation_index = operation_index;
  161. info.intersection_point = intersection_point;
  162. info.direction_point = direction_point;
  163. angles.push_back(info);
  164. m_calculated = false;
  165. }
  166. inline bool occupied()
  167. {
  168. if (! m_calculated)
  169. {
  170. m_occupied = is_occupied();
  171. m_calculated = true;
  172. }
  173. return m_occupied;
  174. }
  175. template <typename Turns, typename TurnSegmentIndices>
  176. inline void get_left_turns(
  177. Turns& turns, TurnSegmentIndices const& turn_segment_indices,
  178. std::set<int>& keep_indices)
  179. {
  180. std::sort(angles.begin(), angles.end(), angle_sort());
  181. calculate_left_turns<AngleInfo>(angles, turns, turn_segment_indices, keep_indices);
  182. }
  183. };
  184. template <typename Point, typename Ring, typename Info>
  185. inline void add_incoming_and_outgoing_angles(Point const& map_point, Point const& intersection_point,
  186. Ring const& ring,
  187. int turn_index,
  188. int operation_index,
  189. segment_identifier seg_id,
  190. Info& info)
  191. {
  192. typedef typename boost::range_iterator
  193. <
  194. Ring const
  195. >::type iterator_type;
  196. int const n = boost::size(ring);
  197. if (seg_id.segment_index >= n || seg_id.segment_index < 0)
  198. {
  199. return;
  200. }
  201. segment_identifier real_seg_id = seg_id;
  202. iterator_type it = boost::begin(ring) + seg_id.segment_index;
  203. // TODO: if we use turn-info ("to", "middle"), we know if to advance without resorting to equals
  204. relaxed_less<Point> comparator;
  205. if (comparator.equals(intersection_point, *it))
  206. {
  207. // It should be equal only once. But otherwise we skip it (in "add")
  208. it = advance_circular(it, ring, seg_id, false);
  209. }
  210. info.add(map_point, *it, intersection_point, turn_index, operation_index, real_seg_id, true);
  211. if (comparator.equals(intersection_point, *it))
  212. {
  213. it = advance_circular(it, ring, real_seg_id);
  214. }
  215. else
  216. {
  217. // Don't upgrade the ID
  218. it = advance_circular(it, ring, seg_id);
  219. }
  220. for (int defensive_check = 0;
  221. comparator.equals(intersection_point, *it) && defensive_check < n;
  222. defensive_check++)
  223. {
  224. it = advance_circular(it, ring, real_seg_id);
  225. }
  226. info.add(map_point, *it, intersection_point, turn_index, operation_index, real_seg_id, false);
  227. }
  228. // Map in two senses of the word: it is a std::map where the key is a point.
  229. // Per point an "occupation_info" record is kept
  230. // Used for the buffer (but will also be used for intersections/unions having complex self-tangencies)
  231. template <typename Point, typename OccupationInfo>
  232. class occupation_map
  233. {
  234. public :
  235. typedef std::map<Point, OccupationInfo, relaxed_less<Point> > map_type;
  236. map_type map;
  237. std::set<int> turn_indices;
  238. inline OccupationInfo& find_or_insert(Point const& point, Point& mapped_point)
  239. {
  240. typename map_type::iterator it = map.find(point);
  241. if (it == boost::end(map))
  242. {
  243. std::pair<typename map_type::iterator, bool> pair
  244. = map.insert(std::make_pair(point, OccupationInfo()));
  245. it = pair.first;
  246. }
  247. mapped_point = it->first;
  248. return it->second;
  249. }
  250. inline bool contains(Point const& point) const
  251. {
  252. typename map_type::const_iterator it = map.find(point);
  253. return it != boost::end(map);
  254. }
  255. inline bool contains_turn_index(int index) const
  256. {
  257. return turn_indices.count(index) > 0;
  258. }
  259. inline void insert_turn_index(int index)
  260. {
  261. turn_indices.insert(index);
  262. }
  263. };
  264. } // namespace detail
  265. #endif // DOXYGEN_NO_DETAIL
  266. }} // namespace boost::geometry
  267. #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_OCCUPATION_INFO_HPP