Commit ee51878e authored by David C. Lonie's avatar David C. Lonie
Browse files

Add GetBoundingBox and use rotations in MathTextUtils.

This patch adds a GetBoundingBox function to vtkMathTextUtilities
and applies rotations from the supplied vtkTextProperty.

The matplotlib MathText interface doesn't have an entry point to
just get the bounding box, so the image is rendered by python as normal,
and then the dimensions are returned.

The MathText library doesn't support rendering rotated text directly,
so a vtkImageReslice filter is used to rotate the image.

Change-Id: I65be970af47c7f8de65f6279c922b6b001f62780
parent 653d2cd3
......@@ -62,6 +62,12 @@ public:
// instance after setting it to fix the reference count.
static void SetInstance(vtkMathTextUtilities *instance);
// Description:
// Determine the dimensions of the image that RenderString will produce for
// a given str, tprop, and dpi
virtual bool GetBoundingBox(vtkTextProperty *tprop, const char *str,
unsigned int dpi, int bbox[4]) = 0;
// Description:
// Render the given string @a str into the vtkImageData @a data with a
// resolution of @a dpi.
......
......@@ -2,6 +2,7 @@ vtk_module(vtkRenderingMatplotlib
IMPLEMENTS
vtkRenderingMathText
DEPENDS
vtkImagingCore
vtkRenderingCore
vtkWrappingPython
TEST_DEPENDS
......
......@@ -18,10 +18,14 @@
#include "vtkPython.h"
#include "vtkImageData.h"
#include "vtkImageReslice.h"
#include "vtkMath.h"
#include "vtkNew.h"
#include "vtkObjectFactory.h"
#include "vtkPath.h"
#include "vtkPoints.h"
#include "vtkTextProperty.h"
#include "vtkTransform.h"
#include <vector>
......@@ -262,6 +266,120 @@ vtkMatplotlibMathTextUtilities::GetFontProperties(vtkTextProperty *tprop)
tpropWeight, tpropFontSize);
}
//----------------------------------------------------------------------------
void vtkMatplotlibMathTextUtilities::RotateCorners(double angleDeg,
double corners[4][2],
double bbox[4])
{
double angleRad = vtkMath::RadiansFromDegrees(angleDeg);
double c = cos(angleRad);
double s = sin(angleRad);
// Rotate corners
for (int i = 0; i < 4; ++i)
{
int newpt[2];
newpt[0] = c * corners[i][0] - s * corners[i][1];
newpt[1] = s * corners[i][0] + c * corners[i][1];
corners[i][0] = newpt[0];
corners[i][1] = newpt[1];
}
// Find new bounds
bbox[0] = VTK_INT_MAX;
bbox[1] = VTK_INT_MIN;
bbox[2] = VTK_INT_MAX;
bbox[3] = VTK_INT_MIN;
for (int i = 0; i < 4; ++i)
{
if (corners[i][0] < bbox[0])
{
bbox[0] = corners[i][0];
}
if (corners[i][0] > bbox[1])
{
bbox[1] = corners[i][0];
}
if (corners[i][1] < bbox[2])
{
bbox[2] = corners[i][1];
}
if (corners[i][1] > bbox[3])
{
bbox[3] = corners[i][1];
}
}
}
//----------------------------------------------------------------------------
bool vtkMatplotlibMathTextUtilities::GetBoundingBox(
vtkTextProperty *tprop, const char *str, unsigned int dpi, int bbox[4])
{
if (!this->MaskParser)
{
if (!this->InitializeMaskParser())
{
vtkErrorMacro(<<"MaskParser is not initialized!");
return false;
}
}
vtkDebugMacro(<<"Calculation bbox for '" << str << "'");
long int rows = 0;
long int cols = 0;
// matplotlib.mathtext seems to mishandle the dpi, this conversion makes the
// text size match the images produced by vtkFreeTypeUtilities, as well as the
// paths generated by StringToPath
long int fontSize = tprop->GetFontSize() * 72.0/static_cast<float>(dpi);
SmartPyObject resultTuple (PyObject_CallMethod(this->MaskParser,
const_cast<char*>("to_mask"),
const_cast<char*>("sii"),
const_cast<char*>(str),
fontSize, dpi));
if (this->CheckForError(resultTuple.GetPointer()))
{
return false;
}
// numpyArray is a borrowed reference, no smart wrapper needed:
PyObject *numpyArray = PyTuple_GetItem(resultTuple.GetPointer(), 0);
if (this->CheckForError(numpyArray))
{
return false;
}
SmartPyObject dimTuple (PyObject_GetAttrString(numpyArray,
const_cast<char*>("shape")));
if (this->CheckForError(dimTuple.GetPointer()))
{
return false;
}
PyArg_ParseTuple(dimTuple.GetPointer(), "ii", &rows, &cols);
if (this->CheckForError())
{
return false;
}
// Determine the dimensions of the rotated image
double angleDeg = tprop->GetOrientation();
// Corners of original image
double corners[4][2] = { {0, 0},
{cols, 0},
{0, rows},
{cols, rows} };
double bboxd[4];
this->RotateCorners(angleDeg, corners, bboxd);
bbox[0] = vtkMath::Round(bboxd[0]);
bbox[1] = vtkMath::Round(bboxd[1]);
bbox[2] = vtkMath::Round(bboxd[2]);
bbox[3] = vtkMath::Round(bboxd[3]);
return true;
}
//----------------------------------------------------------------------------
bool vtkMatplotlibMathTextUtilities::RenderString(const char *str,
vtkImageData *image,
......@@ -277,8 +395,6 @@ bool vtkMatplotlibMathTextUtilities::RenderString(const char *str,
}
}
// TODO rotation, etc from tprop?
vtkDebugMacro(<<"Converting '" << str << "' into MathText image...");
long int rows = 0;
......@@ -374,6 +490,39 @@ bool vtkMatplotlibMathTextUtilities::RenderString(const char *str,
}
}
// Determine the dimensions of the rotated image
double angleDeg = tprop->GetOrientation();
// Save some time if no rotation needed
if (fabs(angleDeg) < 0.01)
{
return true;
}
double *bounds = image->GetBounds();
// Corners of original image
double corners[4][2] = { {bounds[0], bounds[2]},
{bounds[1], bounds[2]},
{bounds[0], bounds[3]},
{bounds[1], bounds[3]} };
double bbox[4];
// Rotate the corners of the image and determine the bounding box
this->RotateCorners(angleDeg, corners, bbox);
// Rotate the temporary image into the returned image:
vtkNew<vtkTransform> rotation;
rotation->RotateWXYZ(-angleDeg, 0, 0, 1);
// Dummy image with the output dimensions
vtkNew<vtkImageData> dummyImage;
dummyImage->SetExtent(bbox[0], bbox[1], bbox[2], bbox[3], 0, 0);
vtkNew<vtkImageReslice> rotator;
rotator->SetInputData(image);
rotator->SetInformationInput(dummyImage.GetPointer());
rotator->SetResliceTransform(rotation.GetPointer());
rotator->SetInterpolationModeToLinear();
rotator->Update();
image->ShallowCopy(rotator->GetOutput());
return true;
}
......
......@@ -38,9 +38,15 @@ public:
static vtkMatplotlibMathTextUtilities *New();
// Description:
// Determine the dimensions of the image that RenderString will produce for
// a given str, tprop, and dpi
bool GetBoundingBox(vtkTextProperty *tprop, const char *str,
unsigned int dpi, int bbox[4]);
// Description:
// Render the given string @a str into the vtkImageData @a data with a
// resolution of @a dpi.
// resolution of @a dpi. The image is resized automatically.
bool RenderString(const char *str, vtkImageData *data, vtkTextProperty *tprop,
unsigned int dpi);
......@@ -71,6 +77,10 @@ protected:
PyObject *PathParser;
PyObject *FontPropertiesClass;
// Rotate the 4 2D corner points by the specified angle (degrees) around the
// origin and calculate the bounding box
void RotateCorners(double angleDeg, double corners[4][2], double bbox[4]);
private:
vtkMatplotlibMathTextUtilities(const vtkMatplotlibMathTextUtilities&); // Not implemented.
void operator=(const vtkMatplotlibMathTextUtilities&); // Not implemented.
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment