aimstil  5.0.5
triangle_mesh_geodesic_map.tpp
Go to the documentation of this file.
1 #ifndef TIL_TRIANGLE_MESH_GEODESIC_MAP_TPP_
2 #define TIL_TRIANGLE_MESH_GEODESIC_MAP_TPP_
3 
4 namespace til
5 {
6  //---------------------------------------------------------------------------
7 
8  template < typename TVertices, typename TNeighborhoods, typename TPrec, typename TStopGhost, typename TStoragePolicy >
9  Mesh_distance_map< TVertices, TNeighborhoods, TPrec, TStopGhost, TStoragePolicy >::Mesh_distance_map(const TVertices & vertices, const TNeighborhoods & neighc)
10  : m_vertices(vertices)
11  //, m_faces(faces)
12  , m_neighc(neighc)
13  , m_pLabel()
14  , m_pDist()
15  //, m_pNeigh()
16  , m_stopGhost()
17  {
18  }
19 
20  //---------------------------------------------------------------------------
21 
22  template < typename TVertices, typename TNeighborhoods, typename TPrec, typename TStopGhost, typename TStoragePolicy >
23  Mesh_distance_map< TVertices, TNeighborhoods, TPrec, TStopGhost, TStoragePolicy >::Mesh_distance_map(const TVertices & vertices, const TNeighborhoods & neighc, const TStopGhost & sp)
24  : m_vertices(vertices)
25  //, m_faces(faces)
26  , m_neighc(neighc)
27  , m_pLabel()
28  , m_pDist()
29  //, m_pNeigh()
30  , m_stopGhost(sp)
31  {
32  }
33 
34  //---------------------------------------------------------------------------
35 
36  template < typename TVertices, typename TNeighborhoods, typename TPrec, typename TStopGhost, typename TStoragePolicy >
37  void Mesh_distance_map< TVertices, TNeighborhoods, TPrec, TStopGhost, TStoragePolicy >::init(VertexIndex iVertex)
38  {
39  std::vector<VertexIndex> startPoints(1, iVertex);
40  std::vector<TPrec> startDist(1, TPrec(0));
41  this->init(startPoints, startDist);
42  }
43 
44  //---------------------------------------------------------------------------
45 
46  template < typename TVertices, typename TNeighborhoods, typename TPrec, typename TStopGhost, typename TStoragePolicy >
47  void Mesh_distance_map< TVertices, TNeighborhoods, TPrec, TStopGhost, TStoragePolicy >::process()
48  {
49  // Main loop
50  VertexIndex iVertex;
51  std::size_t i, j;
52  TPrec d;
53 
54  while (!m_queue.empty())
55  {
56  // Get the vertex with the lowest possible distance
57  iVertex = m_queue.top().first;
58  m_queue.pop();
59  //i = getVertexNumber(m_mesh, iVertex);
60  i = iVertex;
61  // Skip point if it is done already
62  // This happens because when an active neighbor is updated with a new (lower) distance estimate
63  // it is pushed again in the queue instead of being updated. priority_queue indeed does not allow
64  // that. The thing is that if we want both voxel access and distance access, one has to be linear
65  // in time. Dunno which is better, in any case it's kind of a pain.
66  if ((*m_pLabel)[i] == DONE)
67  {
68  continue;
69  }
70 
71  if (!m_stopGhost.proceed(i, *this)) break;
72 
73  // Mark it as DONE
74  (*m_pLabel)[i] = DONE;
75 
76  // Loop on its neighbors
77  //for (typename Neighborhood::const_iterator iNeighbor = (*m_pNeigh)[i].begin();
78  // iNeighbor != (*m_pNeigh)[i].end(); ++iNeighbor)
79  for (typename Neighborhood::const_iterator iNeighbor = m_neighc[i].begin();
80  iNeighbor != m_neighc[i].end(); ++iNeighbor)
81  {
82  //j = getVertexNumber(m_mesh, *iNeighbor);
83  j = *iNeighbor;
84  // Skip DONE points
85  if ((*m_pLabel)[j] == DONE)
86  {
87  continue;
88  }
89  // Get new estimate
90  d = distanceEstimate(*iNeighbor);
91  (*m_pDist)[j] = d;
92  // Add them in the priority queue
93  m_queue.push(std::make_pair(*iNeighbor, d));
94  }
95  }
96  m_allDone = true;
97  }
98 
99  //---------------------------------------------------------------------------
100 
101  template < typename TVertices, typename TNeighborhoods, typename TPrec, typename TStopGhost, typename TStoragePolicy >
102  template < typename TVertexIndex >
103  void Mesh_distance_map< TVertices, TNeighborhoods, TPrec, TStopGhost, TStoragePolicy >::init(std::vector<TVertexIndex> & startPoints, std::vector<TPrec> & startDist)
104  {
105  // Check that input sizes are the same
106  assert(size(startPoints) == size(startDist));
107 
108  this->_init();
109 
110  typename std::vector<TVertexIndex>::const_iterator i = startPoints.begin();
111  typename std::vector<TPrec>::const_iterator d = startDist.begin();
112  for (; i < startPoints.end(); ++i, ++d)
113  {
114  //std::size_t index = getVertexNumber(m_mesh, *i);
115  std::size_t index = *i;
116  // Label input points as DONE
117  (*m_pLabel)[index] = DONE;
118  // Copy input distances in our results
119  (*m_pDist)[index] = *d;
120  // Process starting points neighbors
121  //typename MeshTraits<TMesh>::NeighborIndex nic = getNeighborIndices(m_mesh)[getVertexNumber(m_mesh, *i)];
122  const Neighborhood & nic = m_neighc[*i];
123  //typename MeshTraits<TMesh>::NeighborIndex::const_iterator iNeighbor = nic.begin();
124  typename Neighborhood::const_iterator iNeighbor = nic.begin();
125  for (; iNeighbor != nic.end(); ++iNeighbor)
126  {
127  // Label neighbors of starting points as ACTIVE
128  // label[getVertexNumber(mesh, *iNeighbor)] = ACTIVE;
129  // Compute their geodesic distance
130  TPrec d = distanceEstimate(*iNeighbor);
131 
132  //(*m_pDist)[getVertexNumber(m_mesh, *iNeighbor)] = d;
133  (*m_pDist)[*iNeighbor] = d;
134  // Add them in the priority queue
135  m_queue.push(std::make_pair(*iNeighbor, d));
136  }
137  }
138  }
139 
140  //---------------------------------------------------------------------------
141 
142  template < typename TVertices, typename TNeighborhoods, typename TPrec, typename TStopGhost, typename TStoragePolicy >
143  void Mesh_distance_map<TVertices, TNeighborhoods, TPrec, TStopGhost, TStoragePolicy>::
144  _init()
145  {
146  if (m_pLabel == 0)
147  m_pLabel = shared_ptr<LabelCollection>(new LabelCollection(m_vertices.size()));
148  if (m_pDist == 0)
149  m_pDist = shared_ptr<DistCollection>(new DistCollection(m_vertices.size()));
150 
151  assert(size(*m_pLabel) == m_vertices.size());
152  assert(size(*m_pDist) == m_vertices.size());
153 
154  // set all points as being unprocessed
155  fill(*m_pLabel, Label(UNACTIVE));
156  // set initial distance to infinity -- or close enough ;)
157  fill(*m_pDist, std::numeric_limits<TPrec>::max());
158  m_allDone = false;
159  }
160 
161  //---------------------------------------------------------------------------
162 
163  template < typename TVertices, typename TNeighborhoods, typename TPrec, typename TStopGhost, typename TStoragePolicy >
164  TPrec Graph_distance_map< TVertices, TNeighborhoods, TPrec, TStopGhost, TStoragePolicy >::distanceEstimate(VertexIndex iVertex)
165  {
166  //std::size_t k = getVertexNumber(Base::m_mesh, iVertex);
167  std::size_t k = iVertex;
168  TPrec res = (*Base::m_pDist)[k];
169  const Neighborhood & nh = Base::m_neighc[k];
170  for (typename Neighborhood::const_iterator iN = nh.begin(); iN != nh.end(); ++iN)
171  {
172  //if ((*Base::m_pLabel)[getVertexNumber(Base::m_mesh, *iN)] == Base::DONE)
173  if ((*Base::m_pLabel)[*iN] == Base::DONE)
174  {
175  //res = min(res, (*Base::m_pDist)[getVertexNumber(Base::m_mesh, *iN)] + dist(getVertex(iVertex, Base::m_mesh), getVertex(*iN, Base::m_mesh), prec<TPrec>()));
176  res = min(res, (*Base::m_pDist)[*iN] + dist(Base::m_vertices[iVertex], Base::m_vertices[*iN], prec<TPrec>()));
177  }
178  }
179  return res;
180  }
181 
182  //---------------------------------------------------------------------------
183 
184  template < typename TVertices, typename TCircularNeighborhoods, typename TPrec, typename TStopGhost, typename TStoragePolicy >
185  TPrec Triangle_mesh_geodesic_map<TVertices, TCircularNeighborhoods, TPrec, TStopGhost, TStoragePolicy>::distanceEstimate(VertexIndex iVertex)
186  {
187  const TPrec F = TPrec(1);
188  //std::size_t k = getVertexNumber(Base::m_mesh, iVertex);
189  std::size_t k = iVertex;
190  //Neighborhood &nh = (*Base::m_pNeigh)[k];
191  const Neighborhood & nh = Base::m_neighc[k];
192  //typename til::const_cyclic_iterator<Neighborhood> iN2((*m_neigh)[getVertexNumber(m_mesh, iVertex)], iN+1);
193  math::PolySolver_real<TPrec, math::policy::InfinitySolutions_None> solver;
194 
195  TPrec res = (*Base::m_pDist)[k];
196 
197  // For each neighbor of iVertex
198  //for (typename Neighborhood::const_iterator iN = nh.begin(); iN != nh.end(); ++iN, ++iN2)
199  for (typename Neighborhood::const_iterator iN = nh.begin(); iN != nh.end(); ++iN)
200  {
201  //if ((*Base::m_pLabel)[getVertexNumber(Base::m_mesh, *iN)] == Base::DONE)
202  if ((*Base::m_pLabel)[*iN] == Base::DONE)
203  {
204  // NB: Notations of "Computing Geodesic Paths on Manifolds", Kimmel & Sethian, 97
205  TPrec b2 = dist2(Base::m_vertices[iVertex], Base::m_vertices[*iN], prec<TPrec>());
206  std::size_t iA = *iN;
207  TPrec dA = (*Base::m_pDist)[iA];
208 
209  typename Neighborhood::const_iterator iN2 = cyclic_advance(iN, nh);
210 
211  if ((*Base::m_pLabel)[*iN2] == Base::DONE)
212  {
213  //std::size_t iB = getVertexNumber(Base::m_mesh, *iN2);
214  std::size_t iB = *iN2;
215  TPrec dB = (*Base::m_pDist)[iB];
216  //TPrec a2 = dist2(getVertex(iVertex, Base::m_mesh), getVertex(*iN2, Base::m_mesh), prec<TPrec>());
217  //TPrec c2 = dist2(getVertex(*iN, Base::m_mesh), getVertex(*iN2, Base::m_mesh), prec<TPrec>());
218  TPrec a2 = dist2(Base::m_vertices[iVertex], Base::m_vertices[*iN2], prec<TPrec>());
219  TPrec c2 = dist2(Base::m_vertices[*iN], Base::m_vertices[*iN2], prec<TPrec>());
220 
221  if (dB < dA)
222  {
223  std::swap(a2,b2);
224  std::swap(iA, iB);
225  std::swap(dB, dA);
226  }
227 
228  // We compute these after the previous test to avoid having to swap them as well
229  TPrec u = dB - dA;
230  TPrec a = std::sqrt(a2);
231  TPrec b = std::sqrt(b2);
232 
233  // Question: what do we want to do when div by zero, given that this never happened?
234  TPrec ctheta = fraction<policy::ZeroByZero_Zero, TPrec>(a2+b2-c2, 2*a*b);
235 
236  if (ctheta > 1) ctheta = 1;
237  else if (ctheta < -1) ctheta = -1;
238 
239  solver.solve(c2, 2*u*b*(a*ctheta-b), b2*(u*u-F*F*a2*(1-ctheta*ctheta)));
240 
241  // TODO: this has to change
242  if (solver.nsols() == 0)
243  {
244  res = min(res, b*F + dA, a*F + dB);
245  }
246  else
247  {
248  for (int i = 0; i < solver.nsols(); ++i)
249  {
250  TPrec t = solver.sols()[i];
251  if ((u < t) &&
252  (t*a*ctheta < b*(t-u)) &&
253  (ctheta <= 0 || b*(t-u)*ctheta < a*t))
254  {
255  res = min(res, t + dA);
256  }
257  else
258  {
259  res = min(res, b*F + dA, a*F + dB);
260  }
261  }
262  }
263 
264  // TODO: Optimized version still in the boxes
265  /*
266  Vector<float,3> base = getVertexNumber(m_mesh, *iN2) - getVertexNumber(m_mesh, *iN);
267  Vector<float,3> side = getVertexNumber(m_mesh, iVertex) - getVertexNumber(m_mesh, *iN)
268  math::Poly2solver_real p(
269  norm2(base),
270  -2*u*dot(base,side),
271  u*u*norm2(side) - F^2*crossnorm2(base, side)
272  );
273 
274  for (int i = 0; i < p.nsols(); ++i)
275  {
276  if (fabs(u) < t &&
277  }
278  */
279  }
280  else
281  {
282  res = min(res, std::sqrt(b2)*F + dA);
283  }
284  }
285  }
286  return res;
287  }
288 
289  //---------------------------------------------------------------------------
290 
291  template < typename TVertices, typename TCircularNeighborhoods, typename TPrec, typename TStopGhost, typename TStoragePolicy >
292  TPrec Voronoi_triangle_mesh_geodesic_map<TVertices, TCircularNeighborhoods, TPrec, TStopGhost, TStoragePolicy>::distanceEstimate(VertexIndex iVertex)
293  {
294  const TPrec F = TPrec(1);
295  //std::size_t k = getVertexNumber(Base::m_mesh, iVertex);
296  std::size_t k = iVertex;
297  const Neighborhood &nh = Base::m_neighc[k];
298  //typename til::const_cyclic_iterator<Neighborhood> iN2((*m_neigh)[getVertexNumber(m_mesh, iVertex)], iN+1);
299  math::PolySolver_real<TPrec, math::policy::InfinitySolutions_None> solver;
300 
301  TPrec res = (*Base::m_pDist)[k];
302 
303  // For each neighbor of iVertex
304  //for (typename Neighborhood::const_iterator iN = nh.begin(); iN != nh.end(); ++iN, ++iN2)
305  for (typename Neighborhood::const_iterator iN = nh.begin(); iN != nh.end(); ++iN)
306  {
307  //std::size_t iA = getVertexNumber(Base::m_mesh, *iN);
308  std::size_t iA = *iN;
309  if ((*Base::m_pLabel)[iA] == Base::DONE)
310  {
311  // NB: Notations of "Computing Geodesic Paths on Manifolds", Kimmel & Sethian, 97
312  //TPrec b2 = dist2(getVertex(iVertex, Base::m_mesh), getVertex(*iN, Base::m_mesh), prec<TPrec>());
313  TPrec b2 = dist2(Base::m_vertices[iVertex], Base::m_vertices[*iN], prec<TPrec>());
314  TPrec dA = (*Base::m_pDist)[iA];
315 
316  typename Neighborhood::const_iterator iN2 = cyclic_advance(iN, nh);
317 
318  //std::size_t iB = getVertexNumber(Base::m_mesh, *iN2);
319  std::size_t iB = *iN2;
320  if ((*Base::m_pLabel)[iB] == Base::DONE && (*m_clusterLabel)[iB] == (*m_clusterLabel)[iA])
321  {
322  TPrec dB = (*Base::m_pDist)[iB];
323  TPrec a2 = dist2(Base::m_vertices[iVertex], Base::m_vertices[*iN2], prec<TPrec>());
324  TPrec c2 = dist2(Base::m_vertices[*iN], Base::m_vertices[*iN2], prec<TPrec>());
325 
326  if (dB < dA)
327  {
328  std::swap(a2,b2);
329  std::swap(iA, iB);
330  std::swap(dB, dA);
331  }
332 
333  // We compute these after the previous test to avoid having to swap them as well
334  TPrec u = dB - dA;
335  TPrec a = std::sqrt(a2);
336  TPrec b = std::sqrt(b2);
337 
338  // Question: what do we want to do when div by zero, given that this never happened?
339  TPrec ctheta = fraction<policy::ZeroByZero_Zero, TPrec>(a2+b2-c2, 2*a*b);
340 
341  if (ctheta > 1) ctheta = 1;
342  else if (ctheta < -1) ctheta = -1;
343 
344  solver.solve(c2, 2*u*b*(a*ctheta-b), b2*(u*u-F*F*a2*(1-ctheta*ctheta)));
345 
346  // TODO: this has to change
347  if (solver.nsols() == 0)
348  {
349  TPrec tmp = min(b*F + dA, a*F + dB);
350  if (res > tmp)
351  {
352  res = tmp;
353  (*m_clusterLabel)[k] = (*m_clusterLabel)[iA];
354  }
355  }
356  else
357  {
358  for (int i = 0; i < solver.nsols(); ++i)
359  {
360  TPrec t = solver.sols()[i];
361  if ((u < t) &&
362  (t*a*ctheta < b*(t-u)) &&
363  (ctheta <= 0 || b*(t-u)*ctheta < a*t))
364  {
365  TPrec tmp = t + dA;
366  if (res > tmp)
367  {
368  res = tmp;
369  (*m_clusterLabel)[k] = (*m_clusterLabel)[iA];
370  }
371  }
372  else
373  {
374  TPrec tmp = min(b*F + dA, a*F + dB);
375  if (res > tmp)
376  {
377  res = tmp;
378  (*m_clusterLabel)[k] = (*m_clusterLabel)[iA];
379  }
380  }
381  }
382  }
383  }
384  else
385  {
386  TPrec tmp = std::sqrt(b2)*F + dA;
387  if (res > tmp)
388  {
389  res = tmp;
390  (*m_clusterLabel)[k] = (*m_clusterLabel)[iA];
391  }
392  }
393  }
394  }
395  return res;
396  }
397 
398  //---------------------------------------------------------------------------
399 
400  template < typename TVertices, typename TNeighbors, typename TPrec >
401  void
402  distance_to_neighbors
403  (
404  TVertices const & vertices
405  , TNeighbors const & neighbors
406  , TPrec distance
407  , std::vector<til::sparse_vector<TPrec> > & res
408  )
409  {
410  std::size_t n = vertices.size();
411  typedef std::vector<std::vector<std::size_t> > CNeighborhoods;
412 
413  typedef til::ghost::GMapStop_AboveThreshold<TPrec> Stop_ghost;
414  Stop_ghost stop_ghost(distance);
415 
416  // til::policy::GMap_DefaultStorage<til::sparse_vector, TPrec > replaced by GMap_DefaultStorage_sparse_vect_dbl
417  til::Triangle_mesh_geodesic_map<TVertices, CNeighborhoods, TPrec, Stop_ghost, til::policy::GMap_DefaultStorage_sparse_vect_dbl >
418 
419  //til::Graph_distance_map<TMesh, double, til::ghost::GMapStop_AboveThreshold<double>, til::policy::GMap_DefaultStorage<til::sparse_vector, TMesh, double > >
420  //til::Graph_distance_map<typename TMesh::VertexCollection, CNeighborhoods, double, til::ghost::GMapStop_AboveThreshold<double>, til::policy::GMap_DefaultStorage<til::sparse_vector, double > >
421  //til::Graph_distance_map<TMesh, double, til::ghost::GMapStop_AboveThreshold<double> >
422  geomap(vertices, neighbors, stop_ghost);
423  std::vector<std::size_t> startPoints(1);
424  std::vector<TPrec> dist(1, TPrec(0.0));
425  res.resize(n);
426  shared_ptr<til::sparse_vector<unsigned char> > labels;
427  for (std::size_t i = 0; i < n; ++i)
428  {
429  startPoints[0] = i;
430  geomap.init(startPoints, dist);
431  geomap.process();
432  res[i] = *(geomap.distanceMap());
433  labels = geomap.labels();
434  // this removed temporary, boundary points that are generaly there when
435  // a stopping ghost is used.
436  for (typename til::sparse_vector<TPrec>::Map::iterator j = res[i].getMap().begin();
437  j != res[i].getMap().end();)
438  {
439  if ((*labels)[j->first] != (unsigned char)(1))
440  {
441  res[i].getMap().erase(j++);
442  }
443  else
444  {
445  ++j;
446  }
447  }
448  }
449  }
450 
451 } // namespace til
452 
453 #endif /*TRIANGLE_MESH_GEODESIC_MAP_TPP_*/