/*========================================================================= Program: Visualization Toolkit Module: vtkAxisActor2D.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 "vtkAxisActor2D.h" #include "vtkCellArray.h" #include "vtkObjectFactory.h" #include "vtkPolyData.h" #include "vtkPolyDataMapper2D.h" #include "vtkTextMapper.h" #include "vtkTextProperty.h" #include "vtkViewport.h" #include "vtkWindow.h" #include "vtkMath.h" #include #include vtkStandardNewMacro(vtkAxisActor2D); vtkCxxSetObjectMacro(vtkAxisActor2D,LabelTextProperty,vtkTextProperty); vtkCxxSetObjectMacro(vtkAxisActor2D,TitleTextProperty,vtkTextProperty); //---------------------------------------------------------------------------- // Instantiate this object. vtkAxisActor2D::vtkAxisActor2D() { this->PositionCoordinate->SetCoordinateSystemToNormalizedViewport(); this->PositionCoordinate->SetValue(0.0, 0.0); this->Position2Coordinate->SetCoordinateSystemToNormalizedViewport(); this->Position2Coordinate->SetValue(0.75, 0.0); this->Position2Coordinate->SetReferenceCoordinate(nullptr); this->NumberOfLabels = 5; this->Title = nullptr; this->TitlePosition = 0.5; this->AdjustLabels = 1; this->TickLength = 5; this->MinorTickLength = 3; this->TickOffset = 2; this->NumberOfMinorTicks = 0; this->Range[0] = 0.0; this->Range[1] = 1.0; this->FontFactor = 1.0; this->LabelFactor = 0.75; this->SizeFontRelativeToAxis = 0; this->RulerMode = 0; this->RulerDistance = 1.0; this->LabelTextProperty = vtkTextProperty::New(); this->LabelTextProperty->SetBold(1); this->LabelTextProperty->SetItalic(1); this->LabelTextProperty->SetShadow(1); this->LabelTextProperty->SetFontFamilyToArial(); this->TitleTextProperty = vtkTextProperty::New(); this->TitleTextProperty->ShallowCopy(this->LabelTextProperty); this->LabelFormat = new char[8]; snprintf(this->LabelFormat,8,"%s","%-#6.3g"); this->TitleMapper = vtkTextMapper::New(); this->TitleActor = vtkActor2D::New(); this->TitleActor->SetMapper(this->TitleMapper); // To avoid deleting/rebuilding create once up front this->NumberOfLabelsBuilt = 0; this->LabelMappers = new vtkTextMapper * [VTK_MAX_LABELS]; this->LabelActors = new vtkActor2D * [VTK_MAX_LABELS]; for ( int i=0; i < VTK_MAX_LABELS; i++) { this->LabelMappers[i] = vtkTextMapper::New(); this->LabelActors[i] = vtkActor2D::New(); this->LabelActors[i]->SetMapper(this->LabelMappers[i]); } this->Axis = vtkPolyData::New(); this->AxisMapper = vtkPolyDataMapper2D::New(); this->AxisMapper->SetInputData(this->Axis); this->AxisActor = vtkActor2D::New(); this->AxisActor->SetMapper(this->AxisMapper); this->AxisVisibility = 1; this->TickVisibility = 1; this->LabelVisibility = 1; this->TitleVisibility = 1; this->LastPosition[0] = this->LastPosition[1] = 0; this->LastPosition2[0] = this->LastPosition2[1] = 0; this->LastSize[0] = this->LastSize[1] = 0; this->LastMaxLabelSize[0] = this->LastMaxLabelSize[1] = 0; } //---------------------------------------------------------------------------- vtkAxisActor2D::~vtkAxisActor2D() { delete [] this->LabelFormat; this->LabelFormat = nullptr; this->TitleMapper->Delete(); this->TitleActor->Delete(); delete [] this->Title; this->Title = nullptr; if (this->LabelMappers != nullptr ) { for (int i=0; i < VTK_MAX_LABELS; i++) { this->LabelMappers[i]->Delete(); this->LabelActors[i]->Delete(); } delete [] this->LabelMappers; delete [] this->LabelActors; } this->Axis->Delete(); this->AxisMapper->Delete(); this->AxisActor->Delete(); this->SetLabelTextProperty(nullptr); this->SetTitleTextProperty(nullptr); } //---------------------------------------------------------------------------- // Build the axis, ticks, title, and labels and render. int vtkAxisActor2D::RenderOpaqueGeometry(vtkViewport *viewport) { int i, renderedSomething=0; this->BuildAxis(viewport); // Everything is built, just have to render if ( this->Title != nullptr && this->Title[0] != 0 && this->TitleVisibility ) { renderedSomething += this->TitleActor->RenderOpaqueGeometry(viewport); } if ( this->AxisVisibility || this->TickVisibility ) { renderedSomething += this->AxisActor->RenderOpaqueGeometry(viewport); } if ( this->LabelVisibility ) { for (i=0; iNumberOfLabelsBuilt; i++) { renderedSomething += this->LabelActors[i]->RenderOpaqueGeometry(viewport); } } return renderedSomething; } //---------------------------------------------------------------------------- // Render the axis, ticks, title, and labels. int vtkAxisActor2D::RenderOverlay(vtkViewport *viewport) { int i, renderedSomething=0; // Everything is built, just have to render if ( this->Title != nullptr && this->Title[0] != 0 && this->TitleVisibility ) { renderedSomething += this->TitleActor->RenderOverlay(viewport); } if ( this->AxisVisibility || this->TickVisibility ) { renderedSomething += this->AxisActor->RenderOverlay(viewport); } if ( this->LabelVisibility ) { for (i=0; iNumberOfLabelsBuilt; i++) { renderedSomething += this->LabelActors[i]->RenderOverlay(viewport); } } return renderedSomething; } //----------------------------------------------------------------------------- // Description: // Does this prop have some translucent polygonal geometry? int vtkAxisActor2D::HasTranslucentPolygonalGeometry() { return 0; } //---------------------------------------------------------------------------- // Release any graphics resources that are being consumed by this actor. // The parameter window could be used to determine which graphic // resources to release. void vtkAxisActor2D::ReleaseGraphicsResources(vtkWindow *win) { this->TitleActor->ReleaseGraphicsResources(win); for (int i=0; i < VTK_MAX_LABELS; i++) { this->LabelActors[i]->ReleaseGraphicsResources(win); } this->AxisActor->ReleaseGraphicsResources(win); } //---------------------------------------------------------------------------- void vtkAxisActor2D::PrintSelf(ostream& os, vtkIndent indent) { this->Superclass::PrintSelf(os,indent); if (this->TitleTextProperty) { os << indent << "Title Text Property:\n"; this->TitleTextProperty->PrintSelf(os,indent.GetNextIndent()); } else { os << indent << "Title Text Property: (none)\n"; } if (this->LabelTextProperty) { os << indent << "Label Text Property:\n"; this->LabelTextProperty->PrintSelf(os,indent.GetNextIndent()); } else { os << indent << "Label Text Property: (none)\n"; } os << indent << "Title: " << (this->Title ? this->Title : "(none)") << "\n"; os << indent << "Ruler Mode: " << (this->RulerMode ? "On" : "Off") <<"\n"; os << indent << "Ruler Distance: " << this->GetRulerDistance() <<"\n"; os << indent << "Number Of Labels: " << this->NumberOfLabels << "\n"; os << indent << "Number Of Labels Built: " << this->NumberOfLabelsBuilt << "\n"; os << indent << "Range: (" << this->Range[0] << ", " << this->Range[1] << ")\n"; os << indent << "Label Format: " << this->LabelFormat << "\n"; os << indent << "Font Factor: " << this->FontFactor << "\n"; os << indent << "Label Factor: " << this->LabelFactor << "\n"; os << indent << "Tick Length: " << this->TickLength << "\n"; os << indent << "Tick Offset: " << this->TickOffset << "\n"; os << indent << "Adjust Labels: " << (this->AdjustLabels ? "On\n" : "Off\n"); os << indent << "Axis Visibility: " << (this->AxisVisibility ? "On\n" : "Off\n"); os << indent << "Tick Visibility: " << (this->TickVisibility ? "On\n" : "Off\n"); os << indent << "Label Visibility: " << (this->LabelVisibility ? "On\n" : "Off\n"); os << indent << "Title Visibility: " << (this->TitleVisibility ? "On\n" : "Off\n"); os << indent << "MinorTickLength: " << this->MinorTickLength << endl; os << indent << "NumberOfMinorTicks: " << this->NumberOfMinorTicks << endl; os << indent << "TitlePosition: " << this->TitlePosition << endl; os << indent << "Size Font Relative To Axis: " << (this->SizeFontRelativeToAxis ? "On\n" : "Off\n"); } //---------------------------------------------------------------------------- void vtkAxisActor2D::BuildAxis(vtkViewport *viewport) { int i, *x, viewportSizeHasChanged, positionsHaveChanged; vtkIdType ptIds[2]; double p1[3], p2[3], offset; double interval, deltaX, deltaY; double xTick[3]; double theta, val; int *size, stringSize[2]; char string[512]; if (this->TitleVisibility && !this->TitleTextProperty) { vtkErrorMacro(<<"Need title text property to render axis actor"); return; } if (this->LabelVisibility && !this->LabelTextProperty) { vtkErrorMacro(<<"Need label text property to render axis actor"); return; } // Check to see whether we have to rebuild everything // Viewport change may not require rebuild positionsHaveChanged = 0; int *lastPosition = this->PositionCoordinate->GetComputedViewportValue(viewport); int *lastPosition2 = this->Position2Coordinate->GetComputedViewportValue(viewport); if (lastPosition[0] != this->LastPosition[0] || lastPosition[1] != this->LastPosition[1] || lastPosition2[0] != this->LastPosition2[0] || lastPosition2[1] != this->LastPosition2[1] ) { positionsHaveChanged = 1; } // See whether fonts have to be rebuilt (font size depends on viewport size) viewportSizeHasChanged = 0; size = viewport->GetSize(); if (this->LastSize[0] != size[0] || this->LastSize[1] != size[1]) { viewportSizeHasChanged = 1; this->LastSize[0] = size[0]; this->LastSize[1] = size[1]; } if ( ! viewport->GetVTKWindow() || (!positionsHaveChanged && !viewportSizeHasChanged && viewport->GetMTime() < this->BuildTime && viewport->GetVTKWindow()->GetMTime() < this->BuildTime && this->GetMTime() < this->BuildTime && (!this->LabelVisibility || this->LabelTextProperty->GetMTime() < this->BuildTime) && (!this->TitleVisibility || this->TitleTextProperty->GetMTime() < this->BuildTime)) ) { return; } vtkDebugMacro(<<"Rebuilding axis"); // Initialize and get important info this->Axis->Initialize(); this->AxisActor->SetProperty(this->GetProperty()); // Compute the location of tick marks and labels this->UpdateAdjustedRange(); interval = (this->AdjustedRange[1] - this->AdjustedRange[0]) / (this->AdjustedNumberOfLabels - 1); this->NumberOfLabelsBuilt = this->AdjustedNumberOfLabels; // Generate the axis and tick marks. // We'll do our computation in viewport coordinates. First determine the // location of the endpoints. x = this->PositionCoordinate->GetComputedViewportValue(viewport); p1[0] = x[0]; p1[1] = x[1]; p1[2] = 0.0; this->LastPosition[0] = x[0]; this->LastPosition[1] = x[1]; x = this->Position2Coordinate->GetComputedViewportValue(viewport); p2[0] = x[0]; p2[1] = x[1]; p2[2] = 0.0; this->LastPosition2[0] = x[0]; this->LastPosition2[1] = x[1]; double *xp1, *xp2, len=0.0; if ( this->SizeFontRelativeToAxis ) { xp1 = this->PositionCoordinate->GetComputedDoubleViewportValue(viewport); xp2 = this->Position2Coordinate->GetComputedDoubleViewportValue(viewport); len = sqrt((xp2[0]-xp1[0])*(xp2[0]-xp1[0]) + (xp2[1]-xp1[1])*(xp2[1]-xp1[1])); } vtkPoints *pts = vtkPoints::New(); vtkCellArray *lines = vtkCellArray::New(); this->Axis->SetPoints(pts); this->Axis->SetLines(lines); pts->Delete(); lines->Delete(); // Generate point along axis (as well as tick points) deltaX = p2[0] - p1[0]; deltaY = p2[1] - p1[1]; if (deltaX == 0. && deltaY == 0.) { theta = 0.; } else { theta = atan2(deltaY, deltaX); } // First axis point, where first tick is located ptIds[0] = pts->InsertNextPoint(p1); xTick[0] = p1[0] + this->TickLength*sin(theta); xTick[1] = p1[1] - this->TickLength*cos(theta); xTick[2] = 0.0; pts->InsertNextPoint(xTick); // Set up creation of ticks double p21[3], length; p21[0] = p2[0] - p1[0]; p21[1] = p2[1] - p1[1]; p21[2] = p2[2] - p1[2]; length = vtkMath::Normalize(p21); // Sum of all the ticks: minor and majors. Contains the start and end ticks. int numTicks; // Distance between each minor tick. double distance; if ( this->RulerMode ) { double wp1[3], wp2[3], wp21[3]; this->PositionCoordinate->GetValue(wp1); this->Position2Coordinate->GetValue(wp2); wp21[0] = wp2[0] - wp1[0]; wp21[1] = wp2[1] - wp1[1]; wp21[2] = wp2[2] - wp1[2]; const double worldLength = vtkMath::Norm(wp21); const double worldDistance = this->RulerDistance / (this->NumberOfMinorTicks+1); numTicks = static_cast( worldDistance <= 0.0 ? 0.0 : (worldLength / worldDistance)); const double precision = std::numeric_limits::epsilon(); const bool hasRemainderInDivision = worldDistance <= 0.0 ? false: std::fmod(worldLength, worldDistance) > precision; // numTicks must contain the start and end ticks // Don't add the end tick if it is already in numTicks: // when wLength / wDistance is an integer. numTicks += hasRemainderInDivision ? 2 : 1; // Tick distance was computed in world coordinates, convert to viewport // coordinates. const double worldToLocalRatio = (worldLength <= 0.0 ? 0.0 : length / worldLength); distance = worldDistance * worldToLocalRatio; } else { numTicks = (this->AdjustedNumberOfLabels-1) * (this->NumberOfMinorTicks+1) + 1; distance = length / (numTicks-1); } // Only draw the inner ticks (not the start/end ticks) for (i = 1; i < numTicks - 1; i++) { int tickLength = 0; if ( i % (this->NumberOfMinorTicks+1) == 0 ) { tickLength = this->TickLength; } else { tickLength = this->MinorTickLength; } xTick[0] = p1[0] + i * p21[0] * distance; xTick[1] = p1[1] + i * p21[1] * distance; pts->InsertNextPoint(xTick); xTick[0] = xTick[0] + tickLength * sin(theta); xTick[1] = xTick[1] - tickLength * cos(theta); pts->InsertNextPoint(xTick); } // Last axis point ptIds[1] = pts->InsertNextPoint(p2); xTick[0] = p2[0] + this->TickLength*sin(theta); xTick[1] = p2[1] - this->TickLength*cos(theta); pts->InsertNextPoint(xTick); // Add the axis if requested if (this->AxisVisibility) { lines->InsertNextCell(2, ptIds); } // Create lines representing the tick marks if (this->TickVisibility) { for (i = 0; i < numTicks; i++) { ptIds[0] = 2*i; ptIds[1] = 2*i + 1; lines->InsertNextCell(2, ptIds); } } // Build the labels if (this->LabelVisibility) { // Update the labels text. Do it only if the range has been adjusted, // i.e. if we think that new labels must be created. // WARNING: if LabelFormat has changed, they should be recreated too // but at this point the check on LabelFormat is "included" in // UpdateAdjustedRange(), which is the function that update // AdjustedRangeBuildTime or not. vtkMTimeType labeltime = this->AdjustedRangeBuildTime; if (this->AdjustedRangeBuildTime > this->BuildTime) { for (i = 0; i < this->AdjustedNumberOfLabels; i++) { val = this->AdjustedRange[0] + i * interval; snprintf(string, sizeof(string), this->LabelFormat, val); this->LabelMappers[i]->SetInput(string); // Check if the label text has changed if (this->LabelMappers[i]->GetMTime() > labeltime) { labeltime = this->LabelMappers[i]->GetMTime(); } } } // Copy prop and text prop eventually for (i = 0; i < this->AdjustedNumberOfLabels; i++) { if (this->LabelTextProperty->GetMTime() > this->BuildTime || this->AdjustedRangeBuildTime > this->BuildTime) { // Shallow copy here so that the size of the label prop is not // affected by the automatic adjustment of its text mapper's // size (i.e. its mapper's text property is identical except // for the font size which will be modified later). This // allows text actors to share the same text property, and in // that case specifically allows the title and label text prop // to be the same. this->LabelMappers[i]->GetTextProperty()->ShallowCopy( this->LabelTextProperty); } } // Resize the mappers if needed (i.e. viewport has changed, than // font size should be changed, or label text property has changed, // or some of the labels have changed (got bigger for example) if (positionsHaveChanged || viewportSizeHasChanged || this->LabelTextProperty->GetMTime() > this->BuildTime || labeltime > this->BuildTime) { if ( ! this->SizeFontRelativeToAxis ) { vtkTextMapper::SetMultipleRelativeFontSize(viewport, this->LabelMappers, this->AdjustedNumberOfLabels, size, this->LastMaxLabelSize, 0.015*this->FontFactor*this->LabelFactor); } else { int minFontSize=1000, fontSize, minLabel=0; for (i = 0; i < this->AdjustedNumberOfLabels; i++) { fontSize = this->LabelMappers[i]-> SetConstrainedFontSize(viewport, static_cast((1.0/this->AdjustedNumberOfLabels)*len), static_cast(0.2*len) ); if ( fontSize < minFontSize ) { minFontSize = fontSize; minLabel = i; } } for (i=0; iAdjustedNumberOfLabels; i++) { this->LabelMappers[i]->GetTextProperty()->SetFontSize(minFontSize); } this->LabelMappers[minLabel]->GetSize(viewport,this->LastMaxLabelSize); } } // Position the mappers for (i = 0; i < this->AdjustedNumberOfLabels; i++) { pts->GetPoint((this->NumberOfMinorTicks+1) * 2 * i + 1, xTick); this->LabelMappers[i]->GetSize(viewport, stringSize); this->SetOffsetPosition(xTick, theta, this->LastMaxLabelSize[0], this->LastMaxLabelSize[1], this->TickOffset, this->LabelActors[i]); } } // If labels visible // Now build the title if (this->Title != nullptr && this->Title[0] != 0 && this->TitleVisibility) { this->TitleMapper->SetInput(this->Title); if (this->TitleTextProperty->GetMTime() > this->BuildTime) { // Shallow copy here so that the size of the title prop is not // affected by the automatic adjustment of its text mapper's // size (i.e. its mapper's text property is identical except for // the font size which will be modified later). This allows text // actors to share the same text property, and in that case // specifically allows the title and label text prop to be the same. this->TitleMapper->GetTextProperty()->ShallowCopy( this->TitleTextProperty); } if (positionsHaveChanged || viewportSizeHasChanged || this->TitleTextProperty->GetMTime() > this->BuildTime) { if ( ! this->SizeFontRelativeToAxis ) { vtkTextMapper::SetRelativeFontSize(this->TitleMapper, viewport, size, stringSize, 0.015*this->FontFactor); } else { this->TitleMapper->SetConstrainedFontSize(viewport, static_cast(0.33*len), static_cast(0.2*len) ); this->TitleMapper->GetSize(viewport, stringSize); } } else { this->TitleMapper->GetSize(viewport, stringSize); } xTick[0] = p1[0] + (p2[0] - p1[0]) * this->TitlePosition; xTick[1] = p1[1] + (p2[1] - p1[1]) * this->TitlePosition; xTick[0] = xTick[0] + (this->TickLength + this->TickOffset) * sin(theta); xTick[1] = xTick[1] - (this->TickLength + this->TickOffset) * cos(theta); offset = 0.0; if (this->LabelVisibility) { offset = this->ComputeStringOffset(this->LastMaxLabelSize[0], this->LastMaxLabelSize[1], theta); } this->SetOffsetPosition(xTick, theta, stringSize[0], stringSize[1], static_cast(offset), this->TitleActor); } // If title visible this->BuildTime.Modified(); } //---------------------------------------------------------------------------- void vtkAxisActor2D::UpdateAdjustedRange() { // Try not to update/adjust the range to often, do not update it // if the object has not been modified. // Nevertheless, try the following optimization: there is no need to // update the range if the position coordinate of this actor have // changed. But since vtkActor2D::GetMTime() includes the check for // both Position and Position2 coordinates, we will have to bypass // it. if (this->vtkActor2D::Superclass::GetMTime() <= this->AdjustedRangeBuildTime) { return; } if ( this->AdjustLabels ) { double interval; this->ComputeRange(this->Range, this->AdjustedRange, this->NumberOfLabels, this->AdjustedNumberOfLabels, interval); } else { this->AdjustedNumberOfLabels = this->NumberOfLabels; this->AdjustedRange[0] = this->Range[0]; this->AdjustedRange[1] = this->Range[1]; } this->AdjustedRangeBuildTime.Modified(); } // this is a helper function that computes some useful functions // for an axis. It returns the number of ticks static int vtkAxisActor2DComputeTicks(double sRange[2], double &interval, double &root) { // first we try assuming the first value is reasonable int numTicks; double range = fabs(sRange[1]-sRange[0]); int rootPower = static_cast(floor(log10(range)-1)); root = pow(10.0,rootPower); // val will be between 10 and 100 inclusive of 10 but not 100 double val = range/root; // first we check for an exact match for (numTicks = 5; numTicks < 9; ++numTicks) { if (fabs(val/(numTicks-1.0) - floor(val/(numTicks-1.0))) < .0001) { interval = val*root/(numTicks-1.0); return numTicks; } } // if there isn't an exact match find a reasonable value int newIntScale = 10; if (val > 10) { newIntScale = 12; } if (val > 12) { newIntScale = 15; } if (val > 15) { newIntScale = 18; } if (val > 18) { newIntScale = 20; } if (val > 20) { newIntScale = 25; } if (val > 25) { newIntScale = 30; } if (val > 30) { newIntScale = 40; } if (val > 40) { newIntScale = 50; } if (val > 50) { newIntScale = 60; } if (val > 60) { newIntScale = 70; } if (val > 70) { newIntScale = 80; } if (val > 80) { newIntScale = 90; } if (val > 90) { newIntScale = 100; } // how many ticks should we have switch (newIntScale) { case 12: case 20: case 40: case 80: numTicks = 5; break; case 18: case 30: case 60: case 90: numTicks = 7; break; case 10: case 15: case 25: case 50: case 100: numTicks = 6; break; case 70: numTicks = 8; break; } interval = newIntScale*root/(numTicks-1.0); return numTicks; } //---------------------------------------------------------------------------- //this method takes an initial range and an initial number of ticks and then //computes a final range and number of ticks so that two properties are //satisfied. First the final range includes at least the initial range, and //second the final range divided by the number of ticks (minus one) will be a //reasonable interval void vtkAxisActor2D::ComputeRange(double inRange[2], double outRange[2], int vtkNotUsed(inNumTicks), int &numTicks, double &interval) { // Handle the range double sRange[2]; if ( inRange[0] < inRange[1] ) { sRange[0] = inRange[0]; sRange[1] = inRange[1]; } else if ( inRange[0] > inRange[1] ) { sRange[1] = inRange[0]; sRange[0] = inRange[1]; } else // they're equal, so perturb them by 1 percent { double perturb = 100.; if (inRange[0] == 0.0) { // if they are both zero, then just perturb about zero sRange[0] = -1/perturb; sRange[1] = 1/perturb; } else { sRange[0] = inRange[0] - inRange[0]/perturb; sRange[1] = inRange[0] + inRange[0]/perturb; } } double root; numTicks = vtkAxisActor2DComputeTicks(sRange, interval, root); // is the starting point reasonable? if (fabs(sRange[0]/root - floor(sRange[0]/root)) < 0.01) { outRange[0] = sRange[0]; outRange[1] = outRange[0] + (numTicks-1.0)*interval; } else { // OK the starting point is not a good number, so we must widen the range // First see if the current range will handle moving the start point outRange[0] = floor(sRange[0]/root)*root; if (outRange[0]+(numTicks-1.0)*interval <= sRange[1]) { outRange[1] = outRange[0] + (numTicks-1.0)*interval; } else { // Finally in this case we must switch to a larger range to // have reasonable starting and ending values sRange[0] = outRange[0]; numTicks = vtkAxisActor2DComputeTicks(sRange, interval, root); outRange[1] = outRange[0] + (numTicks-1.0)*interval; } } // Adust if necessary if ( inRange[0] > inRange[1] ) { sRange[0] = outRange[1]; outRange[1] = outRange[0]; outRange[0] = sRange[0]; interval = -interval; } } //---------------------------------------------------------------------------- // Position text with respect to a point (xTick) where the angle of the line // from the point to the center of the text is given by theta. The offset // is the spacing between ticks and labels. void vtkAxisActor2D::SetOffsetPosition(double xTick[3], double theta, int stringWidth, int stringHeight, int offset, vtkActor2D *actor) { double x, y, center[2]; int pos[2]; x = stringWidth/2.0 + offset; y = stringHeight/2.0 + offset; center[0] = xTick[0] + x*sin(theta); center[1] = xTick[1] - y*cos(theta); pos[0] = static_cast(center[0] - stringWidth/2.0); pos[1] = static_cast(center[1] - stringHeight/2.0); actor->SetPosition(pos[0], pos[1]); } //---------------------------------------------------------------------------- double vtkAxisActor2D::ComputeStringOffset(double width, double height, double theta) { double f1 = height*cos(theta); double f2 = width*sin(theta); return (1.2 * sqrt(f1*f1 + f2*f2)); } //---------------------------------------------------------------------------- void vtkAxisActor2D::ShallowCopy(vtkProp *prop) { vtkAxisActor2D *a = vtkAxisActor2D::SafeDownCast(prop); if ( a != nullptr ) { this->SetRange(a->GetRange()); this->SetNumberOfLabels(a->GetNumberOfLabels()); this->SetLabelFormat(a->GetLabelFormat()); this->SetAdjustLabels(a->GetAdjustLabels()); this->SetTitle(a->GetTitle()); this->SetTickLength(a->GetTickLength()); this->SetTickOffset(a->GetTickOffset()); this->SetAxisVisibility(a->GetAxisVisibility()); this->SetTickVisibility(a->GetTickVisibility()); this->SetLabelVisibility(a->GetLabelVisibility()); this->SetTitleVisibility(a->GetTitleVisibility()); this->SetFontFactor(a->GetFontFactor()); this->SetLabelFactor(a->GetLabelFactor()); this->SetLabelTextProperty(a->GetLabelTextProperty()); this->SetTitleTextProperty(a->GetTitleTextProperty()); } // Now do superclass this->vtkActor2D::ShallowCopy(prop); }