Issue
I want to build a PyQt5 application with Python that draws lines and arcs using known (already calculated) point coordinates, i.e., lines with two end point and arcs with two end point and a center point. The point coordinates will be calculated from known geometric parameters such as length, angle, and arc radius. I would like to add horizontal sliders to control the geometric parameters and obtain an interactive 2D graphics application similar to the one in the following image. What is the fastest and most efficient way to achieve this with Pyt5 and Python? What 2D drawing libraries would be most suitable?
Solution
QPainterPath is generally a more appropriate choice for complex and connected drawing paths: not only it provides a unique object representing the path, but it also provides proper painting using dash patterns which wouldn't be (easily) possible with multiple segments.
Qt already provides basic functions to achieve what you want. Specifically, since the center is actually the center of the circle, you already know everything is needed to draw the arc:
- the rectangle (square) of the ellipse (circle) is the
p5
point; - its size is twice the length between
p5
andp3
(orp4
); - the spans are the angles of the lines between
p5
andp3
andp5
andp4
;
Based on your answer, also note that:
- all basic QPainter functions that accept positional arguments for coordinates (
drawLine(x1, y1, x2, y2)
,drawArc(x, y, w, h, angle, span)
, etc.) only accept integer values, to achieve precise painting you need to use the relative Qt objects: QPointF, QLineF, QRectF; always check the documentation to see the accepted arguments types (and don't rely too much in automatic python conversions); - it is usually better to use QPointF objects (which can also be multiplied by factors) as they provide a single object reference;
- antialiasing should be used for smooth lines and curves;
- advanced painting works better with the Graphics View Framework, which also provide easier access to transformation (notably, scaling and rotation);
def draw_arc(self, qp):
# ...
path = QPainterPath(QPointF(p0x, p0y) * sf)
path.lineTo(QPointF(p1x, p1y) * sf)
path.lineTo(QPointF(p2x, p2y) * sf)
start = QPointF(p3x, p3y) * sf
end = QPointF(p4x, p4y) * sf
center = QPointF(p5x, p5y) * sf
# create reference lines to the center of the circle
startLine = QLineF(center, start)
endLine = QLineF(center, end)
radius = startLine.length()
arcRect = QRectF(center.x() - radius, center.y() - radius,
radius * 2, radius * 2)
# no need to lineTo(start), as arcTo() already connects the previous
# point to the start angle of the arc
path.arcTo(arcRect, startLine.angle(), endLine.angle() - startLine.angle())
path.lineTo(QPointF(p6x, p6y) * sf)
qp.setRenderHints(qp.Antialiasing)
qp.drawPath(path)
Note that for arbitrary connections you might need to check the direction of the lines to and from the arc in order to use the proper span angle (which might be negative for counter-clock directions).
Answered By - musicamante
0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.