Название: Пересечение кривой графика с визиром
Отправлено: 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.
Название: Re: Пересечение кривой графика с визиром
Отправлено: AD от Июль 28, 2009, 09:44
Буду благодарен за любые подсказки... Что-то не приходит в голову толковой идеи.
Название: Re: Пересечение кривой графика с визиром
Отправлено: spectre71 от Июль 28, 2009, 10:59
Буду благодарен за любые подсказки... Что-то не приходит в голову толковой идеи.
1) Ты сильно заблуждаешься если думаешь что кто-то будет разбирать твой код, да еще и вырваный кусок в поисках каких-то абстрактных ошибок. 2) Никто не знает что ты имеешь ввиду под "правильно отобразить". У тебя есть функция. Вычисли одну координату по другой.
Название: Re: Пересечение кривой графика с визиром
Отправлено: AD от Июль 28, 2009, 12:00
Правильно отобразить - показать корректное значение. Т.е. если визир пересекается с графиком в точке между значениями 200 и 300, то значение может быть 200 <= y <= 300, а не 165, к примеру, что происходит у меня в данный момент. В том то и дело, что я вычисляю нужной мне функцией, а результат не тот. Конечно, я разберусь в итоге, но если смогут подсказать, то буду благодарен. Для того, чтобы понять кусок кода, я привел комментарии работы функции.
Название: Re: Пересечение кривой графика с визиром
Отправлено: AD от Август 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 есть рисунки получившегося.
|