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>::ShortestPaths::
169getCotangentPoints( Index idx_a ) const
171 bool use_secure = mySecure <= sqrt( KSpace::dimension );
172 // Breadth-first traversal from a
173 std::vector< Index > R; // result
174 std::set < Index > V; // visited or in queue
175 std::queue < Index > Q; // queue for breadth-first traversal
176 const auto a = point( idx_a );
179 while ( ! Q.empty() )
181 const auto j = Q.front();
182 const auto p = point( j );
183 const auto ap = p - a;
185 for ( size_t i = 0; i < myTgcyComputer->myN.size(); i++ ) {
186 const auto & v = myTgcyComputer->myN[ i ];
187 if ( ap.dot( v ) < 0.0 ) continue; // going backward
188 const Point q = p + v;
189 const auto it = myTgcyComputer->myPt2Index.find( q );
190 if ( it == myTgcyComputer->myPt2Index.cend() ) continue; // not in X
191 const auto next = it->second;
192 if ( myVisited[ next ] ) continue; // to avoid
193 if ( V.count( next ) ) continue; // already visited
194 const auto d_a = myDistance[ idx_a ] + ( q - a ).norm();
195 if ( d_a >= ( myDistance[ next ]
196 + ( use_secure ? mySecure : myTgcyComputer->myDN[ i ] ) ) )
197 continue; // only if distance is better.
198 if ( myTgcyComputer->arePointsCotangent( a, q ) )
209//-----------------------------------------------------------------------------
210template < typename TKSpace >
211typename DGtal::TangencyComputer<TKSpace>::ShortestPaths
212DGtal::TangencyComputer<TKSpace>::
213makeShortestPaths( double secure ) const
215 return ShortestPaths( *this, secure );
219//-----------------------------------------------------------------------------
220template < typename TKSpace >
221std::vector< typename DGtal::TangencyComputer<TKSpace>::Path >
222DGtal::TangencyComputer<TKSpace>::
223shortestPaths( const std::vector< Index >& sources,
224 const std::vector< Index >& targets,
225 double secure, bool verbose ) const
227 auto SP = makeShortestPaths( secure );
228 SP.init( targets.cbegin(), targets.cend() );
229 std::vector< Path > paths( sources.size() );
230 while ( ! SP.finished() )
232 auto n = SP.current();
235 trace.info() << "Point " << point( std::get<0>( n ) )
236 << " at distance " << std::get<2>( n ) << std::endl;
238 for ( auto i = 0; i < sources.size(); i++ )
239 paths[ i ] = SP.pathToSource( sources[ i ] );
243//-----------------------------------------------------------------------------
244template < typename TKSpace >
245typename DGtal::TangencyComputer<TKSpace>::Path
246DGtal::TangencyComputer<TKSpace>::
247shortestPath( Index source, Index target,
248 double secure, bool verbose ) const
250 auto SP0 = makeShortestPaths( secure );
251 auto SP1 = makeShortestPaths( secure );
255 while ( ! SP0.finished() && ! SP1.finished() )
257 auto n0 = SP0.current();
258 auto n1 = SP1.current();
259 auto p0 = std::get<0>( n0 );
260 auto p1 = std::get<0>( n1 );
263 if ( SP0.isVisited( p1 ) )
265 auto c0 = SP0.pathToSource( p1 );
266 auto c1 = SP1.pathToSource( p1 );
267 std::copy(c0.rbegin(), c0.rend(), std::back_inserter(Q));
269 std::copy(c1.begin(), c1.end(), std::back_inserter(Q));
274 double last_distance = std::get<2>( n0 ) + std::get<2>( n1 );
275 trace.info() << p0 << " " << p1 << " last_d=" << last_distance << std::endl;
281//-----------------------------------------------------------------------------
282template <typename TKSpace>
284DGtal::TangencyComputer<TKSpace>::
289 const Point zero = Point::zero;
290 Domain neighborhood( Point::diagonal( -1 ), Point::diagonal( 1 ) );
291 for ( auto&& v : neighborhood )
296 myDN.push_back( v.norm() );
301///////////////////////////////////////////////////////////////////////////////
302// class TangencyComputer::Shortestpaths
303///////////////////////////////////////////////////////////////////////////////
305//-----------------------------------------------------------------------------
306template <typename TKSpace>
308DGtal::TangencyComputer<TKSpace>::ShortestPaths::
311 ASSERT( ! finished() );
312 auto elem = myQ.top();
314 propagate( std::get<0>( elem ) );
317 while ( ! finished() )
320 current = std::get<0>( elem );
321 d = std::get<2>( elem );
322 ASSERT( ( ! ( myVisited[ current ] && ( d < myDistance[ current ] ) ) )
323 && "Already visited node and smaller distance" );
324 if ( ! myVisited[ current ] ) break;
329 myAncestor[ current ] = std::get<1>( elem );
330 myDistance[ current ] = d;
331 myVisited [ current ] = true;
335//-----------------------------------------------------------------------------
336template <typename TKSpace>
338DGtal::TangencyComputer<TKSpace>::ShortestPaths::
339propagate( Index current )
341 auto eucl_d = [] ( const Point& p, const Point& q )
342 { return ( p - q ).norm(); };
344 if ( ! myVisited[ current ] )
345 trace.warning() << "Propagate from unvisited node " << current << std::endl;
346 const Point q = myTgcyComputer->point( current );
347 std::vector< Index > N = getCotangentPoints( current );
348 for ( auto next : N )
350 if ( ! myVisited[ next ] )
352 const Point p = myTgcyComputer->point( next );
353 double next_d = myDistance[ current ] + eucl_d( q, p );
354 if ( next_d < myDistance[ next ] )
356 myDistance[ next ] = next_d;
357 myQ.push( std::make_tuple( next, current, next_d ) );
364///////////////////////////////////////////////////////////////////////////////
365// Implementation of inline functions //
367//-----------------------------------------------------------------------------
368template <typename TKSpace>
371DGtal::operator<< ( std::ostream & out,
372 const TangencyComputer<TKSpace> & object )
374 object.selfDisplay( out );
379///////////////////////////////////////////////////////////////////////////////