You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
nmWTAI-Platform/3rd/VTK7.1/source/VTK-7.1.1/Rendering/Annotation/vtkScalarBarActor.cxx

2731 lines
89 KiB
C++

/*=========================================================================
Program: Visualization Toolkit
Module: vtkScalarBarActor.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 "vtkScalarBarActor.h"
#include "vtkScalarBarActorInternal.h"
#include "vtkCellArray.h"
#include "vtkCellData.h"
#include "vtkColor.h"
#include "vtkColorTransferFunction.h"
#include "vtkCoordinate.h"
#include "vtkFloatArray.h"
#include "vtkImageData.h"
#include "vtkLookupTable.h"
#include "vtkMath.h"
#include "vtkMathTextUtilities.h"
#include "vtkNew.h"
#include "vtkObjectFactory.h"
#include "vtkPointData.h"
#include "vtkPolyData.h"
#include "vtkPolyDataMapper2D.h"
#include "vtkProperty2D.h"
#include "vtkRenderWindow.h"
#include "vtkRenderer.h"
#include "vtkScalarsToColors.h"
#include "vtkSmartPointer.h"
#include "vtkTextActor.h"
#include "vtkTextProperty.h"
#include "vtkTexture.h"
#include "vtkTexturedActor2D.h"
#include "vtkViewport.h"
#include "vtkWindow.h"
#include <vector>
#include <set>
#include <map>
#include <cstdio> // for snprintf
#undef VTK_DBG_LAYOUT
vtkStandardNewMacro(vtkScalarBarActor);
vtkCxxSetObjectMacro(vtkScalarBarActor, LookupTable, vtkScalarsToColors);
vtkCxxSetObjectMacro(vtkScalarBarActor, AnnotationTextProperty, vtkTextProperty);
vtkCxxSetObjectMacro(vtkScalarBarActor, LabelTextProperty, vtkTextProperty);
vtkCxxSetObjectMacro(vtkScalarBarActor, TitleTextProperty, vtkTextProperty);
vtkCxxSetObjectMacro(vtkScalarBarActor, BackgroundProperty, vtkProperty2D);
vtkCxxSetObjectMacro(vtkScalarBarActor, FrameProperty, vtkProperty2D);
//----------------------------------------------------------------------------
// Instantiate object with 64 maximum colors; 5 labels; %%-#6.3g label
// format, no title, and vertical orientation. The initial scalar bar
// size is (0.05 x 0.8) of the viewport size.
vtkScalarBarActor::vtkScalarBarActor()
{
this->P = new vtkScalarBarActorInternal;
this->LookupTable = NULL;
this->Position2Coordinate->SetValue(0.17, 0.8);
this->PositionCoordinate->SetCoordinateSystemToNormalizedViewport();
this->PositionCoordinate->SetValue(0.82, 0.1);
this->TextPad = 1;
this->TitleRatio = 0.5;
this->BarRatio = 0.375;
this->MaximumNumberOfColors = 64;
this->NumberOfLabels = 5;
this->NumberOfLabelsBuilt = 0;
this->Orientation = VTK_ORIENT_VERTICAL;
this->Title = NULL;
this->ComponentTitle = NULL;
this->VerticalTitleSeparation = 0;
this->LabelTextProperty = vtkTextProperty::New();
this->LabelTextProperty->SetFontSize(12);
this->LabelTextProperty->SetBold(1);
this->LabelTextProperty->SetItalic(1);
this->LabelTextProperty->SetShadow(1);
this->LabelTextProperty->SetFontFamilyToArial();
this->AnnotationTextProperty = vtkTextProperty::New();
this->AnnotationTextProperty->SetFontSize(12);
this->AnnotationTextProperty->SetBold(1);
this->AnnotationTextProperty->SetItalic(1);
this->AnnotationTextProperty->SetShadow(1);
this->AnnotationTextProperty->SetFontFamilyToArial();
this->TitleTextProperty = vtkTextProperty::New();
this->TitleTextProperty->ShallowCopy(this->LabelTextProperty);
this->LabelFormat = new char[8];
sprintf(this->LabelFormat, "%s", "%-#6.3g");
this->TitleActor = vtkTextActor::New();
this->TitleActor->GetPositionCoordinate()->
SetReferenceCoordinate(this->PositionCoordinate);
this->ScalarBar = vtkPolyData::New();
this->ScalarBarMapper = vtkPolyDataMapper2D::New();
this->ScalarBarMapper->SetInputData(this->ScalarBar);
this->ScalarBarActor = vtkActor2D::New();
this->ScalarBarActor->SetMapper(this->ScalarBarMapper);
this->ScalarBarActor->GetPositionCoordinate()->
SetReferenceCoordinate(this->PositionCoordinate);
this->LastOrigin[0] = 0;
this->LastOrigin[1] = 0;
this->LastSize[0] = 0;
this->LastSize[1] = 0;
this->DrawAnnotations = 1;
this->DrawNanAnnotation = 0;
this->AnnotationTextScaling = 0;
this->FixedAnnotationLeaderLineColor = 0;
this->NanAnnotation = 0;
this->SetNanAnnotation("NaN");
this->P->NanSwatch = vtkPolyData::New();
this->P->NanSwatchMapper = vtkPolyDataMapper2D::New();
this->P->NanSwatchActor = vtkActor2D::New();
this->P->NanSwatchMapper->SetInputData(this->P->NanSwatch);
this->P->NanSwatchActor->SetMapper(this->P->NanSwatchMapper);
this->P->NanSwatchActor->GetPositionCoordinate()->
SetReferenceCoordinate(this->PositionCoordinate);
this->DrawBelowRangeSwatch = false;
this->BelowRangeAnnotation = 0;
this->SetBelowRangeAnnotation("Below");
this->P->BelowRangeSwatch = vtkPolyData::New();
this->P->BelowRangeSwatchMapper = vtkPolyDataMapper2D::New();
this->P->BelowRangeSwatchActor = vtkActor2D::New();
this->P->BelowRangeSwatchMapper->SetInputData(this->P->BelowRangeSwatch);
this->P->BelowRangeSwatchActor->SetMapper(this->P->BelowRangeSwatchMapper);
this->P->BelowRangeSwatchActor->GetPositionCoordinate()->
SetReferenceCoordinate(this->PositionCoordinate);
this->DrawAboveRangeSwatch = false;
this->AboveRangeAnnotation = 0;
this->SetAboveRangeAnnotation("Above");
this->P->AboveRangeSwatch = vtkPolyData::New();
this->P->AboveRangeSwatchMapper = vtkPolyDataMapper2D::New();
this->P->AboveRangeSwatchActor = vtkActor2D::New();
this->P->AboveRangeSwatchMapper->SetInputData(this->P->AboveRangeSwatch);
this->P->AboveRangeSwatchActor->SetMapper(this->P->AboveRangeSwatchMapper);
this->P->AboveRangeSwatchActor->GetPositionCoordinate()->
SetReferenceCoordinate(this->PositionCoordinate);
this->AnnotationLeaderPadding = 8.;
this->P->AnnotationBoxes = vtkPolyData::New();
this->P->AnnotationBoxesMapper = vtkPolyDataMapper2D::New();
this->P->AnnotationBoxesActor = vtkActor2D::New();
this->P->AnnotationBoxesMapper->SetInputData(this->P->AnnotationBoxes);
this->P->AnnotationBoxesActor->SetMapper(this->P->AnnotationBoxesMapper);
this->P->AnnotationBoxesActor->GetPositionCoordinate()->
SetReferenceCoordinate(this->PositionCoordinate);
this->P->AnnotationLeaders = vtkPolyData::New();
this->P->AnnotationLeadersMapper = vtkPolyDataMapper2D::New();
this->P->AnnotationLeadersActor = vtkActor2D::New();
this->P->AnnotationLeadersMapper->SetInputData(this->P->AnnotationLeaders);
this->P->AnnotationLeadersActor->SetMapper(this->P->AnnotationLeadersMapper);
this->P->AnnotationLeadersActor->GetPositionCoordinate()->
SetReferenceCoordinate(this->PositionCoordinate);
this->P->TitleBox.Posn[0] = 0;
this->P->TitleBox.Posn[1] = 0;
this->P->TitleBox.Size[0] = 0;
this->P->TitleBox.Size[1] = 0;
// If opacity is on, a jail like texture is displayed behind it..
this->UseOpacity = 0;
this->TextureGridWidth = 10.0;
this->TexturePolyData = vtkPolyData::New();
vtkPolyDataMapper2D* textureMapper = vtkPolyDataMapper2D::New();
textureMapper->SetInputData(this->TexturePolyData);
this->TextureActor = vtkTexturedActor2D::New();
this->TextureActor->SetMapper(textureMapper);
textureMapper->Delete();
this->TextureActor->GetPositionCoordinate()->
SetReferenceCoordinate(this->PositionCoordinate);
vtkFloatArray* tc = vtkFloatArray::New();
tc->SetNumberOfComponents(2);
tc->SetNumberOfTuples(4);
tc->InsertComponent(0, 0, 0.0);
tc->InsertComponent(0, 1, 0.0);
tc->InsertComponent(1, 1, 0.0);
tc->InsertComponent(3, 0, 0.0);
this->TexturePolyData->GetPointData()->SetTCoords(tc);
tc->Delete();
vtkCellArray* polys2 = vtkCellArray::New();
polys2->InsertNextCell(4);
polys2->InsertCellPoint(0);
polys2->InsertCellPoint(1);
polys2->InsertCellPoint(2);
polys2->InsertCellPoint(3);
polys2->Delete();
vtkProperty2D* imageProperty = vtkProperty2D::New();
imageProperty->SetOpacity(0.08);
this->TextureActor->SetProperty(imageProperty);
imageProperty->Delete();
// Create the default texture. Just a "Jail" like grid
const unsigned int dim = 128;
vtkImageData* image = vtkImageData::New();
image->SetDimensions(dim, dim, 1);
image->AllocateScalars(VTK_UNSIGNED_CHAR, 1);
for (unsigned int y = 0; y < dim; y++)
{
unsigned char* ptr =
static_cast<unsigned char*>(image->GetScalarPointer(0, y, 0));
for (unsigned int x = 0; x < dim; x++)
{
*ptr = ((x == y) || (x == (dim - y - 1))) ? 255 : 0;
++ptr;
}
}
this->Texture = vtkTexture::New();
this->Texture->SetInputData(image);
this->Texture->RepeatOn();
this->TextureActor->SetTexture(this->Texture);
image->Delete();
// Default text position : Above scalar bar if orientation is horizontal
// Right of scalar bar if orientation is vertical
this->TextPosition = SucceedScalarBar;
this->MaximumWidthInPixels = VTK_INT_MAX;
this->MaximumHeightInPixels = VTK_INT_MAX;
this->BackgroundProperty = vtkProperty2D::New();
this->FrameProperty = vtkProperty2D::New();
this->DrawBackground = 0;
this->Background = vtkPolyData::New();
this->BackgroundMapper = vtkPolyDataMapper2D::New();
this->BackgroundMapper->SetInputData(this->Background);
this->BackgroundActor = vtkActor2D::New();
this->BackgroundActor->SetMapper(this->BackgroundMapper);
this->BackgroundActor->GetPositionCoordinate()
->SetReferenceCoordinate(this->PositionCoordinate);
#ifdef VTK_DBG_LAYOUT
this->DrawFrame = 1;
#else // VTK_DBG_LAYOUT
this->DrawFrame = 0;
#endif // VTK_DBG_LAYOUT
this->Frame = vtkPolyData::New();
this->FrameMapper = vtkPolyDataMapper2D::New();
this->FrameMapper->SetInputData(this->Frame);
this->FrameActor = vtkActor2D::New();
this->FrameActor->SetMapper(this->FrameMapper);
this->FrameActor->GetPositionCoordinate()
->SetReferenceCoordinate(this->PositionCoordinate);
this->DrawColorBar = 1;
this->DrawTickLabels = 1;
this->UnconstrainedFontSize = false;
}
//----------------------------------------------------------------------------
// 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 vtkScalarBarActor::ReleaseGraphicsResources(vtkWindow* win)
{
this->TitleActor->ReleaseGraphicsResources(win);
if (!this->P->TextActors.empty())
{
vtkScalarBarActorInternal::ActorVector::iterator it;
for (
it = this->P->TextActors.begin();
it != this->P->TextActors.end();
++it)
{
(*it)->ReleaseGraphicsResources(win);
}
}
for (size_t i = 0; i < this->P->AnnotationLabels.size(); ++i)
{
this->P->AnnotationLabels[i]->ReleaseGraphicsResources(win);
}
this->ScalarBarActor->ReleaseGraphicsResources(win);
this->P->NanSwatchActor->ReleaseGraphicsResources(win);
this->P->AboveRangeSwatchActor->ReleaseGraphicsResources(win);
this->P->BelowRangeSwatchActor->ReleaseGraphicsResources(win);
this->P->AnnotationBoxesActor->ReleaseGraphicsResources(win);
this->P->AnnotationLeadersActor->ReleaseGraphicsResources(win);
this->BackgroundActor->ReleaseGraphicsResources(win);
this->FrameActor->ReleaseGraphicsResources(win);
this->Texture->ReleaseGraphicsResources(win);
}
//----------------------------------------------------------------------------
void vtkScalarBarActor::GetScalarBarRect(int rect[4], vtkViewport* viewport)
{
vtkCoordinate *origin = this->ScalarBarActor->GetPositionCoordinate();
int * vpPos = origin->GetComputedViewportValue(viewport);
rect[0] = vpPos[0];
rect[1] = vpPos[1];
double *bounds = this->ScalarBar->GetBounds();
rect[0] += static_cast<int>(bounds[0] + 0.5);
rect[1] += static_cast<int>(bounds[2] + 0.5);
rect[2] = static_cast<int>(bounds[1] - bounds[0] + 0.5);
rect[3] = static_cast<int>(bounds[3] - bounds[2] + 0.5);
}
//----------------------------------------------------------------------------
vtkScalarBarActor::~vtkScalarBarActor()
{
delete [] this->LabelFormat;
this->LabelFormat = NULL;
this->TitleActor->Delete();
this->SetNanAnnotation(NULL);
this->SetBelowRangeAnnotation(NULL);
this->SetAboveRangeAnnotation(NULL);
this->ScalarBar->Delete();
this->ScalarBarMapper->Delete();
this->ScalarBarActor->Delete();
this->P->NanSwatch->Delete();
this->P->BelowRangeSwatch->Delete();
this->P->AboveRangeSwatch->Delete();
this->P->NanSwatchMapper->Delete();
this->P->AboveRangeSwatchMapper->Delete();
this->P->BelowRangeSwatchMapper->Delete();
this->P->NanSwatchActor->Delete();
this->P->AboveRangeSwatchActor->Delete();
this->P->BelowRangeSwatchActor->Delete();
this->P->AnnotationBoxes->Delete();
this->P->AnnotationBoxesMapper->Delete();
this->P->AnnotationBoxesActor->Delete();
this->P->AnnotationLeaders->Delete();
this->P->AnnotationLeadersMapper->Delete();
this->P->AnnotationLeadersActor->Delete();
delete [] this->Title;
this->Title = NULL;
delete [] this->ComponentTitle;
this->ComponentTitle = NULL;
this->SetLookupTable(NULL);
this->SetAnnotationTextProperty(NULL);
this->SetLabelTextProperty(NULL);
this->SetTitleTextProperty(NULL);
this->Texture->Delete();
this->TextureActor->Delete();
this->TexturePolyData->Delete();
this->Background->Delete();
this->BackgroundMapper->Delete();
this->BackgroundActor->Delete();
this->Frame->Delete();
this->FrameMapper->Delete();
this->FrameActor->Delete();
this->SetBackgroundProperty(NULL);
this->SetFrameProperty(NULL);
delete this->P;
}
//----------------------------------------------------------------------------
int vtkScalarBarActor::RenderOverlay(vtkViewport* viewport)
{
if (!this->RebuildLayoutIfNeeded(viewport))
{
return 0;
}
int renderedSomething = 0;
// Is the viewport's RenderWindow capturing GL2PS-special props? We'll need
// to handle this specially to get the texture to show up right.
if (vtkRenderer *renderer = vtkRenderer::SafeDownCast(viewport))
{
if (vtkRenderWindow *renderWindow = renderer->GetRenderWindow())
{
if (renderWindow->GetCapturingGL2PSSpecialProps())
{
renderer->CaptureGL2PSSpecialProp(this);
}
}
}
// Everything is built, just have to render
if (this->DrawBackground)
{
renderedSomething += this->BackgroundActor->RenderOverlay(viewport);
}
if (this->UseOpacity && this->DrawColorBar)
{
renderedSomething += this->TextureActor->RenderOverlay(viewport);
}
// Draw either the scalar bar (non-indexed mode) or
// the annotated value boxes (indexed mode).
if (!this->LookupTable->GetIndexedLookup())
{
if (this->DrawColorBar)
{
renderedSomething += this->ScalarBarActor->RenderOverlay(viewport);
}
if (this->DrawTickLabels)
{
vtkScalarBarActorInternal::ActorVector::iterator it;
for (
it = this->P->TextActors.begin();
it != this->P->TextActors.end();
++it)
{
renderedSomething += (*it)->RenderOverlay(viewport);
}
}
}
else if (this->DrawColorBar)
{
renderedSomething +=
this->P->AnnotationBoxesActor->RenderOverlay(viewport);
}
if (this->DrawNanAnnotation)
{
renderedSomething +=
this->P->NanSwatchActor->RenderOverlay(viewport);
}
if (this->DrawBelowRangeSwatch)
{
renderedSomething +=
this->P->BelowRangeSwatchActor->RenderOverlay(viewport);
}
if (this->DrawAboveRangeSwatch)
{
renderedSomething +=
this->P->AboveRangeSwatchActor->RenderOverlay(viewport);
}
if (this->DrawFrame)
{
renderedSomething += this->FrameActor->RenderOverlay(viewport);
}
if (this->Title != NULL)
{
renderedSomething += this->TitleActor->RenderOverlay(viewport);
}
if (this->DrawAnnotations)
{
if (!this->P->AnnotationLabels.empty())
{
renderedSomething +=
this->P->AnnotationLeadersActor->RenderOverlay(viewport);
for (size_t i = 0; i < this->P->AnnotationLabels.size(); ++i)
{
renderedSomething +=
this->P->AnnotationLabels[i]->RenderOverlay(viewport);
}
}
}
renderedSomething = (renderedSomething > 0)?(1):(0);
return renderedSomething;
}
int vtkScalarBarActor::RebuildLayoutIfNeeded(vtkViewport* viewport)
{
if (!this->LookupTable)
{
vtkWarningMacro(<< "Need a mapper to render a scalar bar");
return 0;
}
if (!this->TitleTextProperty)
{
vtkErrorMacro(<< "Need title text property to render a scalar bar");
return 0;
}
if (!this->LabelTextProperty)
{
vtkErrorMacro(<< "Need label text property to render a scalar bar");
return 0;
}
if (!this->AnnotationTextProperty)
{
vtkErrorMacro(<< "Need annotation text property to render a scalar bar");
return 0;
}
// Check to see whether we have to rebuild everything
int positionsHaveChanged = 0;
if (viewport->GetMTime() > this->BuildTime ||
(viewport->GetVTKWindow() &&
viewport->GetVTKWindow()->GetMTime() > this->BuildTime))
{
// if the viewport has changed we may - or may not need
// to rebuild, it depends on if the projected coords chage
int size[2];
int* barOrigin;
barOrigin = this->PositionCoordinate->GetComputedViewportValue(viewport);
size[0] =
this->Position2Coordinate->GetComputedViewportValue(viewport)[0] -
barOrigin[0];
size[1] =
this->Position2Coordinate->GetComputedViewportValue(viewport)[1] -
barOrigin[1];
// Check if we have bounds on the maximum size
size[0] = size[0] > this->MaximumWidthInPixels
? this->MaximumWidthInPixels : size[0];
size[1] = size[1] > this->MaximumHeightInPixels
? this->MaximumHeightInPixels : size[1];
if (this->LastSize[0] != size[0] ||
this->LastSize[1] != size[1] ||
this->LastOrigin[0] != barOrigin[0] ||
this->LastOrigin[1] != barOrigin[1])
{
positionsHaveChanged = 1;
}
}
// Check to see whether we have to rebuild everything
if (positionsHaveChanged ||
this->GetMTime() > this->BuildTime ||
this->LookupTable->GetMTime() > this->BuildTime ||
this->AnnotationTextProperty->GetMTime() > this->BuildTime ||
this->LabelTextProperty->GetMTime() > this->BuildTime ||
this->TitleTextProperty->GetMTime() > this->BuildTime ||
this->BackgroundProperty->GetMTime() > this->BuildTime ||
this->FrameProperty->GetMTime() > this->BuildTime)
{
this->RebuildLayout(viewport);
}
return 1;
}
//----------------------------------------------------------------------------
int vtkScalarBarActor::RenderOpaqueGeometry(vtkViewport* viewport)
{
if (!this->RebuildLayoutIfNeeded(viewport))
{
return 0;
}
int renderedSomething = 0;
// Everything is built, just have to render
if (this->Title != NULL)
{
renderedSomething +=
this->TitleActor->RenderOpaqueGeometry(viewport);
}
// Draw either the scalar bar (non-indexed mode) or
// the annotated value boxes (indexed mode).
if (!this->LookupTable->GetIndexedLookup())
{
if (this->DrawColorBar)
{
renderedSomething +=
this->ScalarBarActor->RenderOpaqueGeometry(viewport);
}
vtkScalarBarActorInternal::ActorVector::iterator ait;
for (
ait = this->P->TextActors.begin();
ait != this->P->TextActors.end();
++ait)
{
renderedSomething += (*ait)->RenderOpaqueGeometry(viewport);
}
}
else
{
if (this->DrawColorBar)
{
renderedSomething +=
this->P->AnnotationBoxesActor->RenderOpaqueGeometry(viewport);
}
}
if (this->DrawNanAnnotation)
{
renderedSomething +=
this->P->NanSwatchActor->RenderOpaqueGeometry(viewport);
}
if (this->DrawBelowRangeSwatch)
{
renderedSomething +=
this->P->BelowRangeSwatchActor->RenderOpaqueGeometry(viewport);
}
if (this->DrawAboveRangeSwatch)
{
renderedSomething +=
this->P->AboveRangeSwatchActor->RenderOpaqueGeometry(viewport);
}
// Draw the annotation leaders and labels
if (this->DrawAnnotations)
{
if (!this->P->AnnotationLabels.empty())
{
renderedSomething +=
this->P->AnnotationLeadersActor->RenderOpaqueGeometry(viewport);
for (size_t i = 0; i < this->P->AnnotationLabels.size(); ++i)
{
renderedSomething +=
this->P->AnnotationLabels[i]->RenderOpaqueGeometry(viewport);
}
}
}
renderedSomething = (renderedSomething > 0)?(1):(0);
return renderedSomething;
}
//-----------------------------------------------------------------------------
// Description:
// Does this prop have some translucent polygonal geometry?
int vtkScalarBarActor::HasTranslucentPolygonalGeometry()
{ // TODO: Handle case when IndexedLookup is true and any colors in the palette
// have an alpha value, as the color swatches drawn by
// this->P->AnnotationBoxesActor have 1 translucent triangle for each
// alpha-swatch.
return 0;
}
//----------------------------------------------------------------------------
void vtkScalarBarActor::PrintSelf(ostream& os, vtkIndent indent)
{
this->Superclass::PrintSelf(os, indent);
if (this->LookupTable)
{
os << indent << "Lookup Table:\n";
this->LookupTable->PrintSelf(os, indent.GetNextIndent());
}
else
{
os << indent << "Lookup Table: (none)\n";
}
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";
}
if (this->AnnotationTextProperty)
{
os << indent << "Annotation Text Property:\n";
this->AnnotationTextProperty->PrintSelf(os, indent.GetNextIndent());
}
else
{
os << indent << "Annotation Text Property: (none)\n";
}
os << indent << "Title: " << (this->Title ? this->Title : "(none)") << "\n";
os << indent << "ComponentTitle: "
<< (this->ComponentTitle ? this->ComponentTitle : "(none)") << "\n";
os << indent << "Maximum Number Of Colors: "
<< this->MaximumNumberOfColors << "\n";
os << indent << "Number Of Labels: " << this->NumberOfLabels << "\n";
os << indent << "Number Of Labels Built: " << this->NumberOfLabelsBuilt << "\n";
os << indent << "Orientation: ";
if (this->Orientation == VTK_ORIENT_HORIZONTAL)
{
os << "Horizontal\n";
}
else
{
os << "Vertical\n";
}
os << indent << "Label Format: " << this->LabelFormat << "\n";
os << indent << "UseOpacity: " << this->UseOpacity << "\n";
if (this->UseOpacity)
{
os << indent << "TextureGridWidth: " << this->TextureGridWidth << "\n";
os << indent << "TextureActor:\n";
this->TextureActor->PrintSelf(os, indent.GetNextIndent());
}
if (this->TextPosition == vtkScalarBarActor::PrecedeScalarBar)
{
os << indent << "TextPosition: PrecedeScalarBar\n";
}
else
{
os << indent << "TextPosition: SucceedScalarBar\n";
}
os << indent << "MaximumWidthInPixels: "
<< this->MaximumWidthInPixels << endl;
os << indent << "MaximumHeightInPixels: "
<< this->MaximumHeightInPixels << endl;
os << indent << "DrawAnnotations: "
<< this->DrawAnnotations << endl;
os << indent << "DrawNanAnnotation: "
<< this->DrawNanAnnotation << endl;
os << indent << "NanAnnotation: "
<< (this->NanAnnotation ? this->NanAnnotation : "(none)") << endl;
os << indent << "AnnotationLeaderPadding: "
<< this->AnnotationLeaderPadding << endl;
os << indent << "AnnotationTextScaling: "
<< this->AnnotationTextScaling << endl;
os << indent << "VerticalTitleSeparation: "
<< VerticalTitleSeparation << endl;
os << indent << "DrawBelowRangeSwatch: "
<< this->DrawBelowRangeSwatch << endl;
os << indent << "BelowRangeAnnotation: "
<< (this->BelowRangeAnnotation ? this->BelowRangeAnnotation : "(none)") << endl;
os << indent << "DrawAboveRangeSwatch: "
<< this->DrawAboveRangeSwatch << endl;
os << indent << "AboveRangeAnnotation: "
<< (this->AboveRangeAnnotation ? this->AboveRangeAnnotation : "(none)") << endl;
os << indent << "DrawBackground: " << this->DrawBackground << "\n";
os << indent << "Background Property:\n";
this->BackgroundProperty->PrintSelf(os, indent.GetNextIndent());
os << indent << "DrawFrame: " << this->DrawFrame << "\n";
os << indent << "Frame Property:\n";
this->FrameProperty->PrintSelf(os, indent.GetNextIndent());
}
//----------------------------------------------------------------------------
void vtkScalarBarActor::ShallowCopy(vtkProp* prop)
{
vtkScalarBarActor* a = vtkScalarBarActor::SafeDownCast(prop);
if (a != NULL)
{
this->SetPosition2(a->GetPosition2());
this->SetLookupTable(a->GetLookupTable());
this->SetMaximumNumberOfColors(a->GetMaximumNumberOfColors());
this->SetOrientation(a->GetOrientation());
this->SetAnnotationTextProperty(a->GetAnnotationTextProperty());
this->SetLabelTextProperty(a->GetLabelTextProperty());
this->SetTitleTextProperty(a->GetTitleTextProperty());
this->SetLabelFormat(a->GetLabelFormat());
this->SetTitle(a->GetTitle());
this->GetPositionCoordinate()->SetCoordinateSystem(
a->GetPositionCoordinate()->GetCoordinateSystem());
this->GetPositionCoordinate()->SetValue(
a->GetPositionCoordinate()->GetValue());
this->GetPosition2Coordinate()->SetCoordinateSystem(
a->GetPosition2Coordinate()->GetCoordinateSystem());
this->GetPosition2Coordinate()->SetValue(
a->GetPosition2Coordinate()->GetValue());
this->SetDrawBackground(a->GetDrawBackground());
this->SetBackgroundProperty(a->GetBackgroundProperty());
this->SetDrawFrame(a->GetDrawFrame());
this->SetFrameProperty(a->GetFrameProperty());
}
// Now do superclass
this->vtkActor2D::ShallowCopy(prop);
}
//----------------------------------------------------------------------------
void vtkScalarBarActor::RebuildLayout(vtkViewport* viewport)
{
vtkDebugMacro(<< "Rebuilding subobjects");
this->P->Viewport = viewport;
this->FreeLayoutStorage();
// Permute indices used to measure width and height
// so that thickness and length according to the orientation
// of the scalar bar instead.
if (this->Orientation == VTK_ORIENT_VERTICAL)
{
this->P->TL[0] = 0;
this->P->TL[1] = 1;
}
else
{
this->P->TL[0] = 1;
this->P->TL[1] = 0;
}
this->P->NumNotes = this->LookupTable->GetNumberOfAnnotatedValues();
// Warning: The order of these calls is extremely important
// as each updates members of this->P used by later methods!
this->ComputeFrame();
this->ComputeScalarBarThickness();
this->ComputeSwatchPad();
this->LayoutNanSwatch();
this->LayoutBelowRangeSwatch();
this->LayoutAboveRangeSwatch();
this->PrepareTitleText();
this->LayoutTitle();
this->ComputeScalarBarLength();
this->LayoutAboveRangeSwatchPosn();
this->LayoutTicks();
this->LayoutAnnotations();
if (this->UnconstrainedFontSize)
{
this->LayoutForUnconstrainedFont();
}
// Now generate/configure the VTK datasets and actors that
// illustrate the scalar bar when rendered using the
// layout computed above.
this->ConfigureAnnotations();
this->ConfigureFrame();
this->ConfigureScalarBar();
this->ConfigureTitle();
this->ConfigureTicks();
this->ConfigureNanSwatch();
this->ConfigureAboveBelowRangeSwatch(false);
this->ConfigureAboveBelowRangeSwatch(true);
#ifdef VTK_DBG_LAYOUT
this->DrawBoxes();
#endif // VTK_DBG_LAYOUT
this->BuildTime.Modified();
}
namespace
{
void AddBox(vtkPoints* pts, vtkCellArray* lines, vtkScalarBarBox& box, int tl[2])
{
vtkIdType pid[5];
pid[0] = pts->InsertNextPoint(box.Posn[0], box.Posn[1], 0.);
pid[1] = pts->InsertNextPoint(box.Posn[0] + box.Size[tl[0]], box.Posn[1], 0.);
pid[2] = pts->InsertNextPoint(box.Posn[0] + box.Size[tl[0]], box.Posn[1] +
box.Size[tl[1]], 0.);
pid[3] = pts->InsertNextPoint(box.Posn[0], box.Posn[1] + box.Size[tl[1]], 0.);
pid[4] = pid[0];
for (int i = 0; i < 4; ++i)
{
lines->InsertNextCell(2, pid + i);
}
}
}
void vtkScalarBarActor::DrawBoxes()
{
vtkPoints* pts = this->Frame->GetPoints();
vtkCellArray* lines = this->Frame->GetLines();
AddBox(pts, lines, this->P->ScalarBarBox, this->P->TL);
AddBox(pts, lines, this->P->NanBox, this->P->TL);
AddBox(pts, lines, this->P->TitleBox, this->P->TL);
if (this->NumberOfLabels > 0)
{
AddBox(pts, lines, this->P->TickBox, this->P->TL);
}
}
//----------------------------------------------------------------------------
void vtkScalarBarActor::ComputeFrame()
{
// get the viewport size in display coordinates
int* p0;
int* p1;
int size[2];
p0 = this->PositionCoordinate->GetComputedViewportValue(this->P->Viewport);
p1 = this->Position2Coordinate->GetComputedViewportValue(this->P->Viewport);
for (int i = 0; i < 2; ++i)
{
//this->P->Frame.Posn[i] = p0[i];
this->P->Frame.Posn[i] = 0; // Translate the frame's coordinate system to p0
size[i] = p1[i] - p0[i];
}
// Check if we have bounds on the maximum size
size[0] = size[0] > this->MaximumWidthInPixels
? this->MaximumWidthInPixels : size[0];
size[1] = size[1] > this->MaximumHeightInPixels
? this->MaximumHeightInPixels : size[1];
for (int i = 0; i < 2; ++i)
{
this->P->Frame.Size[i] = size[this->P->TL[i]];
}
this->LastOrigin[0] = p0[0];
this->LastOrigin[1] = p0[1];
this->LastSize[0] = size[0];
this->LastSize[1] = size[1];
}
//----------------------------------------------------------------------------
void vtkScalarBarActor::ComputeScalarBarThickness()
{
// We do not set Size[1] (length), since the title bounds may encroach
// on it in the vertical orientation.
this->P->ScalarBarBox.Size[0] =
static_cast<int>(ceil(this->P->Frame.Size[0] * this->BarRatio));
// The lower-left corner of the scalar bar may be estimated here
// as identical to the Frame position in one or both coordinates,
// depending on whether tick marks should precede the scalar bar or
// not and on the orientation.
//
// It will be altered later in this->LayoutTicks to account
// for the half-height/width of tick labels.
this->P->ScalarBarBox.Posn = this->P->Frame.Posn;
if (this->TextPosition == PrecedeScalarBar)
{
this->P->ScalarBarBox.Posn[this->P->TL[0]] +=
this->P->Frame.Size[0] - this->P->ScalarBarBox.Size[0];
}
// Now knock the thickness down and nudge the bar so the bar doesn't hug the frame.
double nudge = this->P->ScalarBarBox.Size[0] / 8.;
if (nudge > this->TextPad)
{
nudge = this->TextPad;
}
this->P->ScalarBarBox.Size[0] =
static_cast<int>(this->P->ScalarBarBox.Size[0] - nudge);
this->P->ScalarBarBox.Posn[this->P->TL[0]] =
static_cast<int>(this->P->ScalarBarBox.Posn[this->P->TL[0]] +
(nudge * (this->TextPosition == PrecedeScalarBar ? -1 : 1)));
}
//----------------------------------------------------------------------------
void vtkScalarBarActor::ComputeSwatchPad()
{
if (this->P->NumNotes)
{
this->P->SwatchPad = this->P->Frame.Size[1] / this->P->NumNotes > 16. ?
4. : (this->P->Frame.Size[1] / this->P->NumNotes / 4.);
}
else
{
this->P->SwatchPad = 4.;
}
}
//----------------------------------------------------------------------------
void vtkScalarBarActor::LayoutNanSwatch()
{
// We don't have ScalarBarBox.Size[1] set yet; use the frame width instead.
this->P->NanSwatchSize = static_cast<double>(
this->P->ScalarBarBox.Size[0] > this->P->Frame.Size[1] / 4 ?
this->P->Frame.Size[1] / 4 : this->P->ScalarBarBox.Size[0]);
if (this->P->NanSwatchSize < 4 && this->P->Frame.Size[1] > 16)
{
this->P->NanSwatchSize = 4;
}
if (!this->DrawNanAnnotation)
{
this->P->NanSwatchSize = 0;
}
if (this->Orientation == VTK_ORIENT_VERTICAL)
{
this->P->NanBox.Posn[0] = this->P->ScalarBarBox.Posn[0];
this->P->NanBox.Posn[1] = this->P->Frame.Posn[1] + this->TextPad;
this->P->ScalarBarBox.Posn[1] = static_cast<int>(this->P->ScalarBarBox.Posn[1] +
(this->P->NanSwatchSize + this->P->SwatchPad));
}
else // HORIZONTAL
{
this->P->NanBox.Posn = this->P->ScalarBarBox.Posn;
this->P->NanBox.Posn[this->P->TL[1]] =
static_cast<int>(this->P->NanBox.Posn[this->P->TL[1]] +
(this->P->Frame.Size[1] - this->P->NanSwatchSize));
}
this->P->NanBox.Size[0] = this->P->ScalarBarBox.Size[0];
this->P->NanBox.Size[1] = static_cast<int>(this->P->NanSwatchSize);
if (this->P->NanBox.Size[1] > 2 * this->TextPad)
{
this->P->NanBox.Size[1] -= this->TextPad;
}
}
//----------------------------------------------------------------------------
void vtkScalarBarActor::LayoutBelowRangeSwatch()
{
// We don't have ScalarBarBox.Size[1] set yet; use the frame width instead.
this->P->BelowRangeSwatchSize = static_cast<double>(
this->P->ScalarBarBox.Size[0] > this->P->Frame.Size[1] / 4 ?
this->P->Frame.Size[1] / 4 : this->P->ScalarBarBox.Size[0]);
if (this->P->BelowRangeSwatchSize < 4 && this->P->Frame.Size[1] > 16)
{
this->P->BelowRangeSwatchSize = 4;
}
if (!this->DrawBelowRangeSwatch)
{
this->P->BelowRangeSwatchSize = 0;
}
if (this->Orientation == VTK_ORIENT_VERTICAL)
{
this->P->BelowRangeSwatchBox.Posn[0] = this->P->ScalarBarBox.Posn[0];
this->P->BelowRangeSwatchBox.Posn[1] = this->P->Frame.Posn[1] + this->TextPad;
// move away because of nan annotation
if (this->DrawNanAnnotation)
{
this->P->BelowRangeSwatchBox.Posn[1] =
static_cast<int>(this->P->BelowRangeSwatchBox.Posn[1] +
(this->P->NanBox.Size[1] + this->P->SwatchPad));
}
this->P->ScalarBarBox.Posn[1] = static_cast<int>(this->P->ScalarBarBox.Posn[1] +
this->P->BelowRangeSwatchSize);
}
else // HORIZONTAL
{
this->P->BelowRangeSwatchBox.Posn = this->P->ScalarBarBox.Posn;
}
this->P->BelowRangeSwatchBox.Size[0] = this->P->ScalarBarBox.Size[0];
this->P->BelowRangeSwatchBox.Size[1] =
static_cast<int>(this->P->BelowRangeSwatchSize);
if (this->P->BelowRangeSwatchBox.Size[1] > 2 * this->TextPad)
{
this->P->BelowRangeSwatchBox.Size[1] -= this->TextPad;
}
}
//----------------------------------------------------------------------------
void vtkScalarBarActor::LayoutAboveRangeSwatch()
{
// We don't have ScalarBarBox.Size[1] set yet; use the frame width instead.
this->P->AboveRangeSwatchSize = static_cast<double>(
this->P->ScalarBarBox.Size[0] > this->P->Frame.Size[1] / 4 ?
this->P->Frame.Size[1] / 4 : this->P->ScalarBarBox.Size[0]);
if (this->P->AboveRangeSwatchSize < 4 && this->P->Frame.Size[1] > 16)
{
this->P->AboveRangeSwatchSize = 4;
}
if (!this->DrawAboveRangeSwatch)
{
this->P->AboveRangeSwatchSize = 0;
}
}
//----------------------------------------------------------------------------
void vtkScalarBarActor::LayoutAboveRangeSwatchPosn()
{
if (this->Orientation == VTK_ORIENT_VERTICAL)
{
this->P->AboveRangeSwatchBox.Posn[0] = this->P->ScalarBarBox.Posn[0];
this->P->AboveRangeSwatchBox.Posn[1] =
this->P->Frame.Posn[1] + this->TextPad + this->P->ScalarBarBox.Size[1] +
this->P->SwatchPad;
if (this->DrawNanAnnotation)
{
this->P->AboveRangeSwatchBox.Posn[1] =
static_cast<int>(this->P->AboveRangeSwatchBox.Posn[1] +
this->P->SwatchPad +
this->P->NanBox.Size[1]);
}
if (this->DrawBelowRangeSwatch)
{
this->P->AboveRangeSwatchBox.Posn[1] =
static_cast<int>(this->P->AboveRangeSwatchBox.Posn[1] +
this->P->SwatchPad +
this->P->BelowRangeSwatchBox.Size[1]);
}
}
else // HORIZONTAL
{
this->P->AboveRangeSwatchBox.Posn = this->P->ScalarBarBox.Posn;
this->P->AboveRangeSwatchBox.Posn[this->P->TL[1]] =
static_cast<int>(this->P->AboveRangeSwatchBox.Posn[this->P->TL[1]] +
(this->P->Frame.Size[1] - this->P->AboveRangeSwatchSize));
if (this->DrawNanAnnotation)
{
this->P->AboveRangeSwatchBox.Posn[this->P->TL[1]] =
static_cast<int>(this->P->AboveRangeSwatchBox.Posn[this->P->TL[1]] -
(this->P->NanBox.Size[this->P->TL[1]] + this->P->SwatchPad));
}
}
this->P->AboveRangeSwatchBox.Size[0] = this->P->ScalarBarBox.Size[0];
this->P->AboveRangeSwatchBox.Size[1] =
static_cast<int>(this->P->AboveRangeSwatchSize);
if (this->P->AboveRangeSwatchBox.Size[1] > 2 * this->TextPad)
{
this->P->AboveRangeSwatchBox.Size[1] -= this->TextPad;
}
}
//----------------------------------------------------------------------------
void vtkScalarBarActor::PrepareTitleText()
{
// Update actor with the latest title/subtitle
if (this->ComponentTitle && strlen(this->ComponentTitle) > 0)
{
//need to account for a space between title & component and null term
char* combinedTitle =
new char[strlen(this->Title) + strlen(this->ComponentTitle) + 2];
strcpy(combinedTitle, this->Title);
strcat(combinedTitle, " ");
strcat(combinedTitle, this->ComponentTitle);
this->TitleActor->SetInput(combinedTitle);
delete [] combinedTitle;
}
else
{
this->TitleActor->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->TitleActor->GetTextProperty()->ShallowCopy(this->TitleTextProperty);
this->TitleActor->GetTextProperty()->SetJustificationToCentered();
this->TitleActor->GetTextProperty()->SetVerticalJustification(
this->TextPosition == PrecedeScalarBar ? VTK_TEXT_BOTTOM : VTK_TEXT_TOP);
}
}
//----------------------------------------------------------------------------
void vtkScalarBarActor::LayoutTitle()
{
if (this->Title == NULL || !strlen(this->Title))
{
this->P->TitleBox.Posn = vtkTuple<int, 2>(0.);
this->P->TitleBox.Size = vtkTuple<int, 2>(0.);
return;
}
int targetWidth, targetHeight;
// Title spans entire width of frame at top, regardless of orientation.
targetWidth = static_cast<int>(this->P->Frame.Size[this->P->TL[0]]) - 2 *
this->TextPad;
// Height is either: at most half the frame height or
// a fixed portion of the frame remaining after subtracting the
// scalar bar's thickness.
//
// When laid out horizontally, ticks share vertical space with title.
// We want the title to be larger (18pt vs 14pt).
targetHeight = static_cast<int>((
this->Orientation == VTK_ORIENT_VERTICAL ||
this->LookupTable->GetIndexedLookup()) ?
ceil(this->P->Frame.Size[this->P->TL[1]] / 2. - this->TextPad) :
(this->P->Frame.Size[0] - this->P->ScalarBarBox.Size[0] -
(this->TextPosition == SucceedScalarBar ?
this->P->ScalarBarBox.Posn[this->P->TL[0]] : 0) - this->TextPad) *
this->TitleRatio);
if (this->UnconstrainedFontSize)
{
this->TitleActor->GetTextProperty()->SetFontSize(
this->TitleTextProperty->GetFontSize());
}
else
{
this->TitleActor->SetConstrainedFontSize(
this->P->Viewport, targetWidth, targetHeight);
}
// Now fetch the actual size from the actor and use it to
// update the box size and position.
double titleSize[2] = {0, 0};
this->TitleActor->GetSize(this->P->Viewport, titleSize);
this->TitleActor->GetTextProperty()->SetVerticalJustificationToTop();
for (int i = 0; i < 2; ++i)
{
this->P->TitleBox.Size[this->P->TL[i]] =
static_cast<int>(ceil(titleSize[i]));
}
this->P->TitleBox.Posn[0] =
this->P->Frame.Posn[0] +
(this->P->Frame.Size[this->P->TL[0]] - titleSize[0]) / 2;
this->P->TitleBox.Posn[1] =
static_cast<int>(this->P->Frame.Posn[1] + this->P->Frame.Size[this->P->TL[1]]);
if (
this->Orientation == VTK_ORIENT_VERTICAL ||
this->TextPosition == vtkScalarBarActor::SucceedScalarBar)
{
this->P->TitleBox.Posn[1] -= this->P->TitleBox.Size[this->P->TL[1]] +
this->TextPad + static_cast<int>(this->FrameProperty->GetLineWidth());
}
else
{
this->P->TitleBox.Posn[1] = this->P->Frame.Posn[1] + this->TextPad -
static_cast<int>(this->FrameProperty->GetLineWidth());
}
}
//-----------------------------------------------------------------------------
void vtkScalarBarActor::ComputeScalarBarLength()
{
this->P->ScalarBarBox.Size[1] =
this->Orientation == VTK_ORIENT_VERTICAL ?
this->P->Frame.Size[1] - this->P->TitleBox.Size[1] -
this->VerticalTitleSeparation :
this->P->Frame.Size[1];
// The scalar bar does not include the Nan Swatch, the Below Range Swatch and
// the Above Range Swatch.
this->P->ScalarBarBox.Size[1] = static_cast<int>(this->P->ScalarBarBox.Size[1] -
(this->P->NanSwatchSize + this->P->SwatchPad));
// Correct Swatch behevior while keeping compat with images from tests
if (this->P->BelowRangeSwatchSize > 0)
{
this->P->ScalarBarBox.Size[1] -=
this->P->BelowRangeSwatchSize + this->P->SwatchPad;
}
if (this->P->AboveRangeSwatchSize > 0)
{
this->P->ScalarBarBox.Size[1] -= this->P->AboveRangeSwatchSize;
if (this->P->NanSwatchSize > 0)
{
this->P->ScalarBarBox.Size[1] -= this->P->SwatchPad;
}
}
}
//-----------------------------------------------------------------------------
void vtkScalarBarActor::LayoutTicks()
{
if (this->LookupTable->GetIndexedLookup())
{ // no tick marks in indexed lookup mode.
this->NumberOfLabelsBuilt = 0;
return;
}
// find the best size for the ticks
const double* range = this->LookupTable->GetRange();
char string[512];
double val;
int i;
// TODO: this should be optimized, maybe by keeping a list of
// allocated mappers, in order to avoid creation/destruction of
// their underlying text properties (i.e. each time a mapper is
// created, text properties are created and shallow-assigned a font size
// which value might be "far" from the target font size).
this->P->TextActors.resize(this->NumberOfLabels);
// Does this map have its scale set to log?
int isLogTable = this->LookupTable->UsingLogScale();
for (i = 0; i < this->NumberOfLabels; i++)
{
this->P->TextActors[i].TakeReference(vtkTextActor::New());
if (isLogTable)
{
double lval;
if (this->NumberOfLabels > 1)
{
lval = log10(range[0]) +
static_cast<double>(i) / (this->NumberOfLabels - 1) *
(log10(range[1]) - log10(range[0]));
}
else
{
lval = log10(range[0]) + 0.5 * (log10(range[1]) - log10(range[0]));
}
val = pow(10.0, lval);
}
else
{
if (this->NumberOfLabels > 1)
{
val = range[0] +
static_cast<double>(i) / (this->NumberOfLabels - 1)
* (range[1] - range[0]);
}
else
{
val = range[0] + 0.5 * (range[1] - range[0]);
}
}
snprintf(string, 511, this->LabelFormat, val);
this->P->TextActors[i]->SetInput(string);
// 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->P->TextActors[i]->GetTextProperty()->ShallowCopy(
this->LabelTextProperty);
this->P->TextActors[i]->SetProperty(this->GetProperty());
this->P->TextActors[i]->GetPositionCoordinate()->
SetReferenceCoordinate(this->PositionCoordinate);
}
if (this->NumberOfLabels)
{
int labelSize[2];
labelSize[0] = labelSize[1] = 0;
int targetWidth, targetHeight;
this->P->TickBox.Posn = this->P->ScalarBarBox.Posn;
if (this->Orientation == VTK_ORIENT_VERTICAL)
{ // NB. Size[0] = width, Size[1] = height
// Ticks share the width with the scalar bar
this->P->TickBox.Size[0] =
this->P->Frame.Size[0] - this->P->ScalarBarBox.Size[0] -
this->TextPad * 3;
// Tick height could be adjusted if title text is
// lowered by box constraints, but we won't bother:
this->P->TickBox.Size[1] = this->P->Frame.Size[1] -
this->P->TitleBox.Size[1] - 3 * this->TextPad -
this->VerticalTitleSeparation;
// Tick box height also reduced by NaN swatch size, if present:
if (this->DrawNanAnnotation)
{
this->P->TickBox.Size[1] = static_cast<int>(this->P->TickBox.Size[1] -
(this->P->NanBox.Size[1] + this->P->SwatchPad));
}
if (this->DrawBelowRangeSwatch)
{
this->P->TickBox.Size[1] = static_cast<int>(this->P->TickBox.Size[1] -
(this->P->BelowRangeSwatchBox.Size[1] + this->P->SwatchPad));
}
if (this->DrawAboveRangeSwatch)
{
this->P->TickBox.Size[1] = static_cast<int>(this->P->TickBox.Size[1] -
(this->P->AboveRangeSwatchBox.Size[1] + this->P->SwatchPad));
}
if (this->TextPosition == vtkScalarBarActor::PrecedeScalarBar)
{
this->P->TickBox.Posn[0] = this->TextPad;
}
else
{
this->P->TickBox.Posn[0] += this->P->ScalarBarBox.Size[0] + 2 *
this->TextPad;
}
targetWidth = this->P->TickBox.Size[0];
targetHeight = static_cast<int>((this->P->TickBox.Size[1] -
this->TextPad * (this->NumberOfLabels - 1)) /
this->NumberOfLabels);
}
else
{ // NB. Size[1] = width, Size[0] = height
// Ticks span the entire width of the frame
this->P->TickBox.Size[1] = this->P->ScalarBarBox.Size[1];
// Ticks share vertical space with title and scalar bar.
this->P->TickBox.Size[0] =
this->P->Frame.Size[0] - this->P->ScalarBarBox.Size[0] -
4 * this->TextPad - this->P->TitleBox.Size[0];
if (this->TextPosition == vtkScalarBarActor::PrecedeScalarBar)
{
this->P->TickBox.Posn[1] =
this->P->TitleBox.Size[0] + 2 * this->TextPad + this->P->TitleBox.Posn[1];
}
else
{
this->P->TickBox.Posn[1] += this->P->ScalarBarBox.Size[0];
}
targetWidth = static_cast<int>((this->P->TickBox.Size[1] -
this->TextPad * (this->NumberOfLabels - 1)) /
this->NumberOfLabels);
targetHeight = this->P->TickBox.Size[0];
}
if (!this->UnconstrainedFontSize)
{
vtkTextActor::SetMultipleConstrainedFontSize(
this->P->Viewport, targetWidth, targetHeight,
this->P->TextActors.PointerArray(), this->NumberOfLabels,
labelSize);
}
// Now adjust scalar bar size by the half-size of the first and last ticks
this->P->ScalarBarBox.Posn[this->P->TL[1]]
+= labelSize[this->P->TL[1]] / 2.;
this->P->ScalarBarBox.Size[1] -= labelSize[this->P->TL[1]];
this->P->TickBox.Posn[this->P->TL[1]] =
static_cast<int>(this->P->TickBox.Posn[this->P->TL[1]] +
(labelSize[this->P->TL[1]] / 2.));
this->P->TickBox.Size[1] -= labelSize[this->P->TL[1]];
if (this->Orientation == VTK_ORIENT_HORIZONTAL)
{
this->P->ScalarBarBox.Posn[0] += this->P->BelowRangeSwatchSize;
this->P->TickBox.Posn[0] += this->P->BelowRangeSwatchSize;
this->P->TickBox.Posn[1] += this->TextPad *
(this->TextPosition == PrecedeScalarBar ? -1 : 1);
this->P->TickBox.Size[1] -= this->TextPad;
}
}
this->NumberOfLabelsBuilt = this->NumberOfLabels;
}
//-----------------------------------------------------------------------------
void vtkScalarBarActor::LayoutForUnconstrainedFont()
{
if (this->UnconstrainedFontSize)
{
// recompute tickbox layout max sizes
int labelWidth = 0;
int labelHeight = 0;
double fontSize[2] = {0, 0};
for (size_t i = 0; i < this->P->TextActors.size(); ++i)
{
this->P->TextActors.at(i)->GetSize(this->P->Viewport, fontSize);
if (fontSize[0] > labelWidth)
{
labelWidth = fontSize[0];
}
if (fontSize[1] > labelHeight)
{
labelHeight = fontSize[1];
}
}
if (this->Orientation == VTK_ORIENT_VERTICAL)
{
this->P->TitleBox.Posn[1] += labelHeight * 0.75;
this->P->TickBox.Size[0] = labelWidth;
if (this->TextPosition == vtkScalarBarActor::PrecedeScalarBar)
{
this->P->TickBox.Posn[0] =
-labelWidth + this->P->Frame.Size[0] - this->P->ScalarBarBox.Size[0] -
(labelWidth * 0.05);
}
}
else
{
if (this->TextPosition == vtkScalarBarActor::PrecedeScalarBar)
{
this->P->TitleBox.Posn[1] =
this->P->Frame.Posn[1] + this->P->ScalarBarBox.Posn[1] -
this->P->TitleBox.Size[this->P->TL[1]] - labelHeight;
}
else
{
this->P->TitleBox.Posn[1] =
this->P->Frame.Posn[1] +
this->P->ScalarBarBox.Size[this->P->TL[1]] + labelHeight;
}
}
}
}
//----------------------------------------------------------------------------
void vtkScalarBarActor::LayoutAnnotations()
{
if (this->DrawAnnotations)
{
const double* range = this->LookupTable->GetRange();
this->MapAnnotationLabels(
this->LookupTable, this->P->ScalarBarBox.Posn[this->P->TL[1]],
this->P->ScalarBarBox.Size[1], range);
}
}
//----------------------------------------------------------------------------
void vtkScalarBarActor::ConfigureFrame()
{
// set frame structure
vtkPoints* frPts = vtkPoints::New();
frPts->SetNumberOfPoints(5);
vtkCellArray* frLines = vtkCellArray::New();
frLines->Allocate(frLines->EstimateSize(1, 5));
this->FrameActor->SetProperty(this->FrameProperty);
this->Frame->Initialize();
this->Frame->SetPoints(frPts);
this->Frame->SetLines(frLines);
frPts->Delete();
frLines->Delete();
// set background structure
vtkPoints* bgPts = vtkPoints::New();
bgPts->SetNumberOfPoints(4);
vtkCellArray* bgPolys = vtkCellArray::New();
bgPolys->Allocate(bgPolys->EstimateSize(1, 4));
this->BackgroundActor->SetProperty(this->BackgroundProperty);
this->Background->Initialize();
this->Background->SetPoints(bgPts);
this->Background->SetPolys(bgPolys);
bgPts->Delete();
bgPolys->Delete();
double x[3];
x[2] = 0.;
// generate background and frame points and cell
x[0] = 0;
x[1] = 0;
bgPts->SetPoint(0, x);
frPts->SetPoint(0, x);
frPts->SetPoint(4, x);
x[0] = 0;
x[1] = this->P->Frame.Size[this->P->TL[1]] - 0.5;
bgPts->SetPoint(1, x);
frPts->SetPoint(1, x);
x[0] = this->P->Frame.Size[this->P->TL[0]] - 0.5;
x[1] = this->P->Frame.Size[this->P->TL[1]] - 0.5;
bgPts->SetPoint(2, x);
frPts->SetPoint(2, x);
x[0] = this->P->Frame.Size[this->P->TL[0]] - 0.5;
x[1] = 0;
bgPts->SetPoint(3, x);
frPts->SetPoint(3, x);
vtkIdType bgIds[5] = {0, 1, 2, 3, 4};
bgPolys->InsertNextCell(4, bgIds);
frLines->InsertNextCell(5, bgIds);
}
//----------------------------------------------------------------------------
void vtkScalarBarActor::ConfigureScalarBar()
{
vtkScalarsToColors* lut = this->LookupTable;
const double* range = lut->GetRange();
this->P->NumColors = lut->GetIndexedLookup() ?
lut->GetNumberOfAnnotatedValues() : this->MaximumNumberOfColors;
this->P->NumSwatches = this->P->NumColors + (this->DrawNanAnnotation ? 1 : 0);
int numPts = 2 * (this->P->NumColors + 1) + (this->DrawNanAnnotation ? 4 : 0);
this->P->NumSwatches = this->P->NumColors + (this->DrawBelowRangeSwatch ? 1 : 0);
numPts += (this->DrawBelowRangeSwatch ? 4 : 0);
this->P->SwatchPts = vtkPoints::New();
this->P->SwatchPts->SetNumberOfPoints(numPts);
this->P->Polys = vtkCellArray::New();
this->P->Polys->Allocate(
this->P->Polys->EstimateSize(this->P->NumSwatches, 4));
this->P->SwatchColors = vtkUnsignedCharArray::New();
unsigned int nComponents = ((this->UseOpacity) ? 4 : 3);
this->P->SwatchColors->SetNumberOfComponents(nComponents);
this->P->SwatchColors->SetNumberOfTuples(this->P->NumSwatches);
this->ScalarBarActor->SetProperty(this->GetProperty());
this->ScalarBar->Initialize();
this->ScalarBar->SetPoints(this->P->SwatchPts);
this->ScalarBar->SetPolys(this->P->Polys);
this->ScalarBar->GetCellData()->SetScalars(this->P->SwatchColors);
this->P->SwatchPts->Delete();
this->P->Polys->Delete();
this->P->SwatchColors->Delete();
double delta =
static_cast<double>(this->P->ScalarBarBox.Size[1]) / this->P->NumColors;
double x[3];
x[2] = 0.;
for (int i = 0; i < numPts / 2 - (this->DrawNanAnnotation ? 2 : 0) -
(this->DrawBelowRangeSwatch ? 2 : 0) ; ++i)
{
x[this->P->TL[0]] = this->P->ScalarBarBox.Posn[this->P->TL[0]];
x[this->P->TL[1]] = this->P->ScalarBarBox.Posn[this->P->TL[1]] + i * delta;
this->P->SwatchPts->SetPoint(2 * i, x);
x[this->P->TL[0]] = this->P->ScalarBarBox.Posn[this->P->TL[0]] +
this->P->ScalarBarBox.Size[0];
this->P->SwatchPts->SetPoint(2 * i + 1, x);
}
//polygons & cell colors
unsigned char* rgb;
double rgba[4];
vtkIdType ptIds[4];
for (int i = 0; i < this->P->NumColors; ++i)
{
ptIds[0] = 2 * i;
ptIds[1] = ptIds[0] + 1;
ptIds[2] = ptIds[1] + 2;
ptIds[3] = ptIds[0] + 2;
this->P->Polys->InsertNextCell(4, ptIds);
double rgbval;
if (this->LookupTable->UsingLogScale())
{
rgbval = log10(range[0]) +
i * (log10(range[1]) - log10(range[0])) / this->P->NumColors;
rgbval = pow(10.0, rgbval);
}
else
{
rgbval = range[0] + (range[1] - range[0]) *
(i / static_cast<double>(this->P->NumColors));
}
lut->GetColor(rgbval, rgba);
rgba[3] = lut->GetOpacity(rgbval);
//write into array directly
rgb = this->P->SwatchColors->GetPointer(nComponents * i);
rgb[0] = static_cast<unsigned char>(rgba[0] * 255.);
rgb[1] = static_cast<unsigned char>(rgba[1] * 255.);
rgb[2] = static_cast<unsigned char>(rgba[2] * 255.);
if (this->P->SwatchColors->GetNumberOfComponents() > 3)
{
rgb[3] = static_cast<unsigned char>(this->UseOpacity ? rgba[3] * 255. : 255.);
}
}
// Set up a texture actor as an alternative to the 1-quad-per-color
// scalar bar polydata.
vtkPoints* texturePoints = vtkPoints::New();
texturePoints->SetNumberOfPoints(4);
this->TexturePolyData->SetPoints(texturePoints);
texturePoints->SetPoint(0, 0.0, 0.0, 0.0);
double p1[2], p2[2];
p1[0] = this->P->ScalarBarBox.Posn[0];
p1[1] = this->P->ScalarBarBox.Posn[1];
p2[0] = p1[0] + this->P->ScalarBarBox.Size[this->P->TL[0]];
p2[1] = p1[1] + this->P->ScalarBarBox.Size[this->P->TL[1]];
texturePoints->SetPoint(0, p1[0], p1[1], 0.0);
texturePoints->SetPoint(1, p2[0], p1[1], 0.0);
texturePoints->SetPoint(2, p2[0], p2[1], 0.0);
texturePoints->SetPoint(3, p1[0], p2[1], 0.0);
texturePoints->Delete();
double barWidth = this->P->ScalarBarBox.Size[this->P->TL[0]];
double barHeight = this->P->ScalarBarBox.Size[this->P->TL[1]];
vtkDataArray* tc = this->TexturePolyData->GetPointData()->GetTCoords();
tc->SetTuple2(1, barWidth / this->TextureGridWidth, 0.0);
tc->SetTuple2(2, barWidth / this->TextureGridWidth,
barHeight / this->TextureGridWidth);
tc->SetTuple2(3, 0.0, barHeight / this->TextureGridWidth);
}
//----------------------------------------------------------------------------
void vtkScalarBarActor::ConfigureTitle()
{
this->TitleActor->SetPosition(
this->P->TitleBox.Posn[0] + this->P->TitleBox.Size[this->P->TL[0]] / 2,
this->TitleActor->GetTextProperty()->GetVerticalJustification() ==
VTK_TEXT_BOTTOM ?
this->P->TitleBox.Posn[1]:
this->P->TitleBox.Posn[1] + this->P->TitleBox.Size[this->P->TL[1]]);
}
//-----------------------------------------------------------------------------
void vtkScalarBarActor::ConfigureTicks()
{
double val;
double sizeTextData[2];
for (int i = 0; i < this->NumberOfLabelsBuilt; ++i)
{
val = (this->NumberOfLabelsBuilt > 1 ?
static_cast<double>(i) / (this->NumberOfLabelsBuilt - 1) : 0.5) *
this->P->TickBox.Size[1] + this->P->TickBox.Posn[this->P->TL[1]];
this->P->TextActors[i]->GetSize(this->P->Viewport, sizeTextData);
if (this->Orientation == VTK_ORIENT_VERTICAL)
{ // VERTICAL
this->P->TextActors[i]->GetTextProperty()->SetJustification(
this->TextPosition == PrecedeScalarBar ? VTK_TEXT_RIGHT : VTK_TEXT_LEFT);
this->P->TextActors[i]->GetTextProperty()
->SetVerticalJustificationToBottom();
this->P->TextActors[i]->SetPosition(
this->TextPosition == vtkScalarBarActor::PrecedeScalarBar ?
this->P->TickBox.Posn[0] + this->P->TickBox.Size[0] :
this->P->TickBox.Posn[0],
//this->P->TickBox.Posn[0],
val - 0.5 * sizeTextData[1]);
}
else
{ // HORIZONTAL
this->P->TextActors[i]->GetTextProperty()->SetJustificationToCentered();
this->P->TextActors[i]->GetTextProperty()->SetVerticalJustification(
this->TextPosition == PrecedeScalarBar ? VTK_TEXT_TOP : VTK_TEXT_BOTTOM);
this->P->TextActors[i]->SetPosition(val,
this->TextPosition == PrecedeScalarBar ?
this->P->TickBox.Posn[1] + this->P->TickBox.Size[0] :
this->P->TickBox.Posn[1]);
}
}
}
//-----------------------------------------------------------------------------
void vtkScalarBarActor::ConfigureNanSwatch()
{
if (!this->DrawNanAnnotation)
{
return;
}
int numPts = 4;
vtkPoints* pts = vtkPoints::New();
pts->SetNumberOfPoints(numPts);
vtkCellArray* polys = vtkCellArray::New();
polys->Allocate(polys->EstimateSize(1, 4));
vtkUnsignedCharArray* colors = vtkUnsignedCharArray::New();
colors->SetNumberOfComponents(4); // RGBA
colors->SetNumberOfTuples(1);
this->P->NanSwatch->Initialize();
this->P->NanSwatch->SetPoints(pts);
this->P->NanSwatch->SetPolys(polys);
this->P->NanSwatch->GetCellData()->SetScalars(colors);
pts->Delete();
polys->Delete();
colors->Delete();
double x[3];
x[2] = 0.;
for (int j = 0; j < 2; ++j)
{
x[j] = this->P->NanBox.Posn[j];
}
int i = 0;
pts->SetPoint(i++, x);
x[0] += this->P->NanBox.Size[this->P->TL[0]];
pts->SetPoint(i++, x);
x[1] += this->P->NanBox.Size[this->P->TL[1]];
pts->SetPoint(i++, x);
x[0] -= this->P->NanBox.Size[this->P->TL[0]];
pts->SetPoint(i++, x);
// Add the swatch to the polydata and color it:
unsigned char* rgb;
double rgba[4];
vtkIdType ptIds[4];
ptIds[0] = 0;
ptIds[1] = 1;
ptIds[2] = 2;
ptIds[3] = 3;
polys->InsertNextCell(4, ptIds);
this->LookupTable->GetIndexedColor(-1, rgba);
rgb = colors->GetPointer(0); //write into array directly
rgb[0] = static_cast<unsigned char>(rgba[0] * 255.);
rgb[1] = static_cast<unsigned char>(rgba[1] * 255.);
rgb[2] = static_cast<unsigned char>(rgba[2] * 255.);
rgb[3] = static_cast<unsigned char>(this->UseOpacity ? rgba[3] * 255. : 255.);
}
//----------------------------------------------------------------------------
void vtkScalarBarActor::ConfigureAboveBelowRangeSwatch(bool above)
{
// Check above/below
vtkPolyData* swatch;
vtkScalarBarBox* box;
if (above)
{
if (!this->DrawAboveRangeSwatch)
{
return;
}
swatch = this->P->AboveRangeSwatch;
box = &this->P->AboveRangeSwatchBox;
}
else
{
if (!this->DrawBelowRangeSwatch)
{
return;
}
swatch = this->P->BelowRangeSwatch;
box = &this->P->BelowRangeSwatchBox;
}
int numPts = 4;
vtkNew<vtkPoints> pts;
pts->SetNumberOfPoints(numPts);
vtkNew<vtkCellArray> polys;
polys->Allocate(polys->EstimateSize(1, 4));
vtkNew<vtkUnsignedCharArray> colors;
colors->SetNumberOfComponents(4); // RGBA
colors->SetNumberOfTuples(1);
swatch->Initialize();
swatch->SetPoints(pts.Get());
swatch->SetPolys(polys.Get());
swatch->GetCellData()->SetScalars(colors.Get());
double x[3];
x[2] = 0.;
for (int j = 0; j < 2; ++j)
{
x[j] = box->Posn[j];
}
int i = 0;
pts->SetPoint(i++, x);
x[0] += box->Size[this->P->TL[0]];
pts->SetPoint(i++, x);
x[1] += box->Size[this->P->TL[1]];
pts->SetPoint(i++, x);
x[0] -= box->Size[this->P->TL[0]];
pts->SetPoint(i++, x);
// Add the swatch to the polydata and color it:
double rgba[4] = { 1.0, 1.0, 1.0, 1.0 };
vtkIdType ptIds[4] = { 0, 1, 2, 3};
polys->InsertNextCell(4, ptIds);
this->LookupTable->GetIndexedColor(-1, rgba);
vtkLookupTable* lt = vtkLookupTable::SafeDownCast(this->LookupTable);
vtkColorTransferFunction* ctf =
vtkColorTransferFunction::SafeDownCast(this->LookupTable);
if (lt)
{
if (above)
{
lt->GetAboveRangeColor(rgba);
}
else
{
lt->GetBelowRangeColor(rgba);
}
}
else if (ctf)
{
if (above)
{
ctf->GetAboveRangeColor(rgba);
}
else
{
ctf->GetBelowRangeColor(rgba);
}
}
unsigned char* rgb = colors->GetPointer(0); //write into array directly
rgb[0] = static_cast<unsigned char>(rgba[0] * 255.);
rgb[1] = static_cast<unsigned char>(rgba[1] * 255.);
rgb[2] = static_cast<unsigned char>(rgba[2] * 255.);
rgb[3] = static_cast<unsigned char>(this->UseOpacity ? rgba[3] * 255. : 255.);
}
//----------------------------------------------------------------------------
void vtkScalarBarActor::ConfigureAnnotations()
{
// I. Create an actor for each valid label.
int numNotes = static_cast<int>(this->P->Labels.size());
if (!numNotes)
{
return;
}
this->P->AnnotationLabels.resize(numNotes);
this->P->AnnotationAnchors.resize(numNotes);
this->P->AnnotationColors.resize(numNotes);
int i = 0;
std::map<double, vtkStdString>::iterator it;
for (it = this->P->Labels.begin(); it != this->P->Labels.end(); ++it, ++i)
{
this->P->AnnotationAnchors[i] = it->first;
this->P->AnnotationColors[i] = this->P->LabelColors[it->first];
this->P->AnnotationLabels[i] = vtkSmartPointer<vtkTextActor>::New();
if (this->P->Viewport && this->AnnotationTextScaling)
{
this->P->AnnotationLabels[i]->SetTextScaleModeToViewport();
this->P->AnnotationLabels[i]->ComputeScaledFont(this->P->Viewport);
}
this->P->AnnotationLabels[i]->GetTextProperty()->ShallowCopy(
this->AnnotationTextProperty);
this->P->AnnotationLabels[i]->SetProperty(this->GetProperty());
// NB: If passed an empty string, pass a single space to the renderer;
// empty strings get rendered as blobs which is Highly Undesirable.
// Also render an empty string if the annotation can't be placed on the bar.
this->P->AnnotationLabels[i]->SetInput(it->second.c_str());
this->P->AnnotationLabels[i]->GetPositionCoordinate()->
SetReferenceCoordinate(this->PositionCoordinate);
}
// Position each label and, in indexed mode, create the color swatches.
if (this->LookupTable->GetIndexedLookup())
{
int indexedDenom = this->P->NumNotes;
// Must reset the color on the leader lines since vtkTextProperty
// doesn't inherit vtkProperty.
// FIXME: Only set leader color when CellData scalars aren't used.
this->P->AnnotationLeadersActor->GetProperty()->SetColor(
this->AnnotationTextProperty->GetColor());
this->P->AnnotationLeadersActor->GetProperty()->SetOpacity(
this->AnnotationTextProperty->GetOpacity());
// this->ScalarBar will not be drawn; instead, draw padded boxes
// and leaders to labels for each annotated value.
// Since labels are user-provided, we render with vtkTextActor
// to allow fancy-ness.
// 2 triangles per annotation: half-opaque, half-translucent:
int numPts = 4 * indexedDenom;
vtkPoints* pts = vtkPoints::New();
pts->SetNumberOfPoints(numPts);
vtkCellArray* polys = vtkCellArray::New();
polys->Allocate(polys->EstimateSize(2 * indexedDenom, 3));
vtkUnsignedCharArray* colors = vtkUnsignedCharArray::New();
colors->SetNumberOfComponents(4); // RGBA
colors->SetNumberOfTuples(2 * indexedDenom);
this->P->AnnotationBoxes->Initialize();
this->P->AnnotationBoxes->SetPoints(pts);
this->P->AnnotationBoxes->SetPolys(polys);
this->P->AnnotationBoxes->GetCellData()->SetScalars(colors);
//this->P->AnnotationBoxes->SetProperty( this->GetProperty() );
pts->Delete();
polys->Delete();
colors->Delete();
// Use the nicely-provided scalar bar position to place
// the annotated value swatches.
double swatchC0, swatchC1; // fixed swatch coordinates
double delta =
static_cast<double>(this->P->ScalarBarBox.Size[1]) / indexedDenom;
double x[3];
x[2] = 0.;
unsigned char* rgb;
vtkIdType ptIds[4];
swatchC0 = this->P->ScalarBarBox.Posn[this->P->TL[0]];
swatchC1 = swatchC0 + this->P->ScalarBarBox.Size[0];
if (this->Orientation == VTK_ORIENT_VERTICAL)
{
this->PlaceAnnotationsVertically(
this->TextPosition == vtkScalarBarActor::SucceedScalarBar ?
swatchC0 : swatchC1,
this->P->ScalarBarBox.Posn[1],
this->P->ScalarBarBox.Size[this->P->TL[0]],
this->P->ScalarBarBox.Size[this->P->TL[1]],
delta, this->P->SwatchPad);
double top =
this->P->ScalarBarBox.Posn[1] +
this->P->ScalarBarBox.Size[this->P->TL[1]];
for (i = 0; i < indexedDenom; ++i)
{
x[0] = swatchC0;
x[1] = top - i * delta - this->P->SwatchPad;
pts->SetPoint(4 * i, x);
x[0] = swatchC1;
pts->SetPoint(4 * i + 1, x);
x[1] -= delta - this->P->SwatchPad * 2;
pts->SetPoint(4 * i + 2, x);
x[0] = swatchC0;
pts->SetPoint(4 * i + 3, x);
}
}
else
{
this->PlaceAnnotationsHorizontally(
this->P->ScalarBarBox.Posn[0], swatchC1,
this->P->ScalarBarBox.Size[1],
this->P->ScalarBarBox.Size[0], delta, this->P->SwatchPad);
for (i = 0; i < indexedDenom; ++i)
{
x[0] = this->P->ScalarBarBox.Posn[0] + i * delta + this->P->SwatchPad;
x[1] = swatchC0;
pts->SetPoint(4 * i, x);
x[0] += delta - this->P->SwatchPad * 2;
pts->SetPoint(4 * i + 1, x);
x[1] = swatchC1;
pts->SetPoint(4 * i + 2, x);
x[0] -= delta - this->P->SwatchPad * 2;
pts->SetPoint(4 * i + 3, x);
}
}
for (i = 0; i < indexedDenom; ++i)
{
ptIds[0] = 4 * i;
ptIds[1] = ptIds[0] + 1;
ptIds[2] = ptIds[0] + 2;
polys->InsertNextCell(3, ptIds);
ptIds[1] = ptIds[2];
ptIds[2] = ptIds[0] + 3;
polys->InsertNextCell(3, ptIds);
double rgbaF[4];
this->LookupTable->GetIndexedColor(
i == this->P->NumNotes ?
-1 :
i % this->LookupTable->GetNumberOfAvailableColors(),
rgbaF);
rgb = colors->GetPointer(
/* numComponents */ 4 *
/* numCells/swatch */ 2 *
/* swatch */ i); //write into array directly
rgb[0] = static_cast<unsigned char>(rgbaF[0] * 255.);
rgb[1] = static_cast<unsigned char>(rgbaF[1] * 255.);
rgb[2] = static_cast<unsigned char>(rgbaF[2] * 255.);
rgb[3] = static_cast<unsigned char>(rgbaF[3] * 255.);
rgb[4] = static_cast<unsigned char>(rgbaF[0] * 255.);
rgb[5] = static_cast<unsigned char>(rgbaF[1] * 255.);
rgb[6] = static_cast<unsigned char>(rgbaF[2] * 255.);
rgb[7] = 255; // second triangle is always opaque
}
}
else
{
if (this->Orientation == VTK_ORIENT_VERTICAL)
{
this->PlaceAnnotationsVertically(
this->TextPosition == vtkScalarBarActor::SucceedScalarBar ?
this->P->ScalarBarBox.Posn[this->P->TL[0]] :
this->P->ScalarBarBox.Posn[this->P->TL[0]]
+ this->P->ScalarBarBox.Size[0],
this->P->ScalarBarBox.Posn[1],
this->P->ScalarBarBox.Size[0],
this->P->ScalarBarBox.Size[1],
0., this->P->SwatchPad);
}
else // HORIZONTAL
{
this->PlaceAnnotationsHorizontally(
this->P->ScalarBarBox.Posn[0],
this->P->ScalarBarBox.Posn[1] + this->P->ScalarBarBox.Size[0],
this->P->ScalarBarBox.Size[1],
this->P->ScalarBarBox.Size[0],
0., this->P->SwatchPad);
}
}
}
//----------------------------------------------------------------------------
void vtkScalarBarActor::FreeLayoutStorage()
{
// Delete previously constructed objects
if (this->P->Viewport && this->P->Viewport->GetVTKWindow())
{
vtkWindow *win = this->P->Viewport->GetVTKWindow();
if (!this->P->TextActors.empty())
{
vtkScalarBarActorInternal::ActorVector::iterator it;
for (
it = this->P->TextActors.begin();
it != this->P->TextActors.end();
++it)
{
(*it)->ReleaseGraphicsResources(win);
}
}
for (size_t i = 0; i < this->P->AnnotationLabels.size(); ++i)
{
this->P->AnnotationLabels[i]->ReleaseGraphicsResources(win);
}
}
this->P->TextActors.clear();
this->P->AnnotationLabels.clear();
this->P->AnnotationAnchors.clear();
this->P->AnnotationColors.clear();
}
//----------------------------------------------------------------------------
void vtkScalarBarActor::SizeTitle(double* titleSize,
int* size,
vtkViewport* viewport)
{
titleSize[0] = titleSize[1] = 0;
if (this->Title == NULL || !strlen(this->Title))
{
return;
}
int targetWidth, targetHeight;
if (this->Orientation == VTK_ORIENT_VERTICAL)
{
targetWidth = static_cast<int>(0.9 * size[0]);
targetHeight = static_cast<int>(0.1 * size[1]);
}
else
{
targetWidth = size[0];
/*
targetHeight = static_cast<int>(
(this->LookupTable->GetIndexedLookup() ? 0.5 : 0.25) * size[1]);
*/
if (this->LookupTable->GetIndexedLookup())
{
targetHeight = static_cast<int>(0.5 * size[1]);
}
else
{
double sizeTextData[2] = {0, 0};
if (!this->P->TextActors.empty())
{ // Don't overlap tick-mark labels:
this->P->TextActors[0]->GetSize(viewport, sizeTextData);
}
// The scalar bar takes half the height.
// Subtract tick-label height and padding
targetHeight =
static_cast<int>((0.5 - 2 * 0.05) * size[1] - sizeTextData[1]);
}
}
this->TitleActor->SetConstrainedFontSize(
viewport, targetWidth, targetHeight);
this->TitleActor->GetSize(viewport, titleSize);
}
//----------------------------------------------------------------------------
int vtkScalarBarActor::MapAnnotationLabels(
vtkScalarsToColors* lkup, double start, double delta, const double* range)
{
int numNotes = lkup->GetNumberOfAnnotatedValues();
bool indexed = lkup->GetIndexedLookup() ? true : false;
bool vertical = (this->Orientation == VTK_ORIENT_VERTICAL);
vtkColor4d fltCol;
double drange = range[1] - range[0];
// I. If we are not in indexed mode, we must sort the labels that we can
// position by their order of appearance (since placement gives
// precedence to the median label). Hence, we use a map to accumulate
// labels.
this->P->Labels.clear();
this->P->LabelColors.clear();
if (numNotes > 0)
{
for (int i = 0; i < numNotes; ++i)
{
vtkStdString label = lkup->GetAnnotation(i);
lkup->GetAnnotationColor(lkup->GetAnnotatedValue(i), fltCol.GetData());
double x;
bool canPositionLabel = !label.empty();
if (canPositionLabel)
{
if (indexed)
{
// Vertical orientation in indexed lookup mode is a special case:
// The first swatch is placed at the top (highest y coordinate).
// All other cases (all horizontal, interval-mode vertical) order
// labels from lowest coordinate to highest.
x = vertical ?
start + (numNotes - i - 0.5) * delta / numNotes :
start + (i + 0.5) * delta / numNotes;
}
else
{
vtkVariant pos = lkup->GetAnnotatedValue(i);
x = pos.ToDouble(&canPositionLabel);
if (canPositionLabel)
{ // Also do not draw if label is outside the scalar bar range.
canPositionLabel = (x >= range[0] && x <= range[1]);
}
x = canPositionLabel ?
(start + (x - range[0]) * delta / drange) :
vtkMath::Nan();
}
}
if (canPositionLabel)
{
this->P->Labels[x] = label;
// Obtain a color for leader lines
vtkColor3ub intCol;
for (int j = 0; j < 3; ++j)
{
intCol.GetData()[j] =
static_cast<unsigned char>(fltCol.GetData()[j] * 255.);
}
this->P->LabelColors[x] = intCol;
}
}
}
// II. Optionally add a NaN label.
if (
this->DrawNanAnnotation &&
this->NanAnnotation &&
this->NanAnnotation[0] != '\0')
{
// Get the NaN color
lkup->GetIndexedColor(-1, fltCol.GetData());
vtkColor3ub intCol;
for (int j = 0; j < 3; ++j)
{
intCol.GetData()[j] =
static_cast<unsigned char>(fltCol.GetData()[j] * 255.);
}
double x =
this->P->NanBox.Posn[this->P->TL[1]] + this->P->NanBox.Size[1] / 2.;
this->P->Labels[x] = this->NanAnnotation;
this->P->LabelColors[x] = intCol;
}
// III. Optionally add a below range label.
if (
this->DrawBelowRangeSwatch &&
this->BelowRangeAnnotation &&
this->BelowRangeAnnotation[0] != '\0')
{
// Get the below range color
lkup->GetIndexedColor(-1, fltCol.GetData());
vtkColor3ub intCol;
for (int j = 0; j < 3; ++j)
{
intCol.GetData()[j] =
static_cast<unsigned char>(fltCol.GetData()[j] * 255.);
}
double x =
this->P->BelowRangeSwatchBox.Posn[this->P->TL[1]] +
this->P->BelowRangeSwatchBox.Size[1] / 2.;
this->P->Labels[x] = this->BelowRangeAnnotation;
this->P->LabelColors[x] = intCol;
}
// IV. Optionally add an above range label.
if (
this->DrawAboveRangeSwatch &&
this->AboveRangeAnnotation &&
this->AboveRangeAnnotation[0] != '\0')
{
// Get the above range color
lkup->GetIndexedColor(-1, fltCol.GetData());
vtkColor3ub intCol;
for (int j = 0; j < 3; ++j)
{
intCol.GetData()[j] =
static_cast<unsigned char>(fltCol.GetData()[j] * 255.);
}
double x =
this->P->AboveRangeSwatchBox.Posn[this->P->TL[1]] +
this->P->AboveRangeSwatchBox.Size[1] / 2.;
this->P->Labels[x] = this->AboveRangeAnnotation;
this->P->LabelColors[x] = intCol;
}
// V. Give subclasses a chance to edit the label map.
this->EditAnnotations();
return static_cast<int>(this->P->Labels.size());
}
//----------------------------------------------------------------------------
int vtkScalarBarActor::PlaceAnnotationsVertically(
double barX, double barY,
double vtkNotUsed(barWidth), double barHeight,
double vtkNotUsed(delta), double pad)
{
if (!this->LookupTable)
{
return 0;
}
#define VTK_ANN_VLAYOUT(j, dir, delt) \
ctr = this->P->AnnotationAnchors[j]; \
ll[0] = lpts->InsertNextPoint(xl0, ctr, 0.); \
this->P->AnnotationLabels[j]->GetSize(this->P->Viewport, tsz); \
hh = (tsz[1] + pad) / 2.; /* label half-height, incl. padding */ \
if (((dir) < 0 && ctr + hh > dnCum) || ((dir) > 0 && ctr - hh < upCum)) \
ctr = (delt) + (dir) * hh; \
this->P->AnnotationLabels[j]->GetTextProperty()->SetJustification(\
this->TextPosition == PrecedeScalarBar ? VTK_TEXT_LEFT : VTK_TEXT_RIGHT);\
this->P->AnnotationLabels[j]->GetTextProperty()\
->SetVerticalJustificationToCentered(); \
this->P->AnnotationLabels[j]->SetPosition(\
barX + (this->TextPosition == PrecedeScalarBar ? 1 : -1) * \
(pad + this->AnnotationLeaderPadding), \
ctr); \
ll[1] = lpts->InsertNextPoint(xl1, ctr, 0.); \
llines->InsertNextCell(2, ll); \
llcolors->InsertNextTypedTuple(this->P->AnnotationColors[j].GetData()); \
if (upCum < ctr + hh) upCum = ctr + hh; \
if (dnCum > ctr - hh) dnCum = ctr - hh;
int numNotes = static_cast<int>(this->P->AnnotationLabels.size());
vtkPoints* lpts = vtkPoints::New();
vtkCellArray* llines = vtkCellArray::New();
vtkUnsignedCharArray* llcolors = vtkUnsignedCharArray::New();
llcolors->SetName("Leader Line Colors");
llcolors->SetNumberOfComponents(3);
llcolors->Allocate(numNotes);
lpts->Allocate(2 * numNotes);
llines->Allocate(llines->EstimateSize(numNotes, 2));
this->P->AnnotationLeaders->Initialize();
this->P->AnnotationLeaders->SetPoints(lpts);
this->P->AnnotationLeaders->SetLines(llines);
if (this->FixedAnnotationLeaderLineColor)
{
this->P->AnnotationLeaders->GetCellData()->SetScalars(NULL);
}
else
{
this->P->AnnotationLeaders->GetCellData()->SetScalars(llcolors);
}
// Start at the center and move outward (both up and down),
// accumulating label heights as we go.
int ic = numNotes / 2;
int dn, up;
double dnCum, upCum, ctr, hh;
double tsz[2];
// leader-line endpoint x-coordinates:
double xl0 =
barX + (this->TextPosition == PrecedeScalarBar ? 1 : -1) * pad / 2.;
double xl1 = barX +
(this->TextPosition == PrecedeScalarBar ? 1 : -1) *
(pad / 2. + this->AnnotationLeaderPadding);
vtkIdType ll[2]; // leader-line endpoint IDs
if (2 * ic == numNotes)
{
dn = ic - 1;
up = ic;
dnCum = barY + barHeight;
upCum = barY;
}
else
{
dn = ic - 1;
up = ic + 1;
dnCum = barY + barHeight;
upCum = barY;
VTK_ANN_VLAYOUT(ic, 0, dnCum);
/*
cout
<< "ic: " << ic << " ctr: " << ctr << " hh: " << hh
<< " uc: " << upCum << " dc: " << dnCum
<< " t:" << this->P->AnnotationLabels[ic]->GetInput() << endl;
*/
}
for (; dn >= 0; --dn, ++up)
{
VTK_ANN_VLAYOUT(dn, -1, dnCum);
/*
cout
<< "dn: " << dn << " ctr: " << ctr << " hh: " << hh
<< " uc: " << upCum << " dc: " << dnCum
<< " t:" << this->P->AnnotationLabels[dn]->GetInput() << endl;
*/
VTK_ANN_VLAYOUT(up, 1, upCum);
/*
cout
<< "up: " << up << " ctr: " << ctr << " hh: " << hh
<< " uc: " << upCum << " dc: " << dnCum
<< " t:" << this->P->AnnotationLabels[up]->GetInput() << endl;
*/
}
lpts->Delete();
llines->Delete();
llcolors->Delete();
return numNotes;
}
//-----------------------------------------------------------------------------
struct vtkScalarBarHLabelInfo
{
double X[2]; // padded left-right label bounds
double Y[2]; // padded top-bottom label bounds
int Justification;
double Anchor[2]; // x-y coordinates of anchor point
};
//-----------------------------------------------------------------------------
// A non-overlapping label placer for a horizontal array of annotated swatches.
// When space is tight, It displaces labels vertically and uses broken leader
// lines to relate labels back to swatches.
struct vtkScalarBarHLabelPlacer
{
std::vector<vtkScalarBarHLabelInfo> Places;
unsigned Ctr;
double Y0;
double XBounds[2];
int NumPlaced;
double Pad;
double LeaderPad;
double Dir; // displacement direction (either +1 or -1)
bool HaveCtr; // Is a label at the dead center? (i.e., is Places.size() odd?)
vtkScalarBarHLabelPlacer(
unsigned n, double y0, double dir, double xmin, double xmax,
double pad, double leaderPad)
: Places(n), Ctr(n % 2 ? n / 2 : n / 2 - 1), Y0(y0), NumPlaced(0),
Pad(pad), LeaderPad(leaderPad),
Dir(dir < 0 ? -1. : 1.), HaveCtr(n % 2 ? true : false)
{
this->XBounds[0] = xmin;
this->XBounds[1] = xmax;
}
void Place(unsigned i, double xBest, double wd, double ht)
{
vtkScalarBarHLabelInfo& placement(this->Places[i]);
unsigned farLo, farHi;
int medNeighbor;
int posRelToCenter =
(i == this->Ctr && this->HaveCtr) ? 0 : (i > this->Ctr ? 1 : -1);
if (posRelToCenter == 0 || this->NumPlaced == 0)
{ // center label
placement.Y[0] = this->Y0 + this->Dir * (this->LeaderPad + this->Pad);
// Note Y[1] has un-padded bounds on distal y axis! Required below.
placement.Y[1] = placement.Y[0] + this->Dir * ht;
placement.X[0] = xBest - wd / 2. - this->Pad;
placement.X[1] = xBest + wd / 2. + this->Pad;
placement.Justification = VTK_TEXT_CENTERED;
placement.Anchor[0] = xBest;
// Vertical justification changes, but Y[0] is always anchor:
placement.Anchor[1] = placement.Y[0];
}
else // placing *a lateral* (as opposed to *the medial*) label.
{
// First: Horizontal placement.
// Check immediate medial neighbor to see if placement can occur
// without more displacement.
bool needToDisplace = false;
if (posRelToCenter == 1)
{
// label is right-justified;
// placement.X[1] bounded from above by XBounds[1]
// Furthest label we have placed so far.
farLo = 2 * this->Ctr + (this->HaveCtr ? 0 : 1) - i;
farHi = this->Ctr; // The closest label we might overlap is dead center.
medNeighbor = i - 1;
placement.Justification = VTK_TEXT_RIGHT;
placement.X[1] = xBest;
placement.X[0] = placement.X[1] - wd - 2 * this->Pad;
placement.Anchor[0] = placement.X[1]; // - this->Pad;
if (xBest - wd < this->Places[medNeighbor].X[1])
{ // We must displace
needToDisplace = true;
}
}
else // posRelToCenter == -1
{
// label is left-justified;
// placement.X[0] bounded from below by XBounds[0] or left neighbor
// The center label is the closest label we might overlap:
farLo = this->Ctr + (this->HaveCtr ? 0 : 1);
// The furthest label to the right we have placed so far.
farHi = 2 * this->Ctr - i - (this->HaveCtr ? 1 : 0);
medNeighbor = i + 1;
if (!this->HaveCtr && medNeighbor >= static_cast<int>(farHi))
{
medNeighbor = -1;
}
placement.Justification = VTK_TEXT_LEFT;
placement.X[0] = xBest;
placement.X[1] = placement.X[0] + wd + 2 * this->Pad;
placement.Anchor[0] = placement.X[0];
if (medNeighbor >= 0 && xBest + wd > this->Places[medNeighbor].X[0])
{
// we must displace; put the label where it makes sense:
// bounded on left by swatch edge.
needToDisplace = true;
}
}
// Second: Vertical placement. Displace label to avoid overlap if need be.
if (!needToDisplace)
{
placement.Y[0] = (medNeighbor >= 0 ?
this->Places[medNeighbor].Y[0] :
this->Y0 + this->Dir * (this->LeaderPad + this->Pad));
placement.Y[1] = placement.Y[0] + this->Dir * ht;
//placement.X[1] = placement.X[0] + wd;
placement.Anchor[1] = placement.Y[0];
}
else
{ // must displace... find out by how much
// I. At least as much as immediate medial neighbor
placement.Y[0] = this->Places[medNeighbor].Y[1] + this->Dir * this->Pad;
for (unsigned j = farLo; j <= farHi; ++j)
{
// II. Check whether label has any y overlap && any x overlap.
// There are 2 cases: one for labels above swatches, the other
// for labels below swatches.
if (
(this->Dir < 0 && placement.Y[0] > this->Places[j].Y[1] &&
(i > j ?
placement.X[0] <= this->Places[j].X[1] :
placement.X[1] >= this->Places[j].X[0])) ||
(this->Dir > 0 && placement.Y[0] < this->Places[j].Y[1] &&
(i > j ?
placement.X[0] <= this->Places[j].X[1] :
placement.X[1] >= this->Places[j].X[0])))
{
placement.Y[0] = this->Places[j].Y[1] + this->Dir * this->Pad;
}
}
placement.Y[1] = placement.Y[0] + this->Dir * ht;
// Vertical justification changes, but Y[0] is always anchor
placement.Anchor[1] = placement.Y[0];
}
}
++this->NumPlaced;
}
void BreakLeader(
vtkScalarBarHLabelInfo& label, double& curY, int j,
vtkPoints* pts, vtkCellArray* lines, vtkUnsignedCharArray* colors,
const vtkColor3ub& color
)
{
vtkScalarBarHLabelInfo& other(this->Places[j]);
vtkIdType pt;
if (
label.Anchor[0] > other.X[0] && label.Anchor[0] < other.X[1] &&
((this->Dir > 0 && label.Anchor[1] >= other.Y[0]) ||
(this->Dir < 0 && label.Anchor[1] <= other.Y[0])
)
)
{
pt = pts->InsertNextPoint(label.Anchor[0], other.Y[0], 0.);
lines->InsertCellPoint(pt);
lines->InsertNextCell(2);
colors->InsertNextTypedTuple(color.GetData());
curY = other.Y[1];
pt = pts->InsertNextPoint(label.Anchor[0], curY, 0.);
lines->InsertCellPoint(pt);
}
}
// Only called after all labels are placed
void AddBrokenLeader(
int lidx, vtkPoints* pts, vtkCellArray* lines,
vtkUnsignedCharArray* colors, const vtkColor3ub& color)
{
vtkIdType pt;
vtkScalarBarHLabelInfo& label(this->Places[lidx]);
// I. Insert first vertex near swatch:
lines->InsertNextCell(2);
colors->InsertNextTypedTuple(color.GetData());
double curY = this->Y0 + this->Dir * this->Pad / 2.;
pt = pts->InsertNextPoint(label.Anchor[0], curY, 0.);
lines->InsertCellPoint(pt);
// II. Loop over all labels checking for interference.
// Where found, close current line and start new one on the other side.
int ic = static_cast<int>(this->Places.size()) / 2;
int lf, rt;
bool done = false;
if (!this->HaveCtr)
{
lf = ic - 1;
rt = ic;
}
else
{
lf = ic - 1;
rt = ic + 1;
if (lidx == ic)
{
done = true;
}
else
{
//cout << "Break " << lidx << " with " << ic << "\n";
this->BreakLeader(label, curY, ic, pts, lines, colors, color);
}
}
if (!done)
{
for (; lf >= 0; --lf, ++rt)
{
if (lf == lidx) break;
//cout << "Break " << lidx << " with " << lf << "\n";
this->BreakLeader(label, curY, lf, pts, lines, colors, color);
if (rt == lidx) break;
//cout << "Break " << lidx << " with " << rt << "\n";
this->BreakLeader(label, curY, rt, pts, lines, colors, color);
}
}
// III. Finally, close the open line segment with the label anchor point.
pt = pts->InsertNextPoint(
label.Anchor[0], label.Anchor[1] - this->Dir * this->Pad / 2., 0.);
lines->InsertCellPoint(pt);
}
};
//----------------------------------------------------------------------------
/**\brief Non-overlapping label placer for a horizontal array of swatches.
*
* A set of rules are enforced during layout:
* <ul>
* <li> Any label may be wider than the entire legend.
* <li> The center label should be centered on the center swatch
* <li> No other label should extend beyond the legend's matching lateral
* extent (i.e., a label to the left of center
* should never extend beyond the left bounds of its swatch).
* <li> To enforce this, labels may be displaced vertically (distally) away
* from the legend.
* <li> Broken leaders should be drawn connecting each displaced label to
* its swatch, with breaks where long labels from the centerline or beyond
* obstruct it.
* </ul>
*
* The algorithm for performing the layout enforces these rules as follows:
* Labels are placed starting with the central (medial) label
* and moving outwards;
* this provides a consistent placement as the actor is resized.
* First the horizontal label position is determined by examining the
* width of the label and the extents of its medial neighbor (which will
* have been placed already).
* The vertical displacement is then computed by either copying the medial
* neighbor's displacement (if no interference with the neighbor was required)
* or incrementing the displacement beyond its immediate
* neighbor and checking all other relevant labels for intereference.
*/
int vtkScalarBarActor::PlaceAnnotationsHorizontally(
double barX, double barY,
double barWidth, double barHeight,
double vtkNotUsed(delta), double pad)
{
if (!this->LookupTable)
{
return 0;
}
#define VTK_ANN_HLAYOUT(j, placer) \
this->P->AnnotationLabels[j]->GetTextProperty()\
->SetJustification(placer.Places[j].Justification); \
this->P->AnnotationLabels[j]->GetTextProperty()\
->SetVerticalJustification(placer.Dir > 0 ? \
VTK_TEXT_BOTTOM : VTK_TEXT_TOP); \
this->P->AnnotationLabels[j]->SetPosition(placer.Places[j].Anchor); \
placer.AddBrokenLeader(j, lpts, llines, llcolors, \
this->P->AnnotationColors[j]);
int numNotes = static_cast<int>(this->P->AnnotationLabels.size());
bool precede = this->TextPosition == vtkScalarBarActor::PrecedeScalarBar;
vtkScalarBarHLabelPlacer placer(
numNotes, precede ? barY : barY - barHeight, precede ? 1 : -1,
barX, barX + barWidth, pad, this->AnnotationLeaderPadding);
vtkPoints* lpts = vtkPoints::New();
vtkCellArray* llines = vtkCellArray::New();
vtkUnsignedCharArray* llcolors = vtkUnsignedCharArray::New();
llcolors->SetName("Leader Line Color");
llcolors->SetNumberOfComponents(3);
llcolors->Allocate(numNotes * numNotes);
// TODO: Improve estimates, but we don't know how many breaks there will be:
lpts->Allocate(numNotes * numNotes);
llines->Allocate(llines->EstimateSize(numNotes * numNotes, 2));
this->P->AnnotationLeaders->Initialize();
this->P->AnnotationLeaders->SetPoints(lpts);
this->P->AnnotationLeaders->SetLines(llines);
if (this->FixedAnnotationLeaderLineColor)
{
this->P->AnnotationLeaders->GetCellData()->SetScalars(NULL);
}
else
{
this->P->AnnotationLeaders->GetCellData()->SetScalars(llcolors);
}
// Start at the center and move outward (both up and down),
// accumulating label displacement as we go.
int ic = numNotes / 2;
int lf, rt;
double tsz[2];
vtkColor3ub leaderColor;
if (2 * ic == numNotes)
{
lf = ic - 1;
rt = ic;
}
else
{
lf = ic - 1;
rt = ic + 1;
this->P->AnnotationLabels[ic]->GetSize(this->P->Viewport, tsz);
placer.Place(
ic, this->P->AnnotationAnchors[ic], tsz[0], tsz[1]);
VTK_ANN_HLAYOUT(ic, placer);
}
for (; lf >= 0; --lf, ++rt)
{
this->P->AnnotationLabels[lf]->GetSize(this->P->Viewport, tsz);
placer.Place(
lf, this->P->AnnotationAnchors[lf], tsz[0], tsz[1]);
VTK_ANN_HLAYOUT(lf, placer);
this->P->AnnotationLabels[rt]->GetSize(this->P->Viewport, tsz);
placer.Place(
rt, this->P->AnnotationAnchors[rt], tsz[0], tsz[1]);
VTK_ANN_HLAYOUT(rt, placer);
}
lpts->Delete();
llines->Delete();
llcolors->Delete();
return numNotes;
}