fw4spl
MeshFunctions.cpp
1 /* ***** BEGIN LICENSE BLOCK *****
2  * FW4SPL - Copyright (C) IRCAD, 2009-2015.
3  * Distributed under the terms of the GNU Lesser General Public License (LGPL) as
4  * published by the Free Software Foundation.
5  * ****** END LICENSE BLOCK ****** */
6 
7 #include "fwMath/MeshFunctions.hpp"
8 #include "fwMath/VectorFunctions.hpp"
9 
10 #include <boost/unordered_map.hpp>
11 #include <list>
12 #include <map>
13 #include <set>
14 
15 namespace fwMath
16 {
17 
18 //-----------------------------------------------------------------------------
19 
20 bool intersect_triangle(fwVec3d _orig, fwVec3d _dir, fwVec3d _vert0,
21  fwVec3d _vert1, fwVec3d _vert2,
22  double &_t, double &_u, double &_v)
23 {
24  const double Epsilon = 0.000001;
25 
26  fwVec3d edge1, edge2, tvec, pvec, qvec;
27 
28  /* find vectors for two edges sharing vert0 */
29  edge1 = _vert1 - _vert0;
30  edge2 = _vert2 - _vert0;
31 
32  /* begin calculating determinant - also used to calculate U parameter */
33  pvec = ::fwMath::cross(_dir, edge2);
34 
35  /* if determinant is near zero, ray lies in plane of triangle */
36  const double Det = ::fwMath::dot(edge1, pvec);
37 
38  if (Det > -Epsilon && Det < Epsilon)
39  {
40  return false;
41  }
42  const double Inv_det = 1.0 / Det;
43 
44  /* calculate distance from vert0 to ray origin */
45  tvec = _orig - _vert0;
46 
47  /* calculate U parameter and test bounds */
48  _u = Inv_det * ::fwMath::dot(tvec, pvec);
49  if (_u < 0.0 || _u > 1.0)
50  {
51  return false;
52  }
53 
54  /* prepare to test V parameter */
55  qvec = ::fwMath::cross(tvec, edge1);
56 
57  /* calculate V parameter and test bounds */
58  _v = Inv_det * ::fwMath::dot(_dir, qvec);
59  if (_v < 0.0 || _u + _v > 1.0)
60  {
61  return false;
62  }
63 
64  /* calculate t, ray intersects triangle */
65  _t = Inv_det * ::fwMath::dot(edge2, qvec);
66  return true;
67 }
68 
69 //------------------------------------------------------------------------------
70 
71 bool IsInclosedVolume(const fwVertexPosition &_vertex, const fwVertexIndex &_vertexIndex, const fwVec3d &_p)
72 {
73  const unsigned int X = 0, Y = 1, Z = 2;
74  const size_t ElementNbr = _vertexIndex.size();
75  if ( ElementNbr == 0 )
76  {
77  return false;
78  }
79 
80  // on regarde tous les triangles du maillage
81  unsigned int intersectionNbr = 0;
82  for ( size_t i = 0; i < ElementNbr; ++i )
83  {
84  //recuperation des trois sommets du triangle
85  const fwVec3d P1 =
86  {_vertex[ _vertexIndex[i][0] ][0], _vertex[ _vertexIndex[i][0] ][1], _vertex[ _vertexIndex[i][0] ][2]};
87  const fwVec3d P2 =
88  {_vertex[ _vertexIndex[i][1] ][0], _vertex[ _vertexIndex[i][1] ][1], _vertex[ _vertexIndex[i][1] ][2]};
89  const fwVec3d P3 =
90  {_vertex[ _vertexIndex[i][2] ][0], _vertex[ _vertexIndex[i][2] ][1], _vertex[ _vertexIndex[i][2] ][2]};
91 
92  //on enleve les triangles s'ils sont situes au dessus du point
93  OSLM_TRACE(
94  "Trg : " << i << " with Z = [" << P1[Z] << "][" << P2[Z] << "][" << P3[Z] << "] compare with " <<
95  _p[Z] );
96 
97  if ( !(P1[Z] > _p[Z] && P2[Z] > _p[Z] && P3[Z] > _p[Z] ) ) //trianglePotentiallyWellPositionned
98  {
99  //on teste la presence des vertex de part et d'autre des 3 axes.
100  //Si P1[X] > P[X] alors il faut necessairement P2[X] < P[X] ou P3[X] < P[X], idem pour les 2 autres axes
101  //En outre cela permet d'exclure les points qui sont situes sur les axes
102  bool stop = false;
103  for ( unsigned int axe = X; axe <= Y && !stop; ++axe )
104  {
105  const double Delta1 = P1[axe] - _p[axe];
106  const double Delta2 = P2[axe] - _p[axe];
107  const double Delta3 = P3[axe] - _p[axe];
108 
109  OSLM_TRACE("d1 : " << Delta1 << "d2 : " << Delta2 << "d3 : " << Delta3 );
110 
111  if ( Delta1 >= 0.f && Delta2 >= 0.f && Delta3 >= 0.f )
112  {
113  stop = true; break;
114  }
115  if ( Delta1 < 0.f && Delta2 < 0.f && Delta3 < 0.f )
116  {
117  stop = true; break;
118  }
119  }
120  if ( !stop )
121  {
122  OSLM_TRACE("The face(" << i << ") is interesting to find a point in volume");
123 
124  fwVec3d orig = {_p[0], _p[1], _p[2]};
125 
126  fwVec3d dir = { 0.f, 0.f, 1.f};
127  fwVec3d vert0 = { P1[0], P1[1], P1[2]};
128  fwVec3d vert1 = { P2[0], P2[1], P2[2]};
129  fwVec3d vert2 = { P3[0], P3[1], P3[2]};
130  double t, u, v;
131  if ( intersect_triangle (orig, dir, vert0, vert1, vert2, t, u, v) )
132  {
133  //on ne garde que les points situes en dessous du point _p selon l'axe (Oz)
134  if (t < 0.f)
135  {
136  OSLM_TRACE(" t = " << t << " u = " << u << " v = " << v);
137  ++intersectionNbr;
138  }
139  }
140  }
141  }
142  }
143  OSLM_TRACE("Nb intersection : " << intersectionNbr);
144  return ( intersectionNbr%2 == 1 );
145 }
146 
147 //-----------------------------------------------------------------------------
148 
149 bool isBorderlessSurface(const fwVertexIndex &_vertexIndex)
150 {
151  typedef std::pair< int, int > Edge; // always Edge.first < Edge.second !!
152  typedef ::boost::unordered_map< Edge, int > EdgeHistogram;
153  EdgeHistogram edgesHistogram;
154  bool isBorderless = true;
155 
156  for(const fwVertexIndex::value_type &vertex : _vertexIndex)
157  {
158  OSLM_ASSERT("Invalid vertex size: "<< vertex.size(), vertex.size() > 2 );
159  ++edgesHistogram[std::make_pair(std::min(vertex[0],vertex[1]), std::max(vertex[0],vertex[1]) )];
160  ++edgesHistogram[std::make_pair(std::min(vertex[0],vertex[2]), std::max(vertex[0],vertex[2]) )];
161  ++edgesHistogram[std::make_pair(std::min(vertex[2],vertex[1]), std::max(vertex[2],vertex[1]) )];
162  }
163 
164  for(const EdgeHistogram::value_type &histo : edgesHistogram)
165  {
166  if (histo.second<2)
167  {
168  isBorderless = false;
169  break;
170  }
171  }
172 
173  return isBorderless;
174 }
175 
176 //-----------------------------------------------------------------------------
177 
178 // container of connected component
179 void findBorderEdges( const fwVertexIndex &_vertexIndex,
180  std::vector< std::vector< std::pair< int, int > > > &contours)
181 {
182  typedef std::pair< int, int > Edge;
183  typedef std::vector< Edge > Contour; // at Border
184  typedef std::vector< Contour> Contours;
185 
186  std::map< Edge, int > edgesHistogram;
187  for ( fwVertexIndex::value_type vertex : _vertexIndex)
188  {
189  assert(vertex.size() > 2 );
190  int i1 = vertex[0];
191  int i2 = vertex[1];
192  int i3 = vertex[2];
193  edgesHistogram[std::make_pair(std::min(i1,i2), std::max(i1,i2) )]++;
194  edgesHistogram[std::make_pair(std::min(i1,i3), std::max(i1,i3) )]++;
195  edgesHistogram[std::make_pair(std::min(i3,i2), std::max(i3,i2) )]++;
196  }
197 
198  for ( const std::map< Edge, int >::value_type& elt1 : edgesHistogram )
199  {
200  if (elt1.second<2) // an orphan found
201  {
202  Contour contour;
203  contour.reserve(1000);
204  std::list< Edge > fifo;
205  Edge orphan = elt1.first;
206 
207  fifo.push_back(orphan);
208  while( !fifo.empty() )
209  {
210  Edge current = fifo.front();
211  contour.push_back( current );
212  fifo.pop_front();
213  edgesHistogram[current] = 2; // to mark it processed;
214 
215  // search neighbor at border and insert in fifo
216  for ( const std::map< Edge, int >::value_type& elt2 : edgesHistogram )
217  {
218  Edge candidate = elt2.first;
219  if ( elt2.second < 2 ) // at border
220  {
221  if ( candidate.first == current.first || candidate.second == current.second || // neighbor
222  candidate.first == current.second || candidate.second == current.first
223  )
224  {
225  edgesHistogram[candidate] = 2; // mark processed;
226  fifo.push_back( candidate );
227  }
228  }
229  }
230  }
231  // all neighbor processed
232  contours.push_back( contour );
233  }
234  }
235 }
236 
237 //-----------------------------------------------------------------------------
238 
239 bool closeSurface( fwVertexPosition &_vertex, fwVertexIndex &_vertexIndex )
240 {
241  typedef std::pair< int, int > Edge;
242  typedef std::vector< Edge > Contour; // at Border
243  typedef std::vector< Contour> Contours;
244 
245  Contours contours;
246  findBorderEdges( _vertexIndex, contours);
247  bool closurePerformed = !contours.empty();
248  // close each hole
249  for( const Contours::value_type& contour : contours )
250  {
251  size_t newVertexIndex = _vertex.size();
252  // create gravity point & insert new triangle
253  std::vector< float > massCenter(3,0);
254 
255  for ( const Contour::value_type& edge : contour )
256  {
257  for (int i = 0; i<3; ++i )
258  {
259  massCenter[i] += _vertex[edge.first][i];
260  massCenter[i] += _vertex[edge.second][i];
261  }
262  // create new Triangle
263  std::vector< int > triangleIndex(3);
264  triangleIndex[0] = edge.first;
265  triangleIndex[1] = edge.second;
266  triangleIndex[2] = newVertexIndex;
267  _vertexIndex.push_back( triangleIndex ); // TEST
268  }
269  for (int i = 0; i<3; ++i )
270  {
271  massCenter[i] /= contour.size()*2;
272  }
273  _vertex.push_back( massCenter ); // normalize barycenter
274  }
275  return closurePerformed;
276 }
277 
278 //-----------------------------------------------------------------------------
279 
280 bool removeOrphanVertices( fwVertexPosition &_vertex, fwVertexIndex &_vertexIndex )
281 {
282  fwVertexPosition newVertex;
283  newVertex.reserve( _vertex.size() );
284 
285  std::set< int > indexPointToKeep;
286 
287  for( const fwVertexIndex::value_type& vertex : _vertexIndex )
288  {
289  indexPointToKeep.insert( vertex[0] );
290  indexPointToKeep.insert( vertex[1] );
291  indexPointToKeep.insert( vertex[2] );
292  }
293 
294  bool orphanFound = indexPointToKeep.size() != _vertex.size();
295 
296  if (orphanFound)
297  {
298  // rebuild index table according to element suppression
299  int idx = 0;
300  std::map< int, int > translate; // map oldIndex -> newIndex (to take into account removal
301  std::set< int >::iterator idxIter;
302  for (int indexPt : indexPointToKeep )
303  {
304  translate[ indexPt ] = idx++;
305  newVertex.push_back( _vertex[ indexPt ] );
306  }
307 
308  for (fwVertexIndex::value_type& vertex : _vertexIndex )
309  {
310  vertex[0] = translate[ vertex[0] ];
311  vertex[1] = translate[ vertex[1] ];
312  vertex[2] = translate[ vertex[2] ];
313  }
314  _vertex.swap(newVertex);
315  }
316  return orphanFound;
317 }
318 
319 
320 } // namespace fwMath
FWMATH_API bool removeOrphanVertices(fwVertexPosition &_vertex, fwVertexIndex &_vertexIndex)
#define OSLM_ASSERT(message, cond)
work like &#39;assert&#39; from &#39;cassert&#39;, with in addition a message logged by spylog (with FATAL loglevel) ...
Definition: spyLog.hpp:310
#define OSLM_TRACE(message)
Definition: spyLog.hpp:230
FWMATH_API bool closeSurface(fwVertexPosition &_vertex, fwVertexIndex &_vertexIndex)
Closes the surface if necessary.
FWMATH_API bool intersect_triangle(fwVec3d _orig, fwVec3d _dir, fwVec3d _vert0, fwVec3d _vert1, fwVec3d _vert2, double &_t, double &_u, double &_v)
Compute the intersection between triangle(define by threes vertex vert1, vert2, vert3) and the Oz par...
The namespace fwMath contains classes which provide the implementation of several mathematic function...
Definition: Compare.hpp:12
FWMATH_API bool isBorderlessSurface(const fwVertexIndex &_vertexIndex)
test whatever a vertex is duplicated or not