1 #pragma once
2 
3 #include <list>
4 
5 #include <mapbox/geometry/box.hpp>
6 #include <mapbox/geometry/line_string.hpp>
7 #include <mapbox/geometry/multi_polygon.hpp>
8 #include <mapbox/geometry/polygon.hpp>
9 
10 #include <mapbox/geometry/wagyu/build_local_minima_list.hpp>
11 #include <mapbox/geometry/wagyu/build_result.hpp>
12 #include <mapbox/geometry/wagyu/config.hpp>
13 #include <mapbox/geometry/wagyu/local_minimum.hpp>
14 #include <mapbox/geometry/wagyu/snap_rounding.hpp>
15 #include <mapbox/geometry/wagyu/topology_correction.hpp>
16 #include <mapbox/geometry/wagyu/vatti.hpp>
17 
18 #define WAGYU_MAJOR_VERSION 0
19 #define WAGYU_MINOR_VERSION 4
20 #define WAGYU_PATCH_VERSION 3
21 
22 #define WAGYU_VERSION                                                                              \
23     (WAGYU_MAJOR_VERSION * 100000) + (WAGYU_MINOR_VERSION * 100) + (WAGYU_PATCH_VERSION)
24 
25 namespace mapbox {
26 namespace geometry {
27 namespace wagyu {
28 
29 template <typename T>
30 class wagyu {
31 private:
32     local_minimum_list<T> minima_list;
33     bool reverse_output;
34 
35     wagyu(wagyu const&) = delete;
36     wagyu& operator=(wagyu const&) = delete;
37 
38 public:
wagyu()39     wagyu() : minima_list(), reverse_output(false) {
40     }
41 
~wagyu()42     ~wagyu() {
43         clear();
44     }
45 
46     template <typename T2>
add_ring(mapbox::geometry::linear_ring<T2> const & pg,polygon_type p_type=polygon_type_subject)47     bool add_ring(mapbox::geometry::linear_ring<T2> const& pg,
48                   polygon_type p_type = polygon_type_subject) {
49         return add_linear_ring(pg, minima_list, p_type);
50     }
51 
52     template <typename T2>
add_polygon(mapbox::geometry::polygon<T2> const & ppg,polygon_type p_type=polygon_type_subject)53     bool add_polygon(mapbox::geometry::polygon<T2> const& ppg,
54                      polygon_type p_type = polygon_type_subject) {
55         bool result = false;
56         for (auto const& r : ppg) {
57             if (add_ring(r, p_type)) {
58                 result = true;
59             }
60         }
61         return result;
62     }
63 
reverse_rings(bool value)64     void reverse_rings(bool value) {
65         reverse_output = value;
66     }
67 
clear()68     void clear() {
69         minima_list.clear();
70     }
71 
get_bounds()72     mapbox::geometry::box<T> get_bounds() {
73         mapbox::geometry::point<T> min = { 0, 0 };
74         mapbox::geometry::point<T> max = { 0, 0 };
75         if (minima_list.empty()) {
76             return mapbox::geometry::box<T>(min, max);
77         }
78         bool first_set = false;
79         for (auto const& lm : minima_list) {
80             if (!lm.left_bound.edges.empty()) {
81                 if (!first_set) {
82                     min = lm.left_bound.edges.front().top;
83                     max = lm.left_bound.edges.back().bot;
84                     first_set = true;
85                 } else {
86                     min.y = std::min(min.y, lm.left_bound.edges.front().top.y);
87                     max.y = std::max(max.y, lm.left_bound.edges.back().bot.y);
88                     max.x = std::max(max.x, lm.left_bound.edges.back().top.x);
89                     min.x = std::min(min.x, lm.left_bound.edges.back().top.x);
90                 }
91                 for (auto const& e : lm.left_bound.edges) {
92                     max.x = std::max(max.x, e.bot.x);
93                     min.x = std::min(min.x, e.bot.x);
94                 }
95             }
96             if (!lm.right_bound.edges.empty()) {
97                 if (!first_set) {
98                     min = lm.right_bound.edges.front().top;
99                     max = lm.right_bound.edges.back().bot;
100                     first_set = true;
101                 } else {
102                     min.y = std::min(min.y, lm.right_bound.edges.front().top.y);
103                     max.y = std::max(max.y, lm.right_bound.edges.back().bot.y);
104                     max.x = std::max(max.x, lm.right_bound.edges.back().top.x);
105                     min.x = std::min(min.x, lm.right_bound.edges.back().top.x);
106                 }
107                 for (auto const& e : lm.right_bound.edges) {
108                     max.x = std::max(max.x, e.bot.x);
109                     min.x = std::min(min.x, e.bot.x);
110                 }
111             }
112         }
113         return mapbox::geometry::box<T>(min, max);
114     }
115 
116     template <typename T2>
execute(clip_type cliptype,mapbox::geometry::multi_polygon<T2> & solution,fill_type subject_fill_type,fill_type clip_fill_type)117     bool execute(clip_type cliptype,
118                  mapbox::geometry::multi_polygon<T2>& solution,
119                  fill_type subject_fill_type,
120                  fill_type clip_fill_type) {
121 
122         if (minima_list.empty()) {
123             return false;
124         }
125 
126         ring_manager<T> manager;
127 
128         build_hot_pixels(minima_list, manager);
129 
130         execute_vatti(minima_list, manager, cliptype, subject_fill_type, clip_fill_type);
131 
132         correct_topology(manager);
133 
134         build_result(solution, manager, reverse_output);
135 
136         return true;
137     }
138 };
139 }
140 }
141 }
142