How can I draw a shape area around a polyline? So I can move polyline with mouse.
-
@helloworld12345
by polyline you mean a list of points right?
I think the easiest would be to draw rectangles for each line segment and merge them each into a QPainterPath. When you are done callQPainterPath::toFillPolygon()
.
Now the problem is just to calculate the coordinates of the rectangles based on the line-segments and your desired spacing. -
@raven-worx said in How can I draw a shape area around a polyline? So I can move polyline with mouse.:
toFillPolygon()
Thanks raven.
- I didn't use toFillPolygon, but use addPolygon, it works partially, most but not all area can be dragged by mouse.
- I added eclipses around the points of polyline since rect can't cover the turning area of polyline, but it seems the eclipses didn't response when I use mouse to drag it, you have any idea? Below is the simplified code.
def shape(self): final_shape = QPainterPath() ## ##here calcuclate the each polygon for each line session, store the points in polygons ## for k in range(0, len(polygons)): polygon = QPolygonF([polygons[k][0], polygons[k][1], polygons[k][2], polygons[k][3]]) final_shape.addPolygon(polygon) for p in self._polyline: newpath = QPainterPath() newpath.addEllipse(p, 15, 15) final_shape = final_shape.united(newpath) return final_shape
-
@raven-worx if you happen to know some example code in which several graphics(rect + ellipse) are combined in shape, that would definitely help a lot.
-
@raven-worx
you can see I drew a rect for each line session, an ellipse for each point(rect doesn't cover the point). With all these rects and ellipses, the polyline is covered totally.But at the left-most, right-most, up-most, bottom-most area of the shape, my mouse can't drag the polyline. And at the intersection area of rect and ellipse, I can't drag either, does any one have idea?
In paint function, I draw my shape area, please see below picture. My polyline is yellow, shape area is red, the area can't be dragged by mouse is pointed out by black lines.
I also attached my code here.
def shape(self): selectionOffset = 15 path = QPainterPath() pn = [p for p in self._polyline] for k in range(0, len(pn) -1): line = QLineF(pn[k], pn[k+1]) radAngle = line.angle()* math.pi / 180 dx = selectionOffset * math.sin(radAngle) dy = selectionOffset * math.cos(radAngle) offset1 = QPointF(dx, dy) offset2 = QPointF(-dx, -dy) rect_p1 = line.p1() + offset1 rect_p2 = line.p1() + offset2 rect_p3 = line.p2() + offset2 rect_p4 = line.p2() + offset1 polygon_new = QPolygonF([rect_p1, rect_p2, rect_p3, rect_p4]) path.addPolygon(polygon_new) for m in range(0, len(pn)): path.addEllipse(pn[m], 15, 15) return path
-
@helloworld12345
try setting the fillRule of the path toQt::WindingFill
-
I would try this:
- Find out the coordinates of a point which should work for dragging, but doesn't
- Make a debug function that calls yourPolyline->contains(thatPoint)
- Step into the contains method and see where the code decides that the point is not part of your polyline's shape
-
I think I found the root cause, at the beginning I thought shape() function will totally override boundingRect(). But it turns out boundingRect() still functions even I used shape(). When shape() area is out of the area of boundingRect(), the extra part from shape() that if out of the region of boundingRect() will be detected.
Then I enlarge the the area of boundingRect() to make sure it is larger than shape() area, then it seems good now.
Does it make sense to you?
-
Hi, this is what I replied to raven-worx, does it make sense to you?
I think I found the root cause, at the beginning I thought shape() function will totally override boundingRect(). But it turns out boundingRect() still functions even I used shape(). When shape() area is out of the area of boundingRect(), the extra part from shape() that if out of the region of boundingRect() will be detected.
Then I enlarge the the area of boundingRect() to make sure it is larger than shape() area, then it seems good now.
-
The docs nowhere specify that the shape has to be fully contained within the boundingRect. However, it seems like a logical optimization to first make a hit test using the boundingRect, before even checking the much more complex shape.
Do you have any clipping flags set (e.g. ItemClipsToShape, or ItemClipsChildrenToShape for a parent)? This might actually change the behavior, because this code of QGraphicsItem seems relevant:
bool QGraphicsItem::contains(const QPointF &point) const { return isClipped() ? clipPath().contains(point) : shape().contains(point); }
...and the clipPath() starts with the boundingRect()
-
No, I didn't set these two flags ItemClipsToShape, ItemClipsChildrenToShape.
Then I tried setting only one flag ItemClipsToShape, and both of ItemClipsToShape, ItemClipsChildrenToShape. For each, it still check if the point is in the boundingrect() firstly, and then check the shape() which means if point is not in boundingrect(), it wouldn't bother to check shape().
So now my solution is still enlarging the boundingrect() area.