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