source: trunk/packages/vizservers/vtkvis/vtkRpAxisActor2D.cpp @ 2973

Last change on this file since 2973 was 2864, checked in by ldelgass, 13 years ago

Include custom version of VTK 3d axes, with fix for showing gridlines only on
active axis planes. Also include a copy of 2D/3D axis classes, though these
are not currently customized. Based on VTK 5.8.0.

  • Property svn:eol-style set to native
File size: 28.1 KB
Line 
1/*=========================================================================
2
3  Program:   Visualization Toolkit
4  Module:    vtkRpAxisActor2D.cxx
5
6  Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
7  All rights reserved.
8  See Copyright.txt or http://www.kitware.com/Copyright.htm for details.
9
10     This software is distributed WITHOUT ANY WARRANTY; without even
11     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
12     PURPOSE.  See the above copyright notice for more information.
13
14=========================================================================*/
15#include "vtkRpAxisActor2D.h"
16
17#include "vtkCellArray.h"
18#include "vtkObjectFactory.h"
19#include "vtkPolyData.h"
20#include "vtkPolyDataMapper2D.h"
21#include "vtkTextMapper.h"
22#include "vtkTextProperty.h"
23#include "vtkViewport.h"
24#include "vtkWindow.h"
25#include "vtkMath.h"
26
27vtkStandardNewMacro(vtkRpAxisActor2D);
28
29vtkCxxSetObjectMacro(vtkRpAxisActor2D,LabelTextProperty,vtkTextProperty);
30vtkCxxSetObjectMacro(vtkRpAxisActor2D,TitleTextProperty,vtkTextProperty);
31
32//----------------------------------------------------------------------------
33// Instantiate this object.
34vtkRpAxisActor2D::vtkRpAxisActor2D()
35{
36  this->PositionCoordinate->SetCoordinateSystemToNormalizedViewport();
37  this->PositionCoordinate->SetValue(0.0, 0.0);
38
39  this->Position2Coordinate->SetCoordinateSystemToNormalizedViewport();
40  this->Position2Coordinate->SetValue(0.75, 0.0);
41  this->Position2Coordinate->SetReferenceCoordinate(NULL);
42
43  this->NumberOfLabels = 5;
44
45  this->Title = NULL;
46
47  this->TitlePosition = 0.5;
48
49  this->AdjustLabels = 1;
50
51  this->TickLength = 5;
52  this->MinorTickLength = 3;
53  this->TickOffset = 2;
54  this->NumberOfMinorTicks = 0;
55
56  this->Range[0] = 0.0;
57  this->Range[1] = 1.0;
58
59  this->FontFactor = 1.0;
60  this->LabelFactor = 0.75;
61
62  this->SizeFontRelativeToAxis = 0;
63
64  this->RulerMode = 0;
65  this->RulerDistance = 1.0;
66
67  this->LabelTextProperty = vtkTextProperty::New();
68  this->LabelTextProperty->SetBold(1);
69  this->LabelTextProperty->SetItalic(1);
70  this->LabelTextProperty->SetShadow(1);
71  this->LabelTextProperty->SetFontFamilyToArial();
72
73  this->TitleTextProperty = vtkTextProperty::New();
74  this->TitleTextProperty->ShallowCopy(this->LabelTextProperty);
75
76  this->LabelFormat = new char[8];
77  sprintf(this->LabelFormat,"%s","%-#6.3g");
78
79  this->TitleMapper = vtkTextMapper::New();
80  this->TitleActor = vtkActor2D::New();
81  this->TitleActor->SetMapper(this->TitleMapper);
82
83  // To avoid deleting/rebuilding create once up front
84  this->NumberOfLabelsBuilt = 0;
85  this->LabelMappers = new vtkTextMapper * [VTK_MAX_LABELS];
86  this->LabelActors = new vtkActor2D * [VTK_MAX_LABELS];
87  for ( int i=0; i < VTK_MAX_LABELS; i++)
88    {
89    this->LabelMappers[i] = vtkTextMapper::New();
90    this->LabelActors[i] = vtkActor2D::New();
91    this->LabelActors[i]->SetMapper(this->LabelMappers[i]);
92    }
93
94  this->Axis = vtkPolyData::New();
95  this->AxisMapper = vtkPolyDataMapper2D::New();
96  this->AxisMapper->SetInput(this->Axis);
97  this->AxisActor = vtkActor2D::New();
98  this->AxisActor->SetMapper(this->AxisMapper);
99
100  this->AxisVisibility = 1;
101  this->TickVisibility = 1;
102  this->LabelVisibility = 1;
103  this->TitleVisibility = 1;
104
105  this->LastPosition[0] = this->LastPosition[1] = 0;
106  this->LastPosition2[0] = this->LastPosition2[1] = 0;
107
108  this->LastSize[0] = this->LastSize[1] = 0;
109  this->LastMaxLabelSize[0] = this->LastMaxLabelSize[1] = 0;
110}
111
112//----------------------------------------------------------------------------
113vtkRpAxisActor2D::~vtkRpAxisActor2D()
114{
115  if (this->LabelFormat)
116    {
117    delete [] this->LabelFormat;
118    this->LabelFormat = NULL;
119    }
120
121  this->TitleMapper->Delete();
122  this->TitleActor->Delete();
123
124  if (this->Title)
125    {
126    delete [] this->Title;
127    this->Title = NULL;
128    }
129
130  if (this->LabelMappers != NULL )
131    {
132    for (int i=0; i < VTK_MAX_LABELS; i++)
133      {
134      this->LabelMappers[i]->Delete();
135      this->LabelActors[i]->Delete();
136      }
137    delete [] this->LabelMappers;
138    delete [] this->LabelActors;
139    }
140
141  this->Axis->Delete();
142  this->AxisMapper->Delete();
143  this->AxisActor->Delete();
144
145  this->SetLabelTextProperty(NULL);
146  this->SetTitleTextProperty(NULL);
147}
148
149//----------------------------------------------------------------------------
150// Build the axis, ticks, title, and labels and render.
151
152int vtkRpAxisActor2D::RenderOpaqueGeometry(vtkViewport *viewport)
153{
154  int i, renderedSomething=0;
155
156  this->BuildAxis(viewport);
157
158  // Everything is built, just have to render
159  if ( this->Title != NULL && this->Title[0] != 0 && this->TitleVisibility )
160    {
161    renderedSomething += this->TitleActor->RenderOpaqueGeometry(viewport);
162    }
163
164  if ( this->AxisVisibility || this->TickVisibility )
165    {
166    renderedSomething += this->AxisActor->RenderOpaqueGeometry(viewport);
167    }
168
169  if ( this->LabelVisibility )
170    {
171    for (i=0; i<this->NumberOfLabelsBuilt; i++)
172      {
173      renderedSomething +=
174        this->LabelActors[i]->RenderOpaqueGeometry(viewport);
175      }
176    }
177
178  return renderedSomething;
179}
180
181//----------------------------------------------------------------------------
182// Render the axis, ticks, title, and labels.
183
184int vtkRpAxisActor2D::RenderOverlay(vtkViewport *viewport)
185{
186  int i, renderedSomething=0;
187
188  // Everything is built, just have to render
189  if ( this->Title != NULL && this->Title[0] != 0 && this->TitleVisibility )
190    {
191    renderedSomething += this->TitleActor->RenderOverlay(viewport);
192    }
193
194  if ( this->AxisVisibility || this->TickVisibility )
195    {
196    renderedSomething += this->AxisActor->RenderOverlay(viewport);
197    }
198
199  if ( this->LabelVisibility )
200    {
201    for (i=0; i<this->NumberOfLabelsBuilt; i++)
202      {
203      renderedSomething += this->LabelActors[i]->RenderOverlay(viewport);
204      }
205    }
206
207  return renderedSomething;
208}
209
210//-----------------------------------------------------------------------------
211// Description:
212// Does this prop have some translucent polygonal geometry?
213int vtkRpAxisActor2D::HasTranslucentPolygonalGeometry()
214{
215  return 0;
216}
217
218//----------------------------------------------------------------------------
219// Release any graphics resources that are being consumed by this actor.
220// The parameter window could be used to determine which graphic
221// resources to release.
222void vtkRpAxisActor2D::ReleaseGraphicsResources(vtkWindow *win)
223{
224  this->TitleActor->ReleaseGraphicsResources(win);
225  for (int i=0; i < VTK_MAX_LABELS; i++)
226    {
227    this->LabelActors[i]->ReleaseGraphicsResources(win);
228    }
229  this->AxisActor->ReleaseGraphicsResources(win);
230}
231
232//----------------------------------------------------------------------------
233void vtkRpAxisActor2D::PrintSelf(ostream& os, vtkIndent indent)
234{
235  this->Superclass::PrintSelf(os,indent);
236
237  if (this->TitleTextProperty)
238    {
239    os << indent << "Title Text Property:\n";
240    this->TitleTextProperty->PrintSelf(os,indent.GetNextIndent());
241    }
242  else
243    {
244    os << indent << "Title Text Property: (none)\n";
245    }
246
247  if (this->LabelTextProperty)
248    {
249    os << indent << "Label Text Property:\n";
250    this->LabelTextProperty->PrintSelf(os,indent.GetNextIndent());
251    }
252  else
253    {
254    os << indent << "Label Text Property: (none)\n";
255    }
256
257  os << indent << "Title: " << (this->Title ? this->Title : "(none)") << "\n";
258  os << indent << "Ruler Mode: "
259     << (this->RulerMode ? "On" : "Off") <<"\n";
260  os << indent << "Ruler Distance: " << this->GetRulerDistance() <<"\n";
261  os << indent << "Number Of Labels: " << this->NumberOfLabels << "\n";
262  os << indent << "Number Of Labels Built: "
263     << this->NumberOfLabelsBuilt << "\n";
264  os << indent << "Range: (" << this->Range[0]
265     << ", " << this->Range[1] << ")\n";
266
267  os << indent << "Label Format: " << this->LabelFormat << "\n";
268  os << indent << "Font Factor: " << this->FontFactor << "\n";
269  os << indent << "Label Factor: " << this->LabelFactor << "\n";
270  os << indent << "Tick Length: " << this->TickLength << "\n";
271  os << indent << "Tick Offset: " << this->TickOffset << "\n";
272
273  os << indent << "Adjust Labels: "
274     << (this->AdjustLabels ? "On\n" : "Off\n");
275
276  os << indent << "Axis Visibility: "
277     << (this->AxisVisibility ? "On\n" : "Off\n");
278
279  os << indent << "Tick Visibility: "
280     << (this->TickVisibility ? "On\n" : "Off\n");
281
282  os << indent << "Label Visibility: "
283     << (this->LabelVisibility ? "On\n" : "Off\n");
284
285  os << indent << "Title Visibility: "
286     << (this->TitleVisibility ? "On\n" : "Off\n");
287
288  os << indent << "MinorTickLength: " << this->MinorTickLength << endl;
289  os << indent << "NumberOfMinorTicks: " << this->NumberOfMinorTicks
290     << endl;
291  os << indent << "TitlePosition: " << this->TitlePosition << endl;
292
293  os << indent << "Size Font Relative To Axis: "
294     << (this->SizeFontRelativeToAxis ? "On\n" : "Off\n");
295}
296
297//----------------------------------------------------------------------------
298void vtkRpAxisActor2D::BuildAxis(vtkViewport *viewport)
299{
300  int i, *x, viewportSizeHasChanged, positionsHaveChanged;
301  vtkIdType ptIds[2];
302  double p1[3], p2[3], offset;
303  double interval, deltaX, deltaY;
304  double xTick[3];
305  double theta, val;
306  int *size, stringSize[2];
307  char string[512];
308
309  if (this->TitleVisibility && !this->TitleTextProperty)
310    {
311    vtkErrorMacro(<<"Need title text property to render axis actor");
312    return;
313    }
314
315  if (this->LabelVisibility && !this->LabelTextProperty)
316    {
317    vtkErrorMacro(<<"Need label text property to render axis actor");
318    return;
319    }
320
321  // Check to see whether we have to rebuild everything
322  // Viewport change may not require rebuild
323  positionsHaveChanged = 0;
324  int *lastPosition =
325    this->PositionCoordinate->GetComputedViewportValue(viewport);
326  int *lastPosition2 =
327    this->Position2Coordinate->GetComputedViewportValue(viewport);
328  if (lastPosition[0] != this->LastPosition[0] ||
329      lastPosition[1] != this->LastPosition[1] ||
330      lastPosition2[0] != this->LastPosition2[0] ||
331      lastPosition2[1] != this->LastPosition2[1] )
332    {
333    positionsHaveChanged = 1;
334    }
335
336  // See whether fonts have to be rebuilt (font size depends on viewport size)
337  viewportSizeHasChanged = 0;
338  size = viewport->GetSize();
339  if (this->LastSize[0] != size[0] || this->LastSize[1] != size[1])
340    {
341    viewportSizeHasChanged = 1;
342    this->LastSize[0] = size[0];
343    this->LastSize[1] = size[1];
344    }
345
346  if ( ! viewport->GetVTKWindow() ||
347       (!positionsHaveChanged && !viewportSizeHasChanged &&
348        viewport->GetMTime() < this->BuildTime &&
349        viewport->GetVTKWindow()->GetMTime() < this->BuildTime &&
350        this->GetMTime() < this->BuildTime &&
351        (!this->LabelVisibility ||
352         this->LabelTextProperty->GetMTime() < this->BuildTime) &&
353        (!this->TitleVisibility ||
354         this->TitleTextProperty->GetMTime() < this->BuildTime)) )
355    {
356    return;
357    }
358
359  vtkDebugMacro(<<"Rebuilding axis");
360
361  // Initialize and get important info
362  this->Axis->Initialize();
363  this->AxisActor->SetProperty(this->GetProperty());
364  this->TitleActor->SetProperty(this->GetProperty());
365
366  // Compute the location of tick marks and labels
367
368  this->UpdateAdjustedRange();
369
370  interval = (this->AdjustedRange[1] - this->AdjustedRange[0]) / (this->AdjustedNumberOfLabels - 1);
371
372  this->NumberOfLabelsBuilt = this->AdjustedNumberOfLabels;
373
374  // Generate the axis and tick marks.
375  // We'll do our computation in viewport coordinates. First determine the
376  // location of the endpoints.
377  x = this->PositionCoordinate->GetComputedViewportValue(viewport);
378  p1[0] = x[0];
379  p1[1] = x[1];
380  p1[2] = 0.0;
381  this->LastPosition[0] = x[0];
382  this->LastPosition[1] = x[1];
383
384  x = this->Position2Coordinate->GetComputedViewportValue(viewport);
385  p2[0] = x[0];
386  p2[1] = x[1];
387  p2[2] = 0.0;
388  this->LastPosition2[0] = x[0];
389  this->LastPosition2[1] = x[1];
390
391  double *xp1, *xp2, len=0.0;
392  if ( this->SizeFontRelativeToAxis )
393    {
394    xp1 = this->PositionCoordinate->GetComputedDoubleDisplayValue(viewport);
395    xp2 = this->Position2Coordinate->GetComputedDoubleViewportValue(viewport);
396    len = sqrt((xp2[0]-xp1[0])*(xp2[0]-xp1[0]) + (xp2[1]-xp1[1])*(xp2[1]-xp1[1]));
397    }
398
399  vtkPoints *pts = vtkPoints::New();
400  vtkCellArray *lines = vtkCellArray::New();
401  this->Axis->SetPoints(pts);
402  this->Axis->SetLines(lines);
403  pts->Delete();
404  lines->Delete();
405
406  // Generate point along axis (as well as tick points)
407  deltaX = p2[0] - p1[0];
408  deltaY = p2[1] - p1[1];
409
410  if (deltaX == 0. && deltaY == 0.)
411    {
412    theta = 0.;
413    }
414  else
415    {
416    theta = atan2(deltaY, deltaX);
417    }
418
419  // First axis point, where first tick is located
420  ptIds[0] = pts->InsertNextPoint(p1);
421  xTick[0] = p1[0] + this->TickLength*sin(theta);
422  xTick[1] = p1[1] - this->TickLength*cos(theta);
423  xTick[2] = 0.0;
424  pts->InsertNextPoint(xTick);
425
426  // Set up creation of ticks
427  double p21[3], length;
428  p21[0] = p2[0] - p1[0];
429  p21[1] = p2[1] - p1[1];
430  p21[2] = p2[2] - p1[2];
431  length = vtkMath::Normalize(p21);
432
433  int numTicks;
434  double distance;
435  if ( this->RulerMode )
436    {
437    double wp1[3], wp2[3], wp21[3], wLength, wDistance;
438    this->PositionCoordinate->GetValue(wp1);
439    this->Position2Coordinate->GetValue(wp2);
440    wp21[0] = wp2[0] - wp1[0];
441    wp21[1] = wp2[1] - wp1[1];
442    wp21[2] = wp2[2] - wp1[2];
443    wLength = vtkMath::Norm(wp21);
444    wDistance = this->RulerDistance / (this->NumberOfMinorTicks+1);
445    numTicks = (wDistance <= 0.0 ? 0 : static_cast<int>(wLength / wDistance)+1);
446    wDistance *= numTicks;
447    distance = (length / (numTicks-1)) * (wDistance/wLength);
448    }
449  else
450    {
451    numTicks = (this->AdjustedNumberOfLabels-1) *
452      (this->NumberOfMinorTicks+1) + 1;
453    distance = length / (numTicks-1);
454    }
455
456  for (i = 1; i < numTicks - 1; i++)
457    {
458    int tickLength = 0;
459    if ( i % (this->NumberOfMinorTicks+1) == 0 )
460      {
461      tickLength = this->TickLength;
462      }
463    else
464      {
465      tickLength = this->MinorTickLength;
466      }
467    xTick[0] = p1[0] + i * p21[0] * distance;
468    xTick[1] = p1[1] + i * p21[1] * distance;
469    pts->InsertNextPoint(xTick);
470    xTick[0] = xTick[0] + tickLength * sin(theta);
471    xTick[1] = xTick[1] - tickLength * cos(theta);
472    pts->InsertNextPoint(xTick);
473    }
474
475  // Last axis point
476  ptIds[1] = pts->InsertNextPoint(p2);
477  xTick[0] = p2[0] + this->TickLength*sin(theta);
478  xTick[1] = p2[1] - this->TickLength*cos(theta);
479  pts->InsertNextPoint(xTick);
480
481  // Add the axis if requested
482  if (this->AxisVisibility)
483    {
484    lines->InsertNextCell(2, ptIds);
485    }
486
487  // Create lines representing the tick marks
488  if (this->TickVisibility)
489    {
490    for (i = 0; i < numTicks; i++)
491      {
492      ptIds[0] = 2*i;
493      ptIds[1] = 2*i + 1;
494      lines->InsertNextCell(2, ptIds);
495      }
496    }
497
498  // Build the labels
499  if (this->LabelVisibility)
500    {
501    // Update the labels text. Do it only if the range has been adjusted,
502    // i.e. if we think that new labels must be created.
503    // WARNING: if LabelFormat has changed, they should be recreated too
504    // but at this point the check on LabelFormat is "included" in
505    // UpdateAdjustedRange(), which is the function that update
506    // AdjustedRangeBuildTime or not.
507    unsigned long labeltime = this->AdjustedRangeBuildTime;
508    if (this->AdjustedRangeBuildTime > this->BuildTime)
509      {
510      for (i = 0; i < this->AdjustedNumberOfLabels; i++)
511        {
512        val = this->AdjustedRange[0] + i * interval;
513        sprintf(string, this->LabelFormat, val);
514        this->LabelMappers[i]->SetInput(string);
515
516        // Check if the label text has changed
517
518        if (this->LabelMappers[i]->GetMTime() > labeltime)
519          {
520          labeltime = this->LabelMappers[i]->GetMTime();
521          }
522        }
523      }
524
525    // Copy prop and text prop eventually
526    for (i = 0; i < this->AdjustedNumberOfLabels; i++)
527        {
528        this->LabelActors[i]->SetProperty(this->GetProperty());
529        if (this->LabelTextProperty->GetMTime() > this->BuildTime ||
530            this->AdjustedRangeBuildTime > this->BuildTime)
531          {
532          // Shallow copy here so that the size of the label prop is not
533          // affected by the automatic adjustment of its text mapper's
534          // size (i.e. its mapper's text property is identical except
535          // for the font size which will be modified later). This
536          // allows text actors to share the same text property, and in
537          // that case specifically allows the title and label text prop
538          // to be the same.
539          this->LabelMappers[i]->GetTextProperty()->ShallowCopy(
540            this->LabelTextProperty);
541          }
542        }
543
544    // Resize the mappers if needed (i.e. viewport has changed, than
545    // font size should be changed, or label text property has changed,
546    // or some of the labels have changed (got bigger for example)
547    if (positionsHaveChanged || viewportSizeHasChanged ||
548        this->LabelTextProperty->GetMTime() > this->BuildTime ||
549        labeltime > this->BuildTime)
550      {
551      if ( ! this->SizeFontRelativeToAxis )
552        {
553        vtkTextMapper::SetMultipleRelativeFontSize(viewport,
554                                                   this->LabelMappers,
555                                                   this->AdjustedNumberOfLabels,
556                                                   size,
557                                                   this->LastMaxLabelSize,
558                                                   0.015*this->FontFactor*this->LabelFactor);
559        }
560      else
561        {
562         int minFontSize=1000, fontSize, minLabel=0;
563         for (i = 0; i < this->AdjustedNumberOfLabels; i++)
564          {
565          fontSize = this->LabelMappers[i]->
566            SetConstrainedFontSize(viewport,
567                                   static_cast<int>((1.0/this->AdjustedNumberOfLabels)*len),
568                                   static_cast<int>(0.2*len) );
569          if ( fontSize < minFontSize )
570            {
571            minFontSize = fontSize;
572            minLabel = i;
573            }
574          }
575         for (i=0; i<this->AdjustedNumberOfLabels; i++)
576           {
577           this->LabelMappers[i]->GetTextProperty()->SetFontSize(minFontSize);
578           }
579         this->LabelMappers[minLabel]->GetSize(viewport,this->LastMaxLabelSize);
580        }
581      }
582
583    // Position the mappers
584    for (i = 0; i < this->AdjustedNumberOfLabels; i++)
585      {
586      pts->GetPoint((this->NumberOfMinorTicks+1) * 2 * i + 1, xTick);
587      this->LabelMappers[i]->GetSize(viewport, stringSize);
588      this->SetOffsetPosition(xTick,
589                              theta,
590                              this->LastMaxLabelSize[0],
591                              this->LastMaxLabelSize[1],
592                              this->TickOffset,
593                              this->LabelActors[i]);
594      }
595    } // If labels visible
596
597  // Now build the title
598  if (this->Title != NULL && this->Title[0] != 0 && this->TitleVisibility)
599    {
600    this->TitleMapper->SetInput(this->Title);
601
602    if (this->TitleTextProperty->GetMTime() > this->BuildTime)
603      {
604      // Shallow copy here so that the size of the title prop is not
605      // affected by the automatic adjustment of its text mapper's
606      // size (i.e. its mapper's text property is identical except for
607      // the font size which will be modified later). This allows text
608      // actors to share the same text property, and in that case
609      // specifically allows the title and label text prop to be the same.
610      this->TitleMapper->GetTextProperty()->ShallowCopy(
611        this->TitleTextProperty);
612      }
613
614    if (positionsHaveChanged || viewportSizeHasChanged ||
615        this->TitleTextProperty->GetMTime() > this->BuildTime)
616      {
617      if ( ! this->SizeFontRelativeToAxis )
618        {
619        vtkTextMapper::SetRelativeFontSize(this->TitleMapper, viewport, size, stringSize, 0.015*this->FontFactor);
620        }
621      else
622        {
623        this->TitleMapper->SetConstrainedFontSize(viewport,
624                                                  static_cast<int>(0.33*len),
625                                                  static_cast<int>(0.2*len) );
626        this->TitleMapper->GetSize(viewport, stringSize);
627        }
628      }
629    else
630      {
631      this->TitleMapper->GetSize(viewport, stringSize);
632      }
633
634    xTick[0] = p1[0] + (p2[0] - p1[0]) * this->TitlePosition;
635    xTick[1] = p1[1] + (p2[1] - p1[1]) * this->TitlePosition;
636    xTick[0] = xTick[0] + (this->TickLength + this->TickOffset) * sin(theta);
637    xTick[1] = xTick[1] - (this->TickLength + this->TickOffset) * cos(theta);
638
639    offset = 0.0;
640    if (this->LabelVisibility)
641      {
642      offset = this->ComputeStringOffset(this->LastMaxLabelSize[0],
643                                         this->LastMaxLabelSize[1],
644                                         theta);
645      }
646
647    this->SetOffsetPosition(xTick,
648                            theta,
649                            stringSize[0],
650                            stringSize[1],
651                            static_cast<int>(offset),
652                            this->TitleActor);
653    } // If title visible
654
655  this->BuildTime.Modified();
656}
657
658
659//----------------------------------------------------------------------------
660void vtkRpAxisActor2D::UpdateAdjustedRange()
661{
662  // Try not to update/adjust the range to often, do not update it
663  // if the object has not been modified.
664  // Nevertheless, try the following optimization: there is no need to
665  // update the range if the position coordinate of this actor have
666  // changed. But since vtkActor2D::GetMTime() includes the check for
667  // both Position and Position2 coordinates, we will have to bypass
668  // it.
669
670  if (this->vtkActor2D::Superclass::GetMTime() <= this->AdjustedRangeBuildTime)
671    {
672    return;
673    }
674
675  if ( this->AdjustLabels )
676    {
677    double interval;
678    this->ComputeRange(this->Range,
679                       this->AdjustedRange,
680                       this->NumberOfLabels,
681                       this->AdjustedNumberOfLabels,
682                       interval);
683    }
684  else
685    {
686    this->AdjustedNumberOfLabels = this->NumberOfLabels;
687    this->AdjustedRange[0] = this->Range[0];
688    this->AdjustedRange[1] = this->Range[1];
689    }
690  this->AdjustedRangeBuildTime.Modified();
691}
692
693// this is a helper function that computes some useful functions
694// for an axis. It returns the number of ticks
695int vtkRpAxisActor2DComputeTicks(double sRange[2], double &interval,
696                               double &root)
697{
698  // first we try assuming the first value is reasonable
699  int numTicks;
700  double range    = fabs(sRange[1]-sRange[0]);
701  int rootPower   = static_cast<int>(floor(log10(range)-1));
702  root     = pow(10.0,rootPower);
703  // val will be between 10 and 100 inclusive of 10 but not 100
704  double val      = range/root;
705  // first we check for an exact match
706  for (numTicks = 5; numTicks < 9; ++numTicks)
707    {
708    if (fabs(val/(numTicks-1.0) - floor(val/(numTicks-1.0))) < .0001)
709      {
710      interval = val*root/(numTicks-1.0);
711      return numTicks;
712      }
713    }
714
715  // if there isn't an exact match find a reasonable value
716  int newIntScale = 10;
717  if (val > 10)
718    {
719    newIntScale = 12;
720    }
721  if (val > 12)
722    {
723    newIntScale = 15;
724    }
725  if (val > 15)
726    {
727    newIntScale = 18;
728    }
729  if (val > 18)
730    {
731    newIntScale = 20;
732    }
733  if (val > 20)
734    {
735    newIntScale = 25;
736    }
737  if (val > 25)
738    {
739    newIntScale = 30;
740    }
741  if (val > 30)
742    {
743    newIntScale = 40;
744    }
745  if (val > 40)
746    {
747    newIntScale = 50;
748    }
749  if (val > 50)
750    {
751    newIntScale = 60;
752    }
753  if (val > 60)
754    {
755    newIntScale = 70;
756    }
757  if (val > 70)
758    {
759    newIntScale = 80;
760    }
761  if (val > 80)
762    {
763    newIntScale = 90;
764    }
765  if (val > 90)
766    {
767    newIntScale = 100;
768    }
769
770  // how many ticks should we have
771  switch (newIntScale)
772    {
773    case 12:
774    case 20:
775    case 40:
776    case 80:
777      numTicks = 5;
778      break;
779    case 18:
780    case 30:
781    case 60:
782    case 90:
783      numTicks = 7;
784      break;
785    case 10:
786    case 15:
787    case 25:
788    case 50:
789    case 100:
790      numTicks = 6;
791      break;
792    case 70:
793      numTicks = 8;
794      break;
795    }
796
797  interval = newIntScale*root/(numTicks-1.0);
798  return numTicks;
799}
800
801//----------------------------------------------------------------------------
802//this method takes an initial range and an initial number of ticks and then
803//computes a final range and number of ticks so that two properties are
804//satisfied. First the final range includes at least the initial range, and
805//second the final range divided by the number of ticks (minus one) will be a
806//reasonable interval
807void vtkRpAxisActor2D::ComputeRange(double inRange[2],
808                                  double outRange[2],
809                                  int vtkNotUsed(inNumTicks),
810                                  int &numTicks,
811                                  double &interval)
812{
813  // Handle the range
814  double sRange[2];
815  if ( inRange[0] < inRange[1] )
816    {
817    sRange[0] = inRange[0];
818    sRange[1] = inRange[1];
819    }
820  else if ( inRange[0] > inRange[1] )
821    {
822    sRange[1] = inRange[0];
823    sRange[0] = inRange[1];
824    }
825  else // they're equal, so perturb them by 1 percent
826    {
827    double perturb = 100.;
828    if (inRange[0] == 0.0)
829      { // if they are both zero, then just perturb about zero
830      sRange[0] = -1/perturb;
831      sRange[1] = 1/perturb;
832      }
833    else
834      {
835      sRange[0] = inRange[0] - inRange[0]/perturb;
836      sRange[1] = inRange[0] + inRange[0]/perturb;
837      }
838    }
839
840  double root;
841  numTicks = vtkRpAxisActor2DComputeTicks(sRange, interval, root);
842
843  // is the starting point reasonable?
844  if (fabs(sRange[0]/root - floor(sRange[0]/root)) < 0.01)
845    {
846    outRange[0] = sRange[0];
847    outRange[1] = outRange[0] + (numTicks-1.0)*interval;
848    }
849  else
850    {
851    // OK the starting point is not a good number, so we must widen the range
852    // First see if the current range will handle moving the start point
853    outRange[0] = floor(sRange[0]/root)*root;
854    if (outRange[0]+(numTicks-1.0)*interval <= sRange[1])
855      {
856      outRange[1] = outRange[0] + (numTicks-1.0)*interval;
857      }
858    else
859      {
860      // Finally in this case we must switch to a larger range to
861      // have reasonable starting and ending values
862      sRange[0] = outRange[0];
863      numTicks = vtkRpAxisActor2DComputeTicks(sRange, interval, root);
864      outRange[1] = outRange[0] + (numTicks-1.0)*interval;
865      }
866    }
867
868  // Adust if necessary
869  if ( inRange[0] > inRange[1] )
870    {
871    sRange[0] = outRange[1];
872    outRange[1] = outRange[0];
873    outRange[0] = sRange[0];
874    interval = -interval;
875    }
876
877}
878
879//----------------------------------------------------------------------------
880// Position text with respect to a point (xTick) where the angle of the line
881// from the point to the center of the text is given by theta. The offset
882// is the spacing between ticks and labels.
883void vtkRpAxisActor2D::SetOffsetPosition(double xTick[3], double theta,
884                                       int stringWidth, int stringHeight,
885                                       int offset, vtkActor2D *actor)
886{
887  double x, y, center[2];
888  int pos[2];
889
890  x = stringWidth/2.0 + offset;
891  y = stringHeight/2.0 + offset;
892
893  center[0] = xTick[0] + x*sin(theta);
894  center[1] = xTick[1] - y*cos(theta);
895
896  pos[0] = static_cast<int>(center[0] - stringWidth/2.0);
897  pos[1] = static_cast<int>(center[1] - stringHeight/2.0);
898
899  actor->SetPosition(pos[0], pos[1]);
900}
901
902//----------------------------------------------------------------------------
903double vtkRpAxisActor2D::ComputeStringOffset(double width, double height,
904                                           double theta)
905{
906  double f1 = height*cos(theta);
907  double f2 = width*sin(theta);
908  return (1.2 * sqrt(f1*f1 + f2*f2));
909}
910
911//----------------------------------------------------------------------------
912void vtkRpAxisActor2D::ShallowCopy(vtkProp *prop)
913{
914  vtkRpAxisActor2D *a = vtkRpAxisActor2D::SafeDownCast(prop);
915  if ( a != NULL )
916    {
917    this->SetRange(a->GetRange());
918    this->SetNumberOfLabels(a->GetNumberOfLabels());
919    this->SetLabelFormat(a->GetLabelFormat());
920    this->SetAdjustLabels(a->GetAdjustLabels());
921    this->SetTitle(a->GetTitle());
922    this->SetTickLength(a->GetTickLength());
923    this->SetTickOffset(a->GetTickOffset());
924    this->SetAxisVisibility(a->GetAxisVisibility());
925    this->SetTickVisibility(a->GetTickVisibility());
926    this->SetLabelVisibility(a->GetLabelVisibility());
927    this->SetTitleVisibility(a->GetTitleVisibility());
928    this->SetFontFactor(a->GetFontFactor());
929    this->SetLabelFactor(a->GetLabelFactor());
930    this->SetLabelTextProperty(a->GetLabelTextProperty());
931    this->SetTitleTextProperty(a->GetTitleTextProperty());
932    }
933
934  // Now do superclass
935  this->vtkActor2D::ShallowCopy(prop);
936}
Note: See TracBrowser for help on using the repository browser.