1 /*=========================================================================
2  *
3  *  Copyright Insight Software Consortium
4  *
5  *  Licensed under the Apache License, Version 2.0 (the "License");
6  *  you may not use this file except in compliance with the License.
7  *  You may obtain a copy of the License at
8  *
9  *         http://www.apache.org/licenses/LICENSE-2.0.txt
10  *
11  *  Unless required by applicable law or agreed to in writing, software
12  *  distributed under the License is distributed on an "AS IS" BASIS,
13  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  *  See the License for the specific language governing permissions and
15  *  limitations under the License.
16  *
17  *=========================================================================*/
18 #ifndef itkLineConstIterator_hxx
19 #define itkLineConstIterator_hxx
20 
21 #include "itkLineConstIterator.h"
22 
23 namespace itk
24 {
25 template< typename TImage >
26 LineConstIterator< TImage >
LineConstIterator(const ImageType * imagePtr,const IndexType & firstIndex,const IndexType & lastIndex)27 ::LineConstIterator(const ImageType *imagePtr, const IndexType & firstIndex, const IndexType & lastIndex)
28 {
29 
30   m_Image = imagePtr;
31 
32   m_StartIndex = firstIndex;
33   m_LastIndex = lastIndex;
34 
35   IndexType difference;
36   for ( unsigned int i = 0; i < TImage::ImageDimension; ++i )
37     {
38     difference[i] = lastIndex[i] - firstIndex[i];
39     }
40 
41   IndexValueType maxDistance = 0;
42   unsigned int maxDistanceDimension = 0;
43   for ( unsigned int i = 0; i < TImage::ImageDimension; ++i )
44     {
45     IndexValueType distance = itk::Math::abs(difference[i]);
46     if ( distance > maxDistance )
47       {
48       maxDistance = distance;
49       maxDistanceDimension = i;
50       }
51     m_IncrementError[i] = 2 * distance;
52     m_OverflowIncrement[i] = ( difference[i] < 0 ? -1 : 1 );
53     }
54   m_MainDirection = maxDistanceDimension;
55   m_MaximalError.Fill(maxDistance);
56   m_ReduceErrorAfterIncrement.Fill(2 * maxDistance);
57 
58   // Need to set m_EndIndex to be one pixel past the m_LastIndex along
59   // the bresenham line. This is tricky to do.
60   // m_EndIndex[m_MainDirection] is always offset by one from the
61   // m_LastIndex[m_MainDirection].  The other indices may or may not
62   // be incremented depending on the accumulated error to that point.
63   //
64   // To avoid traversing the line to determine whether the other
65   // components need to be adjusted, we merely set the main direction
66   // to be incremented and keep the remaining indices to be same as
67   // LastIndex. Then in the test for IsAtEnd, we just check the
68   // MainDirection component of the index.
69   for ( unsigned int i = 0; i < TImage::ImageDimension; ++i )
70     {
71     if ( i == m_MainDirection )
72       {
73       m_EndIndex[i] = m_LastIndex[i] + m_OverflowIncrement[i];
74       }
75     else
76       {
77       m_EndIndex[i] = m_LastIndex[i];
78       }
79     }
80 
81   m_Region = m_Image->GetBufferedRegion();
82 
83   this->GoToBegin();
84 }
85 
86 template< typename TImage >
87 LineConstIterator< TImage > &
88 LineConstIterator< TImage >
operator =(const Self & it)89 ::operator=(const Self & it)
90 {
91   if(this != &it)
92     {
93     m_Image  = it.m_Image;  // copy the smart pointer
94     m_Region = it.m_Region;
95     m_IsAtEnd = it.m_IsAtEnd;
96     m_CurrentImageIndex   = it.m_CurrentImageIndex;
97     m_StartIndex = it.m_StartIndex;
98     m_LastIndex = it.m_LastIndex;
99     m_EndIndex = it.m_EndIndex;
100     m_MainDirection = it.m_MainDirection;
101     m_AccumulateError = it.m_AccumulateError;
102     m_IncrementError = it.m_IncrementError;
103     m_MaximalError = it.m_MaximalError;
104     m_OverflowIncrement = it.m_OverflowIncrement;
105     m_ReduceErrorAfterIncrement = it.m_ReduceErrorAfterIncrement;
106     }
107   return *this;
108 }
109 
110 template< typename TImage >
111 void
112 LineConstIterator< TImage >
GoToBegin()113 ::GoToBegin()
114 {
115   m_CurrentImageIndex   = m_StartIndex;
116   m_AccumulateError.Fill(0);
117   m_IsAtEnd = ( m_StartIndex[m_MainDirection] == m_EndIndex[m_MainDirection] );
118 }
119 
120 template< typename TImage >
121 void
122 LineConstIterator< TImage >
operator ++()123 ::operator++()
124 {
125   // We need to modify m_AccumulateError, m_CurrentImageIndex, m_IsAtEnd
126   for ( unsigned int i = 0; i < TImage::ImageDimension; ++i )
127     {
128     if ( i == m_MainDirection )
129       {
130       m_CurrentImageIndex[i] += m_OverflowIncrement[i];
131       }
132     else
133       {
134       m_AccumulateError[i] += m_IncrementError[i];
135       if ( m_AccumulateError[i] >= m_MaximalError[i] )
136         {
137         m_CurrentImageIndex[i] += m_OverflowIncrement[i];
138         m_AccumulateError[i] -= m_ReduceErrorAfterIncrement[i];
139         }
140       }
141     }
142 
143   if ( m_CurrentImageIndex[m_MainDirection] == m_EndIndex[m_MainDirection] )
144     {
145     m_IsAtEnd = true;
146     }
147   else if ( !m_Region.IsInside(m_CurrentImageIndex) )
148     {
149     // The new index is outside the acceptable region.  We can iterate no
150     // farther, call this the end.  NOTE THAT INPUT IS STILL INCREMENTED.
151     m_IsAtEnd = true;
152     itkWarningMacro(<< "Line left region; unable to finish tracing it");
153     }
154 }
155 } // end namespace itk
156 
157 #endif
158