vtkPolarAxesActor.cxx 24.2 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
/*=========================================================================

  Program:   Visualization Toolkit
  Module:    vtkPolarAxesActor.cxx
  Thanks:    Kathleen Bonnell, B Division, Lawrence Livermore National Lab

  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"

#include "vtkAxisActor.h"
#include "vtkAxisFollower.h"
#include "vtkCamera.h"
#include "vtkCoordinate.h"
#include "vtkFollower.h"
#include "vtkMath.h"
#include "vtkObjectFactory.h"
#include "vtkProperty.h"
#include "vtkStringArray.h"
#include "vtkViewport.h"

29
#include <vtksys/ios/sstream>
30
31
32
33
34

vtkStandardNewMacro(vtkPolarAxesActor);
vtkCxxSetObjectMacro(vtkPolarAxesActor, Camera,vtkCamera);

// ******************************************************************
Philippe Pébay's avatar
Philippe Pébay committed
35
void vtkPolarAxesActor::PrintSelf( ostream& os, vtkIndent indent )
36
{
Philippe Pébay's avatar
Philippe Pébay committed
37
  this->Superclass::PrintSelf( os,indent );
38

39
40
  os << indent << "Bounds: \n";
  os << indent << "  Xmin,Xmax: (" << this->Bounds[0] << ", "
41
     << this->Bounds[1] << " )\n";
42
  os << indent << "  Ymin,Ymax: (" << this->Bounds[2] << ", "
43
     << this->Bounds[3] << " )\n";
44
  os << indent << "  Zmin,Zmax: (" << this->Bounds[4] << ", "
45
     << this->Bounds[5] << " )\n";
46
47
48
49
50
51

  os << indent << "Number Of Radial Axes" << this->NumberOfRadialAxes << endl;

  os << indent << "Pole: (" 
     << this->Pole[0] << ", "
     << this->Pole[1] << ", "
52
     << this->Pole[2] << " )\n";
53

54
  os << indent << "Maximum Radius" << this->MaximumRadius << endl;
55
  os << indent << "Auto-Scale Radius" << this->AutoScaleRadius << endl;
56
57
  os << indent << "Maximum Angle" << this->MaximumAngle << endl;

58

Philippe Pébay's avatar
Philippe Pébay committed
59
  if ( this->Camera )
60
61
    {
    os << indent << "Camera:\n";
Philippe Pébay's avatar
Philippe Pébay committed
62
    this->Camera->PrintSelf( os,indent.GetNextIndent() );
63
64
65
66
67
68
    }
  else
    {
    os << indent << "Camera: (none)\n";
    }

69
70
71
72
73
  os << indent << "Rebuild Axes: "
     << ( this->RebuildAxes ? "On\n" : "Off\n" );

  os << indent << "Radial Units (degrees): "
     << ( this->RadialUnits ? "On\n" : "Off\n" ) << endl;
74
75

  os << indent << "Radial Axes Visibility: "
76
     << ( this->RadialAxesVisibility ? "On\n" : "Off\n" );
77

78
79
  os << indent << "Radial Title Visibility: "
     << ( this->RadialTitleVisibility ? "On" : "Off" ) << endl;
80

81
82
  os << indent << "Polar Label Visibility: "
     << ( this->PolarLabelVisibility ? "On" : "Off" ) << endl;
83

84
85
86
87
  os << indent << "Polar Tick Visibility: "
     << ( this->PolarTickVisibility ? "On" : "Off" ) << endl;

  os << indent << "Radial Axes Label Format: " << this->RadialLabelFormat << "\n";
88

89
  os << indent << "Tick Location: " << this->TickLocation << endl;
90
91
92
93
94
}

// *************************************************************************
vtkPolarAxesActor::vtkPolarAxesActor() : vtkActor()
{
95
96
97
98
99
  // 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;

100
  // Default pole coordinates
101
102
103
  this->Pole[0] = VTK_DOUBLE_MAX;
  this->Pole[1] = VTK_DOUBLE_MAX;
  this->Pole[2] = VTK_DOUBLE_MAX;
104
105
106
107
108
109
110

  // Default number of polar axes
  this->NumberOfRadialAxes = VTK_DEFAULT_NUMBER_OF_RADIAL_AXES;

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

111
112
113
  // Do not auto-scale radius by default
  this->AutoScaleRadius = false;

114
115
116
117
118
  // Default maximum polar angle
  this->MaximumAngle = VTK_DEFAULT_MAXIMUM_POLAR_ANGLE;

  // By default show angle units (degrees)
  this->RadialUnits = 1;
119
120
121
122
123
124
125
126

  this->RebuildAxes = false;

  this->Camera = NULL;

  this->ScreenSize = 10.0;

  // Create and set radial axes
Philippe Pébay's avatar
Philippe Pébay committed
127
  this->RadialAxes = new vtkAxisActor*[this->NumberOfRadialAxes];
128
129
  for ( int i = 0; i < this->NumberOfRadialAxes; ++ i )
    {
130
    // Create axis of type X
131
    this->RadialAxes[i] = vtkAxisActor::New();
132
133
134
135
136
137
    vtkAxisActor* axis = this->RadialAxes[i];
    axis->SetAxisTypeToX();

    // Title offset is auto-calculated for now
    axis->SetCalculateTitleOffset( 1 );
    axis->SetCalculateLabelOffset( 0 );
138
139

    // Pass information to axes followers
140
141
    vtkAxisFollower* follower = axis->GetTitleActor();
    follower->SetAxis( axis );
142
143
144
145
146
147
148
149
    }

  // Properties of the radial axes
  this->RadialAxesProperty = vtkProperty::New();

  this->ActualRadialLabel = 0;

  // Default tick location, defined in vtkAxisActor
150
  this->TickLocation = VTK_TICKS_BOTH;
151
152
153

  // By default all features are visible
  this->RadialAxesVisibility = 1;
154
  this->RadialTitleVisibility = 1;
155
156
  this->PolarLabelVisibility = 1;
  this->PolarTickVisibility = 1;
157
158

  this->RadialLabelFormat = new char[8];
159
  sprintf( this->RadialLabelFormat, "%s", "%-#6.3g" );
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177

  this->RenderCount = 0;

  this->RenderSomething = 0;

  this->LastRadialPow = 0;

  this->UserRadialPow = 0;

  this->AutoLabelScaling = true;

  this->LastRadialAxesDigits = 3;

  this->MustAdjustRadialValue = false;

  this->ForceRadialLabelReset = false;

  this->LabelScale = -1.0;
178
  this->TitleScale = -1.0;
179
180
181
182
183
184
185
}

// ****************************************************************************
vtkPolarAxesActor::~vtkPolarAxesActor()
{
  this->SetCamera( NULL );

Philippe Pébay's avatar
Philippe Pébay committed
186
  if ( this->RadialAxesProperty )
187
188
189
190
    {
    this->RadialAxesProperty->Delete();
    }

Philippe Pébay's avatar
Philippe Pébay committed
191
  if ( this->RadialLabelFormat )
192
193
194
195
    {
    delete [] this->RadialLabelFormat;
    this->RadialLabelFormat = NULL;
    }
Philippe Pébay's avatar
Philippe Pébay committed
196
197
198
199
200
201
202
203
204
205
206
207
208
209

  if ( this->RadialAxes )
    {
    for ( int i = 0; i < this->NumberOfRadialAxes; ++ i )
      {
      if ( this->RadialAxes[i] )
        {
        this->RadialAxes[i]->Delete();
        this->RadialAxes[i] = NULL;
        }
      }
    delete [] this->RadialAxes;
    this->RadialAxes = NULL;
    }
210
211
212
}

// ****************************************************************************
Philippe Pébay's avatar
Philippe Pébay committed
213
void vtkPolarAxesActor::ShallowCopy( vtkPolarAxesActor *actor )
214
{
Philippe Pébay's avatar
Philippe Pébay committed
215
216
217
  this->Superclass::ShallowCopy( actor );
  this->SetRadialLabelFormat( actor->GetRadialLabelFormat() );
  this->SetCamera( actor->GetCamera() );
218
219
220
221
  this->MustAdjustRadialValue = actor->MustAdjustRadialValue;
  this->ForceRadialLabelReset = actor->ForceRadialLabelReset;
  this->LabelScreenOffset = actor->LabelScreenOffset;
  this->ScreenSize        = actor->ScreenSize;
222
  this->LabelScreenOffset = actor->LabelScreenOffset;
223
224
225
}

// *************************************************************************
Philippe Pébay's avatar
Philippe Pébay committed
226
int vtkPolarAxesActor::RenderOpaqueGeometry( vtkViewport *viewport )
227
228
229
{
  // Initialization
  static bool initialRender = true;
230
  if ( !this->Camera )
231
232
233
234
235
236
237
238
239
240
241
242
    {
    vtkErrorMacro( <<"No camera!" );
    this->RenderSomething = 0;
    return 0;
    }

  this->BuildAxes( viewport );

  if ( initialRender || this->RebuildAxes )
    {
    for ( int i = 0; i < this->NumberOfRadialAxes; ++ i )
      {
Philippe Pébay's avatar
Philippe Pébay committed
243
      this->RadialAxes[i]->BuildAxis( viewport, true );
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
      }
    }
  initialRender = false;
  this->RebuildAxes = false;

  //Render the axes
  int renderedSomething = 0;
  if ( this->RadialAxesVisibility )
    {
    for ( int i = 0; i < this->NumberOfRadialAxes; ++ i )
      {
      renderedSomething +=
        this->RadialAxes[i]->RenderOpaqueGeometry( viewport );
      }
    }

  return renderedSomething;
}

// *************************************************************************
// Screen size affects the screen offset as well.
// *************************************************************************
Philippe Pébay's avatar
Philippe Pébay committed
266
void vtkPolarAxesActor::SetScreenSize( double screenSize )
267
268
{
  this->ScreenSize = screenSize;
269
270
  // Considering pivot point at center of the geometry,
  // hence ( this->ScreenSize * 0.5 ).
271
272
273
274
  this->LabelScreenOffset = 20.0 + this->ScreenSize * 0.5;

  for ( int i = 0; i < this->NumberOfRadialAxes; ++ i )
    {
275
276
277
278
279
    vtkAxisActor* axis = this->RadialAxes[i];
  
    int numberOfLabelsBuilt = axis->GetNumberOfLabelsBuilt();
    vtkAxisFollower** labelActors = axis->GetLabelActors();
    for( int k=0; k < numberOfLabelsBuilt; ++k )
280
      {
Philippe Pébay's avatar
Philippe Pébay committed
281
      labelActors[k]->SetScreenOffset( this->LabelScreenOffset );
282
283
284
285
286
287
288
      }
    }

  this->Modified();
}

// *************************************************************************
Philippe Pébay's avatar
Philippe Pébay committed
289
void vtkPolarAxesActor::ReleaseGraphicsResources( vtkWindow *win )
290
291
292
{
  for ( int i = 0; i < this->NumberOfRadialAxes;  ++i )
    {
Philippe Pébay's avatar
Philippe Pébay committed
293
    this->RadialAxes[i]->ReleaseGraphicsResources( win );
294
295
296
    }
}

297
// *************************************************************************
Philippe Pébay's avatar
Philippe Pébay committed
298
void vtkPolarAxesActor::GetBounds( double bounds[6])
299
{
Philippe Pébay's avatar
Philippe Pébay committed
300
  for ( int i=0; i< 6; i++)
301
302
303
304
305
306
    {
    bounds[i] = this->Bounds[i];
    }
}

// *************************************************************************
Philippe Pébay's avatar
Philippe Pébay committed
307
void vtkPolarAxesActor::GetBounds( double& xmin, double& xmax,
308
                                 double& ymin, double& ymax,
Philippe Pébay's avatar
Philippe Pébay committed
309
                                 double& zmin, double& zmax )
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
{
  xmin = this->Bounds[0];
  xmax = this->Bounds[1];
  ymin = this->Bounds[2];
  ymax = this->Bounds[3];
  zmin = this->Bounds[4];
  zmax = this->Bounds[5];
}

// *************************************************************************
double *vtkPolarAxesActor::GetBounds()
{
  return this->Bounds;
}

325
// *************************************************************************
Philippe Pébay's avatar
Philippe Pébay committed
326
void vtkPolarAxesActor::TransformBounds( vtkViewport *viewport,
Philippe Pébay's avatar
Philippe Pébay committed
327
                                         double bounds[6] )
328
{
Philippe Pébay's avatar
Philippe Pébay committed
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
  double minPt[3], maxPt[3], transMinPt[3], transMaxPt[3];
  minPt[0] = this->Bounds[0];
  minPt[1] = this->Bounds[2];
  minPt[2] = this->Bounds[4];
  maxPt[0] = this->Bounds[1];
  maxPt[1] = this->Bounds[3];
  maxPt[2] = this->Bounds[5];

  viewport->SetWorldPoint(minPt[0], minPt[1], minPt[2], 1.0);
  viewport->WorldToDisplay();
  viewport->GetDisplayPoint(transMinPt);
  viewport->SetWorldPoint(maxPt[0], maxPt[1], maxPt[2], 1.0);
  viewport->WorldToDisplay();
  viewport->GetDisplayPoint(transMaxPt);

  bounds[0] = transMinPt[0];
  bounds[2] = transMinPt[1];
  bounds[4] = transMinPt[2];
  bounds[1] = transMaxPt[0];
  bounds[3] = transMaxPt[1];
  bounds[5] = transMaxPt[2];
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
}

// ****************************************************************************
//  Method: LabelExponent
//
//  Purpose:
//      Determines the proper exponent for the min and max values.
//
//  Arguments:
//      min     The minimum value along a certain axis.
//      max     The maximum value along a certain axis.
//
//  Note:       This code is mostly stolen from old MeshTV code,
//              /meshtvx/toolkit/plotgrid.c, axlab_format.
// ****************************************************************************
Philippe Pébay's avatar
Philippe Pébay committed
365
int vtkPolarAxesActor::LabelExponent( double min, double max )
366
{
Philippe Pébay's avatar
Philippe Pébay committed
367
  if ( min == max )
368
369
370
371
372
373
374
    {
    return 0;
    }

  //
  // Determine power of 10 to scale axis labels to.
  //
Philippe Pébay's avatar
Philippe Pébay committed
375
376
  double range = ( fabs( min ) > fabs( max ) ? fabs( min ) : fabs( max ) );
  double pow10 = log10( range );
377
378
379
380
381
382
383
384

  //
  // Cutoffs for using scientific notation.  The following 4 variables
  // should all be static for maximum performance but were made non-static
  // to get around a compiler bug with the MIPSpro 7.2.1.3 compiler.
  //
  double eformat_cut_min = -1.5;
  double eformat_cut_max =  3.0;
Philippe Pébay's avatar
Philippe Pébay committed
385
386
  double cut_min = pow( 10., eformat_cut_min );
  double cut_max = pow( 10., eformat_cut_max );
387
  double ipow10;
Philippe Pébay's avatar
Philippe Pébay committed
388
  if ( range < cut_min || range > cut_max )
389
390
391
392
393
    {
    //
    // We are going to use scientific notation and round the exponents to
    // the nearest multiple of three.
    //
Philippe Pébay's avatar
Philippe Pébay committed
394
    ipow10 = ( floor( floor( pow10 )/3.) )*3;
395
396
397
398
399
400
    }
  else
    {
    ipow10 = 0;
    }

Philippe Pébay's avatar
Philippe Pébay committed
401
  return static_cast<int>( ipow10 );
402
403
404
}

// *************************************************************************
Philippe Pébay's avatar
Philippe Pébay committed
405
void vtkPolarAxesActor::BuildAxes( vtkViewport *viewport )
406
407
408
{
  double bounds[6];

Philippe Pébay's avatar
Philippe Pébay committed
409
  if ( ( this->GetMTime() < this->BuildTime.GetMTime() ))
410
    {
Philippe Pébay's avatar
Philippe Pébay committed
411
    this->AutoScale( viewport );
412
413
414
415
    return;
    }

  this->SetNonDependentAttributes();
Philippe Pébay's avatar
Philippe Pébay committed
416

417
  // Determine the bounds for possible use ( input, prop, or user-defined )
Philippe Pébay's avatar
Philippe Pébay committed
418
  this->GetBounds( bounds );
419
420
421
422
423
424
425
  
  // If pole coordinates are invalid, use bounds
  double o[3];
  for ( int i = 0; i < 3; ++ i )
    {
    o[i] = this->Pole[i] == VTK_DOUBLE_MAX ? bounds[i * 2] : this->Pole[i];
    }
426
427
428
429
430
431
432
433
434
  
  // 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
       || this->MaximumRadius < 1.e-6 * ls 
       || this->MaximumRadius > 1.e6 * ls )
    {
    this->MaximumRadius = .5 * ls;
    }
435

436
  // Prepare axes for rendering with user-definable options
437
  double dAlpha =  this->MaximumAngle / ( this->NumberOfRadialAxes - 1. );
438
439
  this->ComputePolarAxisTicks( this->RadialAxes[0], bounds[0], bounds[1] );

440
441
//  this->BuildLabels( this->RadialAxes );
//  this->UpdateLabels( this->RadialAxes );
Philippe Pébay's avatar
Philippe Pébay committed
442
  
443
  // Set radial axes
Philippe Pébay's avatar
Philippe Pébay committed
444
  for ( int i = 0; i < this->NumberOfRadialAxes;  ++ i )
445
    {
446
    double theta = i * dAlpha;
Philippe Pébay's avatar
Philippe Pébay committed
447
448
    double thetaRad = vtkMath::RadiansFromDegrees( theta );
    vtkAxisActor* axis = this->RadialAxes[i];
449
450
    double x = o[0] + this->MaximumRadius * cos( thetaRad );
    double y = o[1] + this->MaximumRadius * sin( thetaRad );
451
452
    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
453

454
    // Set axis ticks
455
456
    axis->SetRange( 0., this->MaximumRadius );
    axis->SetMajorTickSize( .02 * this->MaximumRadius );
457
458
459
460
461
462
463
464
465
466
467

    // Set axis title
    vtksys_ios::ostringstream thetaStream;
    thetaStream << theta;
    if ( this->RadialUnits )
      {
      thetaStream << " deg.";
      }
    axis->SetTitle( thetaStream.str().c_str() );
    }

468
  if ( this->ForceRadialLabelReset )
469
    {
470
    // Must recompute the scale
471
472
473
474
475
476
477
478
479
    double center[3];
    center[0] = ( this->Bounds[1] - this->Bounds[0] ) * 0.5;
    center[1] = ( this->Bounds[3] - this->Bounds[2] ) * 0.5;
    center[2] = ( this->Bounds[5] - this->Bounds[4] ) * 0.5;
    double bWidth  = this->Bounds[1] - this->Bounds[0];
    double bHeight = this->Bounds[3] - this->Bounds[2];
    double bLength = sqrt( bWidth * bWidth + bHeight * bHeight );
    double target = bLength * .04;

480
481
482
483
    // Label scale
    vtkAxisActor* axis = this->RadialAxes[0];
    double lenRad = axis->ComputeMaxLabelLength( center );
    double maxLabelLength = this->MaxOf( lenRad, 0.);
484
485
486
487
488
489
    this->LabelScale = 1.;
    if ( maxLabelLength > 0. )
      {
      this->LabelScale = target / maxLabelLength;
      }

490
491
492
493
    // Title scale
    double lenTitle = axis->ComputeTitleLength( center );
    double maxTitleLength = this->MaxOf( lenTitle, 0.);
    target = bLength * 0.1;
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
    this->TitleScale = 1.;
    if ( maxTitleLength > 0. )
      {
      this->TitleScale = target / maxTitleLength;
      }

    // Allow a bit bigger title if we have units, otherwise
    // the title may be too small to read.
    if ( this->RadialUnits )
      {
      this->TitleScale *= 2;
      }

    for ( int i = 0; i < this->NumberOfRadialAxes; ++ i )
      {
      axis = this->RadialAxes[i];
      axis->SetLabelScale( this->LabelScale );
      axis->SetTitleScale( this->TitleScale );
      }
513
514
515
516
517
518
519
520
521
522
523
524
525
    }

  // Scale appropriately.
  this->AutoScale( viewport );

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

// *************************************************************************
void vtkPolarAxesActor::SetNonDependentAttributes()
{
  vtkProperty *prop = this->GetProperty();
Philippe Pébay's avatar
Philippe Pébay committed
526
527
  prop->SetAmbient( 1.0 );
  prop->SetDiffuse( 0.0 );
528
529
  for ( int i = 0; i < this->NumberOfRadialAxes; ++ i )
    {
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
    vtkAxisActor* axis = this->RadialAxes[i];
    axis->SetCamera( this->Camera );
    axis->SetProperty( prop );
    axis->SetAxisLinesProperty( this->RadialAxesProperty );
    axis->SetTickLocation( this->TickLocation );
    axis->SetBounds( this->Bounds );
    axis->SetAxisVisibility( this->RadialAxesVisibility );
    axis->SetTitleVisibility( this->RadialTitleVisibility );
    axis->SetMinorTicksVisible( 0 );
    // Features available only on polar axis
    if ( ! i )
      {
      axis->SetLabelVisibility( this->PolarLabelVisibility );
      axis->SetTickVisibility( this->PolarTickVisibility );
      }
    else
      {
      axis->SetLabelVisibility( 0 );
      axis->SetTickVisibility( 0 );
      }
550
551
552
553
    }
}

// *************************************************************************
Philippe Pébay's avatar
Philippe Pébay committed
554
double vtkPolarAxesActor::MaxOf( double a, double b )
555
{
Philippe Pébay's avatar
Philippe Pébay committed
556
  return ( a > b ? a : b );
557
558
559
}

// *************************************************************************
Philippe Pébay's avatar
Philippe Pébay committed
560
inline double vtkPolarAxesActor::FFix( double value )
561
{
Philippe Pébay's avatar
Philippe Pébay committed
562
  int ivalue = static_cast<int>( value );
563
564
565
566
  return ivalue;
}

// *************************************************************************
Philippe Pébay's avatar
Philippe Pébay committed
567
inline double vtkPolarAxesActor::FSign( double value, double sign )
568
{
Philippe Pébay's avatar
Philippe Pébay committed
569
570
  value = fabs( value );
  if ( sign < 0.)
571
572
573
574
575
576
577
    {
    value *= -1.;
    }
  return value;
}

// *******************************************************************
578
579
580
void vtkPolarAxesActor::ComputePolarAxisTicks( vtkAxisActor* axis,
                                               double boundsMin, 
                                               double boundsMax )
581
582
583
{
  double sortedRange[2], range;
  double fxt, fnt, frac;
584
585
  double div, major;
  double majorStart;
586
  int numTicks;
587
  double *inRange = axis->GetRange();
588
589
590
591
592
593
594

  sortedRange[0] = inRange[0] < inRange[1] ? inRange[0] : inRange[1];
  sortedRange[1] = inRange[0] > inRange[1] ? inRange[0] : inRange[1];

  range = sortedRange[1] - sortedRange[0];

  // Find the integral points.
Philippe Pébay's avatar
Philippe Pébay committed
595
  double pow10 = log10( range );
596
597

  // Build in numerical tolerance
Philippe Pébay's avatar
Philippe Pébay committed
598
  if ( pow10 != 0.)
599
600
    {
    double eps = 10.0e-10;
Philippe Pébay's avatar
Philippe Pébay committed
601
    pow10 = this->FSign( ( fabs( pow10 ) + eps ), pow10 );
602
603
    }

604
  // FFix will move in the wrong direction if pow10 is negative.
Philippe Pébay's avatar
Philippe Pébay committed
605
  if ( pow10 < 0.)
606
607
608
609
    {
    pow10 = pow10 - 1.;
    }

Philippe Pébay's avatar
Philippe Pébay committed
610
  fxt = pow( 10., this->FFix( pow10 ) );
611
612
613

  // Find the number of integral points in the interval.
  fnt  = range/fxt;
Philippe Pébay's avatar
Philippe Pébay committed
614
  fnt  = this->FFix( fnt );
615
  frac = fnt;
Philippe Pébay's avatar
Philippe Pébay committed
616
  numTicks = frac <= 0.5 ? static_cast<int>( this->FFix( fnt ) ) : static_cast<int>( this->FFix( fnt ) + 1 );
617
618

  div = 1.;
Philippe Pébay's avatar
Philippe Pébay committed
619
  if ( numTicks < 5 )
620
621
622
    {
    div = 2.;
    }
Philippe Pébay's avatar
Philippe Pébay committed
623
  if ( numTicks <= 2 )
624
625
626
627
628
629
630
    {
    div = 5.;
    }

  // If there aren't enough major tick points in this decade, use the next
  // decade.
  major = fxt;
Philippe Pébay's avatar
Philippe Pébay committed
631
  if ( div != 1.)
632
633
634
635
    {
    major /= div;
    }

636
  // Figure out the first major tick locations, relative to the
637
  // start of the axis.
Philippe Pébay's avatar
Philippe Pébay committed
638
  if ( sortedRange[0] <= 0.)
639
    {
640
    majorStart = major * ( this->FFix( sortedRange[0]*( 1./major ) ) + 0. );
641
642
643
    }
  else
    {
644
    majorStart = major * ( this->FFix( sortedRange[0]*( 1./major ) ) + 1. );
645
646
    }

647
648
  axis->SetMajorRangeStart( majorStart );
  axis->SetDeltaRangeMajor( major );
649

650
651
  double t = ( majorStart - sortedRange[0] ) / range;
  majorStart = t * boundsMax + ( 1. - t ) * boundsMin;
Philippe Pébay's avatar
Philippe Pébay committed
652
  const double scale = ( boundsMax - boundsMin ) / range;
653
654
  major *= scale;

655
656
657
  // Set major start and deltas
  axis->SetMajorStart( VTK_AXIS_TYPE_X, majorStart );
  axis->SetDeltaMajor( VTK_AXIS_TYPE_X, major );
658
659
660
661
662
663
664
665
666
667
}

// ****************************************************************
void vtkPolarAxesActor::AutoScale( vtkViewport *viewport )
{
  // Current implementation only for perspective projections.
  this->AutoScale( viewport, this->RadialAxes );
}

// ****************************************************************
668
669
void vtkPolarAxesActor::AutoScale( vtkViewport *viewport, 
                                   vtkAxisActor** axis )
670
{
671
672
673
  double newTitleScale = this->TitleScale;

  // Loop over radial axes
674
675
  for ( int i = 0; i < this->NumberOfRadialAxes; ++ i )
    {
676
677
678
679
680
681
682
683
    // Scale title
    newTitleScale = this->AutoScale( viewport, 
                                     this->ScreenSize,
                                     axis[i]->GetTitleActor()->GetPosition() );

    axis[i]->SetTitleScale( newTitleScale );

    // Scale labels
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
    vtkAxisFollower** labelActors = axis[i]->GetLabelActors();

    for( int j = 0; j < axis[i]->GetNumberOfLabelsBuilt(); ++ j )
      {
      double newLabelScale = this->AutoScale( viewport, 
                                              this->ScreenSize,
                                              labelActors[j]->GetPosition() );

      labelActors[j]->SetScale( newLabelScale );
      }
    }
}

// ****************************************************************
double vtkPolarAxesActor::AutoScale( vtkViewport *viewport, 
                                     double screenSize,
                                     double position[3] )
{
  double factor = 1;
Philippe Pébay's avatar
Philippe Pébay committed
703
  if ( viewport->GetSize()[1] > 0 )
704
705
    {
    factor = 2.0 * screenSize
Philippe Pébay's avatar
Philippe Pébay committed
706
      * tan( vtkMath::RadiansFromDegrees( this->Camera->GetViewAngle()/2.0 ) )
707
708
709
710
      / viewport->GetSize()[1];
    }

    double dist = sqrt(
Philippe Pébay's avatar
Philippe Pébay committed
711
712
          vtkMath::Distance2BetweenPoints( position,
                                          this->Camera->GetPosition() ));
713
714
715
716
717
718
719
720
721
722
    double newScale = factor * dist;

    return newScale;
}

// ****************************************************************
void vtkPolarAxesActor::BuildLabels( vtkAxisActor** axes )
{
  char label[64];
  int i, labelCount = 0;
Philippe Pébay's avatar
Philippe Pébay committed
723
  double deltaMajor = axes[0]->GetDeltaMajor( axes[0]->GetAxisType() );
724
725
  const double *p2  = axes[0]->GetPoint2Coordinate()->GetValue();
  double *range     = axes[0]->GetRange();
Philippe Pébay's avatar
Philippe Pébay committed
726
  double lastVal = 0, val = axes[0]->GetMajorStart( axes[0]->GetAxisType() );
727
728
729
730
731
  double extents = range[1] - range[0];
  bool mustAdjustValue = 0;
  int lastPow = 0;

  vtkStringArray *labels = vtkStringArray::New();
732
  const char *format = this->RadialLabelFormat;
733
734
735
736
737
  lastVal = p2[0];
  mustAdjustValue = this->MustAdjustRadialValue;
  lastPow = this->LastRadialPow;

  // figure out how many labels we need:
Philippe Pébay's avatar
Philippe Pébay committed
738
  while ( val <= lastVal && labelCount < VTK_MAX_LABELS )
739
740
741
742
743
    {
    labelCount++;
    val += deltaMajor;
    }

Philippe Pébay's avatar
Philippe Pébay committed
744
  labels->SetNumberOfValues( labelCount );
745
746
747
748
749

  val = axes[0]->GetMajorRangeStart();
  deltaMajor = axes[0]->GetDeltaRangeMajor();

  double scaleFactor = 1.;
Philippe Pébay's avatar
Philippe Pébay committed
750
  if ( lastPow != 0 )
751
    {
Philippe Pébay's avatar
Philippe Pébay committed
752
    scaleFactor = 1.0/pow( 10., lastPow );
753
754
    }

Philippe Pébay's avatar
Philippe Pébay committed
755
  for ( i = 0; i < labelCount; ++ i )
756
    {
Philippe Pébay's avatar
Philippe Pébay committed
757
    if ( fabs( val ) < 0.01 && extents > 1 )
758
759
760
761
762
      {
      // We just happened to fall at something near zero and the range is
      // large, so set it to zero to avoid ugliness.
      val = 0.;
      }
Philippe Pébay's avatar
Philippe Pébay committed
763
    if ( mustAdjustValue )
764
      {
Philippe Pébay's avatar
Philippe Pébay committed
765
      sprintf( label, format, val*scaleFactor );
766
767
768
      }
    else
      {
Philippe Pébay's avatar
Philippe Pébay committed
769
      sprintf( label, format, val );
770
      }
Philippe Pébay's avatar
Philippe Pébay committed
771
    if ( fabs( val ) < 0.01 )
772
773
774
775
776
      {
      //
      // Ensure that -0.0 is never a label
      // The maximum number of digits that we allow past the decimal is 5.
      //
777
      if ( strcmp( label, "-0" ) == 0 )
778
        {
779
        sprintf( label, "0" );
780
        }
781
      else if ( strcmp( label, "-0.0" ) == 0 )
782
        {
783
        sprintf( label, "0.0" );
784
        }
785
      else if ( strcmp( label, "-0.00" ) == 0 )
786
        {
787
        sprintf( label, "0.00" );
788
        }
789
      else if ( strcmp( label, "-0.000" ) == 0 )
790
        {
791
        sprintf( label, "0.000" );
792
        }
793
      else if ( strcmp( label, "-0.0000" ) == 0 )
794
        {
795
        sprintf( label, "0.0000" );
796
        }
797
      else if ( strcmp( label, "-0.00000" ) == 0 )
798
        {
799
        sprintf( label, "0.00000" );
800
801
        }
      }
Philippe Pébay's avatar
Philippe Pébay committed
802
    labels->SetValue( i, label );
803
804
    val += deltaMajor;
    }
Philippe Pébay's avatar
Philippe Pébay committed
805
  for ( i = 0; i < this->NumberOfRadialAxes; ++ i )
806
    {
Philippe Pébay's avatar
Philippe Pébay committed
807
    axes[i]->SetLabels( labels );
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
    }
  labels->Delete();
}

// ****************************************************************************
void vtkPolarAxesActor::SetLabelScaling( bool autoscale, int upow )
{
  if ( autoscale != this->AutoLabelScaling || upow != this->UserRadialPow )
    {
    this->AutoLabelScaling = autoscale;
    this->UserRadialPow = upow;
    this->Modified();
    }
}

// ****************************************************************************
void vtkPolarAxesActor::UpdateLabels( vtkAxisActor** axis )
  {
  for ( int i = 0; i < this->NumberOfRadialAxes; ++ i )
    {
    int numberOfLabelsBuilt = axis[i]->GetNumberOfLabelsBuilt();
    vtkAxisFollower** labelActors = axis[i]->GetLabelActors();
    for( int k = 0; k < numberOfLabelsBuilt; ++ k )
      {
832
      labelActors[k]->SetAxis( this->RadialAxes[i] );
Philippe Pébay's avatar
Philippe Pébay committed
833
      labelActors[k]->SetScreenOffset( this->LabelScreenOffset );
834
835
836
837
      }
    }
  }
// ****************************************************************************
Philippe Pébay's avatar
Philippe Pébay committed
838
void vtkPolarAxesActor::SetRadialAxesProperty( vtkProperty *prop )
839
{
Philippe Pébay's avatar
Philippe Pébay committed
840
  this->RadialAxesProperty->DeepCopy( prop );
841
842
843
844
845
846
847
848
  this->Modified();
}

// ****************************************************************************
vtkProperty* vtkPolarAxesActor::GetRadialAxesProperty()
{
  return this->RadialAxesProperty;
}