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 //-----------------------------------------------------------------------------
39 template <typename TKSpace>
40 DGtal::TangencyComputer<TKSpace>::
41 TangencyComputer( Clone<KSpace> K )
42 : myK( K ), myDConv( myK )
47 //-----------------------------------------------------------------------------
48 template < typename TKSpace >
49 template < typename PointIterator >
51 DGtal::TangencyComputer<TKSpace>::
52 init( PointIterator itB, PointIterator itE )
54 myX = std::vector< Point >( itB, itE );
56 myDConv.makeCellCover( myX.cbegin(), myX.cend(), 1, KSpace::dimension - 1 );
57 for ( Size i = 0; i < myX.size(); ++i )
58 myPt2Index[ myX[ i ] ] = i;
61 //-----------------------------------------------------------------------------
62 template < typename TKSpace >
64 DGtal::TangencyComputer<TKSpace>::
65 arePointsCotangent( const Point& a, const Point& b ) const
67 return myDConv.isFullySubconvex( a, b, myCellCover );
70 //-----------------------------------------------------------------------------
71 template < typename TKSpace >
72 std::vector< typename DGtal::TangencyComputer<TKSpace>::Index >
73 DGtal::TangencyComputer<TKSpace>::
74 getCotangentPoints( const Point& a ) const
76 // Breadth-first traversal from a
77 std::vector< Index > R; // result
78 std::set < Index > V; // visited or in queue
79 std::queue < Index > Q; // queue for breadth-first traversal
80 ASSERT( myPt2Index.find( a ) != myPt2Index.cend() );
81 const auto idx_a = myPt2Index.find( a )->second;
86 const auto j = Q.front();
87 const auto p = myX[ j ];
89 for ( auto && v : myN ) {
90 const Point q = p + v;
91 const auto it = myPt2Index.find( q );
92 if ( it == myPt2Index.cend() ) continue; // not in X
93 const auto next = it->second;
94 if ( V.count( next ) ) continue; // already visited
95 if ( arePointsCotangent( a, q ) )
106 //-----------------------------------------------------------------------------
107 template < typename TKSpace >
108 std::vector< typename DGtal::TangencyComputer<TKSpace>::Index >
109 DGtal::TangencyComputer<TKSpace>::
110 getCotangentPoints( const Point& a,
111 const std::vector< bool > & to_avoid ) const
113 // Breadth-first traversal from a
114 std::vector< Index > R; // result
115 std::set < Index > V; // visited or in queue
116 std::queue < Index > Q; // queue for breadth-first traversal
117 ASSERT( myPt2Index.find( a ) != myPt2Index.cend() );
118 const auto idx_a = myPt2Index.find( a )->second;
121 while ( ! Q.empty() )
123 const auto j = Q.front();
124 const auto p = myX[ j ];
125 const auto ap = p - a;
127 for ( auto && v : myN ) {
128 if ( ap.dot( v ) < 0.0 ) continue;
129 const Point q = p + v;
130 const auto it = myPt2Index.find( q );
131 if ( it == myPt2Index.cend() ) continue; // not in X
132 const auto next = it->second;
133 if ( to_avoid[ next ] ) continue; // to avoid
134 if ( V.count( next ) ) continue; // already visited
135 if ( arePointsCotangent( a, q ) )
146 //-----------------------------------------------------------------------------
147 template < typename TKSpace >
148 std::vector< typename DGtal::TangencyComputer<TKSpace>::Index >
149 DGtal::TangencyComputer<TKSpace>::ShortestPaths::
150 getCotangentPoints( Index idx_a ) const
152 bool use_secure = mySecure <= sqrt( KSpace::dimension );
153 // Breadth-first traversal from a
154 std::vector< Index > R; // result
155 std::set < Index > V; // visited or in queue
156 std::queue < Index > Q; // queue for breadth-first traversal
157 const auto a = point( idx_a );
160 while ( ! Q.empty() )
162 const auto j = Q.front();
163 const auto p = point( j );
164 const auto ap = p - a;
166 for ( int i = 0; i < myTgcyComputer->myN.size(); i++ ) {
167 const auto & v = myTgcyComputer->myN[ i ];
168 if ( ap.dot( v ) < 0.0 ) continue; // going backward
169 const Point q = p + v;
170 const auto it = myTgcyComputer->myPt2Index.find( q );
171 if ( it == myTgcyComputer->myPt2Index.cend() ) continue; // not in X
172 const auto next = it->second;
173 if ( myVisited[ next ] ) continue; // to avoid
174 if ( V.count( next ) ) continue; // already visited
175 const auto d_a = myDistance[ idx_a ] + ( q - a ).norm();
176 if ( d_a >= ( myDistance[ next ]
177 + ( use_secure ? mySecure : myTgcyComputer->myDN[ i ] ) ) )
178 continue; // only if distance is better.
179 if ( myTgcyComputer->arePointsCotangent( a, q ) )
190 //-----------------------------------------------------------------------------
191 template < typename TKSpace >
192 typename DGtal::TangencyComputer<TKSpace>::ShortestPaths
193 DGtal::TangencyComputer<TKSpace>::
194 makeShortestPaths( double secure ) const
196 return ShortestPaths( *this, secure );
200 //-----------------------------------------------------------------------------
201 template < typename TKSpace >
202 std::vector< typename DGtal::TangencyComputer<TKSpace>::Path >
203 DGtal::TangencyComputer<TKSpace>::
204 shortestPaths( const std::vector< Index >& sources,
205 const std::vector< Index >& targets,
206 double secure, bool verbose ) const
208 auto SP = makeShortestPaths( secure );
209 SP.init( targets.cbegin(), targets.cend() );
210 std::vector< Path > paths( sources.size() );
211 while ( ! SP.finished() )
213 auto n = SP.current();
216 trace.info() << "Point " << point( std::get<0>( n ) )
217 << " at distance " << std::get<2>( n ) << std::endl;
219 for ( auto i = 0; i < sources.size(); i++ )
220 paths[ i ] = SP.pathToSource( sources[ i ] );
224 //-----------------------------------------------------------------------------
225 template < typename TKSpace >
226 typename DGtal::TangencyComputer<TKSpace>::Path
227 DGtal::TangencyComputer<TKSpace>::
228 shortestPath( Index source, Index target,
229 double secure, bool verbose ) const
231 auto SP0 = makeShortestPaths( secure );
232 auto SP1 = makeShortestPaths( secure );
236 while ( ! SP0.finished() && ! SP1.finished() )
238 auto n0 = SP0.current();
239 auto n1 = SP1.current();
240 auto p0 = std::get<0>( n0 );
241 auto p1 = std::get<0>( n1 );
244 if ( SP0.isVisited( p1 ) )
246 auto c0 = SP0.pathToSource( p1 );
247 auto c1 = SP1.pathToSource( p1 );
248 std::copy(c0.rbegin(), c0.rend(), std::back_inserter(Q));
250 std::copy(c1.begin(), c1.end(), std::back_inserter(Q));
255 double last_distance = std::get<2>( n0 ) + std::get<2>( n1 );
256 trace.info() << p0 << " " << p1 << " last_d=" << last_distance << std::endl;
262 //-----------------------------------------------------------------------------
263 template <typename TKSpace>
265 DGtal::TangencyComputer<TKSpace>::
270 const Point zero = Point::zero;
271 Domain neighborhood( Point::diagonal( -1 ), Point::diagonal( 1 ) );
272 for ( auto&& v : neighborhood )
277 myDN.push_back( v.norm() );
282 ///////////////////////////////////////////////////////////////////////////////
283 // class TangencyComputer::Shortestpaths
284 ///////////////////////////////////////////////////////////////////////////////
286 //-----------------------------------------------------------------------------
287 template <typename TKSpace>
289 DGtal::TangencyComputer<TKSpace>::ShortestPaths::
292 ASSERT( ! finished() );
293 auto elem = myQ.top();
295 propagate( std::get<0>( elem ) );
299 while ( ! finished() )
303 current = std::get<0>( elem );
304 d = std::get<2>( elem );
305 ASSERT( ( ! ( myVisited[ current ] && ( d < myDistance[ current ] ) ) )
306 && "Already visited node and smaller distance" );
307 if ( ! myVisited[ current ] ) break;
312 myAncestor[ current ] = std::get<1>( elem );
313 myDistance[ current ] = d;
314 myVisited [ current ] = true;
318 //-----------------------------------------------------------------------------
319 template <typename TKSpace>
321 DGtal::TangencyComputer<TKSpace>::ShortestPaths::
322 propagate( Index current )
324 auto eucl_d = [] ( const Point& p, const Point& q )
325 { return ( p - q ).norm(); };
327 if ( ! myVisited[ current ] )
328 trace.warning() << "Propagate from unvisited node " << current << std::endl;
329 const Point q = myTgcyComputer->point( current );
330 std::vector< Index > N = getCotangentPoints( current );
331 for ( auto next : N )
333 if ( ! myVisited[ next ] )
335 const Point p = myTgcyComputer->point( next );
336 double next_d = myDistance[ current ] + eucl_d( q, p );
337 if ( next_d < myDistance[ next ] )
339 myDistance[ next ] = next_d;
340 myQ.push( std::make_tuple( next, current, next_d ) );
347 ///////////////////////////////////////////////////////////////////////////////
348 // Implementation of inline functions //
350 //-----------------------------------------------------------------------------
351 template <typename TKSpace>
354 DGtal::operator<< ( std::ostream & out,
355 const TangencyComputer<TKSpace> & object )
357 object.selfDisplay( out );
362 ///////////////////////////////////////////////////////////////////////////////