! \internal Calculates the minimum distance in pixels the graph's representation has from the given \a pixelPoint. This is used to determine whether the graph was clicked or not, e.g. in \ref selectTest. The closest data point to \a pixelPoint is returned in \a closestData. Note that if the graph has a line representation, the returned distance may be smaller than the distance to the
| 22420 | is \ref QCPScatterStyle::ssNone (i.e. there is no visual representation of the graph), returns -1.0. |
| 22421 | */ |
| 22422 | double QCPGraph::pointDistance(const QPointF &pixelPoint, QCPGraphDataContainer::const_iterator &closestData) const |
| 22423 | { |
| 22424 | closestData = mDataContainer->constEnd(); |
| 22425 | if (mDataContainer->isEmpty()) |
| 22426 | return -1.0; |
| 22427 | if (mLineStyle == lsNone && mScatterStyle.isNone()) |
| 22428 | return -1.0; |
| 22429 | |
| 22430 | // calculate minimum distances to graph data points and find closestData iterator: |
| 22431 | double minDistSqr = (std::numeric_limits<double>::max)(); |
| 22432 | // determine which key range comes into question, taking selection tolerance around pos into account: |
| 22433 | double posKeyMin, posKeyMax, dummy; |
| 22434 | pixelsToCoords(pixelPoint-QPointF(mParentPlot->selectionTolerance(), mParentPlot->selectionTolerance()), posKeyMin, dummy); |
| 22435 | pixelsToCoords(pixelPoint+QPointF(mParentPlot->selectionTolerance(), mParentPlot->selectionTolerance()), posKeyMax, dummy); |
| 22436 | if (posKeyMin > posKeyMax) |
| 22437 | qSwap(posKeyMin, posKeyMax); |
| 22438 | // iterate over found data points and then choose the one with the shortest distance to pos: |
| 22439 | QCPGraphDataContainer::const_iterator begin = mDataContainer->findBegin(posKeyMin, true); |
| 22440 | QCPGraphDataContainer::const_iterator end = mDataContainer->findEnd(posKeyMax, true); |
| 22441 | for (QCPGraphDataContainer::const_iterator it=begin; it!=end; ++it) |
| 22442 | { |
| 22443 | const double currentDistSqr = QCPVector2D(coordsToPixels(it->key, it->value)-pixelPoint).lengthSquared(); |
| 22444 | if (currentDistSqr < minDistSqr) |
| 22445 | { |
| 22446 | minDistSqr = currentDistSqr; |
| 22447 | closestData = it; |
| 22448 | } |
| 22449 | } |
| 22450 | |
| 22451 | // calculate distance to graph line if there is one (if so, will probably be smaller than distance to closest data point): |
| 22452 | if (mLineStyle != lsNone) |
| 22453 | { |
| 22454 | // line displayed, calculate distance to line segments: |
| 22455 | QVector<QPointF> lineData; |
| 22456 | getLines(&lineData, QCPDataRange(0, dataCount())); // don't limit data range further since with sharp data spikes, line segments may be closer to test point than segments with closer key coordinate |
| 22457 | QCPVector2D p(pixelPoint); |
| 22458 | const int step = mLineStyle==lsImpulse ? 2 : 1; // impulse plot differs from other line styles in that the lineData points are only pairwise connected |
| 22459 | for (int i=0; i<lineData.size()-1; i+=step) |
| 22460 | { |
| 22461 | const double currentDistSqr = p.distanceSquaredToLine(lineData.at(i), lineData.at(i+1)); |
| 22462 | if (currentDistSqr < minDistSqr) |
| 22463 | minDistSqr = currentDistSqr; |
| 22464 | } |
| 22465 | } |
| 22466 | |
| 22467 | return qSqrt(minDistSqr); |
| 22468 | } |
| 22469 | |
| 22470 | /*! \internal |
| 22471 |
nothing calls this directly
no test coverage detected