Russian Qt Forum
Май 18, 2024, 04:51 *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

Войти
 
  Начало   Форум  WIKI (Вики)FAQ Помощь Поиск Войти Регистрация  

Страниц: [1]   Вниз
  Печать  
Автор Тема: Пересечение кривой графика с визиром  (Прочитано 3976 раз)
AD
Гость
« : Июль 27, 2009, 18:10 »

Что-то не получается правильно отобразить координату пересечения кривой или кривых графика с визиром. Подскажите, пожалуйста
Код
C++ (Qt)
/// Отображение координат пересечения с визиром
void GraphicDisplay::viewCoordViewfinder(const QVector<SpecPointF>& data, int index, const QPointF& pnt)
{
if(!v_viewfinderAction -> isChecked() && !h_viewfinderAction -> isChecked())
return;
int graphic_x = data[index].x(), graphic_y = data[index].y();
foreach(VFFrame* pf, viewfinderList)
{
int frame_x = pf -> x(), frame_y = pf -> y();
if(pf -> frameShape() == QFrame::VLine && v_viewfinderAction -> isChecked())
if(fabs((double)(frame_x - graphic_x)) <= 3.)
{
QPointF coord(frame_x/* + 10.*/, pnt.y()/* - 10.*/);
QPen oldPen(painter.pen());
painter.setPen(Qt::black);
painter.drawText(coord, QString::number(pnt.x()));
painter.setPen(oldPen);
}
else if(pf -> frameShape() == QFrame::HLine  && h_viewfinderAction -> isChecked())
if(fabs((double)(frame_y - graphic_y)) <= 3.)
{
QPointF coord(pnt.x() + 10., frame_y - 10.);
QPen oldPen(painter.pen());
painter.setPen(Qt::black);
painter.drawText(coord, QString::number(pnt.x()));
painter.setPen(oldPen);
}
}
}
 
Параметры функции: вектор физических координат, текущий индекс в этом векторе и точку на экране, соответствующую заданному значению физической координаты. Далее перебирается список всех возможных визиров (два вида: горизонтальная линия или вертикальная). Давайте для упрощения рассмотрим только вертикальные визиры. Т.е. необходимо найти ординату пересечения. Сравниваются две абсциссы, если их разность по модулю не превышает 3, то выводим ординату.

Вот функция рисования кривых:
Код
C++ (Qt)
/// Отрисовка графика
void GraphicDisplay::drawCurves(QPainter* painter)
{
if(!paramsDisplay -> rect().isValid()) return;
painter -> setClipRect(paramsDisplay -> rect().adjusted(1, 1, -1, -1));
 
QMapIterator<int, QVector<SpecPointF>> iter(curveMap);
int k = 1;
while(iter.hasNext())
{
iter.next(); int id = iter.key();
if(fact_prm.size() == 0 || id >= fact_prm.size()) break;
if(settings.win_type != fact_prm[id].type) continue;
 
QString x_dimension(fact_prm[id].dimension[language_flag].toLower());
double x_dim = (metric_map[x_dimension]) ? metric_map[x_dimension] : 1.0;
QString y_dimension(fact_prm[id].y_dim[language_flag].toLower());
double y_dim = (metric_map[y_dimension]) ? metric_map[y_dimension] : 1.0;
myPen.setColor(fact_prm[id].param_color);
painter -> setPen(myPen);
 
const QVector<SpecPointF>& data = iter.value();
QPolygonF polyline(0);
for(int j=0; j<data.size(); ++j)
{
double x = (settings.win_type != COUNTPARAM) ? data[j].x() * x_dim : data[j].x();
double y = data[j].y() * y_dim;
QPointF pnt(initXY(x, y));
if(isExistPhase(data[j]))
if(!polyline.isEmpty())
{
if(pnt.x() > polyline.last().x())
{
setPenForLine(j);
painter -> setPen(myPen);
if(j > 0 && isExistPhase(data[j - 1]))
{
painter -> drawLine(polyline.last(), pnt);
viewCoordViewfinder(data, j, pnt);
}
polyline.append(pnt);
}
}
else polyline.append(pnt);
}
drawLegend(painter, paramsDisplay -> rect(), k, id);
}
}
 
data - вектор физических координат, j - текущий индекс в векторе, pnt - экранная точка, соответствующая индексу j.
Записан
AD
Гость
« Ответ #1 : Июль 28, 2009, 09:44 »

Буду благодарен за любые подсказки... Что-то не приходит в голову толковой идеи.
Записан
spectre71
Гость
« Ответ #2 : Июль 28, 2009, 10:59 »

Буду благодарен за любые подсказки... Что-то не приходит в голову толковой идеи.
1) Ты сильно заблуждаешься если думаешь что кто-то будет разбирать твой код, да еще и вырваный кусок в поисках каких-то абстрактных ошибок.
2) Никто не знает что ты имеешь ввиду под "правильно отобразить".

У тебя есть функция. Вычисли одну координату по другой.
Записан
AD
Гость
« Ответ #3 : Июль 28, 2009, 12:00 »

Правильно отобразить - показать корректное значение. Т.е. если визир пересекается с графиком в точке между значениями 200 и 300, то значение может быть 200 <= y <= 300, а не 165, к примеру, что происходит у меня в данный момент.
В том то и дело, что я вычисляю нужной мне функцией, а результат не тот. Конечно, я разберусь в итоге, но если смогут подсказать, то буду благодарен. Для того, чтобы понять кусок кода, я привел комментарии работы функции.
Записан
AD
Гость
« Ответ #4 : Август 05, 2009, 15:03 »

Получилось сделать корректное отображение пересечение графика с визиром.

Выложу код, вдруг, все-таки пригодится кому-нибудь. Если что, смогу и объяснить, где что в коде делается!
Код
C++ (Qt)
/// Получение размерностей заданной по id кривой
QPointF GraphicDisplay::dimensions(int id)
{
QString x_dimension(fact_prm[id].dimension[language_flag].toLower());
double x_dim = (metric_map[x_dimension]) ? metric_map[x_dimension] : 1.0;
QString y_dimension(fact_prm[id].y_dim[language_flag].toLower());
double y_dim = (metric_map[y_dimension]) ? metric_map[y_dimension] : 1.0;
return QPointF(x_dim, y_dim);
}
 
/// Поиск точки пересечения визира с графиком (в реальных координатах - следует переводить в экранные)
QPointF GraphicDisplay::findCrossPoint(const QPointF& pnt, const QPointF& prev_pnt, const QPointF& pnt_vf)
{
double curr_x = pnt.x(), curr_y = pnt.y(), prev_x = prev_pnt.x(), prev_y = prev_pnt.y(), y_vf = pnt_vf.y(),
x_vf = pnt_vf.x();
double y = prev_y + (curr_y - prev_y) * (x_vf - prev_x) / (curr_x - prev_x),
x = prev_x + (curr_x - prev_x) * (y_vf - prev_y) / (curr_y - prev_y);
if(curr_y - prev_y == 0.) x = curr_x;
if(curr_x - prev_x == 0.) y = curr_y;
 
return QPointF(x, y);
}
 
/// Отображение текста точки пересечения визира с графиком
void GraphicDisplay::drawViewfinderText(QPainter* painter, const QPointF& coord, const QPen& pen,
double coordinate)
{
QBrush oldBrush(pen.color());
QPen oldPen(pen.color());
painter -> setBrush(pen.color());
QColor color((pen.color() == QColor(Qt::blue)) ? Qt::darkGreen : Qt::blue);
painter -> setPen(color);
painter -> drawText(coord, QString::number(coordinate));
painter -> setPen(oldPen);
painter -> setBrush(oldBrush);
}
 
/// Отображение координат пересечения с визиром
void GraphicDisplay::viewCoordViewfinder(QPainter* painter, int id, const QVector<SpecPointF>& data, int index)
{
if(!v_viewfinderAction -> isChecked() && !h_viewfinderAction -> isChecked()) return;
QPointF dim(dimensions(id));
double real_y = data[index].y(), prev_ry = data[index - 1].y(),
real_x = (settings.win_type != COUNTPARAM) ? data[index].x() * dim.x() : data[index].x(),
prev_rx = (settings.win_type != COUNTPARAM) ? data[index - 1].x() * dim.x() : data[index - 1].x();
QPointF pnt(initXY(real_x, real_y)), prev_pnt(initXY(prev_rx, prev_ry)), rl_pnt(real_x, real_y),
prev_rl_pnt(prev_rx, prev_ry);
foreach(VFFrame* pf, viewfinderList)
{
QPoint screen_pnt_vf(pf -> x(), pf -> y());
QPointF pnt_vf(initXY(&screen_pnt_vf));
double prev_x = prev_rl_pnt.x(), prev_y = prev_rl_pnt.y(), curr_x = rl_pnt.x(), curr_y = rl_pnt.y();
double x_vf = pnt_vf.x(), y_vf = pnt_vf.y();
QPointF res_point(findCrossPoint(rl_pnt, prev_rl_pnt, pnt_vf));
double result_x = res_point.x(), result_y = res_point.y();
QPointF crd_scr(initXY(result_x, result_y));
if(pf -> frameShape() == QFrame::VLine && v_viewfinderAction -> isChecked() &&
prev_x <= x_vf && curr_x > x_vf)
{
QPointF coord(pf -> x() + 15, crd_scr.y() - 1.);
drawViewfinderText(painter, coord, painter -> pen(), res_point.y());
}
else if(pf -> frameShape() == QFrame::HLine && h_viewfinderAction -> isChecked() &&
prev_y <= y_vf && curr_y > y_vf)
{
QPointF coord(crd_scr.x() - 1., pf -> y() - 15.);
drawViewfinderText(painter, coord, painter -> pen(), res_point.x());
}
}
}
 
/// Отрисовка графика
void GraphicDisplay::drawCurves(QPainter* painter)
{
if(!paramsDisplay -> rect().isValid()) return;
painter -> setClipRect(paramsDisplay -> rect().adjusted(1, 1, -1, -1));
 
QMapIterator<int, QVector<SpecPointF>> iter(curveMap);
int k = 1;
bool smoothing = valueElement("diagramSmooth", false).toBool();
while(iter.hasNext())
{
iter.next(); int id = iter.key();
if(fact_prm.size() == 0 || id >= fact_prm.size()) break;
if(settings.win_type != fact_prm[id].type) continue;
QPointF dim(dimensions(id));
setColorPen(painter, id);
 
const QVector<SpecPointF>& data = iter.value();
QPolygonF polyline(0);
for(int j=0; j<data.size(); ++j)
{
if(!isExistPhase(data[j])) continue;
 
double x = (settings.win_type != COUNTPARAM) ? data[j].x() * dim.x() : data[j].x();
double y = data[j].y() * dim.y();
QPointF pnt(initXY(x, y));
if(!polyline.isEmpty())
{
if(smoothing && pnt.x() <= polyline.last().x()) continue;
setPenForLine(j);
painter -> setPen(myPen);
if(j > 0 && isExistPhase(data[j - 1]))
painter -> drawLine(polyline.last(), pnt),
viewCoordViewfinder(painter, id, data, j);
polyline.append(pnt);
}
else polyline.append(pnt);
}
drawLegend(painter, paramsDisplay -> rect(), k, id);
}
}

На http://www.forum.crossplatform.ru/index.php?showtopic=3180&pid=23077&st=10&#entry23077
есть рисунки получившегося.
Записан
Страниц: [1]   Вверх
  Печать  
 
Перейти в:  


Страница сгенерирована за 0.803 секунд. Запросов: 20.