aimsalgo 6.0.0
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
39#include <aims/utility/cyclic_iterator.h>
40
41namespace 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)