PDA

View Full Version : Diagram Scene Example - two overlapping ellipses



dougluna
16th April 2017, 15:45
Hello forum,

I believe almost everyone in the forum have gone through the diagramscene example that comes along with in the Qt Demo.

I have included a new shape - ellipse in the editor, using this at DiagramItem:


elif self.diagramType == self.Ellipse:
item = QtGui.QGraphicsEllipseItem(-80,-80,160,160)
self.myPolygon = item.shape().toFillPolygon()

Now, i want to have a new shape with two overlapping ellipses, like the figure below:

12441

I tried to use Arc, setStartAngle and setSpanAngle, but i was not successful.

Any hint about it?

Thanks!

wysota
18th April 2017, 20:04
Either compose your item from two ellipse items (so that you have a QGraphicsItem with two children) or implement a custom item type (a descendant of QGraphicsShapeItem) where you will draw the custom shape using QPainter.

dougluna
19th April 2017, 01:24
Hey, thanks for the quick answer!

I tried using a new QPainterPath, doing this:


el1 = QtGui.QGraphicsEllipseItem(-133.3333,-80,160,160).shape()
el2 = QtGui.QGraphicsEllipseItem(-26.66667, -80, 160, 160).shape()
path2 = QtGui.QPainterPath()
path2.addPolygon(el1.toFillPolygon())
path2.addPolygon(el2.toFillPolygon())

self.myPolygon = path2.toFillPolygon()

It's almost perfect, but it also draws a line connecting the two circles.

12442

I believe that is something related to the moveTo function, but I didn't understand it.

Any hints?

d_stranz
20th April 2017, 22:56
From the QPainterPath::toFillPolygon() documentation:


QPolygonF QPainterPath::toFillPolygon(const QTransform &matrix) const

Converts the path into a polygon using the QTransform matrix, and returns the polygon.

The polygon is created by first converting all subpaths to polygons, then using a rewinding technique to make sure that overlapping subpaths can be filled using the correct fill rule.

Note that rewinding inserts addition [sic] lines in the polygon so the outline of the fill polygon does not match the outline of the path.

Note the last line. Your overlapping ellipses create an indeterminate state, so toFillPolygon() is forced to insert an extra edge to make the winding determinate under the default Qt::OddEvenFill filling rule. If you intend for the ellipses to be filled, you could try setting the fill rule to Qt::WindingFill which might fix the problem. If you aren't going to fill them, then don't call this method.

dougluna
26th April 2017, 20:40
From the QPainterPath::toFillPolygon() documentation:



Note the last line. Your overlapping ellipses create an indeterminate state, so toFillPolygon() is forced to insert an extra edge to make the winding determinate under the default Qt::OddEvenFill filling rule. If you intend for the ellipses to be filled, you could try setting the fill rule to Qt::WindingFill which might fix the problem. If you aren't going to fill them, then don't call this method.

Hey, thanks!
I tried to set the Fill Rule as WindingFill, but it didn't fix the problem.


path2 = QtGui.QPainterPath()
path2.setFillRule(Qt.WindingFill)

Any other ideas?

d_stranz
27th April 2017, 00:02
I just looked at your original code again and can't understand why you are doing this:



el1 = QtGui.QGraphicsEllipseItem(-133.3333,-80,160,160).shape()
el2 = QtGui.QGraphicsEllipseItem(-26.66667, -80, 160, 160).shape()
path2 = QtGui.QPainterPath()
path2.addPolygon(el1.toFillPolygon())
path2.addPolygon(el2.toFillPolygon())

self.myPolygon = path2.toFillPolygon()


Creating two QGraphicsEllipseItem instances just to get their polygons doesn't make a lot of sense, when this would be much more straightforward:



path2 = QtGui.QPainterPath()
path2.addEllipse(-133.3333,-80,160,160)
path2.addEllipse(-26.66667, -80, 160, 160)

self.myPolygon = path2.toFillPolygon()


I am also not clear why you need self.myPolygon when there is already a QGraphicsPathItem class. You simply create your QPainterPath, add the two ellipses, and set that path on your QGraphicsPathItem instance. No need for all this conversion to polygons.

dougluna
27th April 2017, 05:43
I am also not clear why you need self.myPolygon when there is already a QGraphicsPathItem class. You simply create your QPainterPath, add the two ellipses, and set that path on your QGraphicsPathItem instance. No need for all this conversion to polygons.

It's because I'm using the Diagram Scene Example, which DiagramItem class is a child of QtGui.QGraphicsPolygonItem.

d_stranz
27th April 2017, 19:45
OK, but I think that it is all those polygon conversions that is causing the extra lines to appear. You can still construct the path using only ellipses and convert the final result to a polygon.

dougluna
28th April 2017, 04:27
I tried what you've suggested, replacing my code with yours and setting the FillRule as WindingFill, but the line is still there. I don't know what more should I try.

d_stranz
28th April 2017, 18:06
I doubt there is anything you can do if you must convert the path to a polygon. It is this conversion that is adding the extra line, as the docs say will happen. In order to create a single, complete polygon from two independent ellipses, it has to connect them.

You could easily solve this problem if you studied the Diagram Scene example and modified it to accept items derived from QAbstractGraphicsShapeItem instead of limiting it to polygon items only. Then you could add your path item without being forced to convert it to a polygon.

dougluna
28th April 2017, 19:42
I doubt there is anything you can do if you must convert the path to a polygon. It is this conversion that is adding the extra line, as the docs say will happen. In order to create a single, complete polygon from two independent ellipses, it has to connect them.

You could easily solve this problem if you studied the Diagram Scene example and modified it to accept items derived from QAbstractGraphicsShapeItem instead of limiting it to polygon items only. Then you could add your path item without being forced to convert it to a polygon.

Yeah, I agree with you. I'll study it. Thanks a lot!