source: branches/blt4/packages/vizservers/vtkvis/vtkRpAxisActor2D.cpp @ 2936

Last change on this file since 2936 was 2936, checked in by gah, 12 years ago

sync back with trunk

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.