otbGlView.h 16.8 KB
Newer Older
1
/*=========================================================================
2

3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
  Program:   ORFEO Toolbox
  Language:  C++
  Date:      $Date$
  Version:   $Revision$


  Copyright (c) Centre National d'Etudes Spatiales. All rights reserved.
  See OTBCopyright.txt for details.


     This software is distributed WITHOUT ANY WARRANTY; without even
     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
     PURPOSE.  See the above copyright notices for more information.

=========================================================================*/
Julien Michel's avatar
INIT  
Julien Michel committed
18 19 20
#ifndef otb_GlView_h
#define otb_GlView_h

21 22

#include "otbGeoInterface.h"
Julien Michel's avatar
INIT  
Julien Michel committed
23
#include "otbGlActor.h"
24
#include "otbViewSettings.h"
Julien Michel's avatar
INIT  
Julien Michel committed
25 26 27

#include <map>
#include <vector>
28
#include <cassert>
29

Julien Michel's avatar
INIT  
Julien Michel committed
30 31 32
namespace otb
{

33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58
template< typename T >
void
assert_quiet_NaN( T val )
{
  assert( !std::numeric_limits< T >::has_quiet_NaN ||
	  ( std::numeric_limits< T >::has_quiet_NaN &&
	    val!=std::numeric_limits< T >::quiet_NaN() ) );
}

template< typename T >
void
assert_signaling_NaN( T val )
{
  assert( !std::numeric_limits< T >::has_signaling_NaN ||
	  ( std::numeric_limits< T >::has_signaling_NaN &&
	    val!=std::numeric_limits< T >::signaling_NaN() ) );
}

template< typename T >
void
assert_NaN( T val )
{
  assert_quiet_NaN( val );
  assert_signaling_NaN( val );
}

59 60 61 62 63 64 65 66 67 68 69 70 71
/** 
 * The GlView class acts like an OpenGl scene where actors deriving
 * from the GlActor class can be rendered. The GlView class contains the
 * OpenGl viewport and manages:
 * - The size of the viewport,
 * - The entire refresh loop, including light or heavy rendering of
 * all actors and all OpenGl specific stuff needed before and after
 * the actors update,
 * - The actors stack (order in which actors are rendered).
 * 
 * All parameters related to scene description (origin, spacing, angle
 * ...) are stored and managed by the ViewSettings class.
 */
Julien Michel's avatar
INIT  
Julien Michel committed
72 73 74 75 76 77 78 79 80 81 82 83 84
class GlView 
  : public itk::Object
{
public:
  typedef GlView                                          Self;
  typedef itk::Object                                     Superclass;
  typedef itk::SmartPointer<Self>                         Pointer;
  typedef itk::SmartPointer<const Self>                   ConstPointer;

  typedef otb::GlActor                                    ActorType;
  typedef std::map<std::string,ActorType::Pointer>        ActorMapType;
  typedef std::vector<std::string>                        StringVectorType;

85 86 87 88 89
  /**
   * Type definition for otb::GlActor storage key.
   */
  typedef StringVectorType::value_type KeyType;

Julien Michel's avatar
INIT  
Julien Michel committed
90 91
  itkNewMacro(Self);

92 93 94 95 96 97
  /**
   * The Intialize method will reset the OpenGl viewport to the given
   * size, clear view settings and remove any existing actor.
   * \param sx Width of the viewport
   * \param sy Height of the viewport
   */ 
Julien Michel's avatar
INIT  
Julien Michel committed
98 99
  void Initialize(unsigned int sx, unsigned int sy);

100 101 102 103 104 105 106 107 108 109 110 111
  /**
   * This method allows to add a new actor (deriving from GlActor) to
   * the GlView. The actor can be identified by an optional key. If
   * not provided, and the default value is used, the method will
   * generate a key to identify the actor. In both case, the key is
   * returned by the method.  
   * \param actor The actor to be added
   * \param key The key to be used to identify the actor (default to
   * empty string)
   * \return The key identifying the actor (either passed to the
   * method or generated by it).
   */
Julien Michel's avatar
INIT  
Julien Michel committed
112 113
  std::string AddActor(ActorType * actor, const std::string & key = "");

114 115 116 117 118 119 120
  /** 
   * This method will try to remove the actor identified by the given
   * key.
   * \param key The key identifying the actor to remove
   * \return True if the actor has been found and removed, false
   * otherwise
   */
121 122
  bool RemoveActor(const std::string & key);

123 124 125
  /**
   * This method will remove all existing actors at once.
   */
Julien Michel's avatar
INIT  
Julien Michel committed
126 127
  void ClearActors();

128 129 130 131 132 133 134
  /**
   * This method allows to retrieve a pointer to the actor identified
   * by the given key.
   * \param key The key identifying the actor to retrieve
   * \return A pointer to the retrieved actor. This pointer will be
   * null if no actor could be found with this key.
   */  
135
  ActorType::Pointer GetActor(const std::string & key) const;
Julien Michel's avatar
INIT  
Julien Michel committed
136

137 138 139 140 141 142 143 144 145
  /**
   * Tells wether an otb::GlActor is contained given its storage key.
   *
   * @param key otb::GlActor storage key.
   *
   * @return true if an otb::GlActor is contained given storage key.
   */
  bool ContainsActor( const KeyType & key ) const;

146 147 148 149 150
  /**
   * This method will return a vector containing the keys of all
   * actors.
   * \return A vector of string containing the keys of all actors.
   */ 
151 152
  std::vector<std::string> GetActorsKeys() const;

153 154 155 156
  /**
   * This method handles all the things that should be done before
   * rendering.
   */
Julien Michel's avatar
INIT  
Julien Michel committed
157 158
  void BeforeRendering();

159 160 161 162
  /**
   * This method handles all the things that should be after before
   * rendering.
   */
Julien Michel's avatar
INIT  
Julien Michel committed
163 164
  void AfterRendering();

165 166 167 168 169 170
  /**
   * This method will update the rendering of the OpenGl viewport,
   * taking into account all parameters in the ViewSettings, without
   * fetching any missing data from disk or RAM. It is therefore very
   * fast.
   */
Julien Michel's avatar
INIT  
Julien Michel committed
171 172
  void LightRender();

173 174 175 176 177 178
  /**
   * This method will update the rendering of the OpenGl viewport,
   * taking into account all parameters in the ViewSettings, but will
   * first compute and load any missing data for a complete
   * rendering. As such, this update routine can be time consuming.
   */
Julien Michel's avatar
INIT  
Julien Michel committed
179 180 181 182 183 184 185 186 187
  void HeavyRender();

  // Resize viewport
  void Resize(unsigned int sx, unsigned int sy);

  itkSetObjectMacro(Settings,ViewSettings);
  itkGetObjectMacro(Settings,ViewSettings);
  itkGetConstObjectMacro(Settings,ViewSettings);

188 189
  //comment this macro (not compiling with OTB 3.X)
  // Get Rendering order
190 191
  const StringVectorType & GetRenderingOrder() const
  {
192
    return m_RenderingOrder;
193 194 195
  };

  /**
196 197
   * Arbitrary set the rendering order of some or all of contained
   * otb::GlActor instances.
198 199 200 201
   *
   * Keys which are not contained will be ignored.
   *
   * @param keys The ordered sequence of keys.
202 203
   * @param front <code>true</code> to order selected otb::GlActor
   *              instances in front of non-selected ones.
204
   */
205 206
  void SetRenderingOrder( const StringVectorType & keys,
                          bool front );
Julien Michel's avatar
Julien Michel committed
207

208 209 210 211 212 213
  // This will rotate the rendering order (without modifying the order)
  void RotateRenderingOrder(bool down = false);

  // Move actor in rendering order
  void MoveActorInRenderingOrder(std::string key, bool down = false);

214 215 216 217
  // Move actor to the end of rendering order (either front if front
  // is set to true or back if front is set to false)
  void MoveActorToEndOfRenderingOrder(std::string key, bool front = false);

218
  /**
219 220
   * Reproject point and spacing expressed in viewport coordinate
   * system into given actor coordinate system.
221 222
   */
  template< typename P, typename S, typename P2, typename S2 >
223 224 225 226 227 228
  bool ReprojectFromView( P & center,
			  S & spacing,
			  const KeyType & key,
			  const P2 & vcenter,
			  const S2 & vspacing,
			  double norm = 1000.0 ) const;
229

230 231 232
  /**
   */
  template< typename P >
233
  bool GetExtent( P & origin, P & extent, bool isOverlay =false ) const;
234 235 236 237

  /**
   */
  template< typename Point, typename Spacing >
238 239 240
  bool ZoomToExtent( const Spacing & native,
		     Point & center,
		     Spacing & spacing ) const;
241 242 243 244

  /**
   */
  template< typename Point, typename Spacing >
245 246 247 248
  bool ZoomToLayer( const KeyType & key,
		    const Spacing & native,
		    Point & center,
		    Spacing & spacing ) const;
249

250 251 252 253 254
  /**
   */
  template< typename Point, typename Spacing >
  bool ZoomToRegion( const Point & origin,
		     const Point & extent,
255
		     const Spacing & native,
256 257 258
		     Point & center,
		     Spacing & spacing ) const;

259 260 261 262 263 264 265
  /**
   */
  template< typename Point, typename Spacing >
  bool ZoomToFull( const KeyType & key,
		   Point & center,
		   Spacing & spacing,
		   double units = 1000.0 ) const;
266

Julien Michel's avatar
INIT  
Julien Michel committed
267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284
protected:
  GlView();

  virtual ~GlView();

private:
  // prevent implementation
  GlView(const Self&);
  void operator=(const Self&);

  ViewSettings::Pointer m_Settings;

  ActorMapType          m_Actors;

  StringVectorType      m_RenderingOrder;

}; // End class GlView

285 286 287 288

template< typename P, typename S, typename P2, typename S2 >
bool
GlView
289 290 291 292 293 294
::ReprojectFromView( P & center,
		     S & spacing,
		     const KeyType & key,
		     const P2 & vcenter,
		     const S2 & vspacing,
		     double norm ) const
295
{
296
  // std::cout << "otb::GlView@" << std::hex << this << std::endl << "{" << std::endl;
Stéphane Albert's avatar
Stéphane Albert committed
297

298 299 300 301 302 303 304
  assert_NaN( vcenter[ 0 ] );
  assert_NaN( vcenter[ 1 ] );

  assert_NaN( vspacing[ 0 ] );
  assert_NaN( vspacing[ 1 ] );


305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323
  //
  // Reference actor has not been found.
  otb::GlActor::Pointer actor( GetActor( key ) );

  if( actor.IsNull() )
    return false;


  //
  // Reference actor does not implement geo-interface.
  const otb::GeoInterface * geo =
    dynamic_cast< const GeoInterface * >( actor.GetPointer() );

  if( geo==NULL )
    return false;


  //
  // Compute transform origin.
324
  if( !geo->TransformFromViewport( center, vcenter, true ) )
325 326 327 328 329 330 331 332
    return false;

  //
  // Compute transformed X-axis extremity.
  GeoInterface::Point2d x( vcenter );

  x[ 0 ] += norm * vspacing[ 0 ]; 

333
  // std::cout << "X {" << std::endl;
Stéphane Albert's avatar
Stéphane Albert committed
334

335 336 337
  if( !geo->TransformFromViewport( x, x, true ) )
    return false;

338
  // std::cout << "x: " << x[ 0 ] << ", " << x[ 1 ] << std::endl;
Stéphane Albert's avatar
Stéphane Albert committed
339

340 341
  // assert_NaN( x[ 0 ] );
  // assert_NaN( x[ 1 ] );
Stéphane Albert's avatar
Stéphane Albert committed
342

343
  // std::cout << "}" << std::endl;
Stéphane Albert's avatar
Stéphane Albert committed
344

345 346 347 348 349 350
  //
  // Compute transformed Y-axis extremity.
  GeoInterface::Point2d y( vcenter );

  y[ 1 ] += norm * vspacing[ 1 ];

351
  // std::cout << "Y {" << std::endl;
Stéphane Albert's avatar
Stéphane Albert committed
352

353 354 355
  if( !geo->TransformFromViewport( y, y, true ) )
    return false; 

356
  // std::cout << "y: " << y[ 0 ] << ", " << y[ 1 ] << std::endl;
Stéphane Albert's avatar
Stéphane Albert committed
357

358 359
  // assert_NaN( y[ 0 ] );
  // assert_NaN( y[ 1 ] );
Stéphane Albert's avatar
Stéphane Albert committed
360

361
  // std::cout << "}" << std::endl;
Stéphane Albert's avatar
Stéphane Albert committed
362

363 364 365 366 367 368 369 370 371
  //
  // Compute transformed spacing.
  //
  // Note SAT:
  //     Formula has been taken from IceViewer::key_callback(). I think
  // that the norm of the transformed X and Y axises is not
  // the new spacing if transform contains a rotation.
  //     To correct this, transformed X and Y vectors should be
  // projected against reference actor X and Y axises (using vectorial
372
  // dot product).
373

374 375
  x[ 0 ] -= center[ 0 ];
  x[ 1 ] -= center[ 1 ];
376

377 378
  y[ 0 ] -= center[ 0 ];
  y[ 1 ] -= center[ 1 ];
379 380 381 382

  spacing[ 0 ] = vcl_sqrt( x[ 0 ] * x[ 0 ] + x[ 1 ] * x[ 1 ] ) / norm;
  spacing[ 1 ] = vcl_sqrt( y[ 0 ] * y[ 0 ] + y[ 1 ] * y[ 1 ] ) / norm;

383 384 385 386 387 388 389 390 391
  // Sign of x-spacing is done by sign( x . (1, 0) ) which is sign( x[ 0 ] )
  // Sign of y-spacing is done by sign( y . (0, 1) ) which is sign[ y[ 1 ] )

  if( x[ 0 ]<0.0 )
    spacing[ 0 ] = -spacing[ 0 ];

  if( y[ 1 ]<0.0 )
    spacing[ 1 ] = -spacing[ 1 ];

392 393 394 395 396 397 398 399
  //
  // Chech outputs.
  assert_NaN( center[ 0 ] );
  assert_NaN( center[ 1 ] );

  assert_NaN( spacing[ 0 ] );
  assert_NaN( spacing[ 1 ] );

400
  // std::cout << "} otb::GlView@" << std::hex << this << std::endl;
Stéphane Albert's avatar
Stéphane Albert committed
401

402 403
  //
  // Ok.
404 405 406
  return true;
}

407 408

template< typename P >
409
bool
410
GlView
411
::GetExtent( P & origin, P & extent, bool isOverlay ) const
412 413 414
{
  if( m_Actors.empty() )
    {
Stéphane Albert's avatar
Stéphane Albert committed
415 416
    origin.Fill( 0 );
    extent.Fill( 0 );
417

418
    return false;
419 420 421 422 423 424 425 426 427 428 429 430 431
    }


  origin[ 0 ] = std::numeric_limits< typename P::ValueType >::infinity();
  origin[ 1 ] = std::numeric_limits< typename P::ValueType >::infinity();

  extent[ 0 ] = -std::numeric_limits< typename P::ValueType >::infinity();
  extent[ 1 ] = -std::numeric_limits< typename P::ValueType >::infinity();

  for( ActorMapType::const_iterator it( m_Actors.begin() );
       it!=m_Actors.end();
       ++it )
    {
432
    assert( !it->second.IsNull() );
433

434 435 436 437
    if( it->second->GetOverlay()==isOverlay )
      {
      P o;
      P e;
Stéphane Albert's avatar
Stéphane Albert committed
438

439 440
      o.Fill( 0 );
      e.Fill( 0 );
441

442
      it->second->GetExtent( o[ 0 ], o[ 1 ], e[ 0 ], e[ 1 ] );
443

444

445 446
      if( o[ 0 ]<origin[ 0 ] )
	origin[ 0 ] = o[ 0 ];
447

448 449
      if( o[ 1 ]<origin[ 1 ] )
	origin[ 1 ] = o[ 1 ];
450

451 452
      if( o[ 0 ]>extent[ 0 ] )
	extent[ 0 ] = o[ 0 ];
453

454 455
      if( o[ 1 ]>extent[ 1 ] )
	extent[ 1 ] = o[ 1 ];
456 457


458 459
      if( e[ 0 ]<origin[ 0 ] )
	origin[ 0 ] = e[ 0 ];
460

461 462
      if( e[ 1 ]<origin[ 1 ] )
	origin[ 1 ] = e[ 1 ];
463

464 465
      if( e[ 0 ]>extent[ 0 ] )
	extent[ 0 ] = e[ 0 ];
466

467 468 469
      if( e[ 1 ]>extent[ 1 ] )
	extent[ 1 ] = e[ 1 ];
      }
470
    }
471 472 473 474 475 476 477 478

  return true;
}


template< typename Point, typename Spacing >
bool
GlView
479
::ZoomToExtent( const Spacing & native, Point & center, Spacing & spacing ) const
480 481 482 483
{
  Point o;
  Point e;

Stéphane Albert's avatar
Stéphane Albert committed
484 485 486
  o.Fill( 0 );
  e.Fill( 0 );

487 488 489 490
  // Get origin and extent of all layers in viewport system.
  if( !GetExtent( o, e ) )
    return false;

491 492 493
  // std::cout << "origin: [ " << o[ 0 ] << ", " << o[ 1 ] << " ]" << std::endl;
  // std::cout << "extent: [ " << e[ 0 ] << ", " << e[ 1 ] << " ]" << std::endl;

494
  // Zoom to overall region.
495
  return ZoomToRegion( o, e, native, center, spacing );
496 497 498 499 500 501
}


template< typename Point, typename Spacing >
bool
GlView
502 503 504 505
::ZoomToLayer( const KeyType & key,
	       const Spacing & native,
	       Point & center,
	       Spacing & spacing ) const
506 507 508 509
{
  Point o;
  Point e;

510
  // Get layer actor.
511
  GlActor::Pointer actor( GetActor( key ) );
512 513 514 515

  // If not found...
  if( actor.IsNull() )
    return false;
516 517 518 519

  // Get origin and extent of layer.
  actor->GetExtent( o[ 0 ], o[ 1 ], e[ 0 ], e[ 1 ] );

520
  // Zoom layer region.
521
  return ZoomToRegion( o, e, native, center, spacing );
522 523 524 525 526 527 528 529
}


template< typename Point, typename Spacing >
bool
GlView
::ZoomToRegion( const Point & origin,
		const Point & extent,
530
		const Spacing & native,
531 532 533
		Point & center,
		Spacing & spacing ) const
{
534 535 536 537 538 539 540
  // std::cout
  //   << std::hex << this
  //   << "::ZoomToRegion( "
  //   << "[ " << origin[ 0 ] << ", " << origin[ 1 ] << "], "
  //   << "[ " << extent[ 0 ] << ", " << extent[ 1 ] << "], "
  //   << "[ " << spacing[ 0 ] << ", " << spacing[ 1 ] << "] )"
  //   << std::endl;
Stéphane Albert's avatar
Stéphane Albert committed
541

542
  // Compute center point.
543
  center.SetToMidPoint( origin, extent );
544

545
  // std::cout << "-> center: " << center[ 0 ] << ", " << center[ 1 ] << std::endl;
Stéphane Albert's avatar
Stéphane Albert committed
546

547 548
  // Get scale of (o, e) in viewport.
  assert( !m_Settings.IsNull() );
549
  double scale = m_Settings->GetScale( origin, extent, true );
550

551
  // std::cout << "-> scale: " << scale << std::endl;
Stéphane Albert's avatar
Stéphane Albert committed
552

553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576
  /*
  assert( !std::numeric_limits< typename Spacing::ValueType >::has_quiet_NaN() ||
	  ( std::numeric_limits< typename Spacing::ValueType >::has_quiet_NaN() &&
	    native[ 0 ]!=std::numeric_limits< typename Spacing::ValueType >::quiet_NaN()
	  )
  );
  assert( !std::numeric_limits< typename Spacing::ValueType >::has_quiet_NaN() ||
	  ( std::numeric_limits< typename Spacing::ValueType >::has_quiet_NaN() &&
	  native[ 1 ]!=std::numeric_limits< typename Spacing::ValueType >::quiet_NaN()
	  )
  );

  assert( !std::numeric_limits< typename Spacing::ValueType >::has_quiet_NaN() ||
	  ( std::numeric_limits< typename Spacing::ValueType >::has_quiet_NaN() &&
	    native[ 0 ]!=std::numeric_limits< typename Spacing::ValueType >::quiet_NaN()
	  )
  );
  assert( !std::numeric_limits< typename Spacing::ValueType >::has_quiet_NaN() ||
	  ( std::numeric_limits< typename Spacing::ValueType >::has_quiet_NaN() &&
	  native[ 1 ]!=std::numeric_limits< typename Spacing::ValueType >::quiet_NaN()
	  )
  );
  */

577
  // Apply signed scale.
578 579
  spacing[ 0 ] = ( native[ 0 ]<0.0 ? -1 : +1 ) * scale;
  spacing[ 1 ] = ( native[ 1 ]<0.0 ? -1 : +1 ) * scale;
580

581
  // std::cout << "-> spacing: " << center[ 0 ] << ", " << center[ 1 ] << std::endl;
Stéphane Albert's avatar
Stéphane Albert committed
582

583 584 585 586 587 588 589 590
  // Ok.
  return true;
}


template< typename Point, typename Spacing >
bool
GlView
591 592 593 594
::ZoomToFull( const KeyType & key,
	      Point & center,
	      Spacing & spacing,
	      double units ) const
595
{
596
  // Get layer actor.
597
  GlActor::Pointer actor( GetActor( key ) );
598 599 600 601

  // If not found...
  if( actor.IsNull() )
    return false;
602 603

  // Get geo-interface.
604 605
  const GeoInterface * geo =
    dynamic_cast< const GeoInterface * >( actor.GetPointer() );
606 607 608 609 610 611 612 613 614 615 616 617 618

  if( geo==NULL )
    return false;

  // Get viewport current center and spacing.
  assert( !m_Settings.IsNull() );

  center = m_Settings->GetViewportCenter();
  spacing = m_Settings->GetSpacing();

  // Transform center point to image space..
  Point o;

619
  if( !geo->TransformFromViewport( o, center, true ) )
620 621
    return false;

622
  //
623 624 625 626 627 628 629
  // Consider arbitrary point on the X-axis.
  Point e;

  e[ 0 ] = center[ 0 ] + units * spacing[ 0 ];
  e[ 1 ] = center[ 1 ];

  // Transform considered point.
630
  if( !geo->TransformFromViewport( e, e, true ) )
631 632 633 634 635 636 637
    return false;

  // Compute extent vector.
  e[ 0 ] -= o[ 0 ];
  e[ 1 ] -= o[ 1 ];

  // Apply extent vector length to view spacing.
638 639 640
  spacing[ 0 ] =
    units * spacing[ 0 ] /
    vcl_sqrt( e[ 0 ] * e[ 0 ] + e[ 1 ] * e[ 1 ] );
641

642
  //
643 644 645 646 647
  // Consider arbitrary point on the Y-axis.
  e[ 0 ] = center[ 0 ];
  e[ 1 ] = center[ 1 ] + units * spacing[ 1 ];

  // Transform considered point.
648
  if( !geo->TransformFromViewport( e, e, true ) )
649 650 651 652 653 654 655
    return false;

  // Compute extent vector.
  e[ 0 ] -= o[ 0 ];
  e[ 1 ] -= o[ 1 ];

  // Apply extent vector length to view spacing.
656 657 658
  spacing[ 1 ] =
    units * spacing[ 1 ] /
    vcl_sqrt( e[ 0 ] * e[ 0 ] + e[ 1 ] * e[ 1 ] );
659

660
  //
661 662
  // Ok.
  return true;
663 664 665
}


Julien Michel's avatar
INIT  
Julien Michel committed
666 667 668
} // End namespace otb

#endif