You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
2529 lines
78 KiB
C++
2529 lines
78 KiB
C++
/*=========================================================================
|
|
|
|
Program: Visualization Toolkit
|
|
Module: vtkPolarAxesActor.cxx
|
|
|
|
Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
|
|
All rights reserved.
|
|
See Copyright.txt or http://www.kitware.com/Copyright.htm for details.
|
|
|
|
This software is distributed WITHOUT ANY WARRANTY; without even
|
|
the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
|
PURPOSE. See the above copyright notice for more information.
|
|
|
|
=========================================================================*/
|
|
#include "vtkPolarAxesActor.h"
|
|
|
|
#include "vtkAxisFollower.h"
|
|
#include "vtkCamera.h"
|
|
#include "vtkCellArray.h"
|
|
#include "vtkCoordinate.h"
|
|
#include "vtkEllipseArcSource.h"
|
|
#include "vtkFollower.h"
|
|
#include "vtkMath.h"
|
|
#include "vtkMathUtilities.h"
|
|
#include "vtkNew.h"
|
|
#include "vtkObjectFactory.h"
|
|
#include "vtkPolyData.h"
|
|
#include "vtkPolyDataMapper.h"
|
|
#include "vtkProperty.h"
|
|
#include "vtkStringArray.h"
|
|
#include "vtkTextProperty.h"
|
|
#include "vtkViewport.h"
|
|
|
|
#include <sstream>
|
|
|
|
#define VTK_EXPONENT_AXES_ACTOR_RTOL (1. - 10. * VTK_DBL_EPSILON)
|
|
|
|
vtkStandardNewMacro(vtkPolarAxesActor);
|
|
vtkCxxSetObjectMacro(vtkPolarAxesActor, Camera, vtkCamera);
|
|
vtkCxxSetObjectMacro(vtkPolarAxesActor, PolarAxisLabelTextProperty, vtkTextProperty);
|
|
vtkCxxSetObjectMacro(vtkPolarAxesActor, PolarAxisTitleTextProperty, vtkTextProperty);
|
|
vtkCxxSetObjectMacro(vtkPolarAxesActor, LastRadialAxisTextProperty, vtkTextProperty);
|
|
vtkCxxSetObjectMacro(vtkPolarAxesActor, SecondaryRadialAxesTextProperty, vtkTextProperty);
|
|
vtkCxxSetObjectMacro(vtkPolarAxesActor, LastRadialAxisProperty, vtkProperty);
|
|
vtkCxxSetObjectMacro(vtkPolarAxesActor, SecondaryRadialAxesProperty, vtkProperty);
|
|
|
|
//-----------------------------------------------------------------------------
|
|
void vtkPolarAxesActor::PrintSelf(ostream& os, vtkIndent indent)
|
|
{
|
|
this->Superclass::PrintSelf(os, indent);
|
|
|
|
os << indent << "Bounds: \n";
|
|
os << indent << " Xmin,Xmax: (" << this->Bounds[0] << ", "
|
|
<< this->Bounds[1] << ")\n";
|
|
os << indent << " Ymin,Ymax: (" << this->Bounds[2] << ", "
|
|
<< this->Bounds[3] << ")\n";
|
|
os << indent << " Zmin,Zmax: (" << this->Bounds[4] << ", "
|
|
<< this->Bounds[5] << ")\n";
|
|
|
|
os << indent << "ScreenSize: " << this->ScreenSize << "\n";
|
|
|
|
os << indent << "Number Of Radial Axes: " << this->NumberOfRadialAxes << endl;
|
|
|
|
os << indent << "Range: ("
|
|
<< this->Range[0] << ", "
|
|
<< this->Range[1] << ")\n";
|
|
|
|
os << indent << "Pole: ("
|
|
<< this->Pole[0] << ", "
|
|
<< this->Pole[1] << ", "
|
|
<< this->Pole[2] << ")\n";
|
|
|
|
os << indent << "Number of radial axes: " << this->NumberOfRadialAxes << endl;
|
|
os << indent << "Auto Subdivide Polar Axis: " << this->AutoSubdividePolarAxis << endl;
|
|
os << indent << "Abgle between two radial axes: " << this->DeltaAngleRadialAxes << endl;
|
|
os << indent << "Minimum Radius: " << this->MinimumRadius << endl;
|
|
os << indent << "Maximum Radius: " << this->MaximumRadius << endl;
|
|
os << indent << "Log Scale: " << (this->Log ? "On" : "Off") << endl;
|
|
os << indent << "Auto-Scale Radius: " << (this->AutoScaleRadius ? "On" : "Off") << endl;
|
|
os << indent << "Ratio: " << this->Ratio << endl;
|
|
os << indent << "Minimum Angle: " << this->MinimumAngle << endl;
|
|
os << indent << "Maximum Angle: " << this->MaximumAngle << endl;
|
|
os << indent << "Smallest Visible Polar Angle: " << this->SmallestVisiblePolarAngle << endl;
|
|
os << indent << "Radial Units (degrees): "
|
|
<< (this->RadialUnits ? "On\n" : "Off\n") << endl;
|
|
|
|
if (this->Camera)
|
|
{
|
|
os << indent << "Camera:\n";
|
|
this->Camera->PrintSelf(os, indent.GetNextIndent());
|
|
}
|
|
else
|
|
{
|
|
os << indent << "Camera: (none)\n";
|
|
}
|
|
|
|
os << indent << "EnableDistanceLOD: "
|
|
<< (this->EnableDistanceLOD ? "On" : "Off") << endl;
|
|
os << indent << "DistanceLODThreshold: " << this->DistanceLODThreshold << "\n";
|
|
|
|
os << indent << "EnableViewAngleLOD: "
|
|
<< (this->EnableViewAngleLOD ? "On" : "Off") << endl;
|
|
os << indent << "ViewAngleLODThreshold: " << this->ViewAngleLODThreshold << "\n";
|
|
|
|
os << indent << "Polar Axis Title: " << this->PolarAxisTitle << "\n";
|
|
os << indent << "Polar Label Format: " << this->PolarLabelFormat << "\n";
|
|
os << indent << "Title Scale: " << this->TitleScale << "\n";
|
|
os << indent << "Label Scale: " << this->LabelScale << "\n";
|
|
os << indent << "Radial Angle Format: " << this->RadialAngleFormat << "\n";
|
|
os << indent << "PolarAxisLabelTextProperty: " << this->PolarAxisLabelTextProperty << endl;
|
|
os << indent << "PolarAxisTitleTextProperty: " << this->PolarAxisTitleTextProperty << endl;
|
|
os << indent << "RadialAxisTextProperty: " << this->LastRadialAxisTextProperty << endl;
|
|
os << indent << "SecondaryRadialAxesTextProperty: " << this->SecondaryRadialAxesTextProperty << endl;
|
|
os << indent << "Polar Axis Visibility: "
|
|
<< (this->PolarAxisVisibility ? "On\n" : "Off\n");
|
|
os << indent << "Polar Title Visibility: "
|
|
<< (this->PolarTitleVisibility ? "On" : "Off") << endl;
|
|
os << indent << "Polar Label Visibility: "
|
|
<< (this->PolarLabelVisibility ? "On" : "Off") << endl;
|
|
if (this->PolarAxisTitleLocation == VTK_TITLE_BOTTOM)
|
|
{
|
|
os << indent << "Polar Title Location: BOTTOM" << endl;
|
|
}
|
|
else if (this->PolarAxisTitleLocation == VTK_TITLE_EXTERN)
|
|
{
|
|
os << indent << "Polar Title Location: EXTERN" << endl;
|
|
}
|
|
|
|
os << indent << "Polar Label exponent location: ";
|
|
|
|
if (this->ExponentLocation == VTK_EXPONENT_BOTTOM)
|
|
{
|
|
os << " next to the polar axis title." << endl;
|
|
}
|
|
else if (this->ExponentLocation == VTK_EXPONENT_EXTERN)
|
|
{
|
|
os << " outer side." << endl;
|
|
}
|
|
else
|
|
{
|
|
os << " bound to labels." << endl;
|
|
}
|
|
|
|
os << indent << "Radial Axes Visibility: " << (this->RadialAxesVisibility ? "On\n" : "Off\n");
|
|
os << indent << "Radial Title Visibility: " << (this->RadialTitleVisibility ? "On" : "Off") << endl;
|
|
if (this->RadialAxisTitleLocation == VTK_TITLE_BOTTOM)
|
|
{
|
|
os << indent << "Radial Title Location: BOTTOM" << endl;
|
|
}
|
|
else if (this->RadialAxisTitleLocation == VTK_TITLE_EXTERN)
|
|
{
|
|
os << indent << "Radial Title Location: EXTERN" << endl;
|
|
}
|
|
|
|
os << indent << "Polar Arcs Visibility: " << (this->PolarArcsVisibility ? "On" : "Off") << endl;
|
|
os << indent << "Draw Radial Gridlines: " << (this->DrawRadialGridlines ? "On" : "Off") << endl;
|
|
os << indent << "Draw Polar Arcs Gridlines: " << (this->DrawPolarArcsGridlines ? "On" : "Off") << endl;
|
|
os << indent << "Draw Radial Axes From Polar Axis: " << (this->RadialAxesOriginToPolarAxis ? "On" : "Off") << endl;
|
|
|
|
//--------------------- TICKS ------------------
|
|
os << indent << "TickLocation: " << this->TickLocation << endl;
|
|
|
|
os << indent << "Ticks overall enabled: " << (this->PolarTickVisibility ? "On" : "Off") << endl;
|
|
os << indent << "Draw Arc Ticks From Polar Axis: " << (this->ArcTicksOriginToPolarAxis ? "On" : "Off") << endl;
|
|
|
|
//--- major ticks ---
|
|
// polar axis and last radial axis
|
|
os << indent << "Axes Major Tick Visibility: " << (this->AxisTickVisibility ? "On" : "Off") << endl;
|
|
if (this->AxisTickVisibility && this->PolarTickVisibility)
|
|
{
|
|
os << indent << "Axes Major Tick Step: " << this->DeltaRangeMajor << endl;
|
|
os << indent << "PolarAxis Major Tick Size: " << this->PolarAxisMajorTickSize << endl;
|
|
os << indent << "PolarAxis Major Tick Thickness: " << this->PolarAxisMajorTickThickness << endl;
|
|
if (this->RadialAxesVisibility)
|
|
{
|
|
os << indent << "Last Radial Axis Major Ticks Size: " << this->LastRadialAxisMajorTickSize << endl;
|
|
os << indent << "Last Radial Axis Major Ticks Thickness: " << this->LastRadialAxisMajorTickThickness << endl;
|
|
}
|
|
}
|
|
|
|
// last arc
|
|
os << indent << "Arc Major Ticks Visibility: " << (this->ArcTickVisibility ? "On" : "Off") << endl;
|
|
if (this->ArcTickVisibility && this->PolarTickVisibility)
|
|
{
|
|
os << indent << "Arc Major Angle Step: " << this->DeltaAngleMajor << endl;
|
|
os << indent << "Arc Major Ticks Size: " << this->ArcMajorTickSize << endl;
|
|
os << indent << "Arc Major Ticks Thickness: " << this->ArcMajorTickThickness << endl;
|
|
}
|
|
|
|
//--- minor ticks ---
|
|
// polar axis and last radial axis
|
|
os << indent << "Axis Minor Ticks Visibility: " << (this->AxisMinorTickVisibility ? "On" : "Off") << endl;
|
|
if (this->AxisMinorTickVisibility && this->PolarTickVisibility)
|
|
{
|
|
os << indent << "Axes Minor Tick Step: " << this->DeltaRangeMinor << endl;
|
|
os << indent << "Ratio Between PolarAxis Major and Minor Tick : " << this->PolarAxisTickRatioSize << endl;
|
|
os << indent << "Ratio Between PolarAxis Major and Minor Tick Thickness : " << this->PolarAxisTickRatioThickness << endl;
|
|
if (this->RadialAxesVisibility)
|
|
{
|
|
os << indent << "Ratio Between LastAxis Major and Minor Tick : " << this->LastAxisTickRatioSize << endl;
|
|
os << indent << "Ratio Between LastAxis Major and Minor Tick Thickness: " << this->LastAxisTickRatioThickness << endl;
|
|
}
|
|
}
|
|
os << indent << "Arc Minor Ticks Visibility: " << (this->ArcMinorTickVisibility ? "On" : "Off") << endl;
|
|
if (this->ArcMinorTickVisibility && this->PolarTickVisibility)
|
|
{
|
|
os << indent << "Arc Minor Angle Step: " << this->DeltaAngleMinor << endl;
|
|
os << indent << "Ratio Between Last Arc Major and Minor Tick : " << this->ArcTickRatioSize << endl;
|
|
os << indent << "Ratio Between Last Arc Major and Minor Tick Thickness: " << this->ArcTickRatioThickness << endl;
|
|
}
|
|
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
vtkPolarAxesActor::vtkPolarAxesActor() : vtkActor()
|
|
{
|
|
// 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;
|
|
|
|
// Default pole coordinates
|
|
this->Pole[0] = 0.;
|
|
this->Pole[1] = 0.;
|
|
this->Pole[2] = 0.;
|
|
|
|
// Invalid default number of polar arcs, and auto-calculate by default
|
|
this->AutoSubdividePolarAxis = true;
|
|
|
|
// Ratio of the ellipse arc
|
|
this->Ratio = 1.0;
|
|
|
|
// Polar Axis scale type
|
|
this->Log = 0;
|
|
|
|
// Default minimum polar radius size
|
|
this->MinimumRadius = 0.0;
|
|
|
|
// Default maximum polar radius size
|
|
this->MaximumRadius = 5.0;
|
|
|
|
// Default minimum Range
|
|
this->Range[0] = 0.0;
|
|
|
|
// Default maximum Range
|
|
this->Range[1] = 10.0;
|
|
|
|
// Do not auto-scale radius by default
|
|
this->AutoScaleRadius = false;
|
|
|
|
// Default minimum polar angle
|
|
this->MinimumAngle = 0.;
|
|
|
|
// Default maximum polar angle
|
|
this->MaximumAngle = 90.;
|
|
|
|
// Default smallest radial angle distinguishable from polar axis
|
|
this->SmallestVisiblePolarAngle = .5;
|
|
|
|
// By default show angle units (degrees)
|
|
this->RadialUnits = true;
|
|
|
|
this->Camera = NULL;
|
|
|
|
// Default text screen size
|
|
this->ScreenSize = 10.0;
|
|
|
|
// Text properties of polar axis title and labels, with default color white
|
|
// Properties of the radial axes, with default color black
|
|
this->PolarAxisProperty = vtkProperty::New();
|
|
this->PolarAxisProperty->SetColor(0., 0., 0.);
|
|
this->PolarAxisTitleTextProperty = vtkTextProperty::New();
|
|
this->PolarAxisTitleTextProperty->SetOpacity(1.0);
|
|
this->PolarAxisTitleTextProperty->SetColor(1., 1. , 1.);
|
|
this->PolarAxisTitleTextProperty->SetFontFamilyToArial();
|
|
this->PolarAxisLabelTextProperty = vtkTextProperty::New();
|
|
this->PolarAxisLabelTextProperty->SetColor(1., 1. , 1.);
|
|
this->PolarAxisLabelTextProperty->SetFontFamilyToArial();
|
|
|
|
// Create and set polar axis of type X
|
|
this->PolarAxis = vtkAxisActor::New();
|
|
this->PolarAxis->SetAxisTypeToX();
|
|
|
|
this->PolarAxis->SetCalculateTitleOffset(0);
|
|
this->PolarAxis->SetCalculateLabelOffset(0);
|
|
this->PolarAxis->SetTitleOffset(10);
|
|
this->PolarAxis->SetLabelOffset(2);
|
|
this->PolarAxis->SetExponentOffset(5);
|
|
|
|
// Default distance LOD settings
|
|
this->EnableDistanceLOD = 1;
|
|
this->DistanceLODThreshold = .7;
|
|
|
|
// Default view angle LOD settings
|
|
this->EnableViewAngleLOD = 1;
|
|
this->ViewAngleLODThreshold = .3;
|
|
|
|
this->RadialAxes = NULL;
|
|
|
|
// Properties of the last radial axe, with default color black
|
|
this->LastRadialAxisProperty = vtkProperty::New();
|
|
this->LastRadialAxisProperty->SetAmbient(1.0);
|
|
this->LastRadialAxisProperty->SetDiffuse(0.0);
|
|
this->LastRadialAxisProperty->SetColor(0., 0., 0.);
|
|
|
|
this->LastRadialAxisTextProperty = vtkTextProperty::New();
|
|
this->LastRadialAxisTextProperty->SetOpacity(1.0);
|
|
this->LastRadialAxisTextProperty->SetColor(1., 1. , 1.);
|
|
this->LastRadialAxisTextProperty->SetFontFamilyToArial();
|
|
|
|
// Properties of the secondaries radial axes, with default color black
|
|
this->SecondaryRadialAxesProperty = vtkProperty::New();
|
|
this->SecondaryRadialAxesProperty->SetAmbient(1.0);
|
|
this->SecondaryRadialAxesProperty->SetDiffuse(0.0);
|
|
this->SecondaryRadialAxesProperty->SetColor(0., 0., 0.);
|
|
|
|
this->SecondaryRadialAxesTextProperty = vtkTextProperty::New();
|
|
this->SecondaryRadialAxesTextProperty->SetOpacity(1.0);
|
|
this->SecondaryRadialAxesTextProperty->SetColor(1., 1. , 1.);
|
|
this->SecondaryRadialAxesTextProperty->SetFontFamilyToArial();
|
|
|
|
// Create and set principal polar arcs and ancillary objects, with default color white
|
|
this->PolarArcs = vtkPolyData::New();
|
|
this->PolarArcsMapper = vtkPolyDataMapper::New();
|
|
this->PolarArcsMapper->SetInputData(this->PolarArcs);
|
|
this->PolarArcsActor = vtkActor::New();
|
|
this->PolarArcsActor->SetMapper(this->PolarArcsMapper);
|
|
this->PolarArcsActor->GetProperty()->SetColor(1., 1., 1.);
|
|
|
|
// Create and set secondary polar arcs and ancillary objects, with default color white
|
|
this->SecondaryPolarArcs = vtkPolyData::New();
|
|
this->SecondaryPolarArcsMapper = vtkPolyDataMapper::New();
|
|
this->SecondaryPolarArcsMapper->SetInputData(this->SecondaryPolarArcs);
|
|
this->SecondaryPolarArcsActor = vtkActor::New();
|
|
this->SecondaryPolarArcsActor->SetMapper(this->SecondaryPolarArcsMapper);
|
|
this->SecondaryPolarArcsActor->GetProperty()->SetColor(1., 1., 1.);
|
|
|
|
// Create the vtk Object for arc ticks
|
|
this->ArcMajorTickPts = vtkPoints::New();
|
|
this->ArcMinorTickPts = vtkPoints::New();
|
|
|
|
this->ArcTickPolyData = vtkPolyData::New();
|
|
this->ArcMinorTickPolyData = vtkPolyData::New();
|
|
|
|
this->ArcTickPolyDataMapper = vtkPolyDataMapper::New();
|
|
this->ArcTickPolyDataMapper->SetInputData(this->ArcTickPolyData);
|
|
|
|
this->ArcMinorTickPolyDataMapper = vtkPolyDataMapper::New();
|
|
this->ArcMinorTickPolyDataMapper->SetInputData(this->ArcMinorTickPolyData);
|
|
|
|
this->ArcTickActor = vtkActor::New();
|
|
this->ArcTickActor->SetMapper(this->ArcTickPolyDataMapper);
|
|
|
|
this->ArcMinorTickActor = vtkActor::New();
|
|
this->ArcMinorTickActor->SetMapper(this->ArcMinorTickPolyDataMapper);
|
|
|
|
// Default title for polar axis (sometimes also called "Radius")
|
|
this->PolarAxisTitle = new char[16];
|
|
sprintf(this->PolarAxisTitle, "%s", "Radial Distance");
|
|
|
|
this->PolarLabelFormat = new char[8];
|
|
sprintf(this->PolarLabelFormat, "%s", "%-#6.3g");
|
|
|
|
this->ExponentLocation = VTK_EXPONENT_LABELS;
|
|
|
|
this->RadialAngleFormat = new char[8];
|
|
sprintf(this->RadialAngleFormat, "%s", "%-#3.1f");
|
|
|
|
this->RadialAxisTitleLocation = VTK_TITLE_BOTTOM;
|
|
this->PolarAxisTitleLocation = VTK_TITLE_BOTTOM;
|
|
|
|
// By default all polar axis features are visible
|
|
this->PolarAxisVisibility = 1;
|
|
this->PolarTitleVisibility = 1;
|
|
this->PolarLabelVisibility = 1;
|
|
|
|
this->TickLocation = vtkAxisActor::VTK_TICKS_BOTH;
|
|
|
|
this->ArcTicksOriginToPolarAxis = 1.0;
|
|
|
|
// ----- tick visibility -----
|
|
// overall visibility
|
|
this->PolarTickVisibility = 1;
|
|
|
|
this->AxisTickVisibility = 1;
|
|
this->AxisMinorTickVisibility = 0;
|
|
|
|
this->ArcTickVisibility = 1;
|
|
this->ArcMinorTickVisibility = 0;
|
|
|
|
// tick size
|
|
this->PolarAxisMajorTickSize = 0.1;
|
|
this->PolarAxisTickRatioSize = 0.3;
|
|
|
|
this->LastRadialAxisMajorTickSize = 0.1;
|
|
this->LastAxisTickRatioSize = 0.3;
|
|
|
|
this->ArcMajorTickSize = 0.1;
|
|
this->ArcTickRatioSize = 0.3;
|
|
|
|
// tick thickness
|
|
this->PolarAxisMajorTickThickness = 1.0;
|
|
this->PolarAxisTickRatioThickness = 0.5;
|
|
|
|
this->LastRadialAxisMajorTickThickness = 1.0;
|
|
this->LastAxisTickRatioThickness = 0.5;
|
|
|
|
this->ArcMajorTickThickness = 1.0;
|
|
this->ArcTickRatioThickness = 0.5;
|
|
|
|
// Step between 2 major ticks, in range value (values displayed on the axis).
|
|
this->DeltaRangeMajor = 1.0;
|
|
|
|
// Step between 2 minor ticks, in range value (values displayed on the axis).
|
|
this->DeltaRangeMinor = 0.5 * this->DeltaRangeMajor;
|
|
|
|
// Angle between 2 major ticks on the last arc.
|
|
this->DeltaAngleMajor = 10.0;
|
|
|
|
// Angle between 2 minor ticks on the last arc.
|
|
this->DeltaAngleMinor = 0.5 *this->DeltaAngleMajor;
|
|
|
|
this->RadialAxesOriginToPolarAxis = 1;
|
|
this->DeltaAngleRadialAxes = 45.0;
|
|
this->NumberOfRadialAxes = 0;
|
|
|
|
// By default all radial axes features are visible
|
|
this->RadialAxesVisibility = 1;
|
|
this->RadialTitleVisibility = 1;
|
|
|
|
// By default polar arcs are visible
|
|
this->PolarArcsVisibility = 1;
|
|
|
|
// By default inner radial lines and polar arcs lines are visible
|
|
this->DrawRadialGridlines = 1;
|
|
this->DrawPolarArcsGridlines = 1;
|
|
|
|
// Default title scale
|
|
this->TitleScale = -1.;
|
|
|
|
// Default label scale
|
|
this->LabelScale = -1.;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
vtkPolarAxesActor::~vtkPolarAxesActor()
|
|
{
|
|
this->SetCamera(NULL);
|
|
|
|
if (this->PolarAxisProperty)
|
|
{
|
|
this->PolarAxisProperty->Delete();
|
|
}
|
|
|
|
if (this->LastRadialAxisProperty)
|
|
{
|
|
this->LastRadialAxisProperty->Delete();
|
|
}
|
|
|
|
if (this->SecondaryRadialAxesProperty)
|
|
{
|
|
this->SecondaryRadialAxesProperty->Delete();
|
|
}
|
|
|
|
delete [] this->PolarLabelFormat;
|
|
this->PolarLabelFormat = NULL;
|
|
|
|
delete [] this->RadialAngleFormat;
|
|
this->RadialAngleFormat = NULL;
|
|
|
|
delete [] this->PolarAxisTitle;
|
|
this->PolarAxisTitle = NULL;
|
|
|
|
if (this->PolarAxisTitleTextProperty)
|
|
{
|
|
this->PolarAxisTitleTextProperty->Delete();
|
|
this->PolarAxisTitleTextProperty = NULL;
|
|
}
|
|
|
|
if (this->PolarAxisLabelTextProperty)
|
|
{
|
|
this->PolarAxisLabelTextProperty->Delete();
|
|
this->PolarAxisLabelTextProperty = NULL;
|
|
}
|
|
|
|
if (this->LastRadialAxisTextProperty)
|
|
{
|
|
this->LastRadialAxisTextProperty->Delete();
|
|
this->LastRadialAxisTextProperty = NULL;
|
|
}
|
|
|
|
if (this->SecondaryRadialAxesTextProperty)
|
|
{
|
|
this->SecondaryRadialAxesTextProperty->Delete();
|
|
this->SecondaryRadialAxesTextProperty = NULL;
|
|
}
|
|
|
|
if (this->PolarAxis)
|
|
{
|
|
this->PolarAxis->Delete();
|
|
this->PolarAxis = NULL;
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
if (this->PolarArcs)
|
|
{
|
|
this->PolarArcs->Delete();
|
|
this->PolarArcs = NULL;
|
|
}
|
|
if (this->PolarArcsMapper)
|
|
{
|
|
this->PolarArcsMapper->Delete();
|
|
this->PolarArcsMapper = NULL;
|
|
}
|
|
if (this->PolarArcsActor)
|
|
{
|
|
this->PolarArcsActor->Delete();
|
|
this->PolarArcsActor = NULL;
|
|
}
|
|
|
|
if (this->SecondaryPolarArcs)
|
|
{
|
|
this->SecondaryPolarArcs->Delete();
|
|
this->SecondaryPolarArcs = NULL;
|
|
}
|
|
if (this->SecondaryPolarArcsMapper)
|
|
{
|
|
this->SecondaryPolarArcsMapper->Delete();
|
|
this->SecondaryPolarArcsMapper = NULL;
|
|
}
|
|
if (this->SecondaryPolarArcsActor)
|
|
{
|
|
this->SecondaryPolarArcsActor->Delete();
|
|
this->SecondaryPolarArcsActor = NULL;
|
|
}
|
|
|
|
// ticks related objects
|
|
if (this->ArcMajorTickPts)
|
|
{
|
|
this->ArcMajorTickPts->Delete();
|
|
this->ArcMajorTickPts = NULL;
|
|
}
|
|
if (this->ArcMinorTickPts)
|
|
{
|
|
this->ArcMinorTickPts->Delete();
|
|
this->ArcMinorTickPts = NULL;
|
|
}
|
|
if (this->ArcTickPolyData)
|
|
{
|
|
this->ArcTickPolyData->Delete();
|
|
this->ArcTickPolyData = NULL;
|
|
}
|
|
if (this->ArcMinorTickPolyData)
|
|
{
|
|
this->ArcMinorTickPolyData->Delete();
|
|
this->ArcMinorTickPolyData = NULL;
|
|
}
|
|
if (this->ArcTickPolyDataMapper)
|
|
{
|
|
this->ArcTickPolyDataMapper->Delete();
|
|
this->ArcTickPolyDataMapper = NULL;
|
|
}
|
|
if (this->ArcMinorTickPolyDataMapper)
|
|
{
|
|
this->ArcMinorTickPolyDataMapper->Delete();
|
|
this->ArcMinorTickPolyDataMapper = NULL;
|
|
}
|
|
if (this->ArcTickActor)
|
|
{
|
|
this->ArcTickActor->Delete();
|
|
this->ArcTickActor = NULL;
|
|
}
|
|
if (this->ArcMinorTickActor)
|
|
{
|
|
this->ArcMinorTickActor->Delete();
|
|
this->ArcMinorTickActor = NULL;
|
|
}
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
int vtkPolarAxesActor::RenderOpaqueGeometry(vtkViewport *viewport)
|
|
{
|
|
// Initialization
|
|
int renderedSomething = 0;
|
|
if (!this->Camera)
|
|
{
|
|
vtkErrorMacro(<< "No camera!");
|
|
return renderedSomething;
|
|
}
|
|
|
|
this->BuildAxes(viewport);
|
|
|
|
// Render the polar axis
|
|
if (this->PolarAxisVisibility)
|
|
{
|
|
renderedSomething += this->PolarAxis->RenderOpaqueGeometry(viewport);
|
|
}
|
|
|
|
// Render the radial axes
|
|
if (this->RadialAxesVisibility)
|
|
{
|
|
bool isInnerAxis, isAxisVisible;
|
|
for (int i = 0; i < this->NumberOfRadialAxes; ++ i)
|
|
{
|
|
isInnerAxis = (i != this->NumberOfRadialAxes - 1) ||
|
|
(vtkMathUtilities::FuzzyCompare(MaximumAngle, MinimumAngle));
|
|
isAxisVisible = !isInnerAxis || this->DrawRadialGridlines;
|
|
if (this->RadialAxesVisibility && isAxisVisible)
|
|
{
|
|
renderedSomething += this->RadialAxes[i]->RenderOpaqueGeometry(viewport);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Render the polar arcs
|
|
if (this->PolarArcsVisibility)
|
|
{
|
|
renderedSomething += this->PolarArcsActor->RenderOpaqueGeometry(viewport);
|
|
renderedSomething += this->SecondaryPolarArcsActor->RenderOpaqueGeometry(viewport);
|
|
|
|
if (this->PolarTickVisibility)
|
|
{
|
|
if (this->ArcTickVisibility)
|
|
{
|
|
renderedSomething += this->ArcTickActor->RenderOpaqueGeometry(viewport);
|
|
}
|
|
if (this->ArcMinorTickVisibility)
|
|
{
|
|
renderedSomething += this->ArcMinorTickActor->RenderOpaqueGeometry(viewport);
|
|
}
|
|
}
|
|
}
|
|
return renderedSomething;
|
|
}
|
|
|
|
int vtkPolarAxesActor::RenderOverlay(vtkViewport *viewport)
|
|
{
|
|
int renderedSomething = 0;
|
|
|
|
if (this->PolarAxisVisibility && this->PolarAxis->GetUse2DMode())
|
|
{
|
|
renderedSomething += this->PolarAxis->RenderOverlay(viewport);
|
|
}
|
|
|
|
if (this->RadialAxesVisibility)
|
|
{
|
|
for (int i = 0; i < this->NumberOfRadialAxes; ++i)
|
|
{
|
|
if (this->RadialAxes[i]->GetUse2DMode())
|
|
{
|
|
renderedSomething += this->RadialAxes[i]->RenderOverlay(viewport);
|
|
}
|
|
}
|
|
}
|
|
return renderedSomething;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
void vtkPolarAxesActor::ReleaseGraphicsResources(vtkWindow *win)
|
|
{
|
|
this->PolarAxis->ReleaseGraphicsResources(win);
|
|
for (int i = 0; i < this->NumberOfRadialAxes; ++ i)
|
|
{
|
|
this->RadialAxes[i]->ReleaseGraphicsResources(win);
|
|
}
|
|
this->SecondaryPolarArcsActor->ReleaseGraphicsResources(win);
|
|
this->PolarArcsActor->ReleaseGraphicsResources(win);
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
void vtkPolarAxesActor::CalculateBounds()
|
|
{
|
|
// Fetch angles, at this point it is already known that angular sector <= 360.
|
|
double minAngle = this->MinimumAngle;
|
|
double maxAngle = this->MaximumAngle;
|
|
|
|
// Ensure that angles are not both < -180 nor both > 180 degrees
|
|
if (maxAngle < -180.)
|
|
{
|
|
// Increment angles modulo 360 degrees
|
|
minAngle += 360.;
|
|
maxAngle += 360.;
|
|
}
|
|
else if (minAngle > 180.)
|
|
{
|
|
// Decrement angles modulo 360 degrees
|
|
minAngle -= 360.;
|
|
maxAngle -= 360.;
|
|
}
|
|
|
|
// Prepare trigonometric quantities
|
|
double thetaMin = vtkMath::RadiansFromDegrees(minAngle);
|
|
double cosThetaMin = cos(thetaMin);
|
|
double sinThetaMin = sin(thetaMin);
|
|
double thetaMax = vtkMath::RadiansFromDegrees(maxAngle);
|
|
double cosThetaMax = cos(thetaMax);
|
|
double sinThetaMax = sin(thetaMax);
|
|
|
|
// Calculate extremal cosines across angular sector
|
|
double minCos;
|
|
double maxCos;
|
|
if (minAngle * maxAngle < 0.)
|
|
{
|
|
// Angular sector contains null angle
|
|
maxCos = 1.;
|
|
if (minAngle < 180. && maxAngle > 180.)
|
|
{
|
|
// Angular sector also contains flat angle
|
|
minCos = -1.;
|
|
}
|
|
else
|
|
{
|
|
// Angular sector does not contain flat angle
|
|
minCos = cosThetaMin < cosThetaMax ? cosThetaMin : cosThetaMax;
|
|
}
|
|
|
|
}
|
|
else if (minAngle < 180. && maxAngle > 180.)
|
|
{
|
|
// Angular sector does not contain flat angle (and not null angle)
|
|
minCos = -1.;
|
|
maxCos = cosThetaMax > cosThetaMin ? cosThetaMax : cosThetaMin;
|
|
}
|
|
else
|
|
{
|
|
// Angular sector does not contain flat nor null angle
|
|
minCos = cosThetaMin < cosThetaMax ? cosThetaMin : cosThetaMax;
|
|
maxCos = cosThetaMax > cosThetaMin ? cosThetaMax : cosThetaMin;
|
|
}
|
|
|
|
// Calculate extremal sines across angular sector
|
|
double minSin;
|
|
double maxSin;
|
|
if (minAngle < -90. && maxAngle > -90.)
|
|
{
|
|
// Angular sector contains negative right angle
|
|
minSin = -1.;
|
|
if (minAngle < 90. && maxAngle > 90.)
|
|
{
|
|
// Angular sector also contains positive right angle
|
|
maxSin = 1.;
|
|
}
|
|
else
|
|
{
|
|
// Angular sector contain does not contain positive right angle
|
|
maxSin = sinThetaMax > sinThetaMin ? sinThetaMax : sinThetaMin;
|
|
}
|
|
}
|
|
else if (minAngle < 90. && maxAngle > 90.)
|
|
{
|
|
// Angular sector contains positive right angle (and not negative one)
|
|
minSin = sinThetaMin < sinThetaMax ? sinThetaMin : sinThetaMax;
|
|
maxSin = 1.;
|
|
}
|
|
else
|
|
{
|
|
// Angular sector contain does not contain either right angle
|
|
minSin = sinThetaMin < sinThetaMax ? sinThetaMin : sinThetaMax;
|
|
maxSin = sinThetaMax > sinThetaMin ? sinThetaMax : sinThetaMin;
|
|
}
|
|
|
|
// Now calculate bounds
|
|
// xmin
|
|
this->Bounds[0] = this->Pole[0] + this->MaximumRadius * minCos;
|
|
// xmax
|
|
this->Bounds[1] = this->Pole[0] + this->MaximumRadius * maxCos;
|
|
// ymin
|
|
this->Bounds[2] = this->Pole[1] + this->MaximumRadius * minSin;
|
|
// ymax
|
|
this->Bounds[3] = this->Pole[1] + this->MaximumRadius * maxSin;
|
|
// zmin
|
|
this->Bounds[4] = this->Pole[2];
|
|
// zmax
|
|
this->Bounds[5] = this->Pole[2];
|
|
|
|
// Update modification time of bounds
|
|
this->BoundsMTime.Modified();
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
void vtkPolarAxesActor::GetBounds(double bounds[6])
|
|
{
|
|
for (int i = 0; i< 6; i++)
|
|
{
|
|
bounds[i] = this->Bounds[i];
|
|
}
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
void vtkPolarAxesActor::GetBounds(double& xmin, double& xmax,
|
|
double& ymin, double& ymax,
|
|
double& zmin, double& zmax)
|
|
{
|
|
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;
|
|
}
|
|
|
|
bool vtkPolarAxesActor::CheckMembersConsistency()
|
|
{
|
|
if (this->MaximumAngle > 360.0 || this->MinimumAngle > 360.0)
|
|
{
|
|
// Incorrect MaximumRadius input
|
|
vtkWarningMacro(<< "Cannot draw polar axis, Angle > 360.0: "
|
|
<< "MinimumAngle : " << this->MinimumAngle << " _ MaximumAngle: " << this->MaximumAngle);
|
|
return false;
|
|
}
|
|
|
|
// Min/Max Radius
|
|
if (vtkMathUtilities::FuzzyCompare(this->MaximumRadius, this->MinimumRadius))
|
|
{
|
|
// MaximumRadius and this->MinimumRadius are too close
|
|
vtkWarningMacro(<< "Maximum and Minimum Radius cannot be distinct: "
|
|
<< " MinimumRadius: " << this->MinimumRadius << " _ MaximumRadius: " << this->MaximumRadius);
|
|
return false;
|
|
}
|
|
|
|
if (this->MaximumRadius <= 0.0 || this->MinimumRadius < 0.0)
|
|
{
|
|
// Incorrect MaximumRadius input
|
|
vtkWarningMacro(<< "Cannot draw polar axis, Negative Radius value set: "
|
|
<< "MinimumRadius : " << this->MinimumRadius << " _ MaximumRadius: " << this->MaximumRadius);
|
|
return false;
|
|
}
|
|
|
|
// Min/Max Range
|
|
if (vtkMathUtilities::FuzzyCompare(this->Range[0], this->Range[1]))
|
|
{
|
|
// MaximumRadius and this->MinimumRadius are too close
|
|
vtkWarningMacro(<< "Maximum and Minimum Range cannot be distinct: "
|
|
<< " Range[0]: " << this->Range[0] << " _ Range[1]: " << this->Range[1]);
|
|
return false;
|
|
}
|
|
|
|
// Log Mode
|
|
if (this->Log != 0 && this->Range[0] <= 0.0)
|
|
{
|
|
vtkWarningMacro(<< "Scale Set to Linear. Range value undefined for log scale enabled. "
|
|
<< "Current Range: (" << this->Range[0] << ", " << this->Range[1] << ")"
|
|
<< "Range must be > 0.0 for log scale to be enabled"
|
|
<< ".");
|
|
|
|
this->Log = 0;
|
|
}
|
|
|
|
// Range Step
|
|
if (this->DeltaRangeMajor <= 0.0 ||
|
|
(this->DeltaRangeMajor > fabs(this->Range[1] -this->Range[0]) && !AutoSubdividePolarAxis))
|
|
{
|
|
vtkWarningMacro(<< "Axis Major Step or Range length invalid: " << "DeltaRangeMajor: " << this->DeltaRangeMajor
|
|
<< "_ Range length: " << fabs(this->Range[1] -this->Range[0])
|
|
<< " _ Enable AutoSubdividePolarAxis to get a proper DeltaRangeMajor or set it yourself");
|
|
return false;
|
|
}
|
|
if (this->DeltaRangeMinor <= 0.0 ||
|
|
(this->DeltaRangeMinor > fabs(this->Range[1] -this->Range[0]) && !AutoSubdividePolarAxis))
|
|
{
|
|
vtkWarningMacro(<< "Axis Minor Step or range length invalid: " << "DeltaRangeMinor: " << this->DeltaRangeMinor
|
|
<< "_ Range length: " << fabs(this->Range[1] -this->Range[0])
|
|
<< " _ Enable AutoSubdividePolarAxis to get a proper DeltaRangeMinor or set it yourself");
|
|
return false;
|
|
}
|
|
|
|
// Angle Step
|
|
if (this->DeltaAngleMajor <= 0.0 || this->DeltaAngleMajor >= 360.0 ||
|
|
this->DeltaAngleMinor <= 0.0 || this->DeltaAngleMinor >= 360.0)
|
|
{
|
|
vtkWarningMacro(<< "Arc Delta Angle: " << "DeltaAngleMajor: " << this->DeltaAngleMajor
|
|
<< " _ DeltaAngleMinor: " << this->DeltaAngleMinor << "_ DeltaAngles should be in ]0.0, 360.0[ range. ");
|
|
return false;
|
|
}
|
|
|
|
// Angle Step
|
|
if (this->DeltaAngleRadialAxes <= 0.0 || this->DeltaAngleRadialAxes >= 360.0)
|
|
{
|
|
vtkWarningMacro(<< "Delta Angle for radial axes: " << "DeltaAngleRadialAxes: " << this->DeltaAngleRadialAxes
|
|
<< "_ DeltaAngleRadialAxes should be in ]0.0, 360.0[ range. ");
|
|
return false;
|
|
}
|
|
|
|
// Tick ratios range check
|
|
if (this->PolarAxisTickRatioThickness < (1.0 / VTK_MAXIMUM_RATIO) || this->PolarAxisTickRatioThickness > VTK_MAXIMUM_RATIO ||
|
|
this->LastAxisTickRatioThickness < (1.0 / VTK_MAXIMUM_RATIO) || this->LastAxisTickRatioThickness > VTK_MAXIMUM_RATIO ||
|
|
this->ArcTickRatioThickness < (1.0 / VTK_MAXIMUM_RATIO) || this->ArcTickRatioThickness > VTK_MAXIMUM_RATIO ||
|
|
this->PolarAxisTickRatioSize < (1.0 / VTK_MAXIMUM_RATIO) || this->PolarAxisTickRatioSize > VTK_MAXIMUM_RATIO ||
|
|
this->LastAxisTickRatioSize < (1.0 / VTK_MAXIMUM_RATIO) || this->LastAxisTickRatioSize > VTK_MAXIMUM_RATIO ||
|
|
this->ArcTickRatioSize < (1.0 / VTK_MAXIMUM_RATIO) || this->ArcTickRatioSize > VTK_MAXIMUM_RATIO)
|
|
{
|
|
vtkWarningMacro(<< "A size/thickness ratio between major and minor ticks is way too large: "
|
|
<< "PolarAxisTickRatioThickness: " << this->PolarAxisTickRatioThickness
|
|
<< "LastAxisTickRatioThickness: " << this->LastAxisTickRatioThickness
|
|
<< "ArcTickRatioThickness: " << this->ArcTickRatioThickness
|
|
<< "PolarAxisTickRatioSize: " << this->PolarAxisTickRatioSize
|
|
<< "LastAxisTickRatioSize: " << this->LastAxisTickRatioSize
|
|
<< "ArcTickRatioSize: " << this->ArcTickRatioSize);
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
void vtkPolarAxesActor::BuildAxes(vtkViewport *viewport)
|
|
{
|
|
if (this->GetMTime() < this->BuildTime.GetMTime())
|
|
{
|
|
this->AutoScale(viewport);
|
|
return;
|
|
}
|
|
|
|
if (this->MaximumRadius - this->MinimumRadius < 0.0)
|
|
{
|
|
std::swap(this->MinimumRadius, this->MaximumRadius);
|
|
}
|
|
if (Range[0] > Range[1])
|
|
{
|
|
std::swap(Range[0], Range[1]);
|
|
}
|
|
if (this->DeltaRangeMajor < 0.0)
|
|
{
|
|
this->DeltaRangeMajor *= -1.0;
|
|
}
|
|
|
|
if (this->DeltaRangeMinor < 0.0)
|
|
{
|
|
this->DeltaRangeMinor *= -1.0;
|
|
}
|
|
|
|
// ---------- Angles check -----------
|
|
// set angle range [0.0; 360.0]
|
|
this->MaximumAngle = std::fmod(this->MaximumAngle, 360);
|
|
this->MinimumAngle = std::fmod(this->MinimumAngle, 360);
|
|
|
|
if (this->MaximumAngle < 0.0)
|
|
{
|
|
this->MaximumAngle += 360.0;
|
|
}
|
|
|
|
// set angle range [0.0; 360.0]
|
|
if (this->MinimumAngle < 0.0)
|
|
{
|
|
this->MinimumAngle += 360.0;
|
|
}
|
|
|
|
// this->MaximumAngle < this->MinimumAngle is possible, no swap
|
|
|
|
if (!this->CheckMembersConsistency())
|
|
{
|
|
return;
|
|
}
|
|
|
|
// Determine the bounds
|
|
this->CalculateBounds();
|
|
|
|
// Set polar axis endpoints
|
|
vtkAxisActor* axis = this->PolarAxis;
|
|
|
|
// compute ellipse angle
|
|
double miniAngleEllipse =
|
|
this->ComputeEllipseAngle(this->MinimumAngle, this->Ratio);
|
|
|
|
// Set the start point and end point (world coord system) of the Polar Axis.
|
|
double startPt[3], endPt[3];
|
|
startPt[0] = this->Pole[0] + this->MinimumRadius * cos(miniAngleEllipse);
|
|
startPt[1] = this->Pole[1] + this->MinimumRadius * this->Ratio * sin(miniAngleEllipse);
|
|
startPt[2] = this->Pole[2];
|
|
|
|
endPt[0] = this->Pole[0] + this->MaximumRadius * cos(miniAngleEllipse);
|
|
endPt[1] = this->Pole[1] + this->MaximumRadius * this->Ratio * sin(miniAngleEllipse);
|
|
endPt[2] = this->Pole[2];
|
|
|
|
axis->GetPoint1Coordinate()->SetValue(startPt);
|
|
axis->GetPoint2Coordinate()->SetValue(endPt);
|
|
|
|
// axis Type. We assume the polar graph is built in the local plane x-y
|
|
if ((this->MinimumAngle > 45.0 && this->MinimumAngle < 135.0) ||
|
|
(this->MinimumAngle > 225.0 && this->MinimumAngle < 315.0))
|
|
{
|
|
axis->SetAxisTypeToY();
|
|
}
|
|
else
|
|
{
|
|
axis->SetAxisTypeToX();
|
|
}
|
|
|
|
// Set axess attributes (range, tick location)
|
|
this->SetCommonAxisAttributes(axis);
|
|
this->SetPolarAxisAttributes(axis);
|
|
|
|
// ------- Ticks thickness -------
|
|
|
|
// Polar Axis
|
|
this->PolarAxis->GetAxisMajorTicksProperty()->SetLineWidth(this->PolarAxisMajorTickThickness);
|
|
double minorThickness = this->PolarAxisTickRatioThickness * this->PolarAxisMajorTickThickness;
|
|
if (minorThickness < 1.0)
|
|
{
|
|
minorThickness = 1.0;
|
|
}
|
|
this->PolarAxis->GetAxisMinorTicksProperty()->SetLineWidth(minorThickness);
|
|
|
|
// Last arc
|
|
this->ArcTickActor->GetProperty()->SetLineWidth(this->ArcMajorTickThickness);
|
|
minorThickness = std::max(this->ArcMajorTickThickness * this->ArcTickRatioThickness, 1.);
|
|
|
|
this->ArcMinorTickActor->GetProperty()->SetLineWidth(minorThickness);
|
|
|
|
// last polar axis line width is set in BuildRadialAxes() function
|
|
|
|
// Build polar axis ticks
|
|
if (this->Log)
|
|
{
|
|
this->BuildLabelsLog();
|
|
this->BuildPolarArcsLog();
|
|
}
|
|
else
|
|
{
|
|
// Build polar axis labels
|
|
this->BuildPolarAxisLabelsArcs();
|
|
}
|
|
|
|
// Set title relative location from the axis
|
|
if (this->PolarAxisTitleLocation == VTK_TITLE_BOTTOM)
|
|
{
|
|
this->PolarAxis->SetTitleAlignLocation(vtkAxisActor::VTK_ALIGN_BOTTOM);
|
|
}
|
|
else
|
|
{
|
|
this->PolarAxis->SetTitleAlignLocation(vtkAxisActor::VTK_ALIGN_POINT2);
|
|
}
|
|
|
|
// Build radial axes
|
|
this->BuildRadialAxes();
|
|
|
|
// Build ticks located on the last arc
|
|
if (this->PolarTickVisibility)
|
|
{
|
|
this->BuildArcTicks();
|
|
}
|
|
|
|
// color copy
|
|
vtkProperty* prop = this->PolarArcsActor->GetProperty();
|
|
double color[3];
|
|
prop->GetColor(color);
|
|
this->ArcTickActor->GetProperty()->SetColor(color);
|
|
this->ArcMinorTickActor->GetProperty()->SetColor(color);
|
|
|
|
// Update axis title follower
|
|
vtkAxisFollower* follower = axis->GetTitleActor();
|
|
|
|
follower->SetAxis(axis);
|
|
follower->SetEnableDistanceLOD(this->EnableDistanceLOD);
|
|
follower->SetDistanceLODThreshold(this->DistanceLODThreshold);
|
|
follower->SetEnableViewAngleLOD(this->EnableViewAngleLOD);
|
|
follower->SetViewAngleLODThreshold(this->ViewAngleLODThreshold);
|
|
|
|
// Update axis title follower
|
|
vtkAxisFollower* expFollower = this->PolarAxis->GetExponentActor();
|
|
expFollower->SetAxis(this->PolarAxis);
|
|
expFollower->SetEnableDistanceLOD(this->EnableDistanceLOD);
|
|
expFollower->SetDistanceLODThreshold(this->DistanceLODThreshold);
|
|
expFollower->SetEnableViewAngleLOD(this->EnableViewAngleLOD);
|
|
expFollower->SetViewAngleLODThreshold(this->ViewAngleLODThreshold);
|
|
|
|
// Update axis label followers
|
|
vtkAxisFollower** labelActors = axis->GetLabelActors();
|
|
int numberOfLabels = axis->GetNumberOfLabelsBuilt();
|
|
for (int i = 0; i < numberOfLabels; ++i)
|
|
{
|
|
labelActors[i]->SetAxis(axis);
|
|
labelActors[i]->SetEnableDistanceLOD(this->EnableDistanceLOD);
|
|
labelActors[i]->SetDistanceLODThreshold(this->DistanceLODThreshold);
|
|
labelActors[i]->SetEnableViewAngleLOD(this->EnableViewAngleLOD);
|
|
labelActors[i]->SetViewAngleLODThreshold(this->ViewAngleLODThreshold);
|
|
}
|
|
|
|
// Build polar axis
|
|
this->PolarAxis->BuildAxis(viewport, true);
|
|
|
|
// Scale appropriately
|
|
this->AutoScale(viewport);
|
|
|
|
this->BuildTime.Modified();
|
|
}
|
|
|
|
void vtkPolarAxesActor::AutoComputeTicksProperties()
|
|
{
|
|
// set major tick size as 0.02 * majorRadius
|
|
this->PolarAxisMajorTickSize = 0.02 * this->MaximumRadius;
|
|
this->LastRadialAxisMajorTickSize = this->PolarAxisMajorTickSize;
|
|
this->ArcMajorTickSize = this->PolarAxisMajorTickSize;
|
|
|
|
// set DeltaRangeMajor according to Range[1] magnitude
|
|
double rangeLength = fabs(this->PolarAxis->GetRange()[1] - this->PolarAxis->GetRange()[0]);
|
|
|
|
// we would like no more than 15 ticks
|
|
double threshold = log10(1.5);
|
|
double log10RangeLength = log10(rangeLength);
|
|
|
|
double stepPow10 = (log10RangeLength - std::floor(log10RangeLength) < threshold) ? std::floor(log10RangeLength) - 1.0: std::floor(log10RangeLength);
|
|
|
|
this->DeltaRangeMajor = std::pow(10.0, stepPow10);
|
|
this->DeltaRangeMinor = this->DeltaRangeMajor / 2.0;
|
|
}
|
|
//-----------------------------------------------------------------------------
|
|
void vtkPolarAxesActor::SetCommonAxisAttributes(vtkAxisActor* axis)
|
|
{
|
|
vtkProperty* prop = this->GetProperty();
|
|
prop->SetAmbient(1.0);
|
|
prop->SetDiffuse(0.0);
|
|
axis->SetProperty(prop);
|
|
|
|
axis->SetScreenSize(this->ScreenSize);
|
|
|
|
// Common space and range attributes
|
|
axis->SetCamera(this->Camera);
|
|
axis->SetBounds(this->Bounds);
|
|
|
|
// User defined range
|
|
axis->SetRange(this->Range[0], this->Range[1]);
|
|
|
|
// Axis scale type
|
|
axis->SetLog(this->Log);
|
|
|
|
// Major and minor ticks draw begins at Range[0]
|
|
axis->SetMajorRangeStart(axis->GetRange()[0]);
|
|
axis->SetMinorRangeStart(axis->GetRange()[0]);
|
|
|
|
axis->SetCalculateTitleOffset(0);
|
|
axis->SetCalculateLabelOffset(0);
|
|
|
|
// Set polar axis ticks
|
|
axis->SetTickVisibility(this->AxisTickVisibility && this->PolarTickVisibility);
|
|
|
|
// Set polar axis minor ticks
|
|
axis->SetMinorTicksVisible(this->AxisMinorTickVisibility && this->PolarTickVisibility);
|
|
|
|
axis->SetTickLocation(this->TickLocation);
|
|
}
|
|
|
|
void vtkPolarAxesActor::SetPolarAxisAttributes(vtkAxisActor* axis)
|
|
{
|
|
// Set polar axis lines
|
|
axis->SetAxisVisibility(this->PolarAxisVisibility);
|
|
|
|
// #### Warning #### : Set this property BEFORE apply the ticks thickness of the vtkAxisActor instances
|
|
axis->SetAxisLinesProperty(this->PolarAxisProperty);
|
|
|
|
// Set polar axis title
|
|
axis->SetTitleVisibility(this->PolarTitleVisibility);
|
|
axis->SetTitle(this->PolarAxisTitle);
|
|
axis->SetTitleTextProperty(this->PolarAxisTitleTextProperty);
|
|
|
|
// Set Labels exponent value
|
|
if (this->ExponentLocation == VTK_EXPONENT_BOTTOM)
|
|
{
|
|
axis->SetExponentLocation(vtkAxisActor::VTK_ALIGN_BOTTOM);
|
|
axis->SetExponentVisibility(true);
|
|
}
|
|
else if (this->ExponentLocation == VTK_EXPONENT_EXTERN)
|
|
{
|
|
axis->SetExponentLocation(vtkAxisActor::VTK_ALIGN_POINT2);
|
|
axis->SetExponentVisibility(true);
|
|
}
|
|
else
|
|
{
|
|
axis->SetExponentVisibility(false);
|
|
}
|
|
|
|
// Set polar axis labels
|
|
axis->SetLabelVisibility(this->PolarLabelVisibility);
|
|
axis->SetLabelTextProperty(this->PolarAxisLabelTextProperty);
|
|
|
|
// compute tick length, and delta Range values (if log == 1, deltaRange properties will be overwritten)
|
|
if (this->AutoSubdividePolarAxis)
|
|
{
|
|
this->AutoComputeTicksProperties();
|
|
}
|
|
|
|
axis->SetMajorTickSize(this->PolarAxisMajorTickSize);
|
|
|
|
axis->SetMinorTickSize(this->PolarAxisTickRatioSize * this->PolarAxisMajorTickSize);
|
|
|
|
// Set the value between two ticks
|
|
axis->SetDeltaRangeMajor(this->DeltaRangeMajor);
|
|
axis->SetDeltaRangeMinor(this->DeltaRangeMinor);
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
inline double vtkPolarAxesActor::FFix(double value)
|
|
{
|
|
int ivalue = static_cast<int>(value);
|
|
return ivalue;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
inline double vtkPolarAxesActor::FSign(double value, double sign)
|
|
{
|
|
value = fabs(value);
|
|
if (sign < 0.)
|
|
{
|
|
value *= -1.;
|
|
}
|
|
return value;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
void vtkPolarAxesActor::CreateRadialAxes(int axisCount)
|
|
{
|
|
// If number of radial axes does not change, do nothing
|
|
if (this->NumberOfRadialAxes == axisCount)
|
|
{
|
|
return;
|
|
}
|
|
|
|
// Delete existing secondary radial axes
|
|
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;
|
|
}
|
|
|
|
// Create and set n radial axes of type X
|
|
this->NumberOfRadialAxes = axisCount;
|
|
|
|
// Create requested number of secondary radial axes
|
|
this->RadialAxes = new vtkAxisActor* [this->NumberOfRadialAxes];
|
|
for (int i = 0; i < this->NumberOfRadialAxes; ++ i)
|
|
{
|
|
// Create axis of type X
|
|
this->RadialAxes[i] = vtkAxisActor::New();
|
|
vtkAxisActor* axis = this->RadialAxes[i];
|
|
axis->SetAxisTypeToX();
|
|
axis->SetCalculateTitleOffset(0);
|
|
axis->SetCalculateLabelOffset(0);
|
|
axis->SetLabelOffset(0);
|
|
axis->SetTitleOffset(2);
|
|
axis->SetLabelVisibility(0);
|
|
axis->SetUse2DMode(this->PolarAxis->GetUse2DMode());
|
|
}
|
|
|
|
this->Modified();
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
void vtkPolarAxesActor::BuildRadialAxes()
|
|
{
|
|
bool originToPolarAxis = this->RadialAxesOriginToPolarAxis != 0.0;
|
|
|
|
// set MaximumAngle and MinimumAngle range: [0.0; 360.0]
|
|
double angleSection = (this->MaximumAngle > this->MinimumAngle)?
|
|
this->MaximumAngle - this->MinimumAngle: 360.0 - fabs(this->MaximumAngle - this->MinimumAngle);
|
|
|
|
if (vtkMathUtilities::FuzzyCompare(this->MaximumAngle, this->MinimumAngle) || angleSection == 360.0)
|
|
{
|
|
angleSection = 360.0;
|
|
}
|
|
|
|
bool positiveSection = false;
|
|
double dAlpha = this->DeltaAngleRadialAxes;
|
|
double alphaDeg, currentAlpha;
|
|
|
|
// current ellipse angle
|
|
double actualAngle;
|
|
int i = 0;
|
|
|
|
double minorThickness;
|
|
|
|
double alphaStart = (originToPolarAxis) ? this->MinimumAngle + dAlpha: std::floor(this->MinimumAngle / dAlpha) * dAlpha + dAlpha;
|
|
double alphaStop = angleSection + this->MinimumAngle + dAlpha;
|
|
|
|
int n = (angleSection == 360.0)? 0:1;
|
|
double intPart, fractPart;
|
|
fractPart = modf((alphaStop - alphaStart) / dAlpha, &intPart);
|
|
|
|
n += intPart;
|
|
|
|
if (fractPart == 0.0)
|
|
{
|
|
n--;
|
|
}
|
|
|
|
if (n > VTK_MAXIMUM_NUMBER_OF_RADIAL_AXES)
|
|
{
|
|
this->DeltaAngleRadialAxes = angleSection / n;
|
|
dAlpha = this->DeltaAngleRadialAxes;
|
|
}
|
|
if (this->DeltaAngleRadialAxes >= angleSection || n == 0)
|
|
{
|
|
n = 1;
|
|
alphaStart = angleSection + this->MinimumAngle;
|
|
}
|
|
|
|
// init radial axis. Does nothing if number of radial axes doesn't change
|
|
this->CreateRadialAxes(n);
|
|
|
|
char titleValue[64];
|
|
for (alphaDeg = alphaStart; alphaDeg <= alphaStop && i < this->NumberOfRadialAxes; alphaDeg += dAlpha, i++)
|
|
{
|
|
currentAlpha = alphaDeg;
|
|
|
|
if (currentAlpha > angleSection + this->MinimumAngle)
|
|
{
|
|
currentAlpha = angleSection + this->MinimumAngle;
|
|
}
|
|
|
|
// Calculate startpoint coordinates
|
|
double thetaEllipse = this->ComputeEllipseAngle(currentAlpha, this->Ratio);
|
|
double xStart = this->Pole[0] + this->MinimumRadius * cos(thetaEllipse);
|
|
double yStart = this->Pole[1] + this->MinimumRadius * this->Ratio * sin(thetaEllipse);
|
|
|
|
// Calculate endpoint coordinates
|
|
double xEnd = this->Pole[0] + this->MaximumRadius * cos(thetaEllipse);
|
|
double yEnd = this->Pole[1] + this->MaximumRadius * this->Ratio * sin(thetaEllipse);
|
|
|
|
// radius angle (different from angle used to compute ellipse point)
|
|
actualAngle = vtkMath::DegreesFromRadians(atan2(yEnd - this->Pole[1], xEnd - this->Pole[0]));
|
|
|
|
// to keep angle positive for the last ones
|
|
if (actualAngle > 0.0 || this->MinimumAngle < 180.0)
|
|
{
|
|
positiveSection = true;
|
|
}
|
|
|
|
if (actualAngle < 0.0 && positiveSection)
|
|
{
|
|
actualAngle += 360.0;
|
|
}
|
|
|
|
// Set radial axis endpoints
|
|
vtkAxisActor* axis = this->RadialAxes[i];
|
|
|
|
// The last arc has its own property
|
|
if ((alphaDeg + dAlpha) >= alphaStop)
|
|
{
|
|
axis->SetAxisLinesProperty(this->LastRadialAxisProperty);
|
|
axis->SetTitleTextProperty(this->LastRadialAxisTextProperty);
|
|
}
|
|
else
|
|
{
|
|
axis->SetAxisLinesProperty(this->SecondaryRadialAxesProperty);
|
|
axis->SetTitleTextProperty(this->SecondaryRadialAxesTextProperty);
|
|
}
|
|
|
|
axis->GetPoint1Coordinate()->SetValue(xStart, yStart, this->Pole[2]);
|
|
axis->GetPoint2Coordinate()->SetValue(xEnd, yEnd, this->Pole[2]);
|
|
|
|
// set the range steps
|
|
axis->SetDeltaRangeMajor(this->PolarAxis->GetDeltaRangeMajor());
|
|
axis->SetDeltaRangeMinor(this->PolarAxis->GetDeltaRangeMinor());
|
|
|
|
// Set common axis attributes
|
|
this->SetCommonAxisAttributes(axis);
|
|
|
|
// Set radial axis lines
|
|
axis->SetAxisVisibility(this->RadialAxesVisibility);
|
|
|
|
// Set title relative location from the axis
|
|
if (this->RadialAxisTitleLocation == VTK_TITLE_BOTTOM)
|
|
{
|
|
axis->SetTitleAlignLocation(vtkAxisActor::VTK_ALIGN_BOTTOM);
|
|
}
|
|
else
|
|
{
|
|
axis->SetTitleAlignLocation(vtkAxisActor::VTK_ALIGN_POINT2);
|
|
}
|
|
|
|
// Set radial axis title with polar angle as title for non-polar axes
|
|
if (this->PolarAxisVisibility && fabs(alphaDeg) < 2.)
|
|
{
|
|
// Prevent conflict between radial and polar axes titles
|
|
axis->SetTitleVisibility(false);
|
|
|
|
if (fabs(alphaDeg) < this->SmallestVisiblePolarAngle)
|
|
{
|
|
// Do not show radial axes too close to polar axis
|
|
axis->SetAxisVisibility(false);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// Use polar angle as a title for the radial axis
|
|
axis->SetTitleVisibility(this->RadialTitleVisibility);
|
|
axis->GetTitleTextProperty()->SetColor(this->LastRadialAxisProperty->GetColor());
|
|
std::ostringstream title;
|
|
|
|
title.setf(std::ios::fixed, std::ios::floatfield);
|
|
sprintf(titleValue, this->RadialAngleFormat, actualAngle);
|
|
title << titleValue << (this->RadialUnits ? " deg" : "");
|
|
axis->SetTitle(title.str().c_str());
|
|
|
|
// Update axis title followers
|
|
axis->GetTitleActor()->SetAxis(axis);
|
|
axis->GetTitleActor()->SetEnableDistanceLOD(this->EnableDistanceLOD);
|
|
axis->GetTitleActor()->SetDistanceLODThreshold(this->DistanceLODThreshold);
|
|
axis->GetTitleActor()->SetEnableViewAngleLOD(this->EnableViewAngleLOD);
|
|
axis->GetTitleActor()->SetViewAngleLODThreshold(this->ViewAngleLODThreshold);
|
|
}
|
|
|
|
// Ticks for the last radial axis
|
|
if (angleSection != 360.0 && i == this->NumberOfRadialAxes - 1)
|
|
{
|
|
// axis Type. We assume the polar graph is built in the local plane x-y
|
|
if ((actualAngle > 45.0 && actualAngle < 135.0) ||
|
|
(actualAngle > 225.0 && actualAngle < 315.0))
|
|
{
|
|
axis->SetAxisTypeToY();
|
|
}
|
|
else
|
|
axis->SetAxisTypeToX();
|
|
|
|
// Set polar axis ticks
|
|
axis->SetTickVisibility(this->AxisTickVisibility && this->PolarTickVisibility);
|
|
axis->SetMajorTickSize(this->LastRadialAxisMajorTickSize);
|
|
|
|
// Set polar axis minor ticks
|
|
axis->SetMinorTicksVisible(this->AxisMinorTickVisibility && this->PolarTickVisibility);
|
|
axis->SetMinorTickSize(this->LastAxisTickRatioSize * this->LastRadialAxisMajorTickSize);
|
|
|
|
// Set the tick orientation
|
|
axis->SetTickLocation(this->TickLocation);
|
|
|
|
axis->GetAxisMajorTicksProperty()->SetLineWidth(this->LastRadialAxisMajorTickThickness);
|
|
minorThickness = this->LastRadialAxisMajorTickThickness * LastAxisTickRatioThickness;
|
|
if (minorThickness < 1.0)
|
|
{
|
|
minorThickness = 1.0;
|
|
}
|
|
axis->GetAxisMinorTicksProperty()->SetLineWidth(minorThickness);
|
|
}
|
|
else
|
|
{
|
|
axis->SetLabelVisibility(0);
|
|
axis->SetTickVisibility(0);
|
|
}
|
|
}
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
void vtkPolarAxesActor::BuildArcTicks()
|
|
{
|
|
bool originToPolarAxis = this->ArcTicksOriginToPolarAxis != 0.0;
|
|
|
|
// set MaximumAngle and MinimumAngle range: [0.0; 360.0]
|
|
double angleSection = (this->MaximumAngle > this->MinimumAngle)?
|
|
this->MaximumAngle - this->MinimumAngle: 360.0 - fabs(this->MaximumAngle - this->MinimumAngle);
|
|
|
|
if (vtkMathUtilities::FuzzyCompare(this->MaximumAngle, this->MinimumAngle) || angleSection == 360.0)
|
|
{
|
|
angleSection = 360.0;
|
|
}
|
|
|
|
// Create requested number of radial axes
|
|
double dAlpha = this->DeltaAngleMajor;
|
|
double alphaStart;
|
|
|
|
alphaStart = (originToPolarAxis) ? this->MinimumAngle + dAlpha: std::floor(this->MinimumAngle / dAlpha) * dAlpha + dAlpha;
|
|
|
|
for (double alphaDeg = alphaStart; alphaDeg < (angleSection + this->MinimumAngle); alphaDeg += dAlpha)
|
|
{
|
|
double thetaEllipse = ComputeEllipseAngle(alphaDeg, this->Ratio);
|
|
StoreTicksPtsFromParamEllipse(this->MaximumRadius, thetaEllipse, this->ArcMajorTickSize, this->ArcMajorTickPts);
|
|
}
|
|
|
|
// Copy/paste should be replaced with a python-like generator to provide parameters to StoreTicksPtsFromParamEllipse()
|
|
// without running twice through the ellipse
|
|
|
|
dAlpha = this->DeltaAngleMinor;
|
|
alphaStart = (originToPolarAxis) ? this->MinimumAngle + dAlpha: std::floor(this->MinimumAngle / dAlpha) * dAlpha + dAlpha;
|
|
for (double alphaDeg = alphaStart; alphaDeg < (angleSection + this->MinimumAngle); alphaDeg += dAlpha)
|
|
{
|
|
double thetaEllipse = ComputeEllipseAngle(alphaDeg, this->Ratio);
|
|
StoreTicksPtsFromParamEllipse(this->MaximumRadius, thetaEllipse, this->ArcTickRatioSize * this->ArcMajorTickSize, this->ArcMinorTickPts);
|
|
}
|
|
|
|
// set vtk object to draw the ticks
|
|
vtkNew<vtkPoints> majorPts;
|
|
vtkNew<vtkPoints> minorPts;
|
|
vtkNew<vtkCellArray> majorLines;
|
|
vtkNew<vtkCellArray> minorLines;
|
|
vtkIdType ptIds[2];
|
|
int numTickPts, numLines, i;
|
|
this->ArcTickPolyData->SetPoints(majorPts.Get());
|
|
this->ArcTickPolyData->SetLines(majorLines.Get());
|
|
this->ArcMinorTickPolyData->SetPoints(minorPts.Get());
|
|
this->ArcMinorTickPolyData->SetLines(minorLines.Get());
|
|
|
|
if (this->ArcTickVisibility)
|
|
{
|
|
numTickPts = this->ArcMajorTickPts->GetNumberOfPoints();
|
|
for (i = 0; i < numTickPts; i++)
|
|
{
|
|
majorPts->InsertNextPoint(this->ArcMajorTickPts->GetPoint(i));
|
|
}
|
|
}
|
|
if (this->ArcMinorTickVisibility)
|
|
{
|
|
// In 2D mode, the minorTickPts for yz portion or xz portion have been removed.
|
|
numTickPts = this->ArcMinorTickPts->GetNumberOfPoints();
|
|
for (i = 0; i < numTickPts; i++)
|
|
{
|
|
minorPts->InsertNextPoint(this->ArcMinorTickPts->GetPoint(i));
|
|
}
|
|
}
|
|
|
|
// create lines
|
|
if (this->ArcTickVisibility)
|
|
{
|
|
numLines = majorPts->GetNumberOfPoints() / 2;
|
|
for (i = 0; i < numLines; i++)
|
|
{
|
|
ptIds[0] = 2 * i;
|
|
ptIds[1] = 2 * i + 1;
|
|
majorLines->InsertNextCell(2, ptIds);
|
|
}
|
|
}
|
|
if (this->ArcMinorTickVisibility)
|
|
{
|
|
numLines = minorPts->GetNumberOfPoints() / 2;
|
|
for (i = 0; i < numLines; i++)
|
|
{
|
|
ptIds[0] = 2 * i;
|
|
ptIds[1] = 2 * i + 1;
|
|
minorLines->InsertNextCell(2, ptIds);
|
|
}
|
|
}
|
|
}
|
|
|
|
void vtkPolarAxesActor::StoreTicksPtsFromParamEllipse(double a, double angleEllipseRad, double tickSize, vtkPoints* tickPts)
|
|
{
|
|
// plane point: point located in the plane of the ellipse
|
|
// normal Dir Point: point located according to the direction of the z vector
|
|
|
|
// inside direction: direction from the arc to its center for plane points, and positive z direction
|
|
// outside direction: direction from the arc to the outer radial direction for plane points, and negative z direction
|
|
|
|
int i;
|
|
double planeInPt[3], planeOutPt[3], normalDirPt[3], invNormalDirPt[3];
|
|
|
|
if (!tickPts)
|
|
{
|
|
return;
|
|
}
|
|
|
|
double b = a * this->Ratio;
|
|
double xArc = this->Pole[0] + a * cos(angleEllipseRad);
|
|
double yArc = this->Pole[1] + b * sin(angleEllipseRad);
|
|
double ellipsePt[3] = {xArc, yArc, this->Pole[2]};
|
|
|
|
double deltaVector[3] = {a * cos(angleEllipseRad), b * sin(angleEllipseRad), 0.0 };
|
|
vtkMath::Normalize(deltaVector);
|
|
|
|
double orthoVector[3] = {0.0, 0.0, 1.0};
|
|
|
|
// init
|
|
for (i = 0;i<3;i++)
|
|
{
|
|
planeInPt[i] = planeOutPt[i] = normalDirPt[i] = invNormalDirPt[i] = ellipsePt[i];
|
|
}
|
|
|
|
if (this->TickLocation == vtkAxisActor::VTK_TICKS_INSIDE || this->TickLocation == vtkAxisActor::VTK_TICKS_BOTH)
|
|
{
|
|
for (i = 0;i<3;i++)
|
|
{
|
|
planeInPt[i] = ellipsePt[i] - tickSize * deltaVector[i];
|
|
}
|
|
|
|
for (i = 0;i<3;i++)
|
|
{
|
|
normalDirPt[i] = ellipsePt[i] + tickSize * orthoVector[i];
|
|
}
|
|
}
|
|
|
|
if (this->TickLocation == vtkAxisActor::VTK_TICKS_OUTSIDE || this->TickLocation == vtkAxisActor::VTK_TICKS_BOTH)
|
|
{
|
|
for (i = 0;i<3;i++)
|
|
{
|
|
planeOutPt[i] = ellipsePt[i] + tickSize * deltaVector[i];
|
|
}
|
|
|
|
for (i = 0;i<3;i++)
|
|
{
|
|
invNormalDirPt[i] = ellipsePt[i] - tickSize * orthoVector[i];
|
|
}
|
|
}
|
|
|
|
tickPts->InsertNextPoint(planeInPt);
|
|
tickPts->InsertNextPoint(planeOutPt);
|
|
tickPts->InsertNextPoint(normalDirPt);
|
|
tickPts->InsertNextPoint(invNormalDirPt);
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
void vtkPolarAxesActor::BuildPolarAxisLabelsArcs()
|
|
{
|
|
double angleSection = (this->MaximumAngle > this->MinimumAngle) ?
|
|
this->MaximumAngle - this->MinimumAngle: 360.0 -
|
|
fabs(this->MaximumAngle - this->MinimumAngle);
|
|
|
|
// if Min and max angle are the same, interpret it as 360 segment opening
|
|
if (vtkMathUtilities::FuzzyCompare(this->MaximumAngle, this->MinimumAngle))
|
|
{
|
|
angleSection = 360.0;
|
|
}
|
|
|
|
// Prepare trigonometric quantities
|
|
vtkIdType arcResolution = static_cast<vtkIdType>(
|
|
angleSection * (VTK_POLAR_ARC_RESOLUTION_PER_DEG / this->Ratio));
|
|
|
|
// Principal Arc points
|
|
vtkNew<vtkPoints> polarArcsPoints;
|
|
this->PolarArcs->SetPoints(polarArcsPoints.Get());
|
|
|
|
// Principal Arc lines
|
|
vtkNew<vtkCellArray> polarArcsLines;
|
|
this->PolarArcs->SetLines(polarArcsLines.Get());
|
|
|
|
// Secondary Arc points
|
|
vtkNew<vtkPoints> secondaryPolarArcsPoints;
|
|
this->SecondaryPolarArcs->SetPoints(secondaryPolarArcsPoints.Get());
|
|
|
|
// Secondary Arc lines
|
|
vtkNew<vtkCellArray> secondaryPolarArcsLines;
|
|
this->SecondaryPolarArcs->SetLines(secondaryPolarArcsLines.Get());
|
|
|
|
vtkAxisActor* axis = this->PolarAxis;
|
|
|
|
// Base ellipse arc value, refers to world coordinate system
|
|
double axisLength = this->MaximumRadius - this->MinimumRadius;
|
|
double rangeLength = axis->GetRange()[1] - axis->GetRange()[0];
|
|
double rangeScale = axisLength / rangeLength;
|
|
|
|
// Label values refers to range values
|
|
double valueRange = axis->GetRange()[0];
|
|
double currentValue;
|
|
double deltaRange = axis->GetDeltaRangeMajor();
|
|
double deltaArc;
|
|
|
|
// Prepare storage for polar axis labels
|
|
std::list<double> labelValList;
|
|
|
|
vtkIdType pointIdOffset = 0;
|
|
bool isInnerArc, isArcVisible, isLastArc;
|
|
|
|
currentValue = axis->GetRange()[0];
|
|
while (currentValue < axis->GetRange()[1])
|
|
{
|
|
currentValue =
|
|
(valueRange > axis->GetRange()[1]) ? axis->GetRange()[1]: valueRange;
|
|
deltaArc = (currentValue - axis->GetRange()[0]) * rangeScale;
|
|
|
|
isInnerArc =
|
|
currentValue > axis->GetRange()[0] && currentValue < axis->GetRange()[1];
|
|
isArcVisible = !isInnerArc || this->DrawPolarArcsGridlines;
|
|
isLastArc = currentValue == axis->GetRange()[1];
|
|
|
|
// Store value
|
|
labelValList.push_back(currentValue);
|
|
|
|
// Build polar arcs for non-zero values
|
|
if (deltaArc + this->MinimumRadius > 0. && isArcVisible)
|
|
{
|
|
// Create elliptical polar arc with corresponding to this tick mark
|
|
vtkNew<vtkEllipseArcSource> arc;
|
|
arc->SetCenter(this->Pole);
|
|
arc->SetRatio(this->Ratio);
|
|
arc->SetNormal(0., 0., 1.);
|
|
arc->SetMajorRadiusVector(deltaArc + this->MinimumRadius, 0.0, 0.0);
|
|
arc->SetStartAngle(this->MinimumAngle);
|
|
arc->SetSegmentAngle(angleSection);
|
|
arc->SetResolution(arcResolution);
|
|
arc->Update();
|
|
|
|
if (isLastArc)
|
|
{
|
|
// Add polar arc
|
|
vtkPoints* arcPoints = NULL;
|
|
vtkIdType nPoints = 0;
|
|
vtkIdType* arcPointIds = NULL;
|
|
if (arc->GetOutput()->GetNumberOfPoints() > 0)
|
|
{
|
|
arcPoints = arc->GetOutput()->GetPoints();
|
|
nPoints = arcResolution + 1;
|
|
arcPointIds = new vtkIdType[nPoints];
|
|
for (vtkIdType j = 0; j < nPoints; ++ j)
|
|
{
|
|
polarArcsPoints->InsertNextPoint(arcPoints->GetPoint(j));
|
|
arcPointIds[j] = j;
|
|
}
|
|
polarArcsLines->InsertNextCell(nPoints, arcPointIds);
|
|
}
|
|
|
|
// Clean up
|
|
delete [] arcPointIds;
|
|
}
|
|
else
|
|
{
|
|
// Append new secondary polar arc to existing ones
|
|
vtkPoints* arcPoints = NULL;
|
|
vtkIdType nPoints = 0;
|
|
vtkIdType* arcPointIds = NULL;
|
|
if (arc->GetOutput()->GetNumberOfPoints() > 0)
|
|
{
|
|
arcPoints = arc->GetOutput()->GetPoints();
|
|
nPoints = arcResolution + 1;
|
|
arcPointIds = new vtkIdType[nPoints];
|
|
|
|
for (vtkIdType j = 0; j < nPoints; ++ j)
|
|
{
|
|
secondaryPolarArcsPoints->InsertNextPoint(arcPoints->GetPoint(j));
|
|
arcPointIds[j] = pointIdOffset + j;
|
|
}
|
|
secondaryPolarArcsLines->InsertNextCell(nPoints, arcPointIds);
|
|
}
|
|
|
|
// Clean up
|
|
delete [] arcPointIds;
|
|
|
|
// Update polyline cell offset
|
|
pointIdOffset += nPoints;
|
|
}
|
|
}
|
|
|
|
// Move to next value
|
|
valueRange += deltaRange;
|
|
}
|
|
|
|
// set up vtk collection to store labels
|
|
vtkNew<vtkStringArray> labels;
|
|
|
|
if (this->ExponentLocation != VTK_EXPONENT_LABELS)
|
|
{
|
|
// it modifies the values of labelValList
|
|
std::string commonLbl = FindExponentAndAdjustValues(labelValList);
|
|
axis->SetExponent(commonLbl.c_str());
|
|
|
|
this->GetSignificantPartFromValues(labels.Get(), labelValList);
|
|
}
|
|
else
|
|
{
|
|
axis->SetExponent("");
|
|
// construct label string array
|
|
labels->SetNumberOfValues(labelValList.size());
|
|
|
|
std::list<double>::iterator itList;
|
|
std::size_t i = 0;
|
|
for (itList = labelValList.begin();
|
|
itList != labelValList.end(); i++, itList++)
|
|
{
|
|
char label[64];
|
|
sprintf(label, this->PolarLabelFormat, *itList);
|
|
labels->SetValue(i, label);
|
|
}
|
|
}
|
|
|
|
// Store labels
|
|
axis->SetLabels(labels.Get());
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
void vtkPolarAxesActor::BuildPolarArcsLog()
|
|
{
|
|
double angleSection = (this->MaximumAngle > this->MinimumAngle)?
|
|
this->MaximumAngle - this->MinimumAngle: 360.0 -
|
|
fabs(this->MaximumAngle - this->MinimumAngle);
|
|
|
|
// if Min and max angle are the same, interpret it as 360 segment opening
|
|
if (vtkMathUtilities::FuzzyCompare(this->MaximumAngle, this->MinimumAngle))
|
|
{
|
|
angleSection = 360.0;
|
|
}
|
|
|
|
vtkIdType arcResolution =
|
|
static_cast<vtkIdType>(angleSection * (VTK_POLAR_ARC_RESOLUTION_PER_DEG / this->Ratio));
|
|
|
|
// Principal Arc points
|
|
vtkNew<vtkPoints> polarArcsPoints;
|
|
this->PolarArcs->SetPoints(polarArcsPoints.Get());
|
|
|
|
// Principal Arc lines
|
|
vtkNew<vtkCellArray> polarArcsLines;
|
|
this->PolarArcs->SetLines(polarArcsLines.Get());
|
|
|
|
// Secondary Arc points
|
|
vtkNew<vtkPoints> secondaryPolarArcsPoints;
|
|
this->SecondaryPolarArcs->SetPoints(secondaryPolarArcsPoints.Get());
|
|
|
|
// Secondary Arc lines
|
|
vtkNew<vtkCellArray> secondaryPolarArcsLines;
|
|
this->SecondaryPolarArcs->SetLines(secondaryPolarArcsLines.Get());
|
|
|
|
//--- prepare significant values ----
|
|
double miniAngleEllipseRad = ComputeEllipseAngle(this->MinimumAngle, this->Ratio);
|
|
|
|
// Distance from Pole to Range[0]
|
|
vtkAxisActor* axis = this->PolarAxis;
|
|
|
|
double deltaVector[3], polarAxisUnitVect[3];
|
|
vtkMath::Subtract(axis->GetPoint2(), axis->GetPoint1(), deltaVector);
|
|
vtkMath::Subtract(axis->GetPoint2(), axis->GetPoint1(), polarAxisUnitVect);
|
|
vtkMath::Normalize(polarAxisUnitVect);
|
|
|
|
// polar axis actor length
|
|
double axisLength = vtkMath::Norm(deltaVector);
|
|
|
|
// conversion factor
|
|
double rangeScaleLog = axisLength / log10(axis->GetRange()[1] / axis->GetRange()[0]);
|
|
|
|
// reuse deltaVector
|
|
vtkMath::Subtract(axis->GetPoint1(), this->Pole, deltaVector);
|
|
double distanceAxisPoint1FromPole = vtkMath::Norm(deltaVector);
|
|
|
|
double base = 10.0;
|
|
double log10Range0 = log10(axis->GetRange()[0]);
|
|
double log10Range1 = log10(axis->GetRange()[1]);
|
|
double lowBound = std::pow(base, static_cast<int>(std::floor(log10Range0)));
|
|
double upBound = std::pow(base, static_cast<int>(ceil(log10Range1)));
|
|
|
|
int i;
|
|
double tickVal, tickRangeVal, indexTickRangeValue;
|
|
|
|
vtkIdType pointIdOffset = 0;
|
|
bool isInnerArc, isArcVisible, isLastArc;
|
|
double a, b;
|
|
double epsilon = 1e-8;
|
|
|
|
for (indexTickRangeValue = lowBound; indexTickRangeValue <= upBound; indexTickRangeValue *= base)
|
|
{
|
|
// to keep major values as power of 10
|
|
tickRangeVal = indexTickRangeValue;
|
|
|
|
isInnerArc = tickRangeVal > lowBound && tickRangeVal < upBound;
|
|
isArcVisible = !isInnerArc || this->DrawPolarArcsGridlines;
|
|
isLastArc = tickRangeVal == upBound;
|
|
|
|
if (!isArcVisible)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
if (tickRangeVal < axis->GetRange()[0])
|
|
{
|
|
tickRangeVal = axis->GetRange()[0];
|
|
}
|
|
|
|
if (tickRangeVal > axis->GetRange()[1])
|
|
{
|
|
tickRangeVal = axis->GetRange()[1];
|
|
}
|
|
|
|
// conversion range value to world value
|
|
tickVal = (log10(tickRangeVal) - log10Range0) * rangeScaleLog;
|
|
|
|
// Vector from Pole to major tick
|
|
for (i = 0; i<3; i++)
|
|
{
|
|
deltaVector[i] = polarAxisUnitVect[i]* (tickVal + distanceAxisPoint1FromPole);
|
|
}
|
|
|
|
if (vtkMath::Norm(deltaVector) == 0.0)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
// epsilon is a very low value. vtkMathUtilities::FuzzyCompare is not fuzzy enough ...
|
|
if (fabs(fabs(miniAngleEllipseRad) - vtkMath::Pi() / 2.0) < epsilon)
|
|
{
|
|
b = deltaVector[1] / sin(miniAngleEllipseRad);
|
|
a = b / this->Ratio;
|
|
}
|
|
else
|
|
{
|
|
a = deltaVector[0] / cos(miniAngleEllipseRad);
|
|
}
|
|
|
|
// Create elliptical polar arc with corresponding to this tick mark
|
|
vtkNew<vtkEllipseArcSource> arc;
|
|
arc->SetCenter(this->Pole);
|
|
arc->SetRatio(this->Ratio);
|
|
arc->SetNormal(0., 0., 1.);
|
|
arc->SetMajorRadiusVector(a, 0.0, 0.0);
|
|
arc->SetStartAngle(this->MinimumAngle);
|
|
arc->SetSegmentAngle(angleSection);
|
|
arc->SetResolution(arcResolution);
|
|
arc->Update();
|
|
|
|
if (isLastArc)
|
|
{
|
|
// Add principal polar arc
|
|
vtkPoints* arcPoints = NULL;
|
|
vtkIdType nPoints;
|
|
vtkIdType* arcPointIds = NULL;
|
|
if (arc->GetOutput()->GetNumberOfPoints() > 0)
|
|
{
|
|
arcPoints = arc->GetOutput()->GetPoints();
|
|
nPoints = arcResolution + 1;
|
|
arcPointIds = new vtkIdType[nPoints];
|
|
for (vtkIdType j = 0; j < nPoints; ++ j)
|
|
{
|
|
polarArcsPoints->InsertNextPoint(arcPoints->GetPoint(j));
|
|
arcPointIds[j] = j;
|
|
}
|
|
polarArcsLines->InsertNextCell(nPoints, arcPointIds);
|
|
}
|
|
// Clean up
|
|
delete [] arcPointIds;
|
|
}
|
|
else
|
|
{
|
|
// Append new polar arc to existing ones
|
|
vtkPoints* arcPoints = NULL;
|
|
vtkIdType nPoints = 0;
|
|
vtkIdType* arcPointIds = NULL;
|
|
if (arc->GetOutput()->GetNumberOfPoints() > 0)
|
|
{
|
|
arcPoints = arc->GetOutput()->GetPoints();
|
|
nPoints = arcResolution + 1;
|
|
arcPointIds = new vtkIdType[nPoints];
|
|
for (vtkIdType j = 0; j < nPoints; ++ j)
|
|
{
|
|
secondaryPolarArcsPoints->InsertNextPoint(arcPoints->GetPoint(j));
|
|
arcPointIds[j] = pointIdOffset + j;
|
|
}
|
|
secondaryPolarArcsLines->InsertNextCell(nPoints, arcPointIds);
|
|
}
|
|
// Clean up
|
|
delete [] arcPointIds;
|
|
|
|
// Update polyline cell offset
|
|
pointIdOffset += nPoints;
|
|
}
|
|
}
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
void vtkPolarAxesActor::BuildLabelsLog()
|
|
{
|
|
// Prepare storage for polar axis labels
|
|
std::list<double> labelValList;
|
|
|
|
vtkAxisActor* axis = this->PolarAxis;
|
|
double base = 10.0;
|
|
|
|
if (axis->GetRange()[0] <= 0.0)
|
|
{
|
|
return;
|
|
}
|
|
|
|
// define major ticks label values
|
|
double indexTickRangeValue;
|
|
double tickRangeVal;
|
|
double log10Range0 = log10(axis->GetRange()[0]);
|
|
double log10Range1 = log10(axis->GetRange()[1]);
|
|
double lowBound = std::pow(base, static_cast<int>(std::floor(log10Range0)));
|
|
double upBound = std::pow(base, static_cast<int>(ceil(log10Range1)));
|
|
|
|
for (indexTickRangeValue = lowBound; indexTickRangeValue <= upBound; indexTickRangeValue *= base)
|
|
{
|
|
tickRangeVal = indexTickRangeValue;
|
|
|
|
if (indexTickRangeValue < axis->GetRange()[0])
|
|
{
|
|
tickRangeVal = axis->GetRange()[0];
|
|
}
|
|
|
|
else if (indexTickRangeValue > axis->GetRange()[1])
|
|
{
|
|
tickRangeVal = axis->GetRange()[1];
|
|
}
|
|
|
|
labelValList.push_back(tickRangeVal);
|
|
}
|
|
|
|
// set up vtk collection to store labels
|
|
vtkNew<vtkStringArray> labels;
|
|
|
|
if (this->ExponentLocation != VTK_EXPONENT_LABELS)
|
|
{
|
|
// it modifies the values of labelValList
|
|
std::string commonLbl = FindExponentAndAdjustValues(labelValList);
|
|
axis->SetExponent(commonLbl.c_str());
|
|
|
|
this->GetSignificantPartFromValues(labels.Get(), labelValList);
|
|
}
|
|
else
|
|
{
|
|
axis->SetExponent("");
|
|
labels->SetNumberOfValues(labelValList.size());
|
|
|
|
std::list<double>::iterator itList;
|
|
std::size_t i = 0;
|
|
for (itList = labelValList.begin();
|
|
itList != labelValList.end(); i++, itList++)
|
|
{
|
|
char label[64];
|
|
sprintf(label, this->PolarLabelFormat, *itList);
|
|
labels->SetValue(i, label);
|
|
}
|
|
}
|
|
|
|
// Store labels
|
|
axis->SetLabels(labels.Get());
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
void vtkPolarAxesActor::BuildPolarAxisLabelsArcsLog()
|
|
{
|
|
this->BuildPolarArcsLog();
|
|
|
|
this->BuildLabelsLog();
|
|
|
|
// Update axis title follower
|
|
vtkAxisFollower* follower = this->PolarAxis->GetTitleActor();
|
|
follower->SetAxis(this->PolarAxis);
|
|
follower->SetEnableDistanceLOD(this->EnableDistanceLOD);
|
|
follower->SetDistanceLODThreshold(this->DistanceLODThreshold);
|
|
follower->SetEnableViewAngleLOD(this->EnableViewAngleLOD);
|
|
follower->SetViewAngleLODThreshold(this->ViewAngleLODThreshold);
|
|
|
|
// Update axis title follower
|
|
vtkAxisFollower* expFollower = this->PolarAxis->GetExponentActor();
|
|
expFollower->SetAxis(this->PolarAxis);
|
|
expFollower->SetEnableDistanceLOD(this->EnableDistanceLOD);
|
|
expFollower->SetDistanceLODThreshold(this->DistanceLODThreshold);
|
|
expFollower->SetEnableViewAngleLOD(this->EnableViewAngleLOD);
|
|
expFollower->SetViewAngleLODThreshold(this->ViewAngleLODThreshold);
|
|
|
|
// Update axis label followers
|
|
vtkAxisFollower** labelActors = this->PolarAxis->GetLabelActors();
|
|
int labelCount = this->PolarAxis->GetNumberOfLabelsBuilt();
|
|
for (int i = 0; i < labelCount; ++ i)
|
|
{
|
|
labelActors[i]->SetAxis(this->PolarAxis);
|
|
labelActors[i]->SetEnableDistanceLOD(this->EnableDistanceLOD);
|
|
labelActors[i]->SetDistanceLODThreshold(this->DistanceLODThreshold);
|
|
labelActors[i]->SetEnableViewAngleLOD(this->EnableViewAngleLOD);
|
|
labelActors[i]->SetViewAngleLODThreshold(this->ViewAngleLODThreshold);
|
|
}
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
std::string vtkPolarAxesActor::FindExponentAndAdjustValues(
|
|
std::list<double>& valuesList)
|
|
{
|
|
std::list<double>::iterator itDouble;
|
|
|
|
double exponentMean = 0.0;
|
|
int count = 0;
|
|
|
|
// find common exponent
|
|
for (itDouble = valuesList.begin(); itDouble != valuesList.end(); itDouble++)
|
|
{
|
|
if (*itDouble != 0.0)
|
|
{
|
|
double exponent = std::floor(log10(fabs(*itDouble)));
|
|
exponentMean += exponent;
|
|
count++;
|
|
}
|
|
}
|
|
|
|
if (count == 0)
|
|
{
|
|
return "";
|
|
}
|
|
|
|
exponentMean /= count;
|
|
|
|
// adjust exponent to int value. Round it if fract part != 0.0
|
|
double intPart, fractPart;
|
|
fractPart = modf(exponentMean, &intPart);
|
|
|
|
if (exponentMean < 0.0)
|
|
{
|
|
if (fabs(fractPart) >= 0.5)
|
|
{
|
|
intPart -= 1.0;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (fabs(fractPart) >= 0.5)
|
|
{
|
|
intPart += 1.0;
|
|
}
|
|
}
|
|
exponentMean = intPart;
|
|
|
|
// shift every values
|
|
for (itDouble = valuesList.begin(); itDouble != valuesList.end(); itDouble++)
|
|
{
|
|
if (*itDouble != 0.0)
|
|
{
|
|
*itDouble /= std::pow(10, exponentMean);
|
|
}
|
|
}
|
|
|
|
// Layout of the exponent:
|
|
std::stringstream ss;
|
|
int exponentInt = static_cast<int>(fabs(exponentMean));
|
|
|
|
// add sign
|
|
ss << (exponentMean >= 0.0 ? "+" : "-");
|
|
|
|
// add 0 for pow < 10
|
|
if (exponentInt < 10.0)
|
|
{
|
|
ss << "0";
|
|
}
|
|
|
|
ss << exponentInt;
|
|
|
|
return ss.str();
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
void vtkPolarAxesActor::GetSignificantPartFromValues(vtkStringArray* valuesStr,
|
|
std::list<double>& valuesList)
|
|
{
|
|
if (!valuesStr || valuesList.size() == 0)
|
|
{
|
|
return;
|
|
}
|
|
|
|
valuesStr->SetNumberOfValues(valuesList.size());
|
|
|
|
std::list<double>::iterator itList;
|
|
std::size_t i = 0;
|
|
for (itList = valuesList.begin();
|
|
itList != valuesList.end(); i++, itList++)
|
|
{
|
|
char label[64];
|
|
if (this->ExponentLocation == VTK_EXPONENT_LABELS)
|
|
{
|
|
sprintf(label, this->PolarLabelFormat, *itList);
|
|
valuesStr->SetValue(i, label);
|
|
}
|
|
else
|
|
{
|
|
std::stringstream ss;
|
|
if (*itList == 0.0)
|
|
{
|
|
ss << std::fixed << std::setw(1) << std::setprecision(0) << 0.0;
|
|
valuesStr->SetValue(i, ss.str().c_str());
|
|
continue;
|
|
}
|
|
|
|
// get pow of ten of the value to set the precision of the label
|
|
int exponent = static_cast<int>(std::floor(log10(fabs(*itList))));
|
|
if (exponent < 0)
|
|
{
|
|
ss << std::fixed << std::setw(1) << setprecision(-exponent) << *itList;
|
|
}
|
|
else
|
|
{
|
|
ss << std::fixed << setprecision(1) << *itList;
|
|
}
|
|
|
|
valuesStr->SetValue(i, ss.str().c_str());
|
|
}
|
|
}
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
void vtkPolarAxesActor::AutoScale(vtkViewport *viewport)
|
|
{
|
|
// Scale polar axis title
|
|
vtkAxisActor* axis = this->PolarAxis;
|
|
double newTitleScale
|
|
= vtkAxisFollower::AutoScale(viewport,
|
|
this->Camera,
|
|
this->ScreenSize,
|
|
axis->GetTitleActor()->GetPosition());
|
|
axis->SetTitleScale(newTitleScale);
|
|
|
|
// Scale polar axis labels
|
|
axis->SetLabelScale(newTitleScale);
|
|
|
|
// Loop over radial axes
|
|
for (int i = 0; i < this->NumberOfRadialAxes; ++ i)
|
|
{
|
|
axis = this->RadialAxes[i];
|
|
// Scale title
|
|
newTitleScale
|
|
= vtkAxisFollower::AutoScale(viewport,
|
|
this->Camera,
|
|
this->ScreenSize,
|
|
axis->GetTitleActor()->GetPosition());
|
|
axis->SetTitleScale(newTitleScale);
|
|
}
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
void vtkPolarAxesActor::SetPole(double p[3])
|
|
{
|
|
this->Pole[0] = p[0];
|
|
this->Pole[1] = p[1];
|
|
this->Pole[2] = p[2];
|
|
|
|
// Update bounds
|
|
this->CalculateBounds();
|
|
this->Modified();
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
void vtkPolarAxesActor::SetPole(double x, double y, double z)
|
|
{
|
|
this->Pole[0] = x;
|
|
this->Pole[1] = y;
|
|
this->Pole[2] = z;
|
|
|
|
// Update bounds
|
|
this->CalculateBounds();
|
|
this->Modified();
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
void vtkPolarAxesActor::SetMinimumRadius(double r)
|
|
{
|
|
this->MinimumRadius = r > 0. ? r : 0.;
|
|
|
|
// Update bounds
|
|
this->CalculateBounds();
|
|
this->Modified();
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
void vtkPolarAxesActor::SetMaximumRadius(double r)
|
|
{
|
|
this->MaximumRadius = r > 0. ? r : 0.;
|
|
|
|
// Update bounds
|
|
this->CalculateBounds();
|
|
this->Modified();
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
void vtkPolarAxesActor::SetMinimumAngle(double a)
|
|
{
|
|
if (a > 360.)
|
|
{
|
|
this->MinimumAngle = 360.;
|
|
}
|
|
else if (a < -360.)
|
|
{
|
|
this->MinimumAngle = -360.;
|
|
}
|
|
else
|
|
{
|
|
this->MinimumAngle = a;
|
|
}
|
|
|
|
// Update bounds
|
|
this->CalculateBounds();
|
|
this->Modified();
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
void vtkPolarAxesActor::SetMaximumAngle(double a)
|
|
{
|
|
if (a > 360.)
|
|
{
|
|
this->MaximumAngle = 360.;
|
|
}
|
|
else if (a < -360.)
|
|
{
|
|
this->MaximumAngle = -360.;
|
|
}
|
|
else
|
|
{
|
|
this->MaximumAngle = a;
|
|
}
|
|
|
|
// Update bounds
|
|
this->CalculateBounds();
|
|
this->Modified();
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
void vtkPolarAxesActor::SetUse2DMode(int val)
|
|
{
|
|
for (int i = 0; i < this->NumberOfRadialAxes; ++i)
|
|
{
|
|
this->RadialAxes[i]->SetUse2DMode(val);
|
|
}
|
|
|
|
this->PolarAxis->SetUse2DMode(val);
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
int vtkPolarAxesActor::GetUse2DMode()
|
|
{
|
|
return this->PolarAxis->GetUse2DMode();
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
void vtkPolarAxesActor::SetPolarAxisProperty(vtkProperty *prop)
|
|
{
|
|
this->PolarAxisProperty->DeepCopy(prop);
|
|
this->PolarAxisProperty->SetLineWidth(this->PolarAxisMajorTickThickness);
|
|
this->Modified();
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
void vtkPolarAxesActor::SetPolarArcsProperty(vtkProperty * prop)
|
|
{
|
|
this->PolarArcsActor->SetProperty(prop);
|
|
this->Modified();
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
vtkProperty* vtkPolarAxesActor::GetPolarArcsProperty()
|
|
{
|
|
return this->PolarArcsActor->GetProperty();
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
void vtkPolarAxesActor::SetSecondaryPolarArcsProperty(vtkProperty *prop)
|
|
{
|
|
this->SecondaryPolarArcsActor->SetProperty(prop);
|
|
this->Modified();
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
vtkProperty* vtkPolarAxesActor::GetSecondaryPolarArcsProperty()
|
|
{
|
|
return this->SecondaryPolarArcsActor->GetProperty();
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
void vtkPolarAxesActor::SetNumberOfPolarAxisTicks(int tickCountRequired)
|
|
{
|
|
double rangeLength = fabs(this->Range[1] - this->Range[0]);
|
|
double step = this->ComputeIdealStep(
|
|
tickCountRequired - 1, rangeLength, VTK_MAXIMUM_NUMBER_OF_POLAR_AXIS_TICKS - 1);
|
|
double tmpRangeMajor = this->DeltaRangeMajor;
|
|
double tmpRangeMinor = this->DeltaRangeMinor;
|
|
this->DeltaRangeMajor = (step == 0.0) ? rangeLength / 10.0 : step;
|
|
this->DeltaRangeMinor =
|
|
(step == 0.0) ? (this->DeltaRangeMajor / 2.0) : (step / 2.0);
|
|
if (tmpRangeMajor != this->DeltaRangeMajor || tmpRangeMinor != this->DeltaRangeMinor)
|
|
{
|
|
this->Modified();
|
|
}
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
void vtkPolarAxesActor::SetNumberOfRadialAxes(vtkIdType n)
|
|
{
|
|
if (n == 0)
|
|
{
|
|
if (this->DeltaAngleRadialAxes != 45.)
|
|
{
|
|
this->DeltaAngleRadialAxes = 45.0;
|
|
this->Modified();
|
|
return;
|
|
}
|
|
}
|
|
|
|
double angleSection = (this->MaximumAngle > this->MinimumAngle)?
|
|
this->MaximumAngle - this->MinimumAngle: 360.0 -
|
|
fabs(this->MaximumAngle - this->MinimumAngle);
|
|
|
|
// if Min and max angle are the same, interpret it as 360 segment opening
|
|
if (vtkMathUtilities::FuzzyCompare(this->MaximumAngle, this->MinimumAngle))
|
|
{
|
|
angleSection = 360.0;
|
|
}
|
|
|
|
double step = this->ComputeIdealStep(n - 1, angleSection);
|
|
if (step == 0.0)
|
|
{
|
|
step = angleSection / n;
|
|
}
|
|
|
|
if (this->DeltaAngleRadialAxes != step)
|
|
{
|
|
this->DeltaAngleRadialAxes = step;
|
|
this->Modified();
|
|
}
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
double vtkPolarAxesActor::ComputeIdealStep(
|
|
int subDivsRequired, double rangeLength, int maxSubDivs)
|
|
{
|
|
double pow10, pow10Start, pow10End;
|
|
double rawStep, roundStep, roundStepSup;
|
|
|
|
if (rangeLength == 0.0 || subDivsRequired >= maxSubDivs)
|
|
{
|
|
return 0.0;
|
|
}
|
|
|
|
if (subDivsRequired <= 1)
|
|
{
|
|
return rangeLength;
|
|
}
|
|
|
|
// range step, if axis range is strictly subdivided by the number of ticks wished
|
|
rawStep = rangeLength / subDivsRequired;
|
|
|
|
// pow of 10 order of magnitude
|
|
pow10Start = std::floor(log10(rawStep));
|
|
pow10End = -10.0;
|
|
if (pow10End >= pow10Start)
|
|
{
|
|
pow10End -= 1.0;
|
|
}
|
|
|
|
if (rawStep <= std::pow(10, pow10End))
|
|
{
|
|
return 0.0;
|
|
}
|
|
|
|
double dividend = rawStep;
|
|
|
|
double pow10Step;
|
|
double idealStep = 0.0;
|
|
double subdivs = 1.0, subdivsSup = 1.0;
|
|
|
|
int currentPow10Multiple;
|
|
|
|
for (pow10 = pow10Start; pow10 >= pow10End; pow10 -= 1.0)
|
|
{
|
|
// 10.0, 1.0, 0.1, ...
|
|
pow10Step = std::pow(10.0, pow10);
|
|
|
|
// example: 4 = 0.4874 / 0.1 for pow10Step = 0.1
|
|
currentPow10Multiple = static_cast<int> (dividend / pow10Step);
|
|
|
|
// 0.4 = 4 * 0.1
|
|
roundStep = currentPow10Multiple * pow10Step;
|
|
|
|
// 0.5 = 5 * 0.1
|
|
roundStepSup = (currentPow10Multiple + 1) * pow10Step;
|
|
|
|
// currentIdealStep is the previous digits of the ideal step we seek
|
|
subdivs = rangeLength / (idealStep + roundStep);
|
|
subdivsSup = rangeLength / (idealStep + roundStepSup);
|
|
|
|
if (fabs(subdivs - subDivsRequired) < 1.0 || fabs(subdivsSup - subDivsRequired) < 1.0)
|
|
{
|
|
// if currentStep + the current power of 10, is closer to the require tick count
|
|
if (fabs(subdivs - subDivsRequired) > fabs(subdivsSup - subDivsRequired) &&
|
|
fabs(subdivsSup - subDivsRequired) < 1.0)
|
|
{
|
|
idealStep += roundStepSup;
|
|
}
|
|
|
|
// subdivs closer to subdiv than subdivsSup
|
|
else
|
|
{
|
|
idealStep += roundStep;
|
|
}
|
|
break;
|
|
}
|
|
|
|
idealStep += roundStep;
|
|
|
|
// 0.4874 - 0.4 for roundStep = 0.4
|
|
// remainder becomes dividend
|
|
dividend = dividend - roundStep;
|
|
}
|
|
|
|
// if idealStep is too small
|
|
if (static_cast<int> (rangeLength / idealStep) > subDivsRequired)
|
|
{
|
|
idealStep = rawStep;
|
|
}
|
|
|
|
return idealStep;
|
|
}
|
|
|
|
//-----------------------------------------------------------------------------
|
|
int vtkPolarAxesActor::GetNumberOfPolarAxisTicks()
|
|
{
|
|
double rangeLength = fabs(this->Range[1] - this->Range[0]);
|
|
return static_cast<int>((rangeLength / this->DeltaRangeMajor) + 1);
|
|
}
|
|
|
|
double vtkPolarAxesActor::ComputeEllipseAngle(double angleInDegrees, double ratio)
|
|
{
|
|
double miniAngleEllipse;
|
|
double minimumAngleRad = vtkMath::RadiansFromDegrees(angleInDegrees);
|
|
minimumAngleRad = std::fmod(minimumAngleRad, 2.0 * vtkMath::Pi());
|
|
|
|
// result range: -pi / 2, pi / 2
|
|
miniAngleEllipse = atan(tan(minimumAngleRad) / ratio);
|
|
|
|
// ellipse range: 0, 2 * pi
|
|
if (minimumAngleRad > vtkMath::Pi() / 2 && minimumAngleRad <= vtkMath::Pi())
|
|
{
|
|
miniAngleEllipse += vtkMath::Pi();
|
|
}
|
|
else if (minimumAngleRad > vtkMath::Pi() && minimumAngleRad <= 1.5 * vtkMath::Pi())
|
|
{
|
|
miniAngleEllipse -= vtkMath::Pi();
|
|
}
|
|
return miniAngleEllipse;
|
|
}
|