1 #pragma once
2
3 #include <assert.h>
4 #include <cmath>
5 #include <deque>
6 #include <list>
7 #include <map>
8 #include <mapbox/geometry/box.hpp>
9 #include <mapbox/geometry/wagyu/point.hpp>
10 #include <set>
11 #include <sstream>
12 #include <vector>
13
14 #ifdef DEBUG
15 #include <execinfo.h>
16 #include <iostream>
17 #include <sstream>
18 #include <stdio.h>
19 //
20 // void* callstack[128];
21 // int i, frames = backtrace(callstack, 128);
22 // char** strs = backtrace_symbols(callstack, frames);
23 // for (i = 0; i < frames; ++i) {
24 // printf("%s\n", strs[i]);
25 // }
26 // free(strs);
27 #endif
28
29 namespace mapbox {
30 namespace geometry {
31 namespace wagyu {
32
33 template <typename T>
area_from_point(point_ptr<T> op,std::size_t & size,mapbox::geometry::box<T> & bbox)34 double area_from_point(point_ptr<T> op, std::size_t& size, mapbox::geometry::box<T>& bbox) {
35 point_ptr<T> startOp = op;
36 size = 0;
37 double a = 0.0;
38 T min_x = op->x;
39 T max_x = op->x;
40 T min_y = op->y;
41 T max_y = op->y;
42 do {
43 ++size;
44 if (op->x > max_x) {
45 max_x = op->x;
46 } else if (op->x < min_x) {
47 min_x = op->x;
48 }
49 if (op->y > max_y) {
50 max_y = op->y;
51 } else if (op->y < min_y) {
52 min_y = op->y;
53 }
54 a += static_cast<double>(op->prev->x + op->x) * static_cast<double>(op->prev->y - op->y);
55 op = op->next;
56 } while (op != startOp);
57 bbox.min.x = min_x;
58 bbox.max.x = max_x;
59 bbox.min.y = min_y;
60 bbox.max.y = max_y;
61 return a * 0.5;
62 }
63
64 // NOTE: ring and ring_ptr are forward declared in wagyu/point.hpp
65
66 template <typename T>
67 using ring_vector = std::vector<ring_ptr<T>>;
68
69 template <typename T>
70 struct ring {
71 std::size_t ring_index; // To support unset 0 is undefined and indexes offset by 1
72
73 std::size_t size_; // number of points in the ring
74 double area_; // area of the ring
75 mapbox::geometry::box<T> bbox; // bounding box of the ring
76
77 ring_ptr<T> parent;
78 ring_vector<T> children;
79
80 point_ptr<T> points;
81 point_ptr<T> bottom_point;
82 bool is_hole_;
83 bool corrected;
84
85 ring(ring const&) = delete;
86 ring& operator=(ring const&) = delete;
87
ringmapbox::geometry::wagyu::ring88 ring()
89 : ring_index(0),
90 size_(0),
91 area_(std::numeric_limits<double>::quiet_NaN()),
92 bbox({ 0, 0 }, { 0, 0 }),
93 parent(nullptr),
94 children(),
95 points(nullptr),
96 bottom_point(nullptr),
97 is_hole_(false),
98 corrected(false) {
99 }
100
reset_statsmapbox::geometry::wagyu::ring101 void reset_stats() {
102 area_ = std::numeric_limits<double>::quiet_NaN();
103 is_hole_ = false;
104 bbox.min.x = 0;
105 bbox.min.y = 0;
106 bbox.max.x = 0;
107 bbox.max.y = 0;
108 size_ = 0;
109 }
110
recalculate_statsmapbox::geometry::wagyu::ring111 void recalculate_stats() {
112 if (points != nullptr) {
113 area_ = area_from_point(points, size_, bbox);
114 is_hole_ = !(area_ > 0.0);
115 }
116 }
117
set_statsmapbox::geometry::wagyu::ring118 void set_stats(double a, std::size_t s, mapbox::geometry::box<T> const& b) {
119 bbox = b;
120 area_ = a;
121 size_ = s;
122 is_hole_ = !(area_ > 0.0);
123 }
124
areamapbox::geometry::wagyu::ring125 double area() {
126 if (std::isnan(area_)) {
127 recalculate_stats();
128 }
129 return area_;
130 }
131
is_holemapbox::geometry::wagyu::ring132 bool is_hole() {
133 if (std::isnan(area_)) {
134 recalculate_stats();
135 }
136 return is_hole_;
137 }
138
sizemapbox::geometry::wagyu::ring139 std::size_t size() {
140 if (std::isnan(area_)) {
141 recalculate_stats();
142 }
143 return size_;
144 }
145 };
146
147 template <typename T>
148 using hot_pixel_vector = std::vector<mapbox::geometry::point<T>>;
149
150 template <typename T>
151 using hot_pixel_itr = typename hot_pixel_vector<T>::iterator;
152
153 template <typename T>
154 using hot_pixel_rev_itr = typename hot_pixel_vector<T>::reverse_iterator;
155
156 template <typename T>
157 struct ring_manager {
158
159 ring_vector<T> children;
160 point_vector<T> all_points;
161 hot_pixel_vector<T> hot_pixels;
162 hot_pixel_itr<T> current_hp_itr;
163 std::deque<point<T>> points;
164 std::deque<ring<T>> rings;
165 std::vector<point<T>> storage;
166 std::size_t index;
167
168 ring_manager(ring_manager const&) = delete;
169 ring_manager& operator=(ring_manager const&) = delete;
170
ring_managermapbox::geometry::wagyu::ring_manager171 ring_manager()
172 : children(),
173 all_points(),
174 hot_pixels(),
175 current_hp_itr(hot_pixels.end()),
176 points(),
177 rings(),
178 storage(),
179 index(0) {
180 }
181 };
182
183 template <typename T>
preallocate_point_memory(ring_manager<T> & rings,std::size_t size)184 void preallocate_point_memory(ring_manager<T>& rings, std::size_t size) {
185 rings.storage.reserve(size);
186 rings.all_points.reserve(size);
187 }
188
189 template <typename T>
create_new_ring(ring_manager<T> & manager)190 ring_ptr<T> create_new_ring(ring_manager<T>& manager) {
191 manager.rings.emplace_back();
192 ring_ptr<T> result = &manager.rings.back();
193 result->ring_index = manager.index++;
194 return result;
195 }
196
197 template <typename T>
198 point_ptr<T>
create_new_point(ring_ptr<T> r,mapbox::geometry::point<T> const & pt,ring_manager<T> & rings)199 create_new_point(ring_ptr<T> r, mapbox::geometry::point<T> const& pt, ring_manager<T>& rings) {
200 point_ptr<T> point;
201 if (rings.storage.size() < rings.storage.capacity()) {
202 rings.storage.emplace_back(r, pt);
203 point = &rings.storage.back();
204 } else {
205 rings.points.emplace_back(r, pt);
206 point = &rings.points.back();
207 }
208 rings.all_points.push_back(point);
209 return point;
210 }
211
212 template <typename T>
create_new_point(ring_ptr<T> r,mapbox::geometry::point<T> const & pt,point_ptr<T> before_this_point,ring_manager<T> & rings)213 point_ptr<T> create_new_point(ring_ptr<T> r,
214 mapbox::geometry::point<T> const& pt,
215 point_ptr<T> before_this_point,
216 ring_manager<T>& rings) {
217 point_ptr<T> point;
218 if (rings.storage.size() < rings.storage.capacity()) {
219 rings.storage.emplace_back(r, pt, before_this_point);
220 point = &rings.storage.back();
221 } else {
222 rings.points.emplace_back(r, pt, before_this_point);
223 point = &rings.points.back();
224 }
225 rings.all_points.push_back(point);
226 return point;
227 }
228
229 template <typename T>
set_to_children(ring_ptr<T> r,ring_vector<T> & children)230 void set_to_children(ring_ptr<T> r, ring_vector<T>& children) {
231 for (auto& c : children) {
232 if (c == nullptr) {
233 c = r;
234 return;
235 }
236 }
237 children.push_back(r);
238 }
239
240 template <typename T>
remove_from_children(ring_ptr<T> r,ring_vector<T> & children)241 void remove_from_children(ring_ptr<T> r, ring_vector<T>& children) {
242 for (auto& c : children) {
243 if (c == r) {
244 c = nullptr;
245 return;
246 }
247 }
248 }
249
250 template <typename T>
assign_as_child(ring_ptr<T> new_ring,ring_ptr<T> parent,ring_manager<T> & manager)251 void assign_as_child(ring_ptr<T> new_ring, ring_ptr<T> parent, ring_manager<T>& manager) {
252 // Assigning as a child assumes that this is
253 // a brand new ring. Therefore it does
254 // not have any existing relationships
255 if ((parent == nullptr && new_ring->is_hole()) ||
256 (parent != nullptr && new_ring->is_hole() == parent->is_hole())) {
257 throw std::runtime_error(
258 "Trying to assign a child that is the same orientation as the parent");
259 }
260 auto& children = parent == nullptr ? manager.children : parent->children;
261 set_to_children(new_ring, children);
262 new_ring->parent = parent;
263 }
264
265 template <typename T>
reassign_as_child(ring_ptr<T> ring,ring_ptr<T> parent,ring_manager<T> & manager)266 void reassign_as_child(ring_ptr<T> ring, ring_ptr<T> parent, ring_manager<T>& manager) {
267 // Reassigning a ring assumes it already
268 // has an existing parent
269 if ((parent == nullptr && ring->is_hole()) ||
270 (parent != nullptr && ring->is_hole() == parent->is_hole())) {
271 throw std::runtime_error(
272 "Trying to re-assign a child that is the same orientation as the parent");
273 }
274
275 // Remove the old child relationship
276 auto& old_children = ring->parent == nullptr ? manager.children : ring->parent->children;
277 remove_from_children(ring, old_children);
278
279 // Add new child relationship
280 auto& children = parent == nullptr ? manager.children : parent->children;
281 set_to_children(ring, children);
282 ring->parent = parent;
283 }
284
285 template <typename T>
assign_as_sibling(ring_ptr<T> new_ring,ring_ptr<T> sibling,ring_manager<T> & manager)286 void assign_as_sibling(ring_ptr<T> new_ring, ring_ptr<T> sibling, ring_manager<T>& manager) {
287 // Assigning as a sibling assumes that this is
288 // a brand new ring. Therefore it does
289 // not have any existing relationships
290 if (new_ring->is_hole() != sibling->is_hole()) {
291 throw std::runtime_error(
292 "Trying to assign to be a sibling that is not the same orientation as the sibling");
293 }
294 auto& children = sibling->parent == nullptr ? manager.children : sibling->parent->children;
295 set_to_children(new_ring, children);
296 new_ring->parent = sibling->parent;
297 }
298
299 template <typename T>
reassign_as_sibling(ring_ptr<T> ring,ring_ptr<T> sibling,ring_manager<T> & manager)300 void reassign_as_sibling(ring_ptr<T> ring, ring_ptr<T> sibling, ring_manager<T>& manager) {
301 if (ring->parent == sibling->parent) {
302 return;
303 }
304 // Assigning as a sibling assumes that this is
305 // a brand new ring. Therefore it does
306 // not have any existing relationships
307 if (ring->is_hole() != sibling->is_hole()) {
308 throw std::runtime_error(
309 "Trying to assign to be a sibling that is not the same orientation as the sibling");
310 }
311 // Remove the old child relationship
312 auto& old_children = ring->parent == nullptr ? manager.children : ring->parent->children;
313 remove_from_children(ring, old_children);
314 // Add new relationship
315 auto& children = sibling->parent == nullptr ? manager.children : sibling->parent->children;
316 set_to_children(ring, children);
317 ring->parent = sibling->parent;
318 }
319
320 template <typename T>
ring1_replaces_ring2(ring_ptr<T> ring1,ring_ptr<T> ring2,ring_manager<T> & manager)321 void ring1_replaces_ring2(ring_ptr<T> ring1, ring_ptr<T> ring2, ring_manager<T>& manager) {
322 assert(ring1 != ring2);
323 auto& ring1_children = ring1 == nullptr ? manager.children : ring1->children;
324 for (auto& c : ring2->children) {
325 if (c == nullptr) {
326 continue;
327 }
328 c->parent = ring1;
329 set_to_children(c, ring1_children);
330 c = nullptr;
331 }
332 // Remove the old child relationship
333 auto& old_children = ring2->parent == nullptr ? manager.children : ring2->parent->children;
334 remove_from_children(ring2, old_children);
335 ring2->points = nullptr;
336 ring2->reset_stats();
337 }
338
339 template <typename T>
remove_points(point_ptr<T> pt)340 void remove_points(point_ptr<T> pt) {
341 if (pt != nullptr) {
342 pt->prev->next = nullptr;
343 while (pt != nullptr) {
344 point_ptr<T> tmp = pt;
345 pt = pt->next;
346 tmp->next = nullptr;
347 tmp->prev = nullptr;
348 tmp->ring = nullptr;
349 }
350 }
351 }
352
353 template <typename T>
remove_ring_and_points(ring_ptr<T> r,ring_manager<T> & manager,bool remove_children=true,bool remove_from_parent=true)354 void remove_ring_and_points(ring_ptr<T> r,
355 ring_manager<T>& manager,
356 bool remove_children = true,
357 bool remove_from_parent = true) {
358 // Removes a ring and any children that might be
359 // under that ring.
360 for (auto& c : r->children) {
361 if (c == nullptr) {
362 continue;
363 }
364 if (remove_children) {
365 remove_ring_and_points(c, manager, true, false);
366 }
367 c = nullptr;
368 }
369 if (remove_from_parent) {
370 // Remove the old child relationship
371 auto& old_children = r->parent == nullptr ? manager.children : r->parent->children;
372 remove_from_children(r, old_children);
373 }
374 point_ptr<T> pt = r->points;
375 if (pt != nullptr) {
376 pt->prev->next = nullptr;
377 while (pt != nullptr) {
378 point_ptr<T> tmp = pt;
379 pt = pt->next;
380 tmp->next = nullptr;
381 tmp->prev = nullptr;
382 tmp->ring = nullptr;
383 }
384 }
385 r->points = nullptr;
386 r->reset_stats();
387 }
388
389 template <typename T>
remove_ring(ring_ptr<T> r,ring_manager<T> & manager,bool remove_children=true,bool remove_from_parent=true)390 void remove_ring(ring_ptr<T> r,
391 ring_manager<T>& manager,
392 bool remove_children = true,
393 bool remove_from_parent = true) {
394 // Removes a ring and any children that might be
395 // under that ring.
396 for (auto& c : r->children) {
397 if (c == nullptr) {
398 continue;
399 }
400 if (remove_children) {
401 remove_ring(c, manager, true, false);
402 }
403 c = nullptr;
404 }
405 if (remove_from_parent) {
406 // Remove the old child relationship
407 auto& old_children = r->parent == nullptr ? manager.children : r->parent->children;
408 remove_from_children(r, old_children);
409 }
410 r->points = nullptr;
411 r->reset_stats();
412 }
413
414 template <typename T>
ring_depth(ring_ptr<T> r)415 inline std::size_t ring_depth(ring_ptr<T> r) {
416 std::size_t depth = 0;
417 if (!r) {
418 return depth;
419 }
420 while (r->parent) {
421 depth++;
422 r = r->parent;
423 }
424 return depth;
425 }
426
427 template <typename T>
ring_is_hole(ring_ptr<T> r)428 inline bool ring_is_hole(ring_ptr<T> r) {
429 // This is different then the "normal" way of determing if
430 // a ring is a hole or not because it uses the depth of the
431 // the ring to determine if it is a hole or not. This is only done
432 // intially when rings are output from Vatti.
433 return ring_depth(r) & 1;
434 }
435
436 template <typename T>
set_next(const_point_ptr<T> & node,const const_point_ptr<T> & next_node)437 void set_next(const_point_ptr<T>& node, const const_point_ptr<T>& next_node) {
438 node->next = next_node;
439 }
440
441 template <typename T>
get_next(const_point_ptr<T> & node)442 point_ptr<T> get_next(const_point_ptr<T>& node) {
443 return node->next;
444 }
445
446 template <typename T>
get_prev(const_point_ptr<T> & node)447 point_ptr<T> get_prev(const_point_ptr<T>& node) {
448 return node->prev;
449 }
450
451 template <typename T>
set_prev(const_point_ptr<T> & node,const const_point_ptr<T> & prev_node)452 void set_prev(const_point_ptr<T>& node, const const_point_ptr<T>& prev_node) {
453 node->prev = prev_node;
454 }
455
456 template <typename T>
init(const_point_ptr<T> & node)457 void init(const_point_ptr<T>& node) {
458 set_next(node, node);
459 set_prev(node, node);
460 }
461
462 template <typename T>
link_before(point_ptr<T> & node,point_ptr<T> & new_node)463 void link_before(point_ptr<T>& node, point_ptr<T>& new_node) {
464 point_ptr<T> prev_node = get_prev(node);
465 set_prev(new_node, prev_node);
466 set_next(new_node, node);
467 set_prev(node, new_node);
468 set_next(prev_node, new_node);
469 }
470
471 template <typename T>
link_after(point_ptr<T> & node,point_ptr<T> & new_node)472 void link_after(point_ptr<T>& node, point_ptr<T>& new_node) {
473 point_ptr<T> next_node = get_next(node);
474 set_prev(new_node, node);
475 set_next(new_node, next_node);
476 set_next(node, new_node);
477 set_prev(next_node, new_node);
478 }
479
480 template <typename T>
transfer_point(point_ptr<T> & p,point_ptr<T> & b,point_ptr<T> & e)481 void transfer_point(point_ptr<T>& p, point_ptr<T>& b, point_ptr<T>& e) {
482 if (b != e) {
483 point_ptr<T> prev_p = get_prev(p);
484 point_ptr<T> prev_b = get_prev(b);
485 point_ptr<T> prev_e = get_prev(e);
486 set_next(prev_e, p);
487 set_prev(p, prev_e);
488 set_next(prev_b, e);
489 set_prev(e, prev_b);
490 set_next(prev_p, b);
491 set_prev(b, prev_p);
492 } else {
493 link_before(p, b);
494 }
495 }
496
497 template <typename T>
reverse_ring(point_ptr<T> pp)498 void reverse_ring(point_ptr<T> pp) {
499 if (!pp) {
500 return;
501 }
502 point_ptr<T> pp1;
503 point_ptr<T> pp2;
504 pp1 = pp;
505 do {
506 pp2 = pp1->next;
507 pp1->next = pp1->prev;
508 pp1->prev = pp2;
509 pp1 = pp2;
510 } while (pp1 != pp);
511 }
512
513 #ifdef DEBUG
514
515 template <class charT, class traits, typename T>
operator <<(std::basic_ostream<charT,traits> & out,ring<T> & r)516 inline std::basic_ostream<charT, traits>& operator<<(std::basic_ostream<charT, traits>& out,
517 ring<T>& r) {
518 out << " ring_index: " << r.ring_index << std::endl;
519 if (!r.parent) {
520 // out << " parent_ring ptr: nullptr" << std::endl;
521 out << " parent_index: -----" << std::endl;
522 } else {
523 // out << " parent_ring ptr: " << r.parent << std::endl;
524 out << " parent_ring idx: " << r.parent->ring_index << std::endl;
525 }
526 ring_ptr<T> n = const_cast<ring_ptr<T>>(&r);
527 if (ring_is_hole(n)) {
528 out << " is_hole: true " << std::endl;
529 } else {
530 out << " is_hole: false " << std::endl;
531 }
532 auto pt_itr = r.points;
533 if (pt_itr) {
534 out << " area: " << r.area() << std::endl;
535 out << " points:" << std::endl;
536 out << " [[[" << pt_itr->x << "," << pt_itr->y << "],";
537 pt_itr = pt_itr->next;
538 while (pt_itr != r.points) {
539 out << "[" << pt_itr->x << "," << pt_itr->y << "],";
540 pt_itr = pt_itr->next;
541 }
542 out << "[" << pt_itr->x << "," << pt_itr->y << "]]]" << std::endl;
543 } else {
544 out << " area: NONE" << std::endl;
545 out << " points: NONE" << std::endl;
546 }
547 return out;
548 }
549
550 template <typename T>
debug_ring_addresses(ring_ptr<T> r)551 std::string debug_ring_addresses(ring_ptr<T> r) {
552 std::ostringstream out;
553 out << "Ring: " << r->ring_index << std::endl;
554 if (r->points == nullptr) {
555 out << " Ring has no points" << std::endl;
556 return out.str();
557 }
558 auto pt_itr = r->points;
559 do {
560 out << " [" << pt_itr->x << "," << pt_itr->y << "] - " << pt_itr << std::endl;
561 pt_itr = pt_itr->next;
562 } while (pt_itr != r->points);
563 return out.str();
564 }
565
566 template <typename T>
output_as_polygon(ring_ptr<T> r)567 std::string output_as_polygon(ring_ptr<T> r) {
568 std::ostringstream out;
569
570 auto pt_itr = r->points;
571 if (pt_itr) {
572 out << "[";
573 out << "[[" << pt_itr->x << "," << pt_itr->y << "],";
574 pt_itr = pt_itr->next;
575 while (pt_itr != r->points) {
576 out << "[" << pt_itr->x << "," << pt_itr->y << "],";
577 pt_itr = pt_itr->next;
578 }
579 out << "[" << pt_itr->x << "," << pt_itr->y << "]]";
580 for (auto const& c : r->children) {
581 if (c == nullptr) {
582 continue;
583 }
584 pt_itr = c->points;
585 if (pt_itr) {
586 out << ",[[" << pt_itr->x << "," << pt_itr->y << "],";
587 pt_itr = pt_itr->next;
588 while (pt_itr != c->points) {
589 out << "[" << pt_itr->x << "," << pt_itr->y << "],";
590 pt_itr = pt_itr->next;
591 }
592 out << "[" << pt_itr->x << "," << pt_itr->y << "]]";
593 }
594 }
595 out << "]" << std::endl;
596 } else {
597 out << "[]" << std::endl;
598 }
599
600 return out.str();
601 }
602
603 template <class charT, class traits, typename T>
operator <<(std::basic_ostream<charT,traits> & out,ring_vector<T> & rings)604 inline std::basic_ostream<charT, traits>& operator<<(std::basic_ostream<charT, traits>& out,
605 ring_vector<T>& rings) {
606 out << "START RING VECTOR" << std::endl;
607 for (auto& r : rings) {
608 if (r == nullptr || !r->points) {
609 continue;
610 }
611 out << " ring: " << r->ring_index << " - " << r << std::endl;
612 out << *r;
613 }
614 out << "END RING VECTOR" << std::endl;
615 return out;
616 }
617
618 template <class charT, class traits, typename T>
operator <<(std::basic_ostream<charT,traits> & out,std::deque<ring<T>> & rings)619 inline std::basic_ostream<charT, traits>& operator<<(std::basic_ostream<charT, traits>& out,
620 std::deque<ring<T>>& rings) {
621 out << "START RING VECTOR" << std::endl;
622 for (auto& r : rings) {
623 if (!r.points) {
624 continue;
625 }
626 out << " ring: " << r.ring_index << std::endl;
627 out << r;
628 }
629 out << "END RING VECTOR" << std::endl;
630 return out;
631 }
632
633 template <class charT, class traits, typename T>
operator <<(std::basic_ostream<charT,traits> & out,hot_pixel_vector<T> & hp_vec)634 inline std::basic_ostream<charT, traits>& operator<<(std::basic_ostream<charT, traits>& out,
635 hot_pixel_vector<T>& hp_vec) {
636 out << "Hot Pixels: " << std::endl;
637 for (auto& hp : hp_vec) {
638 out << hp << std::endl;
639 }
640 return out;
641 }
642 #endif
643 }
644 }
645 }
646