Results 1 to 10 of 10

Thread: transform() vs pos() for QGraphicsItem

  1. #1
    Join Date
    Apr 2009
    Posts
    10
    Qt products
    Platforms
    Unix/X11

    Question transform() vs pos() for QGraphicsItem

    Hi all, I'm new QT so please excuse the following if it's obvious.

    There seems to be two item-based coordinate systems for QGraphics items (at least for translations) and they seem to be independent and have a cumulative effect. One you can access via setPos(), moveBy() etc the other via translate() etc by setting the transform matrix.

    I've read in other posts that translate() is only provided for "completeness" and we should use pos() and setPos(), and in the API docs that translate and moveBy are "conceptually separate" . I'm of a mathematical bent and I like affine transforms. I want to set up complex nested transformations which just amounts to matrix multiplication for the affine coordinate system, but it would be a real pain to have to set all movements in a separate co-ordinate system from scaling and rotations ...

    Here is an example (it's pyqt but should be clear)...

    I've created an item in a scene, initially the scenePos and pos are the same:
    Qt Code:
    1. >>> self.scenePos()
    2. PyQt4.QtCore.QPointF(10.0, 10.0)
    3. >>> self.pos()
    4. PyQt4.QtCore.QPointF(10.0, 10.0)
    To copy to clipboard, switch view to plain text mode 

    the translation shows 0,0:
    Qt Code:
    1. >>> t=self.transform();t.dx();t.dy()
    2. 0.0
    3. 0.0
    To copy to clipboard, switch view to plain text mode 

    now translate it to the origin in scene coords:
    Qt Code:
    1. >>> self.translate(-10,-10)
    2. >>> t=self.transform();t.dx();t.dy()
    3. -10.0
    4. -10.0
    5. >>> self.scenePos()
    6. PyQt4.QtCore.QPointF(0.0, 0.0)
    7. >>> self.pos()
    8. PyQt4.QtCore.QPointF(10.0, 10.0)
    To copy to clipboard, switch view to plain text mode 
    you'll notice that the translation and pos coordinate systems are working against each other to have no net effect in the scene coordinates

    Now we can move it back with moveBy() which affects the pos() coordinate system not the translation coordinate system:
    Qt Code:
    1. >>> self.moveBy(10,10)
    2. >>> self.scenePos()
    3. PyQt4.QtCore.QPointF(10.0, 10.0)
    4. >>> self.pos()
    5. PyQt4.QtCore.QPointF(20.0, 20.0)
    6. >>> t=self.transform();t.dx();t.dy()
    7. -10.0
    8. -10.0
    To copy to clipboard, switch view to plain text mode 

    I guess my question boils down to the following: since the affine transform coordinate system is much nicer and richer than the separate movement coordinate system, is it OK to base my code just on the former and always have the pos() at (0,0) or will this bite me later with things like boundingRect() shape() etc ?

  2. #2
    Join Date
    Jan 2006
    Location
    Warsaw, Poland
    Posts
    33,359
    Thanks
    3
    Thanked 5,015 Times in 4,792 Posts
    Qt products
    Qt3 Qt4 Qt5 Qt/Embedded
    Platforms
    Unix/X11 Windows Android Maemo/MeeGo
    Wiki edits
    10

    Default Re: transform() vs pos() for QGraphicsItem

    Treat "pos" as an anchor of child item's origin to its parent's coordinate system. If you don't set a position explicitely, child's origin will be placed at the origin of its parent's. translate() affects the way how the item is drawn and interacted with. You can replace "pos" with it but be aware that you won't be able to recover the item's whereabouts in any meaningful way from the transformation matrix.

    "pos" is easier to use than translate() and it gives a different effect when used together with scaling or rotating. But you don't have to change the initial position - you can stay with (0;0) and use the transformation matrix only.
    Your biological and technological distinctiveness will be added to our own. Resistance is futile.

    Please ask Qt related questions on the forum and not using private messages or visitor messages.


  3. #3
    Join Date
    Apr 2009
    Posts
    10
    Qt products
    Platforms
    Unix/X11

    Default Re: transform() vs pos() for QGraphicsItem

    I've recoded my app to use just the transformation matrix and leave pos() set at [0,0]. There where a couple of gotcha's..

    • the default implementation of mouseMoveEvent() uses the pos() coordinate system, so this has to be re-implemented using translation (including dealing with other selected items).
    • moveBy() uses the pos() coordinate system
    • translate/rotate/scale uses the translate() coordinate system
    • the mapToXXX functions take into account both pos() and translate() coordinate systems


    l think the pos() coordinate system is totally redundant, and it's a pain carrying around two coordinate systems for each item in a scene, esp when they are rotated and scaled about arbitrary points, or nested.

    It is easier to use pos() for movement, but only because of a couple of helper functions such as setPos() and pos() - these can be easily implemented to use the transform matrix. e.g. the items [0,0] point in it's parent frame (what pos() returns for the pos() coordinate system) will be [transform().dx(),transform.dy()]

    I doubt the pos() coordinate system will be joined to the translate() one anytime soon, but the docs could be made a lot clearer on describing these two coordinate systems and how to do things like rotate about some point in the scene when both the translation and the position are not at the origin.

  4. #4
    Join Date
    Jan 2006
    Location
    Warsaw, Poland
    Posts
    33,359
    Thanks
    3
    Thanked 5,015 Times in 4,792 Posts
    Qt products
    Qt3 Qt4 Qt5 Qt/Embedded
    Platforms
    Unix/X11 Windows Android Maemo/MeeGo
    Wiki edits
    10

    Default Re: transform() vs pos() for QGraphicsItem

    Quote Originally Posted by aalexei View Post
    l think the pos() coordinate system is totally redundant,
    Unfortunately for you most users of GraphicsView would say otherwise.

    and it's a pain carrying around two coordinate systems for each item in a scene, esp when they are rotated and scaled about arbitrary points, or nested.
    I think you must be doing something strange. pos() help with rotations and scaling, not makes it more difficult.

    It is easier to use pos() for movement, but only because of a couple of helper functions such as setPos() and pos() - these can be easily implemented to use the transform matrix. e.g. the items [0,0] point in it's parent frame (what pos() returns for the pos() coordinate system) will be [transform().dx(),transform.dy()]
    It's not that easy. If you do translate-rotate-translate then you won't be able to tell the position of each point in the item relative to the parent item unless you know you actually did perform rotation (and what it was and when it was).

    I doubt the pos() coordinate system will be joined to the translate() one anytime soon,
    I can assure you it won't. translate() is only for completeness with GraphicsView, pos() is more intuitive and easier to use so it will always be preferred over pure maths.

    but the docs could be made a lot clearer on describing these two coordinate systems and how to do things like rotate about some point in the scene when both the translation and the position are not at the origin.
    To me, if you are walking into pure math, you're stepping out of the "average person" world and since that moment you are on your own. If you do use translate(), I'd assume you knew what you were doing so proper matrix operations should be easy for you.
    Your biological and technological distinctiveness will be added to our own. Resistance is futile.

    Please ask Qt related questions on the forum and not using private messages or visitor messages.


  5. #5
    Join Date
    Apr 2009
    Posts
    10
    Qt products
    Platforms
    Unix/X11

    Default Re: transform() vs pos() for QGraphicsItem

    Quote Originally Posted by wysota View Post
    Unfortunately for you most users of GraphicsView would say otherwise.
    You can simply re-implement pos() and moveBy() to use the items transform matrix. Most users would never notice. It only bites you if you've had to write code to take both into account.

    Quote Originally Posted by wysota View Post
    I think you must be doing something strange. pos() help with rotations and scaling, not makes it more difficult.
    In what way? It's just another coordinate system that the affine one (the one that let's you do scaling and rotation) sits on top of. Why add that complexity? It seems completely unnecessary.

    Quote Originally Posted by wysota View Post
    It's not that easy. If you do translate-rotate-translate then you won't be able to tell the position of each point in the item relative to the parent item unless you know you actually did perform rotation (and what it was and when it was).
    You've lost me here ... the items origin in the parent frame will still be at the transform's .dx() and .dy(). try it ... The other points on the item won't be so easy, but to map those to the parent you will still need to use the transform. You can't even do that in the pos() coordinate system as it doesn't support rotations and scaling. If you look at the source for mapToParent(), this is exactly what it does:

    Qt Code:
    1. return transform().map(point) + d_ptr->pos;
    To copy to clipboard, switch view to plain text mode 


    Quote Originally Posted by wysota View Post
    I can assure you it won't. translate() is only for completeness with GraphicsView, pos() is more intuitive and easier to use so it will always be preferred over pure maths.
    They do the same thing. There is nothing that you can do with pos() and family, that you can't do with translate() and the transform. That is the whole point of affine transformations - you can do any 2-D graphics transformation with them. It just seems pointless to carry around another coordinate system for no apparent reason. Hardly pure maths


    Quote Originally Posted by wysota View Post
    To me, if you are walking into pure math, you're stepping out of the "average person" world and since that moment you are on your own. If you do use translate(), I'd assume you knew what you were doing so proper matrix operations should be easy for you.
    translate() does the same thing as moveBy(). they just work on two different co-ordinate systems and each item in a view has both. If you want to do something like rotate an item about a point in the scene you have to take into account both - this is what the mapToXXX set of functions have to do. Now, you can simplify your life by keeping translate() at [0,0] but then you lose the ability to do affine transforms in a nice way eg you can't just multiply them etc. Alternatively you can keep pos() at (0,0). If they both do the same thing one is redundant - may as well keep the more powerful one and ditch the other.

  6. #6
    Join Date
    Jan 2006
    Location
    Warsaw, Poland
    Posts
    33,359
    Thanks
    3
    Thanked 5,015 Times in 4,792 Posts
    Qt products
    Qt3 Qt4 Qt5 Qt/Embedded
    Platforms
    Unix/X11 Windows Android Maemo/MeeGo
    Wiki edits
    10

    Default Re: transform() vs pos() for QGraphicsItem

    Quote Originally Posted by aalexei View Post
    You can simply re-implement pos() and moveBy() to use the items transform matrix. Most users would never notice. It only bites you if you've had to write code to take both into account.
    There is a special flag - ItemIgnoresTransformations - if would be useless if pos() was implemented using the transformation matrix.

    I'm also not sure if it is possible to retrieve the position from the matrix if other operations have been applied to it in the meantime. Remember you can apply any changes to the matrix, including shearing and applying the identity matrix. With pos() you have a simple way of knowing the offset between the item and its parent.

    Why add that complexity? It seems completely unnecessary.
    What seems and what is are two different things.

    They do the same thing. There is nothing that you can do with pos() and family, that you can't do with translate() and the transform.
    Not really, see ItemIgnoresTransformations.
    Your biological and technological distinctiveness will be added to our own. Resistance is futile.

    Please ask Qt related questions on the forum and not using private messages or visitor messages.


  7. #7
    Join Date
    Apr 2009
    Posts
    10
    Qt products
    Platforms
    Unix/X11

    Default Re: transform() vs pos() for QGraphicsItem

    Quote Originally Posted by wysota View Post
    There is a special flag - ItemIgnoresTransformations - if would be useless if pos() was implemented using the transformation matrix.
    Can't see how this wouldn't be trivial to implement. If the flag is set, only change the translation part of the affine transform. Just as for ItemIsMovable - you just need to switch the behaviour of the code if the flag is set.

    Quote Originally Posted by wysota View Post
    I'm also not sure if it is possible to retrieve the position from the matrix if other operations have been applied to it in the meantime. Remember you can apply any changes to the matrix, including shearing and applying the identity matrix. With pos() you have a simple way of knowing the offset between the item and its parent.
    It's absolutely possible. Look at the source to mapToXXX functions.

  8. #8
    Join Date
    Jan 2006
    Location
    Warsaw, Poland
    Posts
    33,359
    Thanks
    3
    Thanked 5,015 Times in 4,792 Posts
    Qt products
    Qt3 Qt4 Qt5 Qt/Embedded
    Platforms
    Unix/X11 Windows Android Maemo/MeeGo
    Wiki edits
    10

    Default Re: transform() vs pos() for QGraphicsItem

    Quote Originally Posted by aalexei View Post
    Can't see how this wouldn't be trivial to implement. If the flag is set, only change the translation part of the affine transform.
    You can always set an arbitrary transform on the item and this would affect the functionality. It would probably also not work with nested items (but I'm not sure how ItemIgnoresTransformations works in this case, so I won't say I'm sure of that). Besides operating on matrices is more expensive than just operating on a QPoint so if you can have 90% of the functionality for the cost of 30%, I don't see why not do it and only have a slowdown with the remaining 10%.

    But I won't argue with you - if you think you are right then reimplement appropriate routines in Qt and check if everything works as it used to before. If it does, send a patch to Qt Software with your arguments and maybe they will agree with you.
    Your biological and technological distinctiveness will be added to our own. Resistance is futile.

    Please ask Qt related questions on the forum and not using private messages or visitor messages.


  9. #9
    Join Date
    Apr 2012
    Posts
    13
    Qt products
    Qt4
    Platforms
    Unix/X11

    Default Re: transform() vs pos() for QGraphicsItem

    It is not just setPos(), but also setScale() and setRotation(), and setTransformations(), that do not affect the separate transform() matrix. (e.g. transform() returns the same matrix before and after a call to setScale().)

    I won't argue which is the best approach for the API, but I will say that the Qt approach is not conventional: most graphics programming texts approach use a single transform matrix that a rotation operation would change.

    And the Qt documentation must be read VERY carefully. For example: "The scale is combined with the item's rotation(), transform() and transformations() to map the item's coordinate system to the parent item." Why doesn't it mention pos()? Then you should follow the link to "Transformations" to learn what "combine" means. And "scale a transformation" is QTransform.scale(), not the same thing as calling "setScale()" on a graphic item. QTransform.scale() is a verb setter, QGraphicsItem.scale() is a noun getter. QTransform is separate from QGraphicsTransform. transform() is not the same as transformations(), even though both are noun getters with too similar names.

    This discussion is related to how to serialize a QGraphicsItem. Do you need to serialize (pos(), scale(), rotation(), transform(), transformations()) or can you somehow get a single matrix representing all of those?

  10. #10
    Join Date
    Jan 2006
    Location
    Warsaw, Poland
    Posts
    33,359
    Thanks
    3
    Thanked 5,015 Times in 4,792 Posts
    Qt products
    Qt3 Qt4 Qt5 Qt/Embedded
    Platforms
    Unix/X11 Windows Android Maemo/MeeGo
    Wiki edits
    10

    Default Re: transform() vs pos() for QGraphicsItem

    Quote Originally Posted by bootchk View Post
    It is not just setPos(), but also setScale() and setRotation(), and setTransformations(), that do not affect the separate transform() matrix. (e.g. transform() returns the same matrix before and after a call to setScale().)
    The methods you mention were introduced in Qt 4.6 thus the discussion in this thread does not take them into consideration.

    I won't argue which is the best approach for the API, but I will say that the Qt approach is not conventional: most graphics programming texts approach use a single transform matrix that a rotation operation would change.
    Those methods were added to QGraphicsItem as a convenience. Therefore both "old" and "new" ways exist to operate on the item.

    Why doesn't it mention pos()?
    Because pos() is not part of the "transformation".

    Then you should follow the link to "Transformations" to learn what "combine" means. And "scale a transformation" is QTransform.scale(), not the same thing as calling "setScale()" on a graphic item. QTransform.scale() is a verb setter, QGraphicsItem.scale() is a noun getter. QTransform is separate from QGraphicsTransform. transform() is not the same as transformations(), even though both are noun getters with too similar names.
    Again, some classes and methods are a later addition to Qt. Since you can't remove something that's already defined in an earlier release, some functionality is "doubled".

    This discussion is related to how to serialize a QGraphicsItem. Do you need to serialize (pos(), scale(), rotation(), transform(), transformations()) or can you somehow get a single matrix representing all of those?
    The attributes you mention are not part of the object definition thus this is not about serializing the item but rather the scene (as in getting a snapshot of current mappings of items in the scene). There is no built-in mechanism for that, you need to query all the attributes you are interested in on your own.
    Your biological and technological distinctiveness will be added to our own. Resistance is futile.

    Please ask Qt related questions on the forum and not using private messages or visitor messages.


Similar Threads

  1. Where to apply transform? iterm or QPainter?
    By lni in forum Qt Programming
    Replies: 1
    Last Post: 29th January 2009, 08:40
  2. Replies: 1
    Last Post: 22nd August 2008, 09:12
  3. Smooth pixmap transform in QGraphicsView problem
    By spud in forum Qt Programming
    Replies: 1
    Last Post: 24th October 2007, 16:47

Tags for this Thread

Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  
Digia, Qt and their respective logos are trademarks of Digia Plc in Finland and/or other countries worldwide.