| #pragma once |
| |
| #ifndef TCG_IMAGE_ITERATOR_HPP |
| #define TCG_IMAGE_ITERATOR_HPP |
| |
| |
| #include "../image_iterator.h" |
| #include "../pixel_ops.h" |
| |
| namespace tcg { |
| |
| |
| |
| |
| |
| template <typename It, _iei_adherence_policy _adherence> |
| template <typename Img> |
| image_edge_iterator<It, _adherence>::image_edge_iterator(const Img &img, int x, |
| int y, int dirX, |
| int dirY) |
| : m_lx_1(image_traits<Img>::width(img) - 1) |
| , m_ly_1(image_traits<Img>::height(img) - 1) |
| , m_wrap(image_traits<Img>::wrap(img)) |
| , m_pos(x, y) |
| , m_dir(dirX, dirY) |
| , m_outsideColor(image_traits<Img>::outsideColor(img)) |
| , m_elbowColor(m_outsideColor) |
| , m_pix(image_traits<Img>::pixel(img, x, y)) |
| , m_turn(UNKNOWN) { |
| pixels(m_leftPix, m_rightPix); |
| colors(m_leftColor, m_rightColor); |
| } |
| |
| |
| |
| template <typename It, _iei_adherence_policy _adherence> |
| inline void image_edge_iterator<It, _adherence>::pixels(iter pixLeft, |
| iter pixRight) { |
| if (m_dir.y) |
| if (m_dir.y > 0) |
| pixLeft = m_pix - 1, pixRight = m_pix; |
| else |
| pixLeft = m_pix - m_wrap, pixRight = pixLeft - 1; |
| else if (m_dir.x > 0) |
| pixLeft = m_pix, pixRight = m_pix - m_wrap; |
| else |
| pixRight = m_pix - 1, pixLeft = pixRight - m_wrap; |
| } |
| |
| |
| |
| template <typename It, _iei_adherence_policy _adherence> |
| inline void image_edge_iterator<It, _adherence>::colors( |
| value_type &leftColor, value_type &rightColor) { |
| if (m_dir.y) |
| if (m_dir.y > 0) { |
| if (m_pos.y > m_ly_1) |
| leftColor = rightColor = m_outsideColor; |
| else { |
| leftColor = (m_pos.x > 0) ? *m_leftPix : m_outsideColor; |
| rightColor = (m_pos.x <= m_lx_1) ? *m_rightPix : m_outsideColor; |
| } |
| } else { |
| if (m_pos.y < 1) |
| leftColor = rightColor = m_outsideColor; |
| else { |
| leftColor = (m_pos.x <= m_lx_1) ? *m_leftPix : m_outsideColor; |
| rightColor = (m_pos.x > 0) ? *m_rightPix : m_outsideColor; |
| } |
| } |
| else if (m_dir.x > 0) { |
| if (m_pos.x > m_lx_1) |
| leftColor = rightColor = m_outsideColor; |
| else { |
| leftColor = (m_pos.y <= m_ly_1) ? *m_leftPix : m_outsideColor; |
| rightColor = (m_pos.y > 0) ? *m_rightPix : m_outsideColor; |
| } |
| } else { |
| if (m_pos.x < 1) |
| leftColor = rightColor = m_outsideColor; |
| else { |
| leftColor = (m_pos.y > 0) ? *m_leftPix : m_outsideColor; |
| rightColor = (m_pos.y <= m_ly_1) ? *m_rightPix : m_outsideColor; |
| } |
| } |
| } |
| |
| |
| |
| template <typename It, _iei_adherence_policy _adherence> |
| inline void image_edge_iterator<It, _adherence>::turn( |
| const value_type &newLeftColor, const value_type &newRightColor, |
| policy<RIGHT_ADHERENCE>) { |
| if (newLeftColor == m_rightColor) { |
| if (newRightColor == m_leftColor) |
| turnAmbiguous(newLeftColor, newRightColor); |
| else |
| turnLeft(); |
| } else { |
| if (newRightColor != m_rightColor) |
| turnRight(); |
| else |
| m_turn = STRAIGHT; |
| } |
| |
| m_elbowColor = newLeftColor; |
| |
| pixels(m_leftPix, m_rightPix); |
| } |
| |
| |
| |
| template <typename It, _iei_adherence_policy _adherence> |
| inline void image_edge_iterator<It, _adherence>::turn( |
| const value_type &newLeftColor, const value_type &newRightColor, |
| policy<LEFT_ADHERENCE>) { |
| if (newRightColor == m_leftColor) { |
| if (newLeftColor == m_rightColor) |
| turnAmbiguous(newLeftColor, newRightColor); |
| else |
| turnRight(); |
| } else { |
| if (newLeftColor != m_leftColor) |
| turnLeft(); |
| else |
| m_turn = STRAIGHT; |
| } |
| |
| m_elbowColor = newRightColor; |
| |
| pixels(m_leftPix, m_rightPix); |
| } |
| |
| |
| |
| template <typename It, _iei_adherence_policy _adherence> |
| inline void image_edge_iterator<It, _adherence>::turnAmbiguous( |
| const value_type &newLeftColor, const value_type &newRightColor) { |
| UCHAR count1 = 0, count2 = 0; |
| |
| value_type val; |
| |
| |
| if (m_pos.x > 2) { |
| val = *(m_pix - 2); |
| if (val == m_leftColor) |
| ++count1; |
| else if (val == m_rightColor) |
| ++count2; |
| |
| val = *(m_pix - 2 - m_wrap); |
| if (val == m_leftColor) |
| ++count1; |
| else if (val == m_rightColor) |
| ++count2; |
| } |
| |
| if (m_pos.x < m_lx_1) { |
| val = *(m_pix + 1); |
| if (val == m_leftColor) |
| ++count1; |
| else if (val == m_rightColor) |
| ++count2; |
| |
| val = *(m_pix + 1 - m_wrap); |
| if (val == m_leftColor) |
| ++count1; |
| else if (val == m_rightColor) |
| ++count2; |
| } |
| |
| if (m_pos.y > 2) { |
| int wrap2 = m_wrap << 1; |
| |
| val = *(m_pix - wrap2); |
| if (val == m_leftColor) |
| ++count1; |
| else if (val == m_rightColor) |
| ++count2; |
| |
| val = *(m_pix - wrap2 - 1); |
| if (val == m_leftColor) |
| ++count1; |
| else if (val == m_rightColor) |
| ++count2; |
| } |
| |
| if (m_pos.y < m_ly_1) { |
| val = *(m_pix + m_wrap); |
| if (val == m_leftColor) |
| ++count1; |
| else if (val == m_rightColor) |
| ++count2; |
| |
| val = *(m_pix + m_wrap - 1); |
| if (val == m_leftColor) |
| ++count1; |
| else if (val == m_rightColor) |
| ++count2; |
| } |
| |
| |
| if (count1 <= count2) |
| turnRight(); |
| else if (count1 > count2) |
| turnLeft(); |
| |
| m_turn |= AMBIGUOUS; |
| } |
| |
| |
| |
| template <typename It, _iei_adherence_policy _adherence> |
| void image_edge_iterator<It, _adherence>::advance(policy<RIGHT_ADHERENCE>) { |
| value_type newLeftColor = m_leftColor, newRightColor = m_rightColor; |
| |
| int pixAdd = m_dir.y * m_wrap + m_dir.x; |
| |
| m_pos.x += m_dir.x, m_pos.y += m_dir.y; |
| m_pix += pixAdd, m_leftPix += pixAdd, m_rightPix += pixAdd; |
| m_leftColor = newLeftColor; |
| |
| colors(newLeftColor, newRightColor); |
| |
| turn(newLeftColor, newRightColor); |
| colors(m_leftColor, m_rightColor); |
| } |
| |
| |
| |
| template <typename It, _iei_adherence_policy _adherence> |
| void image_edge_iterator<It, _adherence>::advance(policy<LEFT_ADHERENCE>) { |
| value_type newLeftColor = m_leftColor, newRightColor = m_rightColor; |
| |
| int pixAdd = m_dir.y * m_wrap + m_dir.x; |
| |
| m_pos.x += m_dir.x, m_pos.y += m_dir.y; |
| m_pix += pixAdd, m_leftPix += pixAdd, m_rightPix += pixAdd; |
| m_rightColor = newRightColor; |
| |
| colors(newLeftColor, newRightColor); |
| |
| turn(newLeftColor, newRightColor); |
| colors(m_leftColor, m_rightColor); |
| } |
| |
| } |
| |
| #endif |