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.

310 lines
10 KiB
C++

#include "FITKLegendScaleActor.h"
#include "vtkActor2D.h"
#include "vtkAxisActor2D.h"
#include "vtkCamera.h"
#include "vtkCellArray.h"
#include "vtkCellData.h"
#include "vtkCommand.h"
#include "vtkCoordinate.h"
#include "vtkMath.h"
#include "vtkObjectFactory.h"
#include "vtkPoints.h"
#include "vtkPolyData.h"
#include "vtkPolyDataMapper2D.h"
#include "vtkRenderer.h"
#include "vtkTextMapper.h"
#include "vtkTextProperty.h"
#include "vtkUnsignedCharArray.h"
#include "vtkWindow.h"
vtkStandardNewMacro(FITKLegendScaleActor);
//----------------------------------------------------------------------
FITKLegendScaleActor::FITKLegendScaleActor()
{
this->BottomAxis = vtkAxisActor2D::New();
this->BottomAxis->GetPositionCoordinate()->SetCoordinateSystemToViewport();
this->BottomAxis->GetPosition2Coordinate()->SetCoordinateSystemToViewport();
this->BottomAxis->GetPositionCoordinate()->SetReferenceCoordinate(nullptr);
this->BottomAxis->SetFontFactor(0.6);
this->BottomAxis->SetNumberOfLabels(5);
this->BottomAxis->AdjustLabelsOff();
this->BottomAxis->SetVisibility(false);
this->BottomAxisVisibility = 0;
this->Legend = vtkPolyData::New();
this->LegendPoints = vtkPoints::New();
this->Legend->SetPoints(this->LegendPoints);
this->LegendMapper = vtkPolyDataMapper2D::New();
this->LegendMapper->SetInputData(this->Legend);
this->LegendActor = vtkActor2D::New();
this->LegendActor->SetMapper(this->LegendMapper);
// Create the legend
vtkIdType pts[4];
this->LegendPoints->SetNumberOfPoints(10);
vtkCellArray* legendPolys = vtkCellArray::New();
//#if VTK_MAJOR_VERSION < 9
// legendPolys->Allocate(4, 4);
//#else
// legendPolys->AllocateEstimate(4, 4);
//#endif
pts[0] = 0;
pts[1] = 1;
pts[2] = 6;
pts[3] = 5;
legendPolys->InsertNextCell(4, pts);
pts[0] = 1;
pts[1] = 2;
pts[2] = 7;
pts[3] = 6;
legendPolys->InsertNextCell(4, pts);
pts[0] = 2;
pts[1] = 3;
pts[2] = 8;
pts[3] = 7;
legendPolys->InsertNextCell(4, pts);
pts[0] = 3;
pts[1] = 4;
pts[2] = 9;
pts[3] = 8;
legendPolys->InsertNextCell(4, pts);
this->Legend->SetPolys(legendPolys);
legendPolys->Delete();
// Create the cell data
vtkUnsignedCharArray* colors = vtkUnsignedCharArray::New();
colors->SetNumberOfComponents(3);
colors->SetNumberOfTuples(4);
colors->SetTuple3(0, 0, 0, 0);
colors->SetTuple3(1, 255, 255, 255);
colors->SetTuple3(2, 0, 0, 0);
colors->SetTuple3(3, 255, 255, 255);
this->Legend->GetCellData()->SetScalars(colors);
colors->Delete();
// Now the text. The first five are for the 0,1/4,1/2,3/4,1 labels.
this->LegendLabelProperty = vtkTextProperty::New();
this->LegendLabelProperty->SetJustificationToCentered();
this->LegendLabelProperty->SetVerticalJustificationToTop();
this->LegendLabelProperty->SetBold(1);
this->LegendLabelProperty->SetItalic(0);
this->LegendLabelProperty->SetShadow(1);
this->LegendLabelProperty->SetFontFamilyToArial();
this->LegendLabelProperty->SetFontSize(14);
for (int i = 0; i < 5; i++)
{
this->LabelMappers[i] = vtkTextMapper::New();
this->LabelMappers[i]->SetTextProperty(this->LegendLabelProperty);
this->LabelActors[i] = vtkActor2D::New();
this->LabelActors[i]->SetMapper(this->LabelMappers[i]);
}
this->LabelMappers[0]->SetInput("0");
this->LabelMappers[1]->SetInput("1/4");
this->LabelMappers[2]->SetInput("1/2");
this->LabelMappers[3]->SetInput("3/4");
this->LabelMappers[4]->SetInput("1");
this->Coordinate = vtkCoordinate::New();
this->Coordinate->SetCoordinateSystemToDisplay();
}
//----------------------------------------------------------------------
FITKLegendScaleActor::~FITKLegendScaleActor()
{
this->BottomAxis->Delete();
this->Legend->Delete();
this->LegendPoints->Delete();
this->LegendMapper->Delete();
this->LegendActor->Delete();
for (int i = 0; i < 5; i++)
{
this->LabelMappers[i]->Delete();
this->LabelActors[i]->Delete();
}
this->LegendLabelProperty->Delete();
this->Coordinate->Delete();
}
//----------------------------------------------------------------------
void FITKLegendScaleActor::GetActors2D(vtkPropCollection* pc)
{
pc->AddItem(this->BottomAxis);
}
//----------------------------------------------------------------------
void FITKLegendScaleActor::ReleaseGraphicsResources(vtkWindow* w)
{
this->BottomAxis->ReleaseGraphicsResources(w);
this->LegendActor->ReleaseGraphicsResources(w);
for (int i = 0; i < 6; i++)
{
this->LabelActors[i]->ReleaseGraphicsResources(w);
}
}
//----------------------------------------------------------------------
int FITKLegendScaleActor::RenderOpaqueGeometry(vtkViewport* viewport)
{
this->BuildRepresentation(viewport);
int renderedSomething = 0;
if (this->BottomAxisVisibility)
{
renderedSomething += this->BottomAxis->RenderOpaqueGeometry(viewport);
}
renderedSomething += this->LegendActor->RenderOpaqueGeometry(viewport);
renderedSomething += this->LabelActors[0]->RenderOpaqueGeometry(viewport);
renderedSomething += this->LabelActors[1]->RenderOpaqueGeometry(viewport);
renderedSomething += this->LabelActors[2]->RenderOpaqueGeometry(viewport);
renderedSomething += this->LabelActors[3]->RenderOpaqueGeometry(viewport);
renderedSomething += this->LabelActors[4]->RenderOpaqueGeometry(viewport);
return renderedSomething;
}
//----------------------------------------------------------------------
int FITKLegendScaleActor::RenderOverlay(vtkViewport* viewport)
{
int renderedSomething = 0;
if (this->BottomAxisVisibility)
{
renderedSomething += this->BottomAxis->RenderOverlay(viewport);
}
renderedSomething += this->LegendActor->RenderOverlay(viewport);
renderedSomething += this->LabelActors[0]->RenderOverlay(viewport);
renderedSomething += this->LabelActors[1]->RenderOverlay(viewport);
renderedSomething += this->LabelActors[2]->RenderOverlay(viewport);
renderedSomething += this->LabelActors[3]->RenderOverlay(viewport);
renderedSomething += this->LabelActors[4]->RenderOverlay(viewport);
return renderedSomething;
}
//----------------------------------------------------------------------
void FITKLegendScaleActor::BuildRepresentation(vtkViewport* viewport)
{
if (1) // it's probably best just to rerender every time
// if ( this->GetMTime() > this->BuildTime ||
// (this->Renderer && this->Renderer->GetVTKWindow() &&
// this->Renderer->GetVTKWindow()->GetMTime() > this->BuildTime) )
{
// Specify the locations of the axes.
const int* size = viewport->GetSize();
// Now specify the axis values
// distance between points
double* xL = this->BottomAxis->GetPositionCoordinate()->GetComputedWorldValue(viewport);
double* xR = this->BottomAxis->GetPosition2Coordinate()->GetComputedWorldValue(viewport);
double d = sqrt(vtkMath::Distance2BetweenPoints(xL, xR));
char buf0[256];
snprintf(buf0, sizeof(buf0), "%.3g", -d / 2.0);
this->LabelMappers[0]->SetInput(buf0);
char buf1[256];
snprintf(buf1, sizeof(buf1), "%.3g", -d / 4.0);
this->LabelMappers[1]->SetInput(buf1);
char buf2[256];
snprintf(buf2, sizeof(buf2), "%.3g", 0);
this->LabelMappers[2]->SetInput(buf2);
char buf3[256];
snprintf(buf3, sizeof(buf3), "%.3g", d / 4.0);
this->LabelMappers[3]->SetInput(buf3);
char buf4[256];
snprintf(buf4, sizeof(buf4), "%.3g", d / 2.0);
this->LabelMappers[4]->SetInput(buf4);
this->BottomAxis->SetRange(-d / 2.0, d / 2.0);
// Update the position
double posXScale = 0.25;
double x1 = posXScale * size[0];
double delX = size[0] * (1 - posXScale * 2) / 4.;
this->BottomAxis->GetPositionCoordinate()->SetValue(
x1, 0, 0.0);
this->LegendPoints->SetPoint(0, x1, 30, 0);
this->LegendPoints->SetPoint(1, x1 + delX, 30, 0);
this->LegendPoints->SetPoint(2, x1 + 2 * delX, 30, 0);
this->LegendPoints->SetPoint(3, x1 + 3 * delX, 30, 0);
this->LegendPoints->SetPoint(4, x1 + 4 * delX, 30, 0);
this->LegendPoints->SetPoint(5, x1, 40, 0);
this->LegendPoints->SetPoint(6, x1 + delX, 40, 0);
this->LegendPoints->SetPoint(7, x1 + 2 * delX, 40, 0);
this->LegendPoints->SetPoint(8, x1 + 3 * delX, 40, 0);
this->LegendPoints->SetPoint(9, x1 + 4 * delX, 40, 0);
this->LegendPoints->Modified();
this->BottomAxis->GetPosition2Coordinate()->SetValue(
size[0] - x1, 0,
0.0);
// Specify the position of the legend title
this->Coordinate->SetValue(0.33333 * size[0], 15, 0.0);
double* x = this->Coordinate->GetComputedWorldValue(viewport);
xL[0] = x[0];
xL[1] = x[1];
xL[2] = x[2];
this->Coordinate->SetValue(0.66667 * size[0], 15, 0.0);
x = this->Coordinate->GetComputedWorldValue(viewport);
xR[0] = x[0];
xR[1] = x[1];
xR[2] = x[2];
// Now specify the position of the legend labels
x = this->LegendPoints->GetPoint(0);
this->LabelActors[0]->SetPosition(x[0], x[1] - 1);
x = this->LegendPoints->GetPoint(1);
this->LabelActors[1]->SetPosition(x[0], x[1] - 1);
x = this->LegendPoints->GetPoint(2);
this->LabelActors[2]->SetPosition(x[0], x[1] - 1);
x = this->LegendPoints->GetPoint(3);
this->LabelActors[3]->SetPosition(x[0], x[1] - 1);
x = this->LegendPoints->GetPoint(4);
this->LabelActors[4]->SetPosition(x[0], x[1] - 1);
this->BuildTime.Modified();
}
}
//----------------------------------------------------------------------
void FITKLegendScaleActor::PrintSelf(ostream& os, vtkIndent indent)
{
// Superclass typedef defined in vtkTypeMacro() found in vtkSetGet.h
this->Superclass::PrintSelf(os, indent);
os << indent << "Bottom Axis Visibility: " << (this->BottomAxisVisibility ? "On\n" : "Off\n");
os << indent << "Legend Label Property: ";
if (this->LegendLabelProperty)
{
os << this->LegendLabelProperty << "\n";
}
else
{
os << "(none)\n";
}
os << indent << "Bottom Axis: ";
if (this->BottomAxis)
{
os << this->BottomAxis << "\n";
}
else
{
os << "(none)\n";
}
}