我想用Python构建一个PyQt5应用程序,使用已知(已经计算出的)点坐标绘制直线和圆弧,即具有两个端点的直线和具有两个端点和一个中心点的圆弧。点坐标将根据已知的几何参数(例如长度、角度和圆弧半径)计算得出。我想添加水平滑块来控制几何参数并获得类似于下图中的交互式 2D 图形应用程序。使用 Pyt5 和 Python 实现此目的最快、最有效的方法是什么?哪些 2D 绘图库最合适?
QPainterPath 通常是复杂且连接的绘图路径的更合适选择:它不仅提供了表示路径的唯一对象,而且还提供了使用虚线图案的正确绘画,而这对于多个线段来说是不可能(轻易)实现的。
Qt已经提供了基本的功能来实现你想要的。具体来说,由于 center 实际上是圆的中心,因此您已经知道绘制圆弧所需的一切:
p5
点;p5
和p3
(或p4
)之间长度的两倍;p5
和 p3
以及 p5
和 p4
之间的线的角度;根据您的回答,另请注意:
drawLine(x1, y1, x2, y2)
、drawArc(x, y, w, h, angle, span)
等)仅接受整数值,要实现精确绘制,您需要使用相对的 Qt 对象:QPointF、QLineF、QRectF;始终检查文档以查看接受的参数类型(并且不要过多依赖自动 python 转换); 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)
请注意,对于任意连接,您可能需要检查往返弧线的方向,以便使用正确的跨度角(对于逆时针方向可能为负值)。
我在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_())
输出: