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