1 #pragma once
2
3 #ifndef RASTER_EDGE_ITERATOR_HPP
4 #define RASTER_EDGE_ITERATOR_HPP
5
6 #include "raster_edge_iterator.h"
7
8 namespace TRop {
9 namespace borders {
10
11 template <typename PixelSelector>
RasterEdgeIterator(const raster_typeP & rin,const selector_type & selector,const TPoint & pos,const TPoint & dir,int adherence)12 RasterEdgeIterator<PixelSelector>::RasterEdgeIterator(
13 const raster_typeP &rin, const selector_type &selector, const TPoint &pos,
14 const TPoint &dir, int adherence)
15 : m_ras(rin)
16 , m_lx_1(rin->getLx() - 1)
17 , m_ly_1(rin->getLy() - 1)
18 , m_wrap(rin->getWrap())
19 , m_selector(selector)
20 , m_pos(pos)
21 , m_dir(dir)
22 , m_elbowColor(selector.transparent())
23 , m_rightSide(adherence == RIGHT)
24 , m_turn(UNKNOWN) {
25 pixels(m_leftPix, m_rightPix);
26 colors(m_leftColor, m_rightColor);
27 }
28
29 //---------------------------------------------------------------------------------------------
30
31 template <typename PixelSelector>
setEdge(const TPoint & pos,const TPoint & dir)32 void RasterEdgeIterator<PixelSelector>::setEdge(const TPoint &pos,
33 const TPoint &dir) {
34 m_pos = pos, m_dir = dir;
35 pixels(m_leftPix, m_rightPix);
36 colors(m_leftColor, m_rightColor);
37 }
38
39 //---------------------------------------------------------------------------------------------
40
41 template <typename PixelSelector>
pixels(pixel_type * & pixLeft,pixel_type * & pixRight)42 inline void RasterEdgeIterator<PixelSelector>::pixels(pixel_type *&pixLeft,
43 pixel_type *&pixRight) {
44 pixel_type *pix = m_ras->pixels(0) + m_pos.y * m_wrap + m_pos.x;
45 if (m_dir.y)
46 if (m_dir.y > 0)
47 pixLeft = pix - 1, pixRight = pix;
48 else
49 pixLeft = pix - m_wrap, pixRight = pixLeft - 1;
50 else if (m_dir.x > 0)
51 pixLeft = pix, pixRight = pix - m_wrap;
52 else
53 pixRight = pix - 1, pixLeft = pixRight - m_wrap;
54 }
55
56 //---------------------------------------------------------------------------------------------
57
58 template <typename PixelSelector>
colors(value_type & leftColor,value_type & rightColor)59 inline void RasterEdgeIterator<PixelSelector>::colors(value_type &leftColor,
60 value_type &rightColor) {
61 if (m_dir.y)
62 if (m_dir.y > 0) {
63 if (m_pos.y > m_ly_1)
64 leftColor = rightColor = m_selector.transparent();
65 else {
66 leftColor = (m_pos.x > 0) ? m_selector.value(*m_leftPix)
67 : m_selector.transparent();
68 rightColor = (m_pos.x <= m_lx_1) ? m_selector.value(*m_rightPix)
69 : m_selector.transparent();
70 }
71 } else {
72 if (m_pos.y < 1)
73 leftColor = rightColor = m_selector.transparent();
74 else {
75 leftColor = (m_pos.x <= m_lx_1) ? m_selector.value(*m_leftPix)
76 : m_selector.transparent();
77 rightColor = (m_pos.x > 0) ? m_selector.value(*m_rightPix)
78 : m_selector.transparent();
79 }
80 }
81 else if (m_dir.x > 0) {
82 if (m_pos.x > m_lx_1)
83 leftColor = rightColor = m_selector.transparent();
84 else {
85 leftColor = (m_pos.y <= m_ly_1) ? m_selector.value(*m_leftPix)
86 : m_selector.transparent();
87 rightColor = (m_pos.y > 0) ? m_selector.value(*m_rightPix)
88 : m_selector.transparent();
89 }
90 } else {
91 if (m_pos.x < 1)
92 leftColor = rightColor = m_selector.transparent();
93 else {
94 leftColor = (m_pos.y > 0) ? m_selector.value(*m_leftPix)
95 : m_selector.transparent();
96 rightColor = (m_pos.y <= m_ly_1) ? m_selector.value(*m_rightPix)
97 : m_selector.transparent();
98 }
99 }
100 }
101
102 //---------------------------------------------------------------------------------------------
103
104 template <typename PixelSelector>
turn(const value_type & newLeftColor,const value_type & newRightColor)105 inline void RasterEdgeIterator<PixelSelector>::turn(
106 const value_type &newLeftColor, const value_type &newRightColor) {
107 if (m_rightSide) {
108 if (newLeftColor == m_rightColor) {
109 if (newRightColor == m_leftColor)
110 turnAmbiguous(newLeftColor, newRightColor);
111 else
112 turnLeft();
113 } else {
114 if (newRightColor != m_rightColor)
115 turnRight();
116 else
117 m_turn = STRAIGHT;
118 }
119
120 m_elbowColor = newLeftColor;
121 } else {
122 if (newRightColor == m_leftColor) {
123 if (newLeftColor == m_rightColor)
124 turnAmbiguous(newLeftColor, newRightColor);
125 else
126 turnRight();
127 } else {
128 if (newLeftColor != m_leftColor)
129 turnLeft();
130 else
131 m_turn = STRAIGHT;
132 }
133
134 m_elbowColor = newRightColor;
135 }
136
137 pixels(m_leftPix, m_rightPix);
138 }
139
140 //---------------------------------------------------------------------------------------------
141
142 template <typename PixelSelector>
turnAmbiguous(const value_type & newLeftColor,const value_type & newRightColor)143 inline void RasterEdgeIterator<PixelSelector>::turnAmbiguous(
144 const value_type &newLeftColor, const value_type &newRightColor) {
145 pixel_type *pix = m_ras->pixels(0) + m_pos.y * m_wrap + m_pos.x;
146 UCHAR count1 = 0, count2 = 0;
147
148 value_type val;
149
150 // Check the 4x4 neighbourhood and connect the minority color
151 if (m_pos.x > 2) {
152 val = m_selector.value(*(pix - 2));
153 if (val == m_leftColor)
154 ++count1;
155 else if (val == m_rightColor)
156 ++count2;
157
158 val = m_selector.value(*(pix - 2 - m_wrap));
159 if (val == m_leftColor)
160 ++count1;
161 else if (val == m_rightColor)
162 ++count2;
163 }
164
165 if (m_pos.x < m_lx_1) {
166 val = m_selector.value(*(pix + 1));
167 if (val == m_leftColor)
168 ++count1;
169 else if (val == m_rightColor)
170 ++count2;
171
172 val = m_selector.value(*(pix + 1 - m_wrap));
173 if (val == m_leftColor)
174 ++count1;
175 else if (val == m_rightColor)
176 ++count2;
177 }
178
179 if (m_pos.y > 2) {
180 int wrap2 = m_wrap << 1;
181
182 val = m_selector.value(*(pix - wrap2));
183 if (val == m_leftColor)
184 ++count1;
185 else if (val == m_rightColor)
186 ++count2;
187
188 val = m_selector.value(*(pix - wrap2 - 1));
189 if (val == m_leftColor)
190 ++count1;
191 else if (val == m_rightColor)
192 ++count2;
193 }
194
195 if (m_pos.y < m_ly_1) {
196 val = m_selector.value(*(pix + m_wrap));
197 if (val == m_leftColor)
198 ++count1;
199 else if (val == m_rightColor)
200 ++count2;
201
202 val = m_selector.value(*(pix + m_wrap - 1));
203 if (val == m_leftColor)
204 ++count1;
205 else if (val == m_rightColor)
206 ++count2;
207 }
208
209 // Minority connection - join the one with less count
210 if (count1 < count2)
211 turnRight(); // Join m_leftColor == newRightColor
212 else if (count1 > count2)
213 turnLeft(); // Join m_rightColor == newLeftColor
214 else if (m_rightColor < m_leftColor)
215 turnLeft();
216 else
217 turnRight();
218
219 m_turn |= AMBIGUOUS;
220 }
221
222 //---------------------------------------------------------------------------------------------
223
224 template <typename PixelSelector>
225 RasterEdgeIterator<PixelSelector>
operator ++()226 &RasterEdgeIterator<PixelSelector>::operator++() {
227 value_type newLeftColor = m_leftColor, newRightColor = m_rightColor;
228
229 int pixAdd = m_dir.y * m_wrap + m_dir.x;
230 if (m_rightSide) {
231 do {
232 m_pos.x += m_dir.x, m_pos.y += m_dir.y;
233 m_leftPix += pixAdd, m_rightPix += pixAdd;
234 m_leftColor = newLeftColor;
235
236 colors(newLeftColor, newRightColor);
237 } while ((newRightColor == m_rightColor) &&
238 (newLeftColor != newRightColor) &&
239 m_selector.skip(m_leftColor, newLeftColor));
240 } else {
241 do {
242 m_pos.x += m_dir.x, m_pos.y += m_dir.y;
243 m_leftPix += pixAdd, m_rightPix += pixAdd;
244 m_rightColor = newRightColor;
245
246 colors(newLeftColor, newRightColor);
247 } while ((newLeftColor == m_leftColor) && (newLeftColor != newRightColor) &&
248 m_selector.skip(m_rightColor, newRightColor));
249 }
250
251 turn(newLeftColor, newRightColor);
252 colors(m_leftColor, m_rightColor);
253
254 return *this;
255 }
256 }
257 } // namespace TRop::borders
258
259 #endif // RASTER_EDGE_ITERATOR_HPP
260