DGtal  0.9.2
ChordGenericStandardPlaneComputer.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 ChordGenericStandardPlaneComputer.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 2012/09/20
23  *
24  * Implementation of inline methods defined in ChordGenericStandardPlaneComputer.h
25  *
26  * This file is part of the DGtal library.
27  */
28 
29 
30 //////////////////////////////////////////////////////////////////////////////
31 #include <cstdlib>
32 //////////////////////////////////////////////////////////////////////////////
33 
34 ///////////////////////////////////////////////////////////////////////////////
35 // DEFINITION of static members
36 ///////////////////////////////////////////////////////////////////////////////
37 template <typename TSpace, typename TInputPoint, typename TInternalScalar>
38 typename DGtal::ChordGenericStandardPlaneComputer<TSpace, TInputPoint, TInternalScalar>::Transform
39 DGtal::ChordGenericStandardPlaneComputer<TSpace, TInputPoint, TInternalScalar>::myTransforms[4] = {
40  Transform( true, true ), Transform( true, false ), Transform( false, true ), Transform( false, false ) };
41 
42 ///////////////////////////////////////////////////////////////////////////////
43 // IMPLEMENTATION of inline methods.
44 ///////////////////////////////////////////////////////////////////////////////
45 
46 ///////////////////////////////////////////////////////////////////////////////
47 // ----------------------- Standard services ------------------------------
48 
49 //-----------------------------------------------------------------------------
50 template <typename TSpace, typename TInputPoint, typename TInternalScalar>
51 inline
52 DGtal::ChordGenericStandardPlaneComputer<TSpace, TInputPoint, TInternalScalar>::
53 ~ChordGenericStandardPlaneComputer()
54 { // Nothing to do.
55 }
56 //-----------------------------------------------------------------------------
57 template <typename TSpace, typename TInputPoint, typename TInternalScalar>
58 inline
59 DGtal::ChordGenericStandardPlaneComputer<TSpace, TInputPoint, TInternalScalar>::
60 ChordGenericStandardPlaneComputer()
61 { // Object is invalid
62  _orthantsToErase.reserve( 4 );
63 }
64 //-----------------------------------------------------------------------------
65 template <typename TSpace, typename TInputPoint, typename TInternalScalar>
66 inline
67 DGtal::ChordGenericStandardPlaneComputer<TSpace, TInputPoint, TInternalScalar>::
68 ChordGenericStandardPlaneComputer( const ChordGenericStandardPlaneComputer & other )
69  : myOrthants( other.myOrthants )
70 {
71  for ( OrthantConstIterator it = myOrthants.begin(), itE = myOrthants.end();
72  it != itE; ++it )
73  myComputers[ *it ] = other.myComputers[ *it ];
74  _orthantsToErase.reserve( 4 );
75 }
76 //-----------------------------------------------------------------------------
77 template <typename TSpace, typename TInputPoint, typename TInternalScalar>
78 inline
79 DGtal::ChordGenericStandardPlaneComputer<TSpace, TInputPoint, TInternalScalar> &
80 DGtal::ChordGenericStandardPlaneComputer<TSpace, TInputPoint, TInternalScalar>::
81 operator=( const ChordGenericStandardPlaneComputer & other )
82 {
83  if ( this != &other )
84  {
85  myOrthants = other.myOrthants;
86  for ( OrthantConstIterator it = myOrthants.begin(), itE = myOrthants.end();
87  it != itE; ++it )
88  myComputers[ *it ] = other.myComputers[ *it ];
89  }
90  return *this;
91 }
92 //-----------------------------------------------------------------------------
93 template <typename TSpace, typename TInputPoint, typename TInternalScalar>
94 inline
95 DGtal::Dimension
96 DGtal::ChordGenericStandardPlaneComputer<TSpace, TInputPoint, TInternalScalar>::
97 active() const
98 {
99  ASSERT( myOrthants.size() > 0 );
100  return myOrthants[ 0 ];
101 }
102 //-----------------------------------------------------------------------------
103 template <typename TSpace, typename TInputPoint, typename TInternalScalar>
104 inline
105 void
106 DGtal::ChordGenericStandardPlaneComputer<TSpace, TInputPoint, TInternalScalar>::
107 clear()
108 {
109  myOrthants.clear();
110  for ( unsigned int i = 0; i < 4; ++i )
111  {
112  myOrthants.push_back( i );
113  myComputers[ i ].clear();
114  }
115 }
116 //-----------------------------------------------------------------------------
117 template <typename TSpace, typename TInputPoint, typename TInternalScalar>
118 inline
119 void
120 DGtal::ChordGenericStandardPlaneComputer<TSpace, TInputPoint, TInternalScalar>::
121 init( InternalScalar widthNumerator,
122  InternalScalar widthDenominator )
123 {
124  clear();
125  for ( unsigned int i = 0; i < 4; ++i )
126  {
127  // all Chord computers computes naive planes along z, but the 4
128  // transforms dilate the x,y coordinates in four different ways
129  // to get all the possible orientations of standard planes.
130  myComputers[ i ].init( 2, widthNumerator, widthDenominator );
131  }
132 }
133 //-----------------------------------------------------------------------------
134 template <typename TSpace, typename TInputPoint, typename TInternalScalar>
135 inline
136 typename DGtal::ChordGenericStandardPlaneComputer<TSpace, TInputPoint, TInternalScalar>::Size
137 DGtal::ChordGenericStandardPlaneComputer<TSpace, TInputPoint, TInternalScalar>::
138 size() const
139 {
140  return myComputers[ active() ].size();
141 }
142 //-----------------------------------------------------------------------------
143 template <typename TSpace, typename TInputPoint, typename TInternalScalar>
144 inline
145 bool
146 DGtal::ChordGenericStandardPlaneComputer<TSpace, TInputPoint, TInternalScalar>::
147 empty() const
148 {
149  return myComputers[ active() ].empty();
150 }
151 //-----------------------------------------------------------------------------
152 template <typename TSpace, typename TInputPoint, typename TInternalScalar>
153 inline
154 typename DGtal::ChordGenericStandardPlaneComputer<TSpace, TInputPoint, TInternalScalar>::ConstIterator
155 DGtal::ChordGenericStandardPlaneComputer<TSpace, TInputPoint, TInternalScalar>::
156 begin() const
157 {
158  return ConstIterator( myComputers[ active() ].begin(), invT( active() ) );
159 }
160 //-----------------------------------------------------------------------------
161 template <typename TSpace, typename TInputPoint, typename TInternalScalar>
162 inline
163 typename DGtal::ChordGenericStandardPlaneComputer<TSpace, TInputPoint, TInternalScalar>::ConstIterator
164 DGtal::ChordGenericStandardPlaneComputer<TSpace, TInputPoint, TInternalScalar>::
165 end() const
166 {
167  return ConstIterator( myComputers[ active() ].end(), invT( active() ) );
168 }
169 
170 //-----------------------------------------------------------------------------
171 template <typename TSpace, typename TInputPoint, typename TInternalScalar>
172 inline
173 typename DGtal::ChordGenericStandardPlaneComputer<TSpace, TInputPoint, TInternalScalar>::Size
174 DGtal::ChordGenericStandardPlaneComputer<TSpace, TInputPoint, TInternalScalar>::
175 max_size() const
176 {
177  return myComputers[ active() ].max_size();
178 }
179 //-----------------------------------------------------------------------------
180 template <typename TSpace, typename TInputPoint, typename TInternalScalar>
181 inline
182 typename DGtal::ChordGenericStandardPlaneComputer<TSpace, TInputPoint, TInternalScalar>::Size
183 DGtal::ChordGenericStandardPlaneComputer<TSpace, TInputPoint, TInternalScalar>::
184 maxSize() const
185 {
186  return max_size();
187 }
188 //-----------------------------------------------------------------------------
189 template <typename TSpace, typename TInputPoint, typename TInternalScalar>
190 inline
191 bool
192 DGtal::ChordGenericStandardPlaneComputer<TSpace, TInputPoint, TInternalScalar>::
193 operator()( const Point & p ) const
194 {
195  return myComputers[ active() ].operator()( t( active() )( p ) );
196 }
197 
198 //-----------------------------------------------------------------------------
199 template <typename TSpace, typename TInputPoint, typename TInternalScalar>
200 inline
201 bool
202 DGtal::ChordGenericStandardPlaneComputer<TSpace, TInputPoint, TInternalScalar>::
203 extendAsIs( const InputPoint & p )
204 {
205  ASSERT( isValid() );
206  unsigned int nbok = 0;
207  for ( OrthantConstIterator it = myOrthants.begin(), itE = myOrthants.end();
208  it != itE; ++it )
209  {
210  nbok += myComputers[ *it ].operator()( t( *it )( p ) ) ? 1 : 0;
211  }
212  if ( nbok != 0 ) // at least one is ok.
213  {
214  for ( OrthantIterator it = myOrthants.begin(); it != myOrthants.end(); )
215  // cannot put end() in variable, since end() moves when
216  // modifiying a vector.
217  {
218  bool ok = myComputers[ *it ].extendAsIs( t( *it )( p ) );
219  if ( ! ok )
220  it = myOrthants.erase( it );
221  else
222  ++it;
223  }
224  ASSERT( ! myOrthants.empty() );
225  return true;
226  }
227  return false;
228 }
229 
230 //-----------------------------------------------------------------------------
231 template <typename TSpace, typename TInputPoint, typename TInternalScalar>
232 bool
233 DGtal::ChordGenericStandardPlaneComputer<TSpace, TInputPoint, TInternalScalar>::
234 extend( const InputPoint & p )
235 {
236  ASSERT( isValid() );
237  unsigned int nbok = 0;
238  _orthantsToErase.clear();
239  for ( OrthantConstIterator orthIt = myOrthants.begin(), orthItE = myOrthants.end();
240  orthIt != orthItE; ++orthIt )
241  {
242  Point Tp = t( *orthIt )( p );
243  bool ok = myComputers[ *orthIt ].extend( Tp );
244  if ( ! ok ) _orthantsToErase.push_back( *orthIt );
245  else ++nbok;
246  }
247  if ( nbok != 0 ) // at least one is ok.
248  { // if one is ok, we must remove ko ones from the list of active
249  // axes.
250  OrthantIterator orthIt = myOrthants.begin();
251  for ( unsigned int i = 0; i < _orthantsToErase.size(); ++i )
252  {
253  while ( *orthIt != _orthantsToErase[ i ] ) ++orthIt;
254  orthIt = myOrthants.erase( orthIt );
255  }
256  return true;
257  }
258  return false;
259 }
260 //-----------------------------------------------------------------------------
261 template <typename TSpace, typename TInputPoint, typename TInternalScalar>
262 bool
263 DGtal::ChordGenericStandardPlaneComputer<TSpace, TInputPoint, TInternalScalar>::
264 isExtendable( const InputPoint & p ) const
265 {
266  ASSERT( isValid() );
267  unsigned int nbok = 0;
268  for ( OrthantConstIterator it = myOrthants.begin(), itE = myOrthants.end();
269  it != itE; ++it )
270  {
271  nbok += myComputers[ *it ].isExtendable( t( *it )( p ) ) ? 1 : 0;
272  }
273  return nbok != 0;
274 }
275 //-----------------------------------------------------------------------------
276 template <typename TSpace, typename TInputPoint, typename TInternalScalar>
277 template <typename TInputIterator>
278 bool
279 DGtal::ChordGenericStandardPlaneComputer<TSpace, TInputPoint, TInternalScalar>::
280 extend( TInputIterator it, TInputIterator itE )
281 {
282  BOOST_CONCEPT_ASSERT(( boost::InputIterator<TInputIterator> ));
283  ASSERT( isValid() );
284  typedef boost::transform_iterator<Transform,TInputIterator,InputPoint,InputPoint>
285  TransformedInputIterator;
286  unsigned int nbok = 0;
287  _orthantsToErase.clear();
288  for ( OrthantConstIterator orthIt = myOrthants.begin(), orthItE = myOrthants.end();
289  orthIt != orthItE; ++orthIt )
290  {
291  Dimension orthant = *orthIt;
292  TransformedInputIterator transIt ( it, t( orthant ) );
293  TransformedInputIterator transItE( itE, t( orthant ) );
294  bool ok = myComputers[ orthant ].extend( transIt, transItE );
295  if ( ! ok ) _orthantsToErase.push_back( *orthIt );
296  else ++nbok;
297  }
298  if ( nbok != 0 ) // at least one is ok.
299  { // if one is ok, we must remove ko ones from the list of active
300  // axes.
301  OrthantIterator orthIt = myOrthants.begin();
302  for ( unsigned int i = 0; i < _orthantsToErase.size(); ++i )
303  {
304  while ( *orthIt != _orthantsToErase[ i ] ) ++orthIt;
305  orthIt = myOrthants.erase( orthIt );
306  }
307  return true;
308  }
309  return false;
310 }
311 //-----------------------------------------------------------------------------
312 template <typename TSpace, typename TInputPoint, typename TInternalScalar>
313 template <typename TInputIterator>
314 bool
315 DGtal::ChordGenericStandardPlaneComputer<TSpace, TInputPoint, TInternalScalar>::
316 isExtendable( TInputIterator it, TInputIterator itE ) const
317 {
318  BOOST_CONCEPT_ASSERT(( boost::InputIterator<TInputIterator> ));
319  ASSERT( isValid() );
320  typedef boost::transform_iterator<Transform,TInputIterator,InputPoint,InputPoint>
321  TransformedInputIterator;
322  unsigned int nbok = 0;
323  for ( OrthantConstIterator orthIt = myOrthants.begin(), orthItE = myOrthants.end();
324  orthIt != orthItE; ++orthIt )
325  {
326  Dimension orthant = *orthIt;
327  TransformedInputIterator transIt ( it, t( orthant ) );
328  TransformedInputIterator transItE( itE, t( orthant ) );
329  nbok += myComputers[ orthant ].isExtendable( transIt, transItE ) ? 1 : 0;
330  }
331  return nbok != 0;
332 }
333 
334 //-----------------------------------------------------------------------------
335 template <typename TSpace, typename TInputPoint, typename TInternalScalar>
336 inline
337 typename DGtal::ChordGenericStandardPlaneComputer<TSpace, TInputPoint, TInternalScalar>::Primitive
338 DGtal::ChordGenericStandardPlaneComputer<TSpace, TInputPoint, TInternalScalar>::
339 primitive() const
340 {
341  InternalVector n;
342  InternalScalar imin, imax;
343  InputPoint p_min, p_max;
344  getCharacteristics( n, imin, imax, p_min, p_max );
345  double ddenom = NumberTraits<InternalScalar>::castToDouble( n[ 2 ] );
346  double min = ( NumberTraits<InternalScalar>::castToDouble( imin ) - 0.5 ) / ddenom;
347  double max = ( NumberTraits<InternalScalar>::castToDouble( imax ) + 0.5 ) / ddenom;
348  typename Space::RealVector normal;
349  normal[ 0 ] = NumberTraits<InternalScalar>::castToDouble( n[ 0 ] ) / ddenom;
350  normal[ 1 ] = NumberTraits<InternalScalar>::castToDouble( n[ 1 ] ) / ddenom;
351  normal[ 2 ] = NumberTraits<InternalScalar>::castToDouble( n[ 2 ] ) / ddenom;
352  return Primitive( min, normal, max-min );
353 }
354 
355 //-----------------------------------------------------------------------------
356 template <typename TSpace, typename TInputPoint, typename TInternalScalar>
357 template <typename Vector3D>
358 inline
359 void
360 DGtal::ChordGenericStandardPlaneComputer<TSpace, TInputPoint, TInternalScalar>::
361 getNormal( Vector3D & normal ) const
362 {
363  myComputers[ active() ].getNormal( normal );
364  invT( active() ).transform( normal );
365 }
366 //-----------------------------------------------------------------------------
367 //-----------------------------------------------------------------------------
368 template <typename TSpace, typename TInputPoint, typename TInternalScalar>
369 template <typename Vector3D>
370 inline
371 void
372 DGtal::ChordGenericStandardPlaneComputer<TSpace, TInputPoint, TInternalScalar>::
373 getUnitNormal( Vector3D & normal ) const
374 {
375  myComputers[ active() ].getNormal( normal );
376  invT( active() ).transform( normal );
377  normal /= sqrt( normal[0]*normal[0]
378  +normal[1]*normal[1]
379  +normal[2]*normal[2] );
380 }
381 //-----------------------------------------------------------------------------
382 template <typename TSpace, typename TInputPoint, typename TInternalScalar>
383 inline
384 void
385 DGtal::ChordGenericStandardPlaneComputer<TSpace, TInputPoint, TInternalScalar>::
386 getBounds( double & min, double & max ) const
387 {
388  InternalVector n;
389  InternalScalar imin, imax;
390  InputPoint p_min, p_max;
391  getCharacteristics( n, imin, imax, p_min, p_max );
392  double ddenom = NumberTraits<InternalScalar>::castToDouble( n[ 2 ] );
393  min = ( NumberTraits<InternalScalar>::castToDouble( imin ) - 0.5 ) / ddenom;
394  max = ( NumberTraits<InternalScalar>::castToDouble( imax ) + 0.5 ) / ddenom;
395 }
396 //-----------------------------------------------------------------------------
397 template <typename TSpace, typename TInputPoint, typename TInternalScalar>
398 inline
399 typename DGtal::ChordGenericStandardPlaneComputer<TSpace, TInputPoint, TInternalScalar>::InputPoint
400 DGtal::ChordGenericStandardPlaneComputer<TSpace, TInputPoint, TInternalScalar>::
401 minimalPoint() const
402 {
403  InternalVector n;
404  InternalScalar imin, imax;
405  InputPoint p_min, p_max;
406  getCharacteristics( n, imin, imax, p_min, p_max );
407  return p_min;
408 }
409 //-----------------------------------------------------------------------------
410 template <typename TSpace, typename TInputPoint, typename TInternalScalar>
411 inline
412 typename DGtal::ChordGenericStandardPlaneComputer<TSpace, TInputPoint, TInternalScalar>::InputPoint
413 DGtal::ChordGenericStandardPlaneComputer<TSpace, TInputPoint, TInternalScalar>::
414 maximalPoint() const
415 {
416  InternalVector n;
417  InternalScalar imin, imax;
418  InputPoint p_min, p_max;
419  getCharacteristics( n, imin, imax, p_min, p_max );
420  return p_max;
421 }
422 
423 //-----------------------------------------------------------------------------
424 template <typename TSpace, typename TInputPoint, typename TInternalScalar>
425 inline
426 void
427 DGtal::ChordGenericStandardPlaneComputer<TSpace, TInputPoint, TInternalScalar>::
428 getCharacteristics( InternalVector & n,
429  InternalScalar & imin, InternalScalar & imax,
430  InputPoint & p_min, InputPoint & p_max ) const
431 {
432  // This rather complex method is necessary to guarantee that there
433  // are no numeric error due to bad rounding when casting to double.
434  p_min = invT( active() )( myComputers[ active() ].minimalPoint() );
435  p_max = invT( active() )( myComputers[ active() ].maximalPoint() );
436  // min and max may be swapped because of the transform.
437  n = myComputers[ active() ].exactNormal();
438  invT( active() ).transform( n );
439  if ( n[ 2 ] < NumberTraits<InternalScalar>::ZERO )
440  { n = -n; }
441  imin =
442  ( ( n[ 0 ] * InternalScalar( p_min[ 0 ] ) )
443  + ( n[ 1 ] * InternalScalar( p_min[ 1 ] ) )
444  + ( n[ 2 ] * InternalScalar( p_min[ 2 ] ) ) );
445  imax =
446  ( ( n[ 0 ] * InternalScalar( p_max[ 0 ] ) )
447  + ( n[ 1 ] * InternalScalar( p_max[ 1 ] ) )
448  + ( n[ 2 ] * InternalScalar( p_max[ 2 ] ) ) );
449  if ( imax < imin )
450  {
451  std::swap( imin, imax );
452  std::swap( p_min, p_max );
453  }
454 }
455 
456 
457 ///////////////////////////////////////////////////////////////////////////////
458 // Interface - public :
459 
460 /**
461  * Writes/Displays the object on an output stream.
462  * @param out the output stream where the object is written.
463  */
464 template <typename TSpace, typename TInputPoint, typename TInternalScalar>
465 inline
466 void
467 DGtal::ChordGenericStandardPlaneComputer<TSpace, TInputPoint, TInternalScalar>::selfDisplay ( std::ostream & out ) const
468 {
469  out << "[ChordGenericStandardPlaneComputer";
470  for ( OrthantConstIterator orthIt = myOrthants.begin(), orthItE = myOrthants.end();
471  orthIt != orthItE; ++orthIt )
472  out << " " << myComputers[ *orthIt ];
473  out << " ]";
474 }
475 
476 /**
477  * Checks the validity/consistency of the object.
478  * @return 'true' if the object is valid, 'false' otherwise.
479  */
480 template <typename TSpace, typename TInputPoint, typename TInternalScalar>
481 inline
482 bool
483 DGtal::ChordGenericStandardPlaneComputer<TSpace, TInputPoint, TInternalScalar>::isValid() const
484 {
485  return myComputers[ active() ].isValid();
486 }
487 
488 
489 ///////////////////////////////////////////////////////////////////////////////
490 // Internals
491 ///////////////////////////////////////////////////////////////////////////////
492 
493 //-----------------------------------------------------------------------------
494 template <typename TSpace, typename TInputPoint, typename TInternalScalar>
495 inline
496 typename DGtal::ChordGenericStandardPlaneComputer<TSpace, TInputPoint, TInternalScalar>::Transform
497 DGtal::ChordGenericStandardPlaneComputer<TSpace, TInputPoint, TInternalScalar>::
498 t( Dimension orthant )
499 {
500  ASSERT( orthant < 4 );
501  return myTransforms[ orthant ];
502 }
503 //-----------------------------------------------------------------------------
504 template <typename TSpace, typename TInputPoint, typename TInternalScalar>
505 inline
506 typename DGtal::ChordGenericStandardPlaneComputer<TSpace, TInputPoint, TInternalScalar>::Transform
507 DGtal::ChordGenericStandardPlaneComputer<TSpace, TInputPoint, TInternalScalar>::
508 invT( Dimension orthant )
509 {
510  ASSERT( orthant < 4 );
511  return myTransforms[ orthant ^ 0x3 ];
512 }
513 
514 ///////////////////////////////////////////////////////////////////////////////
515 // Implementation of inline functions //
516 
517 template <typename TSpace, typename TInputPoint, typename TInternalScalar>
518 inline
519 std::ostream&
520 DGtal::operator<< ( std::ostream & out,
521  const ChordGenericStandardPlaneComputer<TSpace, TInputPoint, TInternalScalar> & object )
522 {
523  object.selfDisplay( out );
524  return out;
525 }
526 
527 // //
528 ///////////////////////////////////////////////////////////////////////////////
529