1 #include <cassert>
2 #include "ZigzagConnectorProcessor.h"
3 
4 using namespace cura;
5 
6 
registerVertex(const Point & vertex)7 void ZigzagConnectorProcessor::registerVertex(const Point& vertex)
8 {
9     if (is_first_connector)
10     {
11         first_connector.push_back(vertex);
12     }
13     else
14     { // it's yet unclear whether the polygon segment should be included, so we store it until we know
15         current_connector.push_back(vertex);
16     }
17 }
18 
19 
shouldAddCurrentConnector(int start_scanline_idx,int end_scanline_idx) const20 bool ZigzagConnectorProcessor::shouldAddCurrentConnector(int start_scanline_idx, int end_scanline_idx) const
21 {
22     int direction = end_scanline_idx - start_scanline_idx;
23     //
24     // Decide whether we should add the current connection or not.
25     // Add the current zag connection in the following cases:
26     //  - if the current zag starts on an even scanline and ends on an odd scanline
27     //  - if the current zag is an end piece (check if the previous and the current scanlines are the same)
28     //    and "use end piece" is enabled
29     // Don't add a zag if:
30     //  - the current zag is NOT an end piece, "skip some zags" is enabled, and the current zag lays in a
31     //    segment which needs to be skipped.
32     // Moreover:
33     //  - if a "connected end pieces" is not enabled and the current connection is an end piece, the last line
34     //    of this end piece will not be added.
35     //
36     // The rules above also apply to how the last part is processed (in polygon finishes)
37     //
38     const bool is_this_endpiece = start_scanline_idx == end_scanline_idx;
39     const bool is_this_connection_even = start_scanline_idx % 2 == 0;
40     bool should_skip_this_connection = false;
41     if (skip_some_zags && zag_skip_count > 0)
42     {
43         //
44         // Here is an illustration of how the zags will be removed.
45         // ***We use skip_count = 3 as an example:***
46         //
47         // segment numbers:    0     1     2     3     4     5     6     7     8     9     10
48         //    top zags ->   |     |-----|     |--x--|     |-----|     |-----|     |--x--|     |
49         //                  |     |     |     |     |     |     |     |     |     |     |     |
50         // bottom zags ->   |--x--|     |-----|     |-----|     |--x--|     |-----|     |-----|
51         //
52         // LEGEND:  |  :    zigs
53         //          -  :    zags
54         //
55         // Following the line from left to right, we want to remove a zag in every 3. So here we
56         // are removing zags 0, 3, 6, 9, ..., which is (n * 3), where n = 0, 1, 2, ...
57         //
58         // We treat top and bottom zags differently:
59         //   - a bottom zag goes from left -> right. Example: for zag 6, it goes from scanline 6 to 7.
60         //   - a top zag goes from right -> left. Example: for zag 3, it goes from scanline 4 to 3.
61         // We call the start and end scanline indices <start> and <end> separately.
62         // So, to get the results described above, we skip zags in the following way:
63         //   - if direction > 0 (bottom zags: left -> right), skip zags whose <start> mod 3 == 0
64         //   - if direction < 0 (top zags: right -> left), skip zags whose <end> mod 3 == 0
65         //
66         if (direction > 0)
67         {
68             should_skip_this_connection = start_scanline_idx % zag_skip_count == 0;
69         }
70         else
71         {
72             should_skip_this_connection = (start_scanline_idx - 1) % zag_skip_count == 0;
73         }
74     }
75 
76     const bool should_add =
77         (is_this_connection_even && !is_this_endpiece && !should_skip_this_connection) // normal connections that should be added
78         || (use_endpieces && is_this_endpiece);  // end piece if it is enabled;
79 
80     return should_add;
81 }
82 
83 
registerScanlineSegmentIntersection(const Point & intersection,int scanline_index)84 void ZigzagConnectorProcessor::registerScanlineSegmentIntersection(const Point& intersection, int scanline_index)
85 {
86     if (is_first_connector)
87     {
88         // process as the first connector if we haven't found one yet
89         // this will be processed with the last remaining piece at the end (when the polygon finishes)
90         first_connector.push_back(intersection);
91         first_connector_end_scanline_index = scanline_index;
92         is_first_connector = false;
93     }
94     else
95     {
96         // add the current connector if needed
97         if (shouldAddCurrentConnector(last_connector_index, scanline_index))
98         {
99             const bool is_this_endpiece = scanline_index == last_connector_index;
100             current_connector.push_back(intersection);
101             addZagConnector(current_connector, is_this_endpiece);
102         }
103     }
104 
105     // update state
106     current_connector.clear(); // we're starting a new (odd) zigzag connector, so clear the old one
107     current_connector.push_back(intersection);
108     last_connector_index = scanline_index;
109 }
110 
111 
registerPolyFinished()112 void ZigzagConnectorProcessor::registerPolyFinished()
113 {
114     int scanline_start_index = last_connector_index;
115     int scanline_end_index = first_connector_end_scanline_index;
116     const bool is_endpiece = is_first_connector || (!is_first_connector && scanline_start_index == scanline_end_index);
117 
118     // decides whether to add this zag according to the following rules
119     if ((is_endpiece && use_endpieces)
120         || (!is_endpiece && shouldAddCurrentConnector(scanline_start_index, scanline_end_index)))
121     {
122         // for convenience, put every point in one vector
123         for (const Point& point : first_connector)
124         {
125             current_connector.push_back(point);
126         }
127         first_connector.clear();
128 
129         addZagConnector(current_connector, is_endpiece);
130     }
131 
132     // reset member variables
133     reset();
134 }
135 
136 
addZagConnector(std::vector<Point> & points,bool is_endpiece)137 void ZigzagConnectorProcessor::addZagConnector(std::vector<Point>& points, bool is_endpiece)
138 {
139     // don't include the last line yet
140     if (points.size() >= 3)
141     {
142         for (size_t point_idx = 1; point_idx <= points.size() - 2; ++point_idx)
143         {
144             addLine(points[point_idx - 1], points[point_idx]);
145         }
146     }
147     // only add the last line if:
148     //  - it is not an end piece, or
149     //  - it is an end piece and "connected end pieces" is enabled
150     if ((!is_endpiece || (is_endpiece && connected_endpieces)) && points.size() >= 2)
151     {
152         addLine(points[points.size() - 2], points[points.size() - 1]);
153     }
154 }
155