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.
723 lines
22 KiB
C++
723 lines
22 KiB
C++
/*=========================================================================
|
|
|
|
Program: Visualization Toolkit
|
|
Module: vtkDynamic2DLabelMapper.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.
|
|
|
|
=========================================================================*/
|
|
/*-------------------------------------------------------------------------
|
|
Copyright 2008 Sandia Corporation.
|
|
Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation,
|
|
the U.S. Government retains certain rights in this software.
|
|
-------------------------------------------------------------------------*/
|
|
|
|
#include "vtkDynamic2DLabelMapper.h"
|
|
|
|
#include "vtkActor2D.h"
|
|
#include "vtkCamera.h"
|
|
#include "vtkCommand.h"
|
|
#include "vtkDataArray.h"
|
|
#include "vtkDataSet.h"
|
|
#include "vtkExecutive.h"
|
|
#include "vtkGraph.h"
|
|
#include "vtkIdTypeArray.h"
|
|
#include "vtkInformation.h"
|
|
#include "vtkIntArray.h"
|
|
#include "vtkKdTree.h"
|
|
#include "vtkMath.h"
|
|
#include "vtkObjectFactory.h"
|
|
#include "vtkPointData.h"
|
|
#include "vtkPoints.h"
|
|
#include "vtkRenderer.h"
|
|
#include "vtkSmartPointer.h"
|
|
#include "vtkSortDataArray.h"
|
|
#include "vtkStringArray.h"
|
|
#include "vtkTextMapper.h"
|
|
#include "vtkTextProperty.h"
|
|
#include "vtkTimerLog.h"
|
|
#include "vtkTypeTraits.h"
|
|
#include "vtkUnicodeStringArray.h"
|
|
#include "vtkViewport.h"
|
|
|
|
#include <fstream>
|
|
using std::ofstream;
|
|
|
|
vtkStandardNewMacro(vtkDynamic2DLabelMapper);
|
|
|
|
//----------------------------------------------------------------------------
|
|
// Creates a new label mapper
|
|
|
|
vtkDynamic2DLabelMapper::vtkDynamic2DLabelMapper()
|
|
{
|
|
this->LabelWidth = NULL;
|
|
this->LabelHeight = NULL;
|
|
this->Cutoff = NULL;
|
|
|
|
this->SetInputArrayToProcess(1, 0, 0, vtkDataObject::FIELD_ASSOCIATION_POINTS, "priority");
|
|
this->ReversePriority = false;
|
|
this->LabelHeightPadding = 50;
|
|
this->LabelWidthPadding = 10;
|
|
this->ReferenceScale = 1.0;
|
|
|
|
// Set new default property
|
|
vtkTextProperty* prop = vtkTextProperty::New();
|
|
prop->SetFontSize(12);
|
|
prop->SetBold(1);
|
|
prop->SetItalic(0);
|
|
prop->SetShadow(1);
|
|
prop->SetFontFamilyToArial();
|
|
prop->SetJustificationToCentered();
|
|
prop->SetVerticalJustificationToCentered();
|
|
prop->SetColor(1, 1, 1);
|
|
this->SetLabelTextProperty(prop);
|
|
prop->Delete();
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
vtkDynamic2DLabelMapper::~vtkDynamic2DLabelMapper()
|
|
{
|
|
delete[] this->LabelWidth;
|
|
delete[] this->LabelHeight;
|
|
delete[] this->Cutoff;
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
void vtkDynamic2DLabelMapper::SetPriorityArrayName(const char* name)
|
|
{
|
|
this->SetInputArrayToProcess(1, 0, 0, vtkDataObject::FIELD_ASSOCIATION_POINTS, name);
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
template<typename T>
|
|
void vtkDynamic2DLabelMapper_PrintComponent(char *output, const char *format, int index, const T *array)
|
|
{
|
|
sprintf(output, format, array[index]);
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
void vtkDynamic2DLabelMapper::RenderOpaqueGeometry(vtkViewport *viewport,
|
|
vtkActor2D *actor)
|
|
{
|
|
int i, j, numComp = 0, pointIdLabels, activeComp = 0;
|
|
double x[3];
|
|
vtkAbstractArray *abstractData;
|
|
vtkDataArray *numericData;
|
|
vtkStringArray *stringData;
|
|
vtkUnicodeStringArray* uStringData;
|
|
vtkDataObject *input = this->GetExecutive()->GetInputData(0, 0);
|
|
|
|
if ( ! input )
|
|
{
|
|
vtkErrorMacro(<<"Need input data to render labels (2)");
|
|
return;
|
|
}
|
|
|
|
vtkTextProperty *tprop = this->GetLabelTextProperty();
|
|
if (!tprop)
|
|
{
|
|
vtkErrorMacro(<<"Need text property to render labels");
|
|
return;
|
|
}
|
|
|
|
this->GetInputAlgorithm()->Update();
|
|
|
|
// Input might have changed
|
|
input = this->GetExecutive()->GetInputData(0, 0);
|
|
|
|
vtkDataSet *dsInput = vtkDataSet::SafeDownCast(input);
|
|
vtkGraph *gInput = vtkGraph::SafeDownCast(input);
|
|
if (!dsInput && !gInput)
|
|
{
|
|
vtkErrorMacro(<<"Input must be vtkDataSet or vtkGraph.");
|
|
return;
|
|
}
|
|
vtkDataSetAttributes *pd =
|
|
dsInput ? dsInput->GetPointData() : gInput->GetVertexData();
|
|
|
|
// If no labels we are done
|
|
vtkIdType numItems = dsInput ? dsInput->GetNumberOfPoints() : gInput->GetNumberOfVertices();
|
|
if (numItems == 0)
|
|
{
|
|
return;
|
|
}
|
|
|
|
// Check to see whether we have to rebuild everything
|
|
if ( this->GetMTime() > this->BuildTime ||
|
|
input->GetMTime() > this->BuildTime)
|
|
{
|
|
vtkDebugMacro(<<"Rebuilding labels");
|
|
|
|
vtkIntArray *typeArr = vtkArrayDownCast<vtkIntArray>(
|
|
this->GetInputAbstractArrayToProcess(0, input));
|
|
|
|
// figure out what to label, and if we can label it
|
|
pointIdLabels = 0;
|
|
abstractData = NULL;
|
|
numericData = NULL;
|
|
stringData = NULL;
|
|
uStringData = NULL;
|
|
switch (this->LabelMode)
|
|
{
|
|
case VTK_LABEL_IDS:
|
|
pointIdLabels = 1;
|
|
break;
|
|
case VTK_LABEL_SCALARS:
|
|
if ( pd->GetScalars() )
|
|
{
|
|
numericData = pd->GetScalars();
|
|
}
|
|
break;
|
|
case VTK_LABEL_VECTORS:
|
|
if ( pd->GetVectors() )
|
|
{
|
|
numericData = pd->GetVectors();
|
|
}
|
|
break;
|
|
case VTK_LABEL_NORMALS:
|
|
if ( pd->GetNormals() )
|
|
{
|
|
numericData = pd->GetNormals();
|
|
}
|
|
break;
|
|
case VTK_LABEL_TCOORDS:
|
|
if ( pd->GetTCoords() )
|
|
{
|
|
numericData = pd->GetTCoords();
|
|
}
|
|
break;
|
|
case VTK_LABEL_TENSORS:
|
|
if ( pd->GetTensors() )
|
|
{
|
|
numericData = pd->GetTensors();
|
|
}
|
|
break;
|
|
case VTK_LABEL_FIELD_DATA:
|
|
{
|
|
int arrayNum;
|
|
if (this->FieldDataName != NULL)
|
|
{
|
|
abstractData = pd->GetAbstractArray(this->FieldDataName, arrayNum);
|
|
}
|
|
else
|
|
{
|
|
arrayNum = (this->FieldDataArray < pd->GetNumberOfArrays() ?
|
|
this->FieldDataArray : pd->GetNumberOfArrays() - 1);
|
|
abstractData = pd->GetAbstractArray(arrayNum);
|
|
}
|
|
numericData = vtkArrayDownCast<vtkDataArray>(abstractData);
|
|
stringData = vtkArrayDownCast<vtkStringArray>(abstractData);
|
|
uStringData = vtkArrayDownCast<vtkUnicodeStringArray>(abstractData);
|
|
}; break;
|
|
}
|
|
|
|
// determine number of components and check input
|
|
if ( pointIdLabels )
|
|
{
|
|
;
|
|
}
|
|
else if ( numericData )
|
|
{
|
|
numComp = numericData->GetNumberOfComponents();
|
|
activeComp = 0;
|
|
if ( this->LabeledComponent >= 0 )
|
|
{
|
|
activeComp = (this->LabeledComponent < numComp ?
|
|
this->LabeledComponent : numComp - 1);
|
|
numComp = 1;
|
|
}
|
|
}
|
|
else if ( uStringData )
|
|
{
|
|
vtkWarningMacro( "Unicode string arrays are not adequately supported by the vtkDynamic2DLabelMapper. Unicode strings will be converted to vtkStdStrings for rendering.");
|
|
}
|
|
else if ( !stringData )
|
|
{
|
|
if (this->FieldDataName)
|
|
{
|
|
vtkWarningMacro(<< "Could not find label array ("
|
|
<< this->FieldDataName << ") "
|
|
<< "in input.");
|
|
}
|
|
else
|
|
{
|
|
vtkWarningMacro(<< "Could not find label array ("
|
|
<< "index " << this->FieldDataArray << ") "
|
|
<< "in input.");
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
vtkStdString FormatString;
|
|
if (this->LabelFormat)
|
|
{
|
|
// The user has specified a format string.
|
|
vtkDebugMacro(<<"Using user-specified format string " << this->LabelFormat);
|
|
FormatString = this->LabelFormat;
|
|
}
|
|
else
|
|
{
|
|
// Try to come up with some sane default.
|
|
if (pointIdLabels)
|
|
{
|
|
FormatString = "%d";
|
|
}
|
|
else if (numericData)
|
|
{
|
|
switch (numericData->GetDataType())
|
|
{
|
|
case VTK_VOID: FormatString = "0x%x"; break;
|
|
|
|
// dont use vtkTypeTraits::ParseFormat for character types as parse formats
|
|
// aren't the same as print formats for these types.
|
|
case VTK_BIT:
|
|
case VTK_SHORT:
|
|
case VTK_UNSIGNED_SHORT:
|
|
case VTK_INT:
|
|
case VTK_UNSIGNED_INT:
|
|
FormatString = "%d"; break;
|
|
|
|
case VTK_CHAR:
|
|
case VTK_SIGNED_CHAR:
|
|
case VTK_UNSIGNED_CHAR:
|
|
FormatString = "%c"; break;
|
|
|
|
case VTK_LONG:
|
|
FormatString = vtkTypeTraits<long>::ParseFormat(); break;
|
|
case VTK_UNSIGNED_LONG:
|
|
FormatString = vtkTypeTraits<unsigned long>::ParseFormat(); break;
|
|
|
|
case VTK_ID_TYPE:
|
|
FormatString = vtkTypeTraits<vtkIdType>::ParseFormat(); break;
|
|
|
|
case VTK_LONG_LONG:
|
|
FormatString = vtkTypeTraits<long long>::ParseFormat(); break;
|
|
case VTK_UNSIGNED_LONG_LONG:
|
|
FormatString = vtkTypeTraits<unsigned long long>::ParseFormat(); break;
|
|
|
|
case VTK_FLOAT:
|
|
FormatString = vtkTypeTraits<float>::ParseFormat(); break;
|
|
|
|
case VTK_DOUBLE:
|
|
FormatString = vtkTypeTraits<double>::ParseFormat(); break;
|
|
|
|
default:
|
|
FormatString = "BUG - UNKNOWN DATA FORMAT"; break;
|
|
}
|
|
}
|
|
else if (stringData)
|
|
{
|
|
FormatString = ""; // we'll use vtkStdString::operator+ instead of sprintf
|
|
}
|
|
else if (uStringData)
|
|
{
|
|
FormatString = "unicode"; // we'll use vtkStdString::operator+ instead of sprintf
|
|
}
|
|
else
|
|
{
|
|
FormatString = "BUG - COULDN'T DETECT DATA TYPE";
|
|
}
|
|
|
|
vtkDebugMacro(<<"Using default format string " << FormatString.c_str());
|
|
} // Done building default format string
|
|
|
|
this->NumberOfLabels =
|
|
dsInput ? dsInput->GetNumberOfPoints() : gInput->GetNumberOfVertices();
|
|
if ( this->NumberOfLabels > this->NumberOfLabelsAllocated )
|
|
{
|
|
// delete old stuff
|
|
for (i=0; i < this->NumberOfLabelsAllocated; i++)
|
|
{
|
|
this->TextMappers[i]->Delete();
|
|
}
|
|
delete [] this->TextMappers;
|
|
|
|
this->NumberOfLabelsAllocated = this->NumberOfLabels;
|
|
this->TextMappers = new vtkTextMapper * [this->NumberOfLabelsAllocated];
|
|
for (i=0; i<this->NumberOfLabelsAllocated; i++)
|
|
{
|
|
this->TextMappers[i] = vtkTextMapper::New();
|
|
}
|
|
}//if we have to allocate new text mappers
|
|
|
|
// ----------------------------------------
|
|
// Now we actually construct the label strings
|
|
//
|
|
|
|
const char *LiveFormatString = FormatString.c_str();
|
|
char TempString[1024];
|
|
|
|
for (i=0; i < this->NumberOfLabels; i++)
|
|
{
|
|
vtkStdString ResultString;
|
|
|
|
if ( pointIdLabels )
|
|
{
|
|
sprintf(TempString, LiveFormatString, i);
|
|
ResultString = TempString;
|
|
}
|
|
else
|
|
{
|
|
if ( numericData )
|
|
{
|
|
void *rawData = numericData->GetVoidPointer(i);
|
|
|
|
if ( numComp == 1 )
|
|
{
|
|
switch (numericData->GetDataType())
|
|
{
|
|
vtkTemplateMacro(vtkDynamic2DLabelMapper_PrintComponent(TempString, LiveFormatString, activeComp, static_cast<VTK_TT *>(rawData)));
|
|
}
|
|
ResultString = TempString;
|
|
}
|
|
else // numComp != 1
|
|
{
|
|
ResultString = "(";
|
|
|
|
// Print each component in turn and add it to the string.
|
|
for (j = 0; j < numComp; ++j)
|
|
{
|
|
switch (numericData->GetDataType())
|
|
{
|
|
vtkTemplateMacro(
|
|
vtkDynamic2DLabelMapper_PrintComponent(TempString,
|
|
LiveFormatString,
|
|
j,
|
|
static_cast<VTK_TT *>(rawData)));
|
|
}
|
|
ResultString += TempString;
|
|
|
|
if (j < (numComp-1))
|
|
{
|
|
ResultString += ' ';
|
|
}
|
|
else
|
|
{
|
|
ResultString += ')';
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else // rendering string data
|
|
{
|
|
// If the user hasn't given us a custom format string then
|
|
// we'll sidestep a lot of sprintf nonsense.
|
|
if (this->LabelFormat == NULL)
|
|
{
|
|
if( uStringData )
|
|
{
|
|
ResultString = uStringData->GetValue(i).utf8_str();
|
|
}
|
|
else
|
|
{
|
|
ResultString = stringData->GetValue(i);
|
|
}
|
|
}
|
|
else // the user specified a label format
|
|
{
|
|
snprintf(TempString, 1023, LiveFormatString,
|
|
stringData->GetValue(i).c_str());
|
|
ResultString = TempString;
|
|
} // done printing strings with label format
|
|
} // done printing strings
|
|
} // done creating string
|
|
|
|
this->TextMappers[i]->SetInput(ResultString.c_str());
|
|
|
|
// Find the correct property type
|
|
int type = 0;
|
|
if (typeArr)
|
|
{
|
|
type = typeArr->GetValue(i);
|
|
}
|
|
vtkTextProperty* prop = this->GetLabelTextProperty(type);
|
|
if (!prop)
|
|
{
|
|
prop = this->GetLabelTextProperty(0);
|
|
}
|
|
this->TextMappers[i]->SetTextProperty(prop);
|
|
}
|
|
|
|
this->BuildTime.Modified();
|
|
|
|
//
|
|
// Perform the label layout preprocessing
|
|
//
|
|
|
|
// Calculate height and width padding
|
|
float widthPadding=0, heightPadding = 0;
|
|
if (this->NumberOfLabels > 0)
|
|
{
|
|
widthPadding = this->TextMappers[0]->GetHeight(viewport) *
|
|
this->LabelWidthPadding/100.0;
|
|
heightPadding = this->TextMappers[0]->GetHeight(viewport) *
|
|
this->LabelHeightPadding/100.0;
|
|
}
|
|
|
|
// Calculate label widths / heights
|
|
delete[] this->LabelWidth;
|
|
this->LabelWidth = new float[this->NumberOfLabels];
|
|
for (i = 0; i < this->NumberOfLabels; i++)
|
|
{
|
|
this->LabelWidth[i] = this->TextMappers[i]->GetWidth(viewport)+
|
|
widthPadding;
|
|
}
|
|
|
|
delete[] this->LabelHeight;
|
|
this->LabelHeight = new float[this->NumberOfLabels];
|
|
for (i = 0; i < this->NumberOfLabels; i++)
|
|
{
|
|
this->LabelHeight[i] = this->TextMappers[i]->GetHeight(viewport)+
|
|
heightPadding;
|
|
}
|
|
|
|
// Determine cutoff scales of each point
|
|
delete[] this->Cutoff;
|
|
this->Cutoff = new float[this->NumberOfLabels];
|
|
|
|
vtkTimerLog* timer = vtkTimerLog::New();
|
|
timer->StartTimer();
|
|
|
|
vtkCoordinate* coord = vtkCoordinate::New();
|
|
coord->SetViewport(viewport);
|
|
vtkPoints* pts = vtkPoints::New();
|
|
for (i = 0; i < this->NumberOfLabels; i++)
|
|
{
|
|
double* dc;
|
|
double pti[3];
|
|
if (dsInput)
|
|
{
|
|
dsInput->GetPoint(i, pti);
|
|
}
|
|
else
|
|
{
|
|
gInput->GetPoint(i, pti);
|
|
}
|
|
coord->SetValue(pti);
|
|
dc = coord->GetComputedDoubleDisplayValue(0);
|
|
pts->InsertNextPoint(dc[0], dc[1], 0);
|
|
}
|
|
coord->Delete();
|
|
|
|
timer->StopTimer();
|
|
vtkDebugMacro("vtkDynamic2DLabelMapper computed display coordinates for " << timer->GetElapsedTime() << "s");
|
|
timer->StartTimer();
|
|
|
|
// Announce progress
|
|
double progress = 0;
|
|
this->InvokeEvent(vtkCommand::ProgressEvent, static_cast<void*>(&progress));
|
|
int current = 0;
|
|
int total = this->NumberOfLabels*(this->NumberOfLabels - 1)/2;
|
|
|
|
// Create an index array to store the offsets of the sorted elements.
|
|
vtkIdTypeArray* index = vtkIdTypeArray::New();
|
|
index->SetNumberOfValues(this->NumberOfLabels);
|
|
for (i = 0; i < this->NumberOfLabels; i++)
|
|
{
|
|
index->SetValue(i, i);
|
|
}
|
|
|
|
// If the array is found, sort it and rearrange the corresponding index array.
|
|
vtkAbstractArray* inputArr = this->GetInputAbstractArrayToProcess(1, input);
|
|
if (inputArr)
|
|
{
|
|
// Don't sort the original array, instead make a copy.
|
|
vtkAbstractArray* arr = vtkAbstractArray::CreateArray(inputArr->GetDataType());
|
|
arr->DeepCopy(inputArr);
|
|
vtkSortDataArray::Sort(arr, index);
|
|
arr->Delete();
|
|
}
|
|
|
|
// We normally go from highest (at the end) to lowest (at the beginning).
|
|
// If priorities are reversed, we go from lowest to highest.
|
|
// If no sorted array was used, we just go from index 0 to index n-1.
|
|
vtkIdType begin = this->NumberOfLabels - 1;
|
|
vtkIdType end = -1;
|
|
vtkIdType step = -1;
|
|
if ((this->ReversePriority && inputArr) || (!this->ReversePriority && !inputArr))
|
|
{
|
|
begin = 0;
|
|
end = this->NumberOfLabels;
|
|
step = 1;
|
|
}
|
|
for (i = begin; i != end; i += step)
|
|
{
|
|
vtkIdType indexI = index->GetValue(i);
|
|
float* pti = reinterpret_cast<float*>(pts->GetVoidPointer(3*indexI));
|
|
this->Cutoff[indexI] = VTK_FLOAT_MAX;
|
|
for (j = begin; j != i; j += step)
|
|
{
|
|
vtkIdType indexJ = index->GetValue(j);
|
|
float* ptj = reinterpret_cast<float*>(pts->GetVoidPointer(3*indexJ));
|
|
float absX = (pti[0] - ptj[0]) > 0 ? (pti[0] - ptj[0]) : -(pti[0] - ptj[0]);
|
|
float absY = (pti[1] - ptj[1]) > 0 ? (pti[1] - ptj[1]) : -(pti[1] - ptj[1]);
|
|
float xScale = 2*absX/(this->LabelWidth[indexI] + this->LabelWidth[indexJ]);
|
|
float yScale = 2*absY/(this->LabelHeight[indexI] + this->LabelHeight[indexJ]);
|
|
float maxScale = xScale < yScale ? yScale : xScale;
|
|
if (maxScale < this->Cutoff[indexJ] && maxScale < this->Cutoff[indexI])
|
|
{
|
|
this->Cutoff[indexI] = maxScale;
|
|
}
|
|
if (current % 100000 == 0)
|
|
{
|
|
progress = static_cast<double>(current)/total;
|
|
this->InvokeEvent(vtkCommand::ProgressEvent, static_cast<void*>(&progress));
|
|
}
|
|
current++;
|
|
}
|
|
}
|
|
index->Delete();
|
|
progress = 1.0;
|
|
this->InvokeEvent(vtkCommand::ProgressEvent, static_cast<void*>(&progress));
|
|
|
|
pts->Delete();
|
|
|
|
// Determine the reference scale
|
|
this->ReferenceScale = this->GetCurrentScale(viewport);
|
|
|
|
timer->StopTimer();
|
|
vtkDebugMacro("vtkDynamic2DLabelMapper computed label cutoffs for " << timer->GetElapsedTime() << "s");
|
|
timer->Delete();
|
|
}
|
|
|
|
//
|
|
// Draw labels visible in the current scale
|
|
//
|
|
|
|
// Determine the current scale
|
|
double scale = 1.0;
|
|
if (this->ReferenceScale != 0.0)
|
|
{
|
|
scale = this->GetCurrentScale(viewport) / this->ReferenceScale;
|
|
}
|
|
|
|
for (i = 0; i < this->NumberOfLabels; i++)
|
|
{
|
|
if (dsInput)
|
|
{
|
|
dsInput->GetPoint(i,x);
|
|
}
|
|
else
|
|
{
|
|
gInput->GetPoint(i,x);
|
|
}
|
|
if ((1.0 / scale) < this->Cutoff[i])
|
|
{
|
|
actor->GetPositionCoordinate()->SetCoordinateSystemToWorld();
|
|
actor->GetPositionCoordinate()->SetValue(x);
|
|
this->TextMappers[i]->RenderOpaqueGeometry(viewport, actor);
|
|
}
|
|
}
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
double vtkDynamic2DLabelMapper::GetCurrentScale(vtkViewport *viewport)
|
|
{
|
|
// The current scale is the size on the screen of 1 unit in the xy plane
|
|
|
|
vtkRenderer* ren = vtkRenderer::SafeDownCast(viewport);
|
|
if ( ! ren )
|
|
{
|
|
vtkErrorMacro("vtkDynamic2DLabelMapper only works in a vtkRenderer or subclass");
|
|
return 1.0;
|
|
}
|
|
vtkCamera* camera = ren->GetActiveCamera();
|
|
if ( camera->GetParallelProjection() )
|
|
{
|
|
// For parallel projection, the scale depends on the parallel scale
|
|
double scale = ( ren->GetSize()[1] / 2.0 ) / camera->GetParallelScale();
|
|
return scale;
|
|
}
|
|
else
|
|
{
|
|
// For perspective projection, the scale depends on the view angle
|
|
double viewAngle = camera->GetViewAngle();
|
|
double distZ = camera->GetPosition()[2] > 0 ? camera->GetPosition()[2] : -camera->GetPosition()[2];
|
|
double unitAngle = vtkMath::DegreesFromRadians( atan2( 1.0, distZ ) );
|
|
double scale = ren->GetSize()[1] * unitAngle / viewAngle;
|
|
return scale;
|
|
}
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
void vtkDynamic2DLabelMapper::RenderOverlay(vtkViewport *viewport,
|
|
vtkActor2D *actor)
|
|
{
|
|
int i;
|
|
double x[3];
|
|
vtkDataObject *input = this->GetExecutive()->GetInputData(0, 0);
|
|
vtkGraph *gInput = vtkGraph::SafeDownCast(input);
|
|
vtkDataSet *dsInput = vtkDataSet::SafeDownCast(input);
|
|
vtkIdType numPts = dsInput ? dsInput->GetNumberOfPoints() : gInput->GetNumberOfVertices();
|
|
|
|
// Determine the current scale
|
|
double scale = 1.0;
|
|
if (this->ReferenceScale != 0.0)
|
|
{
|
|
scale = this->GetCurrentScale(viewport) / this->ReferenceScale;
|
|
}
|
|
|
|
if ( ! input )
|
|
{
|
|
vtkErrorMacro(<<"Need input data to render labels (1)");
|
|
return;
|
|
}
|
|
|
|
vtkTimerLog* timer = vtkTimerLog::New();
|
|
timer->StartTimer();
|
|
|
|
for (i=0; i<this->NumberOfLabels && i<numPts; i++)
|
|
{
|
|
if (dsInput)
|
|
{
|
|
dsInput->GetPoint(i, x);
|
|
}
|
|
else
|
|
{
|
|
gInput->GetPoint(i, x);
|
|
}
|
|
actor->SetPosition(x);
|
|
double* display = actor->GetPositionCoordinate()->GetComputedDoubleDisplayValue(viewport);
|
|
double screenX = display[0];
|
|
double screenY = display[1];
|
|
|
|
bool inside =
|
|
viewport->IsInViewport(
|
|
static_cast<int>(screenX + this->LabelWidth[i]),
|
|
static_cast<int>(screenY + this->LabelHeight[i]))
|
|
|| viewport->IsInViewport(
|
|
static_cast<int>(screenX + this->LabelWidth[i]),
|
|
static_cast<int>(screenY - this->LabelHeight[i]))
|
|
|| viewport->IsInViewport(
|
|
static_cast<int>(screenX - this->LabelWidth[i]),
|
|
static_cast<int>(screenY + this->LabelHeight[i]))
|
|
|| viewport->IsInViewport(
|
|
static_cast<int>(screenX - this->LabelWidth[i]),
|
|
static_cast<int>(screenY - this->LabelHeight[i]));
|
|
if (inside && (1.0f / scale) < this->Cutoff[i])
|
|
{
|
|
this->TextMappers[i]->RenderOverlay(viewport, actor);
|
|
}
|
|
}
|
|
|
|
timer->StopTimer();
|
|
vtkDebugMacro("vtkDynamic2DLabelMapper interactive time: " << timer->GetElapsedTime() << "s");
|
|
timer->Delete();
|
|
}
|
|
|
|
//----------------------------------------------------------------------------
|
|
void vtkDynamic2DLabelMapper::PrintSelf(ostream& os, vtkIndent indent)
|
|
{
|
|
this->Superclass::PrintSelf(os,indent);
|
|
os << indent << "ReversePriority: " << (this->ReversePriority ? "on" : "off") << endl;
|
|
os << indent << "LabelHeightPadding: " << (this->LabelHeightPadding ? "on" : "off") << endl;
|
|
os << indent << "LabelWidthPadding: " << (this->LabelWidthPadding ? "on" : "off") << endl;
|
|
}
|