如何画有两个端点坐标的直线和有两个端点和一个中心点坐标的圆弧

问题描述 投票:0回答:2

我想用Python构建一个PyQt5应用程序,使用已知(已经计算出的)点坐标绘制直线和圆弧,即具有两个端点的直线和具有两个端点和一个中心点的圆弧。点坐标将根据已知的几何参数(例如长度、角度和圆弧半径)计算得出。我想添加水平滑块来控制几何参数并获得类似于下图中的交互式 2D 图形应用程序。使用 Pyt5 和 Python 实现此目的最快、最有效的方法是什么?哪些 2D 绘图库最合适?

python pyqt line drawing automatic-ref-counting
2个回答
1
投票

QPainterPath 通常是复杂且连接的绘图路径的更合适选择:它不仅提供了表示路径的唯一对象,而且还提供了使用虚线图案的正确绘画,而这对于多个线段来说是不可能(轻易)实现的。

Qt已经提供了基本的功能来实现你想要的。具体来说,由于 center 实际上是圆的中心,因此您已经知道绘制圆弧所需的一切:

  • 椭圆(圆)的长方形(正方形)就是
    p5
    点;
  • 其大小是
    p5
    p3
    (或
    p4
    )之间长度的两倍;
  • 跨度是
    p5
    p3
    以及
    p5
    p4
    之间的线的角度;

根据您的回答,另请注意:

  • 所有接受坐标位置参数的基本 QPainter 函数(
    drawLine(x1, y1, x2, y2)
    drawArc(x, y, w, h, angle, span)
    等)仅接受整数值,要实现精确绘制,您需要使用相对的 Qt 对象:QPointF、QLineF、QRectF;始终检查文档以查看接受的参数类型(并且不要过多依赖自动 python 转换);
  • 通常最好使用 QPointF 对象(也可以乘以因子),因为它们提供单个对象引用;
  • 抗锯齿应用于平滑的直线和曲线;
  • 高级绘画与图形视图框架配合得更好,它还提供了更轻松的转换(特别是缩放和旋转);
    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)

请注意,对于任意连接,您可能需要检查往返弧线的方向,以便使用正确的跨度角(对于逆时针方向可能为负值)。


1
投票

我在musicamante的帮助下解决了这个问题。我使用了QT的QPainter类。 drawLine() 方法使用起来很简单,因为它只需要终点坐标。 drawArc() 方法使用起始角度和跨度角度,需要额外的方法来获取它们。以下是工作代码。

# Draw lines and arcs.

import sys
import math
from PyQt5.QtWidgets import QWidget, QApplication
from PyQt5.QtGui import QPainter, QPen, QColor, QBrush
from PyQt5.QtCore import Qt


def three_points_angle(p1x, p1y, p2x, p2y, c1x, c1y):
        numerator = p1y*(c1x-p2x) + c1y*(p2x-p1x) + p2y*(p1x-c1x)
        denominator = (p1x-c1x)*(c1x-p2x) + (p1y-c1y)*(c1y-p2y)
        ratio = numerator/denominator

        angleRad = math.atan(ratio)
        angleDeg = (angleRad*180)/math.pi

        if angleDeg < 0:
            angleDeg = 180 + angleDeg

        return angleDeg

class MyApp(QWidget):

    def __init__(self):
        super().__init__()
        self.initUI()

    def initUI(self):
        self.setFixedSize(500, 200)
        self.setWindowTitle('Draw Lines and Arcs')
        self.show()

    def paintEvent(self, e):
        qp = QPainter()
        qp.begin(self)
        self.draw_arc(qp)
        qp.end()

    

    def draw_arc(self, qp):
        qp.setPen(QPen(Qt.blue, 3))

        r1 = 3

        p0y = 0.000000 
        p0x = 56.000000
        p1y = 7.000000 
        p1x = 56.000000
        p2y = 7.000000 
        p2x = 55.500000
        p3y = 3.410242 
        p3x = 53.256870
        p4y = 2.001828 
        p4x = 50.608028
        p5y = 5.000000 
        p5x = 50.712726
        p6y = 3.349775 
        p6x = 12.007856
        
        sf = 490/p1x

        qp.drawLine(round(p0x*sf), round(p0y*sf), round(p1x*sf), round(p1y*sf))
        qp.drawLine(round(p1x*sf), round(p1y*sf), round(p2x*sf), round(p2y*sf))
        qp.drawLine(round(p2x*sf), round(p2y*sf), round(p3x*sf), round(p3y*sf))

        a1_start = three_points_angle(p5x+1, p5y, p3x, p3y, p5x, p5y)
        print("start angle: %f" %a1_start)
        a1_span = three_points_angle(p3x, p3y, p4x, p4y, p5x, p5y)
        print("span angle: %f" %a1_span)
        
        qp.drawArc(round((p5x-r1)*sf), round((p5y-r1)*sf), round(2*r1*sf), round(2*r1*sf), round(a1_start*16), round(a1_span*16))
        qp.drawLine(round(p4x*sf), round(p4y*sf), round(p6x*sf), round(p6y*sf))



if __name__ == '__main__':
    app = QApplication(sys.argv)
    ex = MyApp()
    sys.exit(app.exec_())

输出:

© www.soinside.com 2019 - 2024. All rights reserved.