crossplatform.ru

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

 
Ответить в данную темуНачать новую тему
> Алгоритм отрисовки рельефа, помощь
AD
  опции профиля:
сообщение 30.3.2009, 18:24
Сообщение #1


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

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

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




Репутация:   17  


Что-то мозги уже не соображают. Сможете помочь с алгоритмом отрисофки рельефа? Сейчас это происходит так:
1) Весь виджет заполняется полосками нужного цвета в зависимости от высоты.
2) Далее строится линия рельефа.
3) Пробегая по оси X, заполняем прямоугольники фоновым цветом.
Но это работает видимо не так, как хотелось бы.
Вот код (если не увидите описания некоторых переменных - будьте уверены, они есть, но удалены из примерочного кода):
relief
/// Класс для рисования вертикальной проекции полета и рельефа под ней
class VerticalGraphics: public QWidget
{
    Q_OBJECT

private:
    TLV* main_window;                    ///< указатель на главное окно
    QVector<QPointF> relief_vec;        ///< вектор географических точек рельефа
    QVector<QPointF> vecBLine;            ///< вектор линии, обрамляющая рельеф
    int fill_axis;                        ///< флажок, определяющий инициализацию осей
    int count_logrecords;                ///< количество записей в загруженных логах
    double maxValY, minValY;            ///< максимальное/минимальное значения по оси Y
    bool fin_init;                        ///< окончание инициализации вектора с координатами рельефа
    bool is_resizing;                    ///< флажок изменения размеров окна вертикальной проекции
    QImage* image;                        ///< картинка с рельефом

public:
    QMutex mutex;                        ///< мьютекс для блокировки данных при работе с ними дополнительного потока

private:
    QPointF initXY(double& sx, double& sy);
    void initXCurve();
    void initParamVec();
    void initHeightRelief();
    void initCurve();
    void drawBlackLineRelief(QPainter* painter);
    void drawReliefNature(QPainter* painter, double delta_height, double bx, double ex = 10000);
    void drawReliefRect(QPainter* painter);
    void drawRelief(QPainter* painter);
    void drawOnDevice(QPaintDevice* dev);

protected:
    virtual void resizeEvent(QResizeEvent* events);
    virtual void paintEvent(QPaintEvent* events);

public:
    VerticalGraphics(QWidget *parent = 0);
    ~VerticalGraphics();
    void recreateImage() { if(image) delete image; image = new QImage(size(), QImage::Format_ARGB32); }
};


VerticalGraphics::VerticalGraphics(QWidget *parent): settings(0), main_window(0), fill_axis(0),
                maxValY(-1.0e23), minValY(1.0e23), fin_init(false), is_changed_list(false), is_resizing(false),
                image(new QImage(size(), QImage::Format_ARGB32))
{
    setBackgroundRole(QPalette::Midlight);
    settings = new PlotSettings();
    first_sets = new PlotSettings();
    firstSettings(first_sets);
    setPlotSettings(settings);
}

VerticalGraphics::~VerticalGraphics()
{
    if(image) { delete image; image = 0; }
}

/// Инициализация координат - преобразование из координат графика (sx,sy) в экранные (x,y)
QPointF VerticalGraphics::initXY(double& sx, double& sy)
{
    const int shift_x = 30;
    QRect rect(rect());
    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 VerticalGraphics::initXCurve()
{
    if(!vertic_param) return;

    double x = 0.0, tmp = 0.;
    vec_data.clear();
    if(is_resizing || !fin_init)
        relief_vec.clear();
    switch(vertic_param -> type)
    {
    case DISTPARAM:
        for(QVector<PARAMVALUE>::iterator iter=x_data.dist_x.begin(); iter!=x_data.dist_x.end(); ++iter)
        {
            x += (iter -> value);
            vec_data.append(QPointF(x, 0.0));
            if(is_resizing || !fin_init) relief_vec.append(initXY(x, tmp));
        }
    break;
    case TIMEPARAM:
        for(QVector<PARAMVALUE>::iterator iter=x_data.time_x.begin(); iter!=x_data.time_x.end(); ++iter)
        {
            x += (iter -> value);
            vec_data.append(QPointF(x, 0.0));
            if(is_resizing || !fin_init) relief_vec.append(initXY(x, tmp));
        }
    break;
    case COUNTPARAM:
        if(!main_window) break;
        for(int i=0; i<main_window -> getLog().size(); ++i)
        {
            vec_data.append(QPointF(i, 0.0));
            if(is_resizing || !fin_init) relief_vec.append(initXY((double&)i, tmp));
        }
    break;
    }
}

/// Инициализация высоты рельефа и вектора, обрамляющего рельеф
void VerticalGraphics::initHeightRelief()
{
    vecBLine.clear();
    for(register int index=0; index<relief_vec.size() && index<height_vec.size(); ++index)
    {
        double tmp = 0., sy = height_vec.at(index);
        QPointF pnt(initXY(tmp, sy));
        relief_vec[index].setY(pnt.y());
        vecBLine.append(relief_vec[index]);
    }
}

/// Инициализация вектора данными
void VerticalGraphics::initCurve()
{
    initXCurve();
    mutex.lock();
    QVector<LOGRECORD> log = main_window -> getLog();
    mutex.unlock();
    for(register int i=0; i<param_vec.size() && i<vec_data.size() && i<log.size(); ++i)
    {
        PARAMVALUE* parameter = param_vec[i];
        vec_data[i].setY(parameter -> value);
        mutex.lock();
        vec_data[i].name_file = log[i].name_file;
        vec_data[i].phase = log[i].phase;
        mutex.unlock();
    }
    if(is_resizing || !fin_init)
    {
        initHeightRelief();
        is_resizing = false;
    }
}

/// Отрисовка черной линии рельефа для лучшей видимости его изгибов
void VerticalGraphics::drawBlackLineRelief(QPainter* painter)
{
    QBrush old_brush(painter -> brush());
    QPen old_pen(painter -> pen());
    painter -> setPen(Qt::black);
    painter -> setBrush(Qt::black);
    for(register 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 VerticalGraphics::drawReliefNature(QPainter* painter, double delta_height, double bx, double ex)
{
    double tmp = 0.;
    QPointF checkPoint(initXY(tmp, delta_height));
    if(delta_height <= 0. || checkPoint.y() >= settings -> maxY)
        return;

    int div_step = (delta_height > 1000.) ? 50 : 5;
    int round = delta_height / div_step;
    if(!((int)delta_height % div_step)) --round;
    double delta_height0 = div_step * round;
    double y_screen = initXY(tmp, delta_height0).y();

    QRectF rect(bx, y_screen, ex, y_screen);
    QColor color(demGetColor(demCalcColor(delta_height)));
    painter -> fillRect(rect, QBrush(color));
    drawReliefNature(painter, delta_height0, bx, ex);
}

/// Отрисовка прямоугольника с цветам рельефа
void VerticalGraphics::drawReliefRect(QPainter* painter)
{
    if(!relief_vec.size()) return;

    double bx = relief_vec.at(0).x(), ex = relief_vec.at(relief_vec.size() - 1).x();
    double delta_height = max_delta_height;
    drawReliefNature(painter, delta_height, bx, ex);
}

/// Отрисовка рельефа
void VerticalGraphics::drawRelief(QPainter* painter)
{
    if(relief_vec.isEmpty()) return;
    double bx = relief_vec.at(0).x(), ex = relief_vec.at(relief_vec.size() - 1).x();
    QColor color(palette().window().color());
    for(register int x=bx+1, prev_x=bx, y=0; x<ex; ++x, ++prev_x, ++y)
    {
        double _y = height() - relief_vec.at(y).y();
        QRectF rct(prev_x, 0, x, _y);
        painter -> fillRect(rct, QBrush(color));
    }
}

/// Отрисовка изображения на заданном устройстве (dev)
void VerticalGraphics::drawOnDevice(QPaintDevice* dev)
{
    QPainter painter(dev);

    painter.setWindow(rect());
    painter.setPen(Qt::black);

    if(fill_axis == 0) param_vec.clear();
    if(param_vec.size() <= count_logrecords && fill_axis <= 3)
    {
        initParamVec();
        setPlotValues();
        if(param_vec.size() == count_logrecords)
            ++fill_axis;
    }
    else if(vrt_thread -> isRunning() && param_vec.size() >= count_logrecords)
        vrt_thread -> quit();
    initCurve();
    if(fill_axis == 3)
    {
        fin_init = true;
        drawReliefRect(&painter);
    }

    painter.end();
    update();
}

/// Отрисовка графика
void VerticalGraphics::paintEvent(QPaintEvent* events)
{
    drawOnDevice(image);
    QPainter painter(this);
    painter.fillRect(rect(), QBrush(palette().window().color()));
    painter.setFont(QFont("Tahoma", 8, Qt::SolidLine));
    painter.drawImage(rect(), *image);
    drawRelief(&painter);
    drawGrid(&painter);
    drawBlackLineRelief(&painter);
    drawCurves(&painter);
    painter.end();
}


Ну смысл такой. Основная нагрузка на следующие функции:
1) initHeightRelief() - заполнение вектора с экранными координатами рельефа
2) initCurve() - заполнение вектора с экранными координатами траектории и вызов функции рельефа
3) drawReliefNature() - рекурсивное заполнение полоски (прямоугольника) одним цветом
4) drawReliefRect() - заполнение области экрана вертикальной проекции нужным цветом рельефа
5) drawRelief() - ну и наконец функция отрисовки рельефа (т.е. заполнение вертикальных полосок, как я расчитываю на свой код, цветом виджета).
Ну остальное вроде как понятно....

Помогите разобраться, чего не хватает для правильной отрисовки?
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
trdm
  опции профиля:
сообщение 30.3.2009, 18:57
Сообщение #2


Дмитрий Трошин
****

Группа: Участник
Сообщений: 575
Регистрация: 12.1.2008
Пользователь №: 68

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




Репутация:   6  


Картинку прикрепи, что в итоге получить хочешь?
ПС. По алгоритмическим сайтам не лазил случаем?
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
AD
  опции профиля:
сообщение 30.3.2009, 20:48
Сообщение #3


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

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

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




Репутация:   17  


Цитата(trdm @ 30.3.2009, 19:57) *
Картинку прикрепи, что в итоге получить хочешь?
ПС. По алгоритмическим сайтам не лазил случаем?

Выглядеть должно как на 5 картинке http://www.forum.crossplatform.ru/index.ph...c=1231&st=0 11 поста. Сейчас стараюсь сделать, чтобы не было тех тормозов при отрисовке, что были, когда была сделана та картинка. А сейчас картинка выглядит так:
[attachment=521:Relief.JPG]
Не совсем то, что я хочу. Рельеф в итоге должен повторять контур черной линии!
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
AD
  опции профиля:
сообщение 31.3.2009, 10:38
Сообщение #4


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

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

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




Репутация:   17  


Пока в голову ничего не приходит. Уже и три рисунка сделал и рассчитал количество и все-равно не знаю, почему не так выходит. Есть какие-нибудь идеи?
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
trdm
  опции профиля:
сообщение 31.3.2009, 13:15
Сообщение #5


Дмитрий Трошин
****

Группа: Участник
Сообщений: 575
Регистрация: 12.1.2008
Пользователь №: 68

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




Репутация:   6  


тут разбираться надо. лениво если чесно.
Своих логических заморочек с репортом хватает...
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
AD
  опции профиля:
сообщение 31.3.2009, 14:18
Сообщение #6


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

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

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




Репутация:   17  


Ну вот с некоторыми огрехами, но получилось. Основная ошибка была в невнимательном чтении параметров рисуемого прямоугольника. 3 параметр - ширина, а 4 - высота.

Вот так выглядят основные функции:
Раскрывающийся текст
/// Отрисовка черной линии рельефа для лучшей видимости его изгибов
void VerticalGraphics::drawBlackLineRelief(QPainter* painter)
{
    painter -> setPen(Qt::black);
    painter -> setBrush(Qt::black);
    for(register int i=1, j=0; i<relief_vec.size(); ++i, ++j)
        painter -> drawLine(relief_vec[j], relief_vec[i]);
}

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

    int div_step = (delta_height > 1000.) ? 50 : 5;
    int round = delta_height / div_step;
    if(!((int)delta_height % div_step)) --round;
    double delta_height0 = div_step * round;
    double y_screen = initXY(tmp, delta_height0).y();

    QRectF rect(bx, y_screen, ex, y_screen);
    QColor color(demGetColor(demCalcColor(delta_height)));
    painter -> fillRect(rect, QBrush(color));
    drawReliefNature(painter, delta_height0, bx, ex);
}

/// Отрисовка прямоугольника с цветам рельефа
void VerticalGraphics::drawReliefRect(QPainter* painter)
{
    if(!relief_vec.size()) return;

    double bx = relief_vec.at(0).x(), ex = relief_vec.at(relief_vec.size() - 1).x();
    double delta_height = max_delta_height;
    drawReliefNature(painter, delta_height, bx, ex);
}

/// Отрисовка рельефа
void VerticalGraphics::drawRelief(QPainter* painter)
{
    if(relief_vec.isEmpty()) return;
    QColor color(palette().window().color());
    for(register int i=0; i<relief_vec.size(); ++i)
    {
        double x = relief_vec.at(i).x(), y = relief_vec.at(i).y();
        QRectF rect(x, 0, 1, y);
        painter -> fillRect(rect, QBrush(color));
    }
}
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение
AD
  опции профиля:
сообщение 1.4.2009, 14:35
Сообщение #7


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

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

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




Репутация:   17  


Вот версия, когда все рисуется правильно! :) Сделал и теперь рисуется без тормозов! :)
Раскрывающийся текст
/// Отрисовка черной линии рельефа для лучшей видимости его изгибов
void VerticalGraphics::drawBlackLineRelief(QPainter* painter)
{
    painter -> setPen(Qt::black);
    painter -> setBrush(Qt::black);
    for(register int i=1, j=0; i<relief_vec.size(); ++i, ++j)
        painter -> drawLine(relief_vec[j], relief_vec[i]);
}

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

    int div_step = (delta_height > 1000.) ? 50 : 5;
    int round = delta_height / div_step;
    if(!((int)delta_height % div_step)) --round;
    double delta_height0 = div_step * round;
    double y_screen = initXY(tmp, delta_height0).y();

    double _height = fabs(checkPoint.y() - y_screen);
    QRectF rect(0., y_screen, width(), _height);
    QColor color(demGetColor(demCalcColor(delta_height)));
    painter -> fillRect(rect, QBrush(color));
    drawReliefNature(painter, delta_height0);
}

/// Отрисовка прямоугольника с цветам рельефа
void VerticalGraphics::drawReliefRect(QPainter* painter)
{
    if(!relief_vec.size()) return;

    double bx = relief_vec.at(0).x(), ex = relief_vec.at(relief_vec.size() - 1).x();
    double delta_height = max_delta_height;
    QColor color(palette().window().color());
    QRectF left_rect(0., 0., bx, height()), right_rect(ex, 0., (width() - ex), height());
    drawReliefNature(painter, delta_height);
    painter -> fillRect(left_rect, QBrush(color));
    painter -> fillRect(right_rect, QBrush(color));
}

/// Отрисовка рельефа
void VerticalGraphics::drawRelief(QPainter* painter)
{
    if(relief_vec.isEmpty()) return;
    QColor color(palette().window().color());
    double prev_x = relief_vec.at(0).x(), beg_x(relief_vec.at(0).x()),
           end_x(relief_vec.at(relief_vec.size() - 1).x());
    for(register int i=0; i<relief_vec.size(); ++i)
    {
        double x = relief_vec.at(i).x(), y = relief_vec.at(i).y();
        double width = x - prev_x;
        QRectF rect(prev_x, 0, width, y);
        painter -> fillRect(rect, QBrush(color));
        prev_x = x;
    }
    QRectF left_rect(0., 0., beg_x, height()), right_rect(end_x, 0., (width() - end_x), height());
    painter -> fillRect(left_rect, QBrush(color));
    painter -> fillRect(right_rect, QBrush(color));
}

/// Отрисовка изображения на заданном устройстве (dev)
void VerticalGraphics::drawOnDevice(QPaintDevice* dev)
{
    QPainter painter(dev);

    painter.setWindow(rect());
    painter.setPen(Qt::black);

    if(fill_axis == 0) param_vec.clear();
    if(param_vec.size() <= count_logrecords && fill_axis <= 3)
    {
        initParamVec();
        setPlotValues();
        if(param_vec.size() == count_logrecords)
            ++fill_axis;
    }
    else if(vrt_thread -> isRunning() && param_vec.size() >= count_logrecords)
        vrt_thread -> quit();
    initCurve();
    if(fill_axis == 3)
    {
        fin_init = true;
        drawReliefRect(&painter);
    }

    painter.end();
    update();
}

/// Отрисовка графика
void VerticalGraphics::paintEvent(QPaintEvent* events)
{
    drawOnDevice(image);
    QPainter painter(this);
    painter.setFont(QFont("Tahoma", 8, Qt::SolidLine));
    painter.drawImage(rect(), *image);
    drawRelief(&painter);
    drawGrid(&painter);
    drawBlackLineRelief(&painter);
    drawCurves(&painter);
    painter.end();
}
Перейти в начало страницы
 
Быстрая цитата+Цитировать сообщение

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


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




RSS Текстовая версия Сейчас: 24.4.2024, 17:05