crossplatform.ru

Здравствуйте, гость ( Вход | Регистрация )

3 страниц V   1 2 3 >  
Ответить в данную темуНачать новую тему
> Грамотная отрисовка рельефа, что-то не получается
AD
  опции профиля:
сообщение 2.12.2008, 12:02
Сообщение #1


Профессионал
*****

Группа: Участник
Сообщений: 2003
Регистрация: 4.2.2008
Из: S-Petersburg
Пользователь №: 84

Спасибо сказали: 70 раз(а)




Репутация:   17  


Запутался, не знаю как решить следующую проблему. Необходимо под графиком, который уже нарисован нарисовать рельеф. Отрисовка рельефа должна происходить всего один раз. Т.е. при рисовании в методе paintEvent() естественно эта штуковина нещадно грузит систему. Делаю вызов этой функции в другом месте, но тогда вообще ничего не рисуется (возможно, потому что использую QPainter для получения цвета "кисти" и "карандаша"). Помогите, пожалуйста.
Код самого рисования правилен, вопрос в том, как заставить рисовать не вызывая данную функцию в paintEvent()?
/// Отрисовка рельефа
void ReliefGraphics::drawTrackRelief()
{
    for(QVector<QPointF>::iterator rlfPnt=relief_vec.begin(), i_prev=relief_vec.begin(); rlfPnt!=relief_vec.end();
        ++rlfPnt)
    {
        QPointF cur(*rlfPnt), prev(*i_prev);
        drawReliefNature(&painter, cur, prev);
        if(rlfPnt != relief_vec.begin()) ++i_prev;
    }
}

/// Настройка цвета рельефа (естественный цвет)
void ReliefGraphics::drawReliefNature(QPainter* painter, QPointF cur, QPointF prev)
{
    double distance = cur.x(), delta_height = cur.y();
    QPointF scrPnt(initXY(distance, delta_height));
    if(delta_height <= 0 || scrPnt.y() >= settings -> maxY)
        return;

    QColor color(demGetColor(demCalcColor(delta_height)));
    double delta_height0;
    int div = delta_height > 1000 ? 50 : 5;
    int i = (int)(delta_height / div);
    if(!((int)delta_height % div)) --i;
    delta_height0 = div * i;
    double prev_dist = prev.x(), prev_height = prev.y();
    QPointF screenPoint(initXY(distance, delta_height0)), scrPrev(initXY(prev_dist, prev_height));

    QBrush old_brush(painter -> brush());
    QPen old_pen(painter -> pen());
    painter -> setBrush(QBrush(color));
    painter -> setPen(QPen(color));
    painter -> drawLine(scrPrev, screenPoint);
    painter -> setPen(old_pen);
    painter -> setBrush(old_brush);
    QPointF cur0(distance, delta_height0);
    drawReliefNature(painter, cur0, cur);
}


В итоге получается картинка, подобная этой (такая картинка и должна получаться):[attachment=333:relief.JPG]
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
AD
  опции профиля:
сообщение 2.12.2008, 13:04
Сообщение #2


Профессионал
*****

Группа: Участник
Сообщений: 2003
Регистрация: 4.2.2008
Из: S-Petersburg
Пользователь №: 84

Спасибо сказали: 70 раз(а)




Репутация:   17  


Кто-нибудь сможет помочь? Вопрос состоит в том, где правильно использовать функцию drawTrackRilief() или же как сделать так, чтобы не использовать QPainter и отрисовывать другими средствами. Буду благодарен за любую помощь.
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
AD
  опции профиля:
сообщение 3.12.2008, 10:56
Сообщение #3


Профессионал
*****

Группа: Участник
Сообщений: 2003
Регистрация: 4.2.2008
Из: S-Petersburg
Пользователь №: 84

Спасибо сказали: 70 раз(а)




Репутация:   17  


Тут почитал многое и понял, что эту функцию я могу использовать только в paintEvent()! Но еще кое-что заметил и понял, что по сути ее следует вызывать, только при изменении размеров окна. Вопрос такой можно ли сделать так, чтобы один и тот же QPainter painter в одних функциях рисовал сразу на экран, а в других рисовал бы в битмап, который бы перерисовывался при изменении размеров. Кто хочет помочь, прошу помогите пожалуйста.
Вот код отрисовки:
source
/// Настройка цвета рельефа (естественный цвет)
void ReliefGraphics::drawReliefNature(QPainter* painter, QPointF cur, QPointF prev)
{
    double distance = cur.x(), delta_height = cur.y();
    QPointF scrPnt(initXY(distance, delta_height));
    if(delta_height <= 0 || scrPnt.y() >= settings -> maxY)
        return;

    QColor color(demGetColor(demCalcColor(delta_height)));
    double delta_height0;
    int div = delta_height > 1000 ? 50 : 5;
    int i = (int)(delta_height / div);
    if(!((int)delta_height % div)) --i;
    delta_height0 = div * i;
    double prev_dist = prev.x(), prev_height = prev.y();
    QPointF screenPoint(initXY(distance, delta_height0)), scrPrev(initXY(prev_dist, prev_height));

    QBrush old_brush(painter -> brush());
    QPen old_pen(painter -> pen());
    painter -> setBrush(QBrush(color));
    painter -> setPen(QPen(color));
    painter -> drawLine(scrPrev, screenPoint);
    painter -> setPen(old_pen);
    painter -> setBrush(old_brush);
    QPointF cur0(distance, delta_height0);
    drawReliefNature(painter, cur0, cur);
}

/// Отрисовка черной линии рельефа для лучшей видимости его изгибов
void ReliefGraphics::drawBlackLineRelief(QPainter* painter, const QVector<QPointF>& vecBLine)
{
    QBrush old_brush(painter -> brush());
    QPen old_pen(painter -> pen());
    painter -> setPen(Qt::black);
    painter -> setBrush(Qt::black);
    for(int i=vecBLine.size()-1, j=vecBLine.size()-1; i>=0; --i)
    {
        painter -> drawLine(vecBLine[i], vecBLine[j]);
        if(i != vecBLine.size() - 1) --j;
    }
    painter -> setPen(old_pen);
    painter -> setBrush(old_brush);
}

/// Отрисовка рельефа
void ReliefGraphics::drawTrackRelief()
{
    QVector<QPointF> vecBLine;
    for(QVector<QPointF>::iterator rlfPnt=relief_vec.begin(), i_prev=relief_vec.begin(); rlfPnt!=relief_vec.end();
        ++rlfPnt)
    {
        QPointF cur(*rlfPnt), prev(*i_prev);
        double X = cur.x(), Y = cur.y(), prevX = prev.x(), prevY = prev.y();
        QPointF screen(initXY(X, Y));
        drawReliefNature(&painter, cur, prev);
        if(rlfPnt != relief_vec.begin()) ++i_prev;
        vecBLine.append(screen);
    }
    drawBlackLineRelief(&painter, vecBLine);
}

/// Отрисовка графика
void ReliefGraphics::paintEvent(QPaintEvent* events)
{
    painter.begin(this);

    QRect rect(displayRelief -> rect());
    painter.setWindow(displayRelief -> rect());
    painter.setFont(QFont("Tahoma", 6, Qt::SolidLine));
    painter.setPen(Qt::black);

    if(param_vec.size() <= count_logrecords && coords_vec.size() <= count_logrecords && fill_axis <= 3)
    {
        int sz = coords_vec.size(), sz1 = param_vec.size(), sz2 = relief_vec.size();
        setPlotValues();
        initParamVec();
        if(param_vec.size() == count_logrecords && coords_vec.size() == count_logrecords)
            ++fill_axis;
    }
    initCurve();

    drawTrackRelief();
    drawGrid(&painter);
    drawCurves(&painter);

    painter.end();
}


Буду благодарен за любой совет и помощь. Очень прошу хоть кого-нибудь откликнуться и постараться помочь в столь нетривиальной задачке!
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
Litkevich Yuriy
  опции профиля:
сообщение 3.12.2008, 11:27
Сообщение #4


разработчик РЭА
*******

Группа: Сомодератор
Сообщений: 9655
Регистрация: 9.1.2008
Из: Тюмень
Пользователь №: 64

Спасибо сказали: 807 раз(а)




Репутация:   94  


Цитата(AD @ 3.12.2008, 13:56) *
и тот же QPainter painter
а почему один и тот же?
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
AD
  опции профиля:
сообщение 3.12.2008, 11:34
Сообщение #5


Профессионал
*****

Группа: Участник
Сообщений: 2003
Регистрация: 4.2.2008
Из: S-Petersburg
Пользователь №: 84

Спасибо сказали: 70 раз(а)




Репутация:   17  


Цитата(Litkevich Yuriy) *
а почему один и тот же?

Тогда вопрос поставлю по другому, а в одном paintEvent() можно использовать несколько QPainter? Если можно, то можно небольшие примерчики?
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
Litkevich Yuriy
  опции профиля:
сообщение 3.12.2008, 12:33
Сообщение #6


разработчик РЭА
*******

Группа: Сомодератор
Сообщений: 9655
Регистрация: 9.1.2008
Из: Тюмень
Пользователь №: 64

Спасибо сказали: 807 раз(а)




Репутация:   94  


Цитата(AD @ 3.12.2008, 14:34) *
можно использовать несколько QPainter?
а в любой другой функции можно создавать несколько экземпляров одного и того же типа? ;)
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
AD
  опции профиля:
сообщение 3.12.2008, 12:50
Сообщение #7


Профессионал
*****

Группа: Участник
Сообщений: 2003
Регистрация: 4.2.2008
Из: S-Petersburg
Пользователь №: 84

Спасибо сказали: 70 раз(а)




Репутация:   17  


Цитата(Litkevich Yuriy @ 3.12.2008, 12:33) *
а в любой другой функции можно создавать несколько экземпляров
одного и того же типа? ;)

Можно. Ну хорошо, раз мне не доверяешь, можешь привести пример, чтобы 2 или более объектов QPainter, пожалуйста?
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
AD
  опции профиля:
сообщение 3.12.2008, 17:26
Сообщение #8


Профессионал
*****

Группа: Участник
Сообщений: 2003
Регистрация: 4.2.2008
Из: S-Petersburg
Пользователь №: 84

Спасибо сказали: 70 раз(а)




Репутация:   17  


Дошло как можно это безобразие организовать - через дополнительный параллельный поток. Ведь в потоке я имею право использовать QPainter? Если что, поможете? Естественно, я буду приводить код...

Один из первых вопрос по потокам такой - можно ли использовать в потоке указатель на QPainter, если он объявлен в главном потоке. Если нельзя, то как сделать можно? Буду благодарен за помощь!

Сообщение отредактировал AD - 3.12.2008, 17:52
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
AD
  опции профиля:
сообщение 5.12.2008, 12:54
Сообщение #9


Профессионал
*****

Группа: Участник
Сообщений: 2003
Регистрация: 4.2.2008
Из: S-Petersburg
Пользователь №: 84

Спасибо сказали: 70 раз(а)




Репутация:   17  


Перенес в доп. поток. Вот так это все выглядит:
relief

#ifndef THREAD_H_055
#define THREAD_H_055

#include <QThread>
#ifdef Q_WS_WIN
    #pragma once
#endif // Q_WS_WIN

#include <QPainter>
#include <QDockWidget>
#include <QPointF>
#include <QVector>

class PlotSettings;

/// Класс параллельного потока для отрисовки рельефа вертикальной проекции
class VThread: public QThread
{
    Q_OBJECT

private:
    QPainter painter;                ///< рисовальщик
    QDockWidget* relief_widget;        ///< указатель на виджет, где будет отрисовываться рельеф
    int count_read;                    ///< количество прочитанных элементов
    PlotSettings* settings;            ///< указатель на настройки для различных масштабов
    QVector<QPointF> relief_vec;    ///< вектор геграфических точек рельефа
    QRect rect;                        ///< прямоугольная область, в которой будет производиться рисование

private:
    QPointF initXY(double& sx, double& sy);
    void drawReliefNature(QPainter* painter, QPointF cur, QPointF prev);
    void drawBlackLineRelief(QPainter* painter, const QVector<QPointF>& vecBLine);
    void drawCurves(QPainter* painter);
    void drawTrackRelief(QPainter* painter);

protected:
    virtual void run();

public:
    VThread(): relief_widget(0), count_read(0), settings(0) {}
    VThread(QDockWidget* rlf_widget): painter(rlf_widget), relief_widget(rlf_widget), count_read(0), settings(0) {}
    ~VThread() {}
    void widget(QDockWidget* rlf_widget) { relief_widget = rlf_widget; }
    QDockWidget* widget() { return relief_widget; }
    void count(const int r) { count_read = r; }
    const int count() { return count_read; }
    void init(PlotSettings* s, QRect& rct) { settings = s; rect = rct; }
    void init(PlotSettings* s) { settings = s; }
    void init(QRect& rct) { rect = rct; }
    void initVec(QVector<QPointF>& rv) { relief_vec = rv; }
    void stop(const int size) { if(count_read == size) quit(); }
};

#endif // THREAD_H_055


#include "Thread.h"
#include <QtGui>

/// Инициализация координат - преобразование из координат графика (sx,sy) в экранные (x,y)
QPointF VThread::initXY(double& sx, double& sy)
{
    const int shift_x = 30;
    if(!rect.isValid()) return QPointF();
    QRect rect_shift(rect);        rect_shift.setLeft(rect_shift.left() + shift_x);
    double dx, dy;

    dx = sx - settings -> minX;
    dy = sy - settings -> minY;
    double x = rect_shift.left() + (dx * (rect_shift.width() - 1) / settings -> spanX());;
    double y = rect.bottom() - (dy * (rect.height() - 1) / settings -> spanY());

    return QPointF(x, y);
}

/// Настройка цвета рельефа (естественный цвет)
void VThread::drawReliefNature(QPainter* painter, QPointF cur, QPointF prev)
{
    double distance = cur.x(), delta_height = cur.y();
    QPointF scrPnt(initXY(distance, delta_height));
    if(delta_height <= 0 || scrPnt.y() >= settings -> maxY)
        return;

    QColor color(demGetColor(demCalcColor(delta_height)));
    double delta_height0;
    int div = delta_height > 1000 ? 50 : 5;
    int i = (int)(delta_height / div);
    if(!((int)delta_height % div)) --i;
    delta_height0 = div * i;
    double prev_dist = prev.x(), prev_height = prev.y();
    QPointF screenPoint(initXY(distance, delta_height0)), scrPrev(initXY(prev_dist, prev_height));

    QBrush old_brush(painter -> brush());
    QPen old_pen(painter -> pen());
    painter -> setBrush(QBrush(color));
    painter -> setPen(QPen(color));
    painter -> drawLine(scrPrev, screenPoint);
    for(int ix=scrPrev.x()+1; ix<screenPoint.x(); ++ix)
        painter -> drawLine(QPointF(ix, scrPrev.y()), screenPoint);
    painter -> setPen(old_pen);
    painter -> setBrush(old_brush);
    QPointF cur0(distance, delta_height0);
    drawReliefNature(painter, cur0, cur);
}

/// Отрисовка черной линии рельефа для лучшей видимости его изгибов
void VThread::drawBlackLineRelief(QPainter* painter, const QVector<QPointF>& vecBLine)
{
    QBrush old_brush(painter -> brush());
    QPen old_pen(painter -> pen());
    painter -> setPen(Qt::black);
    painter -> setBrush(Qt::black);
    for(int i=vecBLine.size()-1, j=vecBLine.size()-1; i>=0; --i)
    {
        painter -> drawLine(vecBLine[i], vecBLine[j]);
        if(i != vecBLine.size() - 1) --j;
    }
    painter -> setPen(old_pen);
    painter -> setBrush(old_brush);
}

/// Отрисовка рельефа
void VThread::drawTrackRelief(QPainter* painter)
{
    QVector<QPointF> vecBLine;
    int size = relief_vec.size();
    for(QVector<QPointF>::iterator rlfPnt=relief_vec.begin(), i_prev=relief_vec.begin(); rlfPnt!=relief_vec.end();
        ++rlfPnt, ++count_read)
    {
        usedRlfSpace.acquire();
        QPointF cur(*rlfPnt), prev(*i_prev);
        double X = cur.x(), Y = cur.y(), prevX = prev.x(), prevY = prev.y();
        QPointF screen(initXY(X, Y));
        drawReliefNature(painter, cur, prev);
        if(rlfPnt != relief_vec.begin()) ++i_prev;
        usedRlfSpace.release();
        vecBLine.append(screen);
    }
    drawBlackLineRelief(painter, vecBLine);
}

/// Запуск дополницельного потока
void VThread::run()
{
    drawTrackRelief(&painter);
}

ReliefGraphics::ReliefGraphics(QWidget *parent): settings(0), main_window(0), fill_axis(0), count_logrecords(0),
                maxValY(-1.0e23), minValY(1.0e23), is_resizing(false), fin_init(false)
{

    int r_width = displayRelief -> rect().width() - 1.5 * toolBar -> rect().width();
    int r_height = displayRelief -> rect().height() - 2.5 * VerticalGraphicClass::scroll -> rect().height();
    QRect rect(displayRelief -> rect().x() + toolBar -> rect().width(), displayRelief -> rect().y() +
        VerticalGraphicClass::scroll -> rect().height(), r_width, r_height);
    settings = new PlotSettings();
    vrt_thread = new VThread(this);
    vrt_thread -> init(settings, rect);
}

/// Отрисовка графика
void ReliefGraphics::paintEvent(QPaintEvent* events)
{
    painter.begin(this);
    /// Что-то еще отрисовывается (траектория, например)
    vrt_thread -> stop(count_logrecords);
    painter.end();
}

/// Отображение вертикальной проекции
void TLV::verticProjection(QAction* _sender)
{
    verticPrjAction = _sender;
    if(!verticalProjection) return;

    verticalProjection -> setVisible(verticPrjAction -> isChecked());
    if(verticPrjAction -> isChecked()) verticalProjection -> start();
}


Но рельеф не рисуется. Помогите, пожалуйста. Как заставить отрисовываться? Что я не так делаю?

Сообщение отредактировал AD - 5.12.2008, 14:02
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
kuler
  опции профиля:
сообщение 5.12.2008, 16:25
Сообщение #10


Танцор диско
***

Группа: Участник
Сообщений: 441
Регистрация: 11.9.2008
Из: Москва
Пользователь №: 289

Спасибо сказали: 6 раз(а)




Репутация:   -1  


а почему painter можно использовать в другом потоке?
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение

3 страниц V   1 2 3 >
Быстрый ответОтветить в данную темуНачать новую тему
Теги
Нет тегов для показа


1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0




RSS Текстовая версия Сейчас: 15.9.2019, 15:14