<div dir="ltr"><div><div><div><span style="font-family:courier new,monospace">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.<br>
<br></span></div><span style="font-family:courier new,monospace">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.<br>
<br></span></div><div><span style="font-family:courier new,monospace">The code below demonstrates this problem.<br><br></span></div><div><span style="font-family:courier new,monospace">Any ideas why this is happening or what I'm doing wrong?<br>
<br></span></div><div><span style="font-family:courier new,monospace">Thanks!<br>Tom<br></span></div><div><span style="font-family:courier new,monospace"><br></span></div><span style="font-family:courier new,monospace"><code><br>
from math import sqrt<br>from sys import argv<br><br>from PyQt4.Qt import QApplication<br>from PyQt4.QtCore import QPointF, Qt<br>from PyQt4.QtGui import (<br> QColor,<br> QGraphicsItem,<br> QGraphicsView,<br> QGraphicsScene,<br>
QPainterPath,<br>)<br><br><br>class View(QGraphicsView):<br> def __init__(self, parent=None):<br> super(View, self).__init__(parent)<br> self.epsilon = 11.0<br> self.graphics_scene = QGraphicsScene(self)<br>
self.setScene(self.graphics_scene)<br> self.add_curve()<br><br> def mousePressEvent(self, event):<br> if event.button() == Qt.LeftButton:<br> self.select_item_at(event.x(), event.y())<br>
<br> def select_item_at(self, x, y):<br> self.unselect_items()<br> for item in self.items():<br> if item.contains_point(x, y, self.epsilon):<br> item.set_selected(True)<br> item.update()<br>
<br> def unselect_items(self):<br> for item in self.items():<br> item.set_selected(False)<br> item.update()<br><br> def add_curve(self):<br> color = QColor(255, 0, 0)<br> x0 = 600.0<br>
y0 = 400.0<br> x1 = 800.0<br> y1 = 500.0<br> x2 = 1000.0<br> y2 = 500.0<br> x3 = 1200.0<br> y3 = 400.0<br> control_points = (QPointF(x0, y0), QPointF(x1, y1),<br> QPointF(x2, y2), QPointF(x3, y3))<br>
curve = Curve(color, control_points)<br> self.graphics_scene.addItem(curve)<br><br><br>class Curve(QGraphicsItem):<br> def __init__(self, color, control_points, parent=None, scene=None):<br> super(Curve, self).__init__(parent, scene)<br>
self.selected = False<br> self.color = color<br> self.path = QPainterPath()<br> self.path.moveTo(control_points[0])<br> self.path.cubicTo(*control_points[1:])<br><br> def set_selected(self, selected):<br>
self.selected = selected<br><br> def contains_point(self, x, y, epsilon):<br> p = (x, y)<br> min_distance = float(0x7fffffff)<br> t = 0.0<br> while t < 1.0:<br> point = self.path.pointAtPercent(t)<br>
spline_point = (point.x(), point.y())<br> print p, spline_point<br> distance = self.distance(p, spline_point)<br> if distance < min_distance:<br> min_distance = distance<br>
t += 0.1<br> print min_distance, epsilon<br> return (min_distance <= epsilon)<br><br> def boundingRect(self):<br> return self.path.boundingRect()<br><br> def paint(self, painter, option, widget):<br>
painter.setPen(self.color)<br> painter.setBrush(self.color)<br> painter.strokePath(self.path, painter.pen())<br><br> def distance(self, p0, p1):<br> a = p1[0] - p0[0]<br> b = p1[1] - p0[1]<br>
return sqrt(a * a + b * b)<br><br><br>if __name__ == '__main__':<br> app = QApplication(argv)<br> view = View()<br> view.setGeometry(100, 100, 1600, 900)<br> view.setWindowTitle('MainWindow')<br>
view.show()<br> app.exec_()<br><br></span></div><span style="font-family:courier new,monospace"></code></span><br></div>