[PyQt] selecting a bezier curve

Tom Brown nextstate at gmail.com
Sun Apr 14 01:15:16 BST 2013


I've created a simple application (see below) that draws a bezier curve. I
want to give the user the ability to select the curve so they can move it
around. However, I'm having trouble selecting the curve in an intuitive
fashion. When I click on the curve, the point I click on is actually far
away from the curve.

For example, when I click on the left end of the curve, the x-coordinate of
the point where I clicked is about 100 pixels away from the x-coordinate of
the point of the curve I clicked on.

The code below demonstrates this problem.

Any ideas why this is happening or what I'm doing wrong?

Thanks!
Tom

<code>
from math import sqrt
from sys import argv

from PyQt4.Qt import QApplication
from PyQt4.QtCore import QPointF, Qt
from PyQt4.QtGui import (
    QColor,
    QGraphicsItem,
    QGraphicsView,
    QGraphicsScene,
    QPainterPath,
)


class View(QGraphicsView):
    def __init__(self, parent=None):
        super(View, self).__init__(parent)
        self.epsilon = 11.0
        self.graphics_scene = QGraphicsScene(self)
        self.setScene(self.graphics_scene)
        self.add_curve()

    def mousePressEvent(self, event):
        if event.button() == Qt.LeftButton:
            self.select_item_at(event.x(), event.y())

    def select_item_at(self, x, y):
        self.unselect_items()
        for item in self.items():
            if item.contains_point(x, y, self.epsilon):
                item.set_selected(True)
                item.update()

    def unselect_items(self):
        for item in self.items():
            item.set_selected(False)
            item.update()

    def add_curve(self):
        color = QColor(255, 0, 0)
        x0 = 600.0
        y0 = 400.0
        x1 = 800.0
        y1 = 500.0
        x2 = 1000.0
        y2 = 500.0
        x3 = 1200.0
        y3 = 400.0
        control_points = (QPointF(x0, y0), QPointF(x1, y1),
            QPointF(x2, y2), QPointF(x3, y3))
        curve = Curve(color, control_points)
        self.graphics_scene.addItem(curve)


class Curve(QGraphicsItem):
    def __init__(self, color, control_points, parent=None, scene=None):
        super(Curve, self).__init__(parent, scene)
        self.selected = False
        self.color = color
        self.path = QPainterPath()
        self.path.moveTo(control_points[0])
        self.path.cubicTo(*control_points[1:])

    def set_selected(self, selected):
        self.selected = selected

    def contains_point(self, x, y, epsilon):
        p = (x, y)
        min_distance = float(0x7fffffff)
        t = 0.0
        while t < 1.0:
            point = self.path.pointAtPercent(t)
            spline_point = (point.x(), point.y())
            print p, spline_point
            distance = self.distance(p, spline_point)
            if distance < min_distance:
                min_distance = distance
            t += 0.1
        print min_distance, epsilon
        return (min_distance <= epsilon)

    def boundingRect(self):
        return self.path.boundingRect()

    def paint(self, painter, option, widget):
        painter.setPen(self.color)
        painter.setBrush(self.color)
        painter.strokePath(self.path, painter.pen())

    def distance(self, p0, p1):
        a = p1[0] - p0[0]
        b = p1[1] - p0[1]
        return sqrt(a * a + b * b)


if __name__ == '__main__':
    app = QApplication(argv)
    view = View()
    view.setGeometry(100, 100, 1600, 900)
    view.setWindowTitle('MainWindow')
    view.show()
    app.exec_()

</code>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://www.riverbankcomputing.com/pipermail/pyqt/attachments/20130413/68793159/attachment.html>


More information about the PyQt mailing list