pythonpyqtlinedrawingautomatic-ref-counting

How to draw lines with two end point coordinates and arcs with two end and a center point coordinates


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?

enter image description here


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:

    Based on your answer, also note that:

        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).