vtkPolarAxesActor.cxx 26.9 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
/*=========================================================================

  Program:   Visualization Toolkit
  Module:    vtkPolarAxesActor.cxx

  Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
  All rights reserved.
  See Copyright.txt or http://www.kitware.com/Copyright.htm 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 notice for more information.

 =========================================================================*/
#include "vtkPolarAxesActor.h"

17
#include "vtkArcSource.h"
18
19
20
#include "vtkAxisActor.h"
#include "vtkAxisFollower.h"
#include "vtkCamera.h"
21
#include "vtkCellArray.h"
22
23
24
25
#include "vtkCoordinate.h"
#include "vtkFollower.h"
#include "vtkMath.h"
#include "vtkObjectFactory.h"
26
27
#include "vtkPolyData.h"
#include "vtkPolyDataMapper.h"
28
29
#include "vtkProperty.h"
#include "vtkStringArray.h"
30
#include "vtkTextProperty.h"
31
32
#include "vtkViewport.h"

33
#include <vtksys/ios/sstream>
34

35
#define VTK_POLAR_AXES_ACTOR_RTOL ( 1. - 10. * VTK_DBL_EPSILON )
36

37
38
vtkStandardNewMacro(vtkPolarAxesActor);
vtkCxxSetObjectMacro(vtkPolarAxesActor, Camera,vtkCamera);
39
40
vtkCxxSetObjectMacro(vtkPolarAxesActor,PolarAxisLabelTextProperty,vtkTextProperty);
vtkCxxSetObjectMacro(vtkPolarAxesActor,PolarAxisTitleTextProperty,vtkTextProperty);
41

Aashish Chaudhary's avatar
Aashish Chaudhary committed
42
//-----------------------------------------------------------------------------
Philippe Pébay's avatar
Philippe Pébay committed
43
void vtkPolarAxesActor::PrintSelf( ostream& os, vtkIndent indent )
44
{
Philippe Pébay's avatar
Philippe Pébay committed
45
  this->Superclass::PrintSelf( os,indent );
46

47
48
  os << indent << "Bounds: \n";
  os << indent << "  Xmin,Xmax: (" << this->Bounds[0] << ", "
49
     << this->Bounds[1] << " )\n";
50
  os << indent << "  Ymin,Ymax: (" << this->Bounds[2] << ", "
51
     << this->Bounds[3] << " )\n";
52
  os << indent << "  Zmin,Zmax: (" << this->Bounds[4] << ", "
53
     << this->Bounds[5] << " )\n";
54

Philippe Pébay's avatar
Philippe Pébay committed
55
56
  os << indent << "ScreenSize: (" << this->ScreenSize << ")\n";

57
  os << indent << "Number Of Radial Axes" << this->NumberOfRadialAxes << endl;
58
59
60
  os << indent << "Number Of Polar Axis Ticks" << this->NumberOfPolarAxisTicks << endl;
  os << indent << "Auto Subdivide Polar Axis: "
     << ( this->AutoSubdividePolarAxis ? "On\n" : "Off\n" );
61

Aashish Chaudhary's avatar
Aashish Chaudhary committed
62
  os << indent << "Pole: ("
63
64
     << this->Pole[0] << ", "
     << this->Pole[1] << ", "
65
     << this->Pole[2] << " )\n";
66

67
  os << indent << "Maximum Radius" << this->MaximumRadius << endl;
68
  os << indent << "Auto-Scale Radius" << this->AutoScaleRadius << endl;
69
  os << indent << "Minimum Angle" << this->MinimumAngle << endl;
70
  os << indent << "Maximum Angle" << this->MaximumAngle << endl;
71
  os << indent << "Smallest Visible Polar Angle" << this->SmallestVisiblePolarAngle << endl;
Philippe Pébay's avatar
Philippe Pébay committed
72
73
  os << indent << "Radial Units (degrees): "
     << ( this->RadialUnits ? "On\n" : "Off\n" ) << endl;
74

Philippe Pébay's avatar
Philippe Pébay committed
75
  if ( this->Camera )
76
77
    {
    os << indent << "Camera:\n";
Philippe Pébay's avatar
Philippe Pébay committed
78
    this->Camera->PrintSelf( os,indent.GetNextIndent() );
79
80
81
82
83
84
    }
  else
    {
    os << indent << "Camera: (none)\n";
    }

Philippe Pébay's avatar
Philippe Pébay committed
85
86
87
88
  os << indent << "EnableDistanceLOD: "   
     << ( this->EnableDistanceLOD ? "On" : "Off" ) << endl;
  os << indent << "DistanceLODThreshold: ("   << this->DistanceLODThreshold    << ")\n";

89
90
91
92
  os << indent << "EnableViewAngleLOD: "   
     << ( this->EnableViewAngleLOD ? "On" : "Off" ) << endl;
  os << indent << "ViewAngleLODThreshold: ("   << this->ViewAngleLODThreshold    << ")\n";

Philippe Pébay's avatar
Philippe Pébay committed
93
  os << indent << "Polar Axis Title: " << this->PolarAxisTitle << "\n";
94
  os << indent << "Polar Label Format: " << this->PolarLabelFormat << "\n";
Philippe Pébay's avatar
Philippe Pébay committed
95
96
  os << indent << "PolarAxisLabelTextProperty: " << this->PolarAxisLabelTextProperty << endl;
  os << indent << "PolarAxisTitleTextProperty: " << this->PolarAxisTitleTextProperty << endl;
97
98
99
100
101
102
103
104
  os << indent << "Polar Axis Visibility: "
     << ( this->PolarAxisVisibility ? "On\n" : "Off\n" );
  os << indent << "Polar Title Visibility: "
     << ( this->PolarTitleVisibility ? "On" : "Off" ) << endl;
  os << indent << "Polar Label Visibility: "
     << ( this->PolarLabelVisibility ? "On" : "Off" ) << endl;
  os << indent << "Polar Tick Visibility: "
     << ( this->PolarTickVisibility ? "On" : "Off" ) << endl;
105
106

  os << indent << "Radial Axes Visibility: "
107
     << ( this->RadialAxesVisibility ? "On\n" : "Off\n" );
108
109
  os << indent << "Radial Title Visibility: "
     << ( this->RadialTitleVisibility ? "On" : "Off" ) << endl;
110

111

112
113
  os << indent << "Polar Arcs Visibility: "
     << ( this->PolarArcsVisibility ? "On" : "Off" ) << endl;
114
115
}

Aashish Chaudhary's avatar
Aashish Chaudhary committed
116
//-----------------------------------------------------------------------------
117
118
vtkPolarAxesActor::vtkPolarAxesActor() : vtkActor()
{
119
120
121
122
123
  // Default bounds
  this->Bounds[0] = -1.0; this->Bounds[1] = 1.0;
  this->Bounds[2] = -1.0; this->Bounds[3] = 1.0;
  this->Bounds[4] = -1.0; this->Bounds[5] = 1.0;

124
  // Default pole coordinates
125
126
127
  this->Pole[0] = VTK_DOUBLE_MAX;
  this->Pole[1] = VTK_DOUBLE_MAX;
  this->Pole[2] = VTK_DOUBLE_MAX;
128

129
  // Default number of radial axes
130
  this->NumberOfRadialAxes = VTK_MAXIMUM_NUMBER_OF_RADIAL_AXES;
131

132
133
134
135
  // Invalid default number of polar arcs, and auto-calculate by default
  this->NumberOfPolarAxisTicks = -1;
  this->AutoSubdividePolarAxis = true;

136
137
138
  // Default maximum polar radius
  this->MaximumRadius = VTK_DOUBLE_MAX;

139
140
141
  // Do not auto-scale radius by default
  this->AutoScaleRadius = false;

142
143
144
  // Default minimum polar angle
  this->MinimumAngle = 0.;

145
146
147
  // Default maximum polar angle
  this->MaximumAngle = VTK_DEFAULT_MAXIMUM_POLAR_ANGLE;

148
149
150
  // Default smallest radial angle distinguishable from polar axis
  this->SmallestVisiblePolarAngle = .5;

151
  // By default show angle units (degrees)
152
  this->RadialUnits = true;
153
154
155

  this->Camera = NULL;

156
  // Default text screen size
157
158
  this->ScreenSize = 10.0;

159
160
  // Screen offset for labels
  // Pivot point at center of the geometry hence this->ScreenSize * 0.5
Philippe Pébay's avatar
Philippe Pébay committed
161
  this->LabelScreenOffset = 15.0 + this->ScreenSize * 0.5;
162

163
  // Text properties of polar axis title and labels, with default color white
164
165
166
  // Properties of the radial axes, with default color black
  this->PolarAxisProperty = vtkProperty::New();
  this->PolarAxisProperty->SetColor( 0., 0., 0. );
Philippe Pébay's avatar
Philippe Pébay committed
167
  this->PolarAxisTitleTextProperty = vtkTextProperty::New();
168
  this->PolarAxisTitleTextProperty->SetColor( 1., 1. ,1. );
Philippe Pébay's avatar
Philippe Pébay committed
169
170
  this->PolarAxisTitleTextProperty->SetFontFamilyToArial();
  this->PolarAxisLabelTextProperty = vtkTextProperty::New();
171
  this->PolarAxisLabelTextProperty->SetColor( 1., 1. ,1. );
Philippe Pébay's avatar
Philippe Pébay committed
172
173
  this->PolarAxisLabelTextProperty->SetFontFamilyToArial();

174
175
176
177
178
179
180
181
182
183
  // Create and set polar axis of type X
  this->PolarAxis = vtkAxisActor::New();
  this->PolarAxis->SetAxisTypeToX();
  this->PolarAxis->SetAxisPositionToMinMax();
  this->PolarAxis->SetCalculateTitleOffset( 0 );
  this->PolarAxis->SetCalculateLabelOffset( 0 );

  // Base offset for followers
  double offset = this->LabelScreenOffset + this->ScreenSize * 0.5;

184
185
186
187
  // By default enable distance based LOD
  this->EnableDistanceLOD = 1;
  this->DistanceLODThreshold = .7;

188
189
190
191
  // By default enable view angle based LOD
  this->EnableViewAngleLOD = 1;
  this->ViewAngleLODThreshold = .3;

192
  // Set polar axis title follower (label followers not built yet)
193
194
195
  vtkAxisFollower* follower = this->PolarAxis->GetTitleActor();
  follower->SetAxis( this->PolarAxis );
  follower->SetScreenOffset( 2.0 * offset + 5 );
196
  follower->SetEnableDistanceLOD( this->EnableDistanceLOD );
197
198
199
  follower->SetDistanceLODThreshold( this->DistanceLODThreshold );
  follower->SetEnableViewAngleLOD( this->EnableViewAngleLOD );
  follower->SetViewAngleLODThreshold( this->ViewAngleLODThreshold );
200
201
202
203
204
205

  // Properties of the radial axes, with default color black
  this->RadialAxesProperty = vtkProperty::New();
  this->RadialAxesProperty->SetColor( 0., 0., 0. );

  // Create and set radial axes of type X
206
207
  this->RadialAxes = new vtkAxisActor*[VTK_MAXIMUM_NUMBER_OF_RADIAL_AXES];
  for ( int i = 0; i < VTK_MAXIMUM_NUMBER_OF_RADIAL_AXES; ++ i )
208
    {
209
    // Create axis of type X
210
    this->RadialAxes[i] = vtkAxisActor::New();
211
212
    vtkAxisActor* axis = this->RadialAxes[i];
    axis->SetAxisTypeToX();
213
214
    axis->SetAxisPositionToMinMax();
    axis->SetCalculateTitleOffset( 0 );
215
    axis->SetCalculateLabelOffset( 0 );
216

217
    // Set radial axis title follower
218
219
    axis->GetTitleActor()->SetAxis( axis );
    axis->GetTitleActor()->SetScreenOffset( .67 * offset );
220
    axis->GetTitleActor()->SetEnableDistanceLOD( this->EnableDistanceLOD );
221
    axis->GetTitleActor()->SetDistanceLODThreshold( this->DistanceLODThreshold );
222
223
    axis->GetTitleActor()->SetEnableViewAngleLOD( this->EnableViewAngleLOD );
    axis->GetTitleActor()->SetViewAngleLODThreshold( this->ViewAngleLODThreshold );
224
    } // for ( int i = 0; i < VTK_MAXIMUM_NUMBER_OF_RADIAL_AXES; ++ i )
225

226
  // Create and set polar arcs and ancillary objects, with default color white
227
228
229
230
231
  this->PolarArcs = vtkPolyData::New();
  this->PolarArcsMapper = vtkPolyDataMapper::New();
  this->PolarArcsMapper->SetInput( this->PolarArcs );
  this->PolarArcsActor = vtkActor::New();
  this->PolarArcsActor->SetMapper( this->PolarArcsMapper );
232
  this->PolarArcsActor->GetProperty()->SetColor( 1., 1., 1. );
233

234
  // Default title for polar axis (sometimes also called "Radius")
235
236
  this->PolarAxisTitle = new char[16];
  sprintf(this->PolarAxisTitle, "%s", "Radial Distance");
237
238
  this->PolarLabelFormat = new char[8];
  sprintf( this->PolarLabelFormat, "%s", "%-#6.3g" );
239

240
241
242
243
244
245
246
247
248
249
250
251
  // By default all polar axis features are visible
  this->PolarAxisVisibility = 1;
  this->PolarTitleVisibility = 1;
  this->PolarLabelVisibility = 1;
  this->PolarTickVisibility = 1;

  // By default all radial axes features are visible
  this->RadialAxesVisibility = 1;
  this->RadialTitleVisibility = 1;

  // By default polar arcs are visible
  this->PolarArcsVisibility = 1;
252

253
254
255
256
257
258
  // Default title scale
  this->TitleScale = -1.;

  // Default label scale
  this->LabelScale = -1.;

259
260
261
262
263
  this->RenderCount = 0;

  this->RenderSomething = 0;
}

Aashish Chaudhary's avatar
Aashish Chaudhary committed
264
//-----------------------------------------------------------------------------
265
266
267
268
vtkPolarAxesActor::~vtkPolarAxesActor()
{
  this->SetCamera( NULL );

269
270
271
272
273
  if ( this->PolarAxisProperty )
    {
    this->PolarAxisProperty->Delete();
    }

Philippe Pébay's avatar
Philippe Pébay committed
274
  if ( this->RadialAxesProperty )
275
276
277
278
    {
    this->RadialAxesProperty->Delete();
    }

279
  if ( this->PolarLabelFormat )
280
    {
281
282
    delete [] this->PolarLabelFormat;
    this->PolarLabelFormat = NULL;
283
    }
Philippe Pébay's avatar
Philippe Pébay committed
284

Philippe Pébay's avatar
Philippe Pébay committed
285
  if ( this->PolarAxisTitle )
286
287
288
289
290
    {
    delete [] this->PolarAxisTitle;
    this->PolarAxisTitle = NULL;
    }

Philippe Pébay's avatar
Philippe Pébay committed
291
292
293
294
295
296
297
298
299
300
301
302
  if ( this->PolarAxisTitleTextProperty )
    {
    this->PolarAxisTitleTextProperty->Delete();
    this->PolarAxisTitleTextProperty = NULL;
    }

  if ( this->PolarAxisLabelTextProperty )
    {
    this->PolarAxisLabelTextProperty->Delete();
    this->PolarAxisLabelTextProperty = NULL;
    }

303
304
305
306
307
308
  if ( this->PolarAxis )
    {
    this->PolarAxis->Delete();
    this->PolarAxis = NULL;
    }

Philippe Pébay's avatar
Philippe Pébay committed
309
310
  if ( this->RadialAxes )
    {
311
    for ( int i = 0; i < VTK_MAXIMUM_NUMBER_OF_RADIAL_AXES; ++ i )
Philippe Pébay's avatar
Philippe Pébay committed
312
313
314
315
316
317
318
319
320
321
      {
      if ( this->RadialAxes[i] )
        {
        this->RadialAxes[i]->Delete();
        this->RadialAxes[i] = NULL;
        }
      }
    delete [] this->RadialAxes;
    this->RadialAxes = NULL;
    }
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338

  if (this->PolarArcs)
    {
    this->PolarArcs->Delete();
    this->PolarArcs = NULL;
    }
  if (this->PolarArcsMapper)
    {
    this->PolarArcsMapper->Delete();
    this->PolarArcsMapper = NULL;
    }
  if (this->PolarArcsActor)
    {
    this->PolarArcsActor->Delete();
    this->PolarArcsActor = NULL;
    }

339
340
}

Aashish Chaudhary's avatar
Aashish Chaudhary committed
341
//-----------------------------------------------------------------------------
Philippe Pébay's avatar
Philippe Pébay committed
342
int vtkPolarAxesActor::RenderOpaqueGeometry( vtkViewport *viewport )
343
344
345
{
  // Initialization
  static bool initialRender = true;
346
  if ( !this->Camera )
347
348
349
350
351
352
353
354
    {
    vtkErrorMacro( <<"No camera!" );
    this->RenderSomething = 0;
    return 0;
    }

  this->BuildAxes( viewport );

355
  if ( initialRender )
356
    {
357
358
    this->PolarAxis->BuildAxis( viewport, true );

359
360
    for ( int i = 0; i < this->NumberOfRadialAxes; ++ i )
      {
Philippe Pébay's avatar
Philippe Pébay committed
361
      this->RadialAxes[i]->BuildAxis( viewport, true );
362
363
364
365
366
      }
    }
  initialRender = false;

  int renderedSomething = 0;
367
368
369
370
371
372
373
374

  // Render the polar axis
  if ( this->PolarAxisVisibility )
    {
    renderedSomething += this->PolarAxis->RenderOpaqueGeometry( viewport );
    }

  // Render the radial axes
375
376
377
378
  if ( this->RadialAxesVisibility )
    {
    for ( int i = 0; i < this->NumberOfRadialAxes; ++ i )
      {
379
      renderedSomething += this->RadialAxes[i]->RenderOpaqueGeometry( viewport );
380
381
382
      }
    }

383
384
385
386
387
388
  // Render the polar arcs
  if ( this->PolarArcsVisibility )
    {
    renderedSomething += this->PolarArcsActor->RenderOpaqueGeometry(viewport);
    }

389
390
391
  return renderedSomething;
}

Aashish Chaudhary's avatar
Aashish Chaudhary committed
392
//-----------------------------------------------------------------------------
Philippe Pébay's avatar
Philippe Pébay committed
393
void vtkPolarAxesActor::SetScreenSize( double screenSize )
394
395
{
  this->ScreenSize = screenSize;
396
397
  // Considering pivot point at center of the geometry,
  // hence ( this->ScreenSize * 0.5 ).
Philippe Pébay's avatar
Philippe Pébay committed
398
  this->LabelScreenOffset = 15.0 + this->ScreenSize * 0.5;
399

400
401
402
  vtkAxisFollower** labelActors = this->PolarAxis->GetLabelActors();
  int numberOfLabels = this->PolarAxis->GetNumberOfLabelsBuilt();
  for( int i = 0; i < numberOfLabels; ++ i )
403
    {
404
    labelActors[i]->SetScreenOffset( this->LabelScreenOffset );
405
406
407
408
409
    }

  this->Modified();
}

Aashish Chaudhary's avatar
Aashish Chaudhary committed
410
//-----------------------------------------------------------------------------
Philippe Pébay's avatar
Philippe Pébay committed
411
void vtkPolarAxesActor::ReleaseGraphicsResources( vtkWindow *win )
412
{
413
  this->PolarAxis->ReleaseGraphicsResources(win);
414
415
  for ( int i = 0; i < this->NumberOfRadialAxes;  ++i )
    {
Philippe Pébay's avatar
Philippe Pébay committed
416
    this->RadialAxes[i]->ReleaseGraphicsResources( win );
417
    }
418
419
  this->PolarArcsActor->ReleaseGraphicsResources(win);

420
421
}

Aashish Chaudhary's avatar
Aashish Chaudhary committed
422
//-----------------------------------------------------------------------------
Philippe Pébay's avatar
Philippe Pébay committed
423
void vtkPolarAxesActor::GetBounds( double bounds[6])
424
{
Philippe Pébay's avatar
Philippe Pébay committed
425
  for ( int i=0; i< 6; i++)
426
427
428
429
430
    {
    bounds[i] = this->Bounds[i];
    }
}

Aashish Chaudhary's avatar
Aashish Chaudhary committed
431
//-----------------------------------------------------------------------------
Philippe Pébay's avatar
Philippe Pébay committed
432
void vtkPolarAxesActor::GetBounds( double& xmin, double& xmax,
433
                                 double& ymin, double& ymax,
Philippe Pébay's avatar
Philippe Pébay committed
434
                                 double& zmin, double& zmax )
435
436
437
438
439
440
441
442
443
{
  xmin = this->Bounds[0];
  xmax = this->Bounds[1];
  ymin = this->Bounds[2];
  ymax = this->Bounds[3];
  zmin = this->Bounds[4];
  zmax = this->Bounds[5];
}

Aashish Chaudhary's avatar
Aashish Chaudhary committed
444
//-----------------------------------------------------------------------------
445
446
447
448
449
double *vtkPolarAxesActor::GetBounds()
{
  return this->Bounds;
}

Aashish Chaudhary's avatar
Aashish Chaudhary committed
450
//-----------------------------------------------------------------------------
Philippe Pébay's avatar
Philippe Pébay committed
451
void vtkPolarAxesActor::BuildAxes( vtkViewport *viewport )
452
{
Philippe Pébay's avatar
Philippe Pébay committed
453
  if ( ( this->GetMTime() < this->BuildTime.GetMTime() ))
454
    {
Philippe Pébay's avatar
Philippe Pébay committed
455
    this->AutoScale( viewport );
456
457
458
    return;
    }

459
460
  // Determine the bounds
  double bounds[6];
Philippe Pébay's avatar
Philippe Pébay committed
461
  this->GetBounds( bounds );
Aashish Chaudhary's avatar
Aashish Chaudhary committed
462

463
  // If pole coordinates are invalid, use bounds
464
  double O[3];
465
466
  for ( int i = 0; i < 3; ++ i )
    {
467
    O[i] = this->Pole[i] == VTK_DOUBLE_MAX ? bounds[i * 2] : this->Pole[i];
468
    }
Aashish Chaudhary's avatar
Aashish Chaudhary committed
469

470
471
472
  // If axial scale it out of proportions with object length scale, reset to ls
  double ls = fabs( bounds[1] -  bounds[0] ) + fabs( bounds[3] -  bounds[2] );
  if ( this->AutoScaleRadius
Aashish Chaudhary's avatar
Aashish Chaudhary committed
473
       || this->MaximumRadius < 1.e-6 * ls
474
475
476
477
       || this->MaximumRadius > 1.e6 * ls )
    {
    this->MaximumRadius = .5 * ls;
    }
478

479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
  // Set polar axis endpoints
  vtkAxisActor* axis = this->PolarAxis;
  double ox = O[0] + this->MaximumRadius;
  axis->GetPoint1Coordinate()->SetValue( O[0], O[1], O[2] );
  axis->GetPoint2Coordinate()->SetValue( ox, O[1], O[2] );

  // Set common axis attributes
  this->SetCommonAxisAttributes( axis );

  // Set polar axis lines
  axis->SetAxisVisibility( this->PolarAxisVisibility );
  axis->SetAxisLinesProperty( this->PolarAxisProperty );

  // Set polar axis title
  axis->SetTitleVisibility( this->PolarTitleVisibility );
  axis->SetTitle( this->PolarAxisTitle );
  axis->SetTitleTextProperty( this->PolarAxisTitleTextProperty );

  // Set polar axis ticks (major only)
  axis->SetTickVisibility( this->PolarTickVisibility );
499
  axis->SetTickLocation( VTK_TICKS_BOTH );
500
501
502
503
504
505
506
507
508
509
510
  axis->SetMajorTickSize( .02 * this->MaximumRadius );
  
  // Set polar axis labels
  axis->SetLabelVisibility( this->PolarLabelVisibility );
  axis->SetLabelTextProperty( this->PolarAxisLabelTextProperty );

  // Create requested number of radial axes
  double dAlpha = 
    ( this->MaximumAngle  - this->MinimumAngle ) / ( this->NumberOfRadialAxes - 1. );
  double alpha = this->MinimumAngle;
  for ( int i = 0; i < this->NumberOfRadialAxes;  ++ i, alpha += dAlpha )
511
    {
512
513
514
515
516
517
518
    // Calculate endpoint coordinates
    double alphaRad = vtkMath::RadiansFromDegrees( alpha );
    double x = O[0] + this->MaximumRadius * cos( alphaRad );
    double y = O[1] + this->MaximumRadius * sin( alphaRad );

    // Set radial axis endpoints
    axis = this->RadialAxes[i];
519
520
    axis->GetPoint1Coordinate()->SetValue( O[0], O[1], O[2] );
    axis->GetPoint2Coordinate()->SetValue( x, y, O[2] );
Philippe Pébay's avatar
Philippe Pébay committed
521

522
523
    // Set common axis attributes
    this->SetCommonAxisAttributes( axis );
524

525
526
527
    // Set radial axis lines
    axis->SetAxisVisibility( this->RadialAxesVisibility );
    axis->SetAxisLinesProperty( this->RadialAxesProperty );
528

529
    // Set radial axis title with polar angle as title for non-polar axes
530
531
532
533
    if ( this->PolarAxisVisibility && fabs( alpha ) < 2. )
      { 
      // Prevent conflict between radial and polar axes titles
      axis->SetTitleVisibility( false );
534
535
536
537
538
539

      if ( fabs( alpha ) < this->SmallestVisiblePolarAngle )
        { 
        // Do not show radial axes too close to polar axis
        axis->SetAxisVisibility( false );
        }
540
541
542
543
544
545
546
547
548
549
550
      }
    else
      {
      // Use polar angle as a title for the radial axis
      axis->SetTitleVisibility( this->RadialTitleVisibility );
      axis->GetTitleTextProperty()->SetColor( this->RadialAxesProperty->GetColor() );
      vtksys_ios::ostringstream title;
      title << alpha
            << ( this->RadialUnits ? " deg" : "" );
      axis->SetTitle( title.str().c_str() );
      }
551
552
553
554

    // No labels nor ticks for radial axes
    axis->SetLabelVisibility( 0 );
    axis->SetTickVisibility( 0 );
555
    }
Aashish Chaudhary's avatar
Aashish Chaudhary committed
556

557
558
  // Build polar axis ticks
  this->BuildPolarAxisTicks( O[0] );
559

560
561
  // Build polar axis labels
  this->BuildPolarAxisLabelsArcs( O );
562

563
  // Scale appropriately
564
565
566
567
568
569
  this->AutoScale( viewport );

  this->RenderSomething = 1;
  this->BuildTime.Modified();
}

Aashish Chaudhary's avatar
Aashish Chaudhary committed
570
//-----------------------------------------------------------------------------
571
void vtkPolarAxesActor::SetCommonAxisAttributes( vtkAxisActor* axis )
572
573
{
  vtkProperty *prop = this->GetProperty();
Philippe Pébay's avatar
Philippe Pébay committed
574
575
  prop->SetAmbient( 1.0 );
  prop->SetDiffuse( 0.0 );
576
577
  axis->SetProperty( prop );

578
  // Common space and range attributes
579
580
581
582
583
584
  axis->SetCamera( this->Camera );
  axis->SetBounds( this->Bounds );
  axis->SetRange( 0., this->MaximumRadius );

  // No minor ticks for any kind of axes
  axis->SetMinorTicksVisible( 0 );
585
586
}

Aashish Chaudhary's avatar
Aashish Chaudhary committed
587
//-----------------------------------------------------------------------------
Philippe Pébay's avatar
Philippe Pébay committed
588
inline double vtkPolarAxesActor::FFix( double value )
589
{
Philippe Pébay's avatar
Philippe Pébay committed
590
  int ivalue = static_cast<int>( value );
591
592
593
  return ivalue;
}

Aashish Chaudhary's avatar
Aashish Chaudhary committed
594
//-----------------------------------------------------------------------------
Philippe Pébay's avatar
Philippe Pébay committed
595
inline double vtkPolarAxesActor::FSign( double value, double sign )
596
{
Philippe Pébay's avatar
Philippe Pébay committed
597
598
  value = fabs( value );
  if ( sign < 0.)
599
600
601
602
603
604
    {
    value *= -1.;
    }
  return value;
}

Aashish Chaudhary's avatar
Aashish Chaudhary committed
605
//-----------------------------------------------------------------------------
606
void vtkPolarAxesActor::BuildPolarAxisTicks( double x0 )
607
{
608
  double delta;
609

610
611
612
  if ( this->AutoSubdividePolarAxis
       || this->NumberOfPolarAxisTicks < 0
       || this->NumberOfPolarAxisTicks > VTK_MAXIMUM_NUMBER_OF_POLAR_AXIS_TICKS )
613
    {
614
615
    // Programatically figure the number of divisions of the polar axis
    double pow10 = log10( this->MaximumRadius );
616

617
618
619
620
621
622
    // Build in numerical tolerance
    if ( pow10 != 0.)
      {
      double eps = 10.0e-10;
      pow10 = this->FSign( ( fabs( pow10 ) + eps ), pow10 );
      }
623

624
625
626
627
628
    // FFix will move in the wrong direction if pow10 is negative.
    if ( pow10 < 0.)
      {
      pow10 = pow10 - 1.;
      }
629

630
631
632
633
634
635
    // Find the number of integral points in the interval.
    delta = pow( 10., this->FFix( pow10 ) );
    double fnt = this->MaximumRadius / delta;
    fnt  = this->FFix( fnt );
    int numTicks = fnt <= 0.5 ? 
      static_cast<int>( this->FFix( fnt ) ) : static_cast<int>( this->FFix( fnt ) + 1 );
636

637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
    // If not enough tick points in this decade, scale down
    double div = 1.;
    if ( numTicks < 5 )
      {
      div = 2.;
      }
    if ( numTicks <= 2 )
      {
      div = 5.;
      }
    if ( div != 1.)
      {
      delta /= div;
      }

    // Finally calculate number of tick points
    this->NumberOfPolarAxisTicks = 0;
    while ( delta * this->NumberOfPolarAxisTicks <= this->MaximumRadius )
      {
      ++ this->NumberOfPolarAxisTicks;
      }
    }
  else // if ( this->AutoSubdividePolarAxis || this->NumberOfPolarAxisTicks ... )
660
    {
661
662
    // Use pre-set number of arcs when it is valid and no auto-subdivision was requested
    delta =  this->MaximumRadius / ( this->NumberOfPolarAxisTicks - 1 );
663
    }
664
  // Set major start and delta corresponding to range and coordinates
665
666
667
  this->PolarAxis->SetMajorRangeStart( 0. );
  this->PolarAxis->SetDeltaRangeMajor( delta );
  this->PolarAxis->SetMajorStart( VTK_AXIS_TYPE_X, x0 );
668

669
  // Build in numerical robustness to avoid truncation errors at endpoint
670
  delta *= VTK_POLAR_AXES_ACTOR_RTOL;
671
  this->PolarAxis->SetDeltaMajor( VTK_AXIS_TYPE_X, delta );
672
673
}

Aashish Chaudhary's avatar
Aashish Chaudhary committed
674
//-----------------------------------------------------------------------------
675
void vtkPolarAxesActor::BuildPolarAxisLabelsArcs( double* O )
676
{
677
  // Prepare storage for polar axis labels
678
  vtkStringArray *labels = vtkStringArray::New();
679
  labels->SetNumberOfValues( this->NumberOfPolarAxisTicks );
680

681
  // Prepare trigonometric quantities
682
683
684
685
686
687
688
  double thetaMin = vtkMath::RadiansFromDegrees( this->MinimumAngle );
  double cosThetaMin = cos( thetaMin );
  double sinThetaMin = sin( thetaMin );
  double thetaMax = vtkMath::RadiansFromDegrees( this->MaximumAngle );
  double cosThetaMax = cos( thetaMax );
  double sinThetaMax = sin( thetaMax );
  double angularSector = this->MaximumAngle - this->MinimumAngle;
Aashish Chaudhary's avatar
Aashish Chaudhary committed
689
  vtkIdType arcResolution
690
    = static_cast<vtkIdType>( angularSector * VTK_POLAR_ARC_RESOLUTION_PER_DEG );
691

692
  // Arc points
693
  vtkPoints* polarArcsPoints = vtkPoints::New();
694
695
  this->PolarArcs->SetPoints( polarArcsPoints );
  polarArcsPoints->Delete();
696

697
  // Arc lines
698
  vtkCellArray* polarArcsLines = vtkCellArray::New();
699
700
701
  this->PolarArcs->SetLines( polarArcsLines );
  polarArcsLines->Delete();

702
  // Retreave label features
703
  vtkAxisActor* axis = this->PolarAxis;
704
705
706
707
  double delta = axis->GetDeltaMajor( VTK_AXIS_TYPE_X );
  double value = axis->GetMajorRangeStart();

  // Now create labels and polar arcs
708
  const char *format = this->PolarLabelFormat;
709
  char label[64];
710
  vtkIdType pointIdOffset = 0;
711
  for ( int  i = 0; i < this->NumberOfPolarAxisTicks; ++ i )
712
    {
713
    // Store label
714
    sprintf( label, format, value );
715
    labels->SetValue( i, label );
716

717
    if ( value  > 0. )
718
      {
719
      // Build corresponding polar arc for non-zero values
720
721
722
723
      double x1 = value * cosThetaMin;
      double y1 = value * sinThetaMin;
      double x2 = value * cosThetaMax;
      double y2 = value * sinThetaMax;
724
      vtkArcSource* arc = vtkArcSource::New();
725
      arc->SetCenter( O );
726
727
      arc->SetPoint1( O[0] + x1, O[1] + y1, O[2] );
      arc->SetPoint2( O[0] + x2, O[1] + y2, O[2] );
728
      arc->SetResolution( arcResolution );
729
      arc->SetNegative( angularSector > 180. );
730
      arc->Update();
Aashish Chaudhary's avatar
Aashish Chaudhary committed
731

732
733
734
735
736
737
738
739
740
741
      // Append new polar arc to existing ones
      vtkPoints* arcPoints = arc->GetOutput()->GetPoints();
      vtkIdType nPoints = arcResolution + 1;
      vtkIdType* arcPointIds = new vtkIdType[nPoints];
      for ( vtkIdType j = 0; j < nPoints; ++ j )
        {
        polarArcsPoints->InsertNextPoint( arcPoints->GetPoint( j ) );
        arcPointIds[j] = pointIdOffset + j;
        }
      polarArcsLines->InsertNextCell( nPoints, arcPointIds );
Aashish Chaudhary's avatar
Aashish Chaudhary committed
742

743
744
745
      // Clean up
      arc->Delete();
      delete [] arcPointIds;
Aashish Chaudhary's avatar
Aashish Chaudhary committed
746

747
748
      // Update polyline cell offset
      pointIdOffset += nPoints;
749
750
751
      }

    // Move to next value
752
    value += delta;
753
    }
754
755

  // Store labels
756
  this->PolarAxis->SetLabels( labels );
757
758

  // Clean up
759
  labels->Delete();
760
761
762

  // Update axis label followers
  vtkAxisFollower** labelActors = axis->GetLabelActors();
763
  for( int i = 0; i < this->NumberOfPolarAxisTicks; ++ i )
764
765
766
    {
    labelActors[i]->SetAxis( axis );
    labelActors[i]->SetScreenOffset( this->LabelScreenOffset );
767
    labelActors[i]->SetEnableDistanceLOD( this->EnableDistanceLOD );
768
769
770
    labelActors[i]->SetDistanceLODThreshold( this->DistanceLODThreshold );
    labelActors[i]->SetEnableViewAngleLOD( this->EnableViewAngleLOD );
    labelActors[i]->SetViewAngleLODThreshold( this->ViewAngleLODThreshold );
771
    }
772
773
}

Aashish Chaudhary's avatar
Aashish Chaudhary committed
774
//-----------------------------------------------------------------------------
775
776
777
void vtkPolarAxesActor::AutoScale( vtkViewport *viewport )
{

778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
  // Scale polar axis title
  vtkAxisActor* axis = this->PolarAxis;
  double newTitleScale
    = vtkAxisFollower::AutoScale( viewport, 
                                  this->Camera,
                                  this->ScreenSize, 
                                  axis->GetTitleActor()->GetPosition() );
  axis->SetTitleScale( newTitleScale );

  // Scale polar axis labels
  vtkAxisFollower** labelActors = axis->GetLabelActors();
  for( int i = 0; i < axis->GetNumberOfLabelsBuilt(); ++ i )
    {
    double newLabelScale 
      = vtkAxisFollower::AutoScale( viewport,
                                    this->Camera, 
                                    this->ScreenSize, 
                                    labelActors[i]->GetPosition() );
    labelActors[i]->SetScale( newLabelScale );
    }
798
799

  // Loop over radial axes
800
801
  for ( int i = 0; i < this->NumberOfRadialAxes; ++ i )
    {
802
    axis = this->RadialAxes[i];
803
    // Scale title
804
805
806
807
808
809
    newTitleScale 
      = vtkAxisFollower::AutoScale( viewport, 
                                    this->Camera,
                                    this->ScreenSize,
                                    axis->GetTitleActor()->GetPosition() );
    axis->SetTitleScale( newTitleScale );
810
    }
811
812
}

813
814
815
816
817
818
819
820
821
822
823
824
825
//-----------------------------------------------------------------------------
void vtkPolarAxesActor::SetPolarAxisProperty( vtkProperty *prop )
{
  this->PolarAxisProperty->DeepCopy( prop );
  this->Modified();
}

//-----------------------------------------------------------------------------
vtkProperty* vtkPolarAxesActor::GetPolarAxisProperty()
{
  return this->PolarAxisProperty;
}

Aashish Chaudhary's avatar
Aashish Chaudhary committed
826
//-----------------------------------------------------------------------------
Philippe Pébay's avatar
Philippe Pébay committed
827
void vtkPolarAxesActor::SetRadialAxesProperty( vtkProperty *prop )
828
{
Philippe Pébay's avatar
Philippe Pébay committed
829
  this->RadialAxesProperty->DeepCopy( prop );
830
831
832
  this->Modified();
}

Aashish Chaudhary's avatar
Aashish Chaudhary committed
833
//-----------------------------------------------------------------------------
834
835
836
837
vtkProperty* vtkPolarAxesActor::GetRadialAxesProperty()
{
  return this->RadialAxesProperty;
}
838

Aashish Chaudhary's avatar
Aashish Chaudhary committed
839
//-----------------------------------------------------------------------------
840
841
842
843
844
845
void vtkPolarAxesActor::SetPolarArcsProperty( vtkProperty *prop )
{
  this->PolarArcsActor->SetProperty(prop);
  this->Modified();
}

Aashish Chaudhary's avatar
Aashish Chaudhary committed
846
//-----------------------------------------------------------------------------
847
848
849
850
vtkProperty* vtkPolarAxesActor::GetPolarArcsProperty()
{
  return this->PolarArcsActor->GetProperty();
}