aimsalgo  5.1.2
Neuroimaging image processing
mesh_graph_d.h
Go to the documentation of this file.
1 /* This software and supporting documentation are distributed by
2  * Institut Federatif de Recherche 49
3  * CEA/NeuroSpin, Batiment 145,
4  * 91191 Gif-sur-Yvette cedex
5  * France
6  *
7  * This software is governed by the CeCILL-B license under
8  * French law and abiding by the rules of distribution of free software.
9  * You can use, modify and/or redistribute the software under the
10  * terms of the CeCILL-B license as circulated by CEA, CNRS
11  * and INRIA at the following URL "http://www.cecill.info".
12  *
13  * As a counterpart to the access to the source code and rights to copy,
14  * modify and redistribute granted by the license, users are provided only
15  * with a limited warranty and the software's author, the holder of the
16  * economic rights, and the successive licensors have only limited
17  * liability.
18  *
19  * In this respect, the user's attention is drawn to the risks associated
20  * with loading, using, modifying and/or developing or reproducing the
21  * software by the user in light of its specific status of free software,
22  * that may mean that it is complicated to manipulate, and that also
23  * therefore means that it is reserved for developers and experienced
24  * professionals having in-depth computer knowledge. Users are therefore
25  * encouraged to load and test the software's suitability as regards their
26  * requirements in conditions enabling the security of their systems and/or
27  * data to be ensured and, more generally, to use and operate it in the
28  * same conditions as regards security.
29  *
30  * The fact that you are presently reading this means that you have had
31  * knowledge of the CeCILL-B license and that you accept its terms.
32  */
33 
34 
35 #ifndef AIMS_MESH_MESH_GRAPH_D_H
36 #define AIMS_MESH_MESH_GRAPH_D_H
37 
38 #include <aims/mesh/mesh_graph.h>
40 
41 namespace aims
42 {
43 
44  namespace meshgraph
45  {
46 
47  template < typename TFaceCollection >
48  carto::rc_ptr<std::vector<std::vector<
49  typename TFaceCollection::value_type::value_type> > >
50  circular_neighborhoods( TFaceCollection const & faces,
51  std::size_t nVertices )
52  {
53  typedef typename TFaceCollection::value_type::value_type VertexIndex;
54  typedef std::list<VertexIndex> Neighborhood;
55 
56  // Allocate the result -- it should have as many elements as
57  // the number of vertices of the mesh.
58  std::vector<Neighborhood> res(nVertices);
59  // To check if the circular neighbor of a point is finished
60  // NB: we don't use a vector<bool> as it is apparently quite weird...
61  std::vector<unsigned char> isFinished(nVertices, 0);
62  // To check if everything is finished
63  bool allFinished = false;
64 
65  // NB: the strategy here is quite dumb; basically, we loop through all triangles but will discard a neighbor
66  // if it is not the one that fits at the end of our chain. Thus, we have to loop again and again through
67  // this triangle list -- up to the maximum number of neighbors per point, that is, something like 14 times
68  // for brain meshes. Plus, during the last pass, nothing should change, i.e. we'll do an extra pass for
69  // nothing!
70 
71  while (!allFinished)
72  {
73  allFinished = true;
74 
75  // for all faces
76  for (typename TFaceCollection::const_iterator iFic = faces.begin(); iFic != faces.end(); ++iFic)
77  {
78  // for all couple of points on the face
79  typename TFaceCollection::value_type::const_iterator iFi1 = iFic->begin();
81 
82  // NB: We decide that iFi2 is the main point, and iFi1 is the neighbor of iFi2 we want to add.
83  // There is a reason why we do not also consider the reverse couple at the same time: this is to
84  // ensure that all circular neighbors are turning in the same order, if the triangles do so.
85  for (;iFi1 != iFic->end(); ++iFi1, ++iFi2)
86  {
87  std::size_t i = *iFi2;
88 
89  // Skip voxel if its neighborhood is already done
90  if( !isFinished[i] )
91  {
92 
93  // Check size of the neighborhood
94  if (res[i].size() == 0)
95  {
96  // This is the first neighbor added: no need to check anything
97  res[i].push_back(*iFi1);
98  allFinished = false;
99  }
100  else
101  {
102  // We add the neighbor only if it is the "next" neighbor of the chain. That means
103  // that the last point of the neighbor chain has to be in the current face as well.
104  // Note also that we have to end as well: if this next neighbor also happens to be
105  // the first of the chain, we mark this voxel neighborhood as done.
106 
107  // Loop through all face vertices
108  VertexIndex lastPoint = res[i].back();
109  if( *iFi1 != lastPoint ) // otherwise already done this one
110  {
111 
112  typename TFaceCollection::value_type::const_iterator
113  iFaceVertex = iFic->begin();
114  for( ; iFaceVertex != iFic->end(); ++iFaceVertex )
115  {
116  if (*iFaceVertex == lastPoint)
117  {
118  // Check that the point we are about to add is not
119  // actually the first point of the circular neighborhood.
120  if (*iFi1 == res[i].front())
121  {
122  isFinished[i] = 1;
123  }
124  else if( *iFi1 != lastPoint )
125  {
126  res[i].push_back(*iFi1);
127  allFinished = false;
128  }
129  break;
130  }
131  }
132  }
133  }
134  }
135 
136  // and the other way
137  i = *iFi1;
138 
139  // Skip voxel if its neighborhood is already done
140  if( !isFinished[i] )
141  {
142 
143  // Check size of the neighborhood
144  if (res[i].size() == 0)
145  {
146  // This is the first neighbor added: no need to check anything
147  res[i].insert( res[i].begin(), *iFi2 );
148  allFinished = false;
149  }
150  else
151  {
152  // We add the neighbor only if it is the "first" neighbor of the chain. That means
153  // that the first point of the neighbor chain has to be in the current face as well.
154  // Note also that we have to end as well: if this first neighbor also happens to be
155  // the last of the chain, we mark this voxel neighborhood as done.
156 
157  // Loop through all face vertices
158  VertexIndex firstPoint = res[i].front();
159  if( *iFi2 != firstPoint ) // otherwise already done this one
160  {
161 
162  typename TFaceCollection::value_type::const_iterator
163  iFaceVertex = iFic->begin();
164  for( ; iFaceVertex != iFic->end(); ++iFaceVertex )
165  {
166  if (*iFaceVertex == firstPoint)
167  {
168  // Check that the point we are about to add is not
169  // actually the last point of the circular neighborhood.
170  if (*iFi2 == res[i].back())
171  {
172  isFinished[i] = 1;
173  }
174  else if( *iFi2 != firstPoint )
175  {
176  res[i].insert( res[i].begin(), *iFi2 );
177  allFinished = false;
178  }
179  break;
180  }
181  }
182  }
183  }
184  }
185 
186  }
187  }
188  }
189 
190  //convert the result into a vector
192  res2(new std::vector<std::vector<VertexIndex> >( res.size()) );
193 
194  {
195  for (std::size_t i = 0; i < res.size(); ++i)
196  {
197  std::vector<VertexIndex> & r2 = (*res2)[i];
198  r2.resize( res[i].size() );
199  size_t j = 0;
200  typename std::list<VertexIndex>::iterator il, el = res[i].end();
201  for( il=res[i].begin(); il!=el; ++il, ++j )
202  r2[j] = *il;
203  }
204  }
205  return res2;
206  }
207 
208 
209  //-------------------------------------------------------------------------
210 
211  template < typename TVertexNode, typename TFaceNode, typename TVertexCollection, typename TFaceCollection, typename TNeighborCollection >
213  operator()
214  (
215  TVertexCollection const & vertices,
216  TFaceCollection const & faceIndices,
217  std::vector<std::list<std::size_t> > const & invertedFaceIndices,
218  TNeighborCollection const & neighbors,
219  std::list<TVertexNode> & graph_vertices,
220  std::list<TFaceNode> & graph_faces
221  )
222  {
223  if( vertices.size() != invertedFaceIndices.size() )
224  throw std::runtime_error(
225  "vertices and invertedFaceIndices sizes differ" );
226  if( vertices.size() != neighbors.size() )
227  throw std::runtime_error( "vertices and neighbors sizes differ" );
228 
229  _index_vertex.resize(vertices.size());
230  _index_face.resize(faceIndices.size());
231  {
232  // push all vertices into the vertex list and get an index2iterator translation
233  for (std::size_t i = 0; i < vertices.size(); ++i)
234  {
235  // create a node with current position
236  TVertexNode m;
237  m.pos() = vertices[i];
238  // push this node at the end of the vertex list
239  _index_vertex[i] = graph_vertices.insert(graph_vertices.end(), m);
240  }
241 
242  // now push all faces into the face list
243  for (std::size_t i = 0; i < faceIndices.size(); ++i)
244  {
245  // create a face with current face indices
246  TFaceNode f;
247  for (int j = 0; j < 3; ++j)
248  {
249  if( vertices.size() <= faceIndices[i][j] )
250  throw std::runtime_error(
251  "vertices size smaller than used faceIndices" );
252  f.face[j] = _index_vertex[faceIndices[i][j]];
253  }
254  // push this face at the end of the face list
255  _index_face[i] = graph_faces.insert(graph_faces.end(), f);
256  }
257 
258  // now we need a second pass on the vertices to fill in the neighbor
259  // and the faces structure.
260  for (std::size_t i = 0; i < vertices.size(); ++i)
261  {
262  for (std::list<std::size_t>::const_iterator j = invertedFaceIndices[i].begin(); j != invertedFaceIndices[i].end(); ++j)
263  {
264  if( faceIndices.size() <= *j )
265  throw std::runtime_error(
266  "faceIndices size smaller than used invertedFaceIndices" );
267  _index_vertex[i]->faces().push_back(_index_face[*j]);
268  }
269  for (typename TNeighborCollection::value_type::const_iterator iN = neighbors[i].begin();
270  iN != neighbors[i].end(); ++iN)
271  {
272  if( vertices.size() <= *iN )
273  throw std::runtime_error(
274  "vertices size smaller than used neighbors indices" );
275  _index_vertex[i]->neighbors().push_back(_index_vertex[*iN]);
276  }
277  }
278  }
279  }
280 
281  }
282 }
283 
284 #endif
285 
Converts a AimsSurface mesh into a (vertexList, faceList) mesh graph.
Definition: mesh_graph.h:119
carto::rc_ptr< std::vector< std::vector< typename TFaceCollection::value_type::value_type > > > circular_neighborhoods(TFaceCollection const &faces, std::size_t nVertices)
Definition: mesh_graph_d.h:50