КАТЕГОРИИ: Архитектура-(3434)Астрономия-(809)Биология-(7483)Биотехнологии-(1457)Военное дело-(14632)Высокие технологии-(1363)География-(913)Геология-(1438)Государство-(451)Демография-(1065)Дом-(47672)Журналистика и СМИ-(912)Изобретательство-(14524)Иностранные языки-(4268)Информатика-(17799)Искусство-(1338)История-(13644)Компьютеры-(11121)Косметика-(55)Кулинария-(373)Культура-(8427)Лингвистика-(374)Литература-(1642)Маркетинг-(23702)Математика-(16968)Машиностроение-(1700)Медицина-(12668)Менеджмент-(24684)Механика-(15423)Науковедение-(506)Образование-(11852)Охрана труда-(3308)Педагогика-(5571)Полиграфия-(1312)Политика-(7869)Право-(5454)Приборостроение-(1369)Программирование-(2801)Производство-(97182)Промышленность-(8706)Психология-(18388)Религия-(3217)Связь-(10668)Сельское хозяйство-(299)Социология-(6455)Спорт-(42831)Строительство-(4793)Торговля-(5050)Транспорт-(2929)Туризм-(1568)Физика-(3942)Философия-(17015)Финансы-(26596)Химия-(22929)Экология-(12095)Экономика-(9961)Электроника-(8441)Электротехника-(4623)Энергетика-(12629)Юриспруденция-(1492)Ядерная техника-(1748) |
Пример рисования изображения и формирования тела вращения
/** @mainpage Формирование элементарных графических изображений В примере показано создание приложения, которое формирует элементарное графическое изображение с ипользованием некоторых возможностей библиотеки Qt - классов QPainter и QPainterPath. @file main.cpp @brief Запуск приложения. @details Создается окно из класса Painter. Производится запуск цикла обработки сообщенией. */ #include <QApplication> #include <QTranslator> #include "painter.h"
int main(int argc, char *argv[]) { QApplication app(argc, argv); // Устанавливаем язык для преобразовния строк, использующих функции // tr() или translate(). // В данном примере они содержаться в файле painter.cpp. // Внимание! Строки, которые будут преобразовываться через QTranslator // должны содержать только латинские символы! // Файл ru.ts сгенерирован утилитой lupdate../painter.cpp -ts ru.ts и // отредактирован в Qt Linguist // Файл ru.qm сформирован утилитой lrelease ru.ts QTranslator translator; //путь, начинающийся с:/ означает, что требуемый файл находится // в файле-ресурсе приложения. Если оставить только translations/ru.qm, // то приложение будет искать файл в директории translations относительно // текущей директории if(translator.load(":/translations/ru.qm")) qApp->installTranslator(&translator);
Painter painter; painter.show(); return app.exec(); }
/** @file painter.h @brief Декларация классов программы. */ #include <QWidget> #include <QVector> #include <QFrame>
class RenderArea; class InputImage; class QLineEdit; /** @class Painter @brief Главное окно приложения. @details Обеспечивает формирование окна приложения, содержащего область отображения рисунка и кнопку выхода */ class Painter: public QWidget { Q_OBJECT
public: Painter();
protected: RenderArea * m_RenderArea; ///< Область отображения рисунка. InputImage * m_InputArea; ///< Область рисования кривой для вращения. QLineEdit * m_Exy; ///< Шаг поворота при формирвоании тела вращения.
QLineEdit * m_Eyz; ///< Угол поворота в градусах плоскости yz QLineEdit * m_Exz; ///< Угол поворота в градусах плоскости xz
public slots: void convert(); };
/// @class BaseRenderArea /// @brief Базовый класс для панелей ввода и отображения. class BaseRenderArea: public QFrame { Q_OBJECT
public: ///@brief Структура для хранения координат в массиве struct PointCoords { int x; int y; PointCoords(){ x=y=0;}; PointCoords(int x1, int y1){ x=x1; y=y1; }; }; BaseRenderArea(QWidget *parent = 0);
/// @brief Минимальный размер области отображения /// @details Изменение размеров окна приложения производится с учетом /// допустипых размеров всех элементов. Функция обеспечивает корректное /// отображение области графических примитивов /// @return Допустимые минимальные размеры QSize minimumSizeHint() const;
/// @brief Размер области отображения по умолчанию /// @details При создании окна автоматически рассчитываются размеры /// по указанным рекомендованным размерам всех элементов. /// @return рекомендованные размеры QSize sizeHint() const;
/// @brief Формируте тело вращения по указанному массиву координат void setPoints(const QVector<PointCoords> &, double xy_step_angle, double yz_angle, double xz_angle);
protected: float m_PenWidth; ///< Ширина пера отображения по умолчанию.
/// @brief Обработчик события перерисовки virtual void paintEvent(QPaintEvent * event);
QPainterPath m_Path; ///< Шаблон отображения графических примитивов. };
/** @class RenderArea @brief Область отображения тела вращения. @details Формирует и отображает рисунок */ class RenderArea: public BaseRenderArea { Q_OBJECT
public: RenderArea(QWidget *parent = 0);
/// @brief Метод для формирования тела вращения по массиву значений void setPoints(const QVector<PointCoords> &, double xy_step_angle, double yz_angle, double xz_angle); };
/** @class InputImage @brief Область формирования кривой. @details Обеспечивает формирование, отрисовку кривой. */ class InputImage: public BaseRenderArea { Q_OBJECT
public: InputImage(QWidget *parent = 0);
/// @brief Метод для сканирования введенного изображения void getPoints(QVector<PointCoords> &);
public slots: /// @brief Очистка изображения void clearImage();
protected: /// @brief Обработчик события нажатия клавиши мыши virtual void mousePressEvent (QMouseEvent * event); /// @brief Обработчик события перемещения мыши virtual void mouseMoveEvent (QMouseEvent * event);
/// @brief Вспомогательный метод преобразования координат QPoint from(const QPoint&); }; /** @file painter.cpp @brief Реализация классов программы. */ #include <QPainter> #include <QPushButton> #include <QVBoxLayout> #include <QHBoxLayout> #include <QMouseEvent> #include <QLineEdit> #include <QSpacerItem> #include <QImage> #include <QLabel> #include "painter.h"
#define _USE_MATH_DEFINES #include "math.h"
// Размер поля отображения const float _x_aspect=400; const float _y_aspect=400;
/// @brief Конструктор главного окна /// @details Устанавливает режим выравнивания элементов и создает их. Painter::Painter() { QVBoxLayout *layout = new QVBoxLayout; QHBoxLayout *hlayout = new QHBoxLayout;
// Создаём панели для ввода кривой и вывода тела вращения m_InputArea = new InputImage(this); m_RenderArea = new RenderArea(this);
// формируем отдельную панель для органов управления QFrame * controls = new QFrame(); QVBoxLayout *controllayout = new QVBoxLayout; controls->setLayout(controllayout); controls->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Expanding);
m_Exy=new QLineEdit("30", this); m_Exz=new QLineEdit("0", this); m_Eyz=new QLineEdit("50", this); QPushButton * btn_convert = new QPushButton(tr("Convert")); QPushButton * btn_clear = new QPushButton(tr("Clear"));
QObject::connect(btn_clear, SIGNAL(clicked(bool)), m_InputArea, SLOT(clearImage()));
QObject::connect(btn_convert, SIGNAL(clicked(bool)), this, SLOT(convert()));
// наполняем панель с органами управления controllayout->addWidget(new QLabel(tr("xy step"))); controllayout->addWidget(m_Exy); controllayout->addWidget(new QLabel(tr("xz angle"))); controllayout->addWidget(m_Exz); controllayout->addWidget(new QLabel(tr("yz angle"))); controllayout->addWidget(m_Eyz); controllayout->addWidget(btn_convert); controllayout->addItem(new QSpacerItem(10,10, QSizePolicy::Minimum, QSizePolicy::Expanding)); controllayout->addWidget(btn_clear);
// устанавливаем порядок отображения панелей hlayout->addWidget(m_InputArea); hlayout->addWidget(controls); hlayout->addWidget(m_RenderArea);
QPushButton * btn = new QPushButton(tr("Close"), this); QObject::connect(btn, SIGNAL(clicked(bool)), this, SLOT(close()));
// формируем окончательный вид, добавляем кнопку Close layout->addLayout(hlayout); layout->addWidget(btn);
setLayout(layout); };
/// @details Сканирует панель ввода, преобразует введенные значения углов, /// запускает формирование тела вращения void Painter::convert() { double xy_step_angle, yz_angle, xz_angle; QVector<BaseRenderArea::PointCoords> data;
xy_step_angle = m_Exy->text().toDouble()*M_PI/180.0; yz_angle = m_Eyz->text().toDouble()*M_PI/180.0;
xz_angle = m_Exz->text().toDouble()*M_PI/180.0;
m_InputArea->getPoints(data); m_RenderArea->setPoints(data, xy_step_angle, yz_angle, xz_angle); };
/// @details Конструктор базового класса панелей ввода и отображения. /// Устанавливает формат рамки и инициализирует общие переменные. /// @param parent - Если значение NULL, то область отображения станет /// самостоятельным окном. В противном случае - виджетом-потомком. BaseRenderArea::BaseRenderArea(QWidget *parent):QFrame(parent) { // формируем рамку вокруг виджета setFrameStyle(QFrame::Panel | QFrame::Raised); setLineWidth(2); //Установим перо по умолчанию, равное 2 m_PenWidth=2; };
QSize BaseRenderArea::minimumSizeHint() const { return QSize(100, 100); } QSize BaseRenderArea::sizeHint() const { return QSize(_x_aspect, _y_aspect); }
void BaseRenderArea::paintEvent(QPaintEvent *event) { // Готовим объект отображения QPainter painter(this);
// Определяем режим отображения со сглаживанием painter.setRenderHint(QPainter::Antialiasing);
// Определяем масштаб в зависимости от текущих геометрических размеров // области отображения painter.scale(width()/_x_aspect, height()/_y_aspect);
// Создаем перо для отображения контуров. Используем красный цвет и толщину // линий равную m_PenWidth. painter.setPen( QPen(QColor(255,0,0), m_PenWidth, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin));
// Отображаем контуры painter.drawPath(m_Path);
QFrame::paintEvent(event); // рисуем рамку вокруг панели вызовом предка }
/// @brief Конструктор области отображения RenderArea::RenderArea(QWidget *parent) : BaseRenderArea(parent) { setBackgroundRole(QPalette::Base); QFont font("Arial", 12); m_Path.addText(10,_y_aspect/2, font, tr("Draw on the left panel")); m_PenWidth=0.5; }
/// @param data - массив точек кривой /// @param xy_step_angle - шаг поворота при формировании тела вращения в градусах /// @param yz_angle - угол поворота в градусах плоскости yz /// @param xz_angle - угол поворота в градусах плоскости xz void RenderArea::setPoints(const QVector<PointCoords> & data, double xy_step_angle, double yz_angle, double xz_angle) { m_Path=QPainterPath(); // очищаем область вывода
if(!data.size())return; // Если на входе ничего нет - выходим
double phi; double x,y,z; double xw, yw;
// для ускорения работы программы, синусы и косинусы // вычисляем заранее double cos_yz=cos(yz_angle), sin_yz=sin(yz_angle); double cos_xz=cos(xz_angle), sin_xz=sin(xz_angle);
// цикл, формирующий тело вращения из линии for(phi=M_PI/24; phi<2*M_PI+M_PI/24; phi+=xy_step_angle){ const PointCoords *point;
double sin_r1=sin(phi), cos_r1=cos(phi); for(int i=0; i<data.size();i++){ point=&data[i];
// переназначаем координаты. z=point->x; x=point->y; // смотрим вдоль z. Поворачиваем плоскость x-y. // Поскольку y=0, вычисления относительно y отбрасываем xw=x*cos_r1; //-y*sin_fi; y=x*sin_r1; //+y*cos_fi; x=xw;
// Поворачиваем в плоскости y-z yw=y*cos_yz-z*sin_yz; z=y*sin_yz+z*cos_yz; y=yw;
// Поворачиваем в плоскости x-z xw=x*cos_xz-z*sin_xz; //z=x*sin_fi+z*cos_fi;// z - дальше не используется x=xw;
//проецируем на экран, отбросив z //Смещаем в середину панели и масштабируем с коэффициентом 0.5 xw=_x_aspect/2+x*0.5; yw=_y_aspect/2+y*0.5;
if(!i) m_Path.moveTo(xw,yw); else m_Path.lineTo(xw,yw); } } update(); };
InputImage::InputImage(QWidget *parent) :BaseRenderArea(parent) { };
/// @details Преобразует координаты мыши в локальные координаты виджета QPoint InputImage::from(const QPoint &point){
QPoint pos = mapFrom(this, point); return QPoint(pos.x()* _x_aspect/ width(), pos.y()*_y_aspect/ height()); };
void InputImage::mousePressEvent (QMouseEvent * event) { //Если нажата левая кнопка мыши - рисуем if (event->buttons () & Qt::LeftButton){ m_Path.moveTo(from(event->pos())); } } void InputImage::mouseMoveEvent (QMouseEvent * event) { if (event->buttons () & Qt::LeftButton){ m_Path.lineTo(from(event->pos())); } // принудительно отрисоваваем. Внимание! реализация упрощенная. // На каждое движение мыши будет отрисоваваться всё, что было введено ранее update(); };
void InputImage::clearImage() { m_Path=QPainterPath(); // Создаём пустой объект. update();// Очищаем изображение. };
void InputImage::getPoints(QVector<PointCoords> & data) { data.clear(); // очищаем массив на случай, если там что-то было QColor color(255,0,0); QRgb rgb_color=color.rgb(); // формируем устройство отображения QImage image(_x_aspect,_y_aspect, QImage::Format_RGB32); QPainter painter(&image); painter.setPen(QPen(color, 1, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin)); //выводим сохраненный рисунок painter.drawPath(m_Path);
//сканируем столбцы изображения в матрице пикселов for(int x=0; x<_x_aspect; x++){ // двигаемся снизу изображения for(int y=image.height(); y>=0; y--){ QRgb rgb=image.pixel(x,y); //запоминаем первую точку столбца с соответствующим цветом if(rgb==rgb_color){ data.push_back(PointCoords(x,image.height()-y)); break; } } } };
Файл перевода translations/ru.ts, сформированный следующей утилитой: lupdate../painter.cpp -ts ru.ts и отредактированный в программе Qt Linguist. <?xml version="1.0" encoding="utf-8"?> <!DOCTYPE TS> <TS version="2.0" language="ru_RU"> <context> <name>Painter</name> <message> <location filename="../painter.cpp" line="42"/> <source>Convert</source> <translation type="unfinished">Преобразовать</translation> </message> <message> <location filename="../painter.cpp" line="43"/> <source>Clear</source> <translation type="unfinished">Очистить</translation> </message> <message> <location filename="../painter.cpp" line="51"/> <source>xy step</source> <translation type="unfinished">шаг вращения</translation> </message> <message> <location filename="../painter.cpp" line="53"/> <source>xz angle</source> <translation type="unfinished">угол xz</translation> </message> <message> <location filename="../painter.cpp" line="55"/> <source>yz angle</source> <translation type="unfinished">угол yz</translation> </message> <message> <location filename="../painter.cpp" line="66"/> <source>Close</source> <translation type="unfinished">Закрыть</translation> </message> </context> <context> <name>RenderArea</name> <message> <location filename="../painter.cpp" line="136"/> <source>Draw on the left panel</source> <translation type="unfinished">Рисовать слева</translation> </message> </context> </TS> Внимание! В файле ресурсов подключается результат компиляции файла перевода translations/ru.qm, который необходиом получить вызовом lrelease ru.ts. Если перевод не требуется, не следует подключать в файле проекта использование файла-ресурсов приложения и этого перевода.
Файл ресурсов приложения g2.qrc <RCC> <qresource prefix="/" > <file>translations/ru.qm</file> </qresource> </RCC>
Файл проекта g2.pro (может быть сформирован автоматически): TEMPLATE = app TARGET = DEPENDPATH +=. translations INCLUDEPATH +=.
HEADERS += painter.h SOURCES += main.cpp painter.cpp RESOURCES += g2.qrc TRANSLATIONS += translations/ru.ts
Приложение позволяет нарисовать кривую (левой клавишей мыши на левой панели) и, по нажатию кнопки «Преобразовать», обеспечивает формирование тела вращения с указанными параметрами: шаг поворота кривой, а также угла наклона плоскостей xz и yz. Все значения указываются в градусах.
Рисунок 2 – Внешний вид приложения формирования тела вращения
Более подробно см.: · примеры из комплекта Qt - qt\examples\painting\ · Макс Шлее - Qt 4.5. Профессиональное программирование на C++. Издательство: БХВ-Петербург, 2010 г.–т, 896 стр.,– ISBN 978-5-9775-0398-3 · А. В. Казанцев. Основы компьютерной графики для программистов. Учебное пособие. Казань, 2005.
Дата добавления: 2014-11-25; Просмотров: 459; Нарушение авторских прав?; Мы поможем в написании вашей работы! Нам важно ваше мнение! Был ли полезен опубликованный материал? Да | Нет |