1

I'm having difficulty converting points in the coordinates of one item to the coordinates of another item, like so

from PySide import QtGui, QtCore
import sys

class Editor(QtGui.QMainWindow):
    def __init__(self, parent=None):
        super(Editor, self).__init__(parent)

        scene = QtGui.QGraphicsScene()

        line0 = QtGui.QGraphicsLineItem(  10 , 210 ,  10 , 300 )
        line1 = QtGui.QGraphicsLineItem( 100 , 210 , 100 , 300 )

        scene.addItem( line0 )
        scene.addItem( line1 )

        view = QtGui.QGraphicsView()
        view.setScene( scene )

        self.setGeometry( 250 , 250 , 600 , 600 )
        self.setCentralWidget(view)
        self.show()

        print line1.mapToItem( line0 , QtCore.QPoint( 0 , 0 ) )  # QPoint( 0 , 0 ) in line0's coordinates -> line1's coordinates
        print line1.mapToScene( QtCore.QPointF( 0 , 0 ) )        # QPoint( 0 , 0 ) in line0's coordinates -> screen coordinates


if __name__=="__main__":
    app=QtGui.QApplication(sys.argv)
    myapp = Editor()
    sys.exit(app.exec_())

The results appear to indicate that the transformation failed

PySide.QtCore.QPointF(0.000000, 0.000000)
PySide.QtCore.QPointF(0.000000, 0.000000)
Olumide
  • 5,397
  • 10
  • 55
  • 104

1 Answers1

1

I think you're assuming that the coordinate system for an item starts in its topLeft boundingRect but it's not. In addition, another concept is that the coordinates you pass to the QGraphicsLineItem constructor are relative to that item, not to the coordinates of the scene.

p1(x1, y1)
    ╲
     ╲
      ╲
       ╲
        ╲
         ╲
        p2(x2, y2)
The coordinates (x1, y1) and (x2, y2) are relative to the QGraphicsLineItem

So if you want to obtain the difference of positions between both lines with respect to line1 you must map the value of p1() of the QLineF associated with the QGraphicsLineItem:

print(line1.mapToItem(line0 , line0.line().p1()) -   line1.line().p1())
      └----p1 that belongs to line0 ----------┘    └--p1 that belongs--┘    
              with respect to line1            to line1 with respect to line1

Output:

PySide.QtCore.QPointF(-90.000000, 0.000000)

Explanation:

The Graphics View Framework handles 3 types of coordinate system:

  • Coordinates regarding the viewport of the QGraphicsView, that is, the coordinates depend on the view
  • A coordinate system with respect to the scene, all views have the same coordinate system.
  • A coordinate system with respect to each item

An analogy can be made with an image or video recording system. The first coordinate system refers to what would be seen with respect to the camera, this depends on each camera that is analogous to the QGraphicsView. The second coordinate system is relative to the real world, it does not depend on the camera. And the third coordinate system is with respect to an element in the scene, for example an actor

The point (0, 0) of the coordinate systems of the item matches the position of the item in the scene. In your case, the position of your items is (0, 0) with respect to the scene (check it with print(line0.pos()).

To understand the following code visually is the same but conceptually not.

class Editor(QtGui.QMainWindow):
    def __init__(self, parent=None):
        super(Editor, self).__init__(parent)
        scene = QtGui.QGraphicsScene()
        line0 = QtGui.QGraphicsLineItem(0, 0, 0, 90)
        line0.setPos(10, 210)
        line1 = QtGui.QGraphicsLineItem(0, 0, 0, 90)
        line1.setPos(100, 210)
        scene.addItem( line0 )
        scene.addItem( line1 )
        view = QtGui.QGraphicsView()
        view.setScene( scene )
        self.setGeometry( 250 , 250 , 600 , 600 )
        self.setCentralWidget(view)
        self.show()

eyllanesc
  • 235,170
  • 19
  • 170
  • 241
  • The result is identical to `line0.line().p1() - line1.line().p1()`! ... What makes me wonder if there is a relative coord system lurking is that the `value` passed to `QGraphicsItem::itemChange(GraphicsItemChange change, const QVariant &value)` is *always* relative to the initial position of the item. What I'm _really_ looking to do is to prevent the line item on the RHS from being dragged past the line item on the LHS. Therefore it would be a lot simpler to reason in terms of the relative offset of the line item. – Olumide Apr 15 '19 at 19:36
  • @Olumide In this case it coincides since the position of the items with respect to the scene(`line0.pos() == line1.pos() == QtCore.QPointF(0, 0)`) are the same but in the general case there is not. On the other hand, the position obtained from the itemChange is the position of the item with respect to the scene. I think you have an XY problem, what is your ultimate goal? Do you want the QGraphicsLineItem not to be separated beyond a threshold? And that threshold in which the coordinate system is measured? – eyllanesc Apr 15 '19 at 19:41
  • @Olumide [cont.] Currently, your example is trivial since it does not have transformations such as scaling, rotation, etc. I recommend reading https://doc.qt.io/qt-5/graphicsview.html to understand the coordinate systems – eyllanesc Apr 15 '19 at 19:42
  • Thanks for the explanation. The behaviour/relation between the line items are no different from the handles of a splitter. So perhaps I should just see how far I can go with a splitter. (I'm starting to develop the sense that complicated solutions in Qt often reinvent some sort feature that Qt already has. Qt is a very old and vast framework and there's a good chance that it's implemented most UI features and behaviours that a user may require.) – Olumide Apr 15 '19 at 21:19
  • I'm up for a [chat](https://chat.stackoverflow.com/rooms/191877/discussion-between-olumide-and-eyllanesc) if you want. – Olumide Apr 15 '19 at 21:22