PDA

View Full Version : How to create a text along with curve using QPainterPath



achayaan
9th June 2012, 04:14
I am trying to build a arc with some text. I am able to create the arc and I can place the text along with curve. But so far I cant find a way ro rotate text perpendicular to the curve.
Here is the code I am trying


from __future__ import division
import os
import sys
from PyQt4 import QtGui,QtCore
import math

class PathPaintTest(QtGui.QFrame):


def __init__(self, *args):
super (PathPaintTest, self).__init__(*args)
self.setMaximumSize(250, 110)
self.setMinimumSize(250, 110)
self.setFrameShape(QtGui.QFrame.WinPanel)
self.setFrameShadow(QtGui.QFrame.Sunken)

def paintEvent(self, event):
hw = QtCore.QString("Hello World")
drawWidth = self.width() / 100
painter = QtGui.QPainter(self)
pen = painter.pen()
pen.setWidth(drawWidth)
pen.setColor(QtGui.QColor(QtCore.Qt.red))
painter.setPen(pen)
painter.translate(5,0)
cc1 = QtCore.QPointF(5, -15)
cc2 = QtCore.QPointF(220, -15)
path1 = QtGui.QPainterPath(QtCore.QPointF(5, 140))
path1.cubicTo(cc1, cc2, QtCore.QPointF(240, 140))
painter.drawPath(path1)

pen.setColor(QtGui.QColor(QtCore.Qt.yellow))
painter.setPen(pen)
font = painter.font()
font.setPixelSize(drawWidth * 5)
painter.setFont(font)
percentIncrease = 1 / (hw.size() + 1)
perecent = 0
for i in range(hw.size()):
perecent+=percentIncrease
point = QtCore.QPointF(path1.pointAtPercent(perecent))
painter.drawText(point,QtCore.QString(hw[i]))

QtGui.QFrame.paintEvent(self,event)


class TextTest(QtGui.QWidget):
def __init__(self):
super(TextTest, self).__init__()
self.initUI()

def keyPressEvent(self, event):
if event.key() == QtCore.Qt.Key_Escape:
self.close()

def initUI(self):
self.mypb = PathPaintTest()
hbox = QtGui.QHBoxLayout()
hbox.addWidget(self.mypb)

vbox = QtGui.QVBoxLayout()
vbox.addLayout(hbox)

self.setLayout(vbox)
self.setGeometry(1900, 500, 450, 180)
self.setWindowTitle('Text Test')

def run():

app = QtGui.QApplication(sys.argv)
ex = TextTest()
ex.show()
sys.exit(app.exec_())

if __name__ == "__main__":
run()

But I am trying to achieve something close to this post http://zrusin.blogspot.com/2006/11/text-on-path.html . Like text want to be rotated based on the angle. Any idea how I can do with QPainterPath and QPainter or any other methods ?

I am looking a output like this

7825

Please let me know which will be the best way to achieve this .

Thanks in advance :)

ChrisW67
9th June 2012, 07:28
http://qt-project.org/faq/answer/how_do_i_make_text_follow_the_line_curve_and_angle _of_the_qpainterpath

achayaan
9th June 2012, 08:51
I tried this code but for some reason with python I didnt get the same result . May I am missing some point.

Here is what I am getting

7826

This was I am looking for

7827

May be I am missing something, I was looking like a out put like in my first post and here the new code I am trying



from __future__ import division
import os
import sys
from PyQt4 import QtGui,QtCore
import math

class PathPaintTest(QtGui.QFrame):


def __init__(self, *args):
super (PathPaintTest, self).__init__(*args)
self.setMaximumSize(250, 110)
self.setMinimumSize(250, 110)
self.setFrameShape(QtGui.QFrame.WinPanel)
self.setFrameShadow(QtGui.QFrame.Sunken)

def paintEvent(self, event):
hw = QtCore.QString("Hello World")
drawWidth = self.width() / 100
painter = QtGui.QPainter(self)
pen = painter.pen()
pen.setWidth(drawWidth)
pen.setColor(QtGui.QColor(QtCore.Qt.red))
painter.setPen(pen)
painter.translate(5,0)

c1 = QtCore.QPointF(5, -15)
c2 = QtCore.QPointF(220, -15)
path = QtGui.QPainterPath(QtCore.QPointF(5, 140))
path.cubicTo(c1, c2, QtCore.QPointF(240, 140))
painter.drawPath(path)

pen.setColor(QtGui.QColor(QtCore.Qt.green))
painter.setPen(pen)
font = painter.font()
font.setPixelSize(drawWidth * 10)
painter.setFont(font)
perecentIncrease = 1 / (hw.size() + 1)
perecent = 0

for i in range(hw.size()):
perecent+=perecentIncrease
point = QtCore.QPointF(path.pointAtPercent(perecent))
angle = path.angleAtPercent(perecent)
rad = (0.017453292519943295769)*angle
sina = math.sin(rad)
cosa = math.cos(rad)
deltaPenX = cosa * pen.width()
deltaPenY = sina * pen.width()
newX = (cosa * point.x()) - (sina * point.y())
newY = (cosa * point.y()) + (sina * point.x())
deltaX = newX - point.x()
deltaY = newY - point.y()
tran = QtGui.QTransform(cosa,sina,-sina,cosa,-deltaX + deltaPenX,-deltaY - deltaPenY)
painter.setWorldTransform(tran)
painter.drawText(point,QtCore.QString(hw[i]))

QtGui.QFrame.paintEvent(self,event)


class TextTest(QtGui.QWidget):
def __init__(self):
super(TextTest, self).__init__()
self.initUI()

def keyPressEvent(self, event):
if event.key() == QtCore.Qt.Key_Escape:
self.close()

def initUI(self):
self.mypb = PathPaintTest()
hbox = QtGui.QHBoxLayout()
hbox.addWidget(self.mypb)

vbox = QtGui.QVBoxLayout()
vbox.addLayout(hbox)

self.setLayout(vbox)
self.setGeometry(300, 200, 500, 250)
self.setWindowTitle('Text Test')

def run():

app = QtGui.QApplication(sys.argv)
ex = TextTest()
ex.show()
sys.exit(app.exec_())

if __name__ == "__main__":
run()

ChrisW67
10th June 2012, 00:43
I don't have time to read your code right now, but it look like you are rotating each character by the right amount but in the wrong direction.

Achayan
11th June 2012, 18:05
Thanks Chris,

Yes I dont have any clue how I can achieve a rotation based on angle QTransform.

Achayan
11th June 2012, 22:56
http://labs.qt.nokia.com/2006/11/07/text-on-a-path/ ... this looks also my solution but a google search for Zack Rusin returned https://www.facebook.com/pages/RIP-Zack-Rusin/305276032830579?sk=info, if its true and if its the same Zack Rusin then its so sad :(

ChrisW67
12th June 2012, 05:14
Actually, the original C++ code has the same problem. You get a better result if you make the angle negative at line 44 of your Python version.

The solution can e simplified a little by getting Qt to do more of the mathematics:


#include <QtGui>
#include <cmath>

class Widget : public QWidget
{
public:
Widget ()
: QWidget() { }
private:
void paintEvent ( QPaintEvent *)
{
QString hw("hello world");
int drawWidth = width() / 100;
QPainter painter(this);
QPen pen = painter.pen();
pen.setWidth(drawWidth);
pen.setColor(Qt::darkGreen);
painter.setPen(pen);

QPainterPath path(QPointF(0.0, 0.0));

QPointF c1(width()*0.2,height()*0.8);
QPointF c2(width()*0.8,height()*0.2);

path.cubicTo(c1,c2,QPointF(width(),height()));

//draw the bezier curve
painter.drawPath(path);

//Make the painter ready to draw chars
QFont font = painter.font();
font.setPixelSize(drawWidth*2);
painter.setFont(font);
pen.setColor(Qt::red);
painter.setPen(pen);

qreal percentIncrease = (qreal) 1/(hw.size()+1);
qreal percent = 0;

for ( int i = 0; i < hw.size(); i++ ) {
percent += percentIncrease;

QPointF point = path.pointAtPercent(percent);
qreal angle = path.angleAtPercent(percent); // Clockwise is negative

painter.save();
// Move the virtual origin to the point on the curve
painter.translate(point);
// Rotate to match the angle of the curve
// Clockwise is positive so we negate the angle from above
painter.rotate(-angle);
// Draw a line width above the origin to move the text above the line
// and let Qt do the transformations
painter.drawText(QPoint(0, -pen.width()),QString(hw[i]));
painter.restore();
}
}

};

int main(int argc, char **argv)
{
QApplication app(argc, argv);
Widget widget;
widget.show();
return app.exec();
}

Achayan
12th June 2012, 06:20
thanks a lot Chris, it works perfectly ...