QwtPlotCurve::closestPoint
double distance(const QPointF& p, const QPointF& a, const QPointF& b){ const QPointF v = b - a; const QPointF w = p - a; const double c1 = v.x() * w.x() + v.y() * w.y(); const double c2 = v.x() * v.x() + v.y() * v.y(); const QPointF np = (c1 <= 0 ? a : c2 <= c1 ? b : a + c1 / c2 * v ); return sqrt( (p.x() - np.x()) * (p.x() - np.x()) + (p.y() - np.y()) * (p.y() - np.y()) );}
virtual QwtText trackerText(const QwtDoublePoint& point) const{ // Берём откуда-нибудь курву const MyPlotCurve* curve = ...; // Переходим к пиксельным координатам const QwtScaleMap xmap = curve->plot()->canvasMap(QwtPlot::xBottom); const QwtScaleMap ymap = curve->plot()->canvasMap(QwtPlot::yLeft); const QPointF p(xmap.transform(point.x()), ymap.transform(point.y())); // Запихиваем контрольные точки курвы в полигон QPolygonF polygon; const QwtData& data = curve->data(); for(std::size_t i = 0; i < data.size(); ++i) { polygon.push_back(QPointF(xmap.transform(data.x(i)), ymap.transform(data.y(i)))); } // Учитываем случай, когда курва интерполируется не линейно const bool fitted = curve->testCurveAttribute(QwtPlotCurve::Fitted); QwtCurveFitter* fitter = curve->curveFitter(); if(fitted && fitter) { polygon = fitter->fitCurve(polygon); } // Находим расстояние до курвы как минимум расстояний до всех отрезков курвы double mind = std::numeric_limits<double>::max(); if(polygon.size() > 1) { for(int i = 0; i < polygon.size() - 1; ++i) { const QPointF& a = polygon[i]; const QPointF& b = polygon[i + 1]; const double d = distance(p, a, b); if(mind > d) { mind = d; } } } // Показываем расстояние во всплывающей подсказке return QString::number(static_cast<int>(mind));}
C++ (Qt)qreal distance(const QVector2D & p, const QVector2D & a, const QVector2D & b){ QVector2D vecAB = b - a; QVector2D vecPA = a - p; QVector2D vecPB = b - p; double lenAB = vecAB.length(); // расcтояние AB слишком мало? if (lenAB < EPS) return ((a + b) * 0.5f - p).length(); vecAB /= lenAB; // знаковая длина проекция вектора PA на прямую AB qreal dot1 = dotProduct(vecAB, vecPA); // знаковая длина проекция вектора PB на прямую AB qreal dot2 = dotProduct(vecAB, vecPB); // если за границами отрезка, возвращаем расстояние до ближайшей точки if (dot1 * dot2 > 0) return (fabs(dot1) < fabs(dot2)) ? vecPA.length() : vecPB.length(); // возвращаем длину перпендикуляра return (vecPA - vecAB * dot1).length();// можно и так, тот же результат// return (vecPB - vecAB * dot2).length();}