DGtal 1.3.0
Loading...
Searching...
No Matches
TangencyComputer.ih
1/**
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.
6 *
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.
11 *
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/>.
14 *
15 **/
16
17/**
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
21 *
22 * @date 2021/07/16
23 *
24 * Implementation of inline methods defined in TangencyComputer.h
25 *
26 * This file is part of the DGtal library.
27 */
28
29
30//////////////////////////////////////////////////////////////////////////////
31#include <cstdlib>
32//////////////////////////////////////////////////////////////////////////////
33
34///////////////////////////////////////////////////////////////////////////////
35// class TangencyComputer
36///////////////////////////////////////////////////////////////////////////////
37
38//-----------------------------------------------------------------------------
39template <typename TKSpace>
40DGtal::TangencyComputer<TKSpace>::
41TangencyComputer( Clone<KSpace> K )
42 : myK( K ), myDConv( myK ), myLatticeCellCover( false )
43{
44 setUp();
45}
46
47//-----------------------------------------------------------------------------
48template < typename TKSpace >
49template < typename PointIterator >
50void
51DGtal::TangencyComputer<TKSpace>::
52init( PointIterator itB, PointIterator itE, bool use_lattice_cell_cover )
53{
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();
58 else
59 myCellCover =
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;
63}
64
65//-----------------------------------------------------------------------------
66template < typename TKSpace >
67bool
68DGtal::TangencyComputer<TKSpace>::
69arePointsCotangent( const Point& a, const Point& b ) const
70{
71 return myUseLatticeCellCover
72 ? myDConv.isFullySubconvex( a, b, myLatticeCellCover )
73 : myDConv.isFullySubconvex( a, b, myCellCover );
74}
75
76//-----------------------------------------------------------------------------
77template < typename TKSpace >
78bool
79DGtal::TangencyComputer<TKSpace>::
80arePointsCotangent( const Point& a, const Point& b, const Point& c ) const
81{
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 );
87}
88
89//-----------------------------------------------------------------------------
90template < typename TKSpace >
91std::vector< typename DGtal::TangencyComputer<TKSpace>::Index >
92DGtal::TangencyComputer<TKSpace>::
93getCotangentPoints( const Point& a ) const
94{
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;
101 Q.push ( idx_a );
102 V.insert( idx_a );
103 while ( ! Q.empty() )
104 {
105 const auto j = Q.front();
106 const auto p = myX[ j ];
107 Q.pop();
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 ) )
115 {
116 R.push_back( next );
117 V.insert( next );
118 Q.push ( next );
119 }
120 }
121 }
122 return R;
123}
124
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
131{
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;
138 Q.push ( idx_a );
139 V.insert( idx_a );
140 while ( ! Q.empty() )
141 {
142 const auto j = Q.front();
143 const auto p = myX[ j ];
144 const auto ap = p - a;
145 Q.pop();
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 ) )
155 {
156 R.push_back( next );
157 V.insert( next );
158 Q.push ( next );
159 }
160 }
161 }
162 return R;
163}
164
165//-----------------------------------------------------------------------------
166template < typename TKSpace >
167std::vector< typename DGtal::TangencyComputer<TKSpace>::Index >
168DGtal::TangencyComputer<TKSpace>::ShortestPaths::
169getCotangentPoints( Index idx_a ) const
170{
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 );
177 Q.push ( idx_a );
178 V.insert( idx_a );
179 while ( ! Q.empty() )
180 {
181 const auto j = Q.front();
182 const auto p = point( j );
183 const auto ap = p - a;
184 Q.pop();
185 for ( int 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 ) )
199 {
200 R.push_back( next );
201 V.insert( next );
202 Q.push ( next );
203 }
204 }
205 }
206 return R;
207}
208
209//-----------------------------------------------------------------------------
210template < typename TKSpace >
211typename DGtal::TangencyComputer<TKSpace>::ShortestPaths
212DGtal::TangencyComputer<TKSpace>::
213makeShortestPaths( double secure ) const
214{
215 return ShortestPaths( *this, secure );
216}
217
218
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
226{
227 auto SP = makeShortestPaths( secure );
228 SP.init( targets.cbegin(), targets.cend() );
229 std::vector< Path > paths( sources.size() );
230 while ( ! SP.finished() )
231 {
232 auto n = SP.current();
233 SP.expand();
234 if ( verbose )
235 trace.info() << "Point " << point( std::get<0>( n ) )
236 << " at distance " << std::get<2>( n ) << std::endl;
237 }
238 for ( auto i = 0; i < sources.size(); i++ )
239 paths[ i ] = SP.pathToSource( sources[ i ] );
240 return paths;
241}
242
243//-----------------------------------------------------------------------------
244template < typename TKSpace >
245typename DGtal::TangencyComputer<TKSpace>::Path
246DGtal::TangencyComputer<TKSpace>::
247shortestPath( Index source, Index target,
248 double secure, bool verbose ) const
249{
250 auto SP0 = makeShortestPaths( secure );
251 auto SP1 = makeShortestPaths( secure );
252 SP0.init( source );
253 SP1.init( target );
254 Path Q;
255 while ( ! SP0.finished() && ! SP1.finished() )
256 {
257 auto n0 = SP0.current();
258 auto n1 = SP1.current();
259 auto p0 = std::get<0>( n0 );
260 auto p1 = std::get<0>( n1 );
261 SP0.expand();
262 SP1.expand();
263 if ( SP0.isVisited( p1 ) )
264 {
265 auto c0 = SP0.pathToSource( p1 );
266 auto c1 = SP1.pathToSource( p1 );
267 std::copy(c0.rbegin(), c0.rend(), std::back_inserter(Q));
268 Q.pop_back();
269 std::copy(c1.begin(), c1.end(), std::back_inserter(Q));
270 break;
271 }
272 if ( verbose )
273 {
274 double last_distance = std::get<2>( n0 ) + std::get<2>( n1 );
275 trace.info() << p0 << " " << p1 << " last_d=" << last_distance << std::endl;
276 }
277 }
278 return Q;
279}
280
281//-----------------------------------------------------------------------------
282template <typename TKSpace>
283void
284DGtal::TangencyComputer<TKSpace>::
285setUp()
286{
287 myN.clear();
288 myDN.clear();
289 const Point zero = Point::zero;
290 Domain neighborhood( Point::diagonal( -1 ), Point::diagonal( 1 ) );
291 for ( auto&& v : neighborhood )
292 {
293 if ( v != zero )
294 {
295 myN .push_back( v );
296 myDN.push_back( v.norm() );
297 }
298 }
299}
300
301///////////////////////////////////////////////////////////////////////////////
302// class TangencyComputer::Shortestpaths
303///////////////////////////////////////////////////////////////////////////////
304
305//-----------------------------------------------------------------------------
306template <typename TKSpace>
307void
308DGtal::TangencyComputer<TKSpace>::ShortestPaths::
309expand()
310{
311 ASSERT( ! finished() );
312 auto elem = myQ.top();
313 myQ.pop();
314 propagate( std::get<0>( elem ) );
315 Index current;
316 double d;
317 int nb = 0;
318 while ( ! finished() )
319 {
320 elem = myQ.top();
321 nb += 1;
322 current = std::get<0>( elem );
323 d = std::get<2>( elem );
324 ASSERT( ( ! ( myVisited[ current ] && ( d < myDistance[ current ] ) ) )
325 && "Already visited node and smaller distance" );
326 if ( ! myVisited[ current ] ) break;
327 myQ.pop();
328 }
329 if ( ! finished() )
330 {
331 myAncestor[ current ] = std::get<1>( elem );
332 myDistance[ current ] = d;
333 myVisited [ current ] = true;
334 }
335}
336
337//-----------------------------------------------------------------------------
338template <typename TKSpace>
339void
340DGtal::TangencyComputer<TKSpace>::ShortestPaths::
341propagate( Index current )
342{
343 auto eucl_d = [] ( const Point& p, const Point& q )
344 { return ( p - q ).norm(); };
345
346 if ( ! myVisited[ current ] )
347 trace.warning() << "Propagate from unvisited node " << current << std::endl;
348 const Point q = myTgcyComputer->point( current );
349 std::vector< Index > N = getCotangentPoints( current );
350 for ( auto next : N )
351 {
352 if ( ! myVisited[ next ] )
353 {
354 const Point p = myTgcyComputer->point( next );
355 double next_d = myDistance[ current ] + eucl_d( q, p );
356 if ( next_d < myDistance[ next ] )
357 {
358 myDistance[ next ] = next_d;
359 myQ.push( std::make_tuple( next, current, next_d ) );
360 }
361 }
362 }
363}
364
365
366///////////////////////////////////////////////////////////////////////////////
367// Implementation of inline functions //
368
369//-----------------------------------------------------------------------------
370template <typename TKSpace>
371inline
372std::ostream&
373DGtal::operator<< ( std::ostream & out,
374 const TangencyComputer<TKSpace> & object )
375{
376 object.selfDisplay( out );
377 return out;
378}
379
380// //
381///////////////////////////////////////////////////////////////////////////////