我正在尝试缩放一个QPolygonF,它位于QGraphicsScene的起源QGraphicsView上。
然而,即使将多边形(poly_2)转换为原点(使用QPolygon.translate()和通过boundingRect (x+width)/2和(y+height)/2接收的多边形的中心坐标),新的多边形仍然放置在错误的位置。
蓝色多边形应该根据poly_2的原点进行缩放(请看下面的图像,黑色是原始多边形,蓝色多边形是下面代码的结果,橙色多边形代表预期的结果)

我认为问题可能是坐标来自全局,应该是局部的,但这确实解决了这个问题。
下面是代码:
import PyQt5
from PyQt5 import QtCore
import sys
import PyQt5
from PyQt5.QtCore import *#QPointF, QRectF
from PyQt5.QtGui import *#QPainterPath, QPolygonF, QBrush,QPen,QFont,QColor, QTransform
from PyQt5.QtWidgets import *#QApplication, QGraphicsScene, QGraphicsView, QGraphicsSimpleTextItem
poly_2_coords= [PyQt5.QtCore.QPointF(532.35, 274.98), PyQt5.QtCore.QPointF(525.67, 281.66), PyQt5.QtCore.QPointF(518.4, 292.58), PyQt5.QtCore.QPointF(507.72, 315.49), PyQt5.QtCore.QPointF(501.22, 326.04), PyQt5.QtCore.QPointF(497.16, 328.47), PyQt5.QtCore.QPointF(495.53, 331.71), PyQt5.QtCore.QPointF(488.24, 339.02), PyQt5.QtCore.QPointF(480.94, 349.56), PyQt5.QtCore.QPointF(476.09, 360.1), PyQt5.QtCore.QPointF(476.89, 378.76), PyQt5.QtCore.QPointF(492.3, 393.35), PyQt5.QtCore.QPointF(501.22, 398.21), PyQt5.QtCore.QPointF(527.17, 398.21), PyQt5.QtCore.QPointF(535.28, 390.1), PyQt5.QtCore.QPointF(540.96, 373.89), PyQt5.QtCore.QPointF(539.64, 356.93), PyQt5.QtCore.QPointF(541.46, 329.0), PyQt5.QtCore.QPointF(543.39, 313.87), PyQt5.QtCore.QPointF(545.83, 300.89), PyQt5.QtCore.QPointF(545.83, 276.56), PyQt5.QtCore.QPointF(543.39, 267.64), PyQt5.QtCore.QPointF(537.81, 268.91)]
def main():
app = QApplication(sys.argv)
scene = QGraphicsScene()
view = QGraphicsView(scene)
pen = QPen(QColor(0, 20, 255))
scene.addPolygon(QPolygonF(poly_2_coords))
poly_2 = QPolygonF(poly_2_coords)
trans = QTransform().scale(1.5,1.5)
#poly_22 = trans.mapToPolygon(QRect(int(poly_2.boundingRect().x()),int(poly_2.boundingRect().y()),int(poly_2.boundingRect().width()),int(poly_2.boundingRect().height())))
#trans.mapToPolygon()
#scene.addPolygon(QPolygonF(poly_22),QPen(QColor(0, 20, 255)))
poly_2.translate((poly_2.boundingRect().x()+poly_2.boundingRect().width())/2,(poly_2.boundingRect().y()+poly_2.boundingRect().height())/2)
print(f'poly_2.boundingRect().x() {poly_2.boundingRect().x()}+poly_2.boundingRect().width(){poly_2.boundingRect().width()}')
trans = QTransform().scale(1.4,1.4)
#poly_2.setTransformOriginPoint()
poly_22 = trans.map(poly_2)
scene.addPolygon(poly_22,QPen(QColor(0, 20, 255)))
view.show()
sys.exit(app.exec_())
if __name__ == "__main__":
main()编辑:我尝试将多边形保存为一个QGraphicsItem,并根据bbox的中间X,Y设置它的转换起始点,然后从Global映射到场景,但是没有运气:新的多边形仍然被绘制到错误的位置。
poly_2 = QPolygonF(poly_2_coords)
poly = scene.addPolygon(poly_2)
point = QPoint((poly_2.boundingRect().x()+poly_2.boundingRect().width())/2,(poly_2.boundingRect().y()+poly_2.boundingRect().height())/2)
poly.setTransformOriginPoint(point)
poly.setScale(3)如果将边界矩形的点替换为仅等于X,Y,则结果似乎更接近于我所需要的。然而,在这种情况下,起源点显然是错误的。这只是随机的运气,这个答案似乎更接近我所需要的?

发布于 2022-01-19 00:16:39
在考虑翻译问题之前,有一个更重要的方面需要考虑:如果你想要创建一个基于多边形中心的转换,你必须找到这个中心。这个点叫做质心,任何多边形的几何中心。
虽然对于所有基本的几何形状都有简单的公式,但对于具有任意顶点数的多边形(可能是不规则的),其质心的求法要复杂得多。
使用顶点的算术平均值并不是可行的选择,因为即使在一个简单的正方形中,单面也可能有多个点,这将使计算出的“中心”移向这些点。
公式可以在上面链接的维基百科文章中找到,而有效的python实现可以在这答案中找到。
我修改了这个答案的公式,以便接受一个QPoints序列,同时提高可读性和性能,但概念保持不变:
def centroid(points):
if len(points) < 3:
raise ValueError('At least 3 points are required')
# https://en.wikipedia.org/wiki/Centroid#Of_a_polygon
# https://en.wikipedia.org/wiki/Shoelace_formula
# computation uses concatenated pairs from the sequence, with the
# last point paired to the first one:
# (p[0], p[1]), (p[1], p[2]) [...] (p[n], p[0])
area = cx = cy = 0
p1 = points[0]
for p2 in points[1:] + [p1]:
shoelace = p1.x() * p2.y() - p2.x() * p1.y()
area += shoelace
cx += (p1.x() + p2.x()) * shoelace
cy += (p1.y() + p2.y()) * shoelace
p1 = p2
A = 0.5 * area
factor = 1 / (6 * A)
return cx * factor, cy * factor然后,您有两个选项,取决于您想要对结果项做什么。
缩放项目
在本例中,您创建一个与原始QGraphicsPolygonItem类似的,然后使用上面的公式设置它的转换起始点,并缩放它:
poly_2 = QtGui.QPolygonF(poly_2_coords)
item2 = scene.addPolygon(poly_2, QtGui.QPen(QtGui.QColor(0, 20, 255)))
item2.setTransformOriginPoint(*centroid(poly_2_coords))
item2.setScale(1.5)使用QTransform
对于Qt转换,必须特别小心,因为缩放总是使用0, 0作为起始点。
若要围绕指定的点进行缩放,您必须首先将矩阵转换到该点,然后应用标度,最后将矩阵转换还原为原点:
poly_2 = QtGui.QPolygonF(poly_2_coords)
cx, cy = centroid(poly_2_coords)
trans = QtGui.QTransform()
trans.translate(cx, cy)
trans.scale(1.5, 1.5)
trans.translate(-cx, -cy)
poly_2_scaled = trans.map(poly_2)
scene.addPolygon(poly_2_scaled, QtGui.QPen(QtGui.QColor(0, 20, 255)))这正是QGraphicsItems在使用基本setScale()和setRotation()转换时所做的事情。
形状起始点和项目位置
请记住,QGraphicsItems是,总是在0, 0的位置上创建的。
这一点似乎并不明显,特别是对于基本形状:当您创建一个QGraphicsRectItem给出它的x, y, width, height时,这个位置仍然是0, 0。在处理复杂的几何管理时,通常最好在0, 0中使用原始/引用创建基本形状,然后在x, y中移动项目。
对于像您这样的复杂多边形,一种可能是在0, 0上翻译多边形的质心,然后在实际的质心坐标上移动它:
item = scene.addPolygon(polygon.translated(-cx, -cy))
item.setPos(cx, cy)
item.setScale(1.5)这可能使开发变得更容易(映射的点总是与项的位置一致),并且不再需要更改转换原点这一事实使得反向映射更加简单。
https://stackoverflow.com/questions/70761930
复制相似问题