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