根据左上角缩放旋转的项目移动项目
Scaling a rotated item based on top left moves the item
我希望能够根据中心旋转 QGraphicsItem
,并根据左上角缩放它。
当我尝试结合旋转和缩放时,项目显然也移动了...
#include <QApplication>
#include <QGraphicsView>
#include <QGraphicsTextItem>
void testTransformations(QGraphicsScene* s)
{
qreal angle = 30, scaleX = 2, scaleY = 1;
// Reference rotated not scaled
QGraphicsTextItem* ref = new QGraphicsTextItem("bye world");
ref->setFont(QFont("Arial", 20));
ref->setDefaultTextColor(Qt::green);
s->addItem(ref);
qreal center0X = ref->boundingRect().center().x();
qreal center0Y = ref->boundingRect().center().y();
QTransform t0;
t0.translate(center0X, center0Y);
t0.rotate(angle);
t0.translate(-center0X, -center0Y);
ref->setTransform(t0);
// Reference scaled not rotated
QGraphicsTextItem* ref1 = new QGraphicsTextItem("bye world");
ref1->setFont(QFont("Arial", 20));
ref1->setDefaultTextColor(Qt::yellow);
s->addItem(ref1);
QTransform t;
t.scale(scaleX, scaleY);
ref1->setTransform(t);
// Rotate around center of resized item
QGraphicsTextItem* yyy = new QGraphicsTextItem("bye world");
yyy->setDefaultTextColor(Qt::red);
yyy->setFont(QFont("Arial", 20));
s->addItem(yyy);
qreal center1X = yyy->boundingRect().center().x() * scaleX;
qreal center1Y = yyy->boundingRect().center().y() * scaleY;
// in my code I store the item size, either before or after the resize, and use it to determine the center - which is virtually the same thing as this for a single operation
QTransform t1;
t1.translate(center1X, center1Y);
t1.rotate(angle);
t1.translate(-center1X, -center1Y);
t1.scale(scaleX, scaleY);
yyy->setTransform(t1);
// rotated around center of bounding rectangle
QGraphicsTextItem* xxx = new QGraphicsTextItem("bye world");
xxx->setDefaultTextColor(Qt::blue);
xxx->setFont(QFont("Arial", 20));
s->addItem(xxx);
qreal center2X = xxx->boundingRect().center().x();
qreal center2Y = xxx->boundingRect().center().y();
QTransform t2;
t2.translate(center2X, center2Y);
t2.rotate(angle);
t2.translate(-center2X, -center2Y);
t2.scale(scaleX, scaleY);
xxx->setTransform(t2);
}
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
QGraphicsScene s;
QGraphicsView view(&s);
s.setSceneRect(-20, -20, 500, 500);
view.show();
testTransformations(&s);
return app.exec();
}
结果:
- 绿色是旋转的,未缩放(或缩放了不同的量)
- 黄色是缩放的,不是旋转的
- 蓝色被缩放,并由边界矩形的中心旋转(未调整大小)
- 红色围绕中心缩放和旋转
我现在很明显,转换操作正确 - 如果我调整大小并旋转一个项目,我首先得到黄色然后是红色项目。
然而,我需要的是,如果一个项目已经旋转(绿色)然后缩放,表现得像蓝色 - 在相同方向拉伸,没有跳跃,而如果一个项目首先缩放,然后旋转,表现得像红色...更复杂的是,原始项目(绿色)可能应用了缩放,所以我使用边界矩形的简单解决方案行不通。
我已经尝试计算变化...总是有奇怪的结果。
是否可以根据左上角缩放旋转的项目,同时不移动它,同时围绕其中心旋转它?
它可能需要增量转换,并且根据它们的应用顺序得到不同的结果会很奇怪。
编辑:我一直在尝试位置调整,因为转换失败了,但我一直无法获得转换函数的公式,该转换函数会给我类型的平滑视觉转换:
1) 旋转项目(固定到中心)
2) 缩放项目(固定在左上角)而不跳跃
3) 旋转项目(固定到中心)
其中第 2 步还包括位置偏移。我只是不知道该怎么做。
在我看来,在 "red" 转换的片段中,我会在转换前后添加一个 mapToScene(somePoint)
,并根据结果执行校正 (moveBy
)。
这不是一个很好的修复,但仍然...如果我知道如何在调整大小后调整项目的位置以使其不会跳动,它仍然是一个修复...
好的,不好意思编辑晚了,好像在Qt里面直接实现是不可能的
然而,您可以使用简单的三角函数计算围绕 0,0 原点旋转时与中心的偏移量,并手动移动项目以补偿位移。
想象一个圆心为 0,0 的圆,半径为从圆心到项目边界框中心的直线。当您围绕 0,0 原点旋转项目时,项目的边界框中心将始终位于圆上,因此您可以计算给定旋转角度的偏移量,然后旋转并调整项目的位置以匹配中心以前的状态。
这里有一个小插图,如您所见,旋转后项目移动了偏移量,以使其看起来好像围绕其中心旋转而不是围绕左上角旋转。当然,由于原点仍然是 0,0,它将按您的预期缩放。
编辑:更简单,无需触发,仅使用 Qt 功能,此方法将围绕其中心旋转项目,同时变换原点位于左上角:
static void offsetRotation(qreal angle, QGraphicsItem * i) {
QPointF c = i->mapToScene(i->boundingRect().center());
i->setRotation(angle);
QPointF cNew = i->mapToScene((i->boundingRect()).center());
QPointF offset = c - cNew;
i->moveBy(offset.x(), offset.y());
}
但是,我注意到一些奇怪的事情 - 当原点设置为左上角时,根据我长期使用图形设计软件的经验,缩放并没有真正将左上角保持在我预期的相同位置。相反,该项目将随着其规模的增加而慢慢漂移。原点似乎确实对缩放有一些影响,但我肯定不会称其为任何衡量标准。因此,根据您想要实现的目标,您可能还必须使用相同的偏移调整技巧来进行缩放。当一个项目缩放时,它会继续报告相同的位置,但如果你将其映射到场景,你会意识到它实际上发生了变化,因此你可以跟踪该变化并进行补偿,以便通过相应的 offsetScale
方法。
所有这一切都是有代价的,你的坐标最终会为了保持预期的视觉输出而变得一团糟。这可能会在以后证明是一个并发症。一种解决方案是为您的项目创建您自己的 "public" 坐标,并在内部管理所有混乱以使最终结果正常化。
希望其他人可以提供更清晰的解决方案,从我使用 Qt 的经验来看,从事图形工作的人 类 似乎对图形工作流程几乎没有经验,毫无疑问他们是优秀的程序员, 但最终结果是 Qt 的图形 类 通常是违反直觉的,甚至完全无法按照人们对专业图形软件所期望的方式工作。也许更务实的头脑可以为这个问题提供更好的补救措施。
这是我解决问题的尝试 - 它有效但不是一个很好的解决方案:
- 在任何转换中,我存储
m31()
和 m32()
。
- 如果转换是缩放,我会通过新旧
m31()
和 m32()
之间的变化来抵消
我希望能够根据中心旋转 QGraphicsItem
,并根据左上角缩放它。
当我尝试结合旋转和缩放时,项目显然也移动了...
#include <QApplication>
#include <QGraphicsView>
#include <QGraphicsTextItem>
void testTransformations(QGraphicsScene* s)
{
qreal angle = 30, scaleX = 2, scaleY = 1;
// Reference rotated not scaled
QGraphicsTextItem* ref = new QGraphicsTextItem("bye world");
ref->setFont(QFont("Arial", 20));
ref->setDefaultTextColor(Qt::green);
s->addItem(ref);
qreal center0X = ref->boundingRect().center().x();
qreal center0Y = ref->boundingRect().center().y();
QTransform t0;
t0.translate(center0X, center0Y);
t0.rotate(angle);
t0.translate(-center0X, -center0Y);
ref->setTransform(t0);
// Reference scaled not rotated
QGraphicsTextItem* ref1 = new QGraphicsTextItem("bye world");
ref1->setFont(QFont("Arial", 20));
ref1->setDefaultTextColor(Qt::yellow);
s->addItem(ref1);
QTransform t;
t.scale(scaleX, scaleY);
ref1->setTransform(t);
// Rotate around center of resized item
QGraphicsTextItem* yyy = new QGraphicsTextItem("bye world");
yyy->setDefaultTextColor(Qt::red);
yyy->setFont(QFont("Arial", 20));
s->addItem(yyy);
qreal center1X = yyy->boundingRect().center().x() * scaleX;
qreal center1Y = yyy->boundingRect().center().y() * scaleY;
// in my code I store the item size, either before or after the resize, and use it to determine the center - which is virtually the same thing as this for a single operation
QTransform t1;
t1.translate(center1X, center1Y);
t1.rotate(angle);
t1.translate(-center1X, -center1Y);
t1.scale(scaleX, scaleY);
yyy->setTransform(t1);
// rotated around center of bounding rectangle
QGraphicsTextItem* xxx = new QGraphicsTextItem("bye world");
xxx->setDefaultTextColor(Qt::blue);
xxx->setFont(QFont("Arial", 20));
s->addItem(xxx);
qreal center2X = xxx->boundingRect().center().x();
qreal center2Y = xxx->boundingRect().center().y();
QTransform t2;
t2.translate(center2X, center2Y);
t2.rotate(angle);
t2.translate(-center2X, -center2Y);
t2.scale(scaleX, scaleY);
xxx->setTransform(t2);
}
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
QGraphicsScene s;
QGraphicsView view(&s);
s.setSceneRect(-20, -20, 500, 500);
view.show();
testTransformations(&s);
return app.exec();
}
结果:
- 绿色是旋转的,未缩放(或缩放了不同的量)
- 黄色是缩放的,不是旋转的
- 蓝色被缩放,并由边界矩形的中心旋转(未调整大小)
- 红色围绕中心缩放和旋转
我现在很明显,转换操作正确 - 如果我调整大小并旋转一个项目,我首先得到黄色然后是红色项目。
然而,我需要的是,如果一个项目已经旋转(绿色)然后缩放,表现得像蓝色 - 在相同方向拉伸,没有跳跃,而如果一个项目首先缩放,然后旋转,表现得像红色...更复杂的是,原始项目(绿色)可能应用了缩放,所以我使用边界矩形的简单解决方案行不通。
我已经尝试计算变化...总是有奇怪的结果。
是否可以根据左上角缩放旋转的项目,同时不移动它,同时围绕其中心旋转它?
它可能需要增量转换,并且根据它们的应用顺序得到不同的结果会很奇怪。
编辑:我一直在尝试位置调整,因为转换失败了,但我一直无法获得转换函数的公式,该转换函数会给我类型的平滑视觉转换:
1) 旋转项目(固定到中心)
2) 缩放项目(固定在左上角)而不跳跃
3) 旋转项目(固定到中心)
其中第 2 步还包括位置偏移。我只是不知道该怎么做。
在我看来,在 "red" 转换的片段中,我会在转换前后添加一个 mapToScene(somePoint)
,并根据结果执行校正 (moveBy
)。
这不是一个很好的修复,但仍然...如果我知道如何在调整大小后调整项目的位置以使其不会跳动,它仍然是一个修复...
好的,不好意思编辑晚了,好像在Qt里面直接实现是不可能的
然而,您可以使用简单的三角函数计算围绕 0,0 原点旋转时与中心的偏移量,并手动移动项目以补偿位移。
想象一个圆心为 0,0 的圆,半径为从圆心到项目边界框中心的直线。当您围绕 0,0 原点旋转项目时,项目的边界框中心将始终位于圆上,因此您可以计算给定旋转角度的偏移量,然后旋转并调整项目的位置以匹配中心以前的状态。
这里有一个小插图,如您所见,旋转后项目移动了偏移量,以使其看起来好像围绕其中心旋转而不是围绕左上角旋转。当然,由于原点仍然是 0,0,它将按您的预期缩放。
编辑:更简单,无需触发,仅使用 Qt 功能,此方法将围绕其中心旋转项目,同时变换原点位于左上角:
static void offsetRotation(qreal angle, QGraphicsItem * i) {
QPointF c = i->mapToScene(i->boundingRect().center());
i->setRotation(angle);
QPointF cNew = i->mapToScene((i->boundingRect()).center());
QPointF offset = c - cNew;
i->moveBy(offset.x(), offset.y());
}
但是,我注意到一些奇怪的事情 - 当原点设置为左上角时,根据我长期使用图形设计软件的经验,缩放并没有真正将左上角保持在我预期的相同位置。相反,该项目将随着其规模的增加而慢慢漂移。原点似乎确实对缩放有一些影响,但我肯定不会称其为任何衡量标准。因此,根据您想要实现的目标,您可能还必须使用相同的偏移调整技巧来进行缩放。当一个项目缩放时,它会继续报告相同的位置,但如果你将其映射到场景,你会意识到它实际上发生了变化,因此你可以跟踪该变化并进行补偿,以便通过相应的 offsetScale
方法。
所有这一切都是有代价的,你的坐标最终会为了保持预期的视觉输出而变得一团糟。这可能会在以后证明是一个并发症。一种解决方案是为您的项目创建您自己的 "public" 坐标,并在内部管理所有混乱以使最终结果正常化。
希望其他人可以提供更清晰的解决方案,从我使用 Qt 的经验来看,从事图形工作的人 类 似乎对图形工作流程几乎没有经验,毫无疑问他们是优秀的程序员, 但最终结果是 Qt 的图形 类 通常是违反直觉的,甚至完全无法按照人们对专业图形软件所期望的方式工作。也许更务实的头脑可以为这个问题提供更好的补救措施。
这是我解决问题的尝试 - 它有效但不是一个很好的解决方案:
- 在任何转换中,我存储
m31()
和m32()
。 - 如果转换是缩放,我会通过新旧
m31()
和m32()
之间的变化来抵消