Работая над приложением для GPS навигаторов, столкнулся с необходимостью создания «псевдо 3D» изображения. Пример такого изображения знаком любому, кто хоть раз смотрел легендарные StarWars.
Тот, кто занимался 3D графикой, сразу подумает на использование матриц поворота. В принципе, все верно, за исключением той вещи, что «родные» QMatrix — совершенно двухмерны и не понимают, что же мы от них хотим.
А хотим мы очень простое действо — реализовать поворот изображения по оси oX. Некоторое время назад единственным возможным для Qt решением вопроса был попиксельный пересчет изображения по формулам проекции с фокусом по Z. Как вы можете догадаться, что для медленных навигаторов это был совсем не вариант.
Итак, тролли Нокия предоставили нам класс QTransform, который уже отлично применим для нужных нам вещей. К примеру, мы можем попробовать так в событии:
void Widget::paintEvent(QPaintEvent *e) { QPainter painter; painter.begin(this); painter.setRenderHint(QPainter::SmoothPixmapTransform); QTransform transform; transform.translate(rect().width() / 2, 0); transform.rotate(70, Qt::XAxis); transform.translate(-rect().width() / 2, 0); painter.setTransform(transform); /* НЕОБХОДИМАЯ ОТРИСОВКА */ painter.end(); }
Достаточно проверить на практике и сравнить результаты:
В целом, это еще одно направление работы с трансформированием изображения. Как ни странно, но корни у QTransform растут из блога Zack Rusin’а, за что ему огромное спасибо! :)
Одной из интересных особенностей Qt по работе с матрицами и трансформациями — невозможность штатными средствами узнать угол поворота изображения. Почему так — неизвестно, но факт остается фактом. В случае QTransform вопрос является достаточно непростым по тем причинам, что матрица трансформации является результирующей для матриц сдвига, масштабирования и поворота. Если трансформация задана только матрицей поворота и вы в этом уверены, возможно использовать нечто подобное:
#include <math.h> // Calculates angle of rotation on Ox coordinates qreal rotateAngleOfOx(QTransform & tr) { double pi = 3.141592653; qreal angle = (atan(tr.m21()/tr.m11())*180/pi); if (tr.m21() > 0 && tr.m11() < 0) angle+=180; if (tr.m21() < 0 && tr.m11() < 0) angle+=180; return angle; }
Это пример для только для оси абсцисс. Вы можете самостоятельно расширить ее для нужных вам целей. В идеальном случае, нужно сделать универсальную функцию, в которую бросается значение Qt::Axis, при этом внутри нее должны учитываться другие возможные трансформации.
Вполне возможно, что после сдачи текущего проекта я опубликую полную подборку подобных функций, часто применимых для картографических программ.