Студопедия

КАТЕГОРИИ:


Архитектура-(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; Нарушение авторских прав?; Мы поможем в написании вашей работы!


Нам важно ваше мнение! Был ли полезен опубликованный материал? Да | Нет



studopedia.su - Студопедия (2013 - 2024) год. Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав! Последнее добавление




Генерация страницы за: 0.203 сек.