PyQt5 - 如何计算中心点旋转后 QGraphicsRectItem 的角点?
PyQt5 - How to calculate corner points of a QGraphicsRectItem after rotation by its center point?
我的问题是,在围绕中心点旋转 theta 角度后,我无法找到 HighwayItem(这是一个 QGraphicsRectItem)的每个角点的像素值
我使用了解释 here and I also looked this 解释的旋转矩阵。但是,我找不到真正的价值。
任何帮助都会很棒。谢谢
这是 MapViewer() class。在此视图中创建了一个 HighwayItem。
from PyQt5 import QtCore, QtGui, QtWidgets
from PyQt5.QtGui import QPixmap
from PyQt5.QtCore import Qt, QPoint, QPointF, QRectF
from PyQt5.QtWidgets import QGraphicsScene, \
QGraphicsView, QGraphicsPixmapItem, \
from class_graphical_items import HighwayItem
class MapViewer(QGraphicsView):
def __init__(self, parent, ui):
super(MapViewer, self).__init__(parent)
self.ui = ui
# Attributes for highway
self.add_highway_control = False
self.current_highway = None
self.start = QPointF()
self.hw_counter = 0
self._scene = QGraphicsScene(self)
self._map = QGraphicsPixmapItem()
self._scene.addItem(self._map)
self.setScene(self._scene)
self.setTransformationAnchor(QGraphicsView.AnchorUnderMouse)
self.setResizeAnchor(QGraphicsView.AnchorUnderMouse)
self.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
self.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
self.setFrameShape(QtWidgets.QFrame.NoFrame)
def mousePressEvent(self, event):
if self._map.isUnderMouse():
if self.add_highway_control:
# Create a yellow highway
self.current_highway = HighwayItem(self._scene, self.ui)
self.hw_counter += 1
self.start = self.mapToScene(event.pos()).toPoint()
r = QRectF(self.start, self.start)
self.current_highway.setRect(r)
self._scene.addItem(self.current_highway)
# When adding HW, set drag mode NoDrag
self.setDragMode(QGraphicsView.NoDrag)
super(MapViewer, self).mousePressEvent(event)
def mouseMoveEvent(self, event):
if self.add_highway_control and self.current_highway is not None:
# When adding HW, set drag mode NoDrag
self.setDragMode(QGraphicsView.NoDrag)
r = QRectF(self.start, self.mapToScene(event.pos()).toPoint()).normalized()
self.current_highway.setRect(r)
super(MapViewer, self).mouseReleaseEvent(event)
def mouseReleaseEvent(self, event):
if self.add_highway_control:
if self.current_highway is not None:
# When finish the adding HW, set drag mode ScrollHandDrag
self.setDragMode(QGraphicsView.ScrollHandDrag)
self.update_item_dict(self.current_highway)
self.update_item_table(self.current_highway)
self.current_highway = None
self.add_highway_control = False
super(MapViewer, self).mouseReleaseEvent(event)
这是 HighwayItem class。它有一些规格,如颜色、不透明度等。
通过双击创建的 HighwayItem,我激活了主 window (ui) 中 QTreeWidget 中的旋转框。
通过更改旋转框值,用户可以旋转项目。
class HighwayItem(QGraphicsRectItem):
def __init__(self, scene, ui):
QGraphicsRectItem.__init__(self)
self.scene = scene
self.ui = ui
self.setBrush(QtCore.Qt.yellow)
self.setOpacity(0.5)
self.setZValue(4.0)
self.setFlag(QGraphicsItem.ItemIsMovable, True)
self.setFlag(QGraphicsItem.ItemIsSelectable, True)
self.setFlag(QGraphicsItem.ItemSendsGeometryChanges, True)
self.setFlag(QGraphicsItem.ItemIsFocusable, True)
self.setAcceptHoverEvents(True)
# Here, I'm activating the spinbox by double clicking
# on HighwayItem. In spinbox, I'm entering the rotation angle
# of HighwayItem.
def mouseDoubleClickEvent(self, event):
selected_item = self.scene.selectedItems()
if selected_item:
for i in range(self.ui.treeWidget_objects.topLevelItemCount()):
toplevel_item = self.ui.treeWidget_objects.topLevelItem(i)
heading_item = toplevel_item.child(2)
spinbox = self.ui.treeWidget_objects.itemWidget(heading_item, 2)
if str(toplevel_item.text(2)) == str(selected_item[0]):
if 'HighwayItem' in str(selected_item[0]):
spinbox.setEnabled(True)
else:
spinbox.setEnabled(False)
这是设置 HWItem 旋转角度的 HWHeadingSpinBox() class。我的问题从这里开始。在 rotate_hw() 方法中,我将创建的 HighwayItem 通过其中心点进行转换,并通过其中心点对其进行旋转。
但是,当我尝试在 calc_rotated_coords() 方法中计算硬件的新角时,我搞砸了。
class HWHeadingSpinBox(QSpinBox):
def __init__(self, viewer, selected_hw):
QSpinBox.__init__(self)
self.selected_hw = selected_hw
self.viewer = viewer
# First coords of HW
tl = self.selected_hw.rect().topLeft()
tr = self.selected_hw.rect().topRight()
br = self.selected_hw.rect().bottomRight()
bl = self.selected_hw.rect().bottomLeft()
self.temp_list = [tl, tr, br, bl]
self.setRange(-180, 180)
self.setSuffix('°')
self.setEnabled(False)
self.valueChanged.connect(self.rotate_hw)
def heading_val(self):
return self.value()
def rotate_hw(self):
angle = self.heading_val()
self.selected_hw.prepareGeometryChange()
offset = self.selected_hw.boundingRect().center()
self.selected_hw.sceneBoundingRect().center()
transform = QTransform()
transform.translate(offset.x(), offset.y())
transform.rotate(-angle)
transform.translate(-offset.x(), -offset.y())
self.selected_hw.setTransform(transform)
# br_rect = self.selected_hw.sceneBoundingRect()
# sbr_rect = self.selected_hw.sceneBoundingRect()
# r_rect = self.selected_hw.sceneBoundingRect()
#
# rectitem = QtWidgets.QGraphicsRectItem(br_rect)
# rectitem.setBrush(Qt.red)
# self.viewer._scene.addItem(rectitem)
#
# rectitem = QtWidgets.QGraphicsRectItem(sbr_rect)
# rectitem.setBrush(Qt.green)
# self.viewer._scene.addItem(rectitem)
#
# rectitem = QtWidgets.QGraphicsRectItem(r_rect)
# rectitem.setBrush(Qt.blue)
# self.viewer._scene.addItem(rectitem)
def calc_rotated_coords(self):
# center point
cx = self.selected_hw.rect().center().x()
cy = self.selected_hw.rect().center().y()
# rotation angle
theta = math.radians(angle)
rotated_corners = []
for item in self.temp_list:
x = item.x()
y = item.y()
temp_x = x - cx
temp_y = y - cy
rot_x = temp_x * math.cos(theta) + temp_y * math.sin(theta)
rot_y = -temp_x * math.sin(theta) + temp_y * math.cos(theta)
rotated_corners.append([rot_x, rot_y])
self.temp_list = rotated_corners
print("\nPIXEL VALUES OF HW: \n{}".format(self.temp_list))
解决方法如下:
我在 HighwayItem 中添加了 itemChange(self, change, value) 事件,如果 change 是 ItemPositionHasChanged,我计算了所有项目的角落:
def itemChange(self, change, value):
if change == QGraphicsItem.ItemPositionHasChanged:
top_left = self.mapToScene(self.rect().topLeft())
top_right = self.mapToScene(self.rect().topRight())
bottom_left = self.mapToScene(self.rect().bottomLeft())
bottom_right = self.mapToScene(self.rect().bottomRight())
changed_pos = [top_left, top_right, bottom_right, bottom_left]
return super(HighwayItem, self).itemChange(change, value)
我的问题是,在围绕中心点旋转 theta 角度后,我无法找到 HighwayItem(这是一个 QGraphicsRectItem)的每个角点的像素值
我使用了解释 here and I also looked this 解释的旋转矩阵。但是,我找不到真正的价值。
任何帮助都会很棒。谢谢
这是 MapViewer() class。在此视图中创建了一个 HighwayItem。
from PyQt5 import QtCore, QtGui, QtWidgets
from PyQt5.QtGui import QPixmap
from PyQt5.QtCore import Qt, QPoint, QPointF, QRectF
from PyQt5.QtWidgets import QGraphicsScene, \
QGraphicsView, QGraphicsPixmapItem, \
from class_graphical_items import HighwayItem
class MapViewer(QGraphicsView):
def __init__(self, parent, ui):
super(MapViewer, self).__init__(parent)
self.ui = ui
# Attributes for highway
self.add_highway_control = False
self.current_highway = None
self.start = QPointF()
self.hw_counter = 0
self._scene = QGraphicsScene(self)
self._map = QGraphicsPixmapItem()
self._scene.addItem(self._map)
self.setScene(self._scene)
self.setTransformationAnchor(QGraphicsView.AnchorUnderMouse)
self.setResizeAnchor(QGraphicsView.AnchorUnderMouse)
self.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
self.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
self.setFrameShape(QtWidgets.QFrame.NoFrame)
def mousePressEvent(self, event):
if self._map.isUnderMouse():
if self.add_highway_control:
# Create a yellow highway
self.current_highway = HighwayItem(self._scene, self.ui)
self.hw_counter += 1
self.start = self.mapToScene(event.pos()).toPoint()
r = QRectF(self.start, self.start)
self.current_highway.setRect(r)
self._scene.addItem(self.current_highway)
# When adding HW, set drag mode NoDrag
self.setDragMode(QGraphicsView.NoDrag)
super(MapViewer, self).mousePressEvent(event)
def mouseMoveEvent(self, event):
if self.add_highway_control and self.current_highway is not None:
# When adding HW, set drag mode NoDrag
self.setDragMode(QGraphicsView.NoDrag)
r = QRectF(self.start, self.mapToScene(event.pos()).toPoint()).normalized()
self.current_highway.setRect(r)
super(MapViewer, self).mouseReleaseEvent(event)
def mouseReleaseEvent(self, event):
if self.add_highway_control:
if self.current_highway is not None:
# When finish the adding HW, set drag mode ScrollHandDrag
self.setDragMode(QGraphicsView.ScrollHandDrag)
self.update_item_dict(self.current_highway)
self.update_item_table(self.current_highway)
self.current_highway = None
self.add_highway_control = False
super(MapViewer, self).mouseReleaseEvent(event)
这是 HighwayItem class。它有一些规格,如颜色、不透明度等。
通过双击创建的 HighwayItem,我激活了主 window (ui) 中 QTreeWidget 中的旋转框。 通过更改旋转框值,用户可以旋转项目。
class HighwayItem(QGraphicsRectItem):
def __init__(self, scene, ui):
QGraphicsRectItem.__init__(self)
self.scene = scene
self.ui = ui
self.setBrush(QtCore.Qt.yellow)
self.setOpacity(0.5)
self.setZValue(4.0)
self.setFlag(QGraphicsItem.ItemIsMovable, True)
self.setFlag(QGraphicsItem.ItemIsSelectable, True)
self.setFlag(QGraphicsItem.ItemSendsGeometryChanges, True)
self.setFlag(QGraphicsItem.ItemIsFocusable, True)
self.setAcceptHoverEvents(True)
# Here, I'm activating the spinbox by double clicking
# on HighwayItem. In spinbox, I'm entering the rotation angle
# of HighwayItem.
def mouseDoubleClickEvent(self, event):
selected_item = self.scene.selectedItems()
if selected_item:
for i in range(self.ui.treeWidget_objects.topLevelItemCount()):
toplevel_item = self.ui.treeWidget_objects.topLevelItem(i)
heading_item = toplevel_item.child(2)
spinbox = self.ui.treeWidget_objects.itemWidget(heading_item, 2)
if str(toplevel_item.text(2)) == str(selected_item[0]):
if 'HighwayItem' in str(selected_item[0]):
spinbox.setEnabled(True)
else:
spinbox.setEnabled(False)
这是设置 HWItem 旋转角度的 HWHeadingSpinBox() class。我的问题从这里开始。在 rotate_hw() 方法中,我将创建的 HighwayItem 通过其中心点进行转换,并通过其中心点对其进行旋转。
但是,当我尝试在 calc_rotated_coords() 方法中计算硬件的新角时,我搞砸了。
class HWHeadingSpinBox(QSpinBox):
def __init__(self, viewer, selected_hw):
QSpinBox.__init__(self)
self.selected_hw = selected_hw
self.viewer = viewer
# First coords of HW
tl = self.selected_hw.rect().topLeft()
tr = self.selected_hw.rect().topRight()
br = self.selected_hw.rect().bottomRight()
bl = self.selected_hw.rect().bottomLeft()
self.temp_list = [tl, tr, br, bl]
self.setRange(-180, 180)
self.setSuffix('°')
self.setEnabled(False)
self.valueChanged.connect(self.rotate_hw)
def heading_val(self):
return self.value()
def rotate_hw(self):
angle = self.heading_val()
self.selected_hw.prepareGeometryChange()
offset = self.selected_hw.boundingRect().center()
self.selected_hw.sceneBoundingRect().center()
transform = QTransform()
transform.translate(offset.x(), offset.y())
transform.rotate(-angle)
transform.translate(-offset.x(), -offset.y())
self.selected_hw.setTransform(transform)
# br_rect = self.selected_hw.sceneBoundingRect()
# sbr_rect = self.selected_hw.sceneBoundingRect()
# r_rect = self.selected_hw.sceneBoundingRect()
#
# rectitem = QtWidgets.QGraphicsRectItem(br_rect)
# rectitem.setBrush(Qt.red)
# self.viewer._scene.addItem(rectitem)
#
# rectitem = QtWidgets.QGraphicsRectItem(sbr_rect)
# rectitem.setBrush(Qt.green)
# self.viewer._scene.addItem(rectitem)
#
# rectitem = QtWidgets.QGraphicsRectItem(r_rect)
# rectitem.setBrush(Qt.blue)
# self.viewer._scene.addItem(rectitem)
def calc_rotated_coords(self):
# center point
cx = self.selected_hw.rect().center().x()
cy = self.selected_hw.rect().center().y()
# rotation angle
theta = math.radians(angle)
rotated_corners = []
for item in self.temp_list:
x = item.x()
y = item.y()
temp_x = x - cx
temp_y = y - cy
rot_x = temp_x * math.cos(theta) + temp_y * math.sin(theta)
rot_y = -temp_x * math.sin(theta) + temp_y * math.cos(theta)
rotated_corners.append([rot_x, rot_y])
self.temp_list = rotated_corners
print("\nPIXEL VALUES OF HW: \n{}".format(self.temp_list))
解决方法如下:
我在 HighwayItem 中添加了 itemChange(self, change, value) 事件,如果 change 是 ItemPositionHasChanged,我计算了所有项目的角落:
def itemChange(self, change, value):
if change == QGraphicsItem.ItemPositionHasChanged:
top_left = self.mapToScene(self.rect().topLeft())
top_right = self.mapToScene(self.rect().topRight())
bottom_left = self.mapToScene(self.rect().bottomLeft())
bottom_right = self.mapToScene(self.rect().bottomRight())
changed_pos = [top_left, top_right, bottom_right, bottom_left]
return super(HighwayItem, self).itemChange(change, value)