[英]At will scaling and rotation in a 2D space
I'm trying to write a graphical program in C++ with QT where users can scale and rotate objects with the mouse (just like inkscape or CorelDraw does), however after many months trying to make it happen I still cannot make it work. 我正在尝试用QT用C ++编写一个图形程序,用户可以用鼠标缩放和旋转对象(就像inkscape或CorelDraw一样),但是经过数月的尝试,我仍然无法使它工作。 It currently works for example by just rotating or just scaling, but not when the user want to transform the object in an arbitrary way.
例如,当前它仅通过旋转或缩放即可工作,但当用户想要以任意方式变换对象时则无法工作。 There is an example in QT about affine transformation but it is very simple (eg, it scales using a single factor not x and Y factors), it not provides scale directions or fixed scaling point) so I don't know how to extend it or use it.
QT中有一个关于仿射变换的示例,但是它非常简单(例如,它使用单个因子而不是x和Y因子进行缩放),它不提供缩放方向或固定缩放点),所以我不知道如何扩展它或使用它。
This is how the program is expected to behave: 这是程序的预期行为:
So, how can I implement at least the following: 因此,我如何至少实现以下内容:
Here is the code that in my perspective could make it work: See the code here But it does not work :-( . If you can help me with a better implementation I will appreciate it. 在我看来,这是可以使它起作用的代码 : 请在此处查看代码,但它不起作用:-(。如果可以帮助我提供更好的实现,我将不胜感激。
Sorry to put to many questions but I am completely frustrated. 很抱歉提出很多问题,但我完全沮丧。
Thanks, Carlos. 谢谢,卡洛斯。
cannot make it work
无法使其工作
the result is just wrong
结果是错误的
Doesn't describe your problem very well. 不能很好地描述您的问题。
Basically I don't know what is needed in terms of the concatenation/multiplications of matrices
基本上我不知道矩阵的级联/乘法需要什么
In object store: 在对象库中:
1. position 1.位置
2. rotation 2.旋转
3. scale 3.规模
When you need to draw object, perform operations in this order: 当需要绘制对象时,请按以下顺序执行操作:
1. Scale using stored scale factor 1.使用存储的比例因子进行缩放
2. Rotate using stored angle 2.使用存储的角度旋转
3. Translate to position 3.翻译到位置
Given scale factor s and rotation angle r, to rotate/scale object (point array, or whatever) around arbitrary point (px, py), do this: 给定比例因子s和旋转角度r,以围绕任意点(px,py)旋转/缩放对象(点阵列或其他对象),请执行以下操作:
1. Translate object to -px, -py . 1.将对象转换为-px,-py。 Ie for every vertex do vertex -= p;
即每个顶点都做顶点-= p;
2. Scale object. 2.缩放对象。 For every vertex do vertex *= s
对于每个顶点,执行顶点* = s
3. Rotate object. 3.旋转对象。 Rotate every vertex around point zero using angle r.
使用角度r绕零点旋转每个顶点。
4. Translate object to px, py 4.将对象翻译为px,py
Also I'd recommend to take a look at "Affine Transformations" demo in Qt 4. To view demo, launch qtdemo, select "Demonstrations->Affine Transformations". 另外,我建议您查看Qt 4中的“仿射变换”演示。要查看该演示,请启动qtdemo,选择“演示->仿射变换”。
Consider hiring a geometry tutor. 考虑雇用几何老师。 "Months" is too long to deal with rotate/scale/translate problem.
“月份”太长,无法处理旋转/缩放/平移问题。
But, I have no clue on how to combine of these function in a proper order
但是,我不知道如何以适当的顺序组合这些功能
If you're rotating and scaling around same point, the order of operations doesn't matter. 如果围绕同一点旋转和缩放,则操作顺序无关紧要。
--EDIT-- - 编辑 -
Live example: 现场示例:
Points indicate pivot, start of transform, and end of transform. 点表示枢轴,转换开始和转换结束。 Wireframe letters represent original image.
线框字母代表原始图像。
Red letter represent "rotate and uniformly scale" transform. 红色字母表示“旋转并均匀缩放”转换。
Green letters represent "2D scale" transform. 绿色字母代表“ 2D比例”转换。
For both transform you need pivot, point where you began to drag shape, and point where you stopped dragging shape. 对于这两种变换,您都需要枢轴,指向您开始拖动形状的位置和指向您停止拖动形状的位置。
I will not ever explain this again. 我再也不会解释这一点。
transformtest.pro: transformtest.pro:
TEMPLATE = app
TARGET =
DEPENDPATH += .
INCLUDEPATH += .
# Input
HEADERS += MainWindow.h
SOURCES += main.cpp MainWindow.cpp
main.cpp: main.cpp:
#include <QApplication>
#include "MainWindow.h"
int main(int argc, char** argv){
QApplication app(argc, argv);
MainWindow window;
window.show();
return app.exec();
}
MainWindow.h: MainWindow.h:
#ifndef MAIN_WINDOW_H
#define MAIN_WINDOW_H
#include <QGLWidget>
class QPaintEvent;
class MainWindow: public QWidget{
Q_OBJECT
public:
MainWindow(QWidget* parent = 0);
protected slots:
void updateAngle();
protected:
void paintEvent(QPaintEvent* ev);
float angle;
float distAngle;
};
#endif
MainWindow.cpp: MainWindow.cpp:
#include "MainWindow.h"
#include <QTimer>
#include <QPainter>
#include <QColor>
#include <QVector2D>
#include <math.h>
static const int timerMsec = 50;
static const float pi = 3.14159265f;
MainWindow::MainWindow(QWidget* parent)
:QWidget(parent), angle(0), distAngle(0){
QTimer* timer = new QTimer(this);
timer->start(timerMsec);
connect(timer, SIGNAL(timeout()), this, SLOT(update()));
connect(timer, SIGNAL(timeout()), this, SLOT(updateAngle()));
}
float randFloat(){
return (qrand()&0xFF)/255.0f;
}
float randFloat(float f){
return randFloat()*f;
}
inline QVector2D perp(const QVector2D v){
return QVector2D(-v.y(), v.x());
}
void MainWindow::updateAngle(){
angle = fmod(angle + pi*5.0f/180.0f, pi*2.0f);
distAngle = fmod(distAngle + pi*1.0f/180.0f, pi*2.0f);
}
QTransform buildRotateScale(QVector2D pivot, QVector2D start, QVector2D end){
QVector2D startDiff = start - pivot;
QVector2D endDiff = end - pivot;
float startLength = startDiff.length();
float endLength = endDiff.length();
if (startLength == 0)
return QTransform();
if (endLength == 0)
return QTransform();
float s = endLength/startLength;
startDiff.normalize();
endDiff.normalize();
QVector2D startPerp = perp(startDiff);
float rotationAngle = acos(QVector2D::dotProduct(startDiff, endDiff))*180.0f/pi;
if (QVector2D::dotProduct(startPerp, endDiff) < 0)
rotationAngle = -rotationAngle;
return QTransform().translate(pivot.x(), pivot.y()).rotate(rotationAngle).scale(s, s).translate(-pivot.x(), -pivot.y());
}
QTransform buildScale(QVector2D pivot, QVector2D start, QVector2D end){
QVector2D startDiff = start - pivot;
QVector2D endDiff = end - pivot;
float startLength = startDiff.length();
float endLength = endDiff.length();
if ((startDiff.x() == 0)||(startDiff.y() == 0))
return QTransform();
QVector2D s(endDiff.x()/startDiff.x(), endDiff.y()/startDiff.y());
return QTransform().translate(pivot.x(), pivot.y()).scale(s.x(), s.y()).translate(-pivot.x(), -pivot.y());
}
void MainWindow::paintEvent(QPaintEvent* ev){
QPainter painter(this);
QPointF pivot(width()/2, height()/2);
QPointF transformStart(pivot.x() + 100.0f, pivot.y() - 100.0f);
float r = sinf(distAngle)*100.0f + 150.0f;
QPointF transformEnd(pivot.x() + r*cosf(angle), pivot.y() - r*sinf(angle));
painter.fillRect(this->rect(), QBrush(QColor(Qt::white)));
QPainterPath path;
QString str(tr("This is a test!"));
QFont textFont("Arial", 40);
QFontMetrics metrics(textFont);
QRect rect = metrics.boundingRect(str);
path.addText(QPoint((width()-rect.width())/2, (height()-rect.height())/2), textFont, str);
painter.setPen(QColor(200, 200, 255));
painter.drawPath(path);
painter.setTransform(buildRotateScale(QVector2D(pivot), QVector2D(transformStart), QVector2D(transformEnd)));
painter.fillPath(path, QBrush(QColor(255, 100, 100)));
painter.setPen(QColor(100, 255, 100));
painter.setTransform(buildScale(QVector2D(pivot), QVector2D(transformStart), QVector2D(transformEnd)));
painter.fillPath(path, QBrush(QColor(100, 255, 100)));
painter.setTransform(QTransform());
QPainterPath coords;
r = 10.0f;
coords.addEllipse(pivot, r, r);
coords.addEllipse(transformStart, r, r);
coords.addEllipse(transformEnd, r, r);
painter.setPen(QPen(QBrush(Qt::red), 5.0f));
painter.setBrush(QBrush(QColor(127, 0, 0)));
painter.setPen(QPen(QBrush(Qt::green), 5.0f));
painter.drawLine(QLineF(pivot, transformStart));
painter.setPen(QPen(QBrush(Qt::blue), 5.0f));
painter.drawLine(QLineF(transformStart, transformEnd));
painter.setPen(Qt::red);
painter.drawPath(coords);
painter.end();
}
Basically, you have a point (or series of points) that you want to transform with two linear transformations, R (rotation) and S (scaling). 基本上,您有一个点(或一系列点)要通过两个线性变换R(旋转)和S(缩放)进行变换。 So you're trying to calculate something like
所以您正在尝试计算类似
R(S(x))
where x is a point. 其中x是一个点。 If you represent these operations using matrices, then performing consecutive operations is equivalent to multiplying the matrices, ie
如果您使用矩阵表示这些运算,则执行连续运算等效于将矩阵相乘,即
R*S*x
Unfortunately, you haven't given enough information for me to be more specific...could you post some code (just the small, relevant parts) showing what you're doing? 不幸的是,您没有提供足够的信息让我更具体...您能张贴一些代码(只是相关的小部分)来显示您的工作吗? What do you mean by "natural way"?
“自然方式”是什么意思? What about your result is "just wrong"?
您的结果如何呢?
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.