[geometry] buffer, extracted occupation info to separate file
[boost:cmake.git] / boost / geometry / algorithms / detail / occupation_info.hpp
1 // Boost.Geometry (aka GGL, Generic Geometry Library)
2
3 // Copyright (c) 2012 Barend Gehrels, Amsterdam, the Netherlands.
4
5 // Use, modification and distribution is subject to the Boost Software License,
6 // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
7 // http://www.boost.org/LICENSE_1_0.txt)
8
9 #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_OCCUPATION_INFO_HPP
10 #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OCCUPATION_INFO_HPP
11
12
13 #include <algorithm>
14 #include <boost/range.hpp>
15
16 #include <boost/geometry/core/coordinate_type.hpp>
17 #include <boost/geometry/core/point_type.hpp>
18
19 #include <boost/geometry/algorithms/equals.hpp>
20 #include <boost/geometry/iterators/closing_iterator.hpp>
21
22
23 namespace boost { namespace geometry
24 {
25
26
27 #ifndef DOXYGEN_NO_DETAIL
28 namespace detail
29 {
30
31 template <typename T, typename P1, typename P2>
32 inline T calculate_angle(P1 const& from_point, P2 const& to_point)
33 {
34     typedef P1 vector_type;
35     vector_type v = from_point;
36     geometry::subtract_point(v, to_point);
37     return atan2(geometry::get<1>(v), geometry::get<0>(v));
38 }
39
40 template <typename Iterator, typename Vector>
41 inline Iterator advance_circular(Iterator it, Vector const& vector, bool forward = true)
42 {
43         int const increment = forward ? 1 : -1;
44         if (it == boost::begin(vector) && increment < 0)
45         {
46                 it = boost::end(vector);
47         }
48         it += increment;
49         if (it == boost::end(vector))
50         {
51                 it = boost::begin(vector);
52         }
53         return it;
54 }
55
56 template <typename T>
57 struct angle_info
58 {
59         typedef T angle_type;
60     T angle;
61     bool incoming;
62 };
63
64 template <typename AngleInfo>
65 class occupation_info
66 {
67         typedef std::vector<AngleInfo> collection_type;
68
69         struct angle_sort
70         {
71                 inline bool operator()(AngleInfo const& left, AngleInfo const& right) const
72                 {
73                         // In this case we can compare even double using equals
74                         // return geometry::math::equals(left.angle, right.angle)
75                         return left.angle == right.angle
76                                 ? int(left.incoming) < int(right.incoming)
77                                 : left.angle < right.angle
78                                 ;
79                 }
80         };
81
82     collection_type angles;
83     bool m_occupied;
84         bool m_calculated;
85
86         inline bool is_occupied()
87         {
88                 if (boost::size(angles) <= 1)
89                 {
90                         return false;
91                 }
92
93                 std::sort(angles.begin(), angles.end(), angle_sort());
94
95                 typedef geometry::closing_iterator<collection_type const> closing_iterator;
96                 closing_iterator vit(angles);
97                 closing_iterator end(angles, true);
98
99                 closing_iterator prev = vit++;
100                 for( ; vit != end; prev = vit++)
101                 {
102                         if (! geometry::math::equals(prev->angle, vit->angle)
103                                 && ! prev->incoming
104                                 && vit->incoming)
105                         {
106                                 return false;
107                         }
108                 }
109                 return true;
110         }
111
112 public :
113     inline occupation_info()
114         : m_occupied(false)
115                 , m_calculated(false)
116     {}
117
118         template <typename Point1, typename Point2>
119         inline void add(Point1 const& point1, Point2 const& point2, bool incoming)
120         {
121         AngleInfo info;
122         info.incoming = incoming;
123         info.angle = calculate_angle<typename AngleInfo::angle_type>(point1, point2);
124         angles.push_back(info);
125
126                 m_calculated = false;
127         }
128
129         inline bool occupied()
130         {
131                 if (! m_calculated)
132                 {
133                         m_occupied = is_occupied();
134                         m_calculated = true;
135                 }
136                 return m_occupied;
137         }
138
139 };
140
141
142 template <typename Point, typename Ring, typename Info>
143 inline void add_incoming_and_outgoing_angles(Point const& point,
144                                 Ring const& ring, int segment_index,
145                 Info& info)
146 {
147     typedef typename boost::range_iterator
148         <
149             Ring const
150         >::type iterator_type;
151
152         int const n = boost::size(ring);
153         if (segment_index >= n || segment_index < 0)
154         {
155                 return;
156         }
157
158         iterator_type it = boost::begin(ring) + segment_index;
159
160     if (geometry::equals(point, *it))
161     {
162                 it = advance_circular(it, ring, false);
163     }
164
165         info.add(*it, point, true);
166
167         it = advance_circular(it, ring);
168     for (int defensive_check = 0; 
169                 geometry::equals(point, *it) && defensive_check < n; 
170                 defensive_check++)
171     {
172                 it = advance_circular(it, ring);
173     }
174
175         info.add(*it, point, false);
176 }
177
178
179 // Map in two senses of the word: it is a std::map where the key is a point.
180 // Per point an "occupation_info" record is kept
181 // Used for the buffer (but will also be used for intersections/unions having complex self-tangencies)
182 template <typename Point, typename OccupationInfo>
183 class occupation_map
184 {
185 public :
186     typedef std::map<Point, OccupationInfo, geometry::less<Point> > map_type;
187     map_type map;
188
189     OccupationInfo& find_or_insert(Point point)
190     {
191         typename map_type::iterator it = map.find(point);
192         if (it == boost::end(map))
193         {
194             std::pair<typename map_type::iterator, bool> pair 
195                         = map.insert(std::make_pair(point, OccupationInfo()));
196             it = pair.first;
197         }
198
199         return it->second;
200     }
201
202 };
203
204
205 } // namespace detail
206 #endif // DOXYGEN_NO_DETAIL
207
208
209 }} // namespace boost::geometry
210
211 #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_OCCUPATION_INFO_HPP