Files
ThirdParty-6/ParaView-5.0.1/VTK/Rendering/GL2PS/vtkGL2PSUtilities.cxx

985 lines
30 KiB
C++

/*=========================================================================
Program: Visualization Toolkit
Module: vtkGL2PSUtilities.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 "vtkGL2PSUtilities.h"
#include "vtkIntArray.h"
#include "vtkFloatArray.h"
#include "vtkMath.h"
#include "vtkMatrix4x4.h"
#include "vtkNew.h"
#include "vtkObjectFactory.h"
#include "vtkOpenGLGL2PSHelper.h"
#include "vtkPath.h"
#include "vtkRenderWindow.h"
#include "vtkTextProperty.h"
#include "vtkTextRenderer.h"
#include "vtk_gl2ps.h"
#include <cassert>
#include <sstream>
#include <string>
vtkStandardNewMacro(vtkGL2PSUtilities)
// Initialize static members
vtkRenderWindow *vtkGL2PSUtilities::RenderWindow = NULL;
bool vtkGL2PSUtilities::TextAsPath = false;
float vtkGL2PSUtilities::PointSizeFactor = 5.f / 7.f;
float vtkGL2PSUtilities::LineWidthFactor = 5.f / 7.f;
void vtkGL2PSUtilities::DrawString(const char *str,
vtkTextProperty *tprop, double pos[3],
double backgroundDepth)
{
if (!str)
{
return;
}
vtkTextRenderer *tren(vtkTextRenderer::GetInstance());
if (tren == NULL)
{
vtkNew<vtkGL2PSUtilities> dummy;
vtkErrorWithObjectMacro(dummy.GetPointer(),
<<"vtkTextRenderer unavailable.");
return;
}
int dpi = vtkGL2PSUtilities::RenderWindow->GetDPI();
// Draw the background if needed:
if (tprop->GetBackgroundOpacity() > 0.)
{
vtkTextRenderer::Metrics metrics;
if (tren->GetMetrics(tprop, str, metrics, dpi))
{
double bgPos[3] = { pos[0], pos[1], backgroundDepth };
vtkGL2PSUtilities::ProjectPoint(bgPos);
double bgVerts[12];
bgVerts[0] = bgPos[0] + static_cast<double>(metrics.TopLeft[0]);
bgVerts[1] = bgPos[1] + static_cast<double>(metrics.TopLeft[1]);
bgVerts[2] = bgPos[2];
bgVerts[3] = bgPos[0] + static_cast<double>(metrics.BottomLeft[0]);
bgVerts[4] = bgPos[1] + static_cast<double>(metrics.BottomLeft[1]);
bgVerts[5] = bgPos[2];
bgVerts[6] = bgPos[0] + static_cast<double>(metrics.BottomRight[0]);
bgVerts[7] = bgPos[1] + static_cast<double>(metrics.BottomRight[1]);
bgVerts[8] = bgPos[2];
bgVerts[9] = bgPos[0] + static_cast<double>(metrics.TopRight[0]);
bgVerts[10] = bgPos[1] + static_cast<double>(metrics.TopRight[1]);
bgVerts[11] = bgPos[2];
vtkGL2PSUtilities::UnprojectPoints(bgVerts, 4);
glDisable(GL_LIGHTING);
glDisableClientState(GL_COLOR_ARRAY);
glEnableClientState(GL_VERTEX_ARRAY);
glColor4d(tprop->GetBackgroundColor()[0],
tprop->GetBackgroundColor()[1],
tprop->GetBackgroundColor()[2],
tprop->GetBackgroundOpacity());
glVertexPointer(3, GL_DOUBLE, 0, bgVerts);
glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
}
}
bool isMath = tren->DetectBackend(str) == vtkTextRenderer::MathText;
if (!isMath && !vtkGL2PSUtilities::TextAsPath)
{
const char *fontname = vtkGL2PSUtilities::TextPropertyToPSFontName(tprop);
GLint align = static_cast<GLint>(
vtkGL2PSUtilities::TextPropertyToGL2PSAlignment(tprop));
GLfloat angle = static_cast<GLfloat>(tprop->GetOrientation());
// GL2PS assumes 72 DPI, so we'll have to adjust the font size:
GLint fontSize = static_cast<GLint>(tprop->GetFontSize() * (dpi / 72.));
GL2PSrgba rgba;
double rgbad[3];
tprop->GetColor(rgbad[0], rgbad[1], rgbad[2]);
rgba[0] = static_cast<GLfloat>(rgbad[0]);
rgba[1] = static_cast<GLfloat>(rgbad[1]);
rgba[2] = static_cast<GLfloat>(rgbad[2]);
rgba[3] = tprop->GetOpacity();
glRasterPos3dv(pos);
gl2psTextOptColor(str, fontname, fontSize, align, angle, rgba);
}
else
{
// Render the string to a path and then draw it to GL2PS:
vtkNew<vtkPath> path;
tren->StringToPath(tprop, str, path.GetPointer(), dpi);
// Get color
double rgbd[3];
tprop->GetColor(rgbd[0], rgbd[1], rgbd[2]);
unsigned char rgba[4] = {
static_cast<unsigned char>(rgbd[0]*255),
static_cast<unsigned char>(rgbd[1]*255),
static_cast<unsigned char>(rgbd[2]*255),
static_cast<unsigned char>(tprop->GetOpacity()*255)};
double devicePos[3] = {pos[0], pos[1], pos[2]};
vtkGL2PSUtilities::ProjectPoint(devicePos);
vtkGL2PSUtilities::DrawPath(path.GetPointer(), pos, devicePos, rgba, NULL,
0.0, -1.f, (std::string("Pathified string: ")
+ str).c_str());
}
}
const char *vtkGL2PSUtilities::TextPropertyToPSFontName(vtkTextProperty *tprop)
{
bool bold = tprop->GetBold() != 0;
bool italic = tprop->GetItalic() != 0;
switch (tprop->GetFontFamily())
{
case VTK_ARIAL:
{
if (!bold && !italic)
{
return "Helvetica";
}
else if (bold && italic)
{
return "Helvetica-BoldItalic";
}
else if (bold)
{
return "Helvetica-Bold";
}
else if (italic)
{
return "Helvetica-Italic";
}
}
break;
case VTK_TIMES:
{
if (!bold && !italic)
{
return "Times-Roman";
}
else if (bold && italic)
{
return "Times-BoldOblique";
}
else if (bold)
{
return "Times-Bold";
}
else if (italic)
{
return "Times-Oblique";
}
}
break;
case VTK_COURIER:
{
if (!bold && !italic)
{
return "Courier";
}
else if (bold && italic)
{
return "Courier-BoldOblique";
}
else if (bold)
{
return "Courier-Bold";
}
else if (italic)
{
return "Courier-Oblique";
}
}
break;
case VTK_UNKNOWN_FONT:
default:
break;
}
return "Helvetica";
}
int vtkGL2PSUtilities::TextPropertyToGL2PSAlignment(vtkTextProperty *tprop)
{
switch (tprop->GetJustification())
{
case VTK_TEXT_LEFT:
switch (tprop->GetVerticalJustification())
{
case VTK_TEXT_TOP:
{
return GL2PS_TEXT_TL;
}
case VTK_TEXT_CENTERED:
{
return GL2PS_TEXT_CL;
}
case VTK_TEXT_BOTTOM:
{
return GL2PS_TEXT_BL;
}
}
break;
case VTK_TEXT_CENTERED:
switch (tprop->GetVerticalJustification())
{
case VTK_TEXT_TOP:
{
return GL2PS_TEXT_T;
}
case VTK_TEXT_CENTERED:
{
return GL2PS_TEXT_C;
}
case VTK_TEXT_BOTTOM:
{
return GL2PS_TEXT_B;
}
}
break;
case VTK_TEXT_RIGHT:
switch (tprop->GetVerticalJustification())
{
case VTK_TEXT_TOP:
{
return GL2PS_TEXT_TR;
}
case VTK_TEXT_CENTERED:
{
return GL2PS_TEXT_CR;
}
case VTK_TEXT_BOTTOM:
{
return GL2PS_TEXT_BR;
}
}
default:
break;
}
return GL2PS_TEXT_BL;
}
void vtkGL2PSUtilities::Draw3DPath(vtkPath *path, vtkMatrix4x4 *actorMatrix,
double rasterPos[3],
unsigned char actorColor[4],
const char *label)
{
double translation[2] = {0.0, 0.0};
vtkNew<vtkPath> projPath;
projPath->DeepCopy(path);
vtkGL2PSUtilities::ProjectPoints(projPath->GetPoints(), actorMatrix);
vtkGL2PSUtilities::DrawPath(projPath.GetPointer(), rasterPos, translation,
actorColor, NULL, 0.0, -1.f, label);
}
void vtkGL2PSUtilities::DrawPath(vtkPath *path, double rasterPos[3],
double windowPos[2], unsigned char rgba[4],
double scale[2], double rotateAngle,
float strokeWidth, const char *label)
{
// Replace newlines in label -- these will throw off the comments.
std::string l(label ? label : "");
size_t idx = 0;
while ((idx = l.find('\n', idx)) != std::string::npos)
{
l.replace(idx, 1, "\\n");
}
switch (gl2psGetFileFormat())
{
case GL2PS_PS:
case GL2PS_EPS:
vtkGL2PSUtilities::DrawPathPS(path, rasterPos, windowPos, rgba, scale,
rotateAngle, strokeWidth, l.c_str());
break;
case GL2PS_SVG:
vtkGL2PSUtilities::DrawPathSVG(path, rasterPos, windowPos, rgba, scale,
rotateAngle, strokeWidth, l.c_str());
break;
case GL2PS_PDF:
vtkGL2PSUtilities::DrawPathPDF(path, rasterPos, windowPos, rgba, scale,
rotateAngle, strokeWidth, l.c_str());
break;
default:
break;
}
}
void vtkGL2PSUtilities::StartExport()
{
// This is nasty -- the tokens are used in the feedback buffer to tell GL2PS
// about stippling or when the linewidth/pointsize changes. These are the
// values defined in gl2ps.c as of v1.3.8. If these values change (doubtful)
// we'll need to detect the gl2ps version and set the values per version.
//
// We set these in the helper class to fake the GL2PS functions that inject
// the tokens into the feedback buffer to avoid making vtkRenderingOpenGL
// depend on gl2ps.
vtkOpenGLGL2PSHelper::StippleBeginToken = 5.f; // GL2PS_BEGIN_STIPPLE_TOKEN
vtkOpenGLGL2PSHelper::StippleEndToken = 6.f; // GL2PS_END_STIPPLE_TOKEN
vtkOpenGLGL2PSHelper::PointSizeToken = 7.f; // GL2PS_POINT_SIZE_TOKEN
vtkOpenGLGL2PSHelper::LineWidthToken = 8.f; // GL2PS_LINE_WIDTH_TOKEN
// These are used to scale the points and lines:
vtkOpenGLGL2PSHelper::PointSizeFactor = vtkGL2PSUtilities::PointSizeFactor;
vtkOpenGLGL2PSHelper::LineWidthFactor = vtkGL2PSUtilities::LineWidthFactor;
// Enable the code paths that interact with the feedback buffer:
vtkOpenGLGL2PSHelper::InGL2PSRender = true;
}
void vtkGL2PSUtilities::FinishExport()
{
vtkOpenGLGL2PSHelper::InGL2PSRender = false;
}
void vtkGL2PSUtilities::DrawPathPS(vtkPath *path, double rasterPos[3],
double windowPos[2], unsigned char rgba[4],
double scale[2], double rotateAngle,
float strokeWidth, const char *label)
{
vtkFloatArray *points =
vtkFloatArray::SafeDownCast(path->GetPoints()->GetData());
vtkIntArray *codes = path->GetCodes();
if (points->GetNumberOfTuples() != codes->GetNumberOfTuples())
{
return;
}
std::stringstream out;
out.setf(std::ios_base::left | std::ios_base::fixed);
const int floatPrec = 2;
const int floatWidth = 6;
out.precision(floatPrec);
out.width(floatWidth);
float curveto[3][2];
float curX = 0;
float curY = 0;
float *pt = points->GetPointer(0);
int *code = codes->GetPointer(0);
// These are only used in an assertion, ifdef silences warning on non-debug
// builds
#ifndef NDEBUG
float *ptBegin = pt;
int *codeBegin = code;
#endif
int *codeEnd = code + codes->GetNumberOfTuples();
if (label != NULL && label[0] != '\0')
{
out << "% " << label << endl;
}
out << "gsave" << endl;
out << "initmatrix" << endl;
out << windowPos[0] << " " << windowPos[1] << " translate" << endl;
if (scale)
{
out << scale[0] << " " << scale[1] << " scale" << endl;
}
out << rotateAngle << " rotate" << endl;
out << "newpath" << endl;
while (code < codeEnd)
{
assert(pt - ptBegin == (code - codeBegin) * 3);
switch (static_cast<vtkPath::ControlPointType>(*code))
{
case vtkPath::MOVE_TO:
curX = *pt;
curY = *(++pt);
++pt; // Flush z
out << curX << " " << curY << " moveto\n";
break;
case vtkPath::LINE_TO:
curX = *pt;
curY = *(++pt);
++pt; // Flush z
out << curX << " " << curY << " lineto\n";
break;
case vtkPath::CONIC_CURVE:
// Postscript doesn't support conic curves -- elevate order to cubic:
{
// Next point should be a CONIC_CURVE as well
code += 1;
const float &conicX = *pt;
const float &conicY = *(++pt);
++pt; // Flush z
const float &nextX = *(++pt);
const float &nextY = *(++pt);
++pt; // Flush z
// Perform degree elevation:
curveto[0][0] = (1.0/3.0)*curX + (2.0/3.0)*conicX;
curveto[0][1] = (1.0/3.0)*curY + (2.0/3.0)*conicY;
curveto[1][0] = (2.0/3.0)*conicX + (1.0/3.0)*nextX;
curveto[1][1] = (2.0/3.0)*conicY + (1.0/3.0)*nextY;
curveto[2][0] = curX = nextX;
curveto[2][1] = curY = nextY;
out << curveto[0][0] << " " << curveto[0][1] << endl
<< curveto[1][0] << " " << curveto[1][1] << endl
<< curveto[2][0] << " " << curveto[2][1] << " curveto" << endl;
}
break;
case vtkPath::CUBIC_CURVE:
{
// Next two points should be CUBIC_CURVEs as well
code += 2;
curveto[0][0] = *pt;
curveto[0][1] = *(++pt);
++pt;
curveto[1][0] = *(++pt);
curveto[1][1] = *(++pt);
++pt;
curveto[2][0] = curX = *(++pt);
curveto[2][1] = curY = *(++pt);
++pt;
out << curveto[0][0] << " " << curveto[0][1] << endl
<< curveto[1][0] << " " << curveto[1][1] << endl
<< curveto[2][0] << " " << curveto[2][1] << " curveto" << endl;
}
break;
default:
out << "% Unrecognized control code: " << *code << endl;
pt +=2;
break;
}
++code;
++pt;
}
out << static_cast<float>(rgba[0])/255.f << " " <<
static_cast<float>(rgba[1])/255.f << " " <<
static_cast<float>(rgba[2])/255.f << " setrgbcolor" << endl;
if (strokeWidth > 1e-5)
{
out << strokeWidth << " setlinewidth\nstroke" << endl;
}
else
{
out << "fill" << endl;
}
out << "grestore" << endl;
glRasterPos3dv(rasterPos);
gl2psSpecial(gl2psGetFileFormat(), out.str().c_str());
}
void vtkGL2PSUtilities::DrawPathPDF(vtkPath *path, double rasterPos[3],
double windowPos[2], unsigned char rgba[4],
double scale[2], double rotateAngle,
float strokeWidth,
const char *)
{
vtkFloatArray *points =
vtkFloatArray::SafeDownCast(path->GetPoints()->GetData());
vtkIntArray *codes = path->GetCodes();
if (points->GetNumberOfTuples() != codes->GetNumberOfTuples())
{
return;
}
std::stringstream out;
out.setf(std::ios_base::left | std::ios_base::fixed);
const int floatPrec = 2;
const int floatWidth = 6;
out.precision(floatPrec);
out.width(floatWidth);
float curveto[3][2];
float curX = 0;
float curY = 0;
float *pt = points->GetPointer(0);
int *code = codes->GetPointer(0);
// These are only used in an assertion, ifdef silences warning on non-debug
// builds
#ifndef NDEBUG
float *ptBegin = pt;
int *codeBegin = code;
#endif
int *codeEnd = code + codes->GetNumberOfTuples();
// Push state. PDF doesn't let you reset the CTM, so the hope is that it is
// identity when this block starts...
out << "q" << endl;
// color
out << static_cast<float>(rgba[0])/255.f << " " <<
static_cast<float>(rgba[1])/255.f << " " <<
static_cast<float>(rgba[2])/255.f <<
(strokeWidth > 1e-5 ? " RG" : " rg") << endl;
// opacity
out << static_cast<float>(rgba[3])/255.f
<< (strokeWidth > 1e-5 ? " CA" : " ca") << endl;
// translate
out << 1.f << " " << 0.f << " " << 0.f << " " << 1.f << " "
<< windowPos[0] << " " << windowPos[1] << " cm" << endl;
// rotate
float sT = sin(vtkMath::RadiansFromDegrees(rotateAngle));
float cT = cos(vtkMath::RadiansFromDegrees(rotateAngle));
out << cT << " " << sT << " " << -sT << " " << cT << " " << 0.f << " " << 0.f
<< " cm" << endl;
// scale
if (scale)
{
out << scale[0] << " " << 0.f << " " << 0.f << " " << scale[1] << " " << 0.f
<< " " << 0.f << " cm" << endl;
}
while (code < codeEnd)
{
assert(pt - ptBegin == (code - codeBegin) * 3);
switch (static_cast<vtkPath::ControlPointType>(*code))
{
case vtkPath::MOVE_TO:
curX = *pt;
curY = *(++pt);
++pt; // Flush z
out << curX << " " << curY << " m\n";
break;
case vtkPath::LINE_TO:
curX = *pt;
curY = *(++pt);
++pt; // Flush z
out << curX << " " << curY << " l\n";
break;
case vtkPath::CONIC_CURVE:
// Postscript doesn't support conic curves -- elevate order to cubic:
{
// Next point should be a CONIC_CURVE as well
code += 1;
const float &conicX = *pt;
const float &conicY = *(++pt);
++pt; // Flush z
const float &nextX = *(++pt);
const float &nextY = *(++pt);
++pt; // Flush z
// Perform degree elevation:
curveto[0][0] = (1.0/3.0)*curX + (2.0/3.0)*conicX;
curveto[0][1] = (1.0/3.0)*curY + (2.0/3.0)*conicY;
curveto[1][0] = (2.0/3.0)*conicX + (1.0/3.0)*nextX;
curveto[1][1] = (2.0/3.0)*conicY + (1.0/3.0)*nextY;
curveto[2][0] = curX = nextX;
curveto[2][1] = curY = nextY;
out << curveto[0][0] << " " << curveto[0][1] << endl
<< curveto[1][0] << " " << curveto[1][1] << endl
<< curveto[2][0] << " " << curveto[2][1] << " c" << endl;
}
break;
case vtkPath::CUBIC_CURVE:
{
// Next two points should be CUBIC_CURVEs as well
code += 2;
curveto[0][0] = *pt;
curveto[0][1] = *(++pt);
++pt;
curveto[1][0] = *(++pt);
curveto[1][1] = *(++pt);
++pt;
curveto[2][0] = curX = *(++pt);
curveto[2][1] = curY = *(++pt);
++pt;
out << curveto[0][0] << " " << curveto[0][1] << endl
<< curveto[1][0] << " " << curveto[1][1] << endl
<< curveto[2][0] << " " << curveto[2][1] << " c" << endl;
}
break;
default:
out << "% Unrecognized control code: " << *code << endl;
pt +=2;
break;
}
++code;
++pt;
}
out << "h ";
if (strokeWidth > 1e-5)
{
out << strokeWidth << " w S" << endl;
}
else
{
out<< "f" << endl;
}
out << "Q" << endl; // Pop state
glRasterPos3dv(rasterPos);
gl2psSpecial(gl2psGetFileFormat(), out.str().c_str());
}
void vtkGL2PSUtilities::DrawPathSVG(vtkPath *path, double rasterPos[3],
double windowPos[2], unsigned char rgba[4],
double scale[2], double rotateAngle,
float strokeWidth, const char *label)
{
vtkFloatArray *points =
vtkFloatArray::SafeDownCast(path->GetPoints()->GetData());
vtkIntArray *codes = path->GetCodes();
if (points->GetNumberOfTuples() != codes->GetNumberOfTuples())
{
return;
}
std::stringstream out;
out.setf(std::ios_base::left | std::ios_base::fixed);
const int floatPrec = 2;
const int floatWidth = 6;
out.precision(floatPrec);
out.width(floatWidth);
float curveto[3][2];
float curX = 0;
float curY = 0;
float *pt = points->GetPointer(0);
int *code = codes->GetPointer(0);
// Get the size of the render window -- needed to calculate the SVG position.
if (!vtkGL2PSUtilities::RenderWindow)
{
vtkNew<vtkGL2PSUtilities> dummy;
vtkErrorWithObjectMacro(dummy.GetPointer(), << "No render window set!");
return;
}
double windowHeight =
static_cast<double>(vtkGL2PSUtilities::RenderWindow->GetSize()[1]);
// These are only used in an assertion, ifdef silences warning on non-debug
// builds
#ifndef NDEBUG
float *ptBegin = pt;
int *codeBegin = code;
#endif
if (label != NULL && label[0] != '\0')
{
out << "<!-- " << label << " -->" << endl;
}
int *codeEnd = code + codes->GetNumberOfTuples();
out << "<g transform=\"" << endl
<< " translate(" << windowPos[0] << " "
<< windowHeight - windowPos[1] << ")" << endl;
if (scale)
{
out << " scale(" << scale[0] << " " << -scale[1] << ")" << endl;
}
else
{
out << " scale(1.0 -1.0)" << endl;
}
out << " rotate(" << rotateAngle << ")\"" << endl;
if (strokeWidth > 1e-5)
{
out << " fill=\"none\"" << endl
<< " stroke-width=\"" << strokeWidth << "\"" << endl
<< " stroke=\"rgb(" << std::setprecision(0)
<< static_cast<int>(rgba[0]) << ","
<< static_cast<int>(rgba[1]) << ","
<< static_cast<int>(rgba[2])
<< std::setprecision(floatPrec) << ")\"" << endl;
}
else
{
out << " stroke=\"none\"" << endl
<< " fill=\"rgb(" << std::setprecision(0)
<< static_cast<int>(rgba[0]) << ","
<< static_cast<int>(rgba[1]) << ","
<< static_cast<int>(rgba[2])
<< std::setprecision(floatPrec) << ")\"" << endl;
}
out << " opacity=\"" << static_cast<float>(rgba[3])/255.f << "\"\n"
<< ">" << endl
<< " <path d=\"" << std::right << endl;
while (code < codeEnd)
{
assert(pt - ptBegin == (code - codeBegin) * 3);
switch (static_cast<vtkPath::ControlPointType>(*code))
{
case vtkPath::MOVE_TO:
curX = *pt;
curY = *(++pt);
++pt; // Flush z
out << " M " << curX << " " << curY << endl;
break;
case vtkPath::LINE_TO:
curX = *pt;
curY = *(++pt);
++pt; // Flush z
out << " L " << curX << " " << curY << endl;
break;
case vtkPath::CONIC_CURVE:
{
// Next point should be a CONIC_CURVE as well
code += 1;
const float &conicX = *pt;
const float &conicY = *(++pt);
++pt; // Flush z
const float &nextX = *(++pt);
const float &nextY = *(++pt);
++pt; // Flush z
// Perform degree elevation:
curveto[0][0] = conicX;
curveto[0][1] = conicY;
curveto[1][0] = curX = nextX;
curveto[1][1] = curY = nextY;
out << " Q " << curveto[0][0] << " " << curveto[0][1] << endl
<< " " << curveto[1][0] << " " << curveto[1][1] << endl;
}
break;
case vtkPath::CUBIC_CURVE:
{
// Next two points should be CUBIC_CURVEs as well
code += 2;
curveto[0][0] = *pt;
curveto[0][1] = *(++pt);
++pt;
curveto[1][0] = *(++pt);
curveto[1][1] = *(++pt);
++pt;
curveto[2][0] = curX = *(++pt);
curveto[2][1] = curY = *(++pt);
++pt;
out << " C " << curveto[0][0] << " " << curveto[0][1] << endl
<< " " << curveto[1][0] << " " << curveto[1][1] << endl
<< " " << curveto[2][0] << " " << curveto[2][1] << endl;
}
break;
default:
out << "<!-- Unrecognized control code: " << *code << " -->" << endl;
pt +=2;
break;
}
++code;
++pt;
}
out << " \" />" << endl
<< "</g>" << endl;
glRasterPos3dv(rasterPos);
gl2psSpecial(gl2psGetFileFormat(), out.str().c_str());
}
inline void vtkGL2PSUtilities::ProjectPoint(double point[3],
vtkMatrix4x4 *actorMatrix)
{
// Build transformation matrix
double glMatrix[16];
glGetDoublev(GL_PROJECTION_MATRIX, glMatrix);
vtkNew<vtkMatrix4x4> projectionMatrix;
projectionMatrix->DeepCopy(glMatrix);
projectionMatrix->Transpose();
glGetDoublev(GL_MODELVIEW_MATRIX, glMatrix);
vtkNew<vtkMatrix4x4> modelviewMatrix;
modelviewMatrix->DeepCopy(glMatrix);
modelviewMatrix->Transpose();
vtkNew<vtkMatrix4x4> transformMatrix;
vtkMatrix4x4::Multiply4x4(projectionMatrix.GetPointer(),
modelviewMatrix.GetPointer(),
transformMatrix.GetPointer());
if (actorMatrix)
{
vtkMatrix4x4::Multiply4x4(transformMatrix.GetPointer(),
actorMatrix,
transformMatrix.GetPointer());
}
double viewport[4];
glGetDoublev(GL_VIEWPORT, viewport);
double depthRange[2];
glGetDoublev(GL_DEPTH_RANGE, depthRange);
const double halfWidth = viewport[2] * 0.5;
const double halfHeight = viewport[3] * 0.5;
const double zFactor1 = (depthRange[1] - depthRange[0]) * 0.5;
const double zFactor2 = (depthRange[1] + depthRange[0]) * 0.5;
double tmp[4] = {point[0], point[1], point[2], 1.0};
vtkGL2PSUtilities::ProjectPoint(tmp, transformMatrix.GetPointer(), viewport,
halfWidth, halfHeight, zFactor1, zFactor2);
point[0] = tmp[0];
point[1] = tmp[1];
point[2] = tmp[2];
}
inline void vtkGL2PSUtilities::ProjectPoint(double point[4],
vtkMatrix4x4 *transformMatrix,
double viewportOrigin[],
double halfWidth, double halfHeight,
double zfact1, double zfact2)
{
// Convert world to clip coordinates:
// <out point> = [projection] [modelview] [actor matrix] <in point>
transformMatrix->MultiplyPoint(point, point);
// Clip to NDC
const double invW = 1.0 / point[3];
point[0] *= invW;
point[1] *= invW;
point[2] *= invW;
// NDC to device:
point[0] = point[0] * halfWidth + viewportOrigin[0] + halfWidth;
point[1] = point[1] * halfHeight + viewportOrigin[1] + halfHeight;
point[2] = point[2] * zfact1 + zfact2;
}
inline void vtkGL2PSUtilities::ProjectPoints(vtkPoints *points,
vtkMatrix4x4 *actorMatrix)
{
// Build transformation matrix
double glMatrix[16];
glGetDoublev(GL_PROJECTION_MATRIX, glMatrix);
vtkNew<vtkMatrix4x4> projectionMatrix;
projectionMatrix->DeepCopy(glMatrix);
projectionMatrix->Transpose();
glGetDoublev(GL_MODELVIEW_MATRIX, glMatrix);
vtkNew<vtkMatrix4x4> modelviewMatrix;
modelviewMatrix->DeepCopy(glMatrix);
modelviewMatrix->Transpose();
vtkNew<vtkMatrix4x4> transformMatrix;
vtkMatrix4x4::Multiply4x4(projectionMatrix.GetPointer(),
modelviewMatrix.GetPointer(),
transformMatrix.GetPointer());
if (actorMatrix)
{
vtkMatrix4x4::Multiply4x4(transformMatrix.GetPointer(),
actorMatrix,
transformMatrix.GetPointer());
}
double viewport[4];
glGetDoublev(GL_VIEWPORT, viewport);
double depthRange[2];
glGetDoublev(GL_DEPTH_RANGE, depthRange);
const double halfWidth = viewport[2] * 0.5;
const double halfHeight = viewport[3] * 0.5;
const double zFactor1 = (depthRange[1] - depthRange[0]) * 0.5;
const double zFactor2 = (depthRange[1] + depthRange[0]) * 0.5;
double point[4];
for (vtkIdType i = 0; i < points->GetNumberOfPoints(); ++i)
{
points->GetPoint(i, point);
point[3] = 1.0;
vtkGL2PSUtilities::ProjectPoint(point, transformMatrix.GetPointer(),
viewport, halfWidth, halfHeight, zFactor1,
zFactor2);
points->SetPoint(i, point);
}
}
void vtkGL2PSUtilities::UnprojectPoint(double point[4],
vtkMatrix4x4 *invTransformMatrix,
double viewportOrigin[],
double halfWidth, double halfHeight,
double zfact1, double zfact2)
{
point[0] = (point[0] - viewportOrigin[0] - halfWidth) / halfWidth;
point[1] = (point[1] - viewportOrigin[1] - halfHeight) / halfHeight;
point[2] = (point[2] - zfact2) / zfact1;
point[0] *= point[3];
point[1] *= point[3];
point[2] *= point[3];
invTransformMatrix->MultiplyPoint(point, point);
}
void vtkGL2PSUtilities::UnprojectPoints(double *points3D, vtkIdType numPoints,
vtkMatrix4x4 *actorMatrix)
{
// Build transformation matrix
double glMatrix[16];
glGetDoublev(GL_PROJECTION_MATRIX, glMatrix);
vtkNew<vtkMatrix4x4> projectionMatrix;
projectionMatrix->DeepCopy(glMatrix);
projectionMatrix->Transpose();
glGetDoublev(GL_MODELVIEW_MATRIX, glMatrix);
vtkNew<vtkMatrix4x4> modelviewMatrix;
modelviewMatrix->DeepCopy(glMatrix);
modelviewMatrix->Transpose();
vtkNew<vtkMatrix4x4> transformMatrix;
vtkMatrix4x4::Multiply4x4(projectionMatrix.GetPointer(),
modelviewMatrix.GetPointer(),
transformMatrix.GetPointer());
if (actorMatrix)
{
vtkMatrix4x4::Multiply4x4(transformMatrix.GetPointer(),
actorMatrix,
transformMatrix.GetPointer());
}
transformMatrix->Invert();
double viewport[4];
glGetDoublev(GL_VIEWPORT, viewport);
double depthRange[2];
glGetDoublev(GL_DEPTH_RANGE, depthRange);
const double halfWidth = viewport[2] * 0.5;
const double halfHeight = viewport[3] * 0.5;
const double zFactor1 = (depthRange[1] - depthRange[0]) * 0.5;
const double zFactor2 = (depthRange[1] + depthRange[0]) * 0.5;
double point[4];
for (vtkIdType i = 0; i < numPoints; ++i)
{
std::copy(points3D + (i * 3), points3D + ((i + 1) * 3), point);
point[3] = 1.0;
vtkGL2PSUtilities::UnprojectPoint(point, transformMatrix.GetPointer(),
viewport, halfWidth, halfHeight, zFactor1,
zFactor2);
std::copy(point, point + 3, points3D + (i * 3));
}
}