我正在尝试使用QT在C ++中编写图形程序,用户可以使用鼠标缩放和旋转对象(就像inkscape或CorelDraw一样),但是经过几个月的努力才能实现,我仍然无法使其工作。它目前仅通过旋转或仅缩放来工作,但不是当用户想要以任意方式转换对象时。在QT中有一个关于仿射变换的例子,但它很简单(例如,它使用单个因子而不是x和Y因子进行缩放),它不提供缩放方向或固定缩放点)所以我不知道如何扩展它或使用它。
这是程序预期的表现方式:
那么,我怎样才能实现至少以下内容:
以下是我认为可以使其工作的代码:See the code here但它不起作用:-(。如果你可以帮助我实现更好的实现,我会很感激。
很抱歉提出了许多问题,但我完全感到沮丧。
谢谢, 卡洛斯。
答案 0 :(得分:2)
无法正常工作
结果是错误的
没有很好地描述你的问题。
基本上我不知道矩阵的连接/乘法需要什么
在对象库中:
位置
2.旋转
3.比例
当您需要绘制对象时,按此顺序执行操作:
1.使用存储的比例因子进行缩放
2.使用存储角度旋转
3.转换到位置
给定比例因子s和旋转角度r,在任意点(p.x,p.y)周围旋转/缩放对象(点阵列或其他),执行以下操作:
1.将对象转换为-p.x,-p.y。即对于每个顶点做顶点 - = p;
2.缩放对象。对于每个顶点做顶点* = s
3.旋转物体。使用角度r旋转点零点周围的每个顶点
4.将对象翻译为p.x,p.y。
另外,我建议您在Qt 4中查看"Affine Transformations"演示。要查看演示,请启动qtdemo,选择“演示 - >仿射变换”。
考虑聘请几何导师。 “月份”太长,无法处理旋转/缩放/翻译问题。
但是,我不知道如何以正确的顺序组合这些功能
如果您在同一点上旋转和缩放,则操作顺序无关紧要。
- 编辑 -
实例:
点表示枢轴,变换开始和变换结束。 线框字母代表原始图像 红色字母代表“旋转和均匀缩放”变换 绿色字母代表“2D比例”变换。
对于两个变换,您需要枢轴,指向开始拖动形状的位置,并指向停止拖动形状的位置。
我不会再解释这个。
transformtest.pro:
TEMPLATE = app
TARGET =
DEPENDPATH += .
INCLUDEPATH += .
# Input
HEADERS += MainWindow.h
SOURCES += main.cpp MainWindow.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:
#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:
#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();
}
答案 1 :(得分:1)
基本上,您有一个点(或一系列点)要通过两个线性变换R(旋转)和S(缩放)进行变换。所以你试图计算像
这样的东西R(S(x))
其中x是一个点。如果使用矩阵表示这些操作,则执行连续操作相当于乘以矩阵,即
R*S*x
不幸的是,你没有提供足够的信息让我更具体......你能发布一些代码(只是小的,相关的部分)来展示你在做什么吗? “自然方式”是什么意思?你的结果怎么样“错了”?