// SPDX-FileCopyrightText: Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen // SPDX-License-Identifier: BSD-3-Clause #include "vtkAxisActor.h" #include "Private/vtkTextActorInterfaceInternal.h" #include "vtkAxisFollower.h" #include "vtkBoundingBox.h" #include "vtkCamera.h" #include "vtkCellArray.h" #include "vtkCoordinate.h" #include "vtkFollower.h" #include "vtkMath.h" #include "vtkNew.h" #include "vtkObjectFactory.h" #include "vtkPolyData.h" #include "vtkPolyDataMapper.h" #include "vtkProp3DAxisFollower.h" #include "vtkPropCollection.h" #include "vtkProperty.h" #include "vtkRenderer.h" #include "vtkStringArray.h" #include "vtkStringFormatter.h" #include "vtkTextActor.h" #include "vtkTextActor3D.h" #include "vtkTextProperty.h" #include "vtkTextRenderer.h" #include "vtkViewport.h" #include "vtkWindow.h" #include #define VTK_MAX_TICKS 1000 VTK_ABI_NAMESPACE_BEGIN vtkStandardNewMacro(vtkAxisActor); vtkCxxSetSmartPointerMacro(vtkAxisActor, LabelTextProperty, vtkTextProperty); vtkCxxSetSmartPointerMacro(vtkAxisActor, TitleTextProperty, vtkTextProperty); //------------------------------------------------------------------------------ // Instantiate this object. //------------------------------------------------------------------------------ vtkAxisActor::vtkAxisActor() : TitleProp(std::make_unique()) , ExponentProp(std::make_unique()) { this->Point1Coordinate->SetCoordinateSystemToWorld(); this->Point1Coordinate->SetValue(0.0, 0.0, 0.0); this->Point2Coordinate->SetCoordinateSystemToWorld(); this->Point2Coordinate->SetValue(0.75, 0.0, 0.0); this->Bounds[0] = this->Bounds[2] = this->Bounds[4] = -1; this->Bounds[1] = this->Bounds[3] = this->Bounds[5] = 1; this->LabelFormat = new char[10]; auto result = vtk::format_to_n(this->LabelFormat, 10, "{:s}", "{:<#6.3g}"); *result.out = '\0'; this->TitleTextProperty = vtkSmartPointer::New(); this->TitleTextProperty->SetColor(0., 0., 0.); this->TitleTextProperty->SetFontFamilyToArial(); this->TitleTextProperty->SetFontSize(18.); this->TitleTextProperty->SetVerticalJustificationToCentered(); this->TitleTextProperty->SetJustificationToCentered(); this->TitleProp->SetAxis(this); this->LabelTextProperty = vtkSmartPointer::New(); this->LabelTextProperty->SetColor(0., 0., 0.); this->LabelTextProperty->SetFontFamilyToArial(); this->LabelTextProperty->SetFontSize(14.); this->LabelTextProperty->SetVerticalJustificationToBottom(); this->LabelTextProperty->SetJustificationToLeft(); this->ExponentProp->SetAxis(this); // Main line of axis vtkNew axisLinesMapper; axisLinesMapper->SetInputData(this->AxisLines); this->AxisLinesActor->SetMapper(axisLinesMapper); // Major ticks vtkNew axisMajorTicksMapper; axisMajorTicksMapper->SetInputData(this->AxisMajorTicks); this->AxisMajorTicksActor->SetMapper(axisMajorTicksMapper); // Minor ticks vtkNew axisMinorTicksMapper; axisMinorTicksMapper->SetInputData(this->AxisMinorTicks); this->AxisMinorTicksActor->SetMapper(axisMinorTicksMapper); vtkNew gridlinesMapper; gridlinesMapper->SetInputData(this->Gridlines); this->GridlinesActor->SetMapper(gridlinesMapper); vtkNew innerGridlinesMapper; innerGridlinesMapper->SetInputData(this->InnerGridlines); this->InnerGridlinesActor->SetMapper(innerGridlinesMapper); vtkNew gridpolysMapper; gridpolysMapper->SetInputData(this->Gridpolys); this->GridpolysActor->SetMapper(gridpolysMapper); this->GetProperty()->SetAmbient(1.); this->GetProperty()->SetDiffuse(0.); } //------------------------------------------------------------------------------ vtkAxisActor::~vtkAxisActor() { this->SetCamera(nullptr); delete[] this->LabelFormat; this->LabelFormat = nullptr; } //------------------------------------------------------------------------------ void vtkAxisActor::SetLabelFormat(const char* formatArg) { std::string format = formatArg ? vtk::to_std_format(formatArg) : ""; const char* formatStr = format.c_str(); vtkSetStringBodyMacro(LabelFormat, formatStr); } //------------------------------------------------------------------------------ void vtkAxisActor::ReleaseGraphicsResources(vtkWindow* win) { vtkNew textActors; this->TitleProp->GetActors(textActors); this->ExponentProp->GetActors(textActors); for (int i = 0; i < this->NumberOfLabelsBuilt; i++) { this->LabelProps[i]->GetActors(textActors); } textActors->InitTraversal(); for (int idx = 0; idx < textActors->GetNumberOfItems(); idx++) { vtkProp* prop = textActors->GetNextProp(); prop->ReleaseGraphicsResources(win); } this->AxisLinesActor->ReleaseGraphicsResources(win); this->AxisMajorTicksActor->ReleaseGraphicsResources(win); this->AxisMinorTicksActor->ReleaseGraphicsResources(win); this->GridlinesActor->ReleaseGraphicsResources(win); this->InnerGridlinesActor->ReleaseGraphicsResources(win); this->GridpolysActor->ReleaseGraphicsResources(win); } //------------------------------------------------------------------------------ int vtkAxisActor::RenderOpaqueGeometry(vtkViewport* viewport) { int numberOfRenderedProps = 0; this->BuildAxis(viewport, false); // Everything is built, just have to render // pass keys to sub props vtkInformation* propKeys = this->GetPropertyKeys(); if (!this->AxisHasZeroLength) { if (this->DrawGridlinesOnly && this->DrawGridlines) { // Exit !!!! this->GridlinesActor->SetPropertyKeys(propKeys); return this->GridlinesActor->RenderOpaqueGeometry(viewport); } if (!this->Title.empty() && this->TitleVisibility) { vtkProp* titleActor = this->GetTitleActorInternal(); titleActor->SetPropertyKeys(propKeys); numberOfRenderedProps += titleActor->RenderOpaqueGeometry(viewport); } if (this->AxisVisibility) { this->AxisLinesActor->SetPropertyKeys(propKeys); numberOfRenderedProps += this->AxisLinesActor->RenderOpaqueGeometry(viewport); if (this->TickVisibility) { this->AxisMajorTicksActor->SetPropertyKeys(propKeys); numberOfRenderedProps += this->AxisMajorTicksActor->RenderOpaqueGeometry(viewport); this->AxisMinorTicksActor->SetPropertyKeys(propKeys); numberOfRenderedProps += this->AxisMinorTicksActor->RenderOpaqueGeometry(viewport); } } if (this->DrawGridlines) { this->GridlinesActor->SetPropertyKeys(propKeys); numberOfRenderedProps += this->GridlinesActor->RenderOpaqueGeometry(viewport); } if (this->DrawInnerGridlines) { this->InnerGridlinesActor->SetPropertyKeys(propKeys); numberOfRenderedProps += this->InnerGridlinesActor->RenderOpaqueGeometry(viewport); } if (this->LabelVisibility) { for (int i = 0; i < this->NumberOfLabelsBuilt; i++) { vtkProp* labelActor = this->GetLabelActorInternal(i); labelActor->SetPropertyKeys(propKeys); numberOfRenderedProps += labelActor->RenderOpaqueGeometry(viewport); } if (this->ExponentVisibility && !this->Exponent.empty()) { vtkProp* exponentActor = this->GetExponentActorInternal(); exponentActor->SetPropertyKeys(propKeys); exponentActor->RenderOpaqueGeometry(viewport); } } } return numberOfRenderedProps; } //------------------------------------------------------------------------------ // Build the translucent poly actors and render. //------------------------------------------------------------------------------ int vtkAxisActor::RenderTranslucentGeometry(vtkViewport* viewport) { return this->RenderTranslucentPolygonalGeometry(viewport); } //------------------------------------------------------------------------------ // Build the translucent poly actors and render. //------------------------------------------------------------------------------ int vtkAxisActor::RenderTranslucentPolygonalGeometry(vtkViewport* viewport) { int numberOfRenderedProps = 0; this->BuildAxis(viewport, false); // Everything is built, just have to render // pass keys to sub props vtkInformation* propKeys = this->GetPropertyKeys(); vtkNew translucentProps; this->GetTranslucentProps(translucentProps); translucentProps->InitTraversal(); for (int idx = 0; idx < translucentProps->GetNumberOfItems(); idx++) { vtkProp* prop = translucentProps->GetNextProp(); prop->SetPropertyKeys(propKeys); numberOfRenderedProps += prop->RenderTranslucentPolygonalGeometry(viewport); } return numberOfRenderedProps; } //------------------------------------------------------------------------------ // Render the 2d annotations. //------------------------------------------------------------------------------ int vtkAxisActor::RenderOverlay(vtkViewport* viewport) { int numberOfRenderedProps = 0; // Everything is built, just have to render if (!this->AxisHasZeroLength && !this->DrawGridlinesOnly) { if (this->TitleVisibility) { vtkProp* titleActor = this->GetTitleActorInternal(); titleActor->SetPropertyKeys(this->GetPropertyKeys()); numberOfRenderedProps += titleActor->RenderOverlay(viewport); } if (this->LabelVisibility) { for (int i = 0; i < this->NumberOfLabelsBuilt; i++) { vtkProp* labelActor = this->GetLabelActorInternal(i); labelActor->SetPropertyKeys(this->GetPropertyKeys()); numberOfRenderedProps += labelActor->RenderOverlay(viewport); } if (this->ExponentVisibility) { vtkProp* exponentActor = this->GetExponentActorInternal(); exponentActor->SetPropertyKeys(this->GetPropertyKeys()); numberOfRenderedProps += exponentActor->RenderOverlay(viewport); } } } return numberOfRenderedProps; } //------------------------------------------------------------------------------ vtkTypeBool vtkAxisActor::HasTranslucentPolygonalGeometry() { if (!this->Visibility || this->AxisHasZeroLength) { return 0; } vtkNew translucentProps; this->GetTranslucentProps(translucentProps); translucentProps->InitTraversal(); for (int idx = 0; idx < translucentProps->GetNumberOfItems(); idx++) { vtkProp* prop = translucentProps->GetNextProp(); if (prop->HasTranslucentPolygonalGeometry()) { return 1; } } return this->Superclass::HasTranslucentPolygonalGeometry(); } //-----------------------------------------------------------------------------* // Perform some initialization, determine which Axis type we are //-----------------------------------------------------------------------------* void vtkAxisActor::BuildAxis(vtkViewport* viewport, bool force) { // We'll do our computation in world coordinates. First determine the // location of the endpoints. double *x, p1[3], p2[3]; x = this->Point1Coordinate->GetValue(); p1[0] = x[0]; p1[1] = x[1]; p1[2] = x[2]; x = this->Point2Coordinate->GetValue(); p2[0] = x[0]; p2[1] = x[1]; p2[2] = x[2]; // // Test for axis of zero length. // if (p1[0] == p2[0] && p1[1] == p2[1] && p1[2] == p2[2]) { vtkDebugMacro(<< "Axis has zero length, not building."); this->AxisHasZeroLength = true; return; } this->AxisHasZeroLength = false; if (!force && this->GetMTime() < this->BuildTime.GetMTime() && viewport->GetMTime() < this->BuildTime.GetMTime()) { return; // already built } if (this->Log) { if (this->Range[0] <= 0.0) { vtkWarningMacro(<< "Range value undefined for log scale enabled. " << "Current Range: (" << this->Range[0] << ", " << this->Range[1] << ")" << "Range[0] must be > 0.0. " << "."); return; } if (this->MinorRangeStart <= 0.0 || this->MajorRangeStart <= 0.0) { vtkWarningMacro( << "MinorRangeStart value or MajorRangeStart value undefined for log scale enabled" << "MinorRangeStart: " << this->MinorRangeStart << ", MajorRangeStart: " << this->MajorRangeStart << ". " << "MinorRangeStart and MajorRangeStart must be > 0.0. " << "."); return; } } vtkDebugMacro(<< "Rebuilding axis"); if (force || this->GetProperty()->GetMTime() > this->BuildTime.GetMTime()) { this->UpdateTitleActorProperty(); } // // Generate the axis and tick marks. // bool ticksRebuilt; ticksRebuilt = this->BuildTickPoints(p1, p2, force); bool tickVisChanged = this->TickVisibilityChanged(); if (force || ticksRebuilt || tickVisChanged || this->LastDrawGridlinesLocation != this->DrawGridlinesLocation) { this->LastDrawGridlinesLocation = this->DrawGridlinesLocation; this->SetAxisPointsAndLines(); } // If the ticks have been rebuilt it is more than likely // that the labels should follow... this->BuildLabels(viewport, force || ticksRebuilt); if (this->Use2DMode == 1) { this->BuildLabels2D(viewport, force || ticksRebuilt); } if (!this->Title.empty()) { this->UpdateTitleActorProperty(); } if (this->ExponentVisibility && !this->Exponent.empty()) { this->UpdateExponentActorProperty(); } if (!this->Title.empty()) { this->BuildTitle(force || ticksRebuilt); if (this->Use2DMode == 1) { this->BuildTitle2D(viewport, force || ticksRebuilt); } } if (this->ExponentVisibility && !this->Exponent.empty()) { // build exponent this->BuildExponent(force); if (this->Use2DMode == 1) { this->BuildExponent2D(viewport, force); } } this->LastAxisPosition = this->AxisPosition; this->LastRange[0] = this->Range[0]; this->LastRange[1] = this->Range[1]; this->BuildTime.Modified(); } //------------------------------------------------------------------------------ // Set label values and properties. //------------------------------------------------------------------------------ void vtkAxisActor::BuildLabels(vtkViewport* viewport, bool force) { if (!force && !this->LabelVisibility) { return; } for (int i = 0; i < this->NumberOfLabelsBuilt; i++) { vtkTextActorInterfaceInternal* currentLabel = this->LabelProps[i].get(); this->UpdateLabelActorProperty(i); currentLabel->SetCamera(this->Camera); currentLabel->AdjustScale(); } if (force || this->BuildTime.GetMTime() < this->BoundsTime.GetMTime() || this->AxisPosition != this->LastAxisPosition || this->LastRange[0] != this->Range[0] || this->LastRange[1] != this->Range[1]) { this->SetLabelPositions(viewport, force); } } static constexpr int vtkAxisActorMultiplierTable1[4] = { -1, -1, 1, 1 }; static constexpr int vtkAxisActorMultiplierTable2[4] = { -1, 1, 1, -1 }; //------------------------------------------------------------------------------ // Determine and set scale factor and position for labels. //------------------------------------------------------------------------------ void vtkAxisActor::SetLabelPositions(vtkViewport* viewport, bool force) { if (!force && (!this->LabelVisibility || this->NumberOfLabelsBuilt == 0)) { return; } // // xadjust & yadjust are used for positioning the label correctly // depending upon the 'orientation' of the axis as determined // by its position in view space (via transformed bounds). // double displayBounds[6] = { 0., 0., 0., 0., 0., 0. }; this->TransformBounds(viewport, displayBounds); double bounds[6], tickBottom[3], tickTop[3], pos[3]; double labelAngle = vtkMath::RadiansFromDegrees(this->LabelTextProperty->GetOrientation()); double labelCos = fabs(cos(labelAngle)); double labelSin = fabs(sin(labelAngle)); vtkAxisFollower* pAxisFollower = nullptr; for (int i = 0, ptIdx = 0; i < this->NumberOfLabelsBuilt && ((ptIdx + 1) < this->MajorTickPts->GetNumberOfPoints()); i++, ptIdx += 4) { this->MajorTickPts->GetPoint(ptIdx, tickTop); this->MajorTickPts->GetPoint(ptIdx + 1, tickBottom); pAxisFollower = this->LabelProps[i]->GetFollower(); // get Label actor Transform matrix vtkRenderer* ren = vtkRenderer::SafeDownCast(viewport); if (ren) { pAxisFollower->ComputeTransformMatrix(ren); } // WARNING: calling GetBounds() before ComputeTransformMatrix(), prevent this->Transform to be // updated // previous version: this->LabelActors[i]->GetMapper()->GetBounds(bounds); didn't include scale // labels // vtkProp3D::GetBounds() include previous transform (scale, orientation, translation) pAxisFollower->GetBounds(bounds); double labelWidth = (bounds[1] - bounds[0]); double labelHeight = (bounds[3] - bounds[2]); double labelMagnitude = sqrt(labelWidth * labelWidth + labelHeight * labelHeight); if (this->TickVisibility) { pos[0] = tickBottom[0]; pos[1] = tickBottom[1]; pos[2] = tickBottom[2]; } else { pos[0] = (tickTop[0] + tickBottom[0]) / 2; pos[1] = (tickTop[1] + tickBottom[1]) / 2; pos[2] = (tickTop[2] + tickBottom[2]) / 2; } double deltaPixels = 0.5 * (labelWidth * labelSin + labelHeight * labelCos) / labelMagnitude; this->LabelProps[i]->SetScreenOffset(this->LabelOffset + deltaPixels * this->ScreenSize); this->LabelProps[i]->SetPosition(pos); } } //------------------------------------------------------------------------------ // Set 2D label values and properties. //------------------------------------------------------------------------------ void vtkAxisActor::BuildLabels2D(vtkViewport* viewport, bool force) { if (!force && (!this->LabelVisibility || this->NumberOfLabelsBuilt == 0)) { return; } for (int i = 0; i < this->NumberOfLabelsBuilt; i++) { this->UpdateLabelActorProperty(i); } this->NeedBuild2D = this->BoundsDisplayCoordinateChanged(viewport); if (force || this->NeedBuild2D) { this->SetLabelPositions2D(viewport, force); } } //------------------------------------------------------------------------------ // Determine and set scale factor and position for 2D labels. //------------------------------------------------------------------------------ void vtkAxisActor::SetLabelPositions2D(vtkViewport* viewport, bool force) { if (!force && (!this->LabelVisibility || this->NumberOfLabelsBuilt == 0)) { return; } int xmult = 0; int ymult = 0; double xcoeff = 0.; double ycoeff = 0.; // we are in 2D mode, so no Z axis switch (this->AxisType) { case VTK_AXIS_TYPE_X: xmult = 0; ymult = vtkAxisActorMultiplierTable1[this->AxisPosition]; xcoeff = 0.5; ycoeff = 1.0; break; case VTK_AXIS_TYPE_Y: xmult = vtkAxisActorMultiplierTable1[this->AxisPosition]; ymult = 0; xcoeff = 1.0; ycoeff = 0.5; break; default: // shouldn't get here break; } // // xadjust & yadjust are used for positioning the label correctly // depending upon the 'orientation' of the axis as determined // by its position in view space (via transformed bounds). // double displayBounds[6] = { 0., 0., 0., 0., 0., 0. }; this->TransformBounds(viewport, displayBounds); double xadjust = (displayBounds[0] > displayBounds[1] ? -1 : 1); double yadjust = (displayBounds[2] > displayBounds[3] ? -1 : 1); double transpos[3] = { 0., 0., 0. }; double center[3], tick[3], pos[2]; vtkTextRenderer* tren = vtkTextRenderer::GetInstance(); if (!tren) { vtkErrorMacro(<< "Unable to obtain the vtkTextRenderer instance!"); return; } vtkWindow* win = viewport->GetVTKWindow(); if (!win) { vtkErrorMacro(<< "No render window available: cannot determine DPI."); return; } for (int i = 0, ptIdx = 1; i < this->NumberOfLabelsBuilt && ((ptIdx + 1) < this->MajorTickPts->GetNumberOfPoints()); i++, ptIdx += 4) { this->MajorTickPts->GetPoint(ptIdx, tick); center[0] = tick[0] + xmult * this->MinorTickSize; center[1] = tick[1] + ymult * this->MinorTickSize; center[2] = tick[2]; viewport->SetWorldPoint(center[0], center[1], center[2], 1.0); viewport->WorldToDisplay(); viewport->GetDisplayPoint(transpos); int bbox[4]; if (!tren->GetBoundingBox( this->LabelTextProperty, this->LabelProps[i]->GetInputText(), bbox, win->GetDPI())) { vtkErrorMacro(<< "Unable to calculate bounding box for label " << this->LabelProps[i]->GetInputText()); continue; } double width = (bbox[1] - bbox[0]); double height = (bbox[3] - bbox[2]); pos[0] = (transpos[0] - xadjust * width * xcoeff); pos[1] = (transpos[1] - yadjust * height * ycoeff); this->LabelProps[i]->SetDisplayPosition(pos[0], pos[1]); } } //------------------------------------------------------------------------------ // Determines scale and position for the Title. Currently, // title can only be centered with respect to its axis. //------------------------------------------------------------------------------ void vtkAxisActor::BuildTitle(bool force) { this->NeedBuild2D = false; if (!force && !this->TitleVisibility) { return; } if (!force && this->TitleTextTime.GetMTime() < this->BuildTime.GetMTime() && this->BoundsTime.GetMTime() < this->BuildTime.GetMTime() && this->LabelBuildTime.GetMTime() < this->BuildTime.GetMTime()) { return; } this->UpdateTitleActorProperty(); // ---------- labels size ---------- // local orientation (in the plane of the label) double labelAngle = vtkMath::RadiansFromDegrees(this->LabelTextProperty->GetOrientation()); double labelCos = fabs(cos(labelAngle)), labelSin = fabs(sin(labelAngle)); double labBounds[6]; double offset[2] = { 0, this->TitleOffset[1] }; // Side offset when not centered if (this->TitleAlignLocation == VTK_ALIGN_POINT1 || this->TitleAlignLocation == VTK_ALIGN_POINT2) { offset[0] += this->TitleOffset[0]; } // find max height label (with the label text property considered) // only when title is on bottom if (this->LabelVisibility && this->TitleAlignLocation != VTK_ALIGN_TOP) { double labelMaxHeight, labHeight; labelMaxHeight = labHeight = 0; for (int i = 0; i < this->NumberOfLabelsBuilt; i++) { this->LabelProps[i]->GetBounds(labBounds); // labels actor aren't oriented yet, width and height are considered in // their local coordinate system // however, LabelTextProperty can orient it, but locally (in its plane) labHeight = (labBounds[1] - labBounds[0]) * labelSin + (labBounds[3] - labBounds[2]) * labelCos; labelMaxHeight = (labHeight > labelMaxHeight ? labHeight : labelMaxHeight); } offset[1] += this->LabelOffset + this->ScreenSize * labelMaxHeight; } // ---------- title size ---------- double titleBounds[6]; this->TitleProp->GetBounds(titleBounds); double halfTitleHeight = (titleBounds[3] - titleBounds[2]) * 0.5; double halfTitleWidth = (titleBounds[1] - titleBounds[0]) * 0.5; double* p1 = this->Point1Coordinate->GetValue(); double* p2 = this->Point2Coordinate->GetValue(); double pos[3]; int vertOffsetSign = 1; switch (this->TitleAlignLocation) { case (VTK_ALIGN_TOP): vertOffsetSign = -1; [[fallthrough]]; // NO BREAK case (VTK_ALIGN_BOTTOM): // Position to center of axis for (int i = 0; i < 3; i++) { pos[i] = p1[i] + (p2[i] - p1[i]) / 2.0; } offset[1] += this->ScreenSize * halfTitleHeight; break; case (VTK_ALIGN_POINT1): // Position to p1 for (int i = 0; i < 3; i++) { pos[i] = p1[i]; } offset[0] += this->ScreenSize * halfTitleWidth; offset[1] += this->ScreenSize * halfTitleHeight; break; case (VTK_ALIGN_POINT2): // Position to p2 for (int i = 0; i < 3; i++) { pos[i] = p2[i]; } offset[0] += this->ScreenSize * halfTitleWidth; break; default: // shouldn't get there break; } if (this->TickVisibility && (this->TickLocation == VTK_TICKS_BOTH || (this->TickLocation == VTK_TICKS_INSIDE && this->TitleAlignLocation == VTK_ALIGN_TOP) || (this->TickLocation == VTK_TICKS_OUTSIDE && this->TitleAlignLocation != VTK_ALIGN_TOP))) { for (int i = 0; i < 3; i++) { pos[i] += vertOffsetSign * this->TickVector[i]; } } offset[1] *= vertOffsetSign; this->TitleProp->SetScreenOffsetVector(offset); this->TitleProp->AdjustScale(); this->TitleProp->SetPosition(pos); } //------------------------------------------------------------------------------ void vtkAxisActor::BuildExponent(bool force) { if (!force && (!this->ExponentVisibility || this->Exponent.empty())) { return; } if (!force && this->ExponentTextTime.GetMTime() < this->BuildTime.GetMTime() && this->BoundsTime.GetMTime() < this->BuildTime.GetMTime() && this->LabelBuildTime.GetMTime() < this->BuildTime.GetMTime()) { return; } this->UpdateExponentActorProperty(); // ---------- labels size ---------- // local orientation (in the plane of the label) double labelAngle = vtkMath::RadiansFromDegrees(this->LabelTextProperty->GetOrientation()); double labelCos = fabs(cos(labelAngle)), labelSin = fabs(sin(labelAngle)); double labBounds[6]; double offset[2] = { 0, this->ExponentOffset }; // find max height label (with the label text property considered) // only when title is on bottom if (this->LabelVisibility && this->ExponentLocation != VTK_ALIGN_TOP) { double labelMaxHeight, labHeight; labelMaxHeight = labHeight = 0; for (int i = 0; i < this->NumberOfLabelsBuilt; i++) { this->LabelProps[i]->GetBounds(labBounds); // labels actor aren't oriented yet, width and height are considered in // their local coordinate system // however, LabelTextProperty can orient it, but locally (in its plane) labHeight = (labBounds[1] - labBounds[0]) * labelSin + (labBounds[3] - labBounds[2]) * labelCos; labelMaxHeight = (labHeight > labelMaxHeight ? labHeight : labelMaxHeight); } offset[1] += this->LabelOffset + this->ScreenSize * labelMaxHeight; } // ---------- title size ---------- double titleBounds[6]; this->TitleProp->GetBounds(titleBounds); if (this->TitleVisibility && this->TitleAlignLocation == this->ExponentLocation) { offset[1] += this->TitleOffset[1] + this->ScreenSize * titleBounds[3] - titleBounds[2]; } // ---------- exponent size ---------- double exponentBounds[6]; this->ExponentProp->GetBounds(exponentBounds); double halfExponentHeight = (exponentBounds[3] - exponentBounds[2]) * 0.5; double halfExponentWidth = (exponentBounds[1] - exponentBounds[0]) * 0.5; double* p1 = this->Point1Coordinate->GetValue(); double* p2 = this->Point2Coordinate->GetValue(); double pos[3]; int offsetSign = 1; switch (this->ExponentLocation) { case (VTK_ALIGN_TOP): offsetSign = -1; [[fallthrough]]; // NO BREAK case (VTK_ALIGN_BOTTOM): // Position to center of axis for (int i = 0; i < 3; i++) { pos[i] = p1[i] + (p2[i] - p1[i]) / 2.0; } offset[1] += this->ScreenSize * halfExponentHeight; break; case (VTK_ALIGN_POINT1): // Position to p1 for (int i = 0; i < 3; i++) { pos[i] = p1[i]; } offset[0] += this->ScreenSize * halfExponentWidth; offset[1] += this->ScreenSize * halfExponentHeight; break; case (VTK_ALIGN_POINT2): // Position to p2 for (int i = 0; i < 3; i++) { pos[i] = p2[i]; } offset[0] += this->ScreenSize * halfExponentWidth; break; default: // shouldn't get there break; } if (this->TickVisibility && (this->TickLocation == VTK_TICKS_BOTH || (this->TickLocation == VTK_TICKS_INSIDE && this->ExponentLocation == VTK_ALIGN_TOP) || (this->TickLocation == VTK_TICKS_OUTSIDE && this->ExponentLocation != VTK_ALIGN_TOP))) { for (int i = 0; i < 3; i++) { pos[i] += offsetSign * this->TickVector[i]; } } // Offset is: ExponentOffset + TitleOffset is visible + LabelOffset if visible // + ScreenSize of all offset[1] *= offsetSign; this->ExponentProp->SetScreenOffsetVector(offset); this->ExponentProp->AdjustScale(); this->ExponentProp->SetPosition(pos); } //------------------------------------------------------------------------------ // Determines scale and position for the 2D Title. Currently, // title can only be centered with respect to its axis. //------------------------------------------------------------------------------ void vtkAxisActor::BuildTitle2D(vtkViewport* viewport, bool force) { if (!this->NeedBuild2D && !force && !this->TitleVisibility) { return; } this->UpdateTitleActorProperty(); double scenePos[3]; this->TitleProp->GetReferencePosition(scenePos); double position[2]; this->Get2DPosition(viewport, 1., scenePos, position); if (this->SaveTitlePosition > 0) { if (this->SaveTitlePosition == 1) { this->TitleConstantPosition[0] = position[0]; this->TitleConstantPosition[1] = position[1]; this->SaveTitlePosition = 2; } position[0] = this->TitleConstantPosition[0]; position[1] = this->TitleConstantPosition[1]; } this->TitleProp->SetDisplayPosition(position[0], position[1]); this->TitleProp->RotateActor2DFromAxisProjection(this->GetPoint1(), this->GetPoint2()); } //------------------------------------------------------------------------------ void vtkAxisActor::Get2DPosition( vtkViewport* viewport, double multi, double scenePos[3], double displayPos[2]) { double display[3]; viewport->SetWorldPoint(scenePos[0], scenePos[1], scenePos[2], 1.0); viewport->WorldToDisplay(); viewport->GetDisplayPoint(display); displayPos[0] = display[0]; displayPos[1] = display[1]; int offsetSign = 1; if (this->TitleAlignLocation == VTK_ALIGN_TOP) { offsetSign = -1; } if (this->AxisType == VTK_AXIS_TYPE_X) { displayPos[1] += offsetSign * multi * this->VerticalOffsetXTitle2D; } else if (this->AxisType == VTK_AXIS_TYPE_Y) { displayPos[0] += offsetSign * multi * this->HorizontalOffsetYTitle2D; } displayPos[0] = std::max(displayPos[0], 10.); displayPos[1] = std::max(displayPos[1], 10.); } //------------------------------------------------------------------------------ void vtkAxisActor::BuildExponent2D(vtkViewport* viewport, bool force) { if (!this->NeedBuild2D && !force && !this->LabelVisibility) { return; } // for textactor instead of follower this->UpdateExponentActorProperty(); int titleMult = 1; if (this->TitleVisibility && this->TitleAlignLocation == this->ExponentLocation) { titleMult = 2; } double scenePos[3]; this->ExponentProp->GetReferencePosition(scenePos); double position[2]; this->Get2DPosition(viewport, titleMult, scenePos, position); this->ExponentProp->SetDisplayPosition(position[0], position[1]); this->ExponentProp->RotateActor2DFromAxisProjection(this->GetPoint1(), this->GetPoint2()); } //------------------------------------------------------------------------------ // Transform the bounding box to display coordinates. Used // in determining orientation of the axis. //------------------------------------------------------------------------------ void vtkAxisActor::TransformBounds(vtkViewport* viewport, double bnds[6]) { double minPt[3], maxPt[3], transMinPt[3], transMaxPt[3]; minPt[0] = this->Bounds[0]; minPt[1] = this->Bounds[2]; minPt[2] = this->Bounds[4]; maxPt[0] = this->Bounds[1]; maxPt[1] = this->Bounds[3]; maxPt[2] = this->Bounds[5]; viewport->SetWorldPoint(minPt[0], minPt[1], minPt[2], 1.0); viewport->WorldToDisplay(); viewport->GetDisplayPoint(transMinPt); viewport->SetWorldPoint(maxPt[0], maxPt[1], maxPt[2], 1.0); viewport->WorldToDisplay(); viewport->GetDisplayPoint(transMaxPt); bnds[0] = transMinPt[0]; bnds[2] = transMinPt[1]; bnds[4] = transMinPt[2]; bnds[1] = transMaxPt[0]; bnds[3] = transMaxPt[1]; bnds[5] = transMaxPt[2]; } //------------------------------------------------------------------------------ void vtkAxisActor::PrintSelf(ostream& os, vtkIndent indent) { this->Superclass::PrintSelf(os, indent); os << indent << "Title: " << (this->Title.empty() ? this->Title : "(none)") << "\n"; os << indent << "Number Of Labels Built: " << this->NumberOfLabelsBuilt << "\n"; os << indent << "Range: (" << this->Range[0] << ", " << this->Range[1] << ")\n"; os << indent << "UseTextActor3D: " << this->UseTextActor3D << "\n"; os << indent << "Label Format: " << this->LabelFormat << "\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 << "Point1 Coordinate: " << this->Point1Coordinate << "\n"; this->Point1Coordinate->PrintSelf(os, indent.GetNextIndent()); os << indent << "Point2 Coordinate: " << this->Point2Coordinate << "\n"; this->Point2Coordinate->PrintSelf(os, indent.GetNextIndent()); os << indent << "Title offset: " << this->TitleOffset[0] << ", " << this->TitleOffset[1] << "\n"; os << indent << "Label Y-offset: " << this->LabelOffset << "\n"; os << indent << "Exponent Y-offset: " << this->ExponentOffset << "\n"; os << indent << "AxisType: "; switch (this->AxisType) { case VTK_AXIS_TYPE_X: os << "X Axis" << endl; break; case VTK_AXIS_TYPE_Y: os << "Y Axis" << endl; break; case VTK_AXIS_TYPE_Z: os << "Z Axis" << endl; break; default: // shouldn't get here break; } os << indent << "DeltaMajor: " << this->DeltaMajor[0] << "," << this->DeltaMajor[1] << "," << this->DeltaMajor[2] << endl; os << indent << "DeltaRangeMajor: " << this->DeltaRangeMajor << endl; os << indent << "DeltaRangeMinor: " << this->DeltaRangeMinor << endl; os << indent << "MajorRangeStart: " << this->MajorRangeStart << endl; os << indent << "MinorRangeStart: " << this->MinorRangeStart << endl; os << indent << "MinorTicksVisible: " << this->MinorTicksVisible << endl; os << indent << "Camera: "; if (this->Camera) { this->Camera->PrintSelf(os, indent); } else { os << "(none)" << endl; } os << indent << "MajorTickSize: " << this->MajorTickSize << endl; os << indent << "MinorTickSize: " << this->MinorTickSize << endl; os << indent << "DrawGridlines: " << this->DrawGridlines << endl; os << indent << "MajorStart: " << this->MajorStart[0] << "," << this->MajorStart[1] << "," << this->MajorStart[2] << endl; os << indent << "AxisPosition: " << this->AxisPosition << endl; os << indent << "GridlineXLength: " << this->GridlineXLength << endl; os << indent << "GridlineYLength: " << this->GridlineYLength << endl; os << indent << "GridlineZLength: " << this->GridlineZLength << endl; os << indent << "DrawInnerGridpolys: " << this->DrawGridpolys << endl; os << indent << "DrawInnerGridlines: " << this->DrawInnerGridlines << endl; os << indent << "TickLocation: " << this->TickLocation << endl; os << indent << "LabelTextProperty: " << this->LabelTextProperty << endl; os << indent << "TitleTextProperty: " << this->TitleTextProperty << endl; os << indent << "Use2DMode: " << this->Use2DMode << endl; os << indent << "SaveTitlePosition: " << this->SaveTitlePosition << endl; os << indent << "VerticalOffsetXTitle2D" << this->VerticalOffsetXTitle2D << endl; os << indent << "HorizontalOffsetYTitle2D" << this->HorizontalOffsetYTitle2D << endl; os << indent << "LastMinDisplayCoordinates: (" << this->LastMinDisplayCoordinate[0] << ", " << this->LastMinDisplayCoordinate[1] << ", " << this->LastMinDisplayCoordinate[2] << ")" << endl; os << indent << "LastMaxDisplayCoordinates: (" << this->LastMaxDisplayCoordinate[0] << ", " << this->LastMaxDisplayCoordinate[1] << ", " << this->LastMaxDisplayCoordinate[2] << ")" << endl; } //------------------------------------------------------------------------------ // Sets text string for label vectors. Allocates memory if necessary. //------------------------------------------------------------------------------ void vtkAxisActor::SetLabels(vtkStringArray* labels) { // // If the number of labels has changed, re-allocate the correct // amount of memory. // int numLabels = labels->GetNumberOfValues(); if (numLabels < 0) { vtkErrorMacro(<< "Number of labels " << numLabels << " is invalid"); return; } if (this->NumberOfLabelsBuilt != numLabels) { this->LabelProps.clear(); this->LabelProps.reserve(numLabels); for (int i = 0; i < numLabels; i++) { auto currentLabel = std::make_shared(); currentLabel->SetAxis(this); this->LabelProps.push_back(currentLabel); } } // // Set the label vector text. // for (int i = 0; i < numLabels; i++) { vtkTextActorInterfaceInternal* currentLabel = this->LabelProps[i].get(); currentLabel->SetInputText(labels->GetValue(i)); } this->NumberOfLabelsBuilt = numLabels; this->LabelBuildTime.Modified(); } //-----------------------------------------------------------------------------* // Creates Poly data (lines) from tickmarks (minor/major), gridlines, and axis. //-----------------------------------------------------------------------------* void vtkAxisActor::SetAxisPointsAndLines() { vtkPoints* mainLinePts = vtkPoints::New(); vtkPoints* axisMajorTicksPts = vtkPoints::New(); vtkPoints* axisMinorTicksPts = vtkPoints::New(); vtkCellArray* mainLine = vtkCellArray::New(); vtkCellArray* axisMajorTicksLines = vtkCellArray::New(); vtkCellArray* axisMinorTicksLines = vtkCellArray::New(); vtkCellArray* gridlines = vtkCellArray::New(); vtkCellArray* innerGridlines = vtkCellArray::New(); vtkCellArray* polys = vtkCellArray::New(); this->AxisLines->SetPoints(mainLinePts); this->AxisLines->SetLines(mainLine); this->AxisMajorTicks->SetPoints(axisMajorTicksPts); this->AxisMajorTicks->SetLines(axisMajorTicksLines); this->AxisMinorTicks->SetPoints(axisMinorTicksPts); this->AxisMinorTicks->SetLines(axisMinorTicksLines); this->Gridlines->SetPoints(this->GridlinePts); this->Gridlines->SetLines(gridlines); this->InnerGridlines->SetPoints(this->InnerGridlinePts); this->InnerGridlines->SetLines(innerGridlines); this->Gridpolys->SetPoints(this->GridpolyPts); this->Gridpolys->SetPolys(polys); mainLinePts->Delete(); axisMajorTicksPts->Delete(); axisMinorTicksPts->Delete(); mainLine->Delete(); axisMajorTicksLines->Delete(); axisMinorTicksLines->Delete(); gridlines->Delete(); innerGridlines->Delete(); polys->Delete(); int numMinorTickPts, numGridlines, numInnerGridlines, numMajorTickPts, numGridpolys, numLines; vtkIdType ptIds[2]; vtkIdType polyPtIds[4]; if (this->TickVisibility) { if (this->MinorTicksVisible) { // In 2D mode, the minorTickPts for yz portion or xz portion have been removed. numMinorTickPts = this->MinorTickPts->GetNumberOfPoints(); for (int i = 0; i < numMinorTickPts; i++) { axisMinorTicksPts->InsertNextPoint(this->MinorTickPts->GetPoint(i)); } } numMajorTickPts = this->MajorTickPts->GetNumberOfPoints(); if (this->Use2DMode == 0) { for (int i = 0; i < numMajorTickPts; i++) { axisMajorTicksPts->InsertNextPoint(this->MajorTickPts->GetPoint(i)); } } else { // In 2D mode, we don't need the pts for the xz portion or yz portion of the major tickmarks // majorTickPts not modified because all points are used for labels' positions. for (int i = 0; i < numMajorTickPts; i += 4) { axisMajorTicksPts->InsertNextPoint(this->MajorTickPts->GetPoint(i)); axisMajorTicksPts->InsertNextPoint(this->MajorTickPts->GetPoint(i + 1)); } } } // create major ticks lines numLines = axisMajorTicksPts->GetNumberOfPoints() / 2; for (int i = 0; i < numLines; i++) { ptIds[0] = 2 * i; ptIds[1] = 2 * i + 1; axisMajorTicksLines->InsertNextCell(2, ptIds); } // create major ticks lines numLines = axisMinorTicksPts->GetNumberOfPoints() / 2; for (int i = 0; i < numLines; i++) { ptIds[0] = 2 * i; ptIds[1] = 2 * i + 1; axisMinorTicksLines->InsertNextCell(2, ptIds); } if (this->AxisVisibility) { // first axis point ptIds[0] = mainLinePts->InsertNextPoint(this->Point1Coordinate->GetValue()); // last axis point ptIds[1] = mainLinePts->InsertNextPoint(this->Point2Coordinate->GetValue()); mainLine->InsertNextCell(2, ptIds); } // create grid lines if (this->DrawGridlines && this->AxisOnOrigin == 0) { numGridlines = this->GridlinePts->GetNumberOfPoints() / 2; int start = (this->DrawGridlinesLocation == 0 || this->DrawGridlinesLocation == 1) ? 0 : 1; int increment = (this->DrawGridlinesLocation == 0) ? 1 : 2; for (int i = start; i < numGridlines; i += increment) { ptIds[0] = 2 * i; ptIds[1] = 2 * i + 1; gridlines->InsertNextCell(2, ptIds); } } // create inner grid lines if (this->DrawInnerGridlines && this->AxisOnOrigin == 0) { numInnerGridlines = this->InnerGridlinePts->GetNumberOfPoints() / 2; for (int i = 0; i < numInnerGridlines; i++) { ptIds[0] = 2 * i; ptIds[1] = 2 * i + 1; innerGridlines->InsertNextCell(2, ptIds); } } // create polys (grid polys) if (this->DrawGridpolys && this->AxisOnOrigin == 0) { numGridpolys = this->GridpolyPts->GetNumberOfPoints() / 4; for (int i = 0; i < numGridpolys; i++) { polyPtIds[0] = 4 * i; polyPtIds[1] = 4 * i + 1; polyPtIds[2] = 4 * i + 2; polyPtIds[3] = 4 * i + 3; polys->InsertNextCell(4, polyPtIds); } } } //-----------------------------------------------------------------------------** // Returns true if any tick vis attribute has changed since last check. //-----------------------------------------------------------------------------** bool vtkAxisActor::TickVisibilityChanged() { bool retVal = (this->TickVisibility != this->LastTickVisibility) || (this->DrawGridlines != this->LastDrawGridlines) || (this->MinorTicksVisible != this->LastMinorTicksVisible); this->LastTickVisibility = this->TickVisibility; this->LastDrawGridlines = this->DrawGridlines; this->LastMinorTicksVisible = this->MinorTicksVisible; return retVal; } //-----------------------------------------------------------------------------** // Set the bounds for this actor to use. Sets timestamp BoundsModified. //-----------------------------------------------------------------------------** void vtkAxisActor::SetBounds(const double b[6]) { if ((this->Bounds[0] != b[0]) || (this->Bounds[1] != b[1]) || (this->Bounds[2] != b[2]) || (this->Bounds[3] != b[3]) || (this->Bounds[4] != b[4]) || (this->Bounds[5] != b[5])) { for (int i = 0; i < 6; i++) { this->Bounds[i] = b[i]; } this->BoundsTime.Modified(); } } //-----------------------------------------------------------------------------** // Retrieves the bounds of this actor. //-----------------------------------------------------------------------------** void vtkAxisActor::SetBounds( double xmin, double xmax, double ymin, double ymax, double zmin, double zmax) { if ((this->Bounds[0] != xmin) || (this->Bounds[1] != xmax) || (this->Bounds[2] != ymin) || (this->Bounds[3] != ymax) || (this->Bounds[4] != zmin) || (this->Bounds[5] != zmax)) { this->Bounds[0] = xmin; this->Bounds[1] = xmax; this->Bounds[2] = ymin; this->Bounds[3] = ymax; this->Bounds[4] = zmin; this->Bounds[5] = zmax; this->BoundsTime.Modified(); } } //-----------------------------------------------------------------------------** // Retrieves the bounds of this actor. //-----------------------------------------------------------------------------** double* vtkAxisActor::GetBounds() { return this->Bounds; } //-----------------------------------------------------------------------------** // Retrieves the bounds of this actor. //-----------------------------------------------------------------------------** void vtkAxisActor::GetBounds(double b[6]) { for (int i = 0; i < 6; i++) { b[i] = this->Bounds[i]; } } //----------------------------------------------------------------------------- double vtkAxisActor::ComputeMaxLabelLength() { double maxXSize = 0; double maxYSize = 0; for (int i = 0; i < this->NumberOfLabelsBuilt; i++) { vtkTextActorInterfaceInternal* currentLabel = this->LabelProps[i].get(); double bounds[6]; currentLabel->GetBounds(bounds); double xsize = bounds[1] - bounds[0]; double ysize = bounds[3] - bounds[2]; maxXSize = std::max(xsize, maxXSize); maxYSize = std::max(ysize, maxYSize); } return std::sqrt((maxXSize * maxXSize) + (maxYSize * maxYSize)); } //----------------------------------------------------------------------------- double vtkAxisActor::ComputeTitleLength() { double bounds[6]; this->TitleProp->GetBounds(bounds); double xsize = bounds[1] - bounds[0]; double ysize = bounds[3] - bounds[2]; return std::sqrt((xsize * xsize) + (ysize * ysize)); } //-----------------------------------------------------------------------------** void vtkAxisActor::SetLabelScale(double s) { for (int i = 0; i < this->NumberOfLabelsBuilt; i++) { this->SetLabelScale(i, s); } } //-----------------------------------------------------------------------------** void vtkAxisActor::SetLabelScale(int label, double s) { this->LabelProps[label]->SetScale(s); } //-----------------------------------------------------------------------------** void vtkAxisActor::SetTitleScale(double s) { this->TitleProp->SetScale(s); this->SetExponentScale(s); } //-----------------------------------------------------------------------------** void vtkAxisActor::SetExponentScale(double s) { this->ExponentProp->SetScale(s); } //-----------------------------------------------------------------------------** void vtkAxisActor::SetTitle(const std::string& title) { if (this->Title != title) { this->TitleProp->SetInputText(title); this->Title = title; this->TitleTextTime.Modified(); this->Modified(); } } //-----------------------------------------------------------------------------** void vtkAxisActor::SetTitleAlignLocation(int location) { if (location != this->TitleAlignLocation) { switch (location) { case VTK_ALIGN_TOP: case VTK_ALIGN_BOTTOM: case VTK_ALIGN_POINT1: case VTK_ALIGN_POINT2: { this->TitleAlignLocation = location; this->TitleTextTime.Modified(); this->Modified(); break; } default: { break; } } } } //-----------------------------------------------------------------------------** void vtkAxisActor::SetExponent(const std::string& exponent) { if (this->Exponent != exponent) { this->Exponent = exponent; static const std::string prefix = "e"; this->ExponentProp->SetInputText(prefix + exponent); this->ExponentTextTime.Modified(); this->Modified(); } } //-----------------------------------------------------------------------------** void vtkAxisActor::SetExponentLocation(int location) { if (location != this->ExponentLocation) { switch (location) { case VTK_ALIGN_TOP: case VTK_ALIGN_BOTTOM: case VTK_ALIGN_POINT1: case VTK_ALIGN_POINT2: { this->ExponentLocation = location; this->ExponentTextTime.Modified(); this->Modified(); break; } default: { break; } } } } //------------------------------------------------------------------------------ void vtkAxisActor::SetAxisLinesProperty(vtkProperty* prop) { this->SetAxisMainLineProperty(prop); this->SetAxisMajorTicksProperty(prop); this->SetAxisMinorTicksProperty(prop); this->Modified(); } //------------------------------------------------------------------------------ vtkProperty* vtkAxisActor::GetAxisLinesProperty() { return this->AxisLinesActor->GetProperty(); } //------------------------------------------------------------------------------ void vtkAxisActor::SetAxisMainLineProperty(vtkProperty* prop) { this->AxisLinesActor->SetProperty(prop); this->Modified(); } vtkProperty* vtkAxisActor::GetAxisMainLineProperty() { return this->GetAxisLinesProperty(); } //------------------------------------------------------------------------------ void vtkAxisActor::SetAxisMajorTicksProperty(vtkProperty* prop) { this->AxisMajorTicksActor->SetProperty(prop); this->Modified(); } //------------------------------------------------------------------------------ vtkProperty* vtkAxisActor::GetAxisMajorTicksProperty() { return this->AxisMajorTicksActor->GetProperty(); } //------------------------------------------------------------------------------ void vtkAxisActor::SetAxisMinorTicksProperty(vtkProperty* prop) { this->AxisMinorTicksActor->SetProperty(prop); this->Modified(); } //------------------------------------------------------------------------------ vtkProperty* vtkAxisActor::GetAxisMinorTicksProperty() { return this->AxisMinorTicksActor->GetProperty(); } //------------------------------------------------------------------------------ void vtkAxisActor::SetGridlinesProperty(vtkProperty* prop) { this->GridlinesActor->SetProperty(prop); this->Modified(); } //------------------------------------------------------------------------------ vtkProperty* vtkAxisActor::GetGridlinesProperty() { return this->GridlinesActor->GetProperty(); } //------------------------------------------------------------------------------ void vtkAxisActor::SetInnerGridlinesProperty(vtkProperty* prop) { this->InnerGridlinesActor->SetProperty(prop); this->Modified(); } //------------------------------------------------------------------------------ vtkProperty* vtkAxisActor::GetInnerGridlinesProperty() { return this->InnerGridlinesActor->GetProperty(); } //------------------------------------------------------------------------------ void vtkAxisActor::SetGridpolysProperty(vtkProperty* prop) { this->GridpolysActor->SetProperty(prop); this->Modified(); } //------------------------------------------------------------------------------ vtkProperty* vtkAxisActor::GetGridpolysProperty() { return this->GridpolysActor->GetProperty(); } //------------------------------------------------------------------------------ vtkTextProperty* vtkAxisActor::GetTitleTextProperty() { return this->TitleTextProperty.Get(); } //------------------------------------------------------------------------------ vtkTextProperty* vtkAxisActor::GetLabelTextProperty() { return this->LabelTextProperty.Get(); } //------------------------------------------------------------------------------ vtkProperty* vtkAxisActor::NewTitleProperty() { vtkProperty* newProp = vtkProperty::New(); newProp->DeepCopy(this->GetProperty()); newProp->SetColor(this->TitleTextProperty->GetColor()); return newProp; } //------------------------------------------------------------------------------ vtkProperty* vtkAxisActor::NewLabelProperty() { vtkProperty* newProp = vtkProperty::New(); newProp->DeepCopy(this->GetProperty()); newProp->SetColor(this->LabelTextProperty->GetColor()); return newProp; } //------------------------------------------------------------------------------ void vtkAxisActor::SetCamera(vtkCamera* camera) { if (this->Camera != camera) { this->Camera = camera; this->TitleProp->SetCamera(camera); this->ExponentProp->SetCamera(camera); this->Modified(); } } //------------------------------------------------------------------------------ vtkCamera* vtkAxisActor::GetCamera() { return this->Camera; } //------------------------------------------------------------------------------ double vtkAxisActor::GetDeltaMajor(int axis) { return (axis >= 0 && axis <= 2) ? this->DeltaMajor[axis] : 0; } //------------------------------------------------------------------------------ void vtkAxisActor::SetDeltaMajor(int axis, double value) { if (axis >= 0 && axis <= 2) { this->DeltaMajor[axis] = value; } } //------------------------------------------------------------------------------ double vtkAxisActor::GetMajorStart(int axis) { return (axis >= 0 && axis <= 2) ? this->MajorStart[axis] : 0; } //------------------------------------------------------------------------------ void vtkAxisActor::SetMajorStart(int axis, double value) { if (axis >= 0 && axis <= 2) { this->MajorStart[axis] = value; } } //------------------------------------------------------------------------------ bool vtkAxisActor::BoundsDisplayCoordinateChanged(vtkViewport* viewport) { double transMinPt[3], transMaxPt[3]; viewport->SetWorldPoint(this->Bounds[0], this->Bounds[2], this->Bounds[4], 1.0); viewport->WorldToDisplay(); viewport->GetDisplayPoint(transMinPt); viewport->SetWorldPoint(this->Bounds[1], this->Bounds[3], this->Bounds[5], 1.0); viewport->WorldToDisplay(); viewport->GetDisplayPoint(transMaxPt); if (this->LastMinDisplayCoordinate[0] != transMinPt[0] || this->LastMinDisplayCoordinate[1] != transMinPt[1] || this->LastMinDisplayCoordinate[2] != transMinPt[2] || this->LastMaxDisplayCoordinate[0] != transMaxPt[0] || this->LastMaxDisplayCoordinate[1] != transMaxPt[1] || this->LastMaxDisplayCoordinate[2] != transMaxPt[2]) { for (int i = 0; i < 3; ++i) { this->LastMinDisplayCoordinate[i] = transMinPt[i]; this->LastMaxDisplayCoordinate[i] = transMaxPt[i]; } return true; } return false; } //------------------------------------------------------------------------------ // endpoint-related methods //------------------------------------------------------------------------------ vtkCoordinate* vtkAxisActor::GetPoint1Coordinate() { vtkDebugMacro(<< this->GetClassName() << " (" << this << "): returning Point1 Coordinate address " << this->Point1Coordinate); return this->Point1Coordinate; } //------------------------------------------------------------------------------ vtkCoordinate* vtkAxisActor::GetPoint2Coordinate() { vtkDebugMacro(<< this->GetClassName() << " (" << this << "): returning Point2 Coordinate address " << this->Point2Coordinate); return this->Point2Coordinate; } //------------------------------------------------------------------------------ void vtkAxisActor::SetPoint1(double x, double y, double z) { this->Point1Coordinate->SetValue(x, y, z); } //------------------------------------------------------------------------------ void vtkAxisActor::SetPoint2(double x, double y, double z) { this->Point2Coordinate->SetValue(x, y, z); } //------------------------------------------------------------------------------ double* vtkAxisActor::GetPoint1() { return this->Point1Coordinate->GetValue(); } //------------------------------------------------------------------------------ double* vtkAxisActor::GetPoint2() { return this->Point2Coordinate->GetValue(); } //------------------------------------------------------------------------------ // Creates points for ticks (minor, major, gridlines) in correct position // for a generic axis. //------------------------------------------------------------------------------ bool vtkAxisActor::BuildTickPoints(double p1[3], double p2[3], bool force) { // Prevent any unwanted computation if (!force && (this->AxisPosition == this->LastAxisPosition) && (this->TickLocation == this->LastTickLocation) && (this->BoundsTime.GetMTime() < this->BuildTime.GetMTime()) && (this->Point1Coordinate->GetMTime() < this->BuildTickPointsTime.GetMTime()) && (this->Point2Coordinate->GetMTime() < this->BuildTickPointsTime.GetMTime()) && (this->Range[0] == this->LastRange[0]) && (this->Range[1] == this->LastRange[1])) { return false; } // Reset previous objects this->MinorTickPts->Reset(); this->MajorTickPts->Reset(); this->GridlinePts->Reset(); this->InnerGridlinePts->Reset(); this->GridpolyPts->Reset(); // As we assume that the Axis is not necessary aligned to the absolute X/Y/Z // axis, we will convert the absolute XYZ information to relative one // using a base composed as follow (axis, u, v) double coordSystem[3][3]; // axisVector, uVector, vVector switch (this->AxisType) { case VTK_AXIS_TYPE_X: memcpy(&coordSystem[0], this->AxisBaseForX, 3 * sizeof(double)); memcpy(&coordSystem[1], this->AxisBaseForY, 3 * sizeof(double)); memcpy(&coordSystem[2], this->AxisBaseForZ, 3 * sizeof(double)); break; case VTK_AXIS_TYPE_Y: memcpy(&coordSystem[0], this->AxisBaseForY, 3 * sizeof(double)); memcpy(&coordSystem[1], this->AxisBaseForX, 3 * sizeof(double)); memcpy(&coordSystem[2], this->AxisBaseForZ, 3 * sizeof(double)); break; case VTK_AXIS_TYPE_Z: memcpy(&coordSystem[0], this->AxisBaseForZ, 3 * sizeof(double)); memcpy(&coordSystem[1], this->AxisBaseForX, 3 * sizeof(double)); memcpy(&coordSystem[2], this->AxisBaseForY, 3 * sizeof(double)); break; default: // shouldn't get here break; } //-----------------------------------------------------------------------------* // Build Minor Ticks //-----------------------------------------------------------------------------* if (this->Log) { this->BuildMinorTicksLog(p1, p2, coordSystem); } else { this->BuildMinorTicks(p1, p2, coordSystem); } //-----------------------------------------------------------------------------* // Build Gridline + GridPoly points + InnerGrid (Only for Orthonormal base) //-----------------------------------------------------------------------------* if (!this->Log) { BuildAxisGridLines(p1, p2, coordSystem); } //-----------------------------------------------------------------------------* // Build Major ticks //-----------------------------------------------------------------------------* if (this->Log) { BuildMajorTicksLog(p1, p2, coordSystem); } else { BuildMajorTicks(p1, p2, coordSystem); } this->BuildTickPointsTime.Modified(); this->LastTickLocation = this->TickLocation; return true; } //------------------------------------------------------------------------------ void vtkAxisActor::BuildAxisGridLines(double p1[3], double p2[3], double localCoordSys[3][3]) { int uIndex = 0, vIndex = 0; double uGridLength = 0.0, vGridLength = 0.0; double gridPointClosest[3], gridPointFarest[3], gridPointU[3], gridPointV[3]; double innerGridPointClosestU[3], innerGridPointClosestV[3]; double innerGridPointFarestU[3], innerGridPointFarestV[3]; double deltaVector[3]; int uMult = vtkAxisActorMultiplierTable1[this->AxisPosition]; int vMult = vtkAxisActorMultiplierTable2[this->AxisPosition]; double* axisVector = localCoordSys[0]; double* uVector = localCoordSys[1]; double* vVector = localCoordSys[2]; switch (this->AxisType) { case VTK_AXIS_TYPE_X: uGridLength = this->GridlineYLength; vGridLength = this->GridlineZLength; uIndex = 1; vIndex = 2; break; case VTK_AXIS_TYPE_Y: uGridLength = this->GridlineXLength; vGridLength = this->GridlineZLength; uIndex = 0; vIndex = 2; break; case VTK_AXIS_TYPE_Z: uGridLength = this->GridlineXLength; vGridLength = this->GridlineYLength; uIndex = 0; vIndex = 1; break; default: // shouldn't get here break; } bool hasOrthogonalVectorBase = this->AxisBaseForX[0] == 1 && this->AxisBaseForX[1] == 0 && this->AxisBaseForX[2] == 0 && this->AxisBaseForY[0] == 0 && this->AxisBaseForY[1] == 1 && this->AxisBaseForY[2] == 0 && this->AxisBaseForZ[0] == 0 && this->AxisBaseForZ[1] == 0 && this->AxisBaseForZ[2] == 1; // - Initialize all points to be on the axis for (int i = 0; i < 3; i++) { gridPointClosest[i] = gridPointFarest[i] = gridPointU[i] = gridPointV[i] = p1[i]; deltaVector[i] = (p2[i] - p1[i]); } double axisLength = vtkMath::Norm(deltaVector); double rangeScale = axisLength / (this->Range[1] - this->Range[0]); // - Test that the delta is numerically different from zero if (fabs(this->DeltaMajor[this->AxisType]) <= FLT_EPSILON) { return; } // - Reduce the deltaVector to correspond to a major tick step vtkMath::Normalize(deltaVector); for (int i = 0; i < 3; i++) { deltaVector[i] *= this->DeltaMajor[this->AxisType]; } // - Move base points for (int i = 0; i < 3; i++) { gridPointU[i] -= uVector[i] * uMult * uGridLength; gridPointV[i] -= vVector[i] * vMult * vGridLength; gridPointFarest[i] -= uVector[i] * uMult * uGridLength + vVector[i] * vMult * vGridLength; } // - Add the initial shift if any double axisShift = (this->MajorRangeStart - this->Range[0]) * rangeScale; for (int i = 0; i < 3; i++) { gridPointU[i] += axisVector[i] * axisShift; gridPointV[i] += axisVector[i] * axisShift; gridPointFarest[i] += axisVector[i] * axisShift; gridPointClosest[i] += axisVector[i] * axisShift; } // - Insert Gridlines points along the axis using the DeltaMajor vector double nbIterationAsDouble = (axisLength - axisShift) / vtkMath::Norm(deltaVector); // - Test number of points for numerical difficulties if (!std::isfinite(nbIterationAsDouble) || (nbIterationAsDouble <= 0) || (nbIterationAsDouble > VTK_MAX_TICKS)) { return; } int nbIteration = vtkMath::Floor(nbIterationAsDouble + 2 * FLT_EPSILON) + 1; nbIteration = (nbIteration < VTK_MAX_TICKS) ? nbIteration : VTK_MAX_TICKS; for (int nbTicks = 0; nbTicks < nbIteration; nbTicks++) { // Closest U this->GridlinePts->InsertNextPoint(gridPointClosest); this->GridlinePts->InsertNextPoint(gridPointU); // Farthest U this->GridlinePts->InsertNextPoint(gridPointFarest); this->GridlinePts->InsertNextPoint(gridPointU); // Closest V this->GridlinePts->InsertNextPoint(gridPointClosest); this->GridlinePts->InsertNextPoint(gridPointV); // Farthest V this->GridlinePts->InsertNextPoint(gridPointFarest); this->GridlinePts->InsertNextPoint(gridPointV); // PolyPoints this->GridpolyPts->InsertNextPoint(gridPointClosest); this->GridpolyPts->InsertNextPoint(gridPointU); this->GridpolyPts->InsertNextPoint(gridPointFarest); this->GridpolyPts->InsertNextPoint(gridPointV); // Move forward along the axis for (int i = 0; i < 3; i++) { gridPointClosest[i] += deltaVector[i]; gridPointU[i] += deltaVector[i]; gridPointFarest[i] += deltaVector[i]; gridPointV[i] += deltaVector[i]; } } // - Insert InnerGridLines points // We can only handle inner grid line with orthonormal base, otherwise // we would need to change the API of AxisActor which we don't want for // backward compatibility. if (hasOrthogonalVectorBase) { double axis, u, v; axis = this->MajorStart[this->AxisType]; innerGridPointClosestU[vIndex] = this->GetBounds()[vIndex * 2]; innerGridPointFarestU[vIndex] = this->GetBounds()[vIndex * 2 + 1]; innerGridPointClosestV[uIndex] = this->GetBounds()[uIndex * 2]; innerGridPointFarestV[uIndex] = this->GetBounds()[uIndex * 2 + 1]; while (axis <= p2[this->AxisType]) { innerGridPointClosestU[this->AxisType] = innerGridPointClosestV[this->AxisType] = innerGridPointFarestU[this->AxisType] = innerGridPointFarestV[this->AxisType] = axis; // u lines u = this->MajorStart[uIndex]; while (u <= p2[uIndex] && this->DeltaMajor[uIndex] > FLT_EPSILON) { innerGridPointClosestU[uIndex] = innerGridPointFarestU[uIndex] = u; this->InnerGridlinePts->InsertNextPoint(innerGridPointClosestU); this->InnerGridlinePts->InsertNextPoint(innerGridPointFarestU); u += this->DeltaMajor[uIndex]; } // v lines v = this->MajorStart[vIndex]; while (v <= p2[vIndex] && this->DeltaMajor[vIndex] > FLT_EPSILON) { innerGridPointClosestV[vIndex] = innerGridPointFarestV[vIndex] = v; this->InnerGridlinePts->InsertNextPoint(innerGridPointClosestV); this->InnerGridlinePts->InsertNextPoint(innerGridPointFarestV); v += this->DeltaMajor[vIndex]; } axis += this->DeltaMajor[this->AxisType]; } } } //------------------------------------------------------------------------------ void vtkAxisActor::BuildMinorTicks(double p1[3], double p2[3], double localCoordSys[3][3]) { // (p2 - p1) vector double deltaVector[3]; // inside point: point shifted toward x,y,z direction // outside points: point shifted toward -x,-y,-z direction double vPointInside[3], vPointOutside[3], uPointInside[3], uPointOutside[3]; int uMult = vtkAxisActorMultiplierTable1[this->AxisPosition]; int vMult = vtkAxisActorMultiplierTable2[this->AxisPosition]; double* axisVector = localCoordSys[0]; double* uVector = localCoordSys[1]; double* vVector = localCoordSys[2]; // - Initialize all points to be on the axis for (int i = 0; i < 3; i++) { uPointInside[i] = vPointInside[i] = uPointOutside[i] = vPointOutside[i] = p1[i]; deltaVector[i] = (p2[i] - p1[i]); } double axisLength = vtkMath::Norm(deltaVector); double rangeScale = axisLength / (this->Range[1] - this->Range[0]); // - Move outside points if needed (Axis -> Outside) if (this->TickLocation == VTK_TICKS_OUTSIDE || this->TickLocation == VTK_TICKS_BOTH) { for (int i = 0; i < 3; i++) { uPointOutside[i] += uVector[i] * uMult * this->MinorTickSize; vPointOutside[i] += vVector[i] * vMult * this->MinorTickSize; } } // - Move inside points if needed (Axis -> Inside) if (this->TickLocation == VTK_TICKS_INSIDE || this->TickLocation == VTK_TICKS_BOTH) { for (int i = 0; i < 3; i++) { uPointInside[i] -= uVector[i] * uMult * this->MinorTickSize; vPointInside[i] -= vVector[i] * vMult * this->MinorTickSize; } } // - Add the initial shift if any double axisShift = (this->MinorRangeStart - this->Range[0]) * rangeScale; axisLength -= axisShift; for (int i = 0; i < 3; i++) { uPointInside[i] += axisVector[i] * axisShift; vPointInside[i] += axisVector[i] * axisShift; uPointOutside[i] += axisVector[i] * axisShift; vPointOutside[i] += axisVector[i] * axisShift; } // - Reduce the deltaVector to correspond to a tick step vtkMath::Normalize(deltaVector); double deltaMinor = this->DeltaRangeMinor * rangeScale; if (deltaMinor <= 0.0) { return; } // - Estimate number of steps to catch numerical difficulties double nTicks = axisLength / deltaMinor; if (!std::isfinite(nTicks) || (nTicks <= 0) || (nTicks > VTK_MAX_TICKS)) { return; } // - Insert tick points along the axis using the deltaVector // step is a multiple of deltaMajor value // currentStep as well, except for the last value, it doesn't exceed axisLength double step = 0.0, currentStep = 0.0; double tickPoint[3]; while (currentStep < axisLength) { currentStep = (step > axisLength) ? axisLength : step; // axis/u side for (int i = 0; i < 3; i++) { tickPoint[i] = deltaVector[i] * currentStep + uPointInside[i]; } this->MinorTickPts->InsertNextPoint(tickPoint); // axis/u side for (int i = 0; i < 3; i++) { tickPoint[i] = deltaVector[i] * currentStep + uPointOutside[i]; } this->MinorTickPts->InsertNextPoint(tickPoint); // axis/v side for (int i = 0; i < 3; i++) { tickPoint[i] = deltaVector[i] * currentStep + vPointInside[i]; } this->MinorTickPts->InsertNextPoint(tickPoint); // axis/v side for (int i = 0; i < 3; i++) tickPoint[i] = deltaVector[i] * currentStep + vPointOutside[i]; this->MinorTickPts->InsertNextPoint(tickPoint); step += deltaMinor; } } //------------------------------------------------------------------------------ void vtkAxisActor::BuildMajorTicks(double p1[3], double p2[3], double localCoordSys[3][3]) { double deltaVector[3]; double* axisVector = localCoordSys[0]; double* uVector = localCoordSys[1]; double* vVector = localCoordSys[2]; // inside point: point shifted toward x,y,z direction // outside points: point shifted toward -x,-y,-z direction double vPointInside[3], vPointOutside[3], uPointInside[3], uPointOutside[3]; int uMult = vtkAxisActorMultiplierTable1[this->AxisPosition]; int vMult = vtkAxisActorMultiplierTable2[this->AxisPosition]; // init deltaVector for (int i = 0; i < 3; i++) { deltaVector[i] = (p2[i] - p1[i]); } double axisLength = vtkMath::Norm(deltaVector); // factor of conversion world coord <-> range double rangeScale = axisLength / (this->Range[1] - this->Range[0]); // Delta vector is already initialized with the Major tick scale // - Initialize all points to be on the axis for (int i = 0; i < 3; i++) { uPointInside[i] = vPointInside[i] = uPointOutside[i] = vPointOutside[i] = p1[i]; this->TickVector[i] = uVector[i] * uMult * this->MajorTickSize; } // - Move outside points if needed (Axis -> Outside) if (this->TickLocation == VTK_TICKS_OUTSIDE || this->TickLocation == VTK_TICKS_BOTH) { for (int i = 0; i < 3; i++) { uPointOutside[i] += this->TickVector[i]; vPointOutside[i] += vVector[i] * vMult * this->MajorTickSize; } } // - Move inside points if needed (Axis -> Inside) if (this->TickLocation == VTK_TICKS_INSIDE || this->TickLocation == VTK_TICKS_BOTH) { for (int i = 0; i < 3; i++) { uPointInside[i] -= this->TickVector[i]; vPointInside[i] -= vVector[i] * vMult * this->MajorTickSize; } } // - Add the initial shift if any double axisShift = (this->MajorRangeStart - this->Range[0]) * rangeScale; axisLength -= axisShift; for (int i = 0; i < 3; i++) { uPointInside[i] += axisVector[i] * axisShift; vPointInside[i] += axisVector[i] * axisShift; uPointOutside[i] += axisVector[i] * axisShift; vPointOutside[i] += axisVector[i] * axisShift; } // - Reduce the deltaVector to correspond to a major tick step vtkMath::Normalize(deltaVector); double deltaMajor = this->DeltaRangeMajor * rangeScale; if (deltaMajor <= 0.0) { return; } // - Estimate number of steps to catch numerical difficulties double nTicks = axisLength / deltaMajor; if (!std::isfinite(nTicks) || (nTicks <= 0) || (nTicks > VTK_MAX_TICKS)) { return; } // - Insert tick points along the axis using the deltaVector // step is a multiple of deltaMajor value // currentStep as well, except for the last value, it doesn't exceed axisLength double step = 0.0, currentStep = 0.0; double tickPoint[3]; while (currentStep < axisLength) { currentStep = (step + (this->LastMajorTickPointCorrection * this->DeltaRangeMajor / 2) > axisLength) ? axisLength : step; // axis/u side for (int i = 0; i < 3; i++) tickPoint[i] = deltaVector[i] * currentStep + uPointInside[i]; this->MajorTickPts->InsertNextPoint(tickPoint); // axis/u side for (int i = 0; i < 3; i++) tickPoint[i] = deltaVector[i] * currentStep + uPointOutside[i]; this->MajorTickPts->InsertNextPoint(tickPoint); // axis/v side for (int i = 0; i < 3; i++) tickPoint[i] = deltaVector[i] * currentStep + vPointInside[i]; this->MajorTickPts->InsertNextPoint(tickPoint); // axis/v side for (int i = 0; i < 3; i++) tickPoint[i] = deltaVector[i] * currentStep + vPointOutside[i]; this->MajorTickPts->InsertNextPoint(tickPoint); step += deltaMajor; } } //------------------------------------------------------------------------------ void vtkAxisActor::BuildMinorTicksLog(double p1[3], double p2[3], double localCoordSys[3][3]) { double deltaVector[3]; double* axisVector = localCoordSys[0]; double* uVector = localCoordSys[1]; double* vVector = localCoordSys[2]; // inside point: point shifted toward x,y,z direction // outside points: point shifted toward -x,-y,-z direction double uPointInside[3], vPointInside[3], uPointOutside[3], vPointOutside[3]; for (int i = 0; i < 3; i++) { uPointInside[i] = vPointInside[i] = uPointOutside[i] = vPointOutside[i] = p1[i]; deltaVector[i] = (p2[i] - p1[i]); } double axisLength = vtkMath::Norm(deltaVector); // factor of conversion world coord <-> range double rangeScale = axisLength / log10(this->Range[1] / this->Range[0]); vtkMath::Normalize(deltaVector); int uMult = vtkAxisActorMultiplierTable1[this->AxisPosition]; int vMult = vtkAxisActorMultiplierTable2[this->AxisPosition]; // - Move outside points if needed (Axis -> Outside) if (this->TickLocation == VTK_TICKS_OUTSIDE || this->TickLocation == VTK_TICKS_BOTH) { for (int i = 0; i < 3; i++) { uPointOutside[i] += uVector[i] * uMult * this->MinorTickSize; vPointOutside[i] += vVector[i] * vMult * this->MinorTickSize; } } // - Move inside points if needed (Axis -> Inside) if (this->TickLocation == VTK_TICKS_INSIDE || this->TickLocation == VTK_TICKS_BOTH) { for (int i = 0; i < 3; i++) { uPointInside[i] -= uVector[i] * uMult * this->MinorTickSize; vPointInside[i] -= vVector[i] * vMult * this->MinorTickSize; } } // - Add the initial shift if any double axisShift = log10(this->MinorRangeStart / this->Range[0]) * rangeScale; axisLength -= axisShift; for (int i = 0; i < 3; i++) { uPointInside[i] += axisVector[i] * axisShift; vPointInside[i] += axisVector[i] * axisShift; uPointOutside[i] += axisVector[i] * axisShift; vPointOutside[i] += axisVector[i] * axisShift; } double base = 10.0, index; double step, tickRangeVal, tickVal; // pre set values double log10Range0 = log10(this->Range[0]), log10Range1 = log10(this->Range[1]); double lowBound = pow(base, floor(log10Range0)), upBound = pow(base, ceil(log10Range1)); // log scale can't work with lowBound <= 0 if (!std::isfinite(lowBound) || (lowBound <= 0)) { return; } double minorTickPoint[3], minorTickOnAxis[3]; // step match the minor tick log step, varying between each major tick. // for log10: minor step is 0.1 between 0.1 and 1.0, then 1.0 between 1.0 and 10.0, and so on for (step = lowBound; step < upBound; step *= base) { // number of minor tick between two major tick. for log10, index goes to 2.0 to 9.0 for (index = 2.0; index < base; index += 1.0) { tickRangeVal = index * step; // particular cases: if (tickRangeVal <= Range[0]) { continue; } // over upper bound if (tickRangeVal >= Range[1]) { break; } tickVal = (log10(tickRangeVal) - log10Range0) * rangeScale; // set tick point on axis (not inserted) for (int i = 0; i < 3; i++) { minorTickOnAxis[i] = deltaVector[i] * (tickVal); } // vtkMath::Add(minorTickOnAxis, p1, minorTickOnAxis); // handled later // u inside point vtkMath::Add(minorTickOnAxis, uPointInside, minorTickPoint); this->MinorTickPts->InsertNextPoint(minorTickPoint); // u outside point vtkMath::Add(minorTickOnAxis, uPointOutside, minorTickPoint); this->MinorTickPts->InsertNextPoint(minorTickPoint); if (this->Use2DMode == 0) { // v inside point vtkMath::Add(minorTickOnAxis, vPointInside, minorTickPoint); this->MinorTickPts->InsertNextPoint(minorTickPoint); // v outside point vtkMath::Add(minorTickOnAxis, vPointOutside, minorTickPoint); this->MinorTickPts->InsertNextPoint(minorTickPoint); } } } } //------------------------------------------------------------------------------ void vtkAxisActor::BuildMajorTicksLog(double p1[3], double p2[3], double localCoordSys[3][3]) { double deltaVector[3]; double* axisVector = localCoordSys[0]; double* uVector = localCoordSys[1]; double* vVector = localCoordSys[2]; // inside point: point shifted toward x,y,z direction // outside points: point shifted toward -x,-y,-z direction double vPointInside[3], vPointOutside[3], uPointInside[3], uPointOutside[3]; for (int i = 0; i < 3; i++) { uPointInside[i] = vPointInside[i] = uPointOutside[i] = vPointOutside[i] = p1[i]; deltaVector[i] = (p2[i] - p1[i]); } // length of axis (wold coord system) double axisLength = vtkMath::Norm(deltaVector); // factor of conversion world coord <-> range double rangeScale = axisLength / log10(this->Range[1] / this->Range[0]); vtkMath::Normalize(deltaVector); int uMult = vtkAxisActorMultiplierTable1[this->AxisPosition]; int vMult = vtkAxisActorMultiplierTable2[this->AxisPosition]; for (int i = 0; i < 3; i++) { this->TickVector[i] = uVector[i] * uMult * this->MajorTickSize; } // - Move outside points if needed (Axis -> Outside) if (this->TickLocation == VTK_TICKS_OUTSIDE || this->TickLocation == VTK_TICKS_BOTH) { for (int i = 0; i < 3; i++) { uPointOutside[i] += this->TickVector[i]; vPointOutside[i] += vVector[i] * vMult * this->MajorTickSize; } } // - Move inside points if needed (Axis -> Inside) if (this->TickLocation == VTK_TICKS_INSIDE || this->TickLocation == VTK_TICKS_BOTH) { for (int i = 0; i < 3; i++) { uPointInside[i] -= this->TickVector[i]; vPointInside[i] -= vVector[i] * vMult * this->MajorTickSize; } } // - Add the initial shift if any double axisShift = log10(this->MajorRangeStart / this->Range[0]) * rangeScale; axisLength -= axisShift; for (int i = 0; i < 3; i++) { uPointInside[i] += axisVector[i] * axisShift; vPointInside[i] += axisVector[i] * axisShift; uPointOutside[i] += axisVector[i] * axisShift; vPointOutside[i] += axisVector[i] * axisShift; } double base = 10.0; double indexTickRangeValue; double tickVal, tickRangeVal; double log10Range0 = log10(this->Range[0]), log10Range1 = log10(this->Range[1]); double lowBound = pow(base, (int)floor(log10Range0)), upBound = pow(base, (int)ceil(log10Range1)); // log scale can't work with lowBound <= 0 if (!std::isfinite(lowBound) || (lowBound <= 0)) { return; } double majorTickOnAxis[3], majorTickPoint[3]; for (indexTickRangeValue = lowBound; indexTickRangeValue <= upBound; indexTickRangeValue *= base) { tickRangeVal = indexTickRangeValue; if (indexTickRangeValue < this->Range[0]) { tickRangeVal = this->Range[0]; } else if (indexTickRangeValue > this->Range[1]) { tickRangeVal = this->Range[1]; } tickVal = (log10(tickRangeVal) - log10Range0) * rangeScale; for (int i = 0; i < 3; i++) { majorTickOnAxis[i] = deltaVector[i] * tickVal; } // u inside point vtkMath::Add(majorTickOnAxis, uPointInside, majorTickPoint); this->MajorTickPts->InsertNextPoint(majorTickPoint); // u outside point vtkMath::Add(majorTickOnAxis, uPointOutside, majorTickPoint); this->MajorTickPts->InsertNextPoint(majorTickPoint); // v inside point vtkMath::Add(majorTickOnAxis, vPointInside, majorTickPoint); this->MajorTickPts->InsertNextPoint(majorTickPoint); // v outside point vtkMath::Add(majorTickOnAxis, vPointOutside, majorTickPoint); this->MajorTickPts->InsertNextPoint(majorTickPoint); } } //------------------------------------------------------------------------------ vtkProp* vtkAxisActor::GetTitleActorInternal() { return this->TitleProp->GetActiveProp(this->Use2DMode, !this->UseTextActor3D); } //------------------------------------------------------------------------------ vtkProp* vtkAxisActor::GetLabelActorInternal(int index) { vtkTextActorInterfaceInternal* currentLabel = this->LabelProps[index].get(); return currentLabel->GetActiveProp(this->Use2DMode, !this->UseTextActor3D); } //------------------------------------------------------------------------------ vtkProp* vtkAxisActor::GetExponentActorInternal() { return this->ExponentProp->GetActiveProp(this->Use2DMode, !this->UseTextActor3D); } //------------------------------------------------------------------------------ void vtkAxisActor::UpdateLabelActorProperty(int idx) { vtkTextActorInterfaceInternal* labelProp = this->LabelProps[idx].get(); labelProp->SetTextProperty(this->LabelTextProperty, this->GetProperty()); } //------------------------------------------------------------------------------ void vtkAxisActor::UpdateTitleActorProperty() { this->TitleProp->SetTextProperty(this->TitleTextProperty, this->GetProperty()); } //------------------------------------------------------------------------------ void vtkAxisActor::UpdateExponentActorProperty() { this->ExponentProp->SetTextProperty(this->TitleTextProperty, this->GetProperty()); } //------------------------------------------------------------------------------ void vtkAxisActor::GetTranslucentProps(vtkPropCollection* collection) { if (this->AxisHasZeroLength) { return; } if (this->DrawGridlines) { collection->AddItem(this->GridlinesActor); if (this->DrawGridlinesOnly) { return; } } if (this->DrawInnerGridlines) { collection->AddItem(this->InnerGridlinesActor); } if (this->DrawGridpolys) { collection->AddItem(this->GridpolysActor); } if (!this->Title.empty() && this->TitleVisibility) { collection->AddItem(this->GetTitleActorInternal()); } if (this->LabelVisibility) { for (int i = 0; i < this->NumberOfLabelsBuilt; i++) { collection->AddItem(this->GetLabelActorInternal(i)); } if (this->ExponentVisibility) { collection->AddItem(this->GetExponentActorInternal()); } } collection->AddItem(this->AxisLinesActor); if (this->TickVisibility) { collection->AddItem(this->AxisMajorTicksActor); collection->AddItem(this->AxisMinorTicksActor); } } //------------------------------------------------------------------------------ vtkProp3DAxisFollower* vtkAxisActor::GetLabelFollower3D(int index) { if (static_cast(this->LabelProps.size()) > index) { return this->LabelProps[index]->GetFollower3D(); } return nullptr; } //------------------------------------------------------------------------------ vtkProp3DAxisFollower** vtkAxisActor::GetLabelProps3D() { this->LabelProps3D.clear(); for (const auto& label : this->LabelProps) { this->LabelProps3D.push_back(label->GetFollower3D()); } return this->LabelProps3D.data(); } //------------------------------------------------------------------------------ vtkAxisFollower* vtkAxisActor::GetLabelFollower(int index) { if (static_cast(this->LabelProps.size()) > index) { return this->LabelProps[index]->GetFollower(); } return nullptr; } //------------------------------------------------------------------------------ vtkAxisFollower** vtkAxisActor::GetLabelActors() { this->LabelActors.clear(); for (const auto& label : this->LabelProps) { this->LabelActors.push_back(label->GetFollower()); } return this->LabelActors.data(); } //------------------------------------------------------------------------------ vtkAxisFollower* vtkAxisActor::GetTitleActor() { return this->TitleProp->GetFollower(); } //------------------------------------------------------------------------------ vtkAxisFollower* vtkAxisActor::GetExponentActor() { return this->ExponentProp->GetFollower(); } //------------------------------------------------------------------------------ vtkProp3DAxisFollower* vtkAxisActor::GetTitleProp3D() { return this->TitleProp->GetFollower3D(); } //------------------------------------------------------------------------------ vtkProp3DAxisFollower* vtkAxisActor::GetExponentProp3D() { return this->ExponentProp->GetFollower3D(); } VTK_ABI_NAMESPACE_END