我正在开发路径绘图工具,并发表了一篇关于如何实现更流畅绘图的文章。我对
cubicTo()
和 quadTo()
做了一些修补,但这些确实没有多大帮助。我不知道我的数学是否正确,或者我如何计算出更平滑的绘制路径。我的上一篇文章中有人推荐了一系列数学公式(多项式)来实现平滑的路径。任何代码片段表示赞赏。
def on_path_draw_start(self, event):
# Check the button being pressed
if event.button() == Qt.LeftButton:
# Create a new path
self.path = QPainterPath()
self.path.moveTo(self.mapToScene(event.pos()))
self.last_point = self.mapToScene(event.pos())
# Set drag mode
self.setDragMode(QGraphicsView.NoDrag)
def on_path_draw(self, event):
# Check the buttons
if event.buttons() == Qt.LeftButton:
# Calculate average point for smoother curve
mid_point = (self.last_point + self.mapToScene(event.pos())) / 2.0
# Use the mid_point as control point for quadTo
self.path.quadTo(self.last_point, mid_point)
self.last_point = self.mapToScene(event.pos())
# Remove temporary path if it exists
if self.temp_path_item:
self.canvas.removeItem(self.temp_path_item)
# Load temporary path as QGraphicsItem to view it while drawing
self.temp_path_item = CustomPathItem(self.path)
self.temp_path_item.setPen(self.pen)
if self.button3.isChecked():
self.temp_path_item.setBrush(QBrush(QColor(self.stroke_fill_color)))
self.temp_path_item.setZValue(2)
self.canvas.addItem(self.temp_path_item)
# Create a custom tooltip for the current coords
scene_pos = self.mapToScene(event.pos())
QToolTip.showText(event.pos(), f'dx: {round(scene_pos.x(), 1)}, dy: {round(scene_pos.y(), 1)}')
self.canvas.update()
def on_path_draw_end(self, event):
# Check the buttons
if event.button() == Qt.LeftButton:
# Calculate average point for smoother curve
mid_point = (self.last_point + self.mapToScene(event.pos())) / 2.0
# Use the mid_point as control point for quadTo
self.path.quadTo(self.last_point, mid_point)
self.last_point = self.mapToScene(event.pos())
# Check if there is a temporary path (if so, remove it now)
if self.temp_path_item:
self.canvas.removeItem(self.temp_path_item)
# If stroke fill button is checked, close the subpath
if self.button3.isChecked():
self.path.closeSubpath()
self.canvas.update()
# Load main path as QGraphicsItem
path_item = CustomPathItem(self.path)
path_item.setPen(self.pen)
path_item.setZValue(0)
# If stroke fill button is checked, set the brush
if self.button3.isChecked():
path_item.setBrush(QBrush(QColor(self.stroke_fill_color)))
# Add item
self.canvas.addItem(path_item)
# Set Flags
path_item.setFlag(QGraphicsItem.ItemIsSelectable)
path_item.setFlag(QGraphicsItem.ItemIsMovable)
# Set Tooltop
path_item.setToolTip('MPRUN Path Element')
我知道这是一项艰巨的任务,但我需要一些指导。无论如何,我都不是数学奇才。或者也许我什至不需要数学,我真的不知道。
我基本上只是用 Numpy 和 SciPy 实现了平滑算法。这是代码:
def smooth_path(self, path):
vertices = [(point.x(), point.y()) for point in path.toSubpathPolygons()[0]]
x, y = zip(*vertices)
tck, u = splprep([x, y], s=0)
smooth_x, smooth_y = splev(np.linspace(0, 1, len(vertices) * 2), tck) # Reduce the granularity
smoothed_vertices = np.column_stack((smooth_x, smooth_y))
simplified_vertices = approximate_polygon(smoothed_vertices, tolerance=2.0) # Adjust the tolerance as needed
smooth_path = QPainterPath()
smooth_path.moveTo(simplified_vertices[0][0], simplified_vertices[0][1])
for i in range(1, len(simplified_vertices) - 2, 3):
smooth_path.cubicTo(
simplified_vertices[i][0], simplified_vertices[i][1],
simplified_vertices[i + 1][0], simplified_vertices[i + 1][1],
simplified_vertices[i + 2][0], simplified_vertices[i + 2][1]
)
return smooth_path
要实现此功能,您只需使用以下函数:
my_graphics_path_item.smooth_path(my_graphics_path_item.path())
然后将项目添加到场景中,依此类推...
您还可以更改平滑度的容差(我发现2.0效果最好)
我希望这可以帮助任何解决这个特殊问题的人。