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