PDA

View Full Version : QSvgRenderer and object's shape



Dusdan
3rd December 2007, 10:26
I'm trying to build an application that is able to interact with a scene built from an SVG file, but the QtSvg API is quite poor on this.

It would be nice if QSvgRenderer::boundsOnElement would return a QPainterPath instead of a QRectF, and if it would possible in some way to interact with the objects defined in the SVG file. Are there some plans to implement these features in the SVG module?

wysota
3rd December 2007, 10:37
Remember about complexity of calculating such path. "Bounds" usually mean a rectangle. To calculate the exact path, you'd have to actually draw the element. And when you do, you can calculate the shape yourself.

Dusdan
3rd December 2007, 10:48
Remember about complexity of calculating such path. "Bounds" usually mean a rectangle. To calculate the exact path, you'd have to actually draw the element. And when you do, you can calculate the shape yourself.but QSvgRenderer::boundsOnElement returns the result of QSvgNode::bounds, which is virtual and implemented in the various node objects. I suppose QSvgEllipse has a well-defined shape, it should not be difficule to give this information to the outer world.

wysota
3rd December 2007, 10:57
I don't think so. Bounds in Qt always mean a rectangle, so bounds in the ellipse item is probably a rectangle holding the ellipse, not the shape of the ellipse. For some elements you could have a shape() method, but then calculating a shape of an object that is a bit more complex than an ellipse is again very time consuming. Especially that the shape can have holes inside, which makes it even harder to calculate (try calculating a shape of the character "&" for example).

Dusdan
3rd December 2007, 11:07
I don't think so. Bounds in Qt always mean a rectangle, so bounds in the ellipse item is probably a rectangle holding the ellipse, not the shape of the ellipse. For some elements you could have a shape() method, but then calculating a shape of an object that is a bit more complex than an ellipse is again very time consuming. Especially that the shape can have holes inside, which makes it even harder to calculate (try calculating a shape of the character "&" for example).I understand bounds means a rectangle, but implementing a shape method should be also straightforward (at least for simple objects). other objects could return an empty QPainterPath.

wysota
3rd December 2007, 11:26
I understand bounds means a rectangle, but implementing a shape method should be also straightforward (at least for simple objects).
Yes, of course it'd be nice to have them.

other objects could return an empty QPainterPath.
No, I don't think this is possible. You'd get a lot of "it doesn't work" reports. If you introduce a method, it has to work for every item, even if it's complex. Of course then it'd be useless, because if you know the type of shape, you can calculate the shape yourself. Otherwise you'd end up with an application that calculates shapes of items all the time.

If you have a simple shape, you can calculate it based on the bounding rectangle yourself.

QPainterPath shape;
shape.addEllipse(boundingRect());

Dusdan
3rd December 2007, 11:31
If you have a simple shape, you can calculate it based on the bounding rectangle yourself.

QPainterPath shape;
shape.addEllipse(boundingRect());but how can yo do that if you don't even know the name of the objects inside the SVG file unless you parse it on your own?

And what iif the object is a path (a pentagon, a star, or whatever?). You can't tell anything from the boundingRect, but the node itself can.

wysota
3rd December 2007, 11:55
but how can yo do that if you don't even know the name of the objects inside the SVG file unless you parse it on your own?
You can't. That's the point when I said it's useless, because every shape might be complex. If you expect an ellipse, you can compute its shape, but if you want to handle any shape, calculating its shape is complex and is equal to drawing the shape on a bitmap and then looking which points are filled and which are not and returning the bitmap mask as a shape.


And what iif the object is a path (a pentagon, a star, or whatever?). You can't tell anything from the boundingRect, but the node itself can.

But it's a complex shape, so calculating it according to your method would result in an empty painter path. Now if you have an object composed of two nodes - an ellipse and a "whatever", your idea would result in a painter path that only contains the ellipse. And that's certainly not the shape you'd be looking for.

I suggest you try with the masking approach and see if it's fast enough for you. So when you scale your svg item, draw it to a pixmap and create a mask for it. Then use the mask to calculate hits yourself or use some heuristics to calculate the shape. See QGraphicsPixmapItem for details on how its shape is calculated.

Dusdan
3rd December 2007, 12:42
I suggest you try with the masking approach and see if it's fast enough for you. So when you scale your svg item, draw it to a pixmap and create a mask for it. Then use the mask to calculate hits yourself or use some heuristics to calculate the shape. See QGraphicsPixmapItem for details on how its shape is calculated.I understand that the shape of a QGraphicsSvgItem is, in principle, complex to determine, but I'm referring to single objects inside the SVG tree, which are quite simple, and in general associated to a QSvgNode, which has a definite shape that's it's completely hidden to the user.