! \internal Returns via \a lineData the data points that need to be visualized for this graph when plotting graph lines, taking into consideration the currently visible axis ranges and, if \ref setAdaptiveSampling is enabled, local point densities. The considered data can be restricted further by \a begin and \a end, e.g. to only plot a certain segment of the data (see \ref getDataSegme
| 20904 | \see getOptimizedScatterData |
| 20905 | */ |
| 20906 | void QCPGraph::getOptimizedLineData(QVector<QCPGraphData> *lineData, const QCPGraphDataContainer::const_iterator &begin, const QCPGraphDataContainer::const_iterator &end) const |
| 20907 | { |
| 20908 | if (!lineData) return; |
| 20909 | QCPAxis *keyAxis = mKeyAxis.data(); |
| 20910 | QCPAxis *valueAxis = mValueAxis.data(); |
| 20911 | if (!keyAxis || !valueAxis) { qDebug() << Q_FUNC_INFO << "invalid key or value axis"; return; } |
| 20912 | if (begin == end) return; |
| 20913 | |
| 20914 | int dataCount = end-begin; |
| 20915 | int maxCount = (std::numeric_limits<int>::max)(); |
| 20916 | if (mAdaptiveSampling) |
| 20917 | { |
| 20918 | double keyPixelSpan = qAbs(keyAxis->coordToPixel(begin->key)-keyAxis->coordToPixel((end-1)->key)); |
| 20919 | if (2*keyPixelSpan+2 < static_cast<double>((std::numeric_limits<int>::max)())) |
| 20920 | maxCount = 2*keyPixelSpan+2; |
| 20921 | } |
| 20922 | |
| 20923 | if (mAdaptiveSampling && dataCount >= maxCount) // use adaptive sampling only if there are at least two points per pixel on average |
| 20924 | { |
| 20925 | QCPGraphDataContainer::const_iterator it = begin; |
| 20926 | double minValue = it->value; |
| 20927 | double maxValue = it->value; |
| 20928 | QCPGraphDataContainer::const_iterator currentIntervalFirstPoint = it; |
| 20929 | int reversedFactor = keyAxis->pixelOrientation(); // is used to calculate keyEpsilon pixel into the correct direction |
| 20930 | int reversedRound = reversedFactor==-1 ? 1 : 0; // is used to switch between floor (normal) and ceil (reversed) rounding of currentIntervalStartKey |
| 20931 | double currentIntervalStartKey = keyAxis->pixelToCoord((int)(keyAxis->coordToPixel(begin->key)+reversedRound)); |
| 20932 | double lastIntervalEndKey = currentIntervalStartKey; |
| 20933 | double keyEpsilon = qAbs(currentIntervalStartKey-keyAxis->pixelToCoord(keyAxis->coordToPixel(currentIntervalStartKey)+1.0*reversedFactor)); // interval of one pixel on screen when mapped to plot key coordinates |
| 20934 | bool keyEpsilonVariable = keyAxis->scaleType() == QCPAxis::stLogarithmic; // indicates whether keyEpsilon needs to be updated after every interval (for log axes) |
| 20935 | int intervalDataCount = 1; |
| 20936 | ++it; // advance iterator to second data point because adaptive sampling works in 1 point retrospect |
| 20937 | while (it != end) |
| 20938 | { |
| 20939 | if (it->key < currentIntervalStartKey+keyEpsilon) // data point is still within same pixel, so skip it and expand value span of this cluster if necessary |
| 20940 | { |
| 20941 | if (it->value < minValue) |
| 20942 | minValue = it->value; |
| 20943 | else if (it->value > maxValue) |
| 20944 | maxValue = it->value; |
| 20945 | ++intervalDataCount; |
| 20946 | } else // new pixel interval started |
| 20947 | { |
| 20948 | if (intervalDataCount >= 2) // last pixel had multiple data points, consolidate them to a cluster |
| 20949 | { |
| 20950 | if (lastIntervalEndKey < currentIntervalStartKey-keyEpsilon) // last point is further away, so first point of this cluster must be at a real data point |
| 20951 | lineData->append(QCPGraphData(currentIntervalStartKey+keyEpsilon*0.2, currentIntervalFirstPoint->value)); |
| 20952 | lineData->append(QCPGraphData(currentIntervalStartKey+keyEpsilon*0.25, minValue)); |
| 20953 | lineData->append(QCPGraphData(currentIntervalStartKey+keyEpsilon*0.75, maxValue)); |
| 20954 | if (it->key > currentIntervalStartKey+keyEpsilon*2) // new pixel started further away from previous cluster, so make sure the last point of the cluster is at a real data point |
| 20955 | lineData->append(QCPGraphData(currentIntervalStartKey+keyEpsilon*0.8, (it-1)->value)); |
| 20956 | } else |
| 20957 | lineData->append(QCPGraphData(currentIntervalFirstPoint->key, currentIntervalFirstPoint->value)); |
| 20958 | lastIntervalEndKey = (it-1)->key; |
| 20959 | minValue = it->value; |
| 20960 | maxValue = it->value; |
| 20961 | currentIntervalFirstPoint = it; |
| 20962 | currentIntervalStartKey = keyAxis->pixelToCoord((int)(keyAxis->coordToPixel(it->key)+reversedRound)); |
| 20963 | if (keyEpsilonVariable) |
nothing calls this directly
no test coverage detected