Chris@16
|
1 /*
|
Chris@16
|
2 Copyright 2008 Intel Corporation
|
Chris@16
|
3
|
Chris@16
|
4 Use, modification and distribution are subject to the Boost Software License,
|
Chris@16
|
5 Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
|
Chris@16
|
6 http://www.boost.org/LICENSE_1_0.txt).
|
Chris@16
|
7 */
|
Chris@16
|
8 #ifndef BOOST_POLYGON_POLYGON_45_SET_DATA_HPP
|
Chris@16
|
9 #define BOOST_POLYGON_POLYGON_45_SET_DATA_HPP
|
Chris@16
|
10 #include "polygon_90_set_data.hpp"
|
Chris@16
|
11 #include "detail/boolean_op_45.hpp"
|
Chris@16
|
12 #include "detail/polygon_45_formation.hpp"
|
Chris@16
|
13 #include "detail/polygon_45_touch.hpp"
|
Chris@16
|
14 #include "detail/property_merge_45.hpp"
|
Chris@16
|
15 namespace boost { namespace polygon{
|
Chris@16
|
16
|
Chris@16
|
17 enum RoundingOption { CLOSEST = 0, OVERSIZE = 1, UNDERSIZE = 2, SQRT2 = 3, SQRT1OVER2 = 4 };
|
Chris@16
|
18 enum CornerOption { INTERSECTION = 0, ORTHOGONAL = 1, UNFILLED = 2 };
|
Chris@16
|
19
|
Chris@16
|
20 template <typename ltype, typename rtype, int op_type>
|
Chris@16
|
21 class polygon_45_set_view;
|
Chris@16
|
22
|
Chris@16
|
23 struct polygon_45_set_concept {};
|
Chris@16
|
24
|
Chris@16
|
25 template <typename Unit>
|
Chris@16
|
26 class polygon_45_set_data {
|
Chris@16
|
27 public:
|
Chris@16
|
28 typedef typename polygon_45_formation<Unit>::Vertex45Compact Vertex45Compact;
|
Chris@16
|
29 typedef std::vector<Vertex45Compact> Polygon45VertexData;
|
Chris@16
|
30
|
Chris@16
|
31 typedef Unit coordinate_type;
|
Chris@16
|
32 typedef Polygon45VertexData value_type;
|
Chris@16
|
33 typedef typename value_type::const_iterator iterator_type;
|
Chris@16
|
34 typedef polygon_45_set_data operator_arg_type;
|
Chris@16
|
35
|
Chris@16
|
36 // default constructor
|
Chris@16
|
37 inline polygon_45_set_data() : error_data_(), data_(), dirty_(false), unsorted_(false), is_manhattan_(true) {}
|
Chris@16
|
38
|
Chris@16
|
39 // constructor from a geometry object
|
Chris@16
|
40 template <typename geometry_type>
|
Chris@16
|
41 inline polygon_45_set_data(const geometry_type& that) : error_data_(), data_(), dirty_(false), unsorted_(false), is_manhattan_(true) {
|
Chris@16
|
42 insert(that);
|
Chris@16
|
43 }
|
Chris@16
|
44
|
Chris@16
|
45 // copy constructor
|
Chris@16
|
46 inline polygon_45_set_data(const polygon_45_set_data& that) :
|
Chris@16
|
47 error_data_(that.error_data_), data_(that.data_), dirty_(that.dirty_),
|
Chris@16
|
48 unsorted_(that.unsorted_), is_manhattan_(that.is_manhattan_) {}
|
Chris@16
|
49
|
Chris@16
|
50 template <typename ltype, typename rtype, int op_type>
|
Chris@16
|
51 inline polygon_45_set_data(const polygon_45_set_view<ltype, rtype, op_type>& that) :
|
Chris@16
|
52 error_data_(), data_(), dirty_(false), unsorted_(false), is_manhattan_(true) {
|
Chris@16
|
53 (*this) = that.value();
|
Chris@16
|
54 }
|
Chris@16
|
55
|
Chris@16
|
56 // destructor
|
Chris@16
|
57 inline ~polygon_45_set_data() {}
|
Chris@16
|
58
|
Chris@16
|
59 // assignement operator
|
Chris@16
|
60 inline polygon_45_set_data& operator=(const polygon_45_set_data& that) {
|
Chris@16
|
61 if(this == &that) return *this;
|
Chris@16
|
62 error_data_ = that.error_data_;
|
Chris@16
|
63 data_ = that.data_;
|
Chris@16
|
64 dirty_ = that.dirty_;
|
Chris@16
|
65 unsorted_ = that.unsorted_;
|
Chris@16
|
66 is_manhattan_ = that.is_manhattan_;
|
Chris@16
|
67 return *this;
|
Chris@16
|
68 }
|
Chris@16
|
69
|
Chris@16
|
70 template <typename ltype, typename rtype, int op_type>
|
Chris@16
|
71 inline polygon_45_set_data& operator=(const polygon_45_set_view<ltype, rtype, op_type>& that) {
|
Chris@16
|
72 (*this) = that.value();
|
Chris@16
|
73 return *this;
|
Chris@16
|
74 }
|
Chris@16
|
75
|
Chris@16
|
76 template <typename geometry_object>
|
Chris@16
|
77 inline polygon_45_set_data& operator=(const geometry_object& geometry) {
|
Chris@16
|
78 data_.clear();
|
Chris@16
|
79 insert(geometry);
|
Chris@16
|
80 return *this;
|
Chris@16
|
81 }
|
Chris@16
|
82
|
Chris@16
|
83 // insert iterator range
|
Chris@16
|
84 inline void insert(iterator_type input_begin, iterator_type input_end, bool is_hole = false) {
|
Chris@16
|
85 if(input_begin == input_end || (!data_.empty() && &(*input_begin) == &(*(data_.begin())))) return;
|
Chris@16
|
86 dirty_ = true;
|
Chris@16
|
87 unsorted_ = true;
|
Chris@16
|
88 while(input_begin != input_end) {
|
Chris@16
|
89 insert(*input_begin, is_hole);
|
Chris@16
|
90 ++input_begin;
|
Chris@16
|
91 }
|
Chris@16
|
92 }
|
Chris@16
|
93
|
Chris@16
|
94 // insert iterator range
|
Chris@16
|
95 template <typename iT>
|
Chris@16
|
96 inline void insert(iT input_begin, iT input_end, bool is_hole = false) {
|
Chris@16
|
97 if(input_begin == input_end) return;
|
Chris@16
|
98 dirty_ = true;
|
Chris@16
|
99 unsorted_ = true;
|
Chris@16
|
100 while(input_begin != input_end) {
|
Chris@16
|
101 insert(*input_begin, is_hole);
|
Chris@16
|
102 ++input_begin;
|
Chris@16
|
103 }
|
Chris@16
|
104 }
|
Chris@16
|
105
|
Chris@16
|
106 inline void insert(const polygon_45_set_data& polygon_set, bool is_hole = false);
|
Chris@16
|
107 template <typename coord_type>
|
Chris@16
|
108 inline void insert(const polygon_45_set_data<coord_type>& polygon_set, bool is_hole = false);
|
Chris@16
|
109
|
Chris@16
|
110 template <typename geometry_type>
|
Chris@16
|
111 inline void insert(const geometry_type& geometry_object, bool is_hole = false) {
|
Chris@16
|
112 insert_dispatch(geometry_object, is_hole, typename geometry_concept<geometry_type>::type());
|
Chris@16
|
113 }
|
Chris@16
|
114
|
Chris@16
|
115 inline void insert_clean(const Vertex45Compact& vertex_45, bool is_hole = false) {
|
Chris@16
|
116 if(vertex_45.count.is_45()) is_manhattan_ = false;
|
Chris@16
|
117 data_.push_back(vertex_45);
|
Chris@16
|
118 if(is_hole) data_.back().count.invert();
|
Chris@16
|
119 }
|
Chris@16
|
120
|
Chris@16
|
121 inline void insert(const Vertex45Compact& vertex_45, bool is_hole = false) {
|
Chris@16
|
122 dirty_ = true;
|
Chris@16
|
123 unsorted_ = true;
|
Chris@16
|
124 insert_clean(vertex_45, is_hole);
|
Chris@16
|
125 }
|
Chris@16
|
126
|
Chris@16
|
127 template <typename coordinate_type_2>
|
Chris@16
|
128 inline void insert(const polygon_90_set_data<coordinate_type_2>& polygon_set, bool is_hole = false) {
|
Chris@16
|
129 if(polygon_set.orient() == VERTICAL) {
|
Chris@16
|
130 for(typename polygon_90_set_data<coordinate_type_2>::iterator_type itr = polygon_set.begin();
|
Chris@16
|
131 itr != polygon_set.end(); ++itr) {
|
Chris@16
|
132 Vertex45Compact vertex_45(point_data<Unit>((*itr).first, (*itr).second.first), 2, (*itr).second.second);
|
Chris@16
|
133 vertex_45.count[1] = (*itr).second.second;
|
Chris@16
|
134 if(is_hole) vertex_45.count[1] *= - 1;
|
Chris@16
|
135 insert_clean(vertex_45, is_hole);
|
Chris@16
|
136 }
|
Chris@16
|
137 } else {
|
Chris@16
|
138 for(typename polygon_90_set_data<coordinate_type_2>::iterator_type itr = polygon_set.begin();
|
Chris@16
|
139 itr != polygon_set.end(); ++itr) {
|
Chris@16
|
140 Vertex45Compact vertex_45(point_data<Unit>((*itr).second.first, (*itr).first), 2, (*itr).second.second);
|
Chris@16
|
141 vertex_45.count[1] = (*itr).second.second;
|
Chris@16
|
142 if(is_hole) vertex_45.count[1] *= - 1;
|
Chris@16
|
143 insert_clean(vertex_45, is_hole);
|
Chris@16
|
144 }
|
Chris@16
|
145 }
|
Chris@16
|
146 dirty_ = true;
|
Chris@16
|
147 unsorted_ = true;
|
Chris@16
|
148 }
|
Chris@16
|
149
|
Chris@16
|
150 template <typename output_container>
|
Chris@16
|
151 inline void get(output_container& output) const {
|
Chris@16
|
152 get_dispatch(output, typename geometry_concept<typename output_container::value_type>::type());
|
Chris@16
|
153 }
|
Chris@16
|
154
|
Chris@16
|
155 inline bool has_error_data() const { return !error_data_.empty(); }
|
Chris@16
|
156 inline std::size_t error_count() const { return error_data_.size() / 4; }
|
Chris@16
|
157 inline void get_error_data(polygon_45_set_data& p) const {
|
Chris@16
|
158 p.data_.insert(p.data_.end(), error_data_.begin(), error_data_.end());
|
Chris@16
|
159 }
|
Chris@16
|
160
|
Chris@16
|
161 // equivalence operator
|
Chris@16
|
162 inline bool operator==(const polygon_45_set_data& p) const {
|
Chris@16
|
163 clean();
|
Chris@16
|
164 p.clean();
|
Chris@16
|
165 return data_ == p.data_;
|
Chris@16
|
166 }
|
Chris@16
|
167
|
Chris@16
|
168 // inequivalence operator
|
Chris@16
|
169 inline bool operator!=(const polygon_45_set_data& p) const {
|
Chris@16
|
170 return !((*this) == p);
|
Chris@16
|
171 }
|
Chris@16
|
172
|
Chris@16
|
173 // get iterator to begin vertex data
|
Chris@16
|
174 inline iterator_type begin() const {
|
Chris@16
|
175 return data_.begin();
|
Chris@16
|
176 }
|
Chris@16
|
177
|
Chris@16
|
178 // get iterator to end vertex data
|
Chris@16
|
179 inline iterator_type end() const {
|
Chris@16
|
180 return data_.end();
|
Chris@16
|
181 }
|
Chris@16
|
182
|
Chris@16
|
183 const value_type& value() const {
|
Chris@16
|
184 return data_;
|
Chris@16
|
185 }
|
Chris@16
|
186
|
Chris@16
|
187 // clear the contents of the polygon_45_set_data
|
Chris@16
|
188 inline void clear() { data_.clear(); error_data_.clear(); dirty_ = unsorted_ = false; is_manhattan_ = true; }
|
Chris@16
|
189
|
Chris@16
|
190 // find out if Polygon set is empty
|
Chris@16
|
191 inline bool empty() const { return data_.empty(); }
|
Chris@16
|
192
|
Chris@16
|
193 // get the Polygon set size in vertices
|
Chris@16
|
194 inline std::size_t size() const { clean(); return data_.size(); }
|
Chris@16
|
195
|
Chris@16
|
196 // get the current Polygon set capacity in vertices
|
Chris@16
|
197 inline std::size_t capacity() const { return data_.capacity(); }
|
Chris@16
|
198
|
Chris@16
|
199 // reserve size of polygon set in vertices
|
Chris@16
|
200 inline void reserve(std::size_t size) { return data_.reserve(size); }
|
Chris@16
|
201
|
Chris@16
|
202 // find out if Polygon set is sorted
|
Chris@16
|
203 inline bool sorted() const { return !unsorted_; }
|
Chris@16
|
204
|
Chris@16
|
205 // find out if Polygon set is clean
|
Chris@16
|
206 inline bool dirty() const { return dirty_; }
|
Chris@16
|
207
|
Chris@16
|
208 // find out if Polygon set is clean
|
Chris@16
|
209 inline bool is_manhattan() const { return is_manhattan_; }
|
Chris@16
|
210
|
Chris@16
|
211 bool clean() const;
|
Chris@16
|
212
|
Chris@16
|
213 void sort() const{
|
Chris@16
|
214 if(unsorted_) {
|
Chris@16
|
215 polygon_sort(data_.begin(), data_.end());
|
Chris@16
|
216 unsorted_ = false;
|
Chris@16
|
217 }
|
Chris@16
|
218 }
|
Chris@16
|
219
|
Chris@16
|
220 template <typename input_iterator_type>
|
Chris@16
|
221 void set(input_iterator_type input_begin, input_iterator_type input_end) {
|
Chris@16
|
222 data_.clear();
|
Chris@16
|
223 reserve(std::distance(input_begin, input_end));
|
Chris@16
|
224 insert(input_begin, input_end);
|
Chris@16
|
225 dirty_ = true;
|
Chris@16
|
226 unsorted_ = true;
|
Chris@16
|
227 }
|
Chris@16
|
228
|
Chris@16
|
229 void set_clean(const value_type& value) {
|
Chris@16
|
230 data_ = value;
|
Chris@16
|
231 dirty_ = false;
|
Chris@16
|
232 unsorted_ = false;
|
Chris@16
|
233 }
|
Chris@16
|
234
|
Chris@16
|
235 void set(const value_type& value) {
|
Chris@16
|
236 data_ = value;
|
Chris@16
|
237 dirty_ = true;
|
Chris@16
|
238 unsorted_ = true;
|
Chris@16
|
239 }
|
Chris@16
|
240
|
Chris@16
|
241 // append to the container cT with polygons (holes will be fractured vertically)
|
Chris@16
|
242 template <class cT>
|
Chris@16
|
243 void get_polygons(cT& container) const {
|
Chris@16
|
244 get_dispatch(container, polygon_45_concept());
|
Chris@16
|
245 }
|
Chris@16
|
246
|
Chris@16
|
247 // append to the container cT with PolygonWithHoles objects
|
Chris@16
|
248 template <class cT>
|
Chris@16
|
249 void get_polygons_with_holes(cT& container) const {
|
Chris@16
|
250 get_dispatch(container, polygon_45_with_holes_concept());
|
Chris@16
|
251 }
|
Chris@16
|
252
|
Chris@16
|
253 // append to the container cT with polygons of three or four verticies
|
Chris@16
|
254 // slicing orientation is vertical
|
Chris@16
|
255 template <class cT>
|
Chris@16
|
256 void get_trapezoids(cT& container) const {
|
Chris@16
|
257 clean();
|
Chris@16
|
258 typename polygon_45_formation<Unit>::Polygon45Tiling pf;
|
Chris@16
|
259 //std::cout << "FORMING POLYGONS\n";
|
Chris@16
|
260 pf.scan(container, data_.begin(), data_.end());
|
Chris@16
|
261 //std::cout << "DONE FORMING POLYGONS\n";
|
Chris@16
|
262 }
|
Chris@16
|
263
|
Chris@16
|
264 // append to the container cT with polygons of three or four verticies
|
Chris@16
|
265 template <class cT>
|
Chris@16
|
266 void get_trapezoids(cT& container, orientation_2d slicing_orientation) const {
|
Chris@16
|
267 if(slicing_orientation == VERTICAL) {
|
Chris@16
|
268 get_trapezoids(container);
|
Chris@16
|
269 } else {
|
Chris@16
|
270 polygon_45_set_data<Unit> ps(*this);
|
Chris@16
|
271 ps.transform(axis_transformation(axis_transformation::SWAP_XY));
|
Chris@16
|
272 cT result;
|
Chris@16
|
273 ps.get_trapezoids(result);
|
Chris@16
|
274 for(typename cT::iterator itr = result.begin(); itr != result.end(); ++itr) {
|
Chris@16
|
275 ::boost::polygon::transform(*itr, axis_transformation(axis_transformation::SWAP_XY));
|
Chris@16
|
276 }
|
Chris@16
|
277 container.insert(container.end(), result.begin(), result.end());
|
Chris@16
|
278 }
|
Chris@16
|
279 }
|
Chris@16
|
280
|
Chris@16
|
281 // insert vertex sequence
|
Chris@16
|
282 template <class iT>
|
Chris@16
|
283 void insert_vertex_sequence(iT begin_vertex, iT end_vertex,
|
Chris@16
|
284 direction_1d winding, bool is_hole = false);
|
Chris@16
|
285
|
Chris@16
|
286 // get the external boundary rectangle
|
Chris@16
|
287 template <typename rectangle_type>
|
Chris@16
|
288 bool extents(rectangle_type& rect) const;
|
Chris@16
|
289
|
Chris@16
|
290 // snap verticies of set to even,even or odd,odd coordinates
|
Chris@16
|
291 void snap() const;
|
Chris@16
|
292
|
Chris@16
|
293 // |= &= += *= -= ^= binary operators
|
Chris@16
|
294 polygon_45_set_data& operator|=(const polygon_45_set_data& b);
|
Chris@16
|
295 polygon_45_set_data& operator&=(const polygon_45_set_data& b);
|
Chris@16
|
296 polygon_45_set_data& operator+=(const polygon_45_set_data& b);
|
Chris@16
|
297 polygon_45_set_data& operator*=(const polygon_45_set_data& b);
|
Chris@16
|
298 polygon_45_set_data& operator-=(const polygon_45_set_data& b);
|
Chris@16
|
299 polygon_45_set_data& operator^=(const polygon_45_set_data& b);
|
Chris@16
|
300
|
Chris@16
|
301 // resizing operations
|
Chris@16
|
302 polygon_45_set_data& operator+=(Unit delta);
|
Chris@16
|
303 polygon_45_set_data& operator-=(Unit delta);
|
Chris@16
|
304
|
Chris@16
|
305 // shrink the Polygon45Set by shrinking
|
Chris@16
|
306 polygon_45_set_data& resize(coordinate_type resizing, RoundingOption rounding = CLOSEST,
|
Chris@16
|
307 CornerOption corner = INTERSECTION);
|
Chris@16
|
308
|
Chris@16
|
309 // transform set
|
Chris@16
|
310 template <typename transformation_type>
|
Chris@16
|
311 polygon_45_set_data& transform(const transformation_type& tr);
|
Chris@16
|
312
|
Chris@16
|
313 // scale set
|
Chris@16
|
314 polygon_45_set_data& scale_up(typename coordinate_traits<Unit>::unsigned_area_type factor);
|
Chris@16
|
315 polygon_45_set_data& scale_down(typename coordinate_traits<Unit>::unsigned_area_type factor);
|
Chris@16
|
316 polygon_45_set_data& scale(double scaling);
|
Chris@16
|
317
|
Chris@16
|
318 // self_intersect
|
Chris@16
|
319 polygon_45_set_data& self_intersect() {
|
Chris@16
|
320 sort();
|
Chris@16
|
321 applyAdaptiveUnary_<1>(); //1 = AND
|
Chris@16
|
322 dirty_ = false;
|
Chris@16
|
323 return *this;
|
Chris@16
|
324 }
|
Chris@16
|
325
|
Chris@16
|
326 // self_xor
|
Chris@16
|
327 polygon_45_set_data& self_xor() {
|
Chris@16
|
328 sort();
|
Chris@16
|
329 applyAdaptiveUnary_<3>(); //3 = XOR
|
Chris@16
|
330 dirty_ = false;
|
Chris@16
|
331 return *this;
|
Chris@16
|
332 }
|
Chris@16
|
333
|
Chris@16
|
334 // accumulate the bloated polygon
|
Chris@16
|
335 template <typename geometry_type>
|
Chris@16
|
336 polygon_45_set_data& insert_with_resize(const geometry_type& poly,
|
Chris@16
|
337 coordinate_type resizing, RoundingOption rounding = CLOSEST,
|
Chris@16
|
338 CornerOption corner = INTERSECTION,
|
Chris@16
|
339 bool hole = false) {
|
Chris@16
|
340 return insert_with_resize_dispatch(poly, resizing, rounding, corner, hole, typename geometry_concept<geometry_type>::type());
|
Chris@16
|
341 }
|
Chris@16
|
342
|
Chris@16
|
343 private:
|
Chris@16
|
344 mutable value_type error_data_;
|
Chris@16
|
345 mutable value_type data_;
|
Chris@16
|
346 mutable bool dirty_;
|
Chris@16
|
347 mutable bool unsorted_;
|
Chris@16
|
348 mutable bool is_manhattan_;
|
Chris@16
|
349
|
Chris@16
|
350 private:
|
Chris@16
|
351 //functions
|
Chris@16
|
352 template <typename output_container>
|
Chris@16
|
353 void get_dispatch(output_container& output, polygon_45_concept tag) const {
|
Chris@16
|
354 get_fracture(output, true, tag);
|
Chris@16
|
355 }
|
Chris@16
|
356 template <typename output_container>
|
Chris@16
|
357 void get_dispatch(output_container& output, polygon_45_with_holes_concept tag) const {
|
Chris@16
|
358 get_fracture(output, false, tag);
|
Chris@16
|
359 }
|
Chris@16
|
360 template <typename output_container>
|
Chris@16
|
361 void get_dispatch(output_container& output, polygon_concept tag) const {
|
Chris@16
|
362 get_fracture(output, true, tag);
|
Chris@16
|
363 }
|
Chris@16
|
364 template <typename output_container>
|
Chris@16
|
365 void get_dispatch(output_container& output, polygon_with_holes_concept tag) const {
|
Chris@16
|
366 get_fracture(output, false, tag);
|
Chris@16
|
367 }
|
Chris@16
|
368 template <typename output_container, typename concept_type>
|
Chris@16
|
369 void get_fracture(output_container& container, bool fracture_holes, concept_type ) const {
|
Chris@16
|
370 clean();
|
Chris@16
|
371 typename polygon_45_formation<Unit>::Polygon45Formation pf(fracture_holes);
|
Chris@16
|
372 //std::cout << "FORMING POLYGONS\n";
|
Chris@16
|
373 pf.scan(container, data_.begin(), data_.end());
|
Chris@16
|
374 }
|
Chris@16
|
375
|
Chris@16
|
376 template <typename geometry_type>
|
Chris@16
|
377 void insert_dispatch(const geometry_type& geometry_object, bool is_hole, undefined_concept) {
|
Chris@16
|
378 insert(geometry_object.begin(), geometry_object.end(), is_hole);
|
Chris@16
|
379 }
|
Chris@16
|
380 template <typename geometry_type>
|
Chris@16
|
381 void insert_dispatch(const geometry_type& geometry_object, bool is_hole, rectangle_concept tag);
|
Chris@16
|
382 template <typename geometry_type>
|
Chris@16
|
383 void insert_dispatch(const geometry_type& geometry_object, bool is_hole, polygon_90_concept ) {
|
Chris@16
|
384 insert_vertex_sequence(begin_points(geometry_object), end_points(geometry_object), winding(geometry_object), is_hole);
|
Chris@16
|
385 }
|
Chris@16
|
386 template <typename geometry_type>
|
Chris@16
|
387 void insert_dispatch(const geometry_type& geometry_object, bool is_hole, polygon_90_with_holes_concept ) {
|
Chris@16
|
388 insert_vertex_sequence(begin_points(geometry_object), end_points(geometry_object), winding(geometry_object), is_hole);
|
Chris@16
|
389 for(typename polygon_with_holes_traits<geometry_type>::iterator_holes_type itr =
|
Chris@16
|
390 begin_holes(geometry_object); itr != end_holes(geometry_object);
|
Chris@16
|
391 ++itr) {
|
Chris@16
|
392 insert_vertex_sequence(begin_points(*itr), end_points(*itr), winding(*itr), !is_hole);
|
Chris@16
|
393 }
|
Chris@16
|
394 }
|
Chris@16
|
395 template <typename geometry_type>
|
Chris@16
|
396 void insert_dispatch(const geometry_type& geometry_object, bool is_hole, polygon_45_concept ) {
|
Chris@16
|
397 insert_vertex_sequence(begin_points(geometry_object), end_points(geometry_object), winding(geometry_object), is_hole);
|
Chris@16
|
398 }
|
Chris@16
|
399 template <typename geometry_type>
|
Chris@16
|
400 void insert_dispatch(const geometry_type& geometry_object, bool is_hole, polygon_45_with_holes_concept ) {
|
Chris@16
|
401 insert_vertex_sequence(begin_points(geometry_object), end_points(geometry_object), winding(geometry_object), is_hole);
|
Chris@16
|
402 for(typename polygon_with_holes_traits<geometry_type>::iterator_holes_type itr =
|
Chris@16
|
403 begin_holes(geometry_object); itr != end_holes(geometry_object);
|
Chris@16
|
404 ++itr) {
|
Chris@16
|
405 insert_vertex_sequence(begin_points(*itr), end_points(*itr), winding(*itr), !is_hole);
|
Chris@16
|
406 }
|
Chris@16
|
407 }
|
Chris@16
|
408 template <typename geometry_type>
|
Chris@16
|
409 void insert_dispatch(const geometry_type& geometry_object, bool is_hole, polygon_45_set_concept ) {
|
Chris@16
|
410 polygon_45_set_data ps;
|
Chris@16
|
411 assign(ps, geometry_object);
|
Chris@16
|
412 insert(ps, is_hole);
|
Chris@16
|
413 }
|
Chris@16
|
414 template <typename geometry_type>
|
Chris@16
|
415 void insert_dispatch(const geometry_type& geometry_object, bool is_hole, polygon_90_set_concept ) {
|
Chris@16
|
416 std::list<polygon_90_data<coordinate_type> > pl;
|
Chris@16
|
417 assign(pl, geometry_object);
|
Chris@16
|
418 insert(pl.begin(), pl.end(), is_hole);
|
Chris@16
|
419 }
|
Chris@16
|
420
|
Chris@16
|
421 void insert_vertex_half_edge_45_pair(const point_data<Unit>& pt1, point_data<Unit>& pt2,
|
Chris@16
|
422 const point_data<Unit>& pt3, direction_1d wdir);
|
Chris@16
|
423
|
Chris@16
|
424 template <typename geometry_type>
|
Chris@16
|
425 polygon_45_set_data& insert_with_resize_dispatch(const geometry_type& poly,
|
Chris@16
|
426 coordinate_type resizing, RoundingOption rounding,
|
Chris@16
|
427 CornerOption corner, bool hole, polygon_45_concept tag);
|
Chris@16
|
428
|
Chris@16
|
429 // accumulate the bloated polygon with holes
|
Chris@16
|
430 template <typename geometry_type>
|
Chris@16
|
431 polygon_45_set_data& insert_with_resize_dispatch(const geometry_type& poly,
|
Chris@16
|
432 coordinate_type resizing, RoundingOption rounding,
|
Chris@16
|
433 CornerOption corner, bool hole, polygon_45_with_holes_concept tag);
|
Chris@16
|
434
|
Chris@16
|
435 static void snap_vertex_45(Vertex45Compact& vertex);
|
Chris@16
|
436
|
Chris@16
|
437 public:
|
Chris@16
|
438 template <int op>
|
Chris@16
|
439 void applyAdaptiveBoolean_(const polygon_45_set_data& rvalue) const;
|
Chris@16
|
440 template <int op>
|
Chris@16
|
441 void applyAdaptiveBoolean_(polygon_45_set_data& result, const polygon_45_set_data& rvalue) const;
|
Chris@16
|
442 template <int op>
|
Chris@16
|
443 void applyAdaptiveUnary_() const;
|
Chris@16
|
444 };
|
Chris@16
|
445
|
Chris@16
|
446 template <typename T>
|
Chris@16
|
447 struct geometry_concept<polygon_45_set_data<T> > {
|
Chris@16
|
448 typedef polygon_45_set_concept type;
|
Chris@16
|
449 };
|
Chris@16
|
450
|
Chris@16
|
451 template <typename iT, typename T>
|
Chris@16
|
452 void scale_up_vertex_45_compact_range(iT beginr, iT endr, T factor) {
|
Chris@16
|
453 for( ; beginr != endr; ++beginr) {
|
Chris@16
|
454 scale_up((*beginr).pt, factor);
|
Chris@16
|
455 }
|
Chris@16
|
456 }
|
Chris@16
|
457 template <typename iT, typename T>
|
Chris@16
|
458 void scale_down_vertex_45_compact_range_blindly(iT beginr, iT endr, T factor) {
|
Chris@16
|
459 for( ; beginr != endr; ++beginr) {
|
Chris@16
|
460 scale_down((*beginr).pt, factor);
|
Chris@16
|
461 }
|
Chris@16
|
462 }
|
Chris@16
|
463
|
Chris@16
|
464 template <typename Unit>
|
Chris@16
|
465 inline std::pair<int, int> characterizeEdge45(const point_data<Unit>& pt1, const point_data<Unit>& pt2) {
|
Chris@16
|
466 std::pair<int, int> retval(0, 1);
|
Chris@16
|
467 if(pt1.x() == pt2.x()) {
|
Chris@16
|
468 retval.first = 3;
|
Chris@16
|
469 retval.second = -1;
|
Chris@16
|
470 return retval;
|
Chris@16
|
471 }
|
Chris@16
|
472 //retval.second = pt1.x() < pt2.x() ? -1 : 1;
|
Chris@16
|
473 retval.second = 1;
|
Chris@16
|
474 if(pt1.y() == pt2.y()) {
|
Chris@16
|
475 retval.first = 1;
|
Chris@16
|
476 } else if(pt1.x() < pt2.x()) {
|
Chris@16
|
477 if(pt1.y() < pt2.y()) {
|
Chris@16
|
478 retval.first = 2;
|
Chris@16
|
479 } else {
|
Chris@16
|
480 retval.first = 0;
|
Chris@16
|
481 }
|
Chris@16
|
482 } else {
|
Chris@16
|
483 if(pt1.y() < pt2.y()) {
|
Chris@16
|
484 retval.first = 0;
|
Chris@16
|
485 } else {
|
Chris@16
|
486 retval.first = 2;
|
Chris@16
|
487 }
|
Chris@16
|
488 }
|
Chris@16
|
489 return retval;
|
Chris@16
|
490 }
|
Chris@16
|
491
|
Chris@16
|
492 template <typename cT, typename pT>
|
Chris@16
|
493 bool insert_vertex_half_edge_45_pair_into_vector(cT& output,
|
Chris@16
|
494 const pT& pt1, pT& pt2,
|
Chris@16
|
495 const pT& pt3,
|
Chris@16
|
496 direction_1d wdir) {
|
Chris@16
|
497 int multiplier = wdir == LOW ? -1 : 1;
|
Chris@16
|
498 typename cT::value_type vertex(pt2, 0, 0);
|
Chris@16
|
499 //std::cout << pt1 << " " << pt2 << " " << pt3 << std::endl;
|
Chris@16
|
500 std::pair<int, int> check;
|
Chris@16
|
501 check = characterizeEdge45(pt1, pt2);
|
Chris@16
|
502 //std::cout << "index " << check.first << " " << check.second * -multiplier << std::endl;
|
Chris@16
|
503 vertex.count[check.first] += check.second * -multiplier;
|
Chris@16
|
504 check = characterizeEdge45(pt2, pt3);
|
Chris@16
|
505 //std::cout << "index " << check.first << " " << check.second * multiplier << std::endl;
|
Chris@16
|
506 vertex.count[check.first] += check.second * multiplier;
|
Chris@16
|
507 output.push_back(vertex);
|
Chris@16
|
508 return vertex.count.is_45();
|
Chris@16
|
509 }
|
Chris@16
|
510
|
Chris@16
|
511 template <typename Unit>
|
Chris@16
|
512 inline void polygon_45_set_data<Unit>::insert_vertex_half_edge_45_pair(const point_data<Unit>& pt1, point_data<Unit>& pt2,
|
Chris@16
|
513 const point_data<Unit>& pt3,
|
Chris@16
|
514 direction_1d wdir) {
|
Chris@16
|
515 if(insert_vertex_half_edge_45_pair_into_vector(data_, pt1, pt2, pt3, wdir)) is_manhattan_ = false;
|
Chris@16
|
516 }
|
Chris@16
|
517
|
Chris@16
|
518 template <typename Unit>
|
Chris@16
|
519 template <class iT>
|
Chris@16
|
520 inline void polygon_45_set_data<Unit>::insert_vertex_sequence(iT begin_vertex, iT end_vertex,
|
Chris@16
|
521 direction_1d winding, bool is_hole) {
|
Chris@16
|
522 if(begin_vertex == end_vertex) return;
|
Chris@16
|
523 if(is_hole) winding = winding.backward();
|
Chris@16
|
524 iT itr = begin_vertex;
|
Chris@16
|
525 if(itr == end_vertex) return;
|
Chris@16
|
526 point_data<Unit> firstPt = *itr;
|
Chris@16
|
527 ++itr;
|
Chris@16
|
528 point_data<Unit> secondPt(firstPt);
|
Chris@16
|
529 //skip any duplicate points
|
Chris@16
|
530 do {
|
Chris@16
|
531 if(itr == end_vertex) return;
|
Chris@16
|
532 secondPt = *itr;
|
Chris@16
|
533 ++itr;
|
Chris@16
|
534 } while(secondPt == firstPt);
|
Chris@16
|
535 point_data<Unit> prevPt = secondPt;
|
Chris@16
|
536 point_data<Unit> prevPrevPt = firstPt;
|
Chris@16
|
537 while(itr != end_vertex) {
|
Chris@16
|
538 point_data<Unit> pt = *itr;
|
Chris@16
|
539 //skip any duplicate points
|
Chris@16
|
540 if(pt == prevPt) {
|
Chris@16
|
541 ++itr;
|
Chris@16
|
542 continue;
|
Chris@16
|
543 }
|
Chris@16
|
544 //operate on the three points
|
Chris@16
|
545 insert_vertex_half_edge_45_pair(prevPrevPt, prevPt, pt, winding);
|
Chris@16
|
546 prevPrevPt = prevPt;
|
Chris@16
|
547 prevPt = pt;
|
Chris@16
|
548 ++itr;
|
Chris@16
|
549 }
|
Chris@16
|
550 if(prevPt != firstPt) {
|
Chris@16
|
551 insert_vertex_half_edge_45_pair(prevPrevPt, prevPt, firstPt, winding);
|
Chris@16
|
552 insert_vertex_half_edge_45_pair(prevPt, firstPt, secondPt, winding);
|
Chris@16
|
553 } else {
|
Chris@16
|
554 insert_vertex_half_edge_45_pair(prevPrevPt, firstPt, secondPt, winding);
|
Chris@16
|
555 }
|
Chris@16
|
556 dirty_ = true;
|
Chris@16
|
557 unsorted_ = true;
|
Chris@16
|
558 }
|
Chris@16
|
559
|
Chris@16
|
560 // insert polygon set
|
Chris@16
|
561 template <typename Unit>
|
Chris@16
|
562 inline void polygon_45_set_data<Unit>::insert(const polygon_45_set_data<Unit>& polygon_set, bool is_hole) {
|
Chris@16
|
563 std::size_t count = data_.size();
|
Chris@16
|
564 data_.insert(data_.end(), polygon_set.data_.begin(), polygon_set.data_.end());
|
Chris@16
|
565 error_data_.insert(error_data_.end(), polygon_set.error_data_.begin(),
|
Chris@16
|
566 polygon_set.error_data_.end());
|
Chris@16
|
567 if(is_hole) {
|
Chris@16
|
568 for(std::size_t i = count; i < data_.size(); ++i) {
|
Chris@16
|
569 data_[i].count = data_[i].count.invert();
|
Chris@16
|
570 }
|
Chris@16
|
571 }
|
Chris@16
|
572 dirty_ = true;
|
Chris@16
|
573 unsorted_ = true;
|
Chris@16
|
574 if(polygon_set.is_manhattan_ == false) is_manhattan_ = false;
|
Chris@16
|
575 return;
|
Chris@16
|
576 }
|
Chris@16
|
577 // insert polygon set
|
Chris@16
|
578 template <typename Unit>
|
Chris@16
|
579 template <typename coord_type>
|
Chris@16
|
580 inline void polygon_45_set_data<Unit>::insert(const polygon_45_set_data<coord_type>& polygon_set, bool is_hole) {
|
Chris@16
|
581 std::size_t count = data_.size();
|
Chris@16
|
582 for(typename polygon_45_set_data<coord_type>::iterator_type itr = polygon_set.begin();
|
Chris@16
|
583 itr != polygon_set.end(); ++itr) {
|
Chris@16
|
584 const typename polygon_45_set_data<coord_type>::Vertex45Compact& v = *itr;
|
Chris@16
|
585 typename polygon_45_set_data<Unit>::Vertex45Compact v2;
|
Chris@16
|
586 v2.pt.x(static_cast<Unit>(v.pt.x()));
|
Chris@16
|
587 v2.pt.y(static_cast<Unit>(v.pt.y()));
|
Chris@16
|
588 v2.count = typename polygon_45_formation<Unit>::Vertex45Count(v.count[0], v.count[1], v.count[2], v.count[3]);
|
Chris@16
|
589 data_.push_back(v2);
|
Chris@16
|
590 }
|
Chris@16
|
591 polygon_45_set_data<coord_type> tmp;
|
Chris@16
|
592 polygon_set.get_error_data(tmp);
|
Chris@16
|
593 for(typename polygon_45_set_data<coord_type>::iterator_type itr = tmp.begin();
|
Chris@16
|
594 itr != tmp.end(); ++itr) {
|
Chris@16
|
595 const typename polygon_45_set_data<coord_type>::Vertex45Compact& v = *itr;
|
Chris@16
|
596 typename polygon_45_set_data<Unit>::Vertex45Compact v2;
|
Chris@16
|
597 v2.pt.x(static_cast<Unit>(v.pt.x()));
|
Chris@16
|
598 v2.pt.y(static_cast<Unit>(v.pt.y()));
|
Chris@16
|
599 v2.count = typename polygon_45_formation<Unit>::Vertex45Count(v.count[0], v.count[1], v.count[2], v.count[3]);
|
Chris@16
|
600 error_data_.push_back(v2);
|
Chris@16
|
601 }
|
Chris@16
|
602 if(is_hole) {
|
Chris@16
|
603 for(std::size_t i = count; i < data_.size(); ++i) {
|
Chris@16
|
604 data_[i].count = data_[i].count.invert();
|
Chris@16
|
605 }
|
Chris@16
|
606 }
|
Chris@16
|
607 dirty_ = true;
|
Chris@16
|
608 unsorted_ = true;
|
Chris@16
|
609 if(polygon_set.is_manhattan() == false) is_manhattan_ = false;
|
Chris@16
|
610 return;
|
Chris@16
|
611 }
|
Chris@16
|
612
|
Chris@16
|
613 template <typename cT, typename rT>
|
Chris@16
|
614 void insert_rectangle_into_vector_45(cT& output, const rT& rect, bool is_hole) {
|
Chris@16
|
615 point_data<typename rectangle_traits<rT>::coordinate_type>
|
Chris@16
|
616 llpt = ll(rect), lrpt = lr(rect), ulpt = ul(rect), urpt = ur(rect);
|
Chris@16
|
617 direction_1d dir = COUNTERCLOCKWISE;
|
Chris@16
|
618 if(is_hole) dir = CLOCKWISE;
|
Chris@16
|
619 insert_vertex_half_edge_45_pair_into_vector(output, llpt, lrpt, urpt, dir);
|
Chris@16
|
620 insert_vertex_half_edge_45_pair_into_vector(output, lrpt, urpt, ulpt, dir);
|
Chris@16
|
621 insert_vertex_half_edge_45_pair_into_vector(output, urpt, ulpt, llpt, dir);
|
Chris@16
|
622 insert_vertex_half_edge_45_pair_into_vector(output, ulpt, llpt, lrpt, dir);
|
Chris@16
|
623 }
|
Chris@16
|
624
|
Chris@16
|
625 template <typename Unit>
|
Chris@16
|
626 template <typename geometry_type>
|
Chris@16
|
627 inline void polygon_45_set_data<Unit>::insert_dispatch(const geometry_type& geometry_object,
|
Chris@16
|
628 bool is_hole, rectangle_concept ) {
|
Chris@16
|
629 dirty_ = true;
|
Chris@16
|
630 unsorted_ = true;
|
Chris@16
|
631 insert_rectangle_into_vector_45(data_, geometry_object, is_hole);
|
Chris@16
|
632 }
|
Chris@16
|
633
|
Chris@16
|
634 // get the external boundary rectangle
|
Chris@16
|
635 template <typename Unit>
|
Chris@16
|
636 template <typename rectangle_type>
|
Chris@16
|
637 inline bool polygon_45_set_data<Unit>::extents(rectangle_type& rect) const{
|
Chris@16
|
638 clean();
|
Chris@16
|
639 if(empty()) {
|
Chris@16
|
640 return false;
|
Chris@16
|
641 }
|
Chris@16
|
642 Unit low = (std::numeric_limits<Unit>::max)();
|
Chris@16
|
643 Unit high = (std::numeric_limits<Unit>::min)();
|
Chris@16
|
644 interval_data<Unit> xivl(low, high);
|
Chris@16
|
645 interval_data<Unit> yivl(low, high);
|
Chris@16
|
646 for(typename value_type::const_iterator itr = data_.begin();
|
Chris@16
|
647 itr != data_.end(); ++ itr) {
|
Chris@16
|
648 if((*itr).pt.x() > xivl.get(HIGH))
|
Chris@16
|
649 xivl.set(HIGH, (*itr).pt.x());
|
Chris@16
|
650 if((*itr).pt.x() < xivl.get(LOW))
|
Chris@16
|
651 xivl.set(LOW, (*itr).pt.x());
|
Chris@16
|
652 if((*itr).pt.y() > yivl.get(HIGH))
|
Chris@16
|
653 yivl.set(HIGH, (*itr).pt.y());
|
Chris@16
|
654 if((*itr).pt.y() < yivl.get(LOW))
|
Chris@16
|
655 yivl.set(LOW, (*itr).pt.y());
|
Chris@16
|
656 }
|
Chris@16
|
657 rect = construct<rectangle_type>(xivl, yivl);
|
Chris@16
|
658 return true;
|
Chris@16
|
659 }
|
Chris@16
|
660
|
Chris@16
|
661 //this function snaps the vertex and two half edges
|
Chris@16
|
662 //to be both even or both odd coordinate values if one of the edges is 45
|
Chris@16
|
663 //and throws an excpetion if an edge is non-manhattan, non-45.
|
Chris@16
|
664 template <typename Unit>
|
Chris@16
|
665 inline void polygon_45_set_data<Unit>::snap_vertex_45(typename polygon_45_set_data<Unit>::Vertex45Compact& vertex) {
|
Chris@16
|
666 bool plus45 = vertex.count[2] != 0;
|
Chris@16
|
667 bool minus45 = vertex.count[0] != 0;
|
Chris@16
|
668 if(plus45 || minus45) {
|
Chris@16
|
669 if(abs(vertex.pt.x()) % 2 != abs(vertex.pt.y()) % 2) {
|
Chris@16
|
670 if(vertex.count[1] != 0 ||
|
Chris@16
|
671 (plus45 && minus45)) {
|
Chris@16
|
672 //move right
|
Chris@16
|
673 vertex.pt.x(vertex.pt.x() + 1);
|
Chris@16
|
674 } else {
|
Chris@16
|
675 //assert that vertex.count[3] != 0
|
Chris@16
|
676 Unit modifier = plus45 ? -1 : 1;
|
Chris@16
|
677 vertex.pt.y(vertex.pt.y() + modifier);
|
Chris@16
|
678 }
|
Chris@16
|
679 }
|
Chris@16
|
680 }
|
Chris@16
|
681 }
|
Chris@16
|
682
|
Chris@16
|
683 template <typename Unit>
|
Chris@16
|
684 inline void polygon_45_set_data<Unit>::snap() const {
|
Chris@16
|
685 for(typename value_type::iterator itr = data_.begin();
|
Chris@16
|
686 itr != data_.end(); ++itr) {
|
Chris@16
|
687 snap_vertex_45(*itr);
|
Chris@16
|
688 }
|
Chris@16
|
689 }
|
Chris@16
|
690
|
Chris@16
|
691 // |= &= += *= -= ^= binary operators
|
Chris@16
|
692 template <typename Unit>
|
Chris@16
|
693 inline polygon_45_set_data<Unit>& polygon_45_set_data<Unit>::operator|=(const polygon_45_set_data<Unit>& b) {
|
Chris@16
|
694 insert(b);
|
Chris@16
|
695 return *this;
|
Chris@16
|
696 }
|
Chris@16
|
697 template <typename Unit>
|
Chris@16
|
698 inline polygon_45_set_data<Unit>& polygon_45_set_data<Unit>::operator&=(const polygon_45_set_data<Unit>& b) {
|
Chris@16
|
699 //b.sort();
|
Chris@16
|
700 //sort();
|
Chris@16
|
701 applyAdaptiveBoolean_<1>(b);
|
Chris@16
|
702 dirty_ = false;
|
Chris@16
|
703 unsorted_ = false;
|
Chris@16
|
704 return *this;
|
Chris@16
|
705 }
|
Chris@16
|
706 template <typename Unit>
|
Chris@16
|
707 inline polygon_45_set_data<Unit>& polygon_45_set_data<Unit>::operator+=(const polygon_45_set_data<Unit>& b) {
|
Chris@16
|
708 return (*this) |= b;
|
Chris@16
|
709 }
|
Chris@16
|
710 template <typename Unit>
|
Chris@16
|
711 inline polygon_45_set_data<Unit>& polygon_45_set_data<Unit>::operator*=(const polygon_45_set_data<Unit>& b) {
|
Chris@16
|
712 return (*this) &= b;
|
Chris@16
|
713 }
|
Chris@16
|
714 template <typename Unit>
|
Chris@16
|
715 inline polygon_45_set_data<Unit>& polygon_45_set_data<Unit>::operator-=(const polygon_45_set_data<Unit>& b) {
|
Chris@16
|
716 //b.sort();
|
Chris@16
|
717 //sort();
|
Chris@16
|
718 applyAdaptiveBoolean_<2>(b);
|
Chris@16
|
719 dirty_ = false;
|
Chris@16
|
720 unsorted_ = false;
|
Chris@16
|
721 return *this;
|
Chris@16
|
722 }
|
Chris@16
|
723 template <typename Unit>
|
Chris@16
|
724 inline polygon_45_set_data<Unit>& polygon_45_set_data<Unit>::operator^=(const polygon_45_set_data<Unit>& b) {
|
Chris@16
|
725 //b.sort();
|
Chris@16
|
726 //sort();
|
Chris@16
|
727 applyAdaptiveBoolean_<3>(b);
|
Chris@16
|
728 dirty_ = false;
|
Chris@16
|
729 unsorted_ = false;
|
Chris@16
|
730 return *this;
|
Chris@16
|
731 }
|
Chris@16
|
732
|
Chris@16
|
733 template <typename Unit>
|
Chris@16
|
734 inline polygon_45_set_data<Unit>& polygon_45_set_data<Unit>::operator+=(Unit delta) {
|
Chris@16
|
735 return resize(delta);
|
Chris@16
|
736 }
|
Chris@16
|
737 template <typename Unit>
|
Chris@16
|
738 inline polygon_45_set_data<Unit>& polygon_45_set_data<Unit>::operator-=(Unit delta) {
|
Chris@16
|
739 return (*this) += -delta;
|
Chris@16
|
740 }
|
Chris@16
|
741
|
Chris@16
|
742 template <typename Unit>
|
Chris@16
|
743 inline polygon_45_set_data<Unit>&
|
Chris@16
|
744 polygon_45_set_data<Unit>::resize(Unit resizing, RoundingOption rounding, CornerOption corner) {
|
Chris@16
|
745 if(resizing == 0) return *this;
|
Chris@16
|
746 std::list<polygon_45_with_holes_data<Unit> > pl;
|
Chris@16
|
747 get_polygons_with_holes(pl);
|
Chris@16
|
748 clear();
|
Chris@16
|
749 for(typename std::list<polygon_45_with_holes_data<Unit> >::iterator itr = pl.begin(); itr != pl.end(); ++itr) {
|
Chris@16
|
750 insert_with_resize(*itr, resizing, rounding, corner);
|
Chris@16
|
751 }
|
Chris@16
|
752 clean();
|
Chris@16
|
753 //perterb 45 edges to prevent non-integer intersection errors upon boolean op
|
Chris@16
|
754 //snap();
|
Chris@16
|
755 return *this;
|
Chris@16
|
756 }
|
Chris@16
|
757
|
Chris@16
|
758 //distance is assumed to be positive
|
Chris@16
|
759 inline int roundClosest(double distance) {
|
Chris@16
|
760 int f = (int)distance;
|
Chris@16
|
761 if(distance - (double)f < 0.5) return f;
|
Chris@16
|
762 return f+1;
|
Chris@16
|
763 }
|
Chris@16
|
764
|
Chris@16
|
765 //distance is assumed to be positive
|
Chris@16
|
766 template <typename Unit>
|
Chris@16
|
767 inline Unit roundWithOptions(double distance, RoundingOption rounding) {
|
Chris@16
|
768 if(rounding == CLOSEST) {
|
Chris@16
|
769 return roundClosest(distance);
|
Chris@16
|
770 } else if(rounding == OVERSIZE) {
|
Chris@16
|
771 return (Unit)distance + 1;
|
Chris@16
|
772 } else { //UNDERSIZE
|
Chris@16
|
773 return (Unit)distance;
|
Chris@16
|
774 }
|
Chris@16
|
775 }
|
Chris@16
|
776
|
Chris@16
|
777 // 0 is east, 1 is northeast, 2 is north, 3 is northwest, 4 is west, 5 is southwest, 6 is south
|
Chris@16
|
778 // 7 is southwest
|
Chris@16
|
779 template <typename Unit>
|
Chris@16
|
780 inline point_data<Unit> bloatVertexInDirWithOptions(const point_data<Unit>& point, unsigned int dir,
|
Chris@16
|
781 Unit bloating, RoundingOption rounding) {
|
Chris@16
|
782 const double sqrt2 = 1.4142135623730950488016887242097;
|
Chris@16
|
783 if(dir & 1) {
|
Chris@16
|
784 Unit unitDistance = (Unit)bloating;
|
Chris@16
|
785 if(rounding != SQRT2) {
|
Chris@16
|
786 //45 degree bloating
|
Chris@16
|
787 double distance = (double)bloating;
|
Chris@16
|
788 distance /= sqrt2; // multiply by 1/sqrt2
|
Chris@16
|
789 unitDistance = roundWithOptions<Unit>(distance, rounding);
|
Chris@16
|
790 }
|
Chris@16
|
791 int xMultiplier = 1;
|
Chris@16
|
792 int yMultiplier = 1;
|
Chris@16
|
793 if(dir == 3 || dir == 5) xMultiplier = -1;
|
Chris@16
|
794 if(dir == 5 || dir == 7) yMultiplier = -1;
|
Chris@16
|
795 return point_data<Unit>(point.x()+xMultiplier*unitDistance,
|
Chris@16
|
796 point.y()+yMultiplier*unitDistance);
|
Chris@16
|
797 } else {
|
Chris@16
|
798 if(dir == 0)
|
Chris@16
|
799 return point_data<Unit>(point.x()+bloating, point.y());
|
Chris@16
|
800 if(dir == 2)
|
Chris@16
|
801 return point_data<Unit>(point.x(), point.y()+bloating);
|
Chris@16
|
802 if(dir == 4)
|
Chris@16
|
803 return point_data<Unit>(point.x()-bloating, point.y());
|
Chris@16
|
804 if(dir == 6)
|
Chris@16
|
805 return point_data<Unit>(point.x(), point.y()-bloating);
|
Chris@16
|
806 return point_data<Unit>();
|
Chris@16
|
807 }
|
Chris@16
|
808 }
|
Chris@16
|
809
|
Chris@16
|
810 template <typename Unit>
|
Chris@16
|
811 inline unsigned int getEdge45Direction(const point_data<Unit>& pt1, const point_data<Unit>& pt2) {
|
Chris@16
|
812 if(pt1.x() == pt2.x()) {
|
Chris@16
|
813 if(pt1.y() < pt2.y()) return 2;
|
Chris@16
|
814 return 6;
|
Chris@16
|
815 }
|
Chris@16
|
816 if(pt1.y() == pt2.y()) {
|
Chris@16
|
817 if(pt1.x() < pt2.x()) return 0;
|
Chris@16
|
818 return 4;
|
Chris@16
|
819 }
|
Chris@16
|
820 if(pt2.y() > pt1.y()) {
|
Chris@16
|
821 if(pt2.x() > pt1.x()) return 1;
|
Chris@16
|
822 return 3;
|
Chris@16
|
823 }
|
Chris@16
|
824 if(pt2.x() > pt1.x()) return 7;
|
Chris@16
|
825 return 5;
|
Chris@16
|
826 }
|
Chris@16
|
827
|
Chris@16
|
828 inline unsigned int getEdge45NormalDirection(unsigned int dir, int multiplier) {
|
Chris@16
|
829 if(multiplier < 0)
|
Chris@16
|
830 return (dir + 2) % 8;
|
Chris@16
|
831 return (dir + 4 + 2) % 8;
|
Chris@16
|
832 }
|
Chris@16
|
833
|
Chris@16
|
834 template <typename Unit>
|
Chris@16
|
835 inline point_data<Unit> getIntersectionPoint(const point_data<Unit>& pt1, unsigned int slope1,
|
Chris@16
|
836 const point_data<Unit>& pt2, unsigned int slope2) {
|
Chris@16
|
837 //the intention here is to use all integer arithmetic without causing overflow
|
Chris@16
|
838 //turncation error or divide by zero error
|
Chris@16
|
839 //I don't use floating point arithmetic because its precision may not be high enough
|
Chris@16
|
840 //at the extremes of the integer range
|
Chris@16
|
841 typedef typename coordinate_traits<Unit>::area_type LongUnit;
|
Chris@16
|
842 const Unit rises[8] = {0, 1, 1, 1, 0, -1, -1, -1};
|
Chris@16
|
843 const Unit runs[8] = {1, 1, 0, -1, -1, -1, 0, 1};
|
Chris@16
|
844 LongUnit rise1 = rises[slope1];
|
Chris@16
|
845 LongUnit rise2 = rises[slope2];
|
Chris@16
|
846 LongUnit run1 = runs[slope1];
|
Chris@16
|
847 LongUnit run2 = runs[slope2];
|
Chris@16
|
848 LongUnit x1 = (LongUnit)pt1.x();
|
Chris@16
|
849 LongUnit x2 = (LongUnit)pt2.x();
|
Chris@16
|
850 LongUnit y1 = (LongUnit)pt1.y();
|
Chris@16
|
851 LongUnit y2 = (LongUnit)pt2.y();
|
Chris@16
|
852 Unit x = 0;
|
Chris@16
|
853 Unit y = 0;
|
Chris@16
|
854 if(run1 == 0) {
|
Chris@16
|
855 x = pt1.x();
|
Chris@16
|
856 y = (Unit)(((x1 - x2) * rise2) / run2) + pt2.y();
|
Chris@16
|
857 } else if(run2 == 0) {
|
Chris@16
|
858 x = pt2.x();
|
Chris@16
|
859 y = (Unit)(((x2 - x1) * rise1) / run1) + pt1.y();
|
Chris@16
|
860 } else {
|
Chris@16
|
861 // y - y1 = (rise1/run1)(x - x1)
|
Chris@16
|
862 // y - y2 = (rise2/run2)(x - x2)
|
Chris@16
|
863 // y = (rise1/run1)(x - x1) + y1 = (rise2/run2)(x - x2) + y2
|
Chris@16
|
864 // (rise1/run1 - rise2/run2)x = y2 - y1 + rise1/run1 x1 - rise2/run2 x2
|
Chris@16
|
865 // x = (y2 - y1 + rise1/run1 x1 - rise2/run2 x2)/(rise1/run1 - rise2/run2)
|
Chris@16
|
866 // x = (y2 - y1 + rise1/run1 x1 - rise2/run2 x2)(rise1 run2 - rise2 run1)/(run1 run2)
|
Chris@16
|
867 x = (Unit)((y2 - y1 + ((rise1 * x1) / run1) - ((rise2 * x2) / run2)) *
|
Chris@16
|
868 (run1 * run2) / (rise1 * run2 - rise2 * run1));
|
Chris@16
|
869 if(rise1 == 0) {
|
Chris@16
|
870 y = pt1.y();
|
Chris@16
|
871 } else if(rise2 == 0) {
|
Chris@16
|
872 y = pt2.y();
|
Chris@16
|
873 } else {
|
Chris@16
|
874 // y - y1 = (rise1/run1)(x - x1)
|
Chris@16
|
875 // (run1/rise1)(y - y1) = x - x1
|
Chris@16
|
876 // x = (run1/rise1)(y - y1) + x1 = (run2/rise2)(y - y2) + x2
|
Chris@16
|
877 y = (Unit)((x2 - x1 + ((run1 * y1) / rise1) - ((run2 * y2) / rise2)) *
|
Chris@16
|
878 (rise1 * rise2) / (run1 * rise2 - run2 * rise1));
|
Chris@16
|
879 }
|
Chris@16
|
880 }
|
Chris@16
|
881 return point_data<Unit>(x, y);
|
Chris@16
|
882 }
|
Chris@16
|
883
|
Chris@16
|
884 template <typename Unit>
|
Chris@16
|
885 inline
|
Chris@16
|
886 void handleResizingEdge45_SQRT1OVER2(polygon_45_set_data<Unit>& sizingSet, point_data<Unit> first,
|
Chris@16
|
887 point_data<Unit> second, Unit resizing, CornerOption corner) {
|
Chris@16
|
888 if(first.x() == second.x()) {
|
Chris@16
|
889 sizingSet.insert(rectangle_data<Unit>(first.x() - resizing, first.y(), first.x() + resizing, second.y()));
|
Chris@16
|
890 return;
|
Chris@16
|
891 }
|
Chris@16
|
892 if(first.y() == second.y()) {
|
Chris@16
|
893 sizingSet.insert(rectangle_data<Unit>(first.x(), first.y() - resizing, second.x(), first.y() + resizing));
|
Chris@16
|
894 return;
|
Chris@16
|
895 }
|
Chris@16
|
896 std::vector<point_data<Unit> > pts;
|
Chris@16
|
897 Unit bloating = resizing < 0 ? -resizing : resizing;
|
Chris@16
|
898 if(corner == UNFILLED) {
|
Chris@16
|
899 //we have to round up
|
Chris@16
|
900 bloating = bloating / 2 + bloating % 2 ; //round up
|
Chris@16
|
901 if(second.x() < first.x()) std::swap(first, second);
|
Chris@16
|
902 if(first.y() < second.y()) { //upward sloping
|
Chris@16
|
903 pts.push_back(point_data<Unit>(first.x() + bloating, first.y() - bloating));
|
Chris@16
|
904 pts.push_back(point_data<Unit>(first.x() - bloating, first.y() + bloating));
|
Chris@16
|
905 pts.push_back(point_data<Unit>(second.x() - bloating, second.y() + bloating));
|
Chris@16
|
906 pts.push_back(point_data<Unit>(second.x() + bloating, second.y() - bloating));
|
Chris@16
|
907 sizingSet.insert_vertex_sequence(pts.begin(), pts.end(), CLOCKWISE, false);
|
Chris@16
|
908 } else { //downward sloping
|
Chris@16
|
909 pts.push_back(point_data<Unit>(first.x() + bloating, first.y() + bloating));
|
Chris@16
|
910 pts.push_back(point_data<Unit>(first.x() - bloating, first.y() - bloating));
|
Chris@16
|
911 pts.push_back(point_data<Unit>(second.x() - bloating, second.y() - bloating));
|
Chris@16
|
912 pts.push_back(point_data<Unit>(second.x() + bloating, second.y() + bloating));
|
Chris@16
|
913 sizingSet.insert_vertex_sequence(pts.begin(), pts.end(), COUNTERCLOCKWISE, false);
|
Chris@16
|
914 }
|
Chris@16
|
915 return;
|
Chris@16
|
916 }
|
Chris@16
|
917 if(second.x() < first.x()) std::swap(first, second);
|
Chris@16
|
918 if(first.y() < second.y()) { //upward sloping
|
Chris@16
|
919 pts.push_back(point_data<Unit>(first.x(), first.y() - bloating));
|
Chris@16
|
920 pts.push_back(point_data<Unit>(first.x() - bloating, first.y()));
|
Chris@16
|
921 pts.push_back(point_data<Unit>(second.x(), second.y() + bloating));
|
Chris@16
|
922 pts.push_back(point_data<Unit>(second.x() + bloating, second.y()));
|
Chris@16
|
923 sizingSet.insert_vertex_sequence(pts.begin(), pts.end(), CLOCKWISE, false);
|
Chris@16
|
924 } else { //downward sloping
|
Chris@16
|
925 pts.push_back(point_data<Unit>(first.x() - bloating, first.y()));
|
Chris@16
|
926 pts.push_back(point_data<Unit>(first.x(), first.y() + bloating));
|
Chris@16
|
927 pts.push_back(point_data<Unit>(second.x() + bloating, second.y()));
|
Chris@16
|
928 pts.push_back(point_data<Unit>(second.x(), second.y() - bloating));
|
Chris@16
|
929 sizingSet.insert_vertex_sequence(pts.begin(), pts.end(), CLOCKWISE, false);
|
Chris@16
|
930 }
|
Chris@16
|
931 }
|
Chris@16
|
932
|
Chris@16
|
933
|
Chris@16
|
934 template <typename Unit>
|
Chris@16
|
935 inline
|
Chris@16
|
936 void handleResizingEdge45(polygon_45_set_data<Unit>& sizingSet, point_data<Unit> first,
|
Chris@16
|
937 point_data<Unit> second, Unit resizing, RoundingOption rounding) {
|
Chris@16
|
938 if(first.x() == second.x()) {
|
Chris@16
|
939 sizingSet.insert(rectangle_data<int>(first.x() - resizing, first.y(), first.x() + resizing, second.y()));
|
Chris@16
|
940 return;
|
Chris@16
|
941 }
|
Chris@16
|
942 if(first.y() == second.y()) {
|
Chris@16
|
943 sizingSet.insert(rectangle_data<int>(first.x(), first.y() - resizing, second.x(), first.y() + resizing));
|
Chris@16
|
944 return;
|
Chris@16
|
945 }
|
Chris@16
|
946 //edge is 45
|
Chris@16
|
947 std::vector<point_data<Unit> > pts;
|
Chris@16
|
948 Unit bloating = resizing < 0 ? -resizing : resizing;
|
Chris@16
|
949 if(second.x() < first.x()) std::swap(first, second);
|
Chris@16
|
950 if(first.y() < second.y()) {
|
Chris@16
|
951 pts.push_back(bloatVertexInDirWithOptions(first, 3, bloating, rounding));
|
Chris@16
|
952 pts.push_back(bloatVertexInDirWithOptions(first, 7, bloating, rounding));
|
Chris@16
|
953 pts.push_back(bloatVertexInDirWithOptions(second, 7, bloating, rounding));
|
Chris@16
|
954 pts.push_back(bloatVertexInDirWithOptions(second, 3, bloating, rounding));
|
Chris@16
|
955 sizingSet.insert_vertex_sequence(pts.begin(), pts.end(), HIGH, false);
|
Chris@16
|
956 } else {
|
Chris@16
|
957 pts.push_back(bloatVertexInDirWithOptions(first, 1, bloating, rounding));
|
Chris@16
|
958 pts.push_back(bloatVertexInDirWithOptions(first, 5, bloating, rounding));
|
Chris@16
|
959 pts.push_back(bloatVertexInDirWithOptions(second, 5, bloating, rounding));
|
Chris@16
|
960 pts.push_back(bloatVertexInDirWithOptions(second, 1, bloating, rounding));
|
Chris@16
|
961 sizingSet.insert_vertex_sequence(pts.begin(), pts.end(), HIGH, false);
|
Chris@16
|
962 }
|
Chris@16
|
963 }
|
Chris@16
|
964
|
Chris@16
|
965 template <typename Unit>
|
Chris@16
|
966 inline point_data<Unit> bloatVertexInDirWithSQRT1OVER2(int edge1, int normal1, const point_data<Unit>& second, Unit bloating,
|
Chris@16
|
967 bool first) {
|
Chris@16
|
968 orientation_2d orient = first ? HORIZONTAL : VERTICAL;
|
Chris@16
|
969 orientation_2d orientp = orient.get_perpendicular();
|
Chris@16
|
970 int multiplier = first ? 1 : -1;
|
Chris@16
|
971 point_data<Unit> pt1(second);
|
Chris@16
|
972 if(edge1 == 1) {
|
Chris@16
|
973 if(normal1 == 3) {
|
Chris@16
|
974 move(pt1, orient, -multiplier * bloating);
|
Chris@16
|
975 } else {
|
Chris@16
|
976 move(pt1, orientp, -multiplier * bloating);
|
Chris@16
|
977 }
|
Chris@16
|
978 } else if(edge1 == 3) {
|
Chris@16
|
979 if(normal1 == 1) {
|
Chris@16
|
980 move(pt1, orient, multiplier * bloating);
|
Chris@16
|
981 } else {
|
Chris@16
|
982 move(pt1, orientp, -multiplier * bloating);
|
Chris@16
|
983 }
|
Chris@16
|
984 } else if(edge1 == 5) {
|
Chris@16
|
985 if(normal1 == 3) {
|
Chris@16
|
986 move(pt1, orientp, multiplier * bloating);
|
Chris@16
|
987 } else {
|
Chris@16
|
988 move(pt1, orient, multiplier * bloating);
|
Chris@16
|
989 }
|
Chris@16
|
990 } else {
|
Chris@16
|
991 if(normal1 == 5) {
|
Chris@16
|
992 move(pt1, orient, -multiplier * bloating);
|
Chris@16
|
993 } else {
|
Chris@16
|
994 move(pt1, orientp, multiplier * bloating);
|
Chris@16
|
995 }
|
Chris@16
|
996 }
|
Chris@16
|
997 return pt1;
|
Chris@16
|
998 }
|
Chris@16
|
999
|
Chris@16
|
1000 template <typename Unit>
|
Chris@16
|
1001 inline
|
Chris@16
|
1002 void handleResizingVertex45(polygon_45_set_data<Unit>& sizingSet, const point_data<Unit>& first,
|
Chris@16
|
1003 const point_data<Unit>& second, const point_data<Unit>& third, Unit resizing,
|
Chris@16
|
1004 RoundingOption rounding, CornerOption corner,
|
Chris@16
|
1005 int multiplier) {
|
Chris@16
|
1006 unsigned int edge1 = getEdge45Direction(first, second);
|
Chris@16
|
1007 unsigned int edge2 = getEdge45Direction(second, third);
|
Chris@16
|
1008 unsigned int diffAngle;
|
Chris@16
|
1009 if(multiplier < 0)
|
Chris@16
|
1010 diffAngle = (edge2 + 8 - edge1) % 8;
|
Chris@16
|
1011 else
|
Chris@16
|
1012 diffAngle = (edge1 + 8 - edge2) % 8;
|
Chris@16
|
1013 if(diffAngle < 4) {
|
Chris@16
|
1014 if(resizing > 0) return; //accute interior corner
|
Chris@16
|
1015 else multiplier *= -1; //make it appear to be an accute exterior angle
|
Chris@16
|
1016 }
|
Chris@16
|
1017 Unit bloating = abs(resizing);
|
Chris@16
|
1018 if(rounding == SQRT1OVER2) {
|
Chris@16
|
1019 if(edge1 % 2 && edge2 % 2) return;
|
Chris@16
|
1020 if(corner == ORTHOGONAL && edge1 % 2 == 0 && edge2 % 2 == 0) {
|
Chris@16
|
1021 rectangle_data<Unit> insertion_rect;
|
Chris@16
|
1022 set_points(insertion_rect, second, second);
|
Chris@16
|
1023 bloat(insertion_rect, bloating);
|
Chris@16
|
1024 sizingSet.insert(insertion_rect);
|
Chris@16
|
1025 } else if(corner != ORTHOGONAL) {
|
Chris@16
|
1026 point_data<Unit> pt1(0, 0);
|
Chris@16
|
1027 point_data<Unit> pt2(0, 0);
|
Chris@16
|
1028 unsigned int normal1 = getEdge45NormalDirection(edge1, multiplier);
|
Chris@16
|
1029 unsigned int normal2 = getEdge45NormalDirection(edge2, multiplier);
|
Chris@16
|
1030 if(edge1 % 2) {
|
Chris@16
|
1031 pt1 = bloatVertexInDirWithSQRT1OVER2(edge1, normal1, second, bloating, true);
|
Chris@16
|
1032 } else {
|
Chris@16
|
1033 pt1 = bloatVertexInDirWithOptions(second, normal1, bloating, UNDERSIZE);
|
Chris@16
|
1034 }
|
Chris@16
|
1035 if(edge2 % 2) {
|
Chris@16
|
1036 pt2 = bloatVertexInDirWithSQRT1OVER2(edge2, normal2, second, bloating, false);
|
Chris@16
|
1037 } else {
|
Chris@16
|
1038 pt2 = bloatVertexInDirWithOptions(second, normal2, bloating, UNDERSIZE);
|
Chris@16
|
1039 }
|
Chris@16
|
1040 std::vector<point_data<Unit> > pts;
|
Chris@16
|
1041 pts.push_back(pt1);
|
Chris@16
|
1042 pts.push_back(second);
|
Chris@16
|
1043 pts.push_back(pt2);
|
Chris@16
|
1044 pts.push_back(getIntersectionPoint(pt1, edge1, pt2, edge2));
|
Chris@16
|
1045 polygon_45_data<Unit> poly(pts.begin(), pts.end());
|
Chris@16
|
1046 sizingSet.insert(poly);
|
Chris@16
|
1047 } else {
|
Chris@16
|
1048 //ORTHOGONAL of a 45 degree corner
|
Chris@16
|
1049 int normal = 0;
|
Chris@16
|
1050 if(edge1 % 2) {
|
Chris@16
|
1051 normal = getEdge45NormalDirection(edge2, multiplier);
|
Chris@16
|
1052 } else {
|
Chris@16
|
1053 normal = getEdge45NormalDirection(edge1, multiplier);
|
Chris@16
|
1054 }
|
Chris@16
|
1055 rectangle_data<Unit> insertion_rect;
|
Chris@16
|
1056 point_data<Unit> edgePoint = bloatVertexInDirWithOptions(second, normal, bloating, UNDERSIZE);
|
Chris@16
|
1057 set_points(insertion_rect, second, edgePoint);
|
Chris@16
|
1058 if(normal == 0 || normal == 4)
|
Chris@16
|
1059 bloat(insertion_rect, VERTICAL, bloating);
|
Chris@16
|
1060 else
|
Chris@16
|
1061 bloat(insertion_rect, HORIZONTAL, bloating);
|
Chris@16
|
1062 sizingSet.insert(insertion_rect);
|
Chris@16
|
1063 }
|
Chris@16
|
1064 return;
|
Chris@16
|
1065 }
|
Chris@16
|
1066 unsigned int normal1 = getEdge45NormalDirection(edge1, multiplier);
|
Chris@16
|
1067 unsigned int normal2 = getEdge45NormalDirection(edge2, multiplier);
|
Chris@16
|
1068 point_data<Unit> edgePoint1 = bloatVertexInDirWithOptions(second, normal1, bloating, rounding);
|
Chris@16
|
1069 point_data<Unit> edgePoint2 = bloatVertexInDirWithOptions(second, normal2, bloating, rounding);
|
Chris@16
|
1070 //if the change in angle is 135 degrees it is an accute exterior corner
|
Chris@16
|
1071 if((edge1+ multiplier * 3) % 8 == edge2) {
|
Chris@16
|
1072 if(corner == ORTHOGONAL) {
|
Chris@16
|
1073 rectangle_data<Unit> insertion_rect;
|
Chris@16
|
1074 set_points(insertion_rect, edgePoint1, edgePoint2);
|
Chris@16
|
1075 sizingSet.insert(insertion_rect);
|
Chris@16
|
1076 return;
|
Chris@16
|
1077 }
|
Chris@16
|
1078 }
|
Chris@16
|
1079 std::vector<point_data<Unit> > pts;
|
Chris@16
|
1080 pts.push_back(edgePoint1);
|
Chris@16
|
1081 pts.push_back(second);
|
Chris@16
|
1082 pts.push_back(edgePoint2);
|
Chris@16
|
1083 pts.push_back(getIntersectionPoint(edgePoint1, edge1, edgePoint2, edge2));
|
Chris@16
|
1084 polygon_45_data<Unit> poly(pts.begin(), pts.end());
|
Chris@16
|
1085 sizingSet.insert(poly);
|
Chris@16
|
1086 }
|
Chris@16
|
1087
|
Chris@16
|
1088 template <typename Unit>
|
Chris@16
|
1089 template <typename geometry_type>
|
Chris@16
|
1090 inline polygon_45_set_data<Unit>&
|
Chris@16
|
1091 polygon_45_set_data<Unit>::insert_with_resize_dispatch(const geometry_type& poly,
|
Chris@16
|
1092 coordinate_type resizing,
|
Chris@16
|
1093 RoundingOption rounding,
|
Chris@16
|
1094 CornerOption corner,
|
Chris@16
|
1095 bool hole, polygon_45_concept ) {
|
Chris@16
|
1096 direction_1d wdir = winding(poly);
|
Chris@16
|
1097 int multiplier = wdir == LOW ? -1 : 1;
|
Chris@16
|
1098 if(hole) resizing *= -1;
|
Chris@16
|
1099 typedef typename polygon_45_data<Unit>::iterator_type piterator;
|
Chris@16
|
1100 piterator first, second, third, end, real_end;
|
Chris@16
|
1101 real_end = end_points(poly);
|
Chris@16
|
1102 third = begin_points(poly);
|
Chris@16
|
1103 first = third;
|
Chris@16
|
1104 if(first == real_end) return *this;
|
Chris@16
|
1105 ++third;
|
Chris@16
|
1106 if(third == real_end) return *this;
|
Chris@16
|
1107 second = end = third;
|
Chris@16
|
1108 ++third;
|
Chris@16
|
1109 if(third == real_end) return *this;
|
Chris@16
|
1110 polygon_45_set_data<Unit> sizingSet;
|
Chris@16
|
1111 //insert minkofski shapes on edges and corners
|
Chris@16
|
1112 do {
|
Chris@16
|
1113 if(rounding != SQRT1OVER2) {
|
Chris@16
|
1114 handleResizingEdge45(sizingSet, *first, *second, resizing, rounding);
|
Chris@16
|
1115 } else {
|
Chris@16
|
1116 handleResizingEdge45_SQRT1OVER2(sizingSet, *first, *second, resizing, corner);
|
Chris@16
|
1117 }
|
Chris@16
|
1118 if(corner != UNFILLED)
|
Chris@16
|
1119 handleResizingVertex45(sizingSet, *first, *second, *third, resizing, rounding, corner, multiplier);
|
Chris@16
|
1120 first = second;
|
Chris@16
|
1121 second = third;
|
Chris@16
|
1122 ++third;
|
Chris@16
|
1123 if(third == real_end) {
|
Chris@16
|
1124 third = begin_points(poly);
|
Chris@16
|
1125 if(*second == *third) {
|
Chris@16
|
1126 ++third; //skip first point if it is duplicate of last point
|
Chris@16
|
1127 }
|
Chris@16
|
1128 }
|
Chris@16
|
1129 } while(second != end);
|
Chris@16
|
1130 //sizingSet.snap();
|
Chris@16
|
1131 polygon_45_set_data<Unit> tmp;
|
Chris@16
|
1132 //insert original shape
|
Chris@16
|
1133 tmp.insert_dispatch(poly, false, polygon_45_concept());
|
Chris@16
|
1134 if(resizing < 0) tmp -= sizingSet;
|
Chris@16
|
1135 else tmp += sizingSet;
|
Chris@16
|
1136 tmp.clean();
|
Chris@16
|
1137 insert(tmp, hole);
|
Chris@16
|
1138 dirty_ = true;
|
Chris@16
|
1139 unsorted_ = true;
|
Chris@16
|
1140 return (*this);
|
Chris@16
|
1141 }
|
Chris@16
|
1142
|
Chris@16
|
1143 // accumulate the bloated polygon with holes
|
Chris@16
|
1144 template <typename Unit>
|
Chris@16
|
1145 template <typename geometry_type>
|
Chris@16
|
1146 inline polygon_45_set_data<Unit>&
|
Chris@16
|
1147 polygon_45_set_data<Unit>::insert_with_resize_dispatch(const geometry_type& poly,
|
Chris@16
|
1148 coordinate_type resizing,
|
Chris@16
|
1149 RoundingOption rounding,
|
Chris@16
|
1150 CornerOption corner,
|
Chris@16
|
1151 bool hole, polygon_45_with_holes_concept ) {
|
Chris@16
|
1152 insert_with_resize_dispatch(poly, resizing, rounding, corner, hole, polygon_45_concept());
|
Chris@16
|
1153 for(typename polygon_with_holes_traits<geometry_type>::iterator_holes_type itr =
|
Chris@16
|
1154 begin_holes(poly); itr != end_holes(poly);
|
Chris@16
|
1155 ++itr) {
|
Chris@16
|
1156 insert_with_resize_dispatch(*itr, resizing, rounding, corner, !hole, polygon_45_concept());
|
Chris@16
|
1157 }
|
Chris@16
|
1158 return *this;
|
Chris@16
|
1159 }
|
Chris@16
|
1160
|
Chris@16
|
1161 // transform set
|
Chris@16
|
1162 template <typename Unit>
|
Chris@16
|
1163 template <typename transformation_type>
|
Chris@16
|
1164 inline polygon_45_set_data<Unit>& polygon_45_set_data<Unit>::transform(const transformation_type& tr){
|
Chris@16
|
1165 clean();
|
Chris@16
|
1166 std::vector<polygon_45_with_holes_data<Unit> > polys;
|
Chris@16
|
1167 get(polys);
|
Chris@16
|
1168 for(typename std::vector<polygon_45_with_holes_data<Unit> >::iterator itr = polys.begin();
|
Chris@16
|
1169 itr != polys.end(); ++itr) {
|
Chris@16
|
1170 ::boost::polygon::transform(*itr, tr);
|
Chris@16
|
1171 }
|
Chris@16
|
1172 clear();
|
Chris@16
|
1173 insert(polys.begin(), polys.end());
|
Chris@16
|
1174 dirty_ = true;
|
Chris@16
|
1175 unsorted_ = true;
|
Chris@16
|
1176 return *this;
|
Chris@16
|
1177 }
|
Chris@16
|
1178
|
Chris@16
|
1179 template <typename Unit>
|
Chris@16
|
1180 inline polygon_45_set_data<Unit>& polygon_45_set_data<Unit>::scale_up(typename coordinate_traits<Unit>::unsigned_area_type factor) {
|
Chris@16
|
1181 scale_up_vertex_45_compact_range(data_.begin(), data_.end(), factor);
|
Chris@16
|
1182 return *this;
|
Chris@16
|
1183 }
|
Chris@16
|
1184
|
Chris@16
|
1185 template <typename Unit>
|
Chris@16
|
1186 inline polygon_45_set_data<Unit>& polygon_45_set_data<Unit>::scale_down(typename coordinate_traits<Unit>::unsigned_area_type factor) {
|
Chris@16
|
1187 clean();
|
Chris@16
|
1188 std::vector<polygon_45_with_holes_data<Unit> > polys;
|
Chris@16
|
1189 get_polygons_with_holes(polys);
|
Chris@16
|
1190 for(typename std::vector<polygon_45_with_holes_data<Unit> >::iterator itr = polys.begin();
|
Chris@16
|
1191 itr != polys.end(); ++itr) {
|
Chris@16
|
1192 ::boost::polygon::scale_down(*itr, factor);
|
Chris@16
|
1193 }
|
Chris@16
|
1194 clear();
|
Chris@16
|
1195 insert(polys.begin(), polys.end());
|
Chris@16
|
1196 dirty_ = true;
|
Chris@16
|
1197 unsorted_ = true;
|
Chris@16
|
1198 return *this;
|
Chris@16
|
1199 }
|
Chris@16
|
1200
|
Chris@16
|
1201 template <typename Unit>
|
Chris@16
|
1202 inline polygon_45_set_data<Unit>& polygon_45_set_data<Unit>::scale(double factor) {
|
Chris@16
|
1203 clean();
|
Chris@16
|
1204 std::vector<polygon_45_with_holes_data<Unit> > polys;
|
Chris@16
|
1205 get_polygons_with_holes(polys);
|
Chris@16
|
1206 for(typename std::vector<polygon_45_with_holes_data<Unit> >::iterator itr = polys.begin();
|
Chris@16
|
1207 itr != polys.end(); ++itr) {
|
Chris@16
|
1208 ::boost::polygon::scale(*itr, factor);
|
Chris@16
|
1209 }
|
Chris@16
|
1210 clear();
|
Chris@16
|
1211 insert(polys.begin(), polys.end());
|
Chris@16
|
1212 dirty_ = true;
|
Chris@16
|
1213 unsorted_ = true;
|
Chris@16
|
1214 return *this;
|
Chris@16
|
1215 }
|
Chris@16
|
1216
|
Chris@16
|
1217 template <typename Unit>
|
Chris@16
|
1218 inline bool polygon_45_set_data<Unit>::clean() const {
|
Chris@16
|
1219 if(unsorted_) sort();
|
Chris@16
|
1220 if(dirty_) {
|
Chris@16
|
1221 applyAdaptiveUnary_<0>();
|
Chris@16
|
1222 dirty_ = false;
|
Chris@16
|
1223 }
|
Chris@16
|
1224 return true;
|
Chris@16
|
1225 }
|
Chris@16
|
1226
|
Chris@16
|
1227 template <typename Unit>
|
Chris@16
|
1228 template <int op>
|
Chris@16
|
1229 inline void polygon_45_set_data<Unit>::applyAdaptiveBoolean_(const polygon_45_set_data<Unit>& rvalue) const {
|
Chris@16
|
1230 polygon_45_set_data<Unit> tmp;
|
Chris@16
|
1231 applyAdaptiveBoolean_<op>(tmp, rvalue);
|
Chris@16
|
1232 data_.swap(tmp.data_); //swapping vectors should be constant time operation
|
Chris@16
|
1233 error_data_.swap(tmp.error_data_);
|
Chris@16
|
1234 is_manhattan_ = tmp.is_manhattan_;
|
Chris@16
|
1235 unsorted_ = false;
|
Chris@16
|
1236 dirty_ = false;
|
Chris@16
|
1237 }
|
Chris@16
|
1238
|
Chris@16
|
1239 template <typename Unit2, int op>
|
Chris@16
|
1240 bool applyBoolean45OpOnVectors(std::vector<typename polygon_45_formation<Unit2>::Vertex45Compact>& result_data,
|
Chris@16
|
1241 std::vector<typename polygon_45_formation<Unit2>::Vertex45Compact>& lvalue_data,
|
Chris@16
|
1242 std::vector<typename polygon_45_formation<Unit2>::Vertex45Compact>& rvalue_data
|
Chris@16
|
1243 ) {
|
Chris@16
|
1244 bool result_is_manhattan_ = true;
|
Chris@16
|
1245 typename boolean_op_45<Unit2>::template Scan45<typename boolean_op_45<Unit2>::Count2,
|
Chris@16
|
1246 typename boolean_op_45<Unit2>::template boolean_op_45_output_functor<op> > scan45;
|
Chris@16
|
1247 std::vector<typename boolean_op_45<Unit2>::Vertex45> eventOut;
|
Chris@16
|
1248 typedef std::pair<typename boolean_op_45<Unit2>::Point,
|
Chris@16
|
1249 typename boolean_op_45<Unit2>::template Scan45CountT<typename boolean_op_45<Unit2>::Count2> > Scan45Vertex;
|
Chris@16
|
1250 std::vector<Scan45Vertex> eventIn;
|
Chris@16
|
1251 typedef std::vector<typename polygon_45_formation<Unit2>::Vertex45Compact> value_type;
|
Chris@16
|
1252 typename value_type::const_iterator iter1 = lvalue_data.begin();
|
Chris@16
|
1253 typename value_type::const_iterator iter2 = rvalue_data.begin();
|
Chris@16
|
1254 typename value_type::const_iterator end1 = lvalue_data.end();
|
Chris@16
|
1255 typename value_type::const_iterator end2 = rvalue_data.end();
|
Chris@16
|
1256 const Unit2 UnitMax = (std::numeric_limits<Unit2>::max)();
|
Chris@16
|
1257 Unit2 x = UnitMax;
|
Chris@16
|
1258 while(iter1 != end1 || iter2 != end2) {
|
Chris@16
|
1259 Unit2 currentX = UnitMax;
|
Chris@16
|
1260 if(iter1 != end1) currentX = iter1->pt.x();
|
Chris@16
|
1261 if(iter2 != end2) currentX = (std::min)(currentX, iter2->pt.x());
|
Chris@16
|
1262 if(currentX != x) {
|
Chris@16
|
1263 //std::cout << "SCAN " << currentX << "\n";
|
Chris@16
|
1264 //scan event
|
Chris@16
|
1265 scan45.scan(eventOut, eventIn.begin(), eventIn.end());
|
Chris@16
|
1266 polygon_sort(eventOut.begin(), eventOut.end());
|
Chris@16
|
1267 std::size_t ptCount = 0;
|
Chris@16
|
1268 for(std::size_t i = 0; i < eventOut.size(); ++i) {
|
Chris@16
|
1269 if(!result_data.empty() &&
|
Chris@16
|
1270 result_data.back().pt == eventOut[i].pt) {
|
Chris@16
|
1271 result_data.back().count += eventOut[i];
|
Chris@16
|
1272 ++ptCount;
|
Chris@16
|
1273 } else {
|
Chris@16
|
1274 if(!result_data.empty()) {
|
Chris@16
|
1275 if(result_data.back().count.is_45()) {
|
Chris@16
|
1276 result_is_manhattan_ = false;
|
Chris@16
|
1277 }
|
Chris@16
|
1278 if(ptCount == 2 && result_data.back().count == (typename polygon_45_formation<Unit2>::Vertex45Count(0, 0, 0, 0))) {
|
Chris@16
|
1279 result_data.pop_back();
|
Chris@16
|
1280 }
|
Chris@16
|
1281 }
|
Chris@16
|
1282 result_data.push_back(eventOut[i]);
|
Chris@16
|
1283 ptCount = 1;
|
Chris@16
|
1284 }
|
Chris@16
|
1285 }
|
Chris@16
|
1286 if(ptCount == 2 && result_data.back().count == (typename polygon_45_formation<Unit2>::Vertex45Count(0, 0, 0, 0))) {
|
Chris@16
|
1287 result_data.pop_back();
|
Chris@16
|
1288 }
|
Chris@16
|
1289 eventOut.clear();
|
Chris@16
|
1290 eventIn.clear();
|
Chris@16
|
1291 x = currentX;
|
Chris@16
|
1292 }
|
Chris@16
|
1293 //std::cout << "get next\n";
|
Chris@16
|
1294 if(iter2 != end2 && (iter1 == end1 || iter2->pt.x() < iter1->pt.x() ||
|
Chris@16
|
1295 (iter2->pt.x() == iter1->pt.x() &&
|
Chris@16
|
1296 iter2->pt.y() < iter1->pt.y()) )) {
|
Chris@16
|
1297 //std::cout << "case1 next\n";
|
Chris@16
|
1298 eventIn.push_back(Scan45Vertex
|
Chris@16
|
1299 (iter2->pt,
|
Chris@16
|
1300 typename polygon_45_formation<Unit2>::
|
Chris@16
|
1301 Scan45Count(typename polygon_45_formation<Unit2>::Count2(0, iter2->count[0]),
|
Chris@16
|
1302 typename polygon_45_formation<Unit2>::Count2(0, iter2->count[1]),
|
Chris@16
|
1303 typename polygon_45_formation<Unit2>::Count2(0, iter2->count[2]),
|
Chris@16
|
1304 typename polygon_45_formation<Unit2>::Count2(0, iter2->count[3]))));
|
Chris@16
|
1305 ++iter2;
|
Chris@16
|
1306 } else if(iter1 != end1 && (iter2 == end2 || iter1->pt.x() < iter2->pt.x() ||
|
Chris@16
|
1307 (iter1->pt.x() == iter2->pt.x() &&
|
Chris@16
|
1308 iter1->pt.y() < iter2->pt.y()) )) {
|
Chris@16
|
1309 //std::cout << "case2 next\n";
|
Chris@16
|
1310 eventIn.push_back(Scan45Vertex
|
Chris@16
|
1311 (iter1->pt,
|
Chris@16
|
1312 typename polygon_45_formation<Unit2>::
|
Chris@16
|
1313 Scan45Count(
|
Chris@16
|
1314 typename polygon_45_formation<Unit2>::Count2(iter1->count[0], 0),
|
Chris@16
|
1315 typename polygon_45_formation<Unit2>::Count2(iter1->count[1], 0),
|
Chris@16
|
1316 typename polygon_45_formation<Unit2>::Count2(iter1->count[2], 0),
|
Chris@16
|
1317 typename polygon_45_formation<Unit2>::Count2(iter1->count[3], 0))));
|
Chris@16
|
1318 ++iter1;
|
Chris@16
|
1319 } else {
|
Chris@16
|
1320 //std::cout << "case3 next\n";
|
Chris@16
|
1321 eventIn.push_back(Scan45Vertex
|
Chris@16
|
1322 (iter2->pt,
|
Chris@16
|
1323 typename polygon_45_formation<Unit2>::
|
Chris@16
|
1324 Scan45Count(typename polygon_45_formation<Unit2>::Count2(iter1->count[0],
|
Chris@16
|
1325 iter2->count[0]),
|
Chris@16
|
1326 typename polygon_45_formation<Unit2>::Count2(iter1->count[1],
|
Chris@16
|
1327 iter2->count[1]),
|
Chris@16
|
1328 typename polygon_45_formation<Unit2>::Count2(iter1->count[2],
|
Chris@16
|
1329 iter2->count[2]),
|
Chris@16
|
1330 typename polygon_45_formation<Unit2>::Count2(iter1->count[3],
|
Chris@16
|
1331 iter2->count[3]))));
|
Chris@16
|
1332 ++iter1;
|
Chris@16
|
1333 ++iter2;
|
Chris@16
|
1334 }
|
Chris@16
|
1335 }
|
Chris@16
|
1336 scan45.scan(eventOut, eventIn.begin(), eventIn.end());
|
Chris@16
|
1337 polygon_sort(eventOut.begin(), eventOut.end());
|
Chris@16
|
1338
|
Chris@16
|
1339 std::size_t ptCount = 0;
|
Chris@16
|
1340 for(std::size_t i = 0; i < eventOut.size(); ++i) {
|
Chris@16
|
1341 if(!result_data.empty() &&
|
Chris@16
|
1342 result_data.back().pt == eventOut[i].pt) {
|
Chris@16
|
1343 result_data.back().count += eventOut[i];
|
Chris@16
|
1344 ++ptCount;
|
Chris@16
|
1345 } else {
|
Chris@16
|
1346 if(!result_data.empty()) {
|
Chris@16
|
1347 if(result_data.back().count.is_45()) {
|
Chris@16
|
1348 result_is_manhattan_ = false;
|
Chris@16
|
1349 }
|
Chris@16
|
1350 if(ptCount == 2 && result_data.back().count == (typename polygon_45_formation<Unit2>::Vertex45Count(0, 0, 0, 0))) {
|
Chris@16
|
1351 result_data.pop_back();
|
Chris@16
|
1352 }
|
Chris@16
|
1353 }
|
Chris@16
|
1354 result_data.push_back(eventOut[i]);
|
Chris@16
|
1355 ptCount = 1;
|
Chris@16
|
1356 }
|
Chris@16
|
1357 }
|
Chris@16
|
1358 if(ptCount == 2 && result_data.back().count == (typename polygon_45_formation<Unit2>::Vertex45Count(0, 0, 0, 0))) {
|
Chris@16
|
1359 result_data.pop_back();
|
Chris@16
|
1360 }
|
Chris@16
|
1361 if(!result_data.empty() &&
|
Chris@16
|
1362 result_data.back().count.is_45()) {
|
Chris@16
|
1363 result_is_manhattan_ = false;
|
Chris@16
|
1364 }
|
Chris@16
|
1365 return result_is_manhattan_;
|
Chris@16
|
1366 }
|
Chris@16
|
1367
|
Chris@16
|
1368 template <typename Unit2, int op>
|
Chris@16
|
1369 bool applyUnary45OpOnVectors(std::vector<typename polygon_45_formation<Unit2>::Vertex45Compact>& result_data,
|
Chris@16
|
1370 std::vector<typename polygon_45_formation<Unit2>::Vertex45Compact>& lvalue_data ) {
|
Chris@16
|
1371 bool result_is_manhattan_ = true;
|
Chris@16
|
1372 typename boolean_op_45<Unit2>::template Scan45<typename boolean_op_45<Unit2>::Count1,
|
Chris@16
|
1373 typename boolean_op_45<Unit2>::template unary_op_45_output_functor<op> > scan45;
|
Chris@16
|
1374 std::vector<typename boolean_op_45<Unit2>::Vertex45> eventOut;
|
Chris@16
|
1375 typedef typename boolean_op_45<Unit2>::template Scan45CountT<typename boolean_op_45<Unit2>::Count1> Scan45Count;
|
Chris@16
|
1376 typedef std::pair<typename boolean_op_45<Unit2>::Point, Scan45Count> Scan45Vertex;
|
Chris@16
|
1377 std::vector<Scan45Vertex> eventIn;
|
Chris@16
|
1378 typedef std::vector<typename polygon_45_formation<Unit2>::Vertex45Compact> value_type;
|
Chris@16
|
1379 typename value_type::const_iterator iter1 = lvalue_data.begin();
|
Chris@16
|
1380 typename value_type::const_iterator end1 = lvalue_data.end();
|
Chris@16
|
1381 const Unit2 UnitMax = (std::numeric_limits<Unit2>::max)();
|
Chris@16
|
1382 Unit2 x = UnitMax;
|
Chris@16
|
1383 while(iter1 != end1) {
|
Chris@16
|
1384 Unit2 currentX = iter1->pt.x();
|
Chris@16
|
1385 if(currentX != x) {
|
Chris@16
|
1386 //std::cout << "SCAN " << currentX << "\n";
|
Chris@16
|
1387 //scan event
|
Chris@16
|
1388 scan45.scan(eventOut, eventIn.begin(), eventIn.end());
|
Chris@16
|
1389 polygon_sort(eventOut.begin(), eventOut.end());
|
Chris@16
|
1390 std::size_t ptCount = 0;
|
Chris@16
|
1391 for(std::size_t i = 0; i < eventOut.size(); ++i) {
|
Chris@16
|
1392 if(!result_data.empty() &&
|
Chris@16
|
1393 result_data.back().pt == eventOut[i].pt) {
|
Chris@16
|
1394 result_data.back().count += eventOut[i];
|
Chris@16
|
1395 ++ptCount;
|
Chris@16
|
1396 } else {
|
Chris@16
|
1397 if(!result_data.empty()) {
|
Chris@16
|
1398 if(result_data.back().count.is_45()) {
|
Chris@16
|
1399 result_is_manhattan_ = false;
|
Chris@16
|
1400 }
|
Chris@16
|
1401 if(ptCount == 2 && result_data.back().count == (typename polygon_45_formation<Unit2>::Vertex45Count(0, 0, 0, 0))) {
|
Chris@16
|
1402 result_data.pop_back();
|
Chris@16
|
1403 }
|
Chris@16
|
1404 }
|
Chris@16
|
1405 result_data.push_back(eventOut[i]);
|
Chris@16
|
1406 ptCount = 1;
|
Chris@16
|
1407 }
|
Chris@16
|
1408 }
|
Chris@16
|
1409 if(ptCount == 2 && result_data.back().count == (typename polygon_45_formation<Unit2>::Vertex45Count(0, 0, 0, 0))) {
|
Chris@16
|
1410 result_data.pop_back();
|
Chris@16
|
1411 }
|
Chris@16
|
1412 eventOut.clear();
|
Chris@16
|
1413 eventIn.clear();
|
Chris@16
|
1414 x = currentX;
|
Chris@16
|
1415 }
|
Chris@16
|
1416 //std::cout << "get next\n";
|
Chris@16
|
1417 eventIn.push_back(Scan45Vertex
|
Chris@16
|
1418 (iter1->pt,
|
Chris@16
|
1419 Scan45Count( typename boolean_op_45<Unit2>::Count1(iter1->count[0]),
|
Chris@16
|
1420 typename boolean_op_45<Unit2>::Count1(iter1->count[1]),
|
Chris@16
|
1421 typename boolean_op_45<Unit2>::Count1(iter1->count[2]),
|
Chris@16
|
1422 typename boolean_op_45<Unit2>::Count1(iter1->count[3]))));
|
Chris@16
|
1423 ++iter1;
|
Chris@16
|
1424 }
|
Chris@16
|
1425 scan45.scan(eventOut, eventIn.begin(), eventIn.end());
|
Chris@16
|
1426 polygon_sort(eventOut.begin(), eventOut.end());
|
Chris@16
|
1427
|
Chris@16
|
1428 std::size_t ptCount = 0;
|
Chris@16
|
1429 for(std::size_t i = 0; i < eventOut.size(); ++i) {
|
Chris@16
|
1430 if(!result_data.empty() &&
|
Chris@16
|
1431 result_data.back().pt == eventOut[i].pt) {
|
Chris@16
|
1432 result_data.back().count += eventOut[i];
|
Chris@16
|
1433 ++ptCount;
|
Chris@16
|
1434 } else {
|
Chris@16
|
1435 if(!result_data.empty()) {
|
Chris@16
|
1436 if(result_data.back().count.is_45()) {
|
Chris@16
|
1437 result_is_manhattan_ = false;
|
Chris@16
|
1438 }
|
Chris@16
|
1439 if(ptCount == 2 && result_data.back().count == (typename polygon_45_formation<Unit2>::Vertex45Count(0, 0, 0, 0))) {
|
Chris@16
|
1440 result_data.pop_back();
|
Chris@16
|
1441 }
|
Chris@16
|
1442 }
|
Chris@16
|
1443 result_data.push_back(eventOut[i]);
|
Chris@16
|
1444 ptCount = 1;
|
Chris@16
|
1445 }
|
Chris@16
|
1446 }
|
Chris@16
|
1447 if(ptCount == 2 && result_data.back().count == (typename polygon_45_formation<Unit2>::Vertex45Count(0, 0, 0, 0))) {
|
Chris@16
|
1448 result_data.pop_back();
|
Chris@16
|
1449 }
|
Chris@16
|
1450 if(!result_data.empty() &&
|
Chris@16
|
1451 result_data.back().count.is_45()) {
|
Chris@16
|
1452 result_is_manhattan_ = false;
|
Chris@16
|
1453 }
|
Chris@16
|
1454 return result_is_manhattan_;
|
Chris@16
|
1455 }
|
Chris@16
|
1456
|
Chris@16
|
1457 template <typename cT, typename iT>
|
Chris@16
|
1458 void get_error_rects_shell(cT& posE, cT& negE, iT beginr, iT endr) {
|
Chris@16
|
1459 typedef typename std::iterator_traits<iT>::value_type Point;
|
Chris@16
|
1460 typedef typename point_traits<Point>::coordinate_type Unit;
|
Chris@16
|
1461 typedef typename coordinate_traits<Unit>::area_type area_type;
|
Chris@16
|
1462 Point pt1, pt2, pt3;
|
Chris@16
|
1463 bool i1 = true;
|
Chris@16
|
1464 bool i2 = true;
|
Chris@16
|
1465 bool not_done = beginr != endr;
|
Chris@16
|
1466 bool next_to_last = false;
|
Chris@16
|
1467 bool last = false;
|
Chris@16
|
1468 Point first, second;
|
Chris@16
|
1469 while(not_done) {
|
Chris@16
|
1470 if(last) {
|
Chris@16
|
1471 last = false;
|
Chris@16
|
1472 not_done = false;
|
Chris@16
|
1473 pt3 = second;
|
Chris@16
|
1474 } else if(next_to_last) {
|
Chris@16
|
1475 next_to_last = false;
|
Chris@16
|
1476 last = true;
|
Chris@16
|
1477 pt3 = first;
|
Chris@16
|
1478 } else if(i1) {
|
Chris@16
|
1479 const Point& pt = *beginr;
|
Chris@16
|
1480 first = pt1 = pt;
|
Chris@16
|
1481 i1 = false;
|
Chris@16
|
1482 i2 = true;
|
Chris@16
|
1483 ++beginr;
|
Chris@16
|
1484 if(beginr == endr) return; //too few points
|
Chris@16
|
1485 continue;
|
Chris@16
|
1486 } else if (i2) {
|
Chris@16
|
1487 const Point& pt = *beginr;
|
Chris@16
|
1488 second = pt2 = pt;
|
Chris@16
|
1489 i2 = false;
|
Chris@16
|
1490 ++beginr;
|
Chris@16
|
1491 if(beginr == endr) return; //too few points
|
Chris@16
|
1492 continue;
|
Chris@16
|
1493 } else {
|
Chris@16
|
1494 const Point& pt = *beginr;
|
Chris@16
|
1495 pt3 = pt;
|
Chris@16
|
1496 ++beginr;
|
Chris@16
|
1497 if(beginr == endr) {
|
Chris@16
|
1498 next_to_last = true;
|
Chris@16
|
1499 //skip last point equal to first
|
Chris@16
|
1500 continue;
|
Chris@16
|
1501 }
|
Chris@16
|
1502 }
|
Chris@16
|
1503 if(local_abs(x(pt2)) % 2) { //y % 2 should also be odd
|
Chris@16
|
1504 //is corner concave or convex?
|
Chris@16
|
1505 Point pts[] = {pt1, pt2, pt3};
|
Chris@16
|
1506 area_type ar = point_sequence_area<Point*, area_type>(pts, pts+3);
|
Chris@16
|
1507 direction_1d dir = ar < 0 ? COUNTERCLOCKWISE : CLOCKWISE;
|
Chris@16
|
1508 //std::cout << pt1 << " " << pt2 << " " << pt3 << " " << ar << std::endl;
|
Chris@16
|
1509 if(dir == CLOCKWISE) {
|
Chris@16
|
1510 posE.push_back(rectangle_data<typename Point::coordinate_type>
|
Chris@16
|
1511 (x(pt2) - 1, y(pt2) - 1, x(pt2) + 1, y(pt2) + 1));
|
Chris@16
|
1512
|
Chris@16
|
1513 } else {
|
Chris@16
|
1514 negE.push_back(rectangle_data<typename Point::coordinate_type>
|
Chris@16
|
1515 (x(pt2) - 1, y(pt2) - 1, x(pt2) + 1, y(pt2) + 1));
|
Chris@16
|
1516 }
|
Chris@16
|
1517 }
|
Chris@16
|
1518 pt1 = pt2;
|
Chris@16
|
1519 pt2 = pt3;
|
Chris@16
|
1520 }
|
Chris@16
|
1521 }
|
Chris@16
|
1522
|
Chris@16
|
1523 template <typename cT, typename pT>
|
Chris@16
|
1524 void get_error_rects(cT& posE, cT& negE, const pT& p) {
|
Chris@16
|
1525 get_error_rects_shell(posE, negE, p.begin(), p.end());
|
Chris@16
|
1526 for(typename pT::iterator_holes_type iHb = p.begin_holes();
|
Chris@16
|
1527 iHb != p.end_holes(); ++iHb) {
|
Chris@16
|
1528 get_error_rects_shell(posE, negE, iHb->begin(), iHb->end());
|
Chris@16
|
1529 }
|
Chris@16
|
1530 }
|
Chris@16
|
1531
|
Chris@16
|
1532 template <typename Unit>
|
Chris@16
|
1533 template <int op>
|
Chris@16
|
1534 inline void polygon_45_set_data<Unit>::applyAdaptiveBoolean_(polygon_45_set_data<Unit>& result,
|
Chris@16
|
1535 const polygon_45_set_data<Unit>& rvalue) const {
|
Chris@16
|
1536 result.clear();
|
Chris@16
|
1537 result.error_data_ = error_data_;
|
Chris@16
|
1538 result.error_data_.insert(result.error_data_.end(), rvalue.error_data_.begin(),
|
Chris@16
|
1539 rvalue.error_data_.end());
|
Chris@16
|
1540 if(is_manhattan() && rvalue.is_manhattan()) {
|
Chris@16
|
1541 //convert each into polygon_90_set data and call boolean operations
|
Chris@16
|
1542 polygon_90_set_data<Unit> l90sd(VERTICAL), r90sd(VERTICAL), output(VERTICAL);
|
Chris@16
|
1543 for(typename value_type::const_iterator itr = data_.begin(); itr != data_.end(); ++itr) {
|
Chris@16
|
1544 if((*itr).count[3] == 0) continue; //skip all non vertical edges
|
Chris@16
|
1545 l90sd.insert(std::make_pair((*itr).pt.x(), std::make_pair<Unit, int>((*itr).pt.y(), (*itr).count[3])), false, VERTICAL);
|
Chris@16
|
1546 }
|
Chris@16
|
1547 for(typename value_type::const_iterator itr = rvalue.data_.begin(); itr != rvalue.data_.end(); ++itr) {
|
Chris@16
|
1548 if((*itr).count[3] == 0) continue; //skip all non vertical edges
|
Chris@16
|
1549 r90sd.insert(std::make_pair((*itr).pt.x(), std::make_pair<Unit, int>((*itr).pt.y(), (*itr).count[3])), false, VERTICAL);
|
Chris@16
|
1550 }
|
Chris@16
|
1551 l90sd.sort();
|
Chris@16
|
1552 r90sd.sort();
|
Chris@16
|
1553 #ifdef BOOST_POLYGON_MSVC
|
Chris@16
|
1554 #pragma warning (push)
|
Chris@16
|
1555 #pragma warning (disable: 4127)
|
Chris@16
|
1556 #endif
|
Chris@16
|
1557 if(op == 0) {
|
Chris@16
|
1558 output.applyBooleanBinaryOp(l90sd.begin(), l90sd.end(),
|
Chris@16
|
1559 r90sd.begin(), r90sd.end(), boolean_op::BinaryCount<boolean_op::BinaryOr>());
|
Chris@16
|
1560 } else if (op == 1) {
|
Chris@16
|
1561 output.applyBooleanBinaryOp(l90sd.begin(), l90sd.end(),
|
Chris@16
|
1562 r90sd.begin(), r90sd.end(), boolean_op::BinaryCount<boolean_op::BinaryAnd>());
|
Chris@16
|
1563 } else if (op == 2) {
|
Chris@16
|
1564 output.applyBooleanBinaryOp(l90sd.begin(), l90sd.end(),
|
Chris@16
|
1565 r90sd.begin(), r90sd.end(), boolean_op::BinaryCount<boolean_op::BinaryNot>());
|
Chris@16
|
1566 } else if (op == 3) {
|
Chris@16
|
1567 output.applyBooleanBinaryOp(l90sd.begin(), l90sd.end(),
|
Chris@16
|
1568 r90sd.begin(), r90sd.end(), boolean_op::BinaryCount<boolean_op::BinaryXor>());
|
Chris@16
|
1569 }
|
Chris@16
|
1570 #ifdef BOOST_POLYGON_MSVC
|
Chris@16
|
1571 #pragma warning (pop)
|
Chris@16
|
1572 #endif
|
Chris@16
|
1573 result.data_.clear();
|
Chris@16
|
1574 result.insert(output);
|
Chris@16
|
1575 result.is_manhattan_ = true;
|
Chris@16
|
1576 result.dirty_ = false;
|
Chris@16
|
1577 result.unsorted_ = false;
|
Chris@16
|
1578 } else {
|
Chris@16
|
1579 sort();
|
Chris@16
|
1580 rvalue.sort();
|
Chris@16
|
1581 try {
|
Chris@16
|
1582 result.is_manhattan_ = applyBoolean45OpOnVectors<Unit, op>(result.data_, data_, rvalue.data_);
|
Chris@16
|
1583 } catch (std::string str) {
|
Chris@16
|
1584 std::string msg = "GTL 45 Boolean error, precision insufficient to represent edge intersection coordinate value.";
|
Chris@16
|
1585 if(str == msg) {
|
Chris@16
|
1586 result.clear();
|
Chris@16
|
1587 typedef typename coordinate_traits<Unit>::manhattan_area_type Unit2;
|
Chris@16
|
1588 typedef typename polygon_45_formation<Unit2>::Vertex45Compact Vertex45Compact2;
|
Chris@16
|
1589 typedef std::vector<Vertex45Compact2> Data2;
|
Chris@16
|
1590 Data2 rvalue_data, lvalue_data, result_data;
|
Chris@16
|
1591 rvalue_data.reserve(rvalue.data_.size());
|
Chris@16
|
1592 lvalue_data.reserve(data_.size());
|
Chris@16
|
1593 for(std::size_t i = 0 ; i < data_.size(); ++i) {
|
Chris@16
|
1594 const Vertex45Compact& vi = data_[i];
|
Chris@16
|
1595 Vertex45Compact2 ci;
|
Chris@16
|
1596 ci.pt = point_data<Unit2>(x(vi.pt), y(vi.pt));
|
Chris@16
|
1597 ci.count = typename polygon_45_formation<Unit2>::Vertex45Count
|
Chris@16
|
1598 ( vi.count[0], vi.count[1], vi.count[2], vi.count[3]);
|
Chris@16
|
1599 lvalue_data.push_back(ci);
|
Chris@16
|
1600 }
|
Chris@16
|
1601 for(std::size_t i = 0 ; i < rvalue.data_.size(); ++i) {
|
Chris@16
|
1602 const Vertex45Compact& vi = rvalue.data_[i];
|
Chris@16
|
1603 Vertex45Compact2 ci;
|
Chris@16
|
1604 ci.pt = (point_data<Unit2>(x(vi.pt), y(vi.pt)));
|
Chris@16
|
1605 ci.count = typename polygon_45_formation<Unit2>::Vertex45Count
|
Chris@16
|
1606 ( vi.count[0], vi.count[1], vi.count[2], vi.count[3]);
|
Chris@16
|
1607 rvalue_data.push_back(ci);
|
Chris@16
|
1608 }
|
Chris@16
|
1609 scale_up_vertex_45_compact_range(lvalue_data.begin(), lvalue_data.end(), 2);
|
Chris@16
|
1610 scale_up_vertex_45_compact_range(rvalue_data.begin(), rvalue_data.end(), 2);
|
Chris@16
|
1611 bool result_is_manhattan = applyBoolean45OpOnVectors<Unit2, op>(result_data,
|
Chris@16
|
1612 lvalue_data,
|
Chris@16
|
1613 rvalue_data );
|
Chris@16
|
1614 if(!result_is_manhattan) {
|
Chris@16
|
1615 typename polygon_45_formation<Unit2>::Polygon45Formation pf(false);
|
Chris@16
|
1616 //std::cout << "FORMING POLYGONS\n";
|
Chris@16
|
1617 std::vector<polygon_45_with_holes_data<Unit2> > container;
|
Chris@16
|
1618 pf.scan(container, result_data.begin(), result_data.end());
|
Chris@16
|
1619 Data2 error_data_out;
|
Chris@16
|
1620 std::vector<rectangle_data<Unit2> > pos_error_rects;
|
Chris@16
|
1621 std::vector<rectangle_data<Unit2> > neg_error_rects;
|
Chris@16
|
1622 for(std::size_t i = 0; i < container.size(); ++i) {
|
Chris@16
|
1623 get_error_rects(pos_error_rects, neg_error_rects, container[i]);
|
Chris@16
|
1624 }
|
Chris@16
|
1625 for(std::size_t i = 0; i < pos_error_rects.size(); ++i) {
|
Chris@16
|
1626 insert_rectangle_into_vector_45(result_data, pos_error_rects[i], false);
|
Chris@16
|
1627 insert_rectangle_into_vector_45(error_data_out, pos_error_rects[i], false);
|
Chris@16
|
1628 }
|
Chris@16
|
1629 for(std::size_t i = 0; i < neg_error_rects.size(); ++i) {
|
Chris@16
|
1630 insert_rectangle_into_vector_45(result_data, neg_error_rects[i], true);
|
Chris@16
|
1631 insert_rectangle_into_vector_45(error_data_out, neg_error_rects[i], false);
|
Chris@16
|
1632 }
|
Chris@16
|
1633 scale_down_vertex_45_compact_range_blindly(error_data_out.begin(), error_data_out.end(), 2);
|
Chris@16
|
1634 for(std::size_t i = 0 ; i < error_data_out.size(); ++i) {
|
Chris@16
|
1635 const Vertex45Compact2& vi = error_data_out[i];
|
Chris@16
|
1636 Vertex45Compact ci;
|
Chris@16
|
1637 ci.pt.x(static_cast<Unit>(x(vi.pt)));
|
Chris@16
|
1638 ci.pt.y(static_cast<Unit>(y(vi.pt)));
|
Chris@16
|
1639 ci.count = typename polygon_45_formation<Unit>::Vertex45Count
|
Chris@16
|
1640 ( vi.count[0], vi.count[1], vi.count[2], vi.count[3]);
|
Chris@16
|
1641 result.error_data_.push_back(ci);
|
Chris@16
|
1642 }
|
Chris@16
|
1643 Data2 new_result_data;
|
Chris@16
|
1644 polygon_sort(result_data.begin(), result_data.end());
|
Chris@16
|
1645 applyUnary45OpOnVectors<Unit2, 0>(new_result_data, result_data); //OR operation
|
Chris@16
|
1646 result_data.swap(new_result_data);
|
Chris@16
|
1647 }
|
Chris@16
|
1648 scale_down_vertex_45_compact_range_blindly(result_data.begin(), result_data.end(), 2);
|
Chris@16
|
1649 //result.data_.reserve(result_data.size());
|
Chris@16
|
1650 for(std::size_t i = 0 ; i < result_data.size(); ++i) {
|
Chris@16
|
1651 const Vertex45Compact2& vi = result_data[i];
|
Chris@16
|
1652 Vertex45Compact ci;
|
Chris@16
|
1653 ci.pt.x(static_cast<Unit>(x(vi.pt)));
|
Chris@16
|
1654 ci.pt.y(static_cast<Unit>(y(vi.pt)));
|
Chris@16
|
1655 ci.count = typename polygon_45_formation<Unit>::Vertex45Count
|
Chris@16
|
1656 ( vi.count[0], vi.count[1], vi.count[2], vi.count[3]);
|
Chris@16
|
1657 result.data_.push_back(ci);
|
Chris@16
|
1658 }
|
Chris@16
|
1659 result.is_manhattan_ = result_is_manhattan;
|
Chris@16
|
1660 result.dirty_ = false;
|
Chris@16
|
1661 result.unsorted_ = false;
|
Chris@16
|
1662 } else { throw str; }
|
Chris@16
|
1663 }
|
Chris@16
|
1664 //std::cout << "DONE SCANNING\n";
|
Chris@16
|
1665 }
|
Chris@16
|
1666 }
|
Chris@16
|
1667
|
Chris@16
|
1668 template <typename Unit>
|
Chris@16
|
1669 template <int op>
|
Chris@16
|
1670 inline void polygon_45_set_data<Unit>::applyAdaptiveUnary_() const {
|
Chris@16
|
1671 polygon_45_set_data<Unit> result;
|
Chris@16
|
1672 result.error_data_ = error_data_;
|
Chris@16
|
1673 if(is_manhattan()) {
|
Chris@16
|
1674 //convert each into polygon_90_set data and call boolean operations
|
Chris@16
|
1675 polygon_90_set_data<Unit> l90sd(VERTICAL);
|
Chris@16
|
1676 for(typename value_type::const_iterator itr = data_.begin(); itr != data_.end(); ++itr) {
|
Chris@16
|
1677 if((*itr).count[3] == 0) continue; //skip all non vertical edges
|
Chris@16
|
1678 l90sd.insert(std::make_pair((*itr).pt.x(), std::make_pair<Unit, int>((*itr).pt.y(), (*itr).count[3])), false, VERTICAL);
|
Chris@16
|
1679 }
|
Chris@16
|
1680 l90sd.sort();
|
Chris@16
|
1681 #ifdef BOOST_POLYGON_MSVC
|
Chris@16
|
1682 #pragma warning (push)
|
Chris@16
|
1683 #pragma warning (disable: 4127)
|
Chris@16
|
1684 #endif
|
Chris@16
|
1685 if(op == 0) {
|
Chris@16
|
1686 l90sd.clean();
|
Chris@16
|
1687 } else if (op == 1) {
|
Chris@16
|
1688 l90sd.self_intersect();
|
Chris@16
|
1689 } else if (op == 3) {
|
Chris@16
|
1690 l90sd.self_xor();
|
Chris@16
|
1691 }
|
Chris@16
|
1692 #ifdef BOOST_POLYGON_MSVC
|
Chris@16
|
1693 #pragma warning (pop)
|
Chris@16
|
1694 #endif
|
Chris@16
|
1695 result.data_.clear();
|
Chris@16
|
1696 result.insert(l90sd);
|
Chris@16
|
1697 result.is_manhattan_ = true;
|
Chris@16
|
1698 result.dirty_ = false;
|
Chris@16
|
1699 result.unsorted_ = false;
|
Chris@16
|
1700 } else {
|
Chris@16
|
1701 sort();
|
Chris@16
|
1702 try {
|
Chris@16
|
1703 result.is_manhattan_ = applyUnary45OpOnVectors<Unit, op>(result.data_, data_);
|
Chris@16
|
1704 } catch (std::string str) {
|
Chris@16
|
1705 std::string msg = "GTL 45 Boolean error, precision insufficient to represent edge intersection coordinate value.";
|
Chris@16
|
1706 if(str == msg) {
|
Chris@16
|
1707 result.clear();
|
Chris@16
|
1708 typedef typename coordinate_traits<Unit>::manhattan_area_type Unit2;
|
Chris@16
|
1709 typedef typename polygon_45_formation<Unit2>::Vertex45Compact Vertex45Compact2;
|
Chris@16
|
1710 typedef std::vector<Vertex45Compact2> Data2;
|
Chris@16
|
1711 Data2 lvalue_data, result_data;
|
Chris@16
|
1712 lvalue_data.reserve(data_.size());
|
Chris@16
|
1713 for(std::size_t i = 0 ; i < data_.size(); ++i) {
|
Chris@16
|
1714 const Vertex45Compact& vi = data_[i];
|
Chris@16
|
1715 Vertex45Compact2 ci;
|
Chris@16
|
1716 ci.pt.x(static_cast<Unit>(x(vi.pt)));
|
Chris@16
|
1717 ci.pt.y(static_cast<Unit>(y(vi.pt)));
|
Chris@16
|
1718 ci.count = typename polygon_45_formation<Unit2>::Vertex45Count
|
Chris@16
|
1719 ( vi.count[0], vi.count[1], vi.count[2], vi.count[3]);
|
Chris@16
|
1720 lvalue_data.push_back(ci);
|
Chris@16
|
1721 }
|
Chris@16
|
1722 scale_up_vertex_45_compact_range(lvalue_data.begin(), lvalue_data.end(), 2);
|
Chris@16
|
1723 bool result_is_manhattan = applyUnary45OpOnVectors<Unit2, op>(result_data,
|
Chris@16
|
1724 lvalue_data );
|
Chris@16
|
1725 if(!result_is_manhattan) {
|
Chris@16
|
1726 typename polygon_45_formation<Unit2>::Polygon45Formation pf(false);
|
Chris@16
|
1727 //std::cout << "FORMING POLYGONS\n";
|
Chris@16
|
1728 std::vector<polygon_45_with_holes_data<Unit2> > container;
|
Chris@16
|
1729 pf.scan(container, result_data.begin(), result_data.end());
|
Chris@16
|
1730 Data2 error_data_out;
|
Chris@16
|
1731 std::vector<rectangle_data<Unit2> > pos_error_rects;
|
Chris@16
|
1732 std::vector<rectangle_data<Unit2> > neg_error_rects;
|
Chris@16
|
1733 for(std::size_t i = 0; i < container.size(); ++i) {
|
Chris@16
|
1734 get_error_rects(pos_error_rects, neg_error_rects, container[i]);
|
Chris@16
|
1735 }
|
Chris@16
|
1736 for(std::size_t i = 0; i < pos_error_rects.size(); ++i) {
|
Chris@16
|
1737 insert_rectangle_into_vector_45(result_data, pos_error_rects[i], false);
|
Chris@16
|
1738 insert_rectangle_into_vector_45(error_data_out, pos_error_rects[i], false);
|
Chris@16
|
1739 }
|
Chris@16
|
1740 for(std::size_t i = 0; i < neg_error_rects.size(); ++i) {
|
Chris@16
|
1741 insert_rectangle_into_vector_45(result_data, neg_error_rects[i], true);
|
Chris@16
|
1742 insert_rectangle_into_vector_45(error_data_out, neg_error_rects[i], false);
|
Chris@16
|
1743 }
|
Chris@16
|
1744 scale_down_vertex_45_compact_range_blindly(error_data_out.begin(), error_data_out.end(), 2);
|
Chris@16
|
1745 for(std::size_t i = 0 ; i < error_data_out.size(); ++i) {
|
Chris@16
|
1746 const Vertex45Compact2& vi = error_data_out[i];
|
Chris@16
|
1747 Vertex45Compact ci;
|
Chris@16
|
1748 ci.pt.x(static_cast<Unit>(x(vi.pt)));
|
Chris@16
|
1749 ci.pt.y(static_cast<Unit>(y(vi.pt)));
|
Chris@16
|
1750 ci.count = typename polygon_45_formation<Unit>::Vertex45Count
|
Chris@16
|
1751 ( vi.count[0], vi.count[1], vi.count[2], vi.count[3]);
|
Chris@16
|
1752 result.error_data_.push_back(ci);
|
Chris@16
|
1753 }
|
Chris@16
|
1754 Data2 new_result_data;
|
Chris@16
|
1755 polygon_sort(result_data.begin(), result_data.end());
|
Chris@16
|
1756 applyUnary45OpOnVectors<Unit2, 0>(new_result_data, result_data); //OR operation
|
Chris@16
|
1757 result_data.swap(new_result_data);
|
Chris@16
|
1758 }
|
Chris@16
|
1759 scale_down_vertex_45_compact_range_blindly(result_data.begin(), result_data.end(), 2);
|
Chris@16
|
1760 //result.data_.reserve(result_data.size());
|
Chris@16
|
1761 for(std::size_t i = 0 ; i < result_data.size(); ++i) {
|
Chris@16
|
1762 const Vertex45Compact2& vi = result_data[i];
|
Chris@16
|
1763 Vertex45Compact ci;
|
Chris@16
|
1764 ci.pt.x(static_cast<Unit>(x(vi.pt)));
|
Chris@16
|
1765 ci.pt.y(static_cast<Unit>(y(vi.pt)));
|
Chris@16
|
1766 ci.count = typename polygon_45_formation<Unit>::Vertex45Count
|
Chris@16
|
1767 ( vi.count[0], vi.count[1], vi.count[2], vi.count[3]);
|
Chris@16
|
1768 result.data_.push_back(ci);
|
Chris@16
|
1769 }
|
Chris@16
|
1770 result.is_manhattan_ = result_is_manhattan;
|
Chris@16
|
1771 result.dirty_ = false;
|
Chris@16
|
1772 result.unsorted_ = false;
|
Chris@16
|
1773 } else { throw str; }
|
Chris@16
|
1774 }
|
Chris@16
|
1775 //std::cout << "DONE SCANNING\n";
|
Chris@16
|
1776 }
|
Chris@16
|
1777 data_.swap(result.data_);
|
Chris@16
|
1778 error_data_.swap(result.error_data_);
|
Chris@16
|
1779 dirty_ = result.dirty_;
|
Chris@16
|
1780 unsorted_ = result.unsorted_;
|
Chris@16
|
1781 is_manhattan_ = result.is_manhattan_;
|
Chris@16
|
1782 }
|
Chris@16
|
1783
|
Chris@16
|
1784 template <typename coordinate_type, typename property_type>
|
Chris@16
|
1785 class property_merge_45 {
|
Chris@16
|
1786 private:
|
Chris@16
|
1787 typedef typename coordinate_traits<coordinate_type>::manhattan_area_type big_coord;
|
Chris@16
|
1788 typedef typename polygon_45_property_merge<big_coord, property_type>::MergeSetData tsd;
|
Chris@16
|
1789 tsd tsd_;
|
Chris@16
|
1790 public:
|
Chris@16
|
1791 inline property_merge_45() : tsd_() {}
|
Chris@16
|
1792 inline property_merge_45(const property_merge_45& that) : tsd_(that.tsd_) {}
|
Chris@16
|
1793 inline property_merge_45& operator=(const property_merge_45& that) {
|
Chris@16
|
1794 tsd_ = that.tsd_;
|
Chris@16
|
1795 return *this;
|
Chris@16
|
1796 }
|
Chris@16
|
1797
|
Chris@16
|
1798 inline void insert(const polygon_45_set_data<coordinate_type>& ps, property_type property) {
|
Chris@16
|
1799 ps.clean();
|
Chris@16
|
1800 polygon_45_property_merge<big_coord, property_type>::populateMergeSetData(tsd_, ps.begin(), ps.end(), property);
|
Chris@16
|
1801 }
|
Chris@16
|
1802 template <class GeoObjT>
|
Chris@16
|
1803 inline void insert(const GeoObjT& geoObj, property_type property) {
|
Chris@16
|
1804 polygon_45_set_data<coordinate_type> ps;
|
Chris@16
|
1805 ps.insert(geoObj);
|
Chris@16
|
1806 insert(ps, property);
|
Chris@16
|
1807 }
|
Chris@16
|
1808
|
Chris@16
|
1809 //merge properties of input geometries and store the resulting geometries of regions
|
Chris@16
|
1810 //with unique sets of merged properties to polygons sets in a map keyed by sets of properties
|
Chris@16
|
1811 // T = std::map<std::set<property_type>, polygon_45_set_data<coordiante_type> > or
|
Chris@16
|
1812 // T = std::map<std::vector<property_type>, polygon_45_set_data<coordiante_type> >
|
Chris@16
|
1813 template <class result_type>
|
Chris@16
|
1814 inline void merge(result_type& result) {
|
Chris@16
|
1815 typedef typename result_type::key_type keytype;
|
Chris@16
|
1816 typedef std::map<keytype, polygon_45_set_data<big_coord> > bigtype;
|
Chris@16
|
1817 bigtype result_big;
|
Chris@16
|
1818 polygon_45_property_merge<big_coord, property_type>::performMerge(result_big, tsd_);
|
Chris@16
|
1819 std::vector<polygon_45_with_holes_data<big_coord> > polys;
|
Chris@16
|
1820 std::vector<rectangle_data<big_coord> > pos_error_rects;
|
Chris@16
|
1821 std::vector<rectangle_data<big_coord> > neg_error_rects;
|
Chris@16
|
1822 for(typename std::map<keytype, polygon_45_set_data<big_coord> >::iterator itr = result_big.begin();
|
Chris@16
|
1823 itr != result_big.end(); ++itr) {
|
Chris@16
|
1824 polys.clear();
|
Chris@16
|
1825 (*itr).second.get(polys);
|
Chris@16
|
1826 for(std::size_t i = 0; i < polys.size(); ++i) {
|
Chris@16
|
1827 get_error_rects(pos_error_rects, neg_error_rects, polys[i]);
|
Chris@16
|
1828 }
|
Chris@16
|
1829 (*itr).second += pos_error_rects;
|
Chris@16
|
1830 (*itr).second -= neg_error_rects;
|
Chris@16
|
1831 (*itr).second.scale_down(2);
|
Chris@16
|
1832 result[(*itr).first].insert((*itr).second);
|
Chris@16
|
1833 }
|
Chris@16
|
1834 }
|
Chris@16
|
1835 };
|
Chris@16
|
1836
|
Chris@16
|
1837 //ConnectivityExtraction computes the graph of connectivity between rectangle, polygon and
|
Chris@16
|
1838 //polygon set graph nodes where an edge is created whenever the geometry in two nodes overlap
|
Chris@16
|
1839 template <typename coordinate_type>
|
Chris@16
|
1840 class connectivity_extraction_45 {
|
Chris@16
|
1841 private:
|
Chris@16
|
1842 typedef typename coordinate_traits<coordinate_type>::manhattan_area_type big_coord;
|
Chris@16
|
1843 typedef typename polygon_45_touch<big_coord>::TouchSetData tsd;
|
Chris@16
|
1844 tsd tsd_;
|
Chris@16
|
1845 unsigned int nodeCount_;
|
Chris@16
|
1846 public:
|
Chris@16
|
1847 inline connectivity_extraction_45() : tsd_(), nodeCount_(0) {}
|
Chris@16
|
1848 inline connectivity_extraction_45(const connectivity_extraction_45& that) : tsd_(that.tsd_),
|
Chris@16
|
1849 nodeCount_(that.nodeCount_) {}
|
Chris@16
|
1850 inline connectivity_extraction_45& operator=(const connectivity_extraction_45& that) {
|
Chris@16
|
1851 tsd_ = that.tsd_;
|
Chris@16
|
1852 nodeCount_ = that.nodeCount_; {}
|
Chris@16
|
1853 return *this;
|
Chris@16
|
1854 }
|
Chris@16
|
1855
|
Chris@16
|
1856 //insert a polygon set graph node, the value returned is the id of the graph node
|
Chris@16
|
1857 inline unsigned int insert(const polygon_45_set_data<coordinate_type>& ps) {
|
Chris@16
|
1858 ps.clean();
|
Chris@16
|
1859 polygon_45_touch<big_coord>::populateTouchSetData(tsd_, ps.begin(), ps.end(), nodeCount_);
|
Chris@16
|
1860 return nodeCount_++;
|
Chris@16
|
1861 }
|
Chris@16
|
1862 template <class GeoObjT>
|
Chris@16
|
1863 inline unsigned int insert(const GeoObjT& geoObj) {
|
Chris@16
|
1864 polygon_45_set_data<coordinate_type> ps;
|
Chris@16
|
1865 ps.insert(geoObj);
|
Chris@16
|
1866 return insert(ps);
|
Chris@16
|
1867 }
|
Chris@16
|
1868
|
Chris@16
|
1869 //extract connectivity and store the edges in the graph
|
Chris@16
|
1870 //graph must be indexable by graph node id and the indexed value must be a std::set of
|
Chris@16
|
1871 //graph node id
|
Chris@16
|
1872 template <class GraphT>
|
Chris@16
|
1873 inline void extract(GraphT& graph) {
|
Chris@16
|
1874 polygon_45_touch<big_coord>::performTouch(graph, tsd_);
|
Chris@16
|
1875 }
|
Chris@16
|
1876 };
|
Chris@16
|
1877 }
|
Chris@16
|
1878 }
|
Chris@16
|
1879 #endif
|
Chris@16
|
1880
|