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