Results 1 to 8 of 8

Thread: Improving GV performance

  1. #1
    Join Date
    Aug 2006
    Location
    Bangalore,India
    Posts
    419
    Thanks
    37
    Thanked 53 Times in 40 Posts
    Qt products
    Qt3 Qt4
    Platforms
    Unix/X11

    Default Improving GV performance

    Hi,
    I had asked this kind of question in past but i concentrated more on QGraphicsScene::drawBackground() that time.

    Here follows an example of three possible approach of drawing resistor with nodes. To test while running, select all elements of particular colour and move them together and notice difference for different colours. Obviously the last part, drawing nodes as part of component is faster. But this results in lot of book keeping for my app which I think will not be a nice trade off (sacrificing benifits of gv).

    I am using the first method, where nodes are moved manually. Originally in my app I move them in scene, but for example sake I'm moving in itemChange().

    My questions are:
    1) Using 2nd method (NodesAsChild) doubles number of items when the components are connected. But using first method I will just have a single node for connected components where i just add a reference in nodes component list.
    Will the performance decrease significantly if I use 2nd method ?

    2) Are there any other ways of opimizing any of the methods further ?

    3) Are there any other method of doing what I want, I mean design ?

    I'm using Qt 4.2.3 on kubuntu.

    Qt Code:
    1. #include <QtGui>
    2. #include <cmath>
    3.  
    4. const int NodeRadius = 3;
    5.  
    6. inline qreal distance(const QPointF& p1, const QPointF& p2)
    7. {
    8. qreal dx = p1.x() - p2.x();
    9. qreal dy = p1.y() - p2.y();
    10. return std::sqrt((dx*dx)+(dy*dy));
    11. }
    12.  
    13.  
    14. class Node : public QGraphicsItem
    15. {
    16. public:
    17. enum { Type = UserType + 1 };
    18.  
    19. Node(QGraphicsItem *parent=0, QGraphicsScene *scene=0) : QGraphicsItem(parent,scene)
    20. {
    21. setAcceptedMouseButtons(0);
    22. setFlags(0);
    23. }
    24.  
    25. QRectF boundingRect() const
    26. {
    27. return QRectF(-NodeRadius, -NodeRadius, 2*NodeRadius, 2*NodeRadius);
    28. }
    29.  
    30. void paint(QPainter *p, const QStyleOptionGraphicsItem *o, QWidget *w = 0)
    31. {
    32. Q_UNUSED(o);
    33. Q_UNUSED(w);
    34. p->setRenderHints(QPainter::Antialiasing);
    35. p->setPen(Qt::darkRed);
    36. p->drawEllipse(boundingRect());
    37. }
    38.  
    39. bool contains(const QPointF& pt) const
    40. {
    41. qreal dist = distance(QPointF(0,0),pt);
    42. return (((dist * dist) - (NodeRadius*NodeRadius)) <= 0);
    43. }
    44.  
    45. bool collidesWithItem(QGraphicsItem *other) const
    46. {
    47. Node *port = qgraphicsitem_cast<Node*>(other);
    48. if(!port)
    49. return QGraphicsItem::collidesWithItem(other);
    50. qreal dist = distance(pos(),port->pos());
    51.  
    52. return (dist <= (2 * NodeRadius));
    53. }
    54.  
    55. QPainterPath shape() const
    56. {
    57. path.addEllipse(boundingRect());
    58. return path;
    59. }
    60.  
    61. int type() const
    62. {
    63. return Type;
    64. }
    65.  
    66. };
    67.  
    68. namespace SeparateNodes
    69. {
    70. class Resistor : public QGraphicsItem
    71. {
    72. public:
    73. Resistor(QGraphicsItem *parent = 0, QGraphicsScene *scene=0) : QGraphicsItem(parent,scene)
    74. {
    75. setFlags(ItemIsMovable | ItemIsSelectable | ItemIsFocusable);
    76. Node *n = new Node(0,scene);
    77. n->setPos(-27.0,0.0);
    78. nodes << n;
    79. n = new Node(0,scene);
    80. n->setPos(27.0,0.0);
    81. nodes << n;
    82. }
    83.  
    84. QRectF boundingRect() const
    85. {
    86. return QRectF(-27,-9,54,18);
    87. }
    88.  
    89. void paint(QPainter *p, const QStyleOptionGraphicsItem *o, QWidget *w = 0)
    90. {
    91. Q_UNUSED(o);
    92. Q_UNUSED(w);
    93. p->setPen(Qt::darkMagenta);
    94. p->drawLine(-18, -9, 18, -9);
    95. p->drawLine( 18, -9, 18, 9);
    96. p->drawLine( 18, 9,-18, 9);
    97. p->drawLine(-18, 9,-18, -9);
    98. p->drawLine(-27, 0,-18, 0);
    99. p->drawLine( 18, 0, 27, 0);
    100.  
    101. if( o->state & QStyle::State_Selected)
    102. {
    103. p->setPen(Qt::darkGray);
    104. p->drawRect(boundingRect());
    105. }
    106.  
    107. }
    108.  
    109. QVariant itemChange(GraphicsItemChange change, const QVariant &value)
    110. {
    111. if (change == ItemPositionChange && scene()) {
    112. QPointF newPos = value.toPointF();
    113. QPointF delta = newPos - pos();
    114. foreach(Node *n, nodes)
    115. n->moveBy(delta.x(), delta.y());
    116. }
    117. return QGraphicsItem::itemChange(change, value);
    118. }
    119.  
    120. QList<Node*> nodes;
    121. };
    122. }
    123.  
    124. namespace NodesAsChild
    125. {
    126. class Resistor : public QGraphicsItem
    127. {
    128. public:
    129. Resistor(QGraphicsItem *parent = 0, QGraphicsScene *scene=0) : QGraphicsItem(parent,scene)
    130. {
    131. setFlags(ItemIsMovable | ItemIsSelectable | ItemIsFocusable);
    132. Node *n = new Node(this,scene);
    133. n->setPos(-27.0,0.0);
    134. n = new Node(this,scene);
    135. n->setPos(27.0,0.0);
    136. }
    137.  
    138. QRectF boundingRect() const
    139. {
    140. return QRectF(-27,-9,54,18);
    141. }
    142.  
    143. void paint(QPainter *p, const QStyleOptionGraphicsItem *o, QWidget *w = 0)
    144. {
    145. Q_UNUSED(o);
    146. Q_UNUSED(w);
    147. p->setPen(Qt::darkBlue);
    148. p->drawLine(-18, -9, 18, -9);
    149. p->drawLine( 18, -9, 18, 9);
    150. p->drawLine( 18, 9,-18, 9);
    151. p->drawLine(-18, 9,-18, -9);
    152. p->drawLine(-27, 0,-18, 0);
    153. p->drawLine( 18, 0, 27, 0);
    154.  
    155. if( o->state & QStyle::State_Selected)
    156. {
    157. p->setPen(Qt::darkGray);
    158. p->drawRect(boundingRect());
    159. }
    160.  
    161. }
    162. };
    163. }
    164.  
    165. namespace NodesPartOfResistor
    166. {
    167. class Resistor : public QGraphicsItem
    168. {
    169. public:
    170. Resistor(QGraphicsItem *parent = 0, QGraphicsScene *scene=0) : QGraphicsItem(parent,scene)
    171. {
    172. setFlags(ItemIsMovable | ItemIsSelectable | ItemIsFocusable);
    173. }
    174.  
    175. QRectF boundingRect() const
    176. {
    177. return QRectF(-30,-12,60,24);
    178. }
    179.  
    180. void paint(QPainter *p, const QStyleOptionGraphicsItem *o, QWidget *w = 0)
    181. {
    182. Q_UNUSED(o);
    183. Q_UNUSED(w);
    184. p->setPen(Qt::darkGreen);
    185. p->drawLine(-18, -9, 18, -9);
    186. p->drawLine( 18, -9, 18, 9);
    187. p->drawLine( 18, 9,-18, 9);
    188. p->drawLine(-18, 9,-18, -9);
    189. p->drawLine(-27, 0,-18, 0);
    190. p->drawLine( 18, 0, 27, 0);
    191.  
    192. p->setPen(Qt::darkRed);
    193. p->setRenderHints(QPainter::Antialiasing);
    194. p->drawEllipse(-27-NodeRadius,-NodeRadius,2*NodeRadius,2*NodeRadius);
    195. p->drawEllipse(27-NodeRadius,-NodeRadius,2*NodeRadius,2*NodeRadius);
    196. if( o->state & QStyle::State_Selected)
    197. {
    198. p->setPen(Qt::darkGray);
    199. p->drawRect(boundingRect());
    200. }
    201.  
    202. }
    203. };
    204. }
    205.  
    206. int main(int argc, char *argv[])
    207. {
    208. QApplication app(argc,argv);
    209. QGraphicsScene *scene = new QGraphicsScene(0.,0.,1024,768);
    210. QGraphicsView *view = new QGraphicsView(scene);
    211. view->setDragMode(QGraphicsView::RubberBandDrag);
    212. view->setAcceptDrops(true);
    213. //view->setRenderHints(QPainter::Antialiasing | QPainter::SmoothPixmapTransform);
    214. const int factor = 68;
    215. for(int i = 1; i < 11; i++)
    216. for(int j=1;j<3;j++) {
    217. SeparateNodes::Resistor *r = new SeparateNodes::Resistor(0,scene);
    218. r->setPos(100+i*factor,j*100);
    219. }
    220.  
    221. for(int i = 1; i < 11; i++)
    222. for(int j=1;j<3;j++) {
    223. NodesAsChild::Resistor *r = new NodesAsChild::Resistor(0,scene);
    224. r->setPos(100+i*factor,200+j*100);
    225. }
    226.  
    227. for(int i = 1; i < 11; i++)
    228. for(int j=1;j<3;j++) {
    229. NodesPartOfResistor::Resistor *r = new NodesPartOfResistor::Resistor(0,scene);
    230. r->setPos(100+i*factor,400+j*100);
    231. }
    232.  
    233. view->show();
    234. return app.exec();
    235. }
    To copy to clipboard, switch view to plain text mode 
    The biggest difference between time and space is that you can't reuse time.
    -- Merrick Furst

  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: Improving GV performance

    Have you seen the elastic nodes example that comes with Qt? It does more or less the same you want.

    I'm having trouble here detecting small differences between approaches... Why do you say in the second try the number of nodes will be doubled compared to the first one? You create two new nodes in both cases when adding a resistor.

  3. #3
    Join Date
    Aug 2006
    Location
    Bangalore,India
    Posts
    419
    Thanks
    37
    Thanked 53 Times in 40 Posts
    Qt products
    Qt3 Qt4
    Platforms
    Unix/X11

    Default Re: Improving GV performance

    Quote Originally Posted by wysota View Post
    Have you seen the elastic nodes example that comes with Qt? It does more or less the same you want.
    I've seen that but it uses some animation which i dont need. Anyway both the implementation seems to be similar.

    Quote Originally Posted by wysota View Post
    I'm having trouble here detecting small differences between approaches... Why do you say in the second try the number of nodes will be doubled compared to the first one? You create two new nodes in both cases when adding a resistor.
    I'm sorry for not being clear enough. In the first approach whenever two components are connected, they share a common node and so i delete one of the nodes. I maintain a list of connected components in node, which i update in such case. This also shows visual change by using a brush with solid fill in the node showing connection.
    When a connection happens and I need to move the node(by moving component), I do that in scene's mouse event carefully selecting the appropriate component to control the node movement.

    BTW do you think the second approach is slightly faster(though i cant see difference now) when there's no connection since the parent item includes child's boundRect there by resulting in less updates ?
    The biggest difference between time and space is that you can't reuse time.
    -- Merrick Furst

  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: Improving GV performance

    Quote Originally Posted by Gopala Krishna View Post
    I've seen that but it uses some animation which i dont need.
    I meant to take a look how the nodes are tied to the "rubbers".

    I'm sorry for not being clear enough. In the first approach whenever two components are connected, they share a common node and so i delete one of the nodes.
    I don't think this is implemented in the code you provided. I was expecting something like that but couldn't find it.

    BTW do you think the second approach is slightly faster(though i cant see difference now) when there's no connection since the parent item includes child's boundRect there by resulting in less updates ?
    No, I don't think it makes the whole thing faster. boundingRect of the parent doesn't have to include boundingRects of all its children.

    I think you should make the connectors separate objects and keep pointers to them in your items. Then when you move the item, update its connector in a way you see fit - either by moving only the ending point of the connector or by iterating over all its points and moving each next one sliightly less than the previous one (provided that your connectors have more than two points, of course).

  5. The following user says thank you to wysota for this useful post:

    Gopala Krishna (2nd June 2007)

  6. #5
    Join Date
    Aug 2006
    Location
    Bangalore,India
    Posts
    419
    Thanks
    37
    Thanked 53 Times in 40 Posts
    Qt products
    Qt3 Qt4
    Platforms
    Unix/X11

    Default Re: Improving GV performance

    Thanks for replying

    Quote Originally Posted by wysota View Post
    I don't think this is implemented in the code you provided. I was expecting something like that but couldn't find it.
    It is quite difficult to compress that code into a small example, so I didn't do it

    Quote Originally Posted by wysota View Post
    No, I don't think it makes the whole thing faster. boundingRect of the parent doesn't have to include boundingRects of all its children.
    Thanks for this information. I wont try 2nd method in my original app. Probably the third approach can be tried , but I'm afraid if the performance might not improve significantly (due to lot of bookkeeping)


    Quote Originally Posted by wysota View Post
    I think you should make the connectors separate objects and keep pointers to them in your items. Then when you move the item, update its connector in a way you see fit - either by moving only the ending point of the connector or by iterating over all its points and moving each next one sliightly less than the previous one (provided that your connectors have more than two points, of course).
    Can you elaborate more ? I didn't get this clearly ? What do you mean by connector - node or a wire ?
    The biggest difference between time and space is that you can't reuse time.
    -- Merrick Furst

  7. #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: Improving GV performance

    Wire, of course.

  8. #7
    Join Date
    Aug 2006
    Location
    Bangalore,India
    Posts
    419
    Thanks
    37
    Thanked 53 Times in 40 Posts
    Qt products
    Qt3 Qt4
    Platforms
    Unix/X11

    Default Re: Improving GV performance

    Well , actually i dont have problem with wire for now. What exactly I do is, if a node has more than 2 items(component or wire), i fill the node with solid brush. If the components are moved apart I add a wire between.

    I installed opensource version of qt-4.3 for windows and the result didn't differ much

    I made an important observation though:
    Select all the components and move them all. Notice the speed of moving components.
    Now set the dactor variable in my snippet to 54
    Qt Code:
    1. const int factor = 54;
    To copy to clipboard, switch view to plain text mode 
    Doing so will overlap the nodes of elements in a row.
    Now see the difference!

    With this what I inferred was, there are less number of updates(with bigger update region) and hence faster.
    Can I use some tricks to fake situation like this so that when components are moved ?

    I went through the chip demo, but it doesn't use child items and also the items are rectangular. Hence i can't directly compare chip and my code. Still performance seems to be better in chip. I welcome any suggestion and correction if i am wrong.
    I seriosly want to improve the performance of my app. A client doesn't care what technology you use, he just wants good result. So please do help me. Should I fallback to third approach ?
    The biggest difference between time and space is that you can't reuse time.
    -- Merrick Furst

  9. #8
    Join Date
    Aug 2006
    Location
    Bangalore,India
    Posts
    419
    Thanks
    37
    Thanked 53 Times in 40 Posts
    Qt products
    Qt3 Qt4
    Platforms
    Unix/X11

    Default Re: Improving GV performance

    After I read this post #69 , I tried this
    Qt Code:
    1. view->setViewportUpdateMode(QGraphicsView::SmartViewportUpdate);
    To copy to clipboard, switch view to plain text mode 
    and speed improvements are amazing . may be I can use this when items are moving and switch back to default in other cases.

    Never the less, i still want answer for my questions above since the app has to be compatible with qt-4.2
    The biggest difference between time and space is that you can't reuse time.
    -- Merrick Furst

Similar Threads

  1. Performance problems with overlapping qgraphicsitems
    By brjames in forum Qt Programming
    Replies: 13
    Last Post: 4th May 2008, 21:42
  2. GraphicsView performance problems
    By Gopala Krishna in forum Qt Programming
    Replies: 79
    Last Post: 8th August 2007, 17:32
  3. Replies: 1
    Last Post: 4th October 2006, 16:05
  4. [QT 4] QTextEdit performance
    By fellobo in forum Qt Programming
    Replies: 8
    Last Post: 6th March 2006, 19:27
  5. Increasing performance from Qtextedit, listview, etc?
    By taylor34 in forum Qt Programming
    Replies: 1
    Last Post: 16th February 2006, 10:20

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.