aimstil  5.0.5
mesh_utils.tpp
Go to the documentation of this file.
1 
2 
3 namespace til
4 {
5 
6  //---------------------------------------------------------------------------
7 
8  namespace detail
9  {
10 
11  //-------------------------------------------------------------------------
12 
13  // Exported out of get_n_neighborhood_step to make sure that neigh_n is const so
14  // that if we modify it, we still don't screw up this part: we should not modify
15  // neigh_n while we're iterating on it, because this is a set!
16  // TODO: this could actually be some kind of dilation on a graph.
17  template < typename NeighborCollection >
18  std::set<std::size_t>
19  get_n_neighborhood_unitstep
20  (
21  std::set<std::size_t> const & neigh_n,
22  NeighborCollection const & neighs
23  )
24  {
25  typedef std::set<std::size_t> NeighN;
26  NeighN new_neigh_n = neigh_n;
27  // for all neighbors
28  for (typename NeighN::const_iterator in = neigh_n.begin(); in != neigh_n.end(); ++in)
29  //for (std::size_t j = 0; j < neigh_n.size(); ++j)
30  {
31  // for all neighbors of neighbors
32  //for (std::size_t k = 0; k < neighs[neigh_n[j]].size(); ++k)
33  for (std::size_t k = 0; k < neighs[*in].size(); ++k)
34  {
35  // add neighbor's neighbors to the neighborhood
36  //new_neigh_n.insert(neighs[neigh_n[j]][k]);
37  new_neigh_n.insert(neighs[*in][k]);
38  }
39  }
40  return new_neigh_n;
41  }
42 
43  //-------------------------------------------------------------------------
44 
45  template < typename NeighborCollection >
46  void
47  get_n_neighborhood_step
48  (
49  NeighborCollection const & neigh,
50  std::vector<std::set<std::size_t> > & neigh_n
51  )
52  {
53  assert(neigh.size() == neigh_n.size());
54  // for all vertices
55  for (std::size_t i = 0; i < neigh_n.size(); ++i)
56  {
57  neigh_n[i] = get_n_neighborhood_unitstep(neigh_n[i], neigh);
58  }
59  }
60 
61  //-------------------------------------------------------------------------
62 
63  } // namespace detail
64 
65  //---------------------------------------------------------------------------
66 
67  template < typename NeighborCollection, typename NeighborCollectionOut >
68  void
69  get_n_neighborhood
70  (
71  NeighborCollection const & neigh, ///< [input] The 1-neighborhoods
72  NeighborCollectionOut & neigh_n_out, ///< [output] The computed n-neighborhood
73  unsigned int n ///< [input] the desired neighborhood width
74  )
75  {
76  std::vector<std::set<std::size_t> > neigh_n;
77  neigh_n.resize(neigh.size());
78  // initialize n-neighborhood by including the point itself
79  for (std::size_t i = 0; i < neigh_n.size(); ++i)
80  {
81  neigh_n[i].insert(i);
82  }
83  // iterate
84  // TODO: clearly, this is not optimal for large neighborhoods.
85  for (unsigned int i = 0; i < n; ++i)
86  {
87  detail::get_n_neighborhood_step(neigh, neigh_n);
88  }
89  // finally, remove point
90  for (std::size_t i = 0; i < neigh_n.size(); ++i)
91  {
92  neigh_n[i].erase(i);
93  }
94  neigh_n_out.resize(neigh_n.size());
95  for (std::size_t i = 0; i < neigh_n.size(); ++i)
96  {
97  neigh_n_out[i].resize(neigh_n[i].size());
98  std::copy(neigh_n[i].begin(), neigh_n[i].end(), neigh_n_out[i].begin());
99  }
100  }
101 
102  //---------------------------------------------------------------------------
103 
104  template < typename TFaceCollection >
105  shared_ptr<std::vector<std::vector<typename TFaceCollection::value_type::value_type> > >
106  circular_neighborhoods(TFaceCollection const & faces, std::size_t nVertices)
107  {
108  typedef typename TFaceCollection::value_type::value_type VertexIndex;
109  typedef std::list<VertexIndex> Neighborhood;
110 
111  // Allocate the result -- it should have as many elements as
112  // the number of vertices of the mesh.
113  std::vector<Neighborhood> res(nVertices);
114  // To check if the circular neighbor of a point is finished
115  // NB: we don't use a vector<bool> as it is apparently quite weird...
116  std::vector<unsigned char> isFinished(nVertices, 0);
117  // To check if everything is finished
118  bool allFinished = false;
119 
120  // NB: the strategy here is quite dumb; basically, we loop through all triangles but will discard a neighbor
121  // if it is not the one that fits at the end of our chain. Thus, we have to loop again and again through
122  // this triangle list -- up to the maximum number of neighbors per point, that is, something like 14 times
123  // for brain meshes. Plus, during the last pass, nothing should change, i.e. we'll do an extra pass for
124  // nothing!
125 
126  // TODO: actually we could insert front and back to be hopefully twice as fast...
127  while (!allFinished)
128  {
129  allFinished = true;
130 
131  // for all faces
132  for (typename TFaceCollection::const_iterator iFic = faces.begin(); iFic != faces.end(); ++iFic)
133  {
134  // for all couple of points on the face
135  typename TFaceCollection::value_type::const_iterator iFi1 = iFic->begin();
136  const_cyclic_iterator<typename TFaceCollection::value_type> iFi2(*iFic, iFi1+1);
137 
138  // NB: We decide that iFi2 is the main point, and iFi1 is the neighbor of iFi2 we want to add.
139  // There is a reason why we do not also consider the reverse couple at the same time: this is to
140  // ensure that all circular neighbors are turning in the same order, if the triangles do so.
141  for (;iFi1 != iFic->end(); ++iFi1, ++iFi2)
142  {
143  //std::size_t i = getVertexNumber(mesh, *iFi2);
144  std::size_t i = *iFi2;
145 
146  // Skip voxel if its neighborhood is already done
147  if (isFinished[i])
148  {
149  continue;
150  }
151 
152  // Check size of the neighborhood
153  if (res[i].size() == 0)
154  {
155  // This is the first neighbor added: no need to check anything
156  res[i].push_back(*iFi1);
157  allFinished = false;
158  }
159  else
160  {
161  // We add the neighbor only if it is the "next" neighbor of the chain. That means
162  // that the last point of the neighbor chain has to be in the current face as well.
163  // Note also that we have to end as well: if this next neighbor also happens to be
164  // the first of the chain, we mark this voxel neighborhood as done.
165 
166  // Loop through all face vertices
167  VertexIndex lastPoint = res[i].back();
168  typename TFaceCollection::value_type::const_iterator iFaceVertex = iFic->begin();
169  for (; iFaceVertex != iFic->end(); ++iFaceVertex)
170  {
171  if (*iFaceVertex == lastPoint)
172  {
173  // Check that the point we are about to add is not actually the first point
174  // of the circular neighborhood.
175  if (*iFi1 == res[i].front())
176  {
177  isFinished[i] = 1;
178  }
179  else
180  {
181  res[i].push_back(*iFi1);
182  allFinished = false;
183  }
184  break;
185  }
186  }
187  }
188  }
189  }
190  }
191 
192  //convert the result into a vector
193  shared_ptr<std::vector<std::vector<VertexIndex> > > res2(new std::vector<std::vector<VertexIndex> >);
194  allocate_sameSize(res, *res2);
195  //loop(*res2, res, Convert());
196 
197  {
198  using namespace til::expr;
199  for (std::size_t i = 0; i < size(res); ++i)
200  {
201  detail::loop_xx(castTo(*_1, *_2), (*res2)[i], res[i]);
202  }
203  //detail::loop_xx(castTo(*_1, *_2), *res2, res);
204  }
205  return res2;
206  }
207 
208  //---------------------------------------------------------------------------
209 
210  template < typename T >
211  void
212  neighbors2edges
213  (
214  std::vector<std::vector<T> > const & neighbors,
215  std::vector<std::pair<T, T> > & edges
216  )
217  {
218  typedef std::pair<std::size_t, std::size_t> Edge;
219  std::set<Edge> myedges;
220 #ifndef NDEBUG
221  std::size_t nNeighbors = 0;
222 #endif
223  for (std::size_t i = 0; i < neighbors.size(); ++i)
224  {
225 #ifndef NDEBUG
226  nNeighbors += neighbors.size();
227 #endif
228  for (std::size_t j = 0; j < neighbors[i].size(); ++j)
229  {
230  myedges.insert(make_sorted_pair(i, neighbors[i][j]));
231  }
232  }
233  // works if neighbors is symmetric only...
234  assert(nNeighbors == 2 * myedges.size());
235  // converting back into vector
236  edges.resize(myedges.size());
237  std::copy(myedges.begin(), myedges.end(), edges.begin());
238  }
239 
240  //---------------------------------------------------------------------------
241 
242  template < typename T >
243  void
244  Neighboring_faces<T>::operator()
245  (
246  std::vector<std::vector<T> > const & cneighs
247  , std::vector<numeric_array<T, 3> > const & faces
248  , std::vector<std::vector<T> > & neighborfaces
249  )
250  {
251  typedef numeric_array<T, 3> Vec3D;
252  typedef std::map<Vec3D, T, til::Lexicographical_compare<Vec3D> > Face_indices;
253  Face_indices face_indices;
254  for (std::size_t i = 0; i < faces.size(); ++i)
255  {
256  face_indices[sorted_vector(faces[i])] = i;
257  }
258  neighborfaces.resize(cneighs.size());
259  for (std::size_t i = 0; i < cneighs.size(); ++i)
260  {
261  // NB: this test should never fail, actually a well behaved neighborhood
262  // should have a size >= 3.
263  assert(cneighs[i].size() >= 2);
264  neighborfaces[i].resize(cneighs[i].size());
265  std::size_t nNeighs = cneighs[i].size();
266  for (std::size_t j = 0; j < nNeighs; ++j)
267  {
268  std::size_t j2 = (j+1) % nNeighs;
269  typename Face_indices::iterator pos;
270  pos = face_indices.find(sorted_vector<Vec3D>(i, cneighs[i][j], cneighs[i][j2]));
271  if (pos != face_indices.end())
272  {
273  neighborfaces[i][j] = pos->second;
274  }
275  else
276  {
277  throw InconsistentArguments();
278  }
279  }
280  }
281  }
282 
283  //---------------------------------------------------------------------------
284 
285 } // namespace til