1 #pragma once
2 
3 #include <mapbox/geometry/wagyu/active_bound_list.hpp>
4 #include <mapbox/geometry/wagyu/config.hpp>
5 #include <mapbox/geometry/wagyu/edge.hpp>
6 #include <mapbox/geometry/wagyu/interrupt.hpp>
7 #include <mapbox/geometry/wagyu/intersect_util.hpp>
8 #include <mapbox/geometry/wagyu/local_minimum.hpp>
9 #include <mapbox/geometry/wagyu/local_minimum_util.hpp>
10 #include <mapbox/geometry/wagyu/process_horizontal.hpp>
11 #include <mapbox/geometry/wagyu/ring.hpp>
12 #include <mapbox/geometry/wagyu/ring_util.hpp>
13 #include <mapbox/geometry/wagyu/topology_correction.hpp>
14 #include <mapbox/geometry/wagyu/util.hpp>
15 
16 namespace mapbox {
17 namespace geometry {
18 namespace wagyu {
19 
20 template <typename T>
do_maxima(active_bound_list_itr<T> & bnd,active_bound_list_itr<T> & bndMaxPair,clip_type cliptype,fill_type subject_fill_type,fill_type clip_fill_type,ring_manager<T> & manager,active_bound_list<T> & active_bounds)21 active_bound_list_itr<T> do_maxima(active_bound_list_itr<T>& bnd,
22                                    active_bound_list_itr<T>& bndMaxPair,
23                                    clip_type cliptype,
24                                    fill_type subject_fill_type,
25                                    fill_type clip_fill_type,
26                                    ring_manager<T>& manager,
27                                    active_bound_list<T>& active_bounds) {
28     auto bnd_next = std::next(bnd);
29     auto return_bnd = bnd;
30     bool skipped = false;
31     while (bnd_next != active_bounds.end() && bnd_next != bndMaxPair) {
32         if (*bnd_next == nullptr) {
33             ++bnd_next;
34             continue;
35         }
36         skipped = true;
37         intersect_bounds(*(*bnd), *(*bnd_next), (*bnd)->current_edge->top, cliptype, subject_fill_type, clip_fill_type,
38                          manager, active_bounds);
39         std::iter_swap(bnd, bnd_next);
40         bnd = bnd_next;
41         ++bnd_next;
42     }
43 
44     if ((*bnd)->ring && (*bndMaxPair)->ring) {
45         add_local_maximum_point(*(*bnd), *(*bndMaxPair), (*bnd)->current_edge->top, manager, active_bounds);
46     } else if ((*bnd)->ring || (*bndMaxPair)->ring) {
47         throw std::runtime_error("DoMaxima error");
48     }
49     *bndMaxPair = nullptr;
50     *bnd = nullptr;
51     if (!skipped) {
52         ++return_bnd;
53     }
54     return return_bnd;
55 }
56 
57 template <typename T>
process_edges_at_top_of_scanbeam(T top_y,active_bound_list<T> & active_bounds,scanbeam_list<T> & scanbeam,local_minimum_ptr_list<T> const & minima_sorted,local_minimum_ptr_list_itr<T> & current_lm,ring_manager<T> & manager,clip_type cliptype,fill_type subject_fill_type,fill_type clip_fill_type)58 void process_edges_at_top_of_scanbeam(T top_y,
59                                       active_bound_list<T>& active_bounds,
60                                       scanbeam_list<T>& scanbeam,
61                                       local_minimum_ptr_list<T> const& minima_sorted,
62                                       local_minimum_ptr_list_itr<T>& current_lm,
63                                       ring_manager<T>& manager,
64                                       clip_type cliptype,
65                                       fill_type subject_fill_type,
66                                       fill_type clip_fill_type) {
67 
68     for (auto bnd = active_bounds.begin(); bnd != active_bounds.end();) {
69         interrupt_check(); // Check for interruptions
70         if (*bnd == nullptr) {
71             ++bnd;
72             continue;
73         }
74         // 1. Process maxima, treating them as if they are "bent" horizontal edges,
75         // but exclude maxima with horizontal edges.
76 
77         bool is_maxima_edge = is_maxima(bnd, top_y);
78 
79         if (is_maxima_edge) {
80             auto bnd_max_pair = get_maxima_pair(bnd, active_bounds);
81             is_maxima_edge = ((bnd_max_pair == active_bounds.end() || !current_edge_is_horizontal<T>(bnd_max_pair)) &&
82                               is_maxima(bnd_max_pair, top_y));
83             if (is_maxima_edge) {
84                 bnd = do_maxima(bnd, bnd_max_pair, cliptype, subject_fill_type, clip_fill_type, manager, active_bounds);
85                 continue;
86             }
87         }
88 
89         // 2. Promote horizontal edges.
90         if (is_intermediate(bnd, top_y) && next_edge_is_horizontal<T>(bnd)) {
91             if ((*bnd)->ring) {
92                 insert_hot_pixels_in_path(*(*bnd), (*bnd)->current_edge->top, manager, false);
93             }
94             next_edge_in_bound(*(*bnd), scanbeam);
95             if ((*bnd)->ring) {
96                 add_point_to_ring(*(*bnd), (*bnd)->current_edge->bot, manager);
97             }
98         } else {
99             (*bnd)->current_x = get_current_x(*((*bnd)->current_edge), top_y);
100         }
101         ++bnd;
102     }
103     active_bounds.erase(std::remove(active_bounds.begin(), active_bounds.end(), nullptr), active_bounds.end());
104 
105     insert_horizontal_local_minima_into_ABL(top_y, minima_sorted, current_lm, active_bounds, manager, scanbeam,
106                                             cliptype, subject_fill_type, clip_fill_type);
107 
108     process_horizontals(top_y, active_bounds, manager, scanbeam, cliptype, subject_fill_type, clip_fill_type);
109 
110     // 4. Promote intermediate vertices
111 
112     for (auto bnd = active_bounds.begin(); bnd != active_bounds.end(); ++bnd) {
113         if (is_intermediate(bnd, top_y)) {
114             if ((*bnd)->ring) {
115                 add_point_to_ring(*(*bnd), (*bnd)->current_edge->top, manager);
116             }
117             next_edge_in_bound(*(*bnd), scanbeam);
118         }
119     }
120 }
121 } // namespace wagyu
122 } // namespace geometry
123 } // namespace mapbox
124