Вторник, 27.10.2020 06:48

Масштабирование. Рисование в Qt. Трансформации. Часть 4

Масштабирование. Рисование в Qt. Трансформации. Часть 4

В прошлой части мы рассмотрели вращение. Сегодня мы рассмотрим новый тип трансформации – масштабирование. Мы продолжим работать с проектом с прошлой части.

Для начала, обеспечим себя чистым рабочим столом.

В методе

void MainWindow::paintEvent(QPaintEvent *)

закомментируем

drawChildPicRel();

В настройках формы главного окна изменим его размер до 400х400

Запустим, получим чистое окно:

Изображение удалено.

Мы будем рисовать облака разного размера. Облако будет состоять из кругов.

Добавим метод для отрисовки облака.

void MainWindow::drawCloud()
{
    QColor linesColor(0, 0, 255, 255);
    QPen apen = QPen(linesColor);
    painter->translate(QPoint(150,150));
    painter->setBrush(Qt::white);
    //
    apen = QPen(QColor("white"));
    apen.setWidth(3);
    painter->setPen(apen);
    painter->drawArc(0,0,30,30,360*16,360*16);
    painter->drawEllipse(0, 0, 30,30);
    painter->translate(QPoint(20,-10));
    painter->drawEllipse(0, 0, 30,30);
    painter->translate(QPoint(20,0));
    painter->drawEllipse(0, 0, 30,30);
    painter->translate(QPoint(20,10));
    painter->drawEllipse(0, 0, 30,30);
    painter->translate(QPoint(-20,10));
    painter->drawEllipse(0, 0, 30,30);
    painter->translate(QPoint(-20,0));
    painter->drawEllipse(0, 0, 30,30);
}

Запустим, у нас получится:

Изображение удалено.

Закомментируем строку

painter→setBrush(Qt::white);

Запустим еще раз:

Изображение удалено.

Как видите, облако состоим из кругов, которые накладываются друг на друга, а так как они одинакового цвета, то переходов между ними не видно.

Мы и дальше будем использовать такой режим, для наглядности.

Наше облако выглядит неплохо, но несколько «синтетически». Давайте сделаем его менее симметричным.

Изменим код таким образом:

void MainWindow::drawCloud()
{
    QColor linesColor(0, 0, 255, 255);
    QPen apen = QPen(linesColor);
    painter->translate(QPoint(150,150));
    painter->setBrush(Qt::white);
    
    apen = QPen(QColor("white"));
    apen.setWidth(3);
    painter->setPen(apen);
    painter->drawEllipse(0, 0, 40,40);
    painter->translate(QPoint(20,-10));
    painter->drawEllipse(0, 0, 35,35);
    painter->translate(QPoint(20,0));
    painter->drawEllipse(0, 0, 30,30);
    painter->translate(QPoint(20,10));
    painter->drawEllipse(0, 0, 35,35);
    painter->translate(QPoint(-20,10));
    painter->drawEllipse(0, 0, 30,30);
    painter->translate(QPoint(-20,0));
    painter->drawEllipse(0, 0, 35,35);
}

У нас получиться:

Изображение удалено.

или

Изображение удалено.

Намного лучше, но нам нужны облака разных типов. Для этого усовершенствуем наш код.

void MainWindow::drawCloud(int seed)
{
    QRandomGenerator prng(seed);
    QColor linesColor(0, 0, 255, 255);
    QPen apen = QPen(linesColor);
    painter->translate(QPoint(150,150));
    painter->setBrush(Qt::white);
    //
    apen = QPen(QColor("white"));
    apen.setWidth(3);
    painter->setPen(apen);
    painter->drawEllipse(0, 0, 30+prng.bounded(10),30+prng.bounded(10));
    painter->translate(QPoint(20,-10));
    painter->drawEllipse(0, 0, 30+prng.bounded(10),30+prng.bounded(10));
    painter->translate(QPoint(20,0));
    painter->drawEllipse(0, 0, 30+prng.bounded(10),30+prng.bounded(10));
    painter->translate(QPoint(20,10));
    painter->drawEllipse(0, 0, 30+prng.bounded(10),30+prng.bounded(10));
    painter->translate(QPoint(-20,10));
    painter->drawEllipse(0, 0, 30+prng.bounded(10),30+prng.bounded(10));
    painter->translate(QPoint(-20,0));
    painter->drawEllipse(0, 0, 30+prng.bounded(10),30+prng.bounded(10));
}

Изменим вызов нашего метода на

drawCloud(123); 

Запустим, получим:

Изображение удалено.

или

Изображение удалено.

Давайте разберемся в коде.

Прежде всего, для создания облака используется генератор случайных чисел, но так как нам нужно, чтобы облака были одной и той же формы, каждый раз при запуске программы мы используем зерно (seed) для инициализации генератора случайных чисел.

Это позволяет каждый раз получать от генератора одну и туже последовательность чисел, что очень удобно, так как позволяет установить строгую зависимость результата генерации от некого числа!

Далее при отрисовке каждого эллипса используется вызов метода, который генерирует случайное число в диапазоне от 0 до 10.

prng.bounded(10)

Таким образом у нас получаются отлично выглядящие облака!

Нарисуем несколько облаков.

void MainWindow::drawClouds()
{
    painter->translate(QPoint(0,20));
    painter->save();
    painter->translate(QPoint(20,20));
    drawCloud(121);
    painter->restore();
    painter->save();
    painter->translate(QPoint(120,40));
    drawCloud(122);
    painter->restore();
    painter->save();
    painter->translate(QPoint(220,70));
    drawCloud(123);
    painter->restore();
    painter->save();
    painter->translate(QPoint(200,2));
    drawCloud(124);
    painter->restore();
}

Запустим:

Изображение удалено.

Красивые облака это, конечно, хорошо, но облака бывают разными по размеру, давайте нарисуем несколько облаков разного размера, но, прежде чем продолжить, обновим код рисования домика, радуги и солнышка.

void MainWindow::drawChildPicRel()
{
    painter->translate(QPoint(50,70));
    painter->save();
    QColor linesColor(0, 0, 255, 255);
    QPen apen = QPen(linesColor);
    apen.setWidth(3);
    painter->setPen(apen);
    painter->translate(QPoint(150,220));
    //Квадрат - дом
    painter->drawRect(-50,-50,100,100);
    //Квадрат - окно
    painter->drawRect(-30,-30,60,60);
    //Полигон - крыша и дымоход
    static const QPointF points[7] = {
        QPointF(-50.0, -50.0),
        QPointF(0.0, -100.0),
        QPointF(20.0, -80.0),
        QPointF(20.0, -110.0),
        QPointF(30.0, -110.0),
        QPointF(30.0, -70.0),
        QPointF(50.0, -50.0)
    };
    painter->drawConvexPolygon(points, 7);
    //Линия - крышка дымохода
    painter->drawLine(QLine(15,-110,35,-110));
    painter->drawLine(QLine(15,-110,25,-120));
    painter->drawLine(QLine(25,-120,35,-110));
    painter->restore();
    painter->translate(QPoint(50,50));
    int rainbowWidth = 200;
    int rainbowHeight = 200;
    int rainbowInRad = 30 * 16;
    int rainbowOutRad = 120 * 16;
    int rainbowArcHeight = 4;
    //Дуга - Радуга
    apen = QPen(QColor("red"));
    apen.setWidth(rainbowArcHeight);
    painter->setPen(apen);
    painter->drawArc(0,0,rainbowWidth,rainbowHeight,rainbowInRad,rainbowOutRad);
    apen.setWidth(rainbowArcHeight);
    apen = QPen(QColor("orange"));
    apen.setWidth(rainbowArcHeight);
    painter->setPen(apen);
    painter->drawArc(0,rainbowArcHeight,rainbowWidth,rainbowHeight,rainbowInRad,rainbowOutRad);
    apen = QPen(QColor("yellow"));
    apen.setWidth(rainbowArcHeight);
    painter->setPen(apen);
    painter->drawArc(0,rainbowArcHeight*2,rainbowWidth,rainbowHeight,rainbowInRad,rainbowOutRad);
    apen = QPen(QColor("green"));
    apen.setWidth(rainbowArcHeight);
    painter->setPen(apen);
    painter->drawArc(0,rainbowArcHeight*3,rainbowWidth,rainbowHeight,rainbowInRad,rainbowOutRad);
    apen = QPen(QColor("lightblue"));
    apen.setWidth(rainbowArcHeight);
    painter->setPen(apen);
    painter->drawArc(0,rainbowArcHeight*4,rainbowWidth,rainbowHeight,rainbowInRad,rainbowOutRad);
    apen = QPen(QColor("blue"));
    apen.setWidth(rainbowArcHeight);
    painter->setPen(apen);
    painter->drawArc(0,rainbowArcHeight*5,rainbowWidth,rainbowHeight,rainbowInRad,rainbowOutRad);
    apen = QPen(QColor("violet"));
    apen.setWidth(rainbowArcHeight);
    painter->setPen(apen);
    painter->drawArc(0,rainbowArcHeight*6,rainbowWidth,rainbowHeight,rainbowInRad,rainbowOutRad);
    painter->restore();
    painter->translate(QPoint(220,-90));
    drawSun();
}

Обратите внимание, я использовал методы save() и restore().

Запустим:

Изображение удалено.

Выглядит лучше, а теперь изменим метод отрисовки облаков и изменим их размер:

void MainWindow::drawClouds()
{
    painter->translate(QPoint(0,20));
    painter->save();
    painter->translate(QPoint(20,20));
    painter->scale(0.8,0.8);
    drawCloud(121);
    painter->restore();
    painter->save();
    painter->translate(QPoint(100,60));
    painter->scale(1.2,1.2);
    drawCloud(122);
    painter->restore();
    painter->save();
    painter->translate(QPoint(240,100));
    painter->scale(0.6,0.6);
    drawCloud(123);
    painter->restore();
    painter->save();
    painter->translate(QPoint(225,2));
    painter->scale(0.9,0.9);
    drawCloud(124);
    painter->restore();
}

Для изменения размера мы использовали метод painter->scale

Данный метод принимает числа типа real, таким образом, что, например, обычный размер будет 1,1. 50% меньше будет 0.5,0.5. 150% соответственно 1.5,1.5 и так далее.

Мы получим картинку.

Изображение удалено.

 Влияние масштабирования на трансформацию

Обратите внимание - масштабирование влияет на трансляцию, которая будет производиться после вызова метода scale()

Рассмотрим это на примере, нарисуем круг по центру экрана.

painter->translate(QPoint(200,200));
painter->setBrush(Qt::red);
painter->drawEllipse(-25, -25, 50,50);

Получим результат:

Изображение удалено. 

Изменим код:

painter->scale(0.5,0.5);
painter->translate(QPoint(200,200));
painter->setBrush(Qt::red);
painter->drawEllipse(-25, -25, 50,50);

Получим результат:

Изображение удалено.

Всегда делайте сначала трансляцию, а уже потом масштабирование, чтобы избежать проблем с расположением при рисовании.

Заключение

Сегодня мы рассмотрели последнюю трансформацию — масштабирование.

Добавили метод для рисования облака. Модернизировали его, таким образом, чтобы он позволял генерировать облака разных размеров.

Добавили зерно (seed) для метода, чтобы гарантировать одинаковый результат при каждом запуске программы.

Обновили метод отрисовки дома, с использованием методов save() и restore() и добавили облака.

Рассмотрели влияние масштабирования на трансляцию в QPainter.

Категория Qt
Теги Qt

Добавить комментарий

Простой текст

  • HTML-теги не обрабатываются и показываются как обычный текст
  • Строки и абзацы переносятся автоматически.
  • Адреса веб-страниц и email-адреса преобразовываются в ссылки автоматически.
Просмотров: 288