OpenDAFF C++ API  v1.7
Directional Audio File Format
DAFFVizSGNode.cpp
Go to the documentation of this file.
3 #include <DAFFUtils.h>
4 
5 #include <cassert>
6 #include <math.h>
7 #include <cmath>
8 
9 // VTK includes
10 #include <vtkActor.h>
11 #include <vtkAssembly.h>
12 #include <vtkCamera.h>
13 #include <vtkMatrix4x4.h>
14 #include <vtkTransform.h>
15 
16 namespace DAFFViz
17 {
19  : m_pParentNode( NULL )
20  {
21  m_pNodeAssembly = vtkSmartPointer< vtkAssembly >::New();
22 
23  if( pParentNode != nullptr )
24  pParentNode->AddChildNode( this );
25  }
26 
28  {
29  // Disconnect from parent node
30  if( m_pParentNode )
31  m_pParentNode->RemoveChildNode( this );
32 
33  // Delete own subtree
34  // Important: delete has side-effects on the vector itself. Therefore we use the while construct.
35  while( !m_vpChildNodes.empty() )
36  delete m_vpChildNodes.front();
37 
38  // Remove the node assembly
40  /*
41  * Very important: All subclasses of SGNode MUST remove their own actors in their destructors
42  * If everything went fine, the node assembly is empty here. Otherwise some
43  * subclass of SGNode forgot to tidy up. If we would delete the node assembly
44  * regardless the fact that it is not empty, we get in trouble (crash).
45  * We leave an assertion here, so that programmers are aware of that problem...
46  * ... If you run into that assertion, remind yourself to always RemovePart()
47  * all the vtkActors in your derived class.
48  */
49  assert( m_pNodeAssembly->GetNumberOfPaths() == 0 );
50  //m_pNodeAssembly->GlobalWarningDisplayOff();
51  //m_pNodeAssembly->Delete(); // smart pointer deletes ...
53  }
54 
56  {
57  // Recursively traverse to root node
58  return ( m_pParentNode ? m_pParentNode->GetRootNode() : NULL );
59  }
60 
62  {
63  return m_pParentNode;
64  }
65 
66  bool SGNode::HasParentNode() const
67  {
68  return ( m_pParentNode != NULL );
69  }
70 
71  bool SGNode::IsRoot() const
72  {
73  return ( m_pParentNode == NULL );
74  }
75 
76  bool SGNode::HasChildNodes() const
77  {
78  return ( !m_vpChildNodes.empty() );
79  }
80 
81  bool SGNode::IsLeaf() const
82  {
83  return m_vpChildNodes.empty();
84  }
85 
86  const DAFFViz::SGNode* SGNode::GetChildNode( int iIndex ) const
87  {
88  assert( ( iIndex > 0 ) && ( iIndex < ( int ) m_vpChildNodes.size() ) );
89 
90  if( ( iIndex > 0 ) && ( iIndex < ( int ) m_vpChildNodes.size() ) )
91  return m_vpChildNodes[ iIndex ];
92  else
93  return NULL;
94  }
95 
97  {
98  assert( ( iIndex > 0 ) && ( iIndex < ( int ) m_vpChildNodes.size() ) );
99 
100  if( ( iIndex > 0 ) && ( iIndex < ( int ) m_vpChildNodes.size() ) )
101  return m_vpChildNodes[ iIndex ];
102  else
103  return NULL;
104  }
105 
106  void SGNode::GetChildNodes( std::vector<const DAFFViz::SGNode*>& vpChildren ) const
107  {
108  if( m_vpChildNodes.empty() ) {
109  vpChildren.clear();
110  return;
111  }
112 
113  vpChildren.resize( m_vpChildNodes.size() );
114  for( size_t i = 0; i < m_vpChildNodes.size(); i++ )
115  vpChildren[ i ] = m_vpChildNodes[ i ];
116  }
117 
118  void SGNode::GetChildNodes( std::vector<DAFFViz::SGNode*>& vpChildren ) {
119  if( m_vpChildNodes.empty() ) {
120  vpChildren.clear();
121  return;
122  }
123 
124  vpChildren.resize( m_vpChildNodes.size() );
125  for( size_t i = 0; i < m_vpChildNodes.size(); i++ )
126  vpChildren[ i ] = m_vpChildNodes[ i ];
127  }
128 
130  {
131  /*
132  * Wichtig: Der Knoten darf nur dann hinzugefügt werden, falls er nicht
133  * bereits Unterknoten in einem anderen (Teil)baum ist. Dies
134  * stellt sicher, das jeder Knoten höchstens in einem Teilbaum
135  * enthalten sein ist. Der Test erfolgt über die Wurzel.
136  */
137 
138  assert( pChild != NULL );
139  if( pChild == NULL ) return false;
140 
141  // Ausschließen das man einen Knoten zu sich selbst verknüpft
142  assert( pChild != this );
143  if( pChild == this ) return false;
144 
145  // Child already has a parent (root) node
146  assert( pChild->IsRoot() );
147  if( !pChild->IsRoot() )
148  return false;
149 
150  // Intern den Unterbaum verknüpfen
151  m_vpChildNodes.push_back( pChild );
152 
153  // Beim Kinderknoten den Vaterknoten vermerken
154  pChild->m_pParentNode = this;
155 
156  // Assemblies verknüpfen
158  m_pNodeAssembly->AddPart( pChild->m_pNodeAssembly );
160 
161  return true;
162  }
163 
164  bool SGNode::AddChildNodes( const std::vector<DAFFViz::SGNode*>& vpChildren ) {
165  bool bResult = true;
166  for( std::vector<DAFFViz::SGNode*>::const_iterator cit = vpChildren.begin(); cit != vpChildren.end(); ++cit )
167  bResult &= AddChildNode( *cit );
168  return bResult;
169  }
170 
172  for( std::vector<DAFFViz::SGNode*>::iterator it = m_vpChildNodes.begin(); it != m_vpChildNodes.end(); ++it )
173  if( ( *it ) == pChild ) {
174  // Assemblies lösen
176  m_pNodeAssembly->RemovePart( pChild->m_pNodeAssembly );
178 
179  // Beim Kinderknoten die Vaterschaft entfernen
180  pChild->m_pParentNode = NULL;
181 
182  // Kinderknoten aus der Liste löschen
183  m_vpChildNodes.erase( it );
184 
185  return true;
186  }
187 
188  return false;
189  }
190 
191  bool SGNode::RemoveChildNodes( const std::vector<DAFFViz::SGNode*>& vpChildren ) {
192  bool bResult = true;
193  for( std::vector<DAFFViz::SGNode*>::const_iterator cit = vpChildren.begin(); cit != vpChildren.end(); ++cit )
194  bResult &= RemoveChildNode( *cit );
195  return bResult;
196  }
197 
198  void SGNode::GetPosition( double& x, double& y, double& z ) const
199  {
200  double* data = m_pNodeAssembly->GetPosition();
201  x = data[ 0 ];
202  y = data[ 1 ];
203  z = data[ 2 ];
204  }
205 
206  void SGNode::SetPosition( double x, double y, double z )
207  {
209  // [fwe 2011-11-10] Speicherleck hier drin?
210  m_pNodeAssembly->SetPosition( x, y, z );
212  }
213 
214  void SGNode::GetOrientation( double& rotx_deg, double& roty_deg, double& rotz_deg ) const
215  {
216  double* data = m_pNodeAssembly->GetOrientation();
217  rotx_deg = data[ 0 ];
218  roty_deg = data[ 1 ];
219  rotz_deg = data[ 2 ];
220  }
221 
222  void SGNode::SetOrientation( double rotx_deg, double roty_deg, double rotz_deg )
223  {
225  // [fwe 2011-11-10] Speicherleck hier drin?
226  m_pNodeAssembly->SetOrientation( rotx_deg, roty_deg, rotz_deg );
228  }
229 
230  void SGNode::SetOrientationYPR( double yaw, double pitch, double roll )
231  {
232  double* pos = m_pNodeAssembly->GetPosition();
233 
234  double r = DAFFUtils::grad2rad( roll );
235  double p = DAFFUtils::grad2rad( pitch );
236  double y = DAFFUtils::grad2rad( yaw );
237 
238  // Translation matrix: to origin
239  vtkSmartPointer< vtkMatrix4x4 > mOrigin = vtkSmartPointer< vtkMatrix4x4 >::New();
240  mOrigin->Identity();
241  mOrigin->SetElement( 0, 3, -pos[ 0 ] );
242  mOrigin->SetElement( 1, 3, -pos[ 1 ] );
243  mOrigin->SetElement( 2, 3, -pos[ 2 ] );
244 
245  // Translation matrix: to object position
246  vtkSmartPointer< vtkMatrix4x4 > mPosition = vtkSmartPointer< vtkMatrix4x4 >::New();
247  mPosition->Identity();
248  mPosition->SetElement( 0, 3, pos[ 0 ] );
249  mPosition->SetElement( 1, 3, pos[ 1 ] );
250  mPosition->SetElement( 2, 3, pos[ 2 ] );
251 
252  /*
253  * Roll: homogenous rotation matrix for -Z axis
254  *
255  *
256  * cos(alpha) sin(alpha) 0 0
257  * -sin(alpha) cos(alpha) 0 0
258  * 0 0 1 0
259  * 0 0 0 1
260  */
261  vtkSmartPointer< vtkMatrix4x4 > mRoll = vtkSmartPointer< vtkMatrix4x4 >::New();
262  mRoll->Identity();
263  mRoll->SetElement( 0, 0, cos( r ) );
264  mRoll->SetElement( 0, 1, sin( r ) );
265  mRoll->SetElement( 1, 0, -sin( r ) );
266  mRoll->SetElement( 1, 1, cos( r ) );
267 
268  /*
269  * Pitch: homogenous rotation matrix for +X axis
270  *
271  * 1 0 0 0
272  * 0 cos(alpha) -sin(alpha) 0
273  * 0 sin(alpha) cos(alpha) 0
274  * 0 0 0 1
275  */
276  vtkSmartPointer< vtkMatrix4x4 > mPitch = vtkSmartPointer< vtkMatrix4x4 >::New();
277  mPitch->Identity();
278  mPitch->SetElement( 1, 1, cos( p ) );
279  mPitch->SetElement( 1, 2, -sin( p ) );
280  mPitch->SetElement( 2, 1, sin( p ) );
281  mPitch->SetElement( 2, 2, cos( p ) );
282 
283  /*
284  * Yaw: homogenous rotation matrix for +Y axis
285  *
286  * cos(alpha) 0 sin(alpha) 0
287  * 0 1 0 0
288  * -sin(alpha) 0 cos(alpha) 0
289  * 0 0 0 1
290  */
291  vtkSmartPointer< vtkMatrix4x4 > mYaw = vtkSmartPointer< vtkMatrix4x4 >::New();
292  mYaw->Identity();
293  mYaw->SetElement( 0, 0, cos( y ) );
294  mYaw->SetElement( 0, 2, sin( y ) );
295  mYaw->SetElement( 2, 0, -sin( y ) );
296  mYaw->SetElement( 2, 2, cos( y ) );
297 
298 
299  // Compose transforms
300  // (Order: Origin, Roll, Pitch, Yaw, Position)
301  vtkSmartPointer< vtkTransform > transform = vtkSmartPointer< vtkTransform >::New();
302  transform->Concatenate( mPosition );
303  transform->Concatenate( mYaw );
304  transform->Concatenate( mPitch );
305  transform->Concatenate( mRoll );
306  transform->Concatenate( mOrigin );
307 
308  // Apply new transformation
310  m_pNodeAssembly->SetUserTransform( transform );
312 
313  return;
314  }
315 
316  void SGNode::SetOrientationVU( double vx, double vy, double vz,
317  double ux, double uy, double uz )
318  {
319  double* pos = m_pNodeAssembly->GetPosition();
320 
321  // Translation matrix: to origin
322  vtkSmartPointer< vtkMatrix4x4 > mOrigin = vtkSmartPointer< vtkMatrix4x4 >::New();
323  mOrigin->Identity();
324  mOrigin->SetElement( 0, 3, -pos[ 0 ] );
325  mOrigin->SetElement( 1, 3, -pos[ 1 ] );
326  mOrigin->SetElement( 2, 3, -pos[ 2 ] );
327 
328  // Translation matrix: to object position
329  vtkSmartPointer< vtkMatrix4x4 > mPosition = vtkSmartPointer< vtkMatrix4x4 >::New();
330  mPosition->Identity();
331  mPosition->SetElement( 0, 3, pos[ 0 ] );
332  mPosition->SetElement( 1, 3, pos[ 1 ] );
333  mPosition->SetElement( 2, 3, pos[ 2 ] );
334 
335  // Cross product
336  double zx = uz*vy - uy*vz;
337  double zy = ux*vz - uz*vx;
338  double zz = uy*vx - ux*vy;
339 
340  vtkSmartPointer< vtkMatrix4x4 > mViewUp = vtkSmartPointer< vtkMatrix4x4 >::New();
341  mViewUp->Identity();
342  mViewUp->SetElement( 0, 0, zx );
343  mViewUp->SetElement( 1, 0, zy );
344  mViewUp->SetElement( 2, 0, zz );
345  mViewUp->SetElement( 0, 1, ux );
346  mViewUp->SetElement( 1, 1, uy );
347  mViewUp->SetElement( 2, 1, uz );
348  mViewUp->SetElement( 0, 2, -vx );
349  mViewUp->SetElement( 1, 2, -vy );
350  mViewUp->SetElement( 2, 2, -vz );
351 
352  // Compose transforms
353  // (Order: Origin, Roll, Pitch, Yaw, Position)
354  vtkSmartPointer< vtkTransform > transform = vtkSmartPointer< vtkTransform >::New();
355  transform->Concatenate( mPosition );
356  transform->Concatenate( mViewUp );
357  transform->Concatenate( mOrigin );
358 
359  // Apply new transformation
361  m_pNodeAssembly->SetUserTransform( transform );
363 
364  return;
365  }
366 
367  void SGNode::GetOrientationVU( double& vx, double& vy, double& vz, double& ux, double& uy, double& uz )
368  {
369  vtkSmartPointer< vtkMatrix4x4 > pM = m_pNodeAssembly->GetUserMatrix();
370 
371  std::vector< double > vdView( 4 );
372  std::vector< double > vdDefaultView( 4 );
373  vdDefaultView[ 2 ] = -1.0f;
374  vdDefaultView[ 3 ] = 1.0f;
375  if( pM )
376  {
377  vdView[0] = *pM->MultiplyDoublePoint( &vdDefaultView[0] );
378  vx = vdView[ 0 ];
379  vy = vdView[ 1 ];
380  vz = vdView[ 2 ];
381  }
382  else
383  {
384  for( size_t i = 0; i < 4; i++ )
385  vdView[ i ] = vdDefaultView[ i ];
386  }
387 
388  std::vector< double > vdUp( 4 );
389  std::vector< double > vdDefaultUp( 4 );
390  vdDefaultUp[ 1 ] = vdDefaultUp[ 3 ] = 1.0f;
391  if( pM )
392  {
393  vdUp[0] = *pM->MultiplyDoublePoint( &vdDefaultUp[0] );
394  ux = vdUp[ 0 ];
395  uy = vdUp[ 1 ];
396  uz = vdUp[ 2 ];
397  }
398  else
399  {
400  for( size_t i = 0; i < 4; i++ )
401  vdUp[ i ] = vdDefaultUp[ i ];
402  }
403  }
404 
405  void SGNode::GetOrientationYPR( double& dYawDeg, double& dPitchDeg, double& dRollDeg )
406  {
407  double dEps = DAFF::EPSILON_D;
408  double dPi = DAFF::PI_D;
409 
410  double vx, vy, vz, ux, uy, uz, yaw, pitch, roll;
411  GetOrientationVU( vx, vy, vz, ux, uy, uz );
412 
413  if( vy >= ( 1 - dEps ) )
414  {
415  yaw = atan2( ux, uz );
416  pitch = dPi;
417  roll = 0;
418 
419  dYawDeg = DAFFUtils::rad2grad( yaw );
420  dPitchDeg = DAFFUtils::rad2grad( pitch );
421  dRollDeg = DAFFUtils::rad2grad( roll );
422 
423  return;
424  }
425 
426  if( vy <= -( 1 - dEps ) )
427  {
428  yaw = atan2( -ux, -uz );
429  pitch = -dPi;
430  roll = 0;
431 
432  dYawDeg = DAFFUtils::rad2grad( yaw );
433  dPitchDeg = DAFFUtils::rad2grad( pitch );
434  dRollDeg = DAFFUtils::rad2grad( roll );
435 
436  return;
437  }
438 
439  yaw = atan2( -vx, -vz );
440  pitch = asin( vy );
441 
442  double zy = vz*ux - vx*uz;
443 
444  if( ( uy <= dEps ) && ( uy >= -dEps ) ) {
445  // y-component of cross production v x u
446  double zy = vz*ux - vx*uz;
447  roll = ( zy <= 0 ? dPi: -dPi );
448 
449  dYawDeg = DAFFUtils::rad2grad( yaw );
450  dPitchDeg = DAFFUtils::rad2grad( pitch );
451  dRollDeg = DAFFUtils::rad2grad( roll );
452 
453  return;
454  }
455 
456  // Hint: cos(pitch) = cos( arcsin(vy) ) = sqrt(1-vy^2)
457  double cp = sqrt( 1 - vy*vy );
458  double uy_by_cp = uy / cp;
459  if( std::fabs( uy_by_cp - 1 ) < dEps )
460  roll = 0;
461  else
462  roll = ( zy <= 0 ? acos( uy_by_cp ) : -acos( uy_by_cp ) );
463 
464  dYawDeg = DAFFUtils::rad2grad( yaw );
465  dPitchDeg = DAFFUtils::rad2grad( pitch );
466  dRollDeg = DAFFUtils::rad2grad( roll );
467 
468  return;
469  }
470 
471  void SGNode::GetScale( double& sx, double& sy, double& sz ) const
472  {
473  double* data = m_pNodeAssembly->GetScale();
474  sx = data[ 0 ];
475  sy = data[ 1 ];
476  sz = data[ 2 ];
477  }
478 
479  void SGNode::SetScale( double sx, double sy, double sz )
480  {
482  m_pNodeAssembly->SetScale( sx, sy, sz );
484  }
485 
486  bool SGNode::IsVisible() const
487  {
488  return m_pNodeAssembly->GetVisibility() > 0 ? true : false;
489  }
490 
491  void SGNode::SetVisible( bool bVisible )
492  {
493  // Traverse the subtree, lock has to be applied in child nodes, so no lock here!
494  for( std::vector<SGNode*>::const_iterator cit = m_vpChildNodes.begin(); cit != m_vpChildNodes.end(); ++cit )
495  ( *cit )->SetVisible( bVisible );
496 
498  if( bVisible )
499  m_pNodeAssembly->VisibilityOn();
500  else
501  m_pNodeAssembly->VisibilityOff();
503  }
504 
505  void SGNode::AddActor( vtkSmartPointer< vtkActor > pActor )
506  {
507  assert( pActor != NULL );
508 
510  m_pNodeAssembly->AddPart( pActor );
512  }
513 
514  void SGNode::RemoveActor( vtkSmartPointer< vtkActor > pActor )
515  {
516  assert( pActor != NULL );
517 
519  m_pNodeAssembly->RemovePart( pActor );
520  //m_pNodeAssembly->
522  }
523 
524  void SGNode::AddAssembly( vtkSmartPointer< vtkAssembly > pAssembly )
525  {
526  assert( pAssembly != NULL );
527 
529  m_pNodeAssembly->AddPart( pAssembly );
531  }
532 
533  void SGNode::RemoveAssembly( vtkSmartPointer< vtkAssembly> pAssembly )
534  {
535  assert( pAssembly != NULL );
536 
538  m_pNodeAssembly->RemovePart( pAssembly );
540  }
541 
542  void SGNode::OnSetFollowerCamera( vtkSmartPointer< vtkCamera > pCamera )
543  {
544  // Lock has to be applied in child nodes, so no lock here!
545  for( std::vector<SGNode*>::const_iterator cit = m_vpChildNodes.begin(); cit != m_vpChildNodes.end(); ++cit )
546  ( *cit )->OnSetFollowerCamera( pCamera );
547  }
548 
549  vtkSmartPointer< vtkAssembly > SGNode::GetNodeAssembly()
550  {
551  return m_pNodeAssembly;
552  }
553 
554 } // End of namespace "DAFFViz"
void GetChildNodes(std::vector< const DAFFViz::SGNode * > &vpChildren) const
Returns all the pointers to the child nodes (for const correctness, clears vector if no childs availa...
void RemoveAssembly(vtkSmartPointer< vtkAssembly > pAssembly)
Release an assembly from the assembly of the node.
void AddActor(vtkSmartPointer< vtkActor > pActor)
Add a VTK actor to the node.
void SetPosition(double x, double y, double z)
Position getter (unit is meter)
bool AddChildNode(DAFFViz::SGNode *pChild)
Appends a single child node.
void SetScale(double sx, double sy, double sz)
Scale setter.
void SetOrientation(double dRotXDeg, double dRotYDeg, double dRotZDeg)
Sets the orientation of the node assembly based on world coordinate axis (angles in [°]) ...
void SetOrientationYPR(double dYawDeg, double dPitchDeg, double dRollDeg)
Sets the orientation of the node assembly based on yaw, pitch and roll angles around own coordinate a...
void RemoveActor(vtkSmartPointer< vtkActor > pActor)
Remove a VTK actor from the assembly of the node.
void SetOrientationVU(double vx, double vy, double vz, double ux, double uy, double uz)
Sets the orientation of the node assembly based on view- and up-vectors.
void AddAssembly(vtkSmartPointer< vtkAssembly > pAssembly)
Add a VTK assembly to the node.
#define DAFFVIZ_LOCK_VTK
virtual void OnSetFollowerCamera(vtkSmartPointer< vtkCamera > pCamera)
Set active camera for followers.
bool RemoveChildNodes(const std::vector< DAFFViz::SGNode * > &vpChildren)
Removes a vector of child nodes.
#define NULL
Definition: DAFFDefs.h:59
DAFFViz::SGNode * GetRootNode() const
Traverses up to the root (recursively) and returns the node pointer.
bool HasParentNode() const
Returns true if the node is appended to a parent node.
bool HasChildNodes() const
Returns true if the node combines one or more child nodes.
virtual void SetVisible(bool bVisible)
Set visibility.
void GetPosition(double &x, double &y, double &z) const
Position setter (unit is meter)
Base class for scene graph nodes.
Definition: DAFFVizSGNode.h:67
bool RemoveChildNode(DAFFViz::SGNode *pChild)
Removes a single child node.
void GetOrientation(double &dRotXDeg, double &dRotYDeg, double &dRotZDeg) const
Orientation getter (angles in [°])
void GetOrientationYPR(double &dYawDeg, double &dPitchDeg, double &dRollDeg)
Orientation getter of the node assembly based on yaw, pitch and roll angles around own coordinate axi...
const DAFFViz::SGNode * GetChildNode(int iIndex) const
Returns the pointer to the child node of given index (for const correctness)
void GetOrientationVU(double &vx, double &vy, double &vz, double &ux, double &uy, double &uz)
Returns the orientation of the node assembly based on view- and up-vectors.
static double rad2grad(double phi)
Definition: DAFFUtils.h:114
DAFFViz::SGNode * GetParentNode() const
Returns the parent node pointer.
bool AddChildNodes(const std::vector< DAFFViz::SGNode * > &vpChildren)
Appends a vector child nodes.
#define DAFFVIZ_UNLOCK_VTK
void GetScale(double &sx, double &sy, double &sz) const
Scale getter.
static double grad2rad(double phi)
Definition: DAFFUtils.h:109
SGNode(DAFFViz::SGNode *pParentNode=NULL)
Constructor with optional linking to a parent node.
bool IsLeaf() const
Returns true if the node appears as a leaf node (... has no child nodes)
virtual ~SGNode()
Destructor.
bool IsRoot() const
Returns true if the node is a root node (... has no parent node)
virtual bool IsVisible() const
Returns true if the node is visible.
OpenDAFF is a project from the Institute of Technical Acoustics, RWTH Aachen University, Germany.