移动

时间:2016-08-01 18:58:12

标签: c++ qt rotation qgraphicsitem

在Qt中使用预定义的移动选项后,我遇到了关于对象中心的对象旋转问题。我创建了一个QGraphicsRectItem并设置了ItemIsMovable属性。旋转工作正常(按住鼠标左键并拖动项目)。

现在移动矩形,(按住鼠标左键拖动)并再次尝试旋转。旋转不正确。我使用sceneBoundingBox()。normalize.center()计算矩形的中心。如果我在移动后绘制该点,则它位于正确的位置。

我尝试过setOriginTransform并使用QTransform方法。他们都给了我相同的结果。

我对场景的坐标系与旋转坐标系感到困惑吗?搬家后如何改变?

这是一个精简的可编译头文件和源代码,用于演示此问题。我在Mac上使用Qt 5.7。旋转在函数rotateItem(...)中计算,所有坐标都应在场景坐标系中。

#include <cmath>
#include <QApplication>
#include <QWidget>
#include <QGraphicsView>
#include <QGraphicsScene>
#include <QBrush>
#include <QPen>
#include <QGraphicsSceneMouseEvent>
#include "myrect.h"


// THIS IS THE PROBLEM FUNCTION
// calculate rotations about the center of a given shape item.
void rotateItem(QAbstractGraphicsShapeItem* shape, QPointF center,
                QPointF moved, QPointF initial_pos)
{
  // get the angle from the center to the initial click point
  qreal init_x = initial_pos.x() - center.x();
  qreal init_y = initial_pos.y() - center.y();
  qreal initial_angle = std::atan2(init_y, init_x);
  qreal x = moved.x() - center.x();
  qreal y = moved.y() - center.y();

  qreal mv_angle = std::atan2(y,x);

  // get the changed angle
  qreal angle = (mv_angle - initial_angle)*180/M_PI;

  if (std::fabs(angle) > 360.0)
    angle = 0.0;

  // both transforms give the same result
  QTransform xform;
  xform.translate(center.x(), center.y());
  xform.rotate(angle);
  xform.translate(-center.x(), -center.y());

  shape->setTransform(xform, false);
  //shape->setTransformOriginPoint(center);
  //shape->setRotation(angle);
}



MyRect::MyRect(qreal x, qreal y, qreal width, qreal height) :
      QGraphicsRectItem(x, y, width, height)
{
  mInitialPos.setX(0.0);
  mInitialPos.setY(0.0);

  mInitialCenter.setX(0.0);
  mInitialCenter.setY(0.0);
}

void MyRect::mousePressEvent(QGraphicsSceneMouseEvent *event)
{
  if (event->button() == Qt::LeftButton)
  {
    //if (event->modifiers() == Qt::ControlModifier)
    if (event->modifiers() == Qt::ShiftModifier)
    {
      // ALL COORDINATES ARE IN THE SCENE COORDINATE FRAME (is that a problem?)
      mInitialPos = event->scenePos();
      mInitialCenter = this->sceneBoundingRect().normalized().center();
    }
    else
      QAbstractGraphicsShapeItem::mousePressEvent(event);
  }
}

void MyRect::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
{
  if (event->buttons() == Qt::LeftButton)
  {
    if (event->modifiers() == Qt::ShiftModifier)
    {
      // Call the rotation function
      rotateItem(this, mInitialCenter, event->scenePos(), mInitialPos);
      event->accept();
    }
    else
    {
      QAbstractGraphicsShapeItem::mouseMoveEvent(event);
    }
  }
}

void MyRect::mouseReleaseEvent(QGraphicsSceneMouseEvent* event)
{
  QAbstractGraphicsShapeItem::mouseReleaseEvent(event);
}



QGraphicsItem* add_rectangle(QGraphicsScene* scene)
{
  MyRect* rectangle = new MyRect(-50, 10, 80, 80);

  QBrush red_brush(Qt::red);
  QPen pen(Qt::black);
  pen.setWidth(4);

  rectangle->setBrush(red_brush);
  rectangle->setPen(pen);
  rectangle->setFlag(QGraphicsItem::ItemIsMovable);

  scene->addItem(rectangle);

  return rectangle;
}

int main(int argc, char *argv[])
{
  QApplication a(argc, argv);
  QWidget w;

  QGraphicsView* graphicsView = new QGraphicsView(&w);
  graphicsView->setGeometry(0,0,500,500);
  QGraphicsScene* scene = new QGraphicsScene(&w);
  graphicsView->setScene(scene);

  add_rectangle(scene);

  w.show();

  return a.exec();
}

这是精简对象头文件     #ifndef MYRECT_H     #define MYRECT_H     #包括     #include

class MyRect : public QObject, public QGraphicsRectItem
{
    Q_OBJECT

  public:
    MyRect(qreal x, qreal y, qreal width, qreal height);

    void mousePressEvent(QGraphicsSceneMouseEvent* event);
    void mouseMoveEvent(QGraphicsSceneMouseEvent* event);
    void mouseReleaseEvent(QGraphicsSceneMouseEvent* event);

  private:
    QPointF mInitialPos;
    QPointF mInitialCenter;
};

#endif // MYRECT_H

1 个答案:

答案 0 :(得分:0)

项目坐标系是项目的本地。 Qt文档说明了这一点,但可能不够明确,无法通过我的大脑。

角度旋转坐标系位于场景坐标系中。我不得不将项目平移坐标与角度旋转坐标分开。角度是关于center1计算的,项目围绕中心旋转。

因此rotateItem方法变为:

void rotateItem(QAbstractGraphicsShapeItem* shape, QPointF center1,
                QPointF moved, QPointF initial_pos)
{
  QRectF bbox = shape->boundingRect().normalized();
  QPointF center = bbox.center();  // item translate

  // get the angle from the center to the initial click point
  qreal init_x = initial_pos.x() - center1.x();
  qreal init_y = initial_pos.y() - center1.y();
  qreal initial_angle = std::atan2(init_y, init_x);
  qreal x = moved.x() - center1.x();
  qreal y = moved.y() - center1.y();

  qreal mv_angle = std::atan2(y,x);

  // get the changed angle
  qreal angle = (mv_angle - initial_angle)*180/M_PI;

  if (std::fabs(angle) > 360.0)
    angle = 0.0;

  // both transforms give the same result
  QTransform xform;
  xform.translate(center.x(), center.y());
  xform.rotate(angle);
  xform.translate(-center.x(), -center.y());

  shape->setTransform(xform, false);
}