I am creating a vector editing window. I add elements to a QGraphicsScene
and display it. I am yet writing code so that when moving a node, it moves the underlying path as well.
But how do I move the two joints of the path that lead to the point I try to move? I would first need to break the QPainterPath into subpaths (how? the only method that breaks into subpaths seems to be toSubpathPolygon but polygon is a set of point which looses curve information…) then find the point before the one I am trying to change. How would I go about doing that?
See the screenshots: https://i.sstatic.net/vSoMW.jpg
When moving the node, only one joint gets updated.
The square nodes are defined like this:
class OnCurvePointItem(QGraphicsRectItem):
def __init__(self, x, y, width, height, pointX, pointY, pen=None, brush=None, parent=None):
super(OnCurvePointItem, self).__init__(x, y, width, height, parent)
self.setFlag(QGraphicsItem.ItemIsMovable)
self.setFlag(QGraphicsItem.ItemIsSelectable)
self.setFlag(QGraphicsItem.ItemSendsGeometryChanges)
if pen is not None: self.setPen(pen)
if brush is not None: self.setBrush(brush)
# Absolute coordinates of the points in the path
self._pointX = pointX
self._pointY = pointY
""" # disabled, trying to use itemChange instead.
def mouseMoveEvent(self, event):
pos = event.pos()
print(pos)
super(OnCurvePointItem, self).mouseMoveEvent(event)
path = self.scene()._outlineItem.path()
path.setElementPositionAt(0, pos.x(), pos.y())
self.scene()._outlineItem.setPath(path)
#self.scene().update()
"""
def itemChange(self, change, value):
#print(change)
if change == QGraphicsItem.ItemPositionHasChanged:
# this is the outline path to mutate, stashed in the scene
path = self.scene()._outlineItem.path()
#for i in range(path.elementCount()):
# elem = path.elementAt(i)
# if elem.isCurveTo(): kind = "curve"
# elif elem.isLineTo(): kind = "line"
# else: kind = "move"
# print("{}: {} {}".format(kind, elem.x, elem.y))
#print()
# self.pos() is relative to the original position in the scene
# hardcoding element 0 till I store index in the item object
path.setElementPositionAt(0, self._pointX+self.pos().x(), self._pointY+self.pos().y())
self.scene()._outlineItem.setPath(path)
return QGraphicsItem.itemChange(self, change, value)
Thank you, I'm rather stuck from here. Is there eventually any simple Qt example of vector edition you know of?
I found a piece of software called Carve but the codebase is rather intricated and I can't find anything relevant to what I am doing here…
In the end I chose to just use the points coordinates on each move to create a new updated path from scratch and calling QGraphicsPathItem.updatePath()
when a move happens.
This avoid the need for low-level manipulation, something QPainterPath isn’t exactly made for anyway.