Задача Радуга (FIT9201SURNAME_Rainbow)
Срок выполнения
Рекомендуемая сдача: 17 февраля
Крайний срок: 24 февраля
Предисловие
Задача на использование таймера, буферизацию, простейшую анимацию, случайные величины и визуализацию без блокировки ввода пользователя. В задаче используется визуализация методом Монте-Карло, цветовая модель HSV (ТонНасыщенностьЗначение), аффинные преобразования на плоскости (только поворот).
Условия
Элементы пользовательского интерфейса приложения
1. Два элемента для задания размера поля (ширина и высота)
2. Область, где рисуется изображение
3. Кнопка Clear - очистить поле (можно добавить диалог выбора цвета)
4. Кнопка Start - начать или продолжить рисовать изображение
5. Кнопка Stop - прекратить рисовать изображение (можно объединить функции кнопок Start/Stop в одну)
6. Слайдер для регулировки скорости рисования элементов изображения
Логика приложения
Ваше приложение должно уметь рисовать радугу, используя метод Монте-Карло. Идея метода заключается в выборе случайных точек изображения и закраски их согласно некоторому условию. Условие, позволяющее получить требуемое изображение приводится в листинге. Допускается его модификация, с целью улучшения, и обязательна самостоятельная реализация функции преобразования цвета из цветовой модели HSV в RGB
Если процесс рисования запущен (нажата кнопка Start), то через небольшие промежутки времени (регулируются слайдером 6) на изображении появляются новые элементы (один/несколько пикселей, на ваше усмотрение). При первом запуске приложения слайдер должен быть выставлен так, чтобы после нажатия на кнопку Start, через 10-15 сек получалась "радуга". Наличие пустых точек на радуге допускается. Выбранный способ обновления изображения не должен блокировать пользовательский ввод (должны отсутствовать ощутимые задержки на поведение пользователя).
Листинг 1.1
void DrawPixel() {
const float nx = Random();// [0, 1]
const float ny = Random();// [0, 1]
const float blend = nx;
//
const float scale[2] = {2.0f, 0.6f};
QPointF pt((2.0f * nx - 1.0f) * scale[0], (2.0f * ny - 1.0f) * scale[1]);// [-scale, scale]
const float angle = 25.0f;
QMatrix mLeft(QMatrix().rotate(-angle)), mRight(QMatrix().rotate(angle));
pt = (1.0f - blend) * pt * mLeft + blend * pt * mRight;
const int w = m_Image.width();
const int h = m_Image.height();
QPoint px(
static_cast<int>(0.5f * (pt.x() + 1.0f) * w + 0.5f),
static_cast<int>(0.5f * (pt.y() + 1.0f) * h + 0.5f));
if(0 <= px.x() && px.x() < w && 0 <= px.y() && px.y() < h) {
QColor color;
color.setHsvF(ny, 1.0f, 1.0f);
m_Image.setPixel(px, color.rgba());
}
}
В представленном листинге используется QColor и его метод setHsvF. Использовать его в данной задаче запрещается. В коде используются линейная интерполяция между двумя матрицами поворота и случайные величины. Рекомендуется реализовать свой вариант функции Random, используя Линейно-конгруэнтный генератор псевдослучайных чисел
Листинг 1.2
float Random() {// [0, 1]
static bool s_bSrand = false;
if(!s_bSrand) {
QTime midnight(0, 0, 0);
qsrand(midnight.secsTo(QTime::currentTime()));
s_bSrand = true;
}
static const int RANDOM_MAX = RAND_MAX;
return (qrand() % RANDOM_MAX) / (RANDOM_MAX - 1);
}
Замечания
Сейчас и в дальнейшем, основные требования к задачам сохраняются. Например, требование на именование папок и архива проекта (FIT9201SURNAME_<Имя задачи>), его содержимого.
Допускается уточнение условий задачи по электронной почте.
Эта задача является ознакомительной и сдается лично. Выполнение задачи обязательно.
Приветствуется сдача задачи 17го февраля.