Cloned library of VTK-5.0.0 with extra build files for internal package management.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

507 lines
14 KiB

/*=========================================================================
Program: Visualization Toolkit
Module: $RCSfile: vtkTextMapper.cxx,v $
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 "vtkTextMapper.h"
#include "vtkImagingFactory.h"
#include "vtkTextProperty.h"
#include "vtkToolkits.h"
vtkCxxRevisionMacro(vtkTextMapper, "$Revision: 1.54 $");
//----------------------------------------------------------------------------
// Needed when we don't use the vtkStandardNewMacro.
vtkInstantiatorNewMacro(vtkTextMapper);
//----------------------------------------------------------------------------
vtkCxxSetObjectMacro(vtkTextMapper,TextProperty,vtkTextProperty);
//----------------------------------------------------------------------------
// Creates a new text mapper
vtkTextMapper::vtkTextMapper()
{
this->Input = (char*)NULL;
// consistent Register/unregister
this->TextProperty = NULL;
this->SetTextProperty(vtkTextProperty::New());
this->TextProperty->Delete();
this->TextLines = NULL;
this->NumberOfLines = 0;
this->NumberOfLinesAllocated = 0;
}
//----------------------------------------------------------------------------
// Shallow copy of an actor.
void vtkTextMapper::ShallowCopy(vtkTextMapper *tm)
{
this->SetInput(tm->GetInput());
this->SetTextProperty(tm->GetTextProperty());
this->SetClippingPlanes(tm->GetClippingPlanes());
}
//----------------------------------------------------------------------------
vtkTextMapper *vtkTextMapper::New()
{
// First try to create the object from the vtkObjectFactory
vtkObject* ret = vtkImagingFactory::CreateInstance("vtkTextMapper");
return (vtkTextMapper*)ret;
}
//----------------------------------------------------------------------------
vtkTextMapper::~vtkTextMapper()
{
if (this->Input)
{
delete [] this->Input;
this->Input = NULL;
}
if (this->TextLines != NULL)
{
for (int i=0; i < this->NumberOfLinesAllocated; i++)
{
this->TextLines[i]->Delete();
}
delete [] this->TextLines;
}
this->SetTextProperty(NULL);
}
//----------------------------------------------------------------------------
void vtkTextMapper::PrintSelf(ostream& os, vtkIndent indent)
{
this->Superclass::PrintSelf(os,indent);
if (this->TextProperty)
{
os << indent << "Text Property:\n";
this->TextProperty->PrintSelf(os,indent.GetNextIndent());
}
else
{
os << indent << "Text Property: (none)\n";
}
os << indent << "Input: " << (this->Input ? this->Input : "(none)") << "\n";
os << indent << "NumberOfLines: " << this->NumberOfLines << "\n";
}
//----------------------------------------------------------------------------
int vtkTextMapper::GetWidth(vtkViewport* viewport)
{
int size[2];
this->GetSize(viewport, size);
return size[0];
}
//----------------------------------------------------------------------------
int vtkTextMapper::GetHeight(vtkViewport* viewport)
{
int size[2];
this->GetSize(viewport, size);
return size[1];
}
//----------------------------------------------------------------------------
#define VTK_TM_DEBUG 0
int vtkTextMapper::SetConstrainedFontSize(vtkViewport *viewport,
int targetWidth,
int targetHeight)
{
// If target "empty"
if (targetWidth == 0 && targetHeight == 0)
{
return 0;
}
// Get text property
vtkTextProperty *tprop = this->GetTextProperty();
if (!tprop)
{
vtkErrorMacro(<<"Need text property to apply constaint");
return 0;
}
int fontSize = tprop->GetFontSize();
#if VTK_TM_DEBUG
int oldfontSize = fontSize;
#endif
// Use the last size as a first guess
int tempi[2];
this->GetSize(viewport, tempi);
#if 1
// Now get an estimate of the target font size using bissection
#if VTK_TM_DEBUG
printf("vtkTextMapper::SetConstrainedFontSize: init size: (%d, %d) => (%d, %d)\n", tempi[0], tempi[1], targetWidth, targetHeight);
#endif
// Based on experimentation with big and small font size increments,
// ceil() gives the best result.
// big: floor: 10749, ceil: 10106, cast: 10749, vtkMath::Round: 10311
// small: floor: 12122, ceil: 11770, cast: 12122, vtkMath::Round: 11768
// I guess the best optim would be to have a look at the shape of the
// font size growth curve (probably not that linear)
if (tempi[0] && tempi[1])
{
float fx = (float)targetWidth / (float)tempi[0];
float fy = (float)targetHeight / (float)tempi[1] ;
fontSize = (int)ceil((float)fontSize * ((fx <= fy) ? fx : fy));
tprop->SetFontSize(fontSize);
this->GetSize(viewport, tempi);
}
#if VTK_TM_DEBUG
printf("vtkTextMapper::SetConstrainedFontSize: estimate size: %2d (was: %2d)\n",
fontSize, oldfontSize);
printf("vtkTextMapper::SetConstrainedFontSize: estimate size: (%d, %d) => (%d, %d)\n", tempi[0], tempi[1], targetWidth, targetHeight);
#endif
#endif
// While the size is too small increase it
while (tempi[1] <= targetHeight &&
tempi[0] <= targetWidth &&
fontSize < 100)
{
fontSize++;
#if VTK_TM_DEBUG
printf("vtkTextMapper::SetConstrainedFontSize: search+ size: %2d\n",
fontSize);
#endif
tprop->SetFontSize(fontSize);
this->GetSize(viewport, tempi);
}
#if VTK_TM_DEBUG
printf("vtkTextMapper::SetConstrainedFontSize: search+ size: (%d, %d) => (%d, %d)\n", tempi[0], tempi[1], targetWidth, targetHeight);
#endif
// While the size is too large decrease it
while ((tempi[1] > targetHeight || tempi[0] > targetWidth)
&& fontSize > 0)
{
fontSize--;
#if VTK_TM_DEBUG
printf("vtkTextMapper::SetConstrainedFontSize: search- size: %2d\n",
fontSize);
#endif
tprop->SetFontSize(fontSize);
this->GetSize(viewport, tempi);
}
#if VTK_TM_DEBUG
printf("vtkTextMapper::SetConstrainedFontSize: search- size: (%d, %d) => (%d, %d)\n", tempi[0], tempi[1], targetWidth, targetHeight);
printf("vtkTextMapper::SetConstrainedFontSize: new size: %2d (was: %2d)\n",
fontSize, oldfontSize);
#endif
return fontSize;
}
//----------------------------------------------------------------------------
int vtkTextMapper::SetMultipleConstrainedFontSize(vtkViewport *viewport,
int targetWidth,
int targetHeight,
vtkTextMapper **mappers,
int nbOfMappers,
int *maxResultingSize)
{
maxResultingSize[0] = maxResultingSize[1] = 0;
if (nbOfMappers == 0)
{
return 0;
}
int fontSize, aSize;
// First try to find the constrained font size of the first mapper: it
// will be used minimize the search for the remaining mappers, given the
// fact that all mappers are likely to have the same constrained font size.
int i, first;
for (first = 0; first < nbOfMappers && !mappers[first]; first++) {}
if (first >= nbOfMappers)
{
return 0;
}
fontSize = mappers[first]->SetConstrainedFontSize(
viewport, targetWidth, targetHeight);
#if VTK_TM_DEBUG
printf("vtkTextMapper::SetMultipleConstrainedFontSize: first size: %2d\n",
fontSize);
#endif
// Find the constrained font size for the remaining mappers and
// pick the smallest
for (i = first + 1; i < nbOfMappers; i++)
{
if (mappers[i])
{
mappers[i]->GetTextProperty()->SetFontSize(fontSize);
aSize = mappers[i]->SetConstrainedFontSize(
viewport, targetWidth, targetHeight);
if (aSize < fontSize)
{
fontSize = aSize;
}
}
}
#if VTK_TM_DEBUG
printf("vtkTextMapper::SetMultipleConstrainedFontSize: smallest size: %2d\n",
fontSize);
#endif
// Assign the smallest size to all text mappers and find the largest area
int tempi[2];
for (i = first; i < nbOfMappers; i++)
{
if (mappers[i])
{
mappers[i]->GetTextProperty()->SetFontSize(fontSize);
mappers[i]->GetSize(viewport, tempi);
if (tempi[0] > maxResultingSize[0])
{
maxResultingSize[0] = tempi[0];
}
if (tempi[1] > maxResultingSize[1])
{
maxResultingSize[1] = tempi[1];
}
}
}
// The above code could be optimized further since the mappers
// labels are likely to have the same height: in that case, we could
// have searched for the largest label, find the constrained size
// for this one, then applied this size to all others. But who
// knows, maybe one day the text property will support a text
// orientation/rotation, and in that case the height will vary.
return fontSize;
}
//----------------------------------------------------------------------------
// Parse the input and create multiple text mappers if multiple lines
// (delimited by \n) are specified.
void vtkTextMapper::SetInput(const char *input)
{
if ( this->Input && input && (!strcmp(this->Input,input)))
{
return;
}
if (this->Input)
{
delete [] this->Input;
}
if (input)
{
this->Input = new char[strlen(input)+1];
strcpy(this->Input,input);
}
else
{
this->Input = NULL;
}
this->Modified();
int numLines = this->GetNumberOfLines(input);
if ( numLines <= 1) // a line with no "\n"
{
this->NumberOfLines = numLines;
}
else //multiple lines
{
char *line;
int i;
if ( numLines > this->NumberOfLinesAllocated )
{
// delete old stuff
if ( this->TextLines )
{
for (i=0; i < this->NumberOfLinesAllocated; i++)
{
this->TextLines[i]->Delete();
}
delete [] this->TextLines;
}
// allocate new text mappers
this->NumberOfLinesAllocated = numLines;
this->TextLines = new vtkTextMapper *[numLines];
for (i=0; i < numLines; i++)
{
this->TextLines[i] = vtkTextMapper::New();
}
} //if we need to reallocate
// set the input strings
this->NumberOfLines = numLines;
for (i=0; i < this->NumberOfLines; i++)
{
line = this->NextLine(input, i);
this->TextLines[i]->SetInput( line );
delete [] line;
}
}
}
//----------------------------------------------------------------------------
// Determine the number of lines in the Input string (delimited by "\n").
int vtkTextMapper::GetNumberOfLines(const char *input)
{
if ( input == NULL || input[0] == '\0')
{
return 0;
}
int numLines=1;
const char *ptr = input;
while ( ptr != NULL )
{
if ( (ptr=strstr(ptr,"\n")) != NULL )
{
numLines++;
ptr++; //skip over \n
}
}
return numLines;
}
//----------------------------------------------------------------------------
// Get the next \n delimited line. Returns a string that
// must be freed by the calling function.
char *vtkTextMapper::NextLine(const char *input, int lineNum)
{
const char *ptr, *ptrEnd;
int strLen;
char *line;
ptr = input;
for (int i=0; i != lineNum; i++)
{
ptr = strstr(ptr,"\n");
ptr++;
}
ptrEnd = strstr(ptr,"\n");
if ( ptrEnd == NULL )
{
ptrEnd = strchr(ptr, '\0');
}
strLen = ptrEnd - ptr;
line = new char[strLen+1];
strncpy(line, ptr, strLen);
line[strLen] = '\0';
return line;
}
//----------------------------------------------------------------------------
// Get the size of a multi-line text string
void vtkTextMapper::GetMultiLineSize(vtkViewport* viewport, int size[2])
{
int i;
int lineSize[2];
vtkTextProperty *tprop = this->GetTextProperty();
if (!tprop)
{
vtkErrorMacro(<<"Need text property to get multiline size of mapper");
size[0] = size[1] = 0;
return;
}
lineSize[0] = lineSize[1] = size[0] = size[1] = 0;
for ( i=0; i < this->NumberOfLines; i++ )
{
this->TextLines[i]->GetTextProperty()->ShallowCopy(tprop);
this->TextLines[i]->GetSize(viewport, lineSize);
size[0] = (lineSize[0] > size[0] ? lineSize[0] : size[0]);
size[1] = (lineSize[1] > size[1] ? lineSize[1] : size[1]);
}
// add in the line spacing
this->LineSize = size[1];
size[1] = (int)((float)size[1] * (1.0 + (this->NumberOfLines - 1) * tprop->GetLineSpacing()));
}
//----------------------------------------------------------------------------
void vtkTextMapper::RenderOverlayMultipleLines(vtkViewport *viewport,
vtkActor2D *actor)
{
float offset = 0.0;
int size[2];
// make sure LineSize is up to date
this->GetMultiLineSize(viewport,size);
vtkTextProperty *tprop = this->GetTextProperty();
if (!tprop)
{
vtkErrorMacro(<<"Need text property to render multiple lines of mapper");
return;
}
switch (tprop->GetVerticalJustification())
{
case VTK_TEXT_TOP:
offset = 0.0;
break;
case VTK_TEXT_CENTERED:
offset = (-this->NumberOfLines + 1.0) / 2.0;
break;
case VTK_TEXT_BOTTOM:
offset = -this->NumberOfLines + 1.0;
break;
}
for (int lineNum=0; lineNum < this->NumberOfLines; lineNum++)
{
this->TextLines[lineNum]->GetTextProperty()->ShallowCopy(tprop);
this->TextLines[lineNum]->GetTextProperty()->SetLineOffset
(tprop->GetLineOffset() + (int)((float)this->LineSize * (lineNum + offset) * tprop->GetLineSpacing()));
this->TextLines[lineNum]->RenderOverlay(viewport,actor);
}
}