[PyQt] selecting a bezier curve
Tom Brown
nextstate at gmail.com
Sun Apr 14 02:57:11 BST 2013
Sure! My solution is below.
<code>
from math import sqrt
from sys import argv
from PyQt4.Qt import QApplication
from PyQt4.QtCore import QPoint, 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):
point = self.mapToScene(QPoint(x, y))
self.unselect_items()
for item in self.items():
if item.contains_point(point.x(), point.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>
On Sat, Apr 13, 2013 at 6:52 PM, Christophe BAL <projetmbc at gmail.com> wrote:
> Hello,
> can you give your solution ?
>
> Christophe.
>
>
> 2013/4/14 Tom Brown <nextstate at gmail.com>
>
>> Ah! I found the QGraphicsView.mapToScene() method. This solved my problem.
>>
>> Thanks!
>> Tom
>>
>>
>> On Sat, Apr 13, 2013 at 6:06 PM, Tom Brown <nextstate at gmail.com> wrote:
>>
>>> I've found that this problem isn't specific to a bezier curve. If I
>>> change the curve to a straight line, I observe the same problem. So, I
>>> would think that it has something to do with the way I'm setting up the
>>> view.
>>>
>>> Any ideas would be appreciated.
>>>
>>> Thanks!
>>> Tom
>>>
>>>
>>>
>>> On Sat, Apr 13, 2013 at 5:15 PM, Tom Brown <nextstate at gmail.com> wrote:
>>>
>>>> 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>
>>>>
>>>
>>>
>>
>> _______________________________________________
>> PyQt mailing list PyQt at riverbankcomputing.com
>> http://www.riverbankcomputing.com/mailman/listinfo/pyqt
>>
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://www.riverbankcomputing.com/pipermail/pyqt/attachments/20130413/055c35c1/attachment-0001.html>
More information about the PyQt
mailing list