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 itkSurfaceSpatialObject_hxx
19 #define itkSurfaceSpatialObject_hxx
20
21
22 #include "itkMath.h"
23 #include "itkSurfaceSpatialObject.h"
24
25 namespace itk
26 {
27 /** Constructor */
28 template< unsigned int TDimension >
29 SurfaceSpatialObject< TDimension >
SurfaceSpatialObject()30 ::SurfaceSpatialObject()
31 {
32 this->SetTypeName("SurfaceSpatialObject");
33
34 this->Clear();
35
36 this->Update();
37 }
38
39 template< unsigned int TDimension >
40 void
41 SurfaceSpatialObject< TDimension >
Clear(void)42 ::Clear( void )
43 {
44 Superclass::Clear();
45
46 this->GetProperty().SetRed(1);
47 this->GetProperty().SetGreen(0);
48 this->GetProperty().SetBlue(0);
49 this->GetProperty().SetAlpha(1);
50
51 this->Modified();
52 }
53
54 /** InternalClone */
55 template< unsigned int TDimension >
56 typename LightObject::Pointer
57 SurfaceSpatialObject< TDimension >
InternalClone() const58 ::InternalClone() const
59 {
60 // Default implementation just copies the parameters from
61 // this to new transform.
62 typename LightObject::Pointer loPtr = Superclass::InternalClone();
63
64 typename Self::Pointer rval =
65 dynamic_cast<Self *>(loPtr.GetPointer());
66 if(rval.IsNull())
67 {
68 itkExceptionMacro(<< "downcast to type "
69 << this->GetNameOfClass()
70 << " failed.");
71 }
72
73 return loPtr;
74 }
75
76 /** Print the surface object */
77 template< unsigned int TDimension >
78 void
79 SurfaceSpatialObject< TDimension >
PrintSelf(std::ostream & os,Indent indent) const80 ::PrintSelf(std::ostream & os, Indent indent) const
81 {
82 os << indent << "SurfaceSpatialObject(" << this << ")" << std::endl;
83 Superclass::PrintSelf(os, indent);
84 }
85
86 /** Approximate the normals of the surface */
87 template< unsigned int TDimension >
88 bool
89 SurfaceSpatialObject< TDimension >
Approximate3DNormals()90 ::Approximate3DNormals()
91 {
92 if ( TDimension != 3 )
93 {
94 itkExceptionMacro("Approximate3DNormals works only in 3D");
95 }
96
97 if ( this->m_Points.size() < 3 )
98 {
99 itkExceptionMacro("Approximate3DNormals requires at least 3 points");
100 }
101
102 typename SurfacePointListType::iterator it = this->m_Points.begin();
103 typename SurfacePointListType::iterator itEnd = this->m_Points.end();
104
105 while ( it != itEnd )
106 {
107 // Try to find 3 points close to the corresponding point
108 SurfacePointType pt = *it;
109 PointType pos = ( *it ).GetPositionInObjectSpace();
110
111 std::list< int > badId;
112 unsigned int identifier[3];
113 double absvec = 0;
114 do
115 {
116 identifier[0] = 0;
117 identifier[1] = 0;
118 identifier[2] = 0;
119
120 float max[3];
121 max[0] = 99999999;
122 max[1] = 99999999;
123 max[2] = 99999999;
124
125 typename SurfacePointListType::const_iterator it2 = this->m_Points.begin();
126
127 int i = 0;
128 while ( it2 != this->m_Points.end() )
129 {
130 if ( it2 == it )
131 {
132 i++;
133 it2++;
134 continue;
135 }
136
137 bool badPoint = false;
138 std::list< int >::const_iterator itBadId = badId.begin();
139 while ( itBadId != badId.end() )
140 {
141 if ( *itBadId == i )
142 {
143 badPoint = true;
144 break;
145 }
146 itBadId++;
147 }
148
149 if ( badPoint )
150 {
151 i++;
152 it2++;
153 continue;
154 }
155
156 PointType pos2 = ( *it2 ).GetPositionInObjectSpace();
157 float distance = pos2.EuclideanDistanceTo( pos );
158
159 // Check that the point is not the same as some previously defined
160 bool valid = true;
161 for (auto & j : identifier)
162 {
163 PointType p = this->m_Points[j].GetPositionInObjectSpace();
164 float d = pos2.EuclideanDistanceTo( p );
165 if ( Math::AlmostEquals( d, 0.0f ) )
166 {
167 valid = false;
168 break;
169 }
170 }
171
172 if ( Math::AlmostEquals( distance, 0.0f ) || !valid )
173 {
174 i++;
175 it2++;
176 continue;
177 }
178
179 if ( distance < max[0] )
180 {
181 max[2] = max[1];
182 max[1] = max[0];
183 max[0] = distance;
184 identifier[0] = i;
185 }
186 else if ( distance < max[1] )
187 {
188 max[2] = max[1];
189 max[1] = distance;
190 identifier[1] = i;
191 }
192 else if ( distance < max[2] )
193 {
194 max[2] = distance;
195 identifier[2] = i;
196 }
197 i++;
198 it2++;
199 }
200
201 if ( ( identifier[0] == identifier[1] )
202 || ( identifier[1] == identifier[2] )
203 || ( identifier[0] == identifier[2] )
204 )
205 {
206 std::cout << "Cannot find 3 distinct points!" << std::endl;
207 std::cout << identifier[0] << " : " << identifier[1] << " : "
208 << identifier[2] << std::endl;
209 std::cout << max[0] << " : " << max[1] << " : " << max[2] << std::endl;
210 return false;
211 }
212
213 PointType v1 = this->m_Points[identifier[0]].GetPositionInObjectSpace();
214 PointType v2 = this->m_Points[identifier[1]].GetPositionInObjectSpace();
215 PointType v3 = this->m_Points[identifier[2]].GetPositionInObjectSpace();
216
217 double coa = -( v1[1] * ( v2[2] - v3[2] )
218 + v2[1] * ( v3[2] - v1[2] )
219 + v3[1] * ( v1[2] - v2[2] ) );
220 double cob = -( v1[2] * ( v2[0] - v3[0] )
221 + v2[2] * ( v3[0] - v1[0] )
222 + v3[2] * ( v1[0] - v2[0] ) );
223 double coc = -( v1[0] * ( v2[1] - v3[1] )
224 + v2[0] * ( v3[1] - v1[1] )
225 + v3[0] * ( v1[1] - v2[1] ) );
226
227 absvec = -std::sqrt ( (double)( ( coa * coa ) + ( cob * cob )
228 + ( coc * coc ) ) );
229
230 if ( Math::AlmostEquals( absvec, 0.0 ) )
231 {
232 badId.push_back(identifier[2]);
233 }
234 else
235 {
236 CovariantVectorType normal;
237 normal[0] = coa / absvec;
238 normal[1] = cob / absvec;
239 normal[2] = coc / absvec;
240 ( *it ).SetNormalInObjectSpace(normal);
241 }
242 }
243 while ( ( Math::AlmostEquals( absvec, 0.0 ) )
244 && ( badId.size() < this->m_Points.size() - 1 ) );
245
246 if ( Math::AlmostEquals( absvec, 0.0 ) )
247 {
248 std::cout << "Approximate3DNormals Failed!" << std::endl;
249 std::cout << identifier[0] << " : " << identifier[1] << " : "
250 << identifier[2] << std::endl;
251 std::cout << badId.size() << " : " << this->m_Points.size() - 1 << std::endl;
252 return false;
253 }
254
255 it++;
256 }
257
258 return true;
259 }
260
261 } // end namespace itk
262
263 #endif
264