OpenDAFF C++ API  v1.7
Directional Audio File Format
DAFFVizCarpetPlot.cpp
Go to the documentation of this file.
2 
4 
5 // Todo: strip required
6 #include <vtkActor.h>
7 #include <vtkCellArray.h>
8 #include <vtkCellData.h>
9 #include <vtkContourFilter.h>
10 #include <vtkDoubleArray.h>
11 #include <vtkFloatArray.h>
12 #include <vtkFollower.h>
13 #include <vtkHedgeHog.h>
14 #include <vtkLine.h>
15 #include <vtkLookupTable.h>
16 #include <vtkPointData.h>
17 #include <vtkPoints.h>
18 #include <vtkPolyData.h>
19 #include <vtkPolyDataMapper.h>
20 #include <vtkPolyDataNormals.h>
21 #include <vtkPolyLine.h>
22 #include <vtkProperty.h>
23 #include <vtkScalarBarActor.h>
24 #include <vtkVectorText.h>
25 #include <vtkWarpScalar.h>
26 
27 #include <vtkWindowedSincPolyDataFilter.h>
28 
29 #include <DAFF.h>
30 
31 #include <algorithm>
32 #include <assert.h>
33 
34 namespace DAFFViz
35 {
37  : SGNode()
38  , m_pContentIR( pContentIR )
39  , m_fAngle( 0.0f )
40  , m_iScaling( SCALING_LINEAR )
41  , m_dMin( -1.0 )
42  , m_dMax( 1.0 )
43  , m_iFixedAngle( 0 )
44  , m_pCarpetPolyData( 0 )
45  , m_pCarpetMapper( 0 )
46  , m_pWarp( 0 )
47  , m_pCarpetActor( 0 )
48  , m_iChannel( 0 )
49  , m_bWarp( true )
50  , m_pProbe( 0 )
51  , m_pLabel( 0 )
52  , m_dProbeX( 0 )
53  , m_dProbeY( 0 )
54  {
55  Init();
56  }
57 
58  CarpetPlot::CarpetPlot( SGNode* pParent, const DAFFContentIR* pContentIR )
59  : SGNode( pParent )
60  , m_pContentIR( pContentIR )
61  , m_fAngle( 0.0f )
62  , m_iScaling( SCALING_LINEAR )
63  , m_dMin( -1.0 )
64  , m_dMax( 1.0 )
65  , m_iFixedAngle( 0 )
66  , m_pCarpetPolyData( 0 )
67  , m_pCarpetMapper( 0 )
68  , m_pWarp( 0 )
69  , m_pCarpetActor( 0 )
70  , m_iChannel( 0 )
71  , m_bWarp( true )
72  , m_pProbe( 0 )
73  , m_pLabel( 0 )
74  , m_dProbeX( 0 )
75  , m_dProbeY( 0 )
76  {
77  Init();
78  }
79 
80  void CarpetPlot::Init()
81  {
82  if( m_pContentIR == nullptr )
83  return;
84 
85  // Carpet mesh
86  m_pCarpetPolyData = vtkSmartPointer< vtkPolyData >::New();
87  InitCarpetMesh();
88 
89  // Carpet mapper
90  m_pCarpetMapper = vtkSmartPointer< vtkPolyDataMapper >::New();
91 
92  // create a default lookup table and invert it, so that high values have red color
93  vtkSmartPointer< vtkLookupTable > lut = vtkSmartPointer< vtkLookupTable>::New();
94  vtkSmartPointer< vtkLookupTable > refLut = vtkSmartPointer< vtkLookupTable >::New();
95  lut->Build();
96  refLut->Build();
97 
98  for( int i = 0; i < 256; i++ )
99  lut->SetTableValue( i, refLut->GetTableValue( 255 - i ) );
100 
101  m_pCarpetMapper->SetLookupTable( lut );
102 
103  // Carpet warping (3D visualizatiion)
104 
105  /*
106  vtkSmartPointer< vtkPolyDataNormals > normals = vtkSmartPointer< vtkPolyDataNormals >::New();
107  normals->SetInputData( m_pPlotPolydata );
108  int iCNs = normals->GetComputePointNormals();
109  */
110 
111  m_pWarp = vtkSmartPointer< vtkWarpScalar >::New();
112  m_pWarp->SetInputData( m_pCarpetPolyData );
113  //m_pWarp->SetInputData( normals->GetOutput() );
114  m_pWarp->UseNormalOff();
115  m_pWarp->Update();
116 
117  m_pCarpetMapper->SetInputConnection( m_pWarp->GetOutputPort() );
118 
119  // Carpet actor
120 
121  m_pCarpetActor = vtkSmartPointer< vtkActor >::New();
122  m_pCarpetActor->SetMapper( m_pCarpetMapper );
123  m_pCarpetActor->GetProperty()->SetInterpolationToPhong();
124  m_pCarpetActor->RotateX( -90 );
125  m_pCarpetActor->RotateZ( 180 );
126 
127  AddActor( m_pCarpetActor );
128 
129 
130  /* Probe
131 
132  vtkSmartPointer< vtkPoints > pointsProbe = vtkSmartPointer< vtkPoints >::New();
133  pointsProbe->SetNumberOfPoints( 2 );
134  pointsProbe->InsertPoint( 0, 0, 0, 0 );
135  pointsProbe->InsertPoint( 1, 0, 1, 0 );
136 
137  vtkSmartPointer< vtkCellArray > cellsProbe = vtkSmartPointer< vtkCellArray >::New();
138  vtkSmartPointer< vtkLine > line = vtkSmartPointer< vtkLine >::New();
139  line->GetPointIds()->SetId(0,0);
140  line->GetPointIds()->SetId(1,1);
141  cellsProbe->InsertNextCell( line );
142 
143  vtkSmartPointer< vtkPolyData > polydata = vtkSmartPointer< vtkPolyData >::New();
144  polydata->SetPoints( pointsProbe );
145  polydata->SetLines( cellsProbe );
146 
147  // Create a mapper and actor
148  vtkSmartPointer< vtkPolyDataMapper > mapper = vtkSmartPointer< vtkPolyDataMapper >::New();
149  mapper->SetInputData(polydata);
150 
151  m_pProbe = vtkSmartPointer< vtkActor >::New();
152  m_pProbe->SetMapper(mapper);
153  m_pProbe->VisibilityOff();
154 
155  AddActor( m_pProbe );
156 
157  // label the probe
158  m_pProbeLabel = vtkSmartPointer< vtkVectorText >::New();
159  std::ostringstream s;
160  s << "test";
161  m_pProbeLabel->SetText( s.str().c_str() );
162 
163  vtkSmartPointer< vtkPolyDataMapper > mapper2 = vtkSmartPointer< vtkPolyDataMapper >::New();
164  mapper2->AddInputConnection( m_pProbeLabel->GetOutputPort() );
165 
166  m_pLabel = vtkSmartPointer< vtkFollower >::New();
167  m_pLabel->SetMapper(mapper2);
168  m_pLabel->SetScale(0.03);
169  m_pLabel->SetPosition(0.00, 1.01, 0);
170  m_pLabel->GetProperty()->SetOpacity(0.8);
171  m_pLabel->VisibilityOff();
172 
173  AddActor( m_pLabel );
174  */
175  }
176 
178  {
179  RemoveActor( m_pCarpetActor );
180  //RemoveActor( m_pLabel );
181  //RemoveActor( m_pProbe );
182  }
183 
184  void CarpetPlot::InitCarpetMesh()
185  {
186  const DAFFProperties* pProps = m_pContentIR->getProperties();
187 
188  // --= carpet grid points and faces =--
189 
190  int iNumPointsX, iIndexMaxX;
191  if( m_iFixedAngle == BETA_FIXED )
192  {
193  iNumPointsX = pProps->getAlphaPoints();
194  if( pProps->coversFullAlphaRange() )
195  iIndexMaxX = iNumPointsX + 1; // when we cover full sphere, the last row equals the first one
196  else
197  iIndexMaxX = iNumPointsX;
198  }
199  else
200  {
201  iNumPointsX = pProps->getBetaPoints();
202  iIndexMaxX = iNumPointsX;
203  }
204 
205  int iNumPointsY = m_pContentIR->getFilterLength();
206 
207  vtkIdType quadface[ 4 ];
208  vtkSmartPointer< vtkPoints > points = vtkSmartPointer< vtkPoints >::New();
209  vtkSmartPointer< vtkCellArray > cells = vtkSmartPointer< vtkCellArray >::New();
210  for( int i = 0; i < iIndexMaxX; i++ )
211  {
212  for( int j = 0; j < iNumPointsY; j++ )
213  {
214  if( ( i != iIndexMaxX - 1 ) && ( j != iNumPointsY - 1 ) )
215  { // every time except from first and last row/column
216  quadface[ 0 ] = ( i + 1 )*iNumPointsY + j + 1;
217  quadface[ 1 ] = ( i + 1 )*iNumPointsY + j;
218  quadface[ 2 ] = ( i ) *iNumPointsY + j;
219  quadface[ 3 ] = ( i ) *iNumPointsY + j + 1;
220  for( int k = 0; k < 4; k++ )
221  assert( ( quadface[ k ] >= 0 ) && ( quadface[ k ] < iIndexMaxX*iNumPointsY ) );
222  cells->InsertNextCell( 4, quadface );
223  }
224  vtkIdType iPointiD = i*iNumPointsY + j;
225  double dX = 2.0f * double( i ) / double( iNumPointsX ) - 1.0f;
226  double dY = 2.0f * double( j ) / double( iNumPointsY ) - 1.0f;
227  double dZ = 0.0f;
228  points->InsertPoint( iPointiD, dX, dY, dZ );
229  }
230  }
231 
232  m_pCarpetPolyData->SetPoints( points );
233  m_pCarpetPolyData->SetPolys( cells );
234 
235  SetScalars();
236  }
237 
239  {
240  if( !m_pProbe )
241  return;
242 
243  // Apply new transformation
244  assert( m_pContentIR != 0 );
245  double val=0;
246  int i;
247  std::ostringstream s;
248  float fMag;
249  int iOffs=0, iLen=m_pContentIR->getFilterLength();
250  float* pBuf=0;
251  float dPosX=0, dPosY=0, dPosZ=0; // X := not fixed angle, Y := time
252  dPosY = 2*m_dProbeY/iLen - 1;
253  if (m_iScaling == SCALING_LINEAR) // else dPosZ=0
254  dPosZ = (m_dMin)/(m_dMax-m_dMin);
255  if (m_iFixedAngle==BETA_FIXED) {
256  dPosX = 2*m_dProbeX/m_pContentIR->getProperties()->getBetaSpan() - 1;
257  m_pContentIR->getNearestNeighbour(DAFF_DATA_VIEW, m_dProbeX, m_fAngle, i);
258  } else {
259  dPosX = 2*m_dProbeX/m_pContentIR->getProperties()->getAlphaSpan() - 1;
260  m_pContentIR->getNearestNeighbour(DAFF_DATA_VIEW, m_fAngle, m_dProbeX, i);
261  }
262 
263  m_pProbe->SetPosition(dPosX, dPosZ, dPosY);
264  m_pLabel->SetPosition(dPosX, dPosZ+1.01, dPosY);
265 
266  // update label
267  pBuf = new float[iLen];
268  m_pContentIR->getFilterCoeffs(i, m_iChannel, pBuf);
269  fMag = pBuf[(int)m_dProbeY];
270 
271  if( m_iScaling == SCALING_DECIBEL || false )
272  {
273  fMag = factor2decibel( ( double ) fabs( fMag ) );
274  s << fMag << "db";
275  } else
276  s << fMag;
277 
278  m_pProbeLabel->SetText(s.str().c_str());
279 
280  return;
281  }
282 
283  void CarpetPlot::SetProbeAngles( double dX, double dY )
284  {
285  m_dProbeX = dX;
286  m_dProbeY = dY;
287  }
288 
289  void CarpetPlot::SetProbeVisible( bool bVisible )
290  {
291  m_pProbe->SetVisibility(bVisible);
292  m_pLabel->SetVisibility(bVisible);
293  }
294 
295  void CarpetPlot::SetSelectedAngle( float fAngle )
296  {
297  m_fAngle = fAngle;
298  SetScalars();
299 
300  return;
301  }
302 
304  {
305  return m_fAngle;
306  }
307 
308  void CarpetPlot::SetScaling( int iScaling )
309  {
310  m_iScaling = iScaling;
311  SetScalars();
312 
313  return;
314  }
315 
317  return m_iScaling;
318  }
319 
320  void CarpetPlot::SetFixedAngle( int iFixedAngle )
321  {
322  m_iFixedAngle = iFixedAngle;
323 
324  InitCarpetMesh();
325  }
326 
328  return m_iFixedAngle;
329  }
330 
331  void CarpetPlot::SetRange( double dMin, double dMax )
332  {
333  assert( m_pContentIR != NULL);
334  assert( dMin < dMax );
335  if( m_iScaling == SCALING_LINEAR )
336  {
337  // Convert from linear to decibel
338  m_dMin = dMin;
339  m_dMax = dMax;
340  }
341  else
342  {
343  m_dMin = decibel2factor( dMin );
344  m_dMax = decibel2factor( dMax );
345  }
346  SetScalars();
347  }
348 
349  void CarpetPlot::SetScalarVisibility( bool bVisible )
350  {
351  m_pCarpetMapper->SetScalarVisibility( bVisible );
352  }
353 
355  {
356  return m_pCarpetMapper->GetScalarVisibility();
357  }
358 
359  double CarpetPlot::GetRangeMin() const
360  {
361  if( m_iScaling == SCALING_LINEAR )
362  {
363  return m_dMin;
364  }
365  else
366  if( m_dMin < 0 )
367  return -100;
368  else
369  return factor2decibel( m_dMin );
370  }
371 
372  double CarpetPlot::GetRangeMax() const
373  {
374  if( m_iScaling == SCALING_LINEAR )
375  return m_dMax;
376  else
377  return factor2decibel(m_dMax);
378  }
379 
380  void CarpetPlot::SetWarpingEnabled( bool bEnabled )
381  {
382  m_bWarp = bEnabled;
383  if( m_bWarp )
384  m_pCarpetMapper->SetInputConnection( m_pWarp->GetOutputPort() );
385  else
386  m_pCarpetMapper->SetInputData( m_pCarpetPolyData );
387 
388  updatePlotOffset();
389  }
390 
392  {
393  SetWarpingEnabled( true );
394  }
395 
397  {
398  SetWarpingEnabled( false );
399  }
400 
401  void CarpetPlot::updatePlotOffset()
402  {
403  if( m_pCarpetActor )
404  if( m_bWarp )
405  if( ( m_iScaling == SCALING_LINEAR ) && ( ( m_dMin < 0 ) && ( m_dMax > 0 ) ) )
406  m_pCarpetActor->SetPosition( 0, m_dMin / ( m_dMax - m_dMin ), 0 );
407  else if( m_iScaling == SCALING_DECIBEL )
408  m_pCarpetActor->SetPosition( 0, 0, 0 );
409  else
410  m_pCarpetActor->SetPosition( 0, 0, 0 );
411  else
412  m_pCarpetActor->SetPosition( 0, 0, 0 );
413  }
414 
415 
416  void CarpetPlot::SetScalars()
417  {
418  //TODO: asserts
419  assert( m_pContentIR != NULL);
420  assert( m_dMin < m_dMax );
421 
422  vtkSmartPointer< vtkFloatArray > pIRWarpArray = vtkSmartPointer< vtkFloatArray >::New();
423  pIRWarpArray->SetName( "DAFFIRWarpData" );
424  std::vector< float > vCoeffs( m_pContentIR->getFilterLength() );
425  if( m_iFixedAngle == BETA_FIXED )
426  {
427  int iNumPoints = m_pContentIR->getProperties()->getAlphaPoints();
428  float fStart = m_pContentIR->getProperties()->getAlphaStart();
429  float fRange = m_pContentIR->getProperties()->getAlphaEnd() - fStart;
430  for( int i = 0; i <= iNumPoints; i++ )
431  {
432  // Pull filter coefficients
433  int index=0;
434  m_pContentIR->getNearestNeighbour( DAFF_DATA_VIEW, ( float ) i / ( float ) iNumPoints*fRange + fStart, m_fAngle, index );
435  m_pContentIR->getFilterCoeffs( index, m_iChannel, &vCoeffs[0] );
436  float coeff=0.0f;
437  for( int j = 0; j < m_pContentIR->getFilterLength(); j++ )
438  {
439  coeff = vCoeffs[j];
440 
441  // Check weather decibel scaling is activated
442  if( m_iScaling == SCALING_DECIBEL )
443  {
444  // CAVE: we take absolut value instead of square
445  coeff = ( float ) factor2decibel( ( double ) fabs( coeff ) );
446 
447  // Decibel boundaries
448  float DECIBEL_LOWER = -100;
449  if( m_dMin >= 0 )
450  DECIBEL_LOWER = factor2decibel( m_dMin );
451  float DECIBEL_UPPER = factor2decibel( m_dMax );
452 
453  // Normalize the range into the interval [0,1]
454  // Limit the boundaries
455  coeff = std::max(coeff, DECIBEL_LOWER);
456  coeff = std::min(coeff, DECIBEL_UPPER);
457  // clamp to [0 1]
458  coeff = 1.0 / ( DECIBEL_UPPER - DECIBEL_LOWER )*coeff + DECIBEL_LOWER / ( DECIBEL_LOWER - DECIBEL_UPPER );
459  }
460  else
461  {
462  // Limit the boundaries
463  coeff = std::max( coeff, m_dMin );
464  coeff = std::min( coeff, m_dMax );
465  // clamp to [0 1]
466  coeff = ( coeff - m_dMin ) / ( m_dMax - m_dMin );
467  }
468  // store value in array
469  pIRWarpArray->InsertNextTuple1( coeff );
470  }
471  }
472  }
473  else
474  {
475  int iNumPoints = m_pContentIR->getProperties()->getBetaPoints();
476  float fStart = m_pContentIR->getProperties()->getBetaStart();
477  float fRange = m_pContentIR->getProperties()->getBetaEnd() - fStart;
478  for( int i = 0; i < m_pContentIR->getProperties()->getBetaPoints(); i++ )
479  {
480  // Pull filter coefficients
481  int index=0;
482  m_pContentIR->getNearestNeighbour( DAFF_DATA_VIEW, m_fAngle, ( float ) i / ( float ) iNumPoints*fRange + fStart, index );
483  m_pContentIR->getFilterCoeffs( index, m_iChannel, &vCoeffs[ 0 ] );
484  float coeff=0.0f;
485  for( int j = 0; j < m_pContentIR->getFilterLength(); j++ )
486  {
487  coeff = vCoeffs[j];
488 
489  // Check weather decibel scaling is activated
490  if( m_iScaling == SCALING_DECIBEL )
491  {
492  // CAVE: we take absolut value instead of square
493  coeff = ( float ) factor2decibel( ( double ) fabs( coeff ) );
494 
495  // Decibel boundaries
496  float DECIBEL_LOWER = -100;
497  if( m_dMin >= 0 )
498  DECIBEL_LOWER = factor2decibel( m_dMin );
499  float DECIBEL_UPPER = factor2decibel( m_dMax );
500 
501  // Normalize the range into the interval [0,1]
502  // Limit the boundaries
503  coeff = std::max( coeff, DECIBEL_LOWER );
504  coeff = std::min( coeff, DECIBEL_UPPER );
505  // clamp to [0 1]
506  coeff = 1.0/(DECIBEL_UPPER-DECIBEL_LOWER)*coeff + DECIBEL_LOWER/(DECIBEL_LOWER-DECIBEL_UPPER);
507  }
508  else
509  {
510  // Limit the boundaries
511  coeff = std::max( coeff, m_dMin );
512  coeff = std::min( coeff, m_dMax );
513  // clamp to [0 1]
514  coeff = ( coeff - m_dMin ) / ( m_dMax - m_dMin );
515  }
516  // store value in array
517  pIRWarpArray->InsertNextTuple1( coeff );
518  }
519  }
520  }
521 
522  // Assign scalars to points
523  m_pCarpetPolyData->GetPointData()->SetScalars( pIRWarpArray );
524 
525  // move plot down so it fits to the axes
526  updatePlotOffset();
527  UpdateProbe();
528 
529  return;
530  }
531 
532  double CarpetPlot::factor2decibel( double x ) const
533  {
534  assert( x >= 0 );
535  // Lower boundary is -100 dB
536  if( x <= 0.0000000001 ) return -100;
537  return 10 * log( x ) / log( ( double ) 10 );
538  }
539 
540  double CarpetPlot::decibel2factor( double x ) const
541  {
542  return pow( 10.0, .1*x );
543  }
544 
545  void CarpetPlot::SetDisplayMode( int iMode )
546  {
547  if( iMode == MODE_SURFACE )
548  m_pCarpetActor->GetProperty()->SetRepresentationToSurface();
549  else if( iMode == MODE_WIREFRAME )
550  m_pCarpetActor->GetProperty()->SetRepresentationToWireframe();
551  else if( iMode == MODE_POINT )
552  m_pCarpetActor->GetProperty()->SetRepresentationToPoints();
553  }
554 
555  void CarpetPlot::SetChannel( int iChannel )
556  {
557  m_iChannel = iChannel;
558  SetScalars();
559  }
560 
562  {
563  return m_iChannel;
564  }
565 
566 } // End of namespace "DAFFViz"
void AddActor(vtkSmartPointer< vtkActor > pActor)
Add a VTK actor to the node.
int getScalarVisibility()
Get whether scalars should be used to color the model.
int GetChannel()
get active channel
int GetScaling() const
Get scaling (SCALING_LINEAR | SCALING_DECIBEL)
void RemoveActor(vtkSmartPointer< vtkActor > pActor)
Remove a VTK actor from the assembly of the node.
virtual void getNearestNeighbour(int iView, float fAngle1Deg, float fAngle2Deg, int &iRecordIndex) const =0
Determine the nearest neighbour record and return its index.
void SetScalarVisibility(bool bVisible)
Set whether scalars should be used to color the model.
void SetProbeAngles(double dAlpha, double dBeta)
Set probe angles.
virtual float getAlphaStart() const =0
#define NULL
Definition: DAFFDefs.h:59
void SetDisplayMode(int iMode)
Set display mode (MODE_SURFACE | MODE_WIREFRAME | MODE_POINT)
virtual int getFilterLength() const =0
Returns the number of filter coefficients.
virtual float getBetaEnd() const =0
float GetSelectedAngle() const
Returns the currently selected angle in degree (interval [-90° 90°])
virtual float getBetaStart() const =0
virtual float getBetaSpan() const =0
virtual int getAlphaPoints() const =0
Base class for scene graph nodes.
Definition: DAFFVizSGNode.h:67
virtual int getFilterCoeffs(int iRecordIndex, int iChannel, float *pfDest, float fGain=1.0F) const =0
Retrieves filter coefficients for record and channel.
void SetFixedAngle(int iFixedAngle)
Set fixed angle (ALPHA_FIXED | BETA_FIXED)
double GetRangeMin() const
Set minimum of data range (in dB or absolute values depending on currently used scaling) ...
void SetRange(double dMin, double dMax)
Set data range (in dB or absolute values depending on currently used scaling)
void SetChannel(int iChannel)
Set active channel.
virtual const DAFFProperties * getProperties() const =0
Returns the properties.
int getFixedAngle()
Get fixed angle (ALPHA_FIXED | BETA_FIXED)
Impulse response content interface.
Definition: DAFFContentIR.h:38
void SetProbeVisible(bool bVisible)
Enables/disables probe.
void UpdateProbe()
Update probe nodes.
void SetWarpingEnabled(bool bEnabled)
virtual float getAlphaEnd() const =0
virtual float getAlphaSpan() const =0
double GetRangeMax() const
Set minimum of data range (in dB or absolute values depending on currently used scaling) ...
virtual int getBetaPoints() const =0
Properties of a DAFF file that uses regular sphere grids (or parts of a regular grid) ...
void SetScaling(int iScaling)
Set scaling (SCALING_LINEAR | SCALING_DECIBEL)
void EnableWarp()
Enable/Disable warping (WARP_DISABLE | WARP_ENABLE)
CarpetPlot(SGNode *pParent, const DAFFContentIR *pContentIR)
void SetSelectedAngle(float fAngle)
Sets the currently selected angle in degree.
Data-related view referring to data spherical coordinates (DSC)
Definition: DAFFDefs.h:86
virtual bool coversFullAlphaRange() const =0
Indicates whether the data covers the full alpha range [0°, 360°)
OpenDAFF is a project from the Institute of Technical Acoustics, RWTH Aachen University, Germany.