首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >标度QPolygon的原点

标度QPolygon的原点
EN

Stack Overflow用户
提问于 2022-01-18 20:22:05
回答 1查看 162关注 0票数 4

我正在尝试缩放一个QPolygonF,它位于QGraphicsScene的起源QGraphicsView上。

然而,即使将多边形(poly_2)转换为原点(使用QPolygon.translate()和通过boundingRect (x+width)/2和(y+height)/2接收的多边形的中心坐标),新的多边形仍然放置在错误的位置。

蓝色多边形应该根据poly_2的原点进行缩放(请看下面的图像,黑色是原始多边形,蓝色多边形是下面代码的结果,橙色多边形代表预期的结果)

我认为问题可能是坐标来自全局,应该是局部的,但这确实解决了这个问题。

下面是代码:

代码语言:javascript
复制
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映射到场景,但是没有运气:新的多边形仍然被绘制到错误的位置。

代码语言:javascript
复制
    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,则结果似乎更接近于我所需要的。然而,在这种情况下,起源点显然是错误的。这只是随机的运气,这个答案似乎更接近我所需要的?

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2022-01-19 00:16:39

在考虑翻译问题之前,有一个更重要的方面需要考虑:如果你想要创建一个基于多边形中心的转换,你必须找到这个中心。这个点叫做质心,任何多边形的几何中心。

虽然对于所有基本的几何形状都有简单的公式,但对于具有任意顶点数的多边形(可能是不规则的),其质心的求法要复杂得多。

使用顶点的算术平均值并不是可行的选择,因为即使在一个简单的正方形中,单面也可能有多个点,这将使计算出的“中心”移向这些点。

公式可以在上面链接的维基百科文章中找到,而有效的python实现可以在答案中找到。

我修改了这个答案的公式,以便接受一个QPoints序列,同时提高可读性和性能,但概念保持不变:

代码语言:javascript
复制
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类似的,然后使用上面的公式设置它的转换起始点,并缩放它:

代码语言:javascript
复制
    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作为起始点。

若要围绕指定的点进行缩放,您必须首先将矩阵转换到该点,然后应用标度,最后将矩阵转换还原为原点:

代码语言:javascript
复制
    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上翻译多边形的质心,然后在实际的质心坐标上移动它:

代码语言:javascript
复制
    item = scene.addPolygon(polygon.translated(-cx, -cy))
    item.setPos(cx, cy)
    item.setScale(1.5)

这可能使开发变得更容易(映射的点总是与项的位置一致),并且不再需要更改转换原点这一事实使得反向映射更加简单。

票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/70761930

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档