2 * This program is free software: you can redistribute it and/or modify
3 * it under the terms of the GNU Lesser General Public License as
4 * published by the Free Software Foundation, either version 3 of the
5 * License, or (at your option) any later version.
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
12 * You should have received a copy of the GNU General Public License
13 * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 * @file TangencyComputer.ih
19 * @author Jacques-Olivier Lachaud (\c jacques-olivier.lachaud@univ-savoie.fr )
20 * Laboratory of Mathematics (CNRS, UMR 5127), University of Savoie, France
24 * Implementation of inline methods defined in TangencyComputer.h
26 * This file is part of the DGtal library.
30//////////////////////////////////////////////////////////////////////////////
32//////////////////////////////////////////////////////////////////////////////
34///////////////////////////////////////////////////////////////////////////////
35// class TangencyComputer
36///////////////////////////////////////////////////////////////////////////////
38//-----------------------------------------------------------------------------
39template <typename TKSpace>
40DGtal::TangencyComputer<TKSpace>::
41TangencyComputer( Clone<KSpace> K_ )
42 : myK( K_ ), myDConv( myK ), myLatticeCellCover( false )
47//-----------------------------------------------------------------------------
48template < typename TKSpace >
49template < typename PointIterator >
51DGtal::TangencyComputer<TKSpace>::
52init( PointIterator itB, PointIterator itE, bool use_lattice_cell_cover )
54 myX = std::vector< Point >( itB, itE );
55 myUseLatticeCellCover = use_lattice_cell_cover;
56 if ( use_lattice_cell_cover )
57 myLatticeCellCover = LatticeCellCover( myX.cbegin(), myX.cend() ).starOfPoints();
60 myDConv.makeCellCover( myX.cbegin(), myX.cend(), 1, KSpace::dimension - 1 );
61 for ( Size i = 0; i < myX.size(); ++i )
62 myPt2Index[ myX[ i ] ] = i;
65//-----------------------------------------------------------------------------
66template < typename TKSpace >
68DGtal::TangencyComputer<TKSpace>::
69arePointsCotangent( const Point& a, const Point& b ) const
71 return myUseLatticeCellCover
72 ? myDConv.isFullySubconvex( a, b, myLatticeCellCover )
73 : myDConv.isFullySubconvex( a, b, myCellCover );
76//-----------------------------------------------------------------------------
77template < typename TKSpace >
79DGtal::TangencyComputer<TKSpace>::
80arePointsCotangent( const Point& a, const Point& b, const Point& c ) const
82 std::vector< Point > Z { a, b, c };
83 const auto P = myDConv.makePolytope( Z );
84 return myUseLatticeCellCover
85 ? myDConv.isFullySubconvex( P, myLatticeCellCover )
86 : myDConv.isFullySubconvex( P, myCellCover );
89//-----------------------------------------------------------------------------
90template < typename TKSpace >
91std::vector< typename DGtal::TangencyComputer<TKSpace>::Index >
92DGtal::TangencyComputer<TKSpace>::
93getCotangentPoints( const Point& a ) const
95 // Breadth-first traversal from a
96 std::vector< Index > R; // result
97 std::set < Index > V; // visited or in queue
98 std::queue < Index > Q; // queue for breadth-first traversal
99 ASSERT( myPt2Index.find( a ) != myPt2Index.cend() );
100 const auto idx_a = myPt2Index.find( a )->second;
103 while ( ! Q.empty() )
105 const auto j = Q.front();
106 const auto p = myX[ j ];
108 for ( auto && v : myN ) {
109 const Point q = p + v;
110 const auto it = myPt2Index.find( q );
111 if ( it == myPt2Index.cend() ) continue; // not in X
112 const auto next = it->second;
113 if ( V.count( next ) ) continue; // already visited
114 if ( arePointsCotangent( a, q ) )
125//-----------------------------------------------------------------------------
126template < typename TKSpace >
127std::vector< typename DGtal::TangencyComputer<TKSpace>::Index >
128DGtal::TangencyComputer<TKSpace>::
129getCotangentPoints( const Point& a,
130 const std::vector< bool > & to_avoid ) const
132 // Breadth-first traversal from a
133 std::vector< Index > R; // result
134 std::set < Index > V; // visited or in queue
135 std::queue < Index > Q; // queue for breadth-first traversal
136 ASSERT( myPt2Index.find( a ) != myPt2Index.cend() );
137 const auto idx_a = myPt2Index.find( a )->second;
140 while ( ! Q.empty() )
142 const auto j = Q.front();
143 const auto p = myX[ j ];
144 const auto ap = p - a;
146 for ( auto && v : myN ) {
147 if ( ap.dot( v ) < 0.0 ) continue;
148 const Point q = p + v;
149 const auto it = myPt2Index.find( q );
150 if ( it == myPt2Index.cend() ) continue; // not in X
151 const auto next = it->second;
152 if ( to_avoid[ next ] ) continue; // to avoid
153 if ( V.count( next ) ) continue; // already visited
154 if ( arePointsCotangent( a, q ) )
165//-----------------------------------------------------------------------------
166template < typename TKSpace >
167std::vector< typename DGtal::TangencyComputer<TKSpace>::Index >
168DGtal::TangencyComputer<TKSpace>::
169getCotangentPoints( const Point& a, double max_discrete_distance ) const
171 // Breadth-first traversal from a
172 std::vector< Index > R; // result
173 std::set < Index > V; // visited or in queue
174 std::queue < Index > Q; // queue for breadth-first traversal
175 ASSERT( myPt2Index.find( a ) != myPt2Index.cend() );
176 const auto idx_a = myPt2Index.find( a )->second;
179 const double d2 = max_discrete_distance * max_discrete_distance;
180 while ( ! Q.empty() )
182 const auto j = Q.front();
183 const auto p = myX[ j ];
185 for ( auto && v : myN ) {
186 const Point q = p + v;
187 if ( (q - a).squaredNorm() > d2 ) continue; // too far away
188 const auto it = myPt2Index.find( q );
189 if ( it == myPt2Index.cend() ) continue; // not in X
190 const auto next = it->second;
191 if ( V.count( next ) ) continue; // already visited
192 if ( arePointsCotangent( a, q ) )
204//-----------------------------------------------------------------------------
205template < typename TKSpace >
206std::vector< typename DGtal::TangencyComputer<TKSpace>::Index >
207DGtal::TangencyComputer<TKSpace>::ShortestPaths::
208getCotangentPoints( Index idx_a ) const
210 bool use_secure = mySecure <= sqrt( KSpace::dimension );
211 // Breadth-first traversal from a
212 std::vector< Index > R; // result
213 std::set < Index > V; // visited or in queue
214 std::queue < Index > Q; // queue for breadth-first traversal
215 const auto a = point( idx_a );
218 while ( ! Q.empty() )
220 const auto j = Q.front();
221 const auto p = point( j );
222 const auto ap = p - a;
224 for ( size_t i = 0; i < myTgcyComputer->myN.size(); i++ ) {
225 const auto & v = myTgcyComputer->myN[ i ];
226 if ( ap.dot( v ) < 0.0 ) continue; // going backward
227 const Point q = p + v;
228 const auto it = myTgcyComputer->myPt2Index.find( q );
229 if ( it == myTgcyComputer->myPt2Index.cend() ) continue; // not in X
230 const auto next = it->second;
231 if ( myVisited[ next ] ) continue; // to avoid
232 if ( V.count( next ) ) continue; // already visited
233 const auto d_a = myDistance[ idx_a ] + ( q - a ).norm();
234 if ( d_a >= ( myDistance[ next ]
235 + ( use_secure ? mySecure : myTgcyComputer->myDN[ i ] ) ) )
236 continue; // only if distance is better.
237 if ( myTgcyComputer->arePointsCotangent( a, q ) )
248//-----------------------------------------------------------------------------
249template < typename TKSpace >
250typename DGtal::TangencyComputer<TKSpace>::ShortestPaths
251DGtal::TangencyComputer<TKSpace>::
252makeShortestPaths( double secure ) const
254 return ShortestPaths( *this, secure );
258//-----------------------------------------------------------------------------
259template < typename TKSpace >
260std::vector< typename DGtal::TangencyComputer<TKSpace>::Path >
261DGtal::TangencyComputer<TKSpace>::
262shortestPaths( const std::vector< Index >& sources,
263 const std::vector< Index >& targets,
264 double secure, bool verbose ) const
266 auto SP = makeShortestPaths( secure );
267 SP.init( targets.cbegin(), targets.cend() );
268 std::vector< Path > paths( sources.size() );
269 while ( ! SP.finished() )
271 auto n = SP.current();
274 trace.info() << "Point " << point( std::get<0>( n ) )
275 << " at distance " << std::get<2>( n ) << std::endl;
277 for ( size_t i = 0; i < sources.size(); i++ )
278 paths[ i ] = SP.pathToSource( sources[ i ] );
282//-----------------------------------------------------------------------------
283template < typename TKSpace >
284typename DGtal::TangencyComputer<TKSpace>::Path
285DGtal::TangencyComputer<TKSpace>::
286shortestPath( Index source, Index target,
287 double secure, bool verbose ) const
289 auto SP0 = makeShortestPaths( secure );
290 auto SP1 = makeShortestPaths( secure );
294 while ( ! SP0.finished() && ! SP1.finished() )
296 auto n0 = SP0.current();
297 auto n1 = SP1.current();
298 auto p0 = std::get<0>( n0 );
299 auto p1 = std::get<0>( n1 );
302 if ( SP0.isVisited( p1 ) )
304 auto c0 = SP0.pathToSource( p1 );
305 auto c1 = SP1.pathToSource( p1 );
306 std::copy(c0.rbegin(), c0.rend(), std::back_inserter(Q));
308 std::copy(c1.begin(), c1.end(), std::back_inserter(Q));
313 double last_distance = std::get<2>( n0 ) + std::get<2>( n1 );
314 trace.info() << p0 << " " << p1 << " last_d=" << last_distance << std::endl;
320//-----------------------------------------------------------------------------
321template <typename TKSpace>
323DGtal::TangencyComputer<TKSpace>::
328 const Point zero = Point::zero;
329 Domain neighborhood( Point::diagonal( -1 ), Point::diagonal( 1 ) );
330 for ( auto&& v : neighborhood )
335 myDN.push_back( v.norm() );
340///////////////////////////////////////////////////////////////////////////////
341// class TangencyComputer::Shortestpaths
342///////////////////////////////////////////////////////////////////////////////
344//-----------------------------------------------------------------------------
345template <typename TKSpace>
347DGtal::TangencyComputer<TKSpace>::ShortestPaths::
350 ASSERT( ! finished() );
351 auto elem = myQ.top();
353 propagate( std::get<0>( elem ) );
356 while ( ! finished() )
359 current = std::get<0>( elem );
360 d = std::get<2>( elem );
361 ASSERT( ( ! ( myVisited[ current ] && ( d < myDistance[ current ] ) ) )
362 && "Already visited node and smaller distance" );
363 if ( ! myVisited[ current ] ) break;
368 myAncestor[ current ] = std::get<1>( elem );
369 myDistance[ current ] = d;
370 myVisited [ current ] = true;
374//-----------------------------------------------------------------------------
375template <typename TKSpace>
377DGtal::TangencyComputer<TKSpace>::ShortestPaths::
378propagate( Index current )
380 auto eucl_d = [] ( const Point& p, const Point& q )
381 { return ( p - q ).norm(); };
383 if ( ! myVisited[ current ] )
384 trace.warning() << "Propagate from unvisited node " << current << std::endl;
385 const Point q = myTgcyComputer->point( current );
386 std::vector< Index > N = getCotangentPoints( current );
387 for ( auto next : N )
389 if ( ! myVisited[ next ] )
391 const Point p = myTgcyComputer->point( next );
392 double next_d = myDistance[ current ] + eucl_d( q, p );
393 if ( next_d < myDistance[ next ] )
395 myDistance[ next ] = next_d;
396 myQ.push( std::make_tuple( next, current, next_d ) );
403///////////////////////////////////////////////////////////////////////////////
404// Implementation of inline functions //
406//-----------------------------------------------------------------------------
407template <typename TKSpace>
410DGtal::operator<< ( std::ostream & out,
411 const TangencyComputer<TKSpace> & object )
413 object.selfDisplay( out );
418///////////////////////////////////////////////////////////////////////////////