如何连接多点与流动曲线,使用PyQt5?例如,我试图使用quitTo()对8个点执行此操作,使用交替点作为控制点,但弧不接触控制点(见下面的代码和图表)。我也尝试使用cubicTo(),但这也导致了一个奇怪的曲线。use是否有任何其他函数调用,我应该使用,或自定义的方式来做到这一点?
from PyQt5 import QtGui, QtCore
from PyQt5.QtWidgets import *
from PyQt5.QtGui import *
from PyQt5.QtCore import *
import sys
class Window(QMainWindow):
def __init__(self):
super().__init__()
self.title = "PyQt5 Drawing Tutorial"
self.top= 150
self.left= 150
self.width = 500
self.height = 500
self.InitWindow()
def InitWindow(self):
self.setWindowTitle(self.title)
self.setGeometry(self.top, self.left, self.width, self.height)
self.show()
def paintEvent(self, event):
painter = QPainter(self)
path = QPainterPath()
points = [
QPoint(20,40),
QPoint(60,10),
QPoint(100,50),
QPoint(80,200),
QPoint(200,300),
QPoint(150,400),
QPoint(350,450),
QPoint(400,350),
]
# draw small red dots on each point
painter.setPen(QtCore.Qt.red)
painter.setBrush(QBrush(Qt.red))
for i in range(len(points)):
painter.drawEllipse(points[i], 3, 3)
painter.setPen(QtCore.Qt.blue)
painter.setBrush(QBrush(Qt.red, Qt.NoBrush)) #reset the brush
path.moveTo(points[0])
# connect the points with blue straight lines
#for i in range(len(points)-1): # 1 less than length
# path.lineTo(points[i+1])
# connect points with curve
for i in range(0,len(points),2):
path.quadTo(points[i], points[i+1])
painter.drawPath(path)
App = QApplication(sys.argv)
window = Window()
sys.exit(App.exec())
使用诸如quadTo
或cubicTo
之类的函数将不起作用,因为它们使用控制点来创建贝塞尔曲线,而这些点通常不是曲线的一部分。
我意识到我之前的回答不仅不准确,而且是错误的。我把它留在这个答案的底部,留档/历史用途。
精确的“样条”插值必须使用与可能曲线相切的线段;为了找到您需要的线段数据:
在下图中,您可以看到所有重要的内容:
请注意,第一条和最后一条曲线仅为二次曲线(不是三次曲线),因为只有一个控制点:第一个点的目标线参考,最后一个点的源线参考。
代码使用从第二个点循环到第二个点循环到最后一个点的for循环,还使用上一个循环中设置的控制点。
我建议您使用一个因子=.25
,这应该会创建一条足够平滑的路径。值越低,曲线越“小”,而值越高,路径越“圆”。
class Window(QWidget):
# ...
def buildPath(self):
factor =
self.path = QtGui.QPainterPath(points[0])
for p, current in enumerate(points[1:-1], 1):
# previous segment
source = QtCore.QLineF(points[p - 1], current)
# next segment
target = QtCore.QLineF(current, points[p + 1])
targetAngle = target.angleTo(source)
if targetAngle > 180:
angle = (source.angle() + source.angleTo(target) / 2) % 360
else:
angle = (target.angle() + target.angleTo(source) / 2) % 360
revTarget = QtCore.QLineF.fromPolar(source.length() * factor, angle + 180).translated(current)
cp2 = revTarget.p2()
if p == 1:
self.path.quadTo(cp2, current)
else:
# use the control point "cp1" set in the *previous* cycle
self.path.cubicTo(cp1, cp2, current)
revSource = QtCore.QLineF.fromPolar(target.length() * factor, angle).translated(current)
cp1 = revSource.p2()
# the final curve, that joins to the last point
self.path.quadTo(cp1, points[-1])
有一些算法允许构建插值的“样条”,但是你需要一些数学技能来理解它们,并创建一个创建平滑曲线的好系统。与此同时,一个可能的(但不是完美的)解决方案是创建控制点,这些控制点是从现有段的扩展中计算出来的(这类似于矢量图形编辑器所做的):
每个扩展的末端被用作贝塞尔曲线的控制点:对于第一段和最后一段,我使用二次曲线(一个控制点),而所有其他的都是三次曲线(两个控制点);这导致了一个可以接受的结果:
不幸的是,它远远不够完美,特别是对于某些角度和长度的组合:
我建议您仅在需要时构建路径(例如,点更改),而不是在paintEvent中。
class Window(QWidget):
# ...
def buildPath(self):
self.path = QtGui.QPainterPath()
self.path.moveTo(points[0])
factor = .1412
for p in range(len(points) - 2):
p2 = points[p + 1]
target = QtCore.QLineF(p2, points[p + 2])
reverseTarget = QtCore.QLineF.fromPolar(
target.length() * factor, target.angle() + 180).translated(p2)
if not p:
self.path.quadTo(reverseTarget.p2(), p2)
else:
p0 = points[p - 1]
p1 = points[p]
source = QtCore.QLineF(p0, p1)
current = QtCore.QLineF(p1, p2)
targetAngle = target.angleTo(current)
if 90 < targetAngle < 270:
ratio = abs(sin(radians(targetAngle)))
reverseTarget.setLength(reverseTarget.length() * ratio)
reverseSource = QtCore.QLineF.fromPolar(
source.length() * factor, source.angle()).translated(p1)
sourceAngle = current.angleTo(source)
if 90 < sourceAngle < 270:
ratio = abs(sin(radians(sourceAngle)))
reverseSource.setLength(reverseSource.length() * ratio)
self.path.cubicTo(reverseSource.p2(), reverseTarget.p2(), p2)
final = QtCore.QLineF(points[-3], points[-2])
reverseFinal = QtCore.QLineF.fromPolar(
final.length() * factor, final.angle()).translated(final.p2())
self.path.quadTo(reverseFinal.p2(), points[-1])
我正在尝试使用GeoJSON在地图上绘制点。我阅读了文件,其中说明: 可以通过调用数据对象的loadGeoJSON()方法来加载和显示GeoJSON文件 (https://developers.google.com/maps/documentation/javascript/datalayer) 但是,同一页上的示例代码显示: map.data.loadGeoJson(…) 因此,我使用代码示例,
问题内容: 我正在用Piccolo编写一个交互式applet,并且需要在其中包含高斯曲线(又称正态分布图)。 我想象任何一种Java实现都足够,但是我找不到。理想情况下,我想传递一组值并将图表绘制在面板,图像对象或可以嵌入在applet中的任何对象中。 在让我自己动手编写代码之前,有人知道做这件事的有用代码吗? 欢迎使用其他语言的实现,只要它们易于移植到Java中即可。 问题答案: 不知道它是否有
问题内容: 这是我声明曲线的代码行: 现在我可以使用什么代码来绘制曲线?我尝试了类似的东西: 但显然那没有用。有什么建议? 问题答案: 我已经做了一个最小的测试用例,以证明您在这里的描述。该程序可以运行,但是除非能看到您正在使用的代码,否则我无法真正为您提供帮助。
问题内容: 我正在尝试用Java绘制曲线。一个简单的以(X,Y)开始,(X,Y)结束和曲线量的贝塞尔曲线就足够了。 我找不到在Swing中执行此操作的方法。如果不在Swing中,我可以使用一些简单的数学方法吗?我将如何在Swing中实现它? 编辑:我知道如何通过重写paint(Graphics g)方法绘制形状和线条。 问题答案: 您可以使用Java 2D Object Path2D.Double
我画了4条线从中心到按钮,我给你看的照片。我不知道如何在图片中画出红色的曲线。 [在此处输入图像说明] 或 [在此输入图像说明(更简单)]
本文向大家介绍使用HTML5画布绘制贝塞尔曲线,包括了使用HTML5画布绘制贝塞尔曲线的使用技巧和注意事项,需要的朋友参考一下 是的,请使用HTML canvas方法在HTML5中绘制Bezier曲线。 示例 您可以尝试运行以下代码以使用画布绘制贝塞尔曲线: