1 #ifndef TIL_TRIANGLE_MESH_GEODESIC_MAP_TPP_
2 #define TIL_TRIANGLE_MESH_GEODESIC_MAP_TPP_
6 //---------------------------------------------------------------------------
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)
20 //---------------------------------------------------------------------------
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)
34 //---------------------------------------------------------------------------
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)
39 std::vector<VertexIndex> startPoints(1, iVertex);
40 std::vector<TPrec> startDist(1, TPrec(0));
41 this->init(startPoints, startDist);
44 //---------------------------------------------------------------------------
46 template < typename TVertices, typename TNeighborhoods, typename TPrec, typename TStopGhost, typename TStoragePolicy >
47 void Mesh_distance_map< TVertices, TNeighborhoods, TPrec, TStopGhost, TStoragePolicy >::process()
54 while (!m_queue.empty())
56 // Get the vertex with the lowest possible distance
57 iVertex = m_queue.top().first;
59 //i = getVertexNumber(m_mesh, 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)
71 if (!m_stopGhost.proceed(i, *this)) break;
74 (*m_pLabel)[i] = DONE;
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)
82 //j = getVertexNumber(m_mesh, *iNeighbor);
85 if ((*m_pLabel)[j] == DONE)
90 d = distanceEstimate(*iNeighbor);
92 // Add them in the priority queue
93 m_queue.push(std::make_pair(*iNeighbor, d));
99 //---------------------------------------------------------------------------
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)
105 // Check that input sizes are the same
106 assert(size(startPoints) == size(startDist));
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)
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)
127 // Label neighbors of starting points as ACTIVE
128 // label[getVertexNumber(mesh, *iNeighbor)] = ACTIVE;
129 // Compute their geodesic distance
130 TPrec d = distanceEstimate(*iNeighbor);
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));
140 //---------------------------------------------------------------------------
142 template < typename TVertices, typename TNeighborhoods, typename TPrec, typename TStopGhost, typename TStoragePolicy >
143 void Mesh_distance_map<TVertices, TNeighborhoods, TPrec, TStopGhost, TStoragePolicy>::
147 m_pLabel = shared_ptr<LabelCollection>(new LabelCollection(m_vertices.size()));
149 m_pDist = shared_ptr<DistCollection>(new DistCollection(m_vertices.size()));
151 assert(size(*m_pLabel) == m_vertices.size());
152 assert(size(*m_pDist) == m_vertices.size());
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());
161 //---------------------------------------------------------------------------
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)
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)
172 //if ((*Base::m_pLabel)[getVertexNumber(Base::m_mesh, *iN)] == Base::DONE)
173 if ((*Base::m_pLabel)[*iN] == Base::DONE)
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>()));
182 //---------------------------------------------------------------------------
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)
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;
195 TPrec res = (*Base::m_pDist)[k];
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)
201 //if ((*Base::m_pLabel)[getVertexNumber(Base::m_mesh, *iN)] == Base::DONE)
202 if ((*Base::m_pLabel)[*iN] == Base::DONE)
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];
209 typename Neighborhood::const_iterator iN2 = cyclic_advance(iN, nh);
211 if ((*Base::m_pLabel)[*iN2] == Base::DONE)
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>());
228 // We compute these after the previous test to avoid having to swap them as well
230 TPrec a = std::sqrt(a2);
231 TPrec b = std::sqrt(b2);
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);
236 if (ctheta > 1) ctheta = 1;
237 else if (ctheta < -1) ctheta = -1;
239 solver.solve(c2, 2*u*b*(a*ctheta-b), b2*(u*u-F*F*a2*(1-ctheta*ctheta)));
241 // TODO: this has to change
242 if (solver.nsols() == 0)
244 res = min(res, b*F + dA, a*F + dB);
248 for (int i = 0; i < solver.nsols(); ++i)
250 TPrec t = solver.sols()[i];
252 (t*a*ctheta < b*(t-u)) &&
253 (ctheta <= 0 || b*(t-u)*ctheta < a*t))
255 res = min(res, t + dA);
259 res = min(res, b*F + dA, a*F + dB);
264 // TODO: Optimized version still in the boxes
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(
271 u*u*norm2(side) - F^2*crossnorm2(base, side)
274 for (int i = 0; i < p.nsols(); ++i)
282 res = min(res, std::sqrt(b2)*F + dA);
289 //---------------------------------------------------------------------------
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)
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;
301 TPrec res = (*Base::m_pDist)[k];
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)
307 //std::size_t iA = getVertexNumber(Base::m_mesh, *iN);
308 std::size_t iA = *iN;
309 if ((*Base::m_pLabel)[iA] == Base::DONE)
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];
316 typename Neighborhood::const_iterator iN2 = cyclic_advance(iN, nh);
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])
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>());
333 // We compute these after the previous test to avoid having to swap them as well
335 TPrec a = std::sqrt(a2);
336 TPrec b = std::sqrt(b2);
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);
341 if (ctheta > 1) ctheta = 1;
342 else if (ctheta < -1) ctheta = -1;
344 solver.solve(c2, 2*u*b*(a*ctheta-b), b2*(u*u-F*F*a2*(1-ctheta*ctheta)));
346 // TODO: this has to change
347 if (solver.nsols() == 0)
349 TPrec tmp = min(b*F + dA, a*F + dB);
353 (*m_clusterLabel)[k] = (*m_clusterLabel)[iA];
358 for (int i = 0; i < solver.nsols(); ++i)
360 TPrec t = solver.sols()[i];
362 (t*a*ctheta < b*(t-u)) &&
363 (ctheta <= 0 || b*(t-u)*ctheta < a*t))
369 (*m_clusterLabel)[k] = (*m_clusterLabel)[iA];
374 TPrec tmp = min(b*F + dA, a*F + dB);
378 (*m_clusterLabel)[k] = (*m_clusterLabel)[iA];
386 TPrec tmp = std::sqrt(b2)*F + dA;
390 (*m_clusterLabel)[k] = (*m_clusterLabel)[iA];
398 //---------------------------------------------------------------------------
400 template < typename TVertices, typename TNeighbors, typename TPrec >
402 distance_to_neighbors
404 TVertices const & vertices
405 , TNeighbors const & neighbors
407 , std::vector<til::sparse_vector<TPrec> > & res
410 std::size_t n = vertices.size();
411 typedef std::vector<std::vector<std::size_t> > CNeighborhoods;
413 typedef til::ghost::GMapStop_AboveThreshold<TPrec> Stop_ghost;
414 Stop_ghost stop_ghost(distance);
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 >
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));
426 shared_ptr<til::sparse_vector<unsigned char> > labels;
427 for (std::size_t i = 0; i < n; ++i)
430 geomap.init(startPoints, dist);
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();)
439 if ((*labels)[j->first] != (unsigned char)(1))
441 res[i].getMap().erase(j++);
453 #endif /*TRIANGLE_MESH_GEODESIC_MAP_TPP_*/