JKQtPlotter/examples/jkqtplot_test/QTeXEngine/src/QTeXPaintEngine.cpp
jkriege2 69ad2a0182 - added styling system for JKQTPlotter (+example app)
- improved documentation
- changed: using static const variables instead of \c #define for fixed default values (e.g. JKQTPImageTools::LUTSIZE, JKQTPImageTools::PALETTE_ICON_WIDTH, JKQTPlotterDrawinTools::ABS_MIN_LINEWIDTH, JKQTMathText::ABS_MIN_LINEWIDTH ...)
- new: added debugging option, which surrounds different regions with visible rectangles (JKQTBasePlotter::enableDebugShowRegionBoxes() )
- fixed: colorbars at top were positioned over the plot label
- new: frames (plot viewport, key/legend ...) may be rounded off at the corners
- new: diverse new styling options (default font name/size ...)
- speed improvements to JKQTMathText::useSTIX()
2019-02-09 12:43:12 +01:00

1122 lines
25 KiB
C++

/***************************************************************************
File : QTeXPaintEngine.cpp
Project : QTeXEngine GNU GPL v. 3.0
--------------------------------------------------------------------
Copyright : (C) 2009 by Ion Vasilief
Email (use @ for *) : ion_vasilief*yahoo.fr
Description : Enables the export of QPainter grafics to .tex files
***************************************************************************/
/***************************************************************************
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2.1 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the Free Software *
* Foundation, Inc., 51 Franklin Street, Fifth Floor, *
* Boston, MA 02110-1301 USA *
* *
***************************************************************************/
#include "QTeXEngine.h"
#include <math.h>
#include <QDir>
#include <QTextStream>
#include <QDateTime>
QTeXPaintEngine::QTeXPaintEngine(const QString& f, QTeXPaintDevice::Unit u)
: QPaintEngine(QPaintEngine::AllFeatures),
fname(f),
d_pixmap_index(1),
d_unit(u)
{
d_pgf_mode = false;
d_open_scope = false;
d_gray_scale = false;
d_document_mode = false;
d_escape_text = true;
d_font_size = true;
d_clip_path = QPainterPath();
d_current_color = QColor();
d_pattern_color = QColor();
d_horizontal_alignment = Qt::AlignHCenter;
}
bool QTeXPaintEngine::begin(QPaintDevice* p)
{
setPaintDevice(p);
file = new QFile(fname);
if (file->open(QIODevice::WriteOnly)){
QTextStream t(file);
t.setCodec("UTF-8");
if (d_document_mode){
t << "\\documentclass{article}\n";
t << "\\usepackage[left=0.2cm,top=0.1cm,right=0.2cm,nohead,nofoot]{geometry}\n";
if (d_pgf_mode){
t << "\\usepackage{pgf}\n";
t << "\\usepgflibrary{patterns}\n";
} else {
t << "\\usepackage{tikz}\n";
t << "\\usetikzlibrary{patterns}\n";
}
t << "\\usepackage{ulem}\n";//used for striked out fonts (\sout command)
t << "\\begin{document}\n";
}
QString pictureEnv = "\\begin{tikzpicture}{0";
if (d_pgf_mode)
pictureEnv = "\\begin{pgfpicture}{0";
QString u = unit();
t << pictureEnv + u + "}{0" + u + "}{";
t << QString::number(p->width()) + u + "}{";
t << QString::number(p->height()) + u + "}\n";
if (!d_pgf_mode){
QPainterPath path;
path.addRect(QRect(0, 0, p->width(), p->height()));
t << "\t\\clip" + tikzPath(path);
}
return true;
}
delete file;
return false;
}
bool QTeXPaintEngine::end()
{
QTextStream t(file);
t.setCodec("UTF-8");
if (d_open_scope)
t << endScope();
if (d_pgf_mode)
t << "\\end{pgfpicture}\n";
else
t << "\\end{tikzpicture}\n";
if (d_document_mode)
t << "\\end{document}\n";
file->close();
return true;
}
void QTeXPaintEngine::drawPoints ( const QPointF * points, int pointCount )
{
if (emptyStringOperation())
return;
QMatrix m = painter()->worldMatrix();
double lw = painter()->pen().widthF();
QString s = QString::null;
if (addNewPenColor()){
d_current_color = painter()->pen().color();
s = color(d_current_color);
}
for (int i = 0; i < pointCount; i++){
QPointF p = m.map(points[i]);
if (d_pgf_mode){
QString path = pgfPoint(convertPoint(p));
path += pgfPoint(QPointF(lw, lw)) + "\n";
s += "\\pgfrect[fill]" + path;
} else {
QString path = tikzPoint(convertPoint(p));
path += " rectangle " + tikzPoint(convertPoint(QPointF(p.x() + lw, p.y() + lw))) + ";\n";
s += "\\fill " + path;
}
}
writeToFile(s);
}
void QTeXPaintEngine::drawLines ( const QLineF * lines, int lineCount )
{
if (painter()->pen().style() == Qt::NoPen)
return;
QString s;
for (int i = 0; i < lineCount; i++){
QPainterPath path(lines[i].p1());
path.lineTo(lines[i].p2());
s += drawShape(Line, this->path(path));
}
writeToFile(s);
}
void QTeXPaintEngine::drawPolygon ( const QPointF * points, int pointCount, PolygonDrawMode mode )
{
if (emptyStringOperation())
return;
QVector<QPointF> pts;
for (int i = 0; i < pointCount; i++)
pts << points[i];
QPainterPath path;
path.addPolygon(QPolygonF(pts));
if (mode != QPaintEngine::PolylineMode)
path.closeSubpath ();
QString s;;
if (mode != QPaintEngine::PolylineMode){
path.closeSubpath ();
s += drawShape(Polygon, this->path(path));
} else
s += drawShape(Polyline, this->path(path));
writeToFile(s);
}
void QTeXPaintEngine::drawTextItem ( const QPointF & p, const QTextItem & textItem )
{
QString s = QString::null;
if (addNewPenColor()){
s = color(painter()->pen().color());
d_current_color = painter()->pen().color();
}
QMatrix m = painter()->worldMatrix();
s += "\\pgftext[";
QPointF origin = p;
switch(d_horizontal_alignment){
case Qt::AlignLeft:
s += "left";
break;
case Qt::AlignHCenter:
case Qt::AlignJustify:
origin = QPointF(p.x() + 0.5*textItem.width(), p.y());
s += "center";
break;
case Qt::AlignRight:
origin = QPointF(p.x() + textItem.width(), p.y());
s += "right";
break;
default:
break;
}
s += ", base, at=";
s += pgfPoint(convertPoint(m.map(origin)));
if (painter()->transform().isRotating ()){
double angle = 180.0/M_PI*acos(m.m11());
if (m.m11() != 0.0 && m.m12() > 0)
angle = -angle;
s += ",rotate=" + QString::number(angle);
}
s += "]{";
QFont f = textItem.font();
if (d_font_size)
s += "\\fontsize{" + QString::number(int(f.pointSizeF())) + "}{0}\\selectfont{";
if (f.underline())
s += "\\underline{";
if (f.italic())
s += "\\textit{";
if (f.bold())
s += "\\textbf{";
if (f.strikeOut())
s += "\\sout{";
QString text = textItem.text();
text.remove(QRegExp("~\\"));
if (d_escape_text){
text.replace("$", "\\$");
text.replace("_", "\\_");
text.replace("{", "\\{");
text.replace("}", "\\}");
text.replace("^", "\\^");
text.replace("&", "\\&");
text.replace("%", "\\%");
text.replace("#", "\\#");
}
s += text;
if (d_font_size)
s += "}";
if (f.italic())
s += "}";
if (f.bold())
s += "}";
if (f.underline())
s += "}";
if (f.strikeOut())
s += "}";
s += "}\n";
writeToFile(s);
}
void QTeXPaintEngine::drawRects ( const QRectF * rects, int rectCount )
{
if (emptyStringOperation())
return;
QString s;
for (int i = 0; i < rectCount; i++){
QPainterPath path;
path.addPolygon(QPolygonF(rects[i]));
s += drawShape(Path, this->path(path));
}
writeToFile(s);
}
void QTeXPaintEngine::drawEllipse ( const QRectF & rect )
{
if (emptyStringOperation())
return;
QPointF p = painter()->worldMatrix().map(rect.bottomLeft());
QString path;
if (d_pgf_mode){
path = pgfPoint(convertPoint(QPointF(p.x() + 0.5*rect.width(), p.y() - 0.5*rect.height())));
path += pgfPoint(QPointF(0, 0.5*rect.height()*resFactorY()));
path += pgfPoint(QPointF(0.5*rect.width()*resFactorX(), 0)) + "\n";
} else {
path = tikzPoint(convertPoint(QPointF(p.x() + 0.5*rect.width(), p.y() - 0.5*rect.height())));
path += " ellipse (";
QString u = unit();
path += QString::number(0.5*rect.width()*resFactorX()) + u + " and ";
path += QString::number(0.5*rect.height()*resFactorY()) + u + ");\n";
}
writeToFile(drawShape(Ellipse, path));
}
void QTeXPaintEngine::drawPath ( const QPainterPath & path )
{
if (emptyStringOperation())
return;
writeToFile(drawShape(Path, this->path(path)));
}
QString QTeXPaintEngine::drawPgfShape(Shape shape, const QString & path)
{
if (path.isEmpty())
return QString::null;
QString stroke_command = path + "\\pgfstroke\n";
QString fill_command = path + "\\pgffill\n";
switch(shape){
case Line:
case Polygon:
case Polyline:
case Path:
case Points:
break;
case Rect:
stroke_command = "\\pgfrect[stroke]" + path;
fill_command = "\\pgfrect[fill]" + path;
break;
case Ellipse:
stroke_command = "\\pgfellipse[stroke]" + path;
fill_command = "\\pgfellipse[fill]" + path;
break;
}
QString s = QString::null;
if (shape != Line && shape != Polyline && painter()->brush().style() != Qt::NoBrush){
// fill the background
s += pgfBrush(painter()->brush());
s += fill_command;
}
if (painter()->pen().style() != Qt::NoPen){// draw the contour
s += pgfPen(painter()->pen());
s += stroke_command;
}
return s;
}
QString QTeXPaintEngine::drawShape(Shape shape, const QString & path)
{
if (d_pgf_mode)
return drawPgfShape(shape, path);
return drawTikzShape(shape, path);
}
QString QTeXPaintEngine::drawTikzShape(Shape shape, const QString & path)
{
QString s = QString::null;
if (path.isEmpty())
return s;
if (shape != Line && shape != Polyline && painter()->brush().style() != Qt::NoBrush)
// fill the background
s += tikzBrush(painter()->brush()) + path;
if (painter()->pen().style() != Qt::NoPen)// draw the contour
s += tikzPen(painter()->pen()) + path;
return s;
}
void QTeXPaintEngine::drawImage(const QRectF & r, const QImage & image, const QRectF & sr, Qt::ImageConversionFlags flags)
{
drawPixmap(QPixmap::fromImage(image, flags).copy(sr.toAlignedRect()), r);
}
void QTeXPaintEngine::drawPixmap(const QRectF &r, const QPixmap &pm, const QRectF &sr)
{
drawPixmap(pm.copy(sr.toAlignedRect()), r);
}
void QTeXPaintEngine::drawPixmap(const QPixmap &pix, const QRectF &r)
{
QFileInfo fi(*file);
QString base = fi.baseName() + "-images-";
base += QDateTime::currentDateTime().toString("ddMMyy-hhmmss");
if (!fi.dir().exists(base)){
if (!fi.dir().mkdir(base))
return;
}
QString name = fi.dir().absolutePath();
name += "/" + base + "/image" + QString::number(d_pixmap_index);
name = QDir::cleanPath(name);
if (!pix.save(name + ".png", "PNG"))
return;
d_pixmap_index++;
QTextStream t(file);
t.setCodec("UTF-8");
t << "\\pgfputat";
t << pgfPoint(convertPoint(painter()->worldMatrix().map(r.bottomLeft())));
t << "{\\pgfimage[interpolate=false,width=";
QString u = unit();
t << QString::number(r.width()*resFactorX()) + u + ",height=";
t << QString::number(r.height()*resFactorY()) + u + "]{";
t << name;
t << "}}\n";
}
QString QTeXPaintEngine::clipPath()
{
if (painter()->hasClipping()){
QPainterPath path = painter()->clipPath().simplified();
if (path.elementCount() > 1000)//latex has a limited main memory size
return QString::null;
if (d_pgf_mode)
return pgfPath(path) + "\\pgfclip\n";
else
return "\\clip" + tikzPath(path);
}
return QString::null;
}
QString QTeXPaintEngine::defineColor(const QColor& c, const QString& name)
{
QString col = "\\definecolor{" + name + "}{";
if (d_gray_scale){
col += "gray}{";
double gray = qGray(c.rgb())/255.0;
col += QString::number(gray) + "}\n";
} else {
col += "rgb}{";
col += QString::number(c.redF()) + ",";
col += QString::number(c.greenF()) + ",";
col += QString::number(c.blueF()) + "}\n";
}
return col;
}
QString QTeXPaintEngine::tikzBrush(const QBrush& brush)
{
QString options = QString::null;
if (addNewPatternColor()){
options = defineColor(brush.color(), "c");
d_pattern_color = brush.color();
}
options += "\\fill [pattern color=c, pattern=";
switch(brush.style()){
case Qt::NoBrush:
return QString::null;
break;
case Qt::SolidPattern:
{
QString s = QString::null;
if (addNewBrushColor()){
d_current_color = brush.color();
s = color(brush.color());
}
s += "\\fill";
double alpha = painter()->brush().color().alphaF();
if(alpha > 0.0 && alpha < 1.0)
s += "[opacity=" + QString::number(alpha) + "]";
return s;
}
break;
case Qt::Dense1Pattern:
case Qt::Dense2Pattern:
case Qt::Dense3Pattern:
case Qt::Dense4Pattern:
options += "crosshatch dots";
break;
case Qt::Dense5Pattern:
case Qt::Dense6Pattern:
case Qt::Dense7Pattern:
options += "dots";
break;
case Qt::HorPattern:
options += "horizontal lines";
break;
case Qt::VerPattern:
options += "vertical lines";
break;
case Qt::CrossPattern:
options += "grid";
break;
case Qt::BDiagPattern:
options += "north east lines";
break;
case Qt::FDiagPattern:
options += "north west lines";
break;
case Qt::DiagCrossPattern:
options += "crosshatch";
break;
case Qt::LinearGradientPattern:
{
const QLinearGradient *qtgradient = (const QLinearGradient *)brush.gradient();
QGradientStops stops = qtgradient->stops();
QString lc = defineColor(stops.first().second, "lc");
QString rc = defineColor(stops.last().second, "rc");
QMatrix m = painter()->worldMatrix();
QPointF sp = m.map(qtgradient->start());
QPointF ep = m.map(qtgradient->finalStop());
options = lc + rc + "\\fill [";
options += "left color=lc, ";
options += "right color=rc, ";
options += "shading angle=" + QString::number(-QLineF(sp, ep).angle());
}
break;
case Qt::RadialGradientPattern:
{
const QRadialGradient *qtgradient = (const QRadialGradient *)brush.gradient();
QGradientStops stops = qtgradient->stops();
QString colors;
int count = stops.count();
colors += defineColor(stops[0].second, "c1");
colors += defineColor(stops[count - 1].second, "c2");
/*for (int i = 0; i < count; i++){
QGradientStop stop = stops[i];
colors += defineColor(stop.second, "c" + QString::number(i + 1));
}*/
options = colors + "\\fill [";
options += "inner color=c1, ";
options += "outer color=c2, ";
options += "shading=radial";
qWarning("QTeXEngine: Uncentered Qt::RadialGradientPattern with more than two colors not supported.");
}
break;
case Qt::ConicalGradientPattern:
{
qWarning("QTeXEngine: Qt::ConicalGradientPattern is not supported.");
return QString::null;
}
break;
default:
break;
}
return options + "]";
}
QString QTeXPaintEngine::pgfBrush(const QBrush& brush)
{
QString s = QString::null;
QColor c = brush.color();
QString col = defineColor(c, "c");
QString command = "\\pgfsetfillpattern{";
switch(brush.style()){
case Qt::NoBrush:
break;
case Qt::SolidPattern:
s += color(c);
break;
case Qt::Dense1Pattern:
case Qt::Dense2Pattern:
case Qt::Dense3Pattern:
case Qt::Dense4Pattern:
s += col + command + "crosshatch dots}{c}\n";
break;
case Qt::Dense5Pattern:
case Qt::Dense6Pattern:
case Qt::Dense7Pattern:
s += col + command + "dots}{c}\n";
break;
case Qt::HorPattern:
s += col + command + "horizontal lines}{c}\n";
break;
case Qt::VerPattern:
s += col + command + "vertical lines}{c}\n";
break;
case Qt::CrossPattern:
s += col + command + "grid}{c}\n";
break;
case Qt::BDiagPattern:
s += col + command + "north east lines}{c}\n";
break;
case Qt::FDiagPattern:
s += col + command + "north west lines}{c}\n";
break;
case Qt::DiagCrossPattern:
s += col + command + "crosshatch}{c}\n";
break;
default:
break;
}
return s;
}
QString QTeXPaintEngine::path(const QPainterPath & path)
{
if (path.isEmpty ())
return QString::null;
if (d_pgf_mode)
return pgfPath(path);
return tikzPath(path);
}
QString QTeXPaintEngine::pgfPath(const QPainterPath & path)
{
QString s = QString::null;
int points = path.elementCount();
QMatrix m = painter()->worldMatrix();
int curvePoints = 0;
for (int i = 0; i < points; i++){
QPainterPath::Element el = path.elementAt(i);
QPointF p = m.map(QPointF(el.x, el.y));
switch(el.type){
case QPainterPath::MoveToElement:
s += "\\pgfmoveto" + pgfPoint(convertPoint(p)) + "\n";
break;
case QPainterPath::LineToElement:
s += "\\pgflineto" + pgfPoint(convertPoint(p)) + "\n";
break;
case QPainterPath::CurveToElement:
s += "\\pgfcurveto" + pgfPoint(convertPoint(p));
curvePoints = 0;
break;
case QPainterPath::CurveToDataElement:
s += pgfPoint(convertPoint(p));
curvePoints++;
if (curvePoints == 2)
s += "\n";
break;
}
}
return s;
}
QString QTeXPaintEngine::tikzPath(const QPainterPath & path)
{
QString s = QString::null;
if (path.isEmpty())
return s;
int points = path.elementCount();
QMatrix m = painter()->worldMatrix();
int curvePoints = 0;
for (int i = 0; i < points; i++){
QPainterPath::Element el = path.elementAt(i);
QPointF p = m.map(QPointF(el.x, el.y));
switch(el.type){
case QPainterPath::MoveToElement:
s += tikzPoint(convertPoint(p));
break;
case QPainterPath::LineToElement:
s += " -- " + tikzPoint(convertPoint(p));
break;
case QPainterPath::CurveToElement:
s += " .. controls " + tikzPoint(convertPoint(p));
curvePoints = 0;
break;
case QPainterPath::CurveToDataElement:
curvePoints++;
if (curvePoints == 1)
s += " and " + tikzPoint(convertPoint(p));
else if (curvePoints == 2)
s += " .. " + tikzPoint(convertPoint(p));
break;
}
}
return s + ";\n";
}
QPointF QTeXPaintEngine::convertPoint( const QPointF& p)
{
return QPointF(resFactorX()*p.x(), paintDevice()->height() - resFactorY()*p.y());
}
double QTeXPaintEngine::unitFactor()
{
double factor = 1.0;
switch (d_unit){
case QTeXPaintDevice::pt:
factor = 72.27;
break;
case QTeXPaintDevice::bp:
factor = 72;
break;
case QTeXPaintDevice::mm:
factor = 25.4;
break;
case QTeXPaintDevice::cm:
factor = 2.54;
break;
case QTeXPaintDevice::in:
case QTeXPaintDevice::ex:
case QTeXPaintDevice::em:
break;
}
return factor;
}
double QTeXPaintEngine::resFactorX()
{
return unitFactor()/(double)paintDevice()->logicalDpiX();
}
double QTeXPaintEngine::resFactorY()
{
return unitFactor()/(double)paintDevice()->logicalDpiY();
}
QString QTeXPaintEngine::pgfPoint( const QPointF& p)
{
QString u = unit();
QString s = "{\\pgfpoint{" + QString::number(p.x());
s += u + "}{" + QString::number(p.y()) + u + "}}";
return s;
}
QString QTeXPaintEngine::tikzPoint(const QPointF & p)
{
QString u = unit();
QString s = "(" + QString::number(p.x());
s += u + "," + QString::number(p.y()) + u + ")";
return s;
}
QString QTeXPaintEngine::color( const QColor& col)
{
QString s = "\\color[";
if (d_gray_scale){
s += "gray]{";
double gray = qGray(col.rgb())/255.0;
s += QString::number(gray) + "}\n";
} else {
s += "rgb]{";
s += QString::number(col.redF()) + ",";
s += QString::number(col.greenF()) + ",";
s += QString::number(col.blueF()) + "}\n";
}
return s;
}
QString QTeXPaintEngine::pgfPen(const QPen& pen)
{
QString s = QString::null;
if (pen.style() == Qt::NoPen)
return s;
s += color(pen.color());
s += "\\pgfsetlinewidth{" + QString::number(painter()->pen().widthF()) + "pt}\n";
QString aux = "\\pgfsetdash{";
QString term = "}{0cm}\n";
double space_length = 0.08*pen.widthF();
double dot_length = 0.3*space_length;
double dash_length = 1.5*space_length;
QString dash = "{" + QString::number(dash_length) + "cm}";
QString dot = "{" + QString::number(dot_length) + "cm}";
QString space = "{" + QString::number(space_length) + "cm}";
switch (pen.style()){
case Qt::SolidLine:
break;
case Qt::DashLine:
s += aux + dash + space + term;
break;
case Qt::DotLine:
s += aux + dot + space + term;
break;
case Qt::DashDotLine:
s += aux + dash + space + dot + space + term;
break;
case Qt::DashDotDotLine:
s += aux + dash + space + dot + space + dot + space + term;
break;
case Qt::CustomDashLine:
{
s += aux;
QVector<qreal> pattern = pen.dashPattern();
int count = pattern.count();
QString u = unit();
for (int i = 0; i < count; i++)
s += "{" + QString::number(pattern[i]) + u + "}";
s += term;
break;
}
default:
break;
}
switch (pen.joinStyle()){
case Qt::MiterJoin:
s += "\\pgfsetmiterjoin\n";
//s += "\\pgfsetmiterlimit{" + QString::number(pen.miterLimit()) + "pt}\n";
break;
case Qt::BevelJoin:
s += "\\pgfsetbeveljoin\n";
break;
case Qt::RoundJoin:
s += "\\pgfsetroundjoin\n";
break;
case Qt::SvgMiterJoin:
s += "\\pgfsetmiterjoin\n";
break;
default:
break;
}
switch (pen.capStyle()){
case Qt::FlatCap:
s += "\\pgfsetrectcap\n";
break;
case Qt::SquareCap:
s += "\\pgfsetrectcap\n";
break;
case Qt::RoundCap:
s += "\\pgfsetroundcap\n";
break;
default:
break;
}
return s;
}
QString QTeXPaintEngine::tikzPen(const QPen& pen)
{
if (pen.style() == Qt::NoPen)
return QString::null;
QString col = QString::null;
if (addNewPenColor()){
col = color(pen.color());
d_current_color = pen.color();
}
QString options = "[line width=";
options += QString::number(painter()->pen().widthF()) + "pt, ";
double space_length = 0.08*pen.widthF();
double dot_length = 0.3*space_length;
double dash_length = 1.5*space_length;
QString dash = "on " + QString::number(dash_length) + "cm";
QString dot = "on " + QString::number(dot_length) + "cm";
QString space = " off " + QString::number(space_length) + "cm";
QString aux = "dash pattern=";
QString term = ", dash phase=0pt, ";
switch (pen.style()){
case Qt::SolidLine:
break;
case Qt::DashLine:
options += aux + dash + space + term;
break;
case Qt::DotLine:
options += aux + dot + space + term;
break;
case Qt::DashDotLine:
options += aux + dash + space + dot + space + term;
break;
case Qt::DashDotDotLine:
options += aux + dash + space + dot + space + dot + space + term;
break;
case Qt::CustomDashLine:
{
options += aux;
QVector<qreal> pattern = pen.dashPattern();
int count = pattern.count();
QString u = unit();
for (int i = 0; i < count; i++){
QString s = "on ";
if (i%2)
s = " off ";
options += s + QString::number(pattern[i]) + u;
}
options += term;
break;
}
default:
break;
}
options += "line join=";
switch (pen.joinStyle()){
case Qt::MiterJoin:
options += "miter, ";
break;
case Qt::BevelJoin:
options += "bevel, ";
break;
case Qt::RoundJoin:
options += "round, ";
break;
case Qt::SvgMiterJoin:
options += "miter, ";
break;
default:
break;
}
options += "line cap=";
switch (pen.capStyle()){
case Qt::FlatCap:
options += "rect]";
break;
case Qt::SquareCap:
options += "rect]";
break;
case Qt::RoundCap:
options += "round]";
break;
default:
break;
}
return col + "\\draw" + options;
}
QString QTeXPaintEngine::indentString(const QString& s)
{
QStringList lst = s.split("\n", QString::SkipEmptyParts);
for(int i = 0; i < lst.count(); i++)
lst[i].prepend("\t");
return lst.join("\n") + "\n";
}
QString QTeXPaintEngine::beginScope()
{
QString s = "\\begin{scope}\n";
if (d_pgf_mode)
s = "\\begin{pgfscope}\n";
if (painter()->hasClipping()){
QString clip = clipPath();
if (!clip.isEmpty())
s += indentString(clip);
}
d_pattern_color = QColor();
d_current_color = QColor();
return s;
}
QString QTeXPaintEngine::endScope()
{
if (d_pgf_mode)
return "\\end{pgfscope}\n";
return "\\end{scope}\n";
}
void QTeXPaintEngine::writeToFile(const QString& s)
{
QTextStream t(file);
t.setCodec("UTF-8");
if (d_pgf_mode){
t << beginScope();
t << indentString(s);
t << endScope();
return;
}
QString scope;
if (d_open_scope)
scope = endScope();
if (changedClipping()){
scope += beginScope();
scope += indentString(s);
t << scope;
d_open_scope = true;
if (painter()->hasClipping())
d_clip_path = painter()->clipPath();
else
d_clip_path = QPainterPath();
} else
t << indentString(s);
}
bool QTeXPaintEngine::emptyStringOperation()
{
if ((painter()->brush().style() == Qt::NoBrush ||
(painter()->brush().color().alpha() == 0)) &&
painter()->pen().style() == Qt::NoPen)
return true;
return false;
}
bool QTeXPaintEngine::changedClipping()
{
QPainterPath clipPath = QPainterPath();
if (painter()->hasClipping()){
if (painter()->clipPath().elementCount() > 1000)
return false;
clipPath = painter()->clipPath();
}
if (clipPath != d_clip_path)
return true;
return false;
}
bool QTeXPaintEngine::addNewPatternColor()
{
Qt::BrushStyle style = painter()->brush().style();
if (style <= Qt::SolidPattern || style >= Qt::LinearGradientPattern)
return false;
if (!d_pattern_color.isValid() ||
d_pattern_color != painter()->brush().color())
return true;
return false;
}
bool QTeXPaintEngine::addNewBrushColor()
{
if (!d_current_color.isValid() || changedClipping() ||
d_current_color.name() != painter()->brush().color().name())
return true;
return false;
}
bool QTeXPaintEngine::addNewPenColor()
{
if (!d_current_color.isValid() ||
(changedClipping() && painter()->brush().style() == Qt::NoBrush) ||
d_current_color.name() != painter()->pen().color().name())
return true;
return false;
}
QString QTeXPaintEngine::unit()
{
switch (d_unit){
case QTeXPaintDevice::pt:
return "pt";
break;
case QTeXPaintDevice::bp:
return "bp";
break;
case QTeXPaintDevice::mm:
return "mm";
break;
case QTeXPaintDevice::cm:
return "cm";
break;
case QTeXPaintDevice::in:
return "in";
break;
case QTeXPaintDevice::ex:
return "ex";
break;
case QTeXPaintDevice::em:
return "em";
break;
}
return "pt";
}