@@ -13,8 +13,12 TEMPLATE = app | |||||
13 |
|
13 | |||
14 | INCLUDEPATH += src/QCustomPlot src |
|
14 | INCLUDEPATH += src/QCustomPlot src | |
15 |
|
15 | |||
16 | QMAKE_CXXFLAGS += -O5 -fopenmp -march=corei7-avx -mtune=corei7-avx -mavx |
|
16 | QMAKE_CXXFLAGS_RELEASE += -O5 -fopenmp -march=corei7-avx -mtune=corei7-avx -mavx | |
17 | QMAKE_LFLAGS += -O5 -fopenmp -march=corei7-avx -mtune=corei7-avx -mavx |
|
17 | QMAKE_LFLAGS_RELEASE += -O5 -fopenmp -march=corei7-avx -mtune=corei7-avx -mavx | |
|
18 | ||||
|
19 | QMAKE_CXXFLAGS_DEBUG += -O0 -fopenmp -march=corei7-avx -mtune=corei7-avx -mavx | |||
|
20 | QMAKE_LFLAGS_DEBUG += -O0 -fopenmp -march=corei7-avx -mtune=corei7-avx -mavx | |||
|
21 | ||||
18 |
|
22 | |||
19 | SOURCES += src/main.cpp\ |
|
23 | SOURCES += src/main.cpp\ | |
20 | src/mainwindow.cpp \ |
|
24 | src/mainwindow.cpp \ |
This diff has been collapsed as it changes many lines, (609 lines changed) Show them Hide them | |||||
@@ -5256,7 +5256,7 void QCPAxis::rescale(bool onlyVisiblePl | |||||
5256 | if (p.at(i)->keyAxis() == this) |
|
5256 | if (p.at(i)->keyAxis() == this) | |
5257 | plottableRange = p.at(i)->getKeyRange(currentFoundRange, signDomain); |
|
5257 | plottableRange = p.at(i)->getKeyRange(currentFoundRange, signDomain); | |
5258 | else |
|
5258 | else | |
5259 | plottableRange = p.at(i)->getValueRange(currentFoundRange, signDomain); |
|
5259 | plottableRange = p.at(i)->getValueRange(currentFoundRange, signDomain); | |
5260 | if (currentFoundRange) |
|
5260 | if (currentFoundRange) | |
5261 | { |
|
5261 | { | |
5262 | if (!haveRange) |
|
5262 | if (!haveRange) | |
@@ -9369,6 +9369,7 void QCustomPlot::setMultiSelectModifier | |||||
9369 | mMultiSelectModifier = modifier; |
|
9369 | mMultiSelectModifier = modifier; | |
9370 | } |
|
9370 | } | |
9371 |
|
9371 | |||
|
9372 | ||||
9372 | /*! |
|
9373 | /*! | |
9373 | Sets the viewport of this QCustomPlot. The Viewport is the area that the top level layout |
|
9374 | Sets the viewport of this QCustomPlot. The Viewport is the area that the top level layout | |
9374 | (QCustomPlot::plotLayout()) uses as its rect. Normally, the viewport is the entire widget rect. |
|
9375 | (QCustomPlot::plotLayout()) uses as its rect. Normally, the viewport is the entire widget rect. | |
@@ -14502,7 +14503,7 QCPGraph::QCPGraph(QCPAxis *keyAxis, QCP | |||||
14502 | QCPAbstractPlottable(keyAxis, valueAxis) |
|
14503 | QCPAbstractPlottable(keyAxis, valueAxis) | |
14503 | { |
|
14504 | { | |
14504 | mData = new QCPDataMap; |
|
14505 | mData = new QCPDataMap; | |
14505 |
|
14506 | mDataVector = new QVector<QCPData>(); | ||
14506 | setPen(QPen(Qt::blue, 0)); |
|
14507 | setPen(QPen(Qt::blue, 0)); | |
14507 | setErrorPen(QPen(Qt::black)); |
|
14508 | setErrorPen(QPen(Qt::black)); | |
14508 | setBrush(Qt::NoBrush); |
|
14509 | setBrush(Qt::NoBrush); | |
@@ -14515,6 +14516,7 QCPGraph::QCPGraph(QCPAxis *keyAxis, QCP | |||||
14515 | setErrorBarSkipSymbol(true); |
|
14516 | setErrorBarSkipSymbol(true); | |
14516 | setChannelFillGraph(0); |
|
14517 | setChannelFillGraph(0); | |
14517 | setAdaptiveSampling(true); |
|
14518 | setAdaptiveSampling(true); | |
|
14519 | setUseFastVectors(false); | |||
14518 | } |
|
14520 | } | |
14519 |
|
14521 | |||
14520 | QCPGraph::~QCPGraph() |
|
14522 | QCPGraph::~QCPGraph() | |
@@ -14569,6 +14571,15 void QCPGraph::setData(const QVector<dou | |||||
14569 | } |
|
14571 | } | |
14570 | } |
|
14572 | } | |
14571 |
|
14573 | |||
|
14574 | void QCPGraph::setData(QVector<QCPData> *data) | |||
|
14575 | { | |||
|
14576 | if(data!=mDataVector) | |||
|
14577 | { | |||
|
14578 | delete mDataVector; | |||
|
14579 | this->mDataVector = data; | |||
|
14580 | } | |||
|
14581 | } | |||
|
14582 | ||||
14572 | /*! |
|
14583 | /*! | |
14573 | Replaces the current data with the provided points in \a key and \a value pairs. Additionally the |
|
14584 | Replaces the current data with the provided points in \a key and \a value pairs. Additionally the | |
14574 | symmetrical value error of the data points are set to the values in \a valueError. |
|
14585 | symmetrical value error of the data points are set to the values in \a valueError. | |
@@ -14869,6 +14880,11 void QCPGraph::setAdaptiveSampling(bool | |||||
14869 | mAdaptiveSampling = enabled; |
|
14880 | mAdaptiveSampling = enabled; | |
14870 | } |
|
14881 | } | |
14871 |
|
14882 | |||
|
14883 | void QCPGraph::setUseFastVectors(bool useFastVectors) | |||
|
14884 | { | |||
|
14885 | mUseFastVectors=useFastVectors; | |||
|
14886 | } | |||
|
14887 | ||||
14872 | /*! |
|
14888 | /*! | |
14873 | Adds the provided data points in \a dataMap to the current data. |
|
14889 | Adds the provided data points in \a dataMap to the current data. | |
14874 |
|
14890 | |||
@@ -15095,7 +15111,7 void QCPGraph::rescaleValueAxis(bool onl | |||||
15095 | void QCPGraph::draw(QCPPainter *painter) |
|
15111 | void QCPGraph::draw(QCPPainter *painter) | |
15096 | { |
|
15112 | { | |
15097 | if (!mKeyAxis || !mValueAxis) { qDebug() << Q_FUNC_INFO << "invalid key or value axis"; return; } |
|
15113 | if (!mKeyAxis || !mValueAxis) { qDebug() << Q_FUNC_INFO << "invalid key or value axis"; return; } | |
15098 | if (mKeyAxis.data()->range().size() <= 0 || mData->isEmpty()) return; |
|
15114 | if (mKeyAxis.data()->range().size() <= 0 || (mData->isEmpty() && mDataVector->isEmpty())) return; | |
15099 | if (mLineStyle == lsNone && mScatterStyle.isNone()) return; |
|
15115 | if (mLineStyle == lsNone && mScatterStyle.isNone()) return; | |
15100 |
|
15116 | |||
15101 | // allocate line and (if necessary) point vectors: |
|
15117 | // allocate line and (if necessary) point vectors: | |
@@ -15239,7 +15255,10 void QCPGraph::getLinePlotData(QVector<Q | |||||
15239 | if (!linePixelData) { qDebug() << Q_FUNC_INFO << "null pointer passed as linePixelData"; return; } |
|
15255 | if (!linePixelData) { qDebug() << Q_FUNC_INFO << "null pointer passed as linePixelData"; return; } | |
15240 |
|
15256 | |||
15241 | QVector<QCPData> lineData; |
|
15257 | QVector<QCPData> lineData; | |
15242 | getPreparedData(&lineData, scatterData); |
|
15258 | if(mUseFastVectors) | |
|
15259 | getPreparedDataVector(&lineData, scatterData); | |||
|
15260 | else | |||
|
15261 | getPreparedData(&lineData, scatterData); | |||
15243 | linePixelData->reserve(lineData.size()+2); // added 2 to reserve memory for lower/upper fill base points that might be needed for fill |
|
15262 | linePixelData->reserve(lineData.size()+2); // added 2 to reserve memory for lower/upper fill base points that might be needed for fill | |
15244 | linePixelData->resize(lineData.size()); |
|
15263 | linePixelData->resize(lineData.size()); | |
15245 |
|
15264 | |||
@@ -15850,6 +15869,190 void QCPGraph::getPreparedData(QVector<Q | |||||
15850 | } |
|
15869 | } | |
15851 | } |
|
15870 | } | |
15852 |
|
15871 | |||
|
15872 | ||||
|
15873 | void QCPGraph::getPreparedDataVector(QVector<QCPData> *lineData, QVector<QCPData> *scatterData) const | |||
|
15874 | { | |||
|
15875 | QCPAxis *keyAxis = mKeyAxis.data(); | |||
|
15876 | QCPAxis *valueAxis = mValueAxis.data(); | |||
|
15877 | if (!keyAxis || !valueAxis) { qDebug() << Q_FUNC_INFO << "invalid key or value axis"; return; } | |||
|
15878 | // get visible data range: | |||
|
15879 | QVector<QCPData>::const_iterator lower, upper; // note that upper is the actual upper point, and not 1 step after the upper point | |||
|
15880 | getVisibleDataBoundsVector(lower, upper); | |||
|
15881 | if (lower == mDataVector->constEnd() || upper == mDataVector->constEnd()) | |||
|
15882 | return; | |||
|
15883 | ||||
|
15884 | // count points in visible range, taking into account that we only need to count to the limit maxCount if using adaptive sampling: | |||
|
15885 | int maxCount = std::numeric_limits<int>::max(); | |||
|
15886 | if (mAdaptiveSampling) | |||
|
15887 | { | |||
|
15888 | int keyPixelSpan = qAbs(keyAxis->coordToPixel((*lower).key)-keyAxis->coordToPixel((*upper).key)); | |||
|
15889 | maxCount = 2*keyPixelSpan+2; | |||
|
15890 | } | |||
|
15891 | int dataCount = countDataInBoundsVector(lower, upper, maxCount); | |||
|
15892 | ||||
|
15893 | if (mAdaptiveSampling && dataCount >= maxCount) // use adaptive sampling only if there are at least two points per pixel on average | |||
|
15894 | { | |||
|
15895 | if (lineData) | |||
|
15896 | { | |||
|
15897 | QVector<QCPData>::const_iterator it = lower; | |||
|
15898 | QVector<QCPData>::const_iterator upperEnd = upper+1; | |||
|
15899 | double minValue = (*it).value; | |||
|
15900 | double maxValue = (*it).value; | |||
|
15901 | QVector<QCPData>::const_iterator currentIntervalFirstPoint = it; | |||
|
15902 | int reversedFactor = keyAxis->rangeReversed() != (keyAxis->orientation()==Qt::Vertical) ? -1 : 1; // is used to calculate keyEpsilon pixel into the correct direction | |||
|
15903 | int reversedRound = keyAxis->rangeReversed() != (keyAxis->orientation()==Qt::Vertical) ? 1 : 0; // is used to switch between floor (normal) and ceil (reversed) rounding of currentIntervalStartKey | |||
|
15904 | double currentIntervalStartKey = keyAxis->pixelToCoord((int)(keyAxis->coordToPixel((*lower).key)+reversedRound)); | |||
|
15905 | double lastIntervalEndKey = currentIntervalStartKey; | |||
|
15906 | double keyEpsilon = qAbs(currentIntervalStartKey-keyAxis->pixelToCoord(keyAxis->coordToPixel(currentIntervalStartKey)+1.0*reversedFactor)); // interval of one pixel on screen when mapped to plot key coordinates | |||
|
15907 | bool keyEpsilonVariable = keyAxis->scaleType() == QCPAxis::stLogarithmic; // indicates whether keyEpsilon needs to be updated after every interval (for log axes) | |||
|
15908 | int intervalDataCount = 1; | |||
|
15909 | ++it; // advance iterator to second data point because adaptive sampling works in 1 point retrospect | |||
|
15910 | while (it != upperEnd) | |||
|
15911 | { | |||
|
15912 | if ((*it).key < currentIntervalStartKey+keyEpsilon) // data point is still within same pixel, so skip it and expand value span of this cluster if necessary | |||
|
15913 | { | |||
|
15914 | if ((*it).value < minValue) | |||
|
15915 | minValue = (*it).value; | |||
|
15916 | else if ((*it).value > maxValue) | |||
|
15917 | maxValue = (*it).value; | |||
|
15918 | ++intervalDataCount; | |||
|
15919 | } else // new pixel interval started | |||
|
15920 | { | |||
|
15921 | if (intervalDataCount >= 2) // last pixel had multiple data points, consolidate them to a cluster | |||
|
15922 | { | |||
|
15923 | if (lastIntervalEndKey < currentIntervalStartKey-keyEpsilon) // last point is further away, so first point of this cluster must be at a real data point | |||
|
15924 | lineData->append(QCPData(currentIntervalStartKey+keyEpsilon*0.2, (*currentIntervalFirstPoint).value)); | |||
|
15925 | lineData->append(QCPData(currentIntervalStartKey+keyEpsilon*0.25, minValue)); | |||
|
15926 | lineData->append(QCPData(currentIntervalStartKey+keyEpsilon*0.75, maxValue)); | |||
|
15927 | 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 | |||
|
15928 | lineData->append(QCPData(currentIntervalStartKey+keyEpsilon*0.8, (*(it-1)).value)); | |||
|
15929 | } else | |||
|
15930 | lineData->append(QCPData((*currentIntervalFirstPoint).key, (*currentIntervalFirstPoint).value)); | |||
|
15931 | lastIntervalEndKey = (*(it-1)).key; | |||
|
15932 | minValue = (*it).value; | |||
|
15933 | maxValue = (*it).value; | |||
|
15934 | currentIntervalFirstPoint = it; | |||
|
15935 | currentIntervalStartKey = keyAxis->pixelToCoord((int)(keyAxis->coordToPixel((*it).key)+reversedRound)); | |||
|
15936 | if (keyEpsilonVariable) | |||
|
15937 | keyEpsilon = qAbs(currentIntervalStartKey-keyAxis->pixelToCoord(keyAxis->coordToPixel(currentIntervalStartKey)+1.0*reversedFactor)); | |||
|
15938 | intervalDataCount = 1; | |||
|
15939 | } | |||
|
15940 | ++it; | |||
|
15941 | } | |||
|
15942 | // handle last interval: | |||
|
15943 | if (intervalDataCount >= 2) // last pixel had multiple data points, consolidate them to a cluster | |||
|
15944 | { | |||
|
15945 | if (lastIntervalEndKey < currentIntervalStartKey-keyEpsilon) // last point wasn't a cluster, so first point of this cluster must be at a real data point | |||
|
15946 | lineData->append(QCPData(currentIntervalStartKey+keyEpsilon*0.2, (*currentIntervalFirstPoint).value)); | |||
|
15947 | lineData->append(QCPData(currentIntervalStartKey+keyEpsilon*0.25, minValue)); | |||
|
15948 | lineData->append(QCPData(currentIntervalStartKey+keyEpsilon*0.75, maxValue)); | |||
|
15949 | } else | |||
|
15950 | lineData->append(QCPData((*currentIntervalFirstPoint).key, (*currentIntervalFirstPoint).value)); | |||
|
15951 | } | |||
|
15952 | ||||
|
15953 | if (scatterData) | |||
|
15954 | { | |||
|
15955 | double valueMaxRange = valueAxis->range().upper; | |||
|
15956 | double valueMinRange = valueAxis->range().lower; | |||
|
15957 | QVector<QCPData>::const_iterator it = lower; | |||
|
15958 | QVector<QCPData>::const_iterator upperEnd = upper+1; | |||
|
15959 | double minValue = (*it).value; | |||
|
15960 | double maxValue = (*it).value; | |||
|
15961 | QVector<QCPData>::const_iterator minValueIt = it; | |||
|
15962 | QVector<QCPData>::const_iterator maxValueIt = it; | |||
|
15963 | QVector<QCPData>::const_iterator currentIntervalStart = it; | |||
|
15964 | int reversedFactor = keyAxis->rangeReversed() ? -1 : 1; // is used to calculate keyEpsilon pixel into the correct direction | |||
|
15965 | int reversedRound = keyAxis->rangeReversed() ? 1 : 0; // is used to switch between floor (normal) and ceil (reversed) rounding of currentIntervalStartKey | |||
|
15966 | double currentIntervalStartKey = keyAxis->pixelToCoord((int)(keyAxis->coordToPixel((*lower).key)+reversedRound)); | |||
|
15967 | double keyEpsilon = qAbs(currentIntervalStartKey-keyAxis->pixelToCoord(keyAxis->coordToPixel(currentIntervalStartKey)+1.0*reversedFactor)); // interval of one pixel on screen when mapped to plot key coordinates | |||
|
15968 | bool keyEpsilonVariable = keyAxis->scaleType() == QCPAxis::stLogarithmic; // indicates whether keyEpsilon needs to be updated after every interval (for log axes) | |||
|
15969 | int intervalDataCount = 1; | |||
|
15970 | ++it; // advance iterator to second data point because adaptive sampling works in 1 point retrospect | |||
|
15971 | while (it != upperEnd) | |||
|
15972 | { | |||
|
15973 | if ((*it).key < currentIntervalStartKey+keyEpsilon) // data point is still within same pixel, so skip it and expand value span of this pixel if necessary | |||
|
15974 | { | |||
|
15975 | if ((*it).value < minValue && (*it).value > valueMinRange && (*it).value < valueMaxRange) | |||
|
15976 | { | |||
|
15977 | minValue = (*it).value; | |||
|
15978 | minValueIt = it; | |||
|
15979 | } else if ((*it).value > maxValue && (*it).value > valueMinRange && (*it).value < valueMaxRange) | |||
|
15980 | { | |||
|
15981 | maxValue = (*it).value; | |||
|
15982 | maxValueIt = it; | |||
|
15983 | } | |||
|
15984 | ++intervalDataCount; | |||
|
15985 | } else // new pixel started | |||
|
15986 | { | |||
|
15987 | if (intervalDataCount >= 2) // last pixel had multiple data points, consolidate them | |||
|
15988 | { | |||
|
15989 | // determine value pixel span and add as many points in interval to maintain certain vertical data density (this is specific to scatter plot): | |||
|
15990 | double valuePixelSpan = qAbs(valueAxis->coordToPixel(minValue)-valueAxis->coordToPixel(maxValue)); | |||
|
15991 | int dataModulo = qMax(1, qRound(intervalDataCount/(valuePixelSpan/4.0))); // approximately every 4 value pixels one data point on average | |||
|
15992 | QVector<QCPData>::const_iterator intervalIt = currentIntervalStart; | |||
|
15993 | int c = 0; | |||
|
15994 | while (intervalIt != it) | |||
|
15995 | { | |||
|
15996 | if ((c % dataModulo == 0 || intervalIt == minValueIt || intervalIt == maxValueIt) && (*intervalIt).value > valueMinRange && (*intervalIt).value < valueMaxRange) | |||
|
15997 | scatterData->append((*intervalIt)); | |||
|
15998 | ++c; | |||
|
15999 | ++intervalIt; | |||
|
16000 | } | |||
|
16001 | } else if ((*currentIntervalStart).value > valueMinRange && (*currentIntervalStart).value < valueMaxRange) | |||
|
16002 | scatterData->append((*currentIntervalStart)); | |||
|
16003 | minValue = (*it).value; | |||
|
16004 | maxValue = (*it).value; | |||
|
16005 | currentIntervalStart = it; | |||
|
16006 | currentIntervalStartKey = keyAxis->pixelToCoord((int)(keyAxis->coordToPixel((*it).key)+reversedRound)); | |||
|
16007 | if (keyEpsilonVariable) | |||
|
16008 | keyEpsilon = qAbs(currentIntervalStartKey-keyAxis->pixelToCoord(keyAxis->coordToPixel(currentIntervalStartKey)+1.0*reversedFactor)); | |||
|
16009 | intervalDataCount = 1; | |||
|
16010 | } | |||
|
16011 | ++it; | |||
|
16012 | } | |||
|
16013 | // handle last interval: | |||
|
16014 | if (intervalDataCount >= 2) // last pixel had multiple data points, consolidate them | |||
|
16015 | { | |||
|
16016 | // determine value pixel span and add as many points in interval to maintain certain vertical data density (this is specific to scatter plot): | |||
|
16017 | double valuePixelSpan = qAbs(valueAxis->coordToPixel(minValue)-valueAxis->coordToPixel(maxValue)); | |||
|
16018 | int dataModulo = qMax(1, qRound(intervalDataCount/(valuePixelSpan/4.0))); // approximately every 4 value pixels one data point on average | |||
|
16019 | QVector<QCPData>::const_iterator intervalIt = currentIntervalStart; | |||
|
16020 | int c = 0; | |||
|
16021 | while (intervalIt != it) | |||
|
16022 | { | |||
|
16023 | if ((c % dataModulo == 0 || intervalIt == minValueIt || intervalIt == maxValueIt) && (*intervalIt).value > valueMinRange && (*intervalIt).value < valueMaxRange) | |||
|
16024 | scatterData->append((*intervalIt)); | |||
|
16025 | ++c; | |||
|
16026 | ++intervalIt; | |||
|
16027 | } | |||
|
16028 | } else if ((*currentIntervalStart).value > valueMinRange && (*currentIntervalStart).value < valueMaxRange) | |||
|
16029 | scatterData->append(*currentIntervalStart); | |||
|
16030 | } | |||
|
16031 | } else // don't use adaptive sampling algorithm, transfer points one-to-one from the map into the output parameters | |||
|
16032 | { | |||
|
16033 | QVector<QCPData> *dataVector = 0; | |||
|
16034 | if (lineData) | |||
|
16035 | { | |||
|
16036 | dataVector = lineData; | |||
|
16037 | } | |||
|
16038 | else if (scatterData) | |||
|
16039 | dataVector = scatterData; | |||
|
16040 | if (dataVector) | |||
|
16041 | { | |||
|
16042 | QVector<QCPData>::const_iterator it = lower; | |||
|
16043 | QVector<QCPData>::const_iterator upperEnd = upper+1; | |||
|
16044 | dataVector->reserve(dataCount+2); // +2 for possible fill end points | |||
|
16045 | while (it != upperEnd) | |||
|
16046 | { | |||
|
16047 | dataVector->append(*it); | |||
|
16048 | ++it; | |||
|
16049 | } | |||
|
16050 | } | |||
|
16051 | if (lineData && scatterData) | |||
|
16052 | *scatterData = *dataVector; | |||
|
16053 | } | |||
|
16054 | } | |||
|
16055 | ||||
15853 | /*! \internal |
|
16056 | /*! \internal | |
15854 |
|
16057 | |||
15855 | called by the scatter drawing function (\ref drawScatterPlot) to draw the error bars on one data |
|
16058 | called by the scatter drawing function (\ref drawScatterPlot) to draw the error bars on one data | |
@@ -15988,6 +16191,187 void QCPGraph::getVisibleDataBounds(QCPD | |||||
15988 | upper = (highoutlier ? ubound : ubound-1); // data point range that will be actually drawn |
|
16191 | upper = (highoutlier ? ubound : ubound-1); // data point range that will be actually drawn | |
15989 | } |
|
16192 | } | |
15990 |
|
16193 | |||
|
16194 | ||||
|
16195 | ||||
|
16196 | ||||
|
16197 | QVector<QCPData>::const_iterator __lowerBoundDico(QVector<QCPData>* vector,double key) | |||
|
16198 | { | |||
|
16199 | int DX=vector->size()/2; | |||
|
16200 | int pos=DX; | |||
|
16201 | if(key>=((*vector)[vector->length()-1].key)) | |||
|
16202 | return vector->constEnd(); | |||
|
16203 | if(key<=((*vector)[0].key)) | |||
|
16204 | return vector->constBegin(); | |||
|
16205 | while (DX>1) | |||
|
16206 | { | |||
|
16207 | DX=DX/2; | |||
|
16208 | if((*vector)[pos].key > key) | |||
|
16209 | { | |||
|
16210 | pos-=DX; | |||
|
16211 | } | |||
|
16212 | else | |||
|
16213 | { | |||
|
16214 | pos+=DX; | |||
|
16215 | } | |||
|
16216 | } | |||
|
16217 | return vector->constBegin()+pos+1; | |||
|
16218 | } | |||
|
16219 | ||||
|
16220 | ||||
|
16221 | QVector<QCPData>::const_iterator __upperBoundDico(QVector<QCPData>* vector,double key) | |||
|
16222 | { | |||
|
16223 | int DX=vector->size()/2; | |||
|
16224 | int pos=DX; | |||
|
16225 | if(key>=((*vector)[vector->length()-1].key)) | |||
|
16226 | return vector->constEnd(); | |||
|
16227 | if(key<=((*vector)[0].key)) | |||
|
16228 | return vector->constBegin(); | |||
|
16229 | while (DX>1) | |||
|
16230 | { | |||
|
16231 | DX=DX/2; | |||
|
16232 | if((*vector)[pos].key > key) | |||
|
16233 | { | |||
|
16234 | pos-=DX; | |||
|
16235 | } | |||
|
16236 | else | |||
|
16237 | { | |||
|
16238 | pos+=DX; | |||
|
16239 | } | |||
|
16240 | } | |||
|
16241 | if((*vector)[pos].key >= key) | |||
|
16242 | return vector->constBegin()+pos; | |||
|
16243 | return vector->constBegin()+pos+1; | |||
|
16244 | } | |||
|
16245 | ||||
|
16246 | QVector<QCPData>::const_iterator __lowerBound(QVector<QCPData>* vector,double key) | |||
|
16247 | { | |||
|
16248 | if(vector->length()) | |||
|
16249 | { | |||
|
16250 | double min=(*vector)[0].key,max=(*vector)[vector->length()-1].key; | |||
|
16251 | int speculated=(int)((key/(max-min))*(vector->length()-1)); | |||
|
16252 | double speculatedKey=(*vector)[speculated].key; | |||
|
16253 | double prevKey; | |||
|
16254 | double nextKey; | |||
|
16255 | if(speculated>0) | |||
|
16256 | prevKey= (*vector)[speculated-1].key; | |||
|
16257 | else | |||
|
16258 | prevKey=speculatedKey; | |||
|
16259 | if(speculated<vector->count()-2) | |||
|
16260 | nextKey = (*vector)[speculated+1].key; | |||
|
16261 | else | |||
|
16262 | nextKey=speculated; | |||
|
16263 | ||||
|
16264 | if(key>=max) | |||
|
16265 | return vector->constEnd(); | |||
|
16266 | if(key<=min) | |||
|
16267 | return vector->constBegin(); | |||
|
16268 | ||||
|
16269 | while ((speculatedKey!=key) && !( (speculatedKey>key) && (prevKey<key) ) ) | |||
|
16270 | { | |||
|
16271 | if(Q_UNLIKELY((speculatedKey>key) && (prevKey<key))) | |||
|
16272 | { | |||
|
16273 | break; | |||
|
16274 | } | |||
|
16275 | if(Q_UNLIKELY((speculatedKey<key) && (nextKey>key))) | |||
|
16276 | { | |||
|
16277 | speculated++; | |||
|
16278 | break; | |||
|
16279 | } | |||
|
16280 | if(speculatedKey > key) | |||
|
16281 | max=speculatedKey; | |||
|
16282 | else | |||
|
16283 | min=speculatedKey; | |||
|
16284 | if(speculated>0) | |||
|
16285 | prevKey= (*vector)[speculated-1].key; | |||
|
16286 | else | |||
|
16287 | prevKey=speculatedKey; | |||
|
16288 | if(speculated<vector->count()-2) | |||
|
16289 | nextKey = (*vector)[speculated+1].key; | |||
|
16290 | else | |||
|
16291 | nextKey=speculated; | |||
|
16292 | speculated=(int)((key/(max-min))*(vector->length()-1)); | |||
|
16293 | speculatedKey=(*vector)[speculated].key; | |||
|
16294 | } | |||
|
16295 | if(speculatedKey==key) | |||
|
16296 | return vector->constBegin()+speculated+1; | |||
|
16297 | else | |||
|
16298 | return vector->constBegin()+speculated; | |||
|
16299 | } | |||
|
16300 | return vector->constBegin(); | |||
|
16301 | } | |||
|
16302 | ||||
|
16303 | QVector<QCPData>::const_iterator __upperBound(QVector<QCPData>* vector,double key) | |||
|
16304 | { | |||
|
16305 | if(vector->length()) | |||
|
16306 | { | |||
|
16307 | double min=(*vector)[0].key,max=(*vector)[vector->length()-1].key; | |||
|
16308 | int speculated=(int)((key/(max-min))*(vector->length()-1)); | |||
|
16309 | double speculatedKey=(*vector)[speculated].key; | |||
|
16310 | double prevKey; | |||
|
16311 | double nextKey; | |||
|
16312 | if(speculated>0) | |||
|
16313 | prevKey= (*vector)[speculated-1].key; | |||
|
16314 | else | |||
|
16315 | prevKey=speculatedKey; | |||
|
16316 | if(speculated<vector->count()-2) | |||
|
16317 | nextKey = (*vector)[speculated+1].key; | |||
|
16318 | else | |||
|
16319 | nextKey=speculated; | |||
|
16320 | ||||
|
16321 | if(key>=max) | |||
|
16322 | return vector->constEnd(); | |||
|
16323 | if(key<=min) | |||
|
16324 | return vector->constBegin(); | |||
|
16325 | ||||
|
16326 | while ((speculatedKey!=key) && !( (speculatedKey>key) && (prevKey<key) ) ) | |||
|
16327 | { | |||
|
16328 | if(Q_UNLIKELY((speculatedKey>key) && (prevKey<key))) | |||
|
16329 | { | |||
|
16330 | break; | |||
|
16331 | } | |||
|
16332 | if(Q_UNLIKELY((speculatedKey<key) && (nextKey>key))) | |||
|
16333 | { | |||
|
16334 | speculated++; | |||
|
16335 | break; | |||
|
16336 | } | |||
|
16337 | if(speculatedKey > key) | |||
|
16338 | max=speculatedKey; | |||
|
16339 | else | |||
|
16340 | min=speculatedKey; | |||
|
16341 | if(speculated>0) | |||
|
16342 | prevKey= (*vector)[speculated-1].key; | |||
|
16343 | else | |||
|
16344 | prevKey=speculatedKey; | |||
|
16345 | if(speculated<vector->count()-2) | |||
|
16346 | nextKey = (*vector)[speculated+1].key; | |||
|
16347 | else | |||
|
16348 | nextKey=speculated; | |||
|
16349 | speculated=(int)((key/(max-min))*(vector->length()-1)); | |||
|
16350 | speculatedKey=(*vector)[speculated].key; | |||
|
16351 | } | |||
|
16352 | return vector->constBegin()+speculated; | |||
|
16353 | } | |||
|
16354 | return vector->constEnd(); | |||
|
16355 | } | |||
|
16356 | ||||
|
16357 | void QCPGraph::getVisibleDataBoundsVector(QVector<QCPData>::const_iterator &lower, QVector<QCPData>::const_iterator &upper) const | |||
|
16358 | { | |||
|
16359 | if (!mKeyAxis) { qDebug() << Q_FUNC_INFO << "invalid key axis"; return; } | |||
|
16360 | if (mDataVector->isEmpty()) | |||
|
16361 | { | |||
|
16362 | lower = mDataVector->constEnd(); | |||
|
16363 | upper = mDataVector->constEnd(); | |||
|
16364 | return; | |||
|
16365 | } | |||
|
16366 | QVector<QCPData>::const_iterator lbound = __lowerBoundDico(mDataVector,mKeyAxis.data()->range().lower); | |||
|
16367 | QVector<QCPData>::const_iterator ubound = __lowerBoundDico(mDataVector,mKeyAxis.data()->range().upper); | |||
|
16368 | bool lowoutlier = lbound != mDataVector->constBegin(); // indicates whether there exist points below axis range | |||
|
16369 | bool highoutlier = ubound != mDataVector->constEnd(); // indicates whether there exist points above axis range | |||
|
16370 | ||||
|
16371 | lower = (lowoutlier ? lbound-1 : lbound); // data point range that will be actually drawn | |||
|
16372 | upper = (highoutlier ? ubound : ubound-1); // data point range that will be actually drawn | |||
|
16373 | } | |||
|
16374 | ||||
15991 | /*! \internal |
|
16375 | /*! \internal | |
15992 |
|
16376 | |||
15993 | Counts the number of data points between \a lower and \a upper (including them), up to a maximum |
|
16377 | Counts the number of data points between \a lower and \a upper (including them), up to a maximum | |
@@ -16012,6 +16396,20 int QCPGraph::countDataInBounds(const QC | |||||
16012 | return count; |
|
16396 | return count; | |
16013 | } |
|
16397 | } | |
16014 |
|
16398 | |||
|
16399 | int QCPGraph::countDataInBoundsVector(const QVector<QCPData>::const_iterator &lower, const QVector<QCPData>::const_iterator &upper, int maxCount) const | |||
|
16400 | { | |||
|
16401 | if (upper == mDataVector->constEnd() && lower == mDataVector->constEnd()) | |||
|
16402 | return 0; | |||
|
16403 | QVector<QCPData>::const_iterator it = lower; | |||
|
16404 | int count = 1; | |||
|
16405 | while (it != upper && count < maxCount) | |||
|
16406 | { | |||
|
16407 | ++it; | |||
|
16408 | ++count; | |||
|
16409 | } | |||
|
16410 | return count; | |||
|
16411 | } | |||
|
16412 | ||||
16015 | /*! \internal |
|
16413 | /*! \internal | |
16016 |
|
16414 | |||
16017 | The line data vector generated by e.g. getLinePlotData contains only the line that connects the |
|
16415 | The line data vector generated by e.g. getLinePlotData contains only the line that connects the | |
@@ -16497,6 +16895,8 QCPRange QCPGraph::getKeyRange(bool &fou | |||||
16497 | { |
|
16895 | { | |
16498 | // just call the specialized version which takes an additional argument whether error bars |
|
16896 | // just call the specialized version which takes an additional argument whether error bars | |
16499 | // should also be taken into consideration for range calculation. We set this to true here. |
|
16897 | // should also be taken into consideration for range calculation. We set this to true here. | |
|
16898 | if(mUseFastVectors) | |||
|
16899 | return getKeyRangeVector(foundRange, inSignDomain, true); | |||
16500 | return getKeyRange(foundRange, inSignDomain, true); |
|
16900 | return getKeyRange(foundRange, inSignDomain, true); | |
16501 | } |
|
16901 | } | |
16502 |
|
16902 | |||
@@ -16505,6 +16905,8 QCPRange QCPGraph::getValueRange(bool &f | |||||
16505 | { |
|
16905 | { | |
16506 | // just call the specialized version which takes an additional argument whether error bars |
|
16906 | // just call the specialized version which takes an additional argument whether error bars | |
16507 | // should also be taken into consideration for range calculation. We set this to true here. |
|
16907 | // should also be taken into consideration for range calculation. We set this to true here. | |
|
16908 | if(mUseFastVectors) | |||
|
16909 | return getValueRangeVector(foundRange, inSignDomain, true); | |||
16508 | return getValueRange(foundRange, inSignDomain, true); |
|
16910 | return getValueRange(foundRange, inSignDomain, true); | |
16509 | } |
|
16911 | } | |
16510 |
|
16912 | |||
@@ -16614,6 +17016,106 QCPRange QCPGraph::getKeyRange(bool &fou | |||||
16614 | return range; |
|
17016 | return range; | |
16615 | } |
|
17017 | } | |
16616 |
|
17018 | |||
|
17019 | QCPRange QCPGraph::getKeyRangeVector(bool &foundRange, SignDomain inSignDomain, bool includeErrors) const | |||
|
17020 | { | |||
|
17021 | QCPRange range; | |||
|
17022 | bool haveLower = false; | |||
|
17023 | bool haveUpper = false; | |||
|
17024 | ||||
|
17025 | double current, currentErrorMinus, currentErrorPlus; | |||
|
17026 | ||||
|
17027 | if (inSignDomain == sdBoth) // range may be anywhere | |||
|
17028 | { | |||
|
17029 | QVector<QCPData>::const_iterator it = mDataVector->constBegin(); | |||
|
17030 | while (it != mDataVector->constEnd()) | |||
|
17031 | { | |||
|
17032 | current = (*it).key; | |||
|
17033 | currentErrorMinus = (includeErrors ? (*it).keyErrorMinus : 0); | |||
|
17034 | currentErrorPlus = (includeErrors ? (*it).keyErrorPlus : 0); | |||
|
17035 | if (current-currentErrorMinus < range.lower || !haveLower) | |||
|
17036 | { | |||
|
17037 | range.lower = current-currentErrorMinus; | |||
|
17038 | haveLower = true; | |||
|
17039 | } | |||
|
17040 | if (current+currentErrorPlus > range.upper || !haveUpper) | |||
|
17041 | { | |||
|
17042 | range.upper = current+currentErrorPlus; | |||
|
17043 | haveUpper = true; | |||
|
17044 | } | |||
|
17045 | ++it; | |||
|
17046 | } | |||
|
17047 | } else if (inSignDomain == sdNegative) // range may only be in the negative sign domain | |||
|
17048 | { | |||
|
17049 | QVector<QCPData>::const_iterator it = mDataVector->constBegin(); | |||
|
17050 | while (it != mDataVector->constEnd()) | |||
|
17051 | { | |||
|
17052 | current = (*it).key; | |||
|
17053 | currentErrorMinus = (includeErrors ? (*it).keyErrorMinus : 0); | |||
|
17054 | currentErrorPlus = (includeErrors ? (*it).keyErrorPlus : 0); | |||
|
17055 | if ((current-currentErrorMinus < range.lower || !haveLower) && current-currentErrorMinus < 0) | |||
|
17056 | { | |||
|
17057 | range.lower = current-currentErrorMinus; | |||
|
17058 | haveLower = true; | |||
|
17059 | } | |||
|
17060 | if ((current+currentErrorPlus > range.upper || !haveUpper) && current+currentErrorPlus < 0) | |||
|
17061 | { | |||
|
17062 | range.upper = current+currentErrorPlus; | |||
|
17063 | haveUpper = true; | |||
|
17064 | } | |||
|
17065 | if (includeErrors) // in case point is in valid sign domain but errobars stretch beyond it, we still want to geht that point. | |||
|
17066 | { | |||
|
17067 | if ((current < range.lower || !haveLower) && current < 0) | |||
|
17068 | { | |||
|
17069 | range.lower = current; | |||
|
17070 | haveLower = true; | |||
|
17071 | } | |||
|
17072 | if ((current > range.upper || !haveUpper) && current < 0) | |||
|
17073 | { | |||
|
17074 | range.upper = current; | |||
|
17075 | haveUpper = true; | |||
|
17076 | } | |||
|
17077 | } | |||
|
17078 | ++it; | |||
|
17079 | } | |||
|
17080 | } else if (inSignDomain == sdPositive) // range may only be in the positive sign domain | |||
|
17081 | { | |||
|
17082 | QVector<QCPData>::const_iterator it = mDataVector->constBegin(); | |||
|
17083 | while (it != mDataVector->constEnd()) | |||
|
17084 | { | |||
|
17085 | current = (*it).key; | |||
|
17086 | currentErrorMinus = (includeErrors ? (*it).keyErrorMinus : 0); | |||
|
17087 | currentErrorPlus = (includeErrors ? (*it).keyErrorPlus : 0); | |||
|
17088 | if ((current-currentErrorMinus < range.lower || !haveLower) && current-currentErrorMinus > 0) | |||
|
17089 | { | |||
|
17090 | range.lower = current-currentErrorMinus; | |||
|
17091 | haveLower = true; | |||
|
17092 | } | |||
|
17093 | if ((current+currentErrorPlus > range.upper || !haveUpper) && current+currentErrorPlus > 0) | |||
|
17094 | { | |||
|
17095 | range.upper = current+currentErrorPlus; | |||
|
17096 | haveUpper = true; | |||
|
17097 | } | |||
|
17098 | if (includeErrors) // in case point is in valid sign domain but errobars stretch beyond it, we still want to get that point. | |||
|
17099 | { | |||
|
17100 | if ((current < range.lower || !haveLower) && current > 0) | |||
|
17101 | { | |||
|
17102 | range.lower = current; | |||
|
17103 | haveLower = true; | |||
|
17104 | } | |||
|
17105 | if ((current > range.upper || !haveUpper) && current > 0) | |||
|
17106 | { | |||
|
17107 | range.upper = current; | |||
|
17108 | haveUpper = true; | |||
|
17109 | } | |||
|
17110 | } | |||
|
17111 | ++it; | |||
|
17112 | } | |||
|
17113 | } | |||
|
17114 | ||||
|
17115 | foundRange = haveLower && haveUpper; | |||
|
17116 | return range; | |||
|
17117 | } | |||
|
17118 | ||||
16617 | /*! \overload |
|
17119 | /*! \overload | |
16618 |
|
17120 | |||
16619 | Allows to specify whether the error bars should be included in the range calculation. |
|
17121 | Allows to specify whether the error bars should be included in the range calculation. | |
@@ -16720,6 +17222,105 QCPRange QCPGraph::getValueRange(bool &f | |||||
16720 | return range; |
|
17222 | return range; | |
16721 | } |
|
17223 | } | |
16722 |
|
17224 | |||
|
17225 | QCPRange QCPGraph::getValueRangeVector(bool &foundRange, SignDomain inSignDomain, bool includeErrors) const | |||
|
17226 | { | |||
|
17227 | QCPRange range; | |||
|
17228 | bool haveLower = false; | |||
|
17229 | bool haveUpper = false; | |||
|
17230 | ||||
|
17231 | double current, currentErrorMinus, currentErrorPlus; | |||
|
17232 | ||||
|
17233 | if (inSignDomain == sdBoth) // range may be anywhere | |||
|
17234 | { | |||
|
17235 | QVector<QCPData>::const_iterator it = mDataVector->constBegin(); | |||
|
17236 | while (it != mDataVector->constEnd()) | |||
|
17237 | { | |||
|
17238 | current = (*it).value; | |||
|
17239 | currentErrorMinus = (includeErrors ? (*it).valueErrorMinus : 0); | |||
|
17240 | currentErrorPlus = (includeErrors ? (*it).valueErrorPlus : 0); | |||
|
17241 | if (current-currentErrorMinus < range.lower || !haveLower) | |||
|
17242 | { | |||
|
17243 | range.lower = current-currentErrorMinus; | |||
|
17244 | haveLower = true; | |||
|
17245 | } | |||
|
17246 | if (current+currentErrorPlus > range.upper || !haveUpper) | |||
|
17247 | { | |||
|
17248 | range.upper = current+currentErrorPlus; | |||
|
17249 | haveUpper = true; | |||
|
17250 | } | |||
|
17251 | ++it; | |||
|
17252 | } | |||
|
17253 | } else if (inSignDomain == sdNegative) // range may only be in the negative sign domain | |||
|
17254 | { | |||
|
17255 | QVector<QCPData>::const_iterator it = mDataVector->constBegin(); | |||
|
17256 | while (it != mDataVector->constEnd()) | |||
|
17257 | { | |||
|
17258 | current = (*it).value; | |||
|
17259 | currentErrorMinus = (includeErrors ? (*it).valueErrorMinus : 0); | |||
|
17260 | currentErrorPlus = (includeErrors ? (*it).valueErrorPlus : 0); | |||
|
17261 | if ((current-currentErrorMinus < range.lower || !haveLower) && current-currentErrorMinus < 0) | |||
|
17262 | { | |||
|
17263 | range.lower = current-currentErrorMinus; | |||
|
17264 | haveLower = true; | |||
|
17265 | } | |||
|
17266 | if ((current+currentErrorPlus > range.upper || !haveUpper) && current+currentErrorPlus < 0) | |||
|
17267 | { | |||
|
17268 | range.upper = current+currentErrorPlus; | |||
|
17269 | haveUpper = true; | |||
|
17270 | } | |||
|
17271 | if (includeErrors) // in case point is in valid sign domain but errobars stretch beyond it, we still want to get that point. | |||
|
17272 | { | |||
|
17273 | if ((current < range.lower || !haveLower) && current < 0) | |||
|
17274 | { | |||
|
17275 | range.lower = current; | |||
|
17276 | haveLower = true; | |||
|
17277 | } | |||
|
17278 | if ((current > range.upper || !haveUpper) && current < 0) | |||
|
17279 | { | |||
|
17280 | range.upper = current; | |||
|
17281 | haveUpper = true; | |||
|
17282 | } | |||
|
17283 | } | |||
|
17284 | ++it; | |||
|
17285 | } | |||
|
17286 | } else if (inSignDomain == sdPositive) // range may only be in the positive sign domain | |||
|
17287 | { | |||
|
17288 | QVector<QCPData>::const_iterator it = mDataVector->constBegin(); | |||
|
17289 | while (it != mDataVector->constEnd()) | |||
|
17290 | { | |||
|
17291 | current = (*it).value; | |||
|
17292 | currentErrorMinus = (includeErrors ? (*it).valueErrorMinus : 0); | |||
|
17293 | currentErrorPlus = (includeErrors ? (*it).valueErrorPlus : 0); | |||
|
17294 | if ((current-currentErrorMinus < range.lower || !haveLower) && current-currentErrorMinus > 0) | |||
|
17295 | { | |||
|
17296 | range.lower = current-currentErrorMinus; | |||
|
17297 | haveLower = true; | |||
|
17298 | } | |||
|
17299 | if ((current+currentErrorPlus > range.upper || !haveUpper) && current+currentErrorPlus > 0) | |||
|
17300 | { | |||
|
17301 | range.upper = current+currentErrorPlus; | |||
|
17302 | haveUpper = true; | |||
|
17303 | } | |||
|
17304 | if (includeErrors) // in case point is in valid sign domain but errobars stretch beyond it, we still want to geht that point. | |||
|
17305 | { | |||
|
17306 | if ((current < range.lower || !haveLower) && current > 0) | |||
|
17307 | { | |||
|
17308 | range.lower = current; | |||
|
17309 | haveLower = true; | |||
|
17310 | } | |||
|
17311 | if ((current > range.upper || !haveUpper) && current > 0) | |||
|
17312 | { | |||
|
17313 | range.upper = current; | |||
|
17314 | haveUpper = true; | |||
|
17315 | } | |||
|
17316 | } | |||
|
17317 | ++it; | |||
|
17318 | } | |||
|
17319 | } | |||
|
17320 | ||||
|
17321 | foundRange = haveLower && haveUpper; | |||
|
17322 | return range; | |||
|
17323 | } | |||
16723 |
|
17324 | |||
16724 | //////////////////////////////////////////////////////////////////////////////////////////////////// |
|
17325 | //////////////////////////////////////////////////////////////////////////////////////////////////// | |
16725 | //////////////////// QCPCurveData |
|
17326 | //////////////////// QCPCurveData |
@@ -1862,6 +1862,7 protected: | |||||
1862 | QCPLayer *mCurrentLayer; |
|
1862 | QCPLayer *mCurrentLayer; | |
1863 | QCP::PlottingHints mPlottingHints; |
|
1863 | QCP::PlottingHints mPlottingHints; | |
1864 | Qt::KeyboardModifier mMultiSelectModifier; |
|
1864 | Qt::KeyboardModifier mMultiSelectModifier; | |
|
1865 | bool mUseFastVectors; | |||
1865 |
|
1866 | |||
1866 | // non-property members: |
|
1867 | // non-property members: | |
1867 | QPixmap mPaintBuffer; |
|
1868 | QPixmap mPaintBuffer; | |
@@ -2538,10 +2539,12 public: | |||||
2538 | bool errorBarSkipSymbol() const { return mErrorBarSkipSymbol; } |
|
2539 | bool errorBarSkipSymbol() const { return mErrorBarSkipSymbol; } | |
2539 | QCPGraph *channelFillGraph() const { return mChannelFillGraph.data(); } |
|
2540 | QCPGraph *channelFillGraph() const { return mChannelFillGraph.data(); } | |
2540 | bool adaptiveSampling() const { return mAdaptiveSampling; } |
|
2541 | bool adaptiveSampling() const { return mAdaptiveSampling; } | |
|
2542 | bool useFastVectors() const { return mUseFastVectors; } | |||
2541 |
|
2543 | |||
2542 | // setters: |
|
2544 | // setters: | |
2543 | void setData(QCPDataMap *data, bool copy=false); |
|
2545 | void setData(QCPDataMap *data, bool copy=false); | |
2544 | void setData(const QVector<double> &key, const QVector<double> &value); |
|
2546 | void setData(const QVector<double> &key, const QVector<double> &value); | |
|
2547 | void setData(QVector<QCPData> *data); | |||
2545 | void setDataKeyError(const QVector<double> &key, const QVector<double> &value, const QVector<double> &keyError); |
|
2548 | void setDataKeyError(const QVector<double> &key, const QVector<double> &value, const QVector<double> &keyError); | |
2546 | void setDataKeyError(const QVector<double> &key, const QVector<double> &value, const QVector<double> &keyErrorMinus, const QVector<double> &keyErrorPlus); |
|
2549 | void setDataKeyError(const QVector<double> &key, const QVector<double> &value, const QVector<double> &keyErrorMinus, const QVector<double> &keyErrorPlus); | |
2547 | void setDataValueError(const QVector<double> &key, const QVector<double> &value, const QVector<double> &valueError); |
|
2550 | void setDataValueError(const QVector<double> &key, const QVector<double> &value, const QVector<double> &valueError); | |
@@ -2556,6 +2559,7 public: | |||||
2556 | void setErrorBarSkipSymbol(bool enabled); |
|
2559 | void setErrorBarSkipSymbol(bool enabled); | |
2557 | void setChannelFillGraph(QCPGraph *targetGraph); |
|
2560 | void setChannelFillGraph(QCPGraph *targetGraph); | |
2558 | void setAdaptiveSampling(bool enabled); |
|
2561 | void setAdaptiveSampling(bool enabled); | |
|
2562 | void setUseFastVectors(bool useFastVectors); | |||
2559 |
|
2563 | |||
2560 | // non-property methods: |
|
2564 | // non-property methods: | |
2561 | void addData(const QCPDataMap &dataMap); |
|
2565 | void addData(const QCPDataMap &dataMap); | |
@@ -2580,6 +2584,7 public: | |||||
2580 | protected: |
|
2584 | protected: | |
2581 | // property members: |
|
2585 | // property members: | |
2582 | QCPDataMap *mData; |
|
2586 | QCPDataMap *mData; | |
|
2587 | QVector<QCPData>* mDataVector; | |||
2583 | QPen mErrorPen; |
|
2588 | QPen mErrorPen; | |
2584 | LineStyle mLineStyle; |
|
2589 | LineStyle mLineStyle; | |
2585 | QCPScatterStyle mScatterStyle; |
|
2590 | QCPScatterStyle mScatterStyle; | |
@@ -2588,6 +2593,7 protected: | |||||
2588 | bool mErrorBarSkipSymbol; |
|
2593 | bool mErrorBarSkipSymbol; | |
2589 | QPointer<QCPGraph> mChannelFillGraph; |
|
2594 | QPointer<QCPGraph> mChannelFillGraph; | |
2590 | bool mAdaptiveSampling; |
|
2595 | bool mAdaptiveSampling; | |
|
2596 | bool mUseFastVectors; | |||
2591 |
|
2597 | |||
2592 | // reimplemented virtual methods: |
|
2598 | // reimplemented virtual methods: | |
2593 | virtual void draw(QCPPainter *painter); |
|
2599 | virtual void draw(QCPPainter *painter); | |
@@ -2595,8 +2601,9 protected: | |||||
2595 | virtual QCPRange getKeyRange(bool &foundRange, SignDomain inSignDomain=sdBoth) const; |
|
2601 | virtual QCPRange getKeyRange(bool &foundRange, SignDomain inSignDomain=sdBoth) const; | |
2596 | virtual QCPRange getValueRange(bool &foundRange, SignDomain inSignDomain=sdBoth) const; |
|
2602 | virtual QCPRange getValueRange(bool &foundRange, SignDomain inSignDomain=sdBoth) const; | |
2597 | virtual QCPRange getKeyRange(bool &foundRange, SignDomain inSignDomain, bool includeErrors) const; // overloads base class interface |
|
2603 | virtual QCPRange getKeyRange(bool &foundRange, SignDomain inSignDomain, bool includeErrors) const; // overloads base class interface | |
|
2604 | virtual QCPRange getKeyRangeVector(bool &foundRange, SignDomain inSignDomain, bool includeErrors) const; // overloads base class interface | |||
2598 | virtual QCPRange getValueRange(bool &foundRange, SignDomain inSignDomain, bool includeErrors) const; // overloads base class interface |
|
2605 | virtual QCPRange getValueRange(bool &foundRange, SignDomain inSignDomain, bool includeErrors) const; // overloads base class interface | |
2599 |
|
2606 | virtual QCPRange getValueRangeVector(bool &foundRange, SignDomain inSignDomain, bool includeErrors) const; | ||
2600 | // introduced virtual methods: |
|
2607 | // introduced virtual methods: | |
2601 | virtual void drawFill(QCPPainter *painter, QVector<QPointF> *lineData) const; |
|
2608 | virtual void drawFill(QCPPainter *painter, QVector<QPointF> *lineData) const; | |
2602 | virtual void drawScatterPlot(QCPPainter *painter, QVector<QCPData> *scatterData) const; |
|
2609 | virtual void drawScatterPlot(QCPPainter *painter, QVector<QCPData> *scatterData) const; | |
@@ -2605,6 +2612,7 protected: | |||||
2605 |
|
2612 | |||
2606 | // non-virtual methods: |
|
2613 | // non-virtual methods: | |
2607 | void getPreparedData(QVector<QCPData> *lineData, QVector<QCPData> *scatterData) const; |
|
2614 | void getPreparedData(QVector<QCPData> *lineData, QVector<QCPData> *scatterData) const; | |
|
2615 | void getPreparedDataVector(QVector<QCPData> *lineData, QVector<QCPData> *scatterData) const; | |||
2608 | void getPlotData(QVector<QPointF> *lineData, QVector<QCPData> *scatterData) const; |
|
2616 | void getPlotData(QVector<QPointF> *lineData, QVector<QCPData> *scatterData) const; | |
2609 | void getScatterPlotData(QVector<QCPData> *scatterData) const; |
|
2617 | void getScatterPlotData(QVector<QCPData> *scatterData) const; | |
2610 | void getLinePlotData(QVector<QPointF> *linePixelData, QVector<QCPData> *scatterData) const; |
|
2618 | void getLinePlotData(QVector<QPointF> *linePixelData, QVector<QCPData> *scatterData) const; | |
@@ -2614,7 +2622,9 protected: | |||||
2614 | void getImpulsePlotData(QVector<QPointF> *linePixelData, QVector<QCPData> *scatterData) const; |
|
2622 | void getImpulsePlotData(QVector<QPointF> *linePixelData, QVector<QCPData> *scatterData) const; | |
2615 | void drawError(QCPPainter *painter, double x, double y, const QCPData &data) const; |
|
2623 | void drawError(QCPPainter *painter, double x, double y, const QCPData &data) const; | |
2616 | void getVisibleDataBounds(QCPDataMap::const_iterator &lower, QCPDataMap::const_iterator &upper) const; |
|
2624 | void getVisibleDataBounds(QCPDataMap::const_iterator &lower, QCPDataMap::const_iterator &upper) const; | |
|
2625 | void getVisibleDataBoundsVector(QVector<QCPData>::const_iterator &lower, QVector<QCPData>::const_iterator &upper) const; | |||
2617 | int countDataInBounds(const QCPDataMap::const_iterator &lower, const QCPDataMap::const_iterator &upper, int maxCount) const; |
|
2626 | int countDataInBounds(const QCPDataMap::const_iterator &lower, const QCPDataMap::const_iterator &upper, int maxCount) const; | |
|
2627 | int countDataInBoundsVector(const QVector<QCPData>::const_iterator &lower, const QVector<QCPData>::const_iterator &upper, int maxCount) const; | |||
2618 | void addFillBasePoints(QVector<QPointF> *lineData) const; |
|
2628 | void addFillBasePoints(QVector<QPointF> *lineData) const; | |
2619 | void removeFillBasePoints(QVector<QPointF> *lineData) const; |
|
2629 | void removeFillBasePoints(QVector<QPointF> *lineData) const; | |
2620 | QPointF lowerFillBasePoint(double lowerKey) const; |
|
2630 | QPointF lowerFillBasePoint(double lowerKey) const; |
@@ -43,7 +43,6 SocExplorerPlot::SocExplorerPlot(QWidget | |||||
43 | this->m_plot->setNoAntialiasingOnDrag(true); |
|
43 | this->m_plot->setNoAntialiasingOnDrag(true); | |
44 | this->show(); |
|
44 | this->show(); | |
45 | this->m_plot->legend->setVisible(true); |
|
45 | this->m_plot->legend->setVisible(true); | |
46 |
|
||||
47 | } |
|
46 | } | |
48 |
|
47 | |||
49 | SocExplorerPlot::~SocExplorerPlot() |
|
48 | SocExplorerPlot::~SocExplorerPlot() | |
@@ -117,6 +116,11 void SocExplorerPlot::setAdaptativeSampl | |||||
117 | this->m_plot->graph(graphIndex)->setAdaptiveSampling(enable); |
|
116 | this->m_plot->graph(graphIndex)->setAdaptiveSampling(enable); | |
118 | } |
|
117 | } | |
119 |
|
118 | |||
|
119 | void SocExplorerPlot::setUseFastVector(int graphIndex, bool enable) | |||
|
120 | { | |||
|
121 | this->m_plot->graph(graphIndex)->setUseFastVectors(enable); | |||
|
122 | } | |||
|
123 | ||||
120 | int SocExplorerPlot::addGraph() |
|
124 | int SocExplorerPlot::addGraph() | |
121 | { |
|
125 | { | |
122 | this->m_plot->addGraph(); |
|
126 | this->m_plot->addGraph(); | |
@@ -192,6 +196,16 void SocExplorerPlot::setGraphData(int g | |||||
192 | this->m_plot->replot(); |
|
196 | this->m_plot->replot(); | |
193 | } |
|
197 | } | |
194 |
|
198 | |||
|
199 | void SocExplorerPlot::setGraphData(int graphIndex,QVector<QCPData> *data, bool replot) | |||
|
200 | { | |||
|
201 | if((graphIndex<this->m_plot->graphCount()))// && (x.at(0).type()==QVariant::Double)) | |||
|
202 | { | |||
|
203 | this->m_plot->graph(graphIndex)->setData(data); | |||
|
204 | } | |||
|
205 | if(replot) | |||
|
206 | this->m_plot->replot(); | |||
|
207 | } | |||
|
208 | ||||
195 | void SocExplorerPlot::addGraphData(int graphIndex, QList<QVariant> x, QList<QVariant> y) |
|
209 | void SocExplorerPlot::addGraphData(int graphIndex, QList<QVariant> x, QList<QVariant> y) | |
196 | { |
|
210 | { | |
197 | if((graphIndex<this->m_plot->graphCount()) && (x.count()==y.count()))// && (x.at(0).type()==QVariant::Double)) |
|
211 | if((graphIndex<this->m_plot->graphCount()) && (x.count()==y.count()))// && (x.at(0).type()==QVariant::Double)) |
@@ -43,12 +43,14 public: | |||||
43 | void setLegendFont(QFont font); |
|
43 | void setLegendFont(QFont font); | |
44 | void setLegendSelectedFont(QFont font); |
|
44 | void setLegendSelectedFont(QFont font); | |
45 | void setAdaptativeSampling(int graphIndex,bool enable); |
|
45 | void setAdaptativeSampling(int graphIndex,bool enable); | |
|
46 | void setUseFastVector(int graphIndex,bool enable); | |||
46 | int addGraph(); |
|
47 | int addGraph(); | |
47 | bool removeGraph(int graphIndex); |
|
48 | bool removeGraph(int graphIndex); | |
48 | void removeAllGraphs(); |
|
49 | void removeAllGraphs(); | |
49 | void setGraphName(int graphIndex,QString name); |
|
50 | void setGraphName(int graphIndex,QString name); | |
50 | void setGraphData(int graphIndex, QList<QVariant> x, QList<QVariant> y); |
|
51 | void setGraphData(int graphIndex, QList<QVariant> x, QList<QVariant> y); | |
51 | void setGraphData(int graphIndex, QCPDataMap* data,bool copy = true,bool replot=true); |
|
52 | void setGraphData(int graphIndex, QCPDataMap* data,bool copy = true,bool replot=true); | |
|
53 | void setGraphData(int graphIndex, QVector<QCPData> *data, bool replot); | |||
52 | void addGraphData(int graphIndex, QList<QVariant> x, QList<QVariant> y); |
|
54 | void addGraphData(int graphIndex, QList<QVariant> x, QList<QVariant> y); | |
53 | void addGraphData(int graphIndex, QVariant x, QVariant y); |
|
55 | void addGraphData(int graphIndex, QVariant x, QVariant y); | |
54 | void setGraphPen(int graphIndex,QPen pen); |
|
56 | void setGraphPen(int graphIndex,QPen pen); |
@@ -36,11 +36,13 MainWindow::MainWindow(int OMP_THREADS, | |||||
36 |
|
36 | |||
37 | connect(this->ui->addViewerQpb,SIGNAL(clicked()),this,SLOT(addFolderView())); |
|
37 | connect(this->ui->addViewerQpb,SIGNAL(clicked()),this,SLOT(addFolderView())); | |
38 | connect(&this->fileReader,SIGNAL(dataReady(QCPDataMap*,QCPDataMap*,QCPDataMap*)),this,SLOT(dataReady(QCPDataMap*,QCPDataMap*,QCPDataMap*))); |
|
38 | connect(&this->fileReader,SIGNAL(dataReady(QCPDataMap*,QCPDataMap*,QCPDataMap*)),this,SLOT(dataReady(QCPDataMap*,QCPDataMap*,QCPDataMap*))); | |
|
39 | connect(&this->fileReader,SIGNAL(dataReady(QVector<QCPData>*,QVector<QCPData>*,QVector<QCPData>*)),this,SLOT(dataReady(QVector<QCPData>*,QVector<QCPData>*,QVector<QCPData>*))); | |||
39 | connect(this->ui->calendar,SIGNAL(activated(QDate)),this,SLOT(downloadData(QDate))); |
|
40 | connect(this->ui->calendar,SIGNAL(activated(QDate)),this,SLOT(downloadData(QDate))); | |
40 | for(int i=0;i<3;i++) |
|
41 | for(int i=0;i<3;i++) | |
41 | { |
|
42 | { | |
42 | this->ui->Plot->addGraph(); |
|
43 | this->ui->Plot->addGraph(); | |
43 | this->ui->Plot->setAdaptativeSampling(i,true); |
|
44 | this->ui->Plot->setAdaptativeSampling(i,true); | |
|
45 | this->ui->Plot->setUseFastVector(i,true); | |||
44 | } |
|
46 | } | |
45 | QPen pen = this->ui->Plot->getGraphPen(0); |
|
47 | QPen pen = this->ui->Plot->getGraphPen(0); | |
46 | pen.setColor(Qt::blue); |
|
48 | pen.setColor(Qt::blue); | |
@@ -124,6 +126,23 void MainWindow::dataReady(QCPDataMap *c | |||||
124 | this->ui->Plot->replot(); |
|
126 | this->ui->Plot->replot(); | |
125 | } |
|
127 | } | |
126 |
|
128 | |||
|
129 | void MainWindow::dataReady(QVector<QCPData> *ch1, QVector<QCPData> *ch2, QVector<QCPData> *ch3) | |||
|
130 | { | |||
|
131 | for(int i=0;i<OMP_THREADS;i++) | |||
|
132 | { | |||
|
133 | progressThreadIds[i]=-1; | |||
|
134 | } | |||
|
135 | this->progressWidget->hide(); | |||
|
136 | this->ui->Plot->setGraphName(0,"MAG_X"); | |||
|
137 | this->ui->Plot->setGraphName(1,"MAG_Y"); | |||
|
138 | this->ui->Plot->setGraphName(2,"MAG_Z"); | |||
|
139 | this->ui->Plot->setGraphData(0,ch1,false); | |||
|
140 | this->ui->Plot->setGraphData(1,ch2,false); | |||
|
141 | this->ui->Plot->setGraphData(2,ch3,false); | |||
|
142 | this->ui->Plot->rescaleAxis(); | |||
|
143 | this->ui->Plot->replot(); | |||
|
144 | } | |||
|
145 | ||||
127 | void MainWindow::downloadData(const QDate & date ) |
|
146 | void MainWindow::downloadData(const QDate & date ) | |
128 | { |
|
147 | { | |
129 | QDate tmpDate; |
|
148 | QDate tmpDate; |
@@ -49,6 +49,7 public slots: | |||||
49 | void itemDoubleClicked(QListWidgetItem *item); |
|
49 | void itemDoubleClicked(QListWidgetItem *item); | |
50 | void plotFile(const QString& File); |
|
50 | void plotFile(const QString& File); | |
51 | void dataReady(QCPDataMap *ch1,QCPDataMap *ch2,QCPDataMap *ch3); |
|
51 | void dataReady(QCPDataMap *ch1,QCPDataMap *ch2,QCPDataMap *ch3); | |
|
52 | void dataReady(QVector<QCPData> *ch1,QVector<QCPData> *ch2,QVector<QCPData> *ch3); | |||
52 | void downloadData(const QDate &date); |
|
53 | void downloadData(const QDate &date); | |
53 | void updateProgress(int threadId,int percentProgress); |
|
54 | void updateProgress(int threadId,int percentProgress); | |
54 | void addFolderView(); |
|
55 | void addFolderView(); |
@@ -129,9 +129,12 void ThemisDataFile::run() | |||||
129 | { |
|
129 | { | |
130 | FILE* dataFile; |
|
130 | FILE* dataFile; | |
131 | dataFile = fopen(fileName.toStdString().c_str(),"r"); |
|
131 | dataFile = fopen(fileName.toStdString().c_str(),"r"); | |
132 | QCPDataMap *ch1=new QCPDataMap(); |
|
132 | // QCPDataMap *ch1=new QCPDataMap(); | |
133 | QCPDataMap *ch2=new QCPDataMap(); |
|
133 | // QCPDataMap *ch2=new QCPDataMap(); | |
134 | QCPDataMap *ch3=new QCPDataMap(); |
|
134 | // QCPDataMap *ch3=new QCPDataMap(); | |
|
135 | QVector<QCPData> *ch1=new QVector<QCPData>(); | |||
|
136 | QVector<QCPData> *ch2=new QVector<QCPData>(); | |||
|
137 | QVector<QCPData> *ch3=new QVector<QCPData>(); | |||
135 | QElapsedTimer timr; |
|
138 | QElapsedTimer timr; | |
136 |
|
139 | |||
137 | double _x=0.0; |
|
140 | double _x=0.0; | |
@@ -157,19 +160,24 void ThemisDataFile::run() | |||||
157 | timr.start(); |
|
160 | timr.start(); | |
158 | for(int i=0;i<(FileSize/(58));i++) |
|
161 | for(int i=0;i<(FileSize/(58));i++) | |
159 | { |
|
162 | { | |
160 |
|
|
163 | _x= i; | |
161 | _x= __decodeTimeFromEpoch((i*58),(unsigned char*)line); |
|
164 | //_x= __decodeTimeFromEpoch((i*58),(unsigned char*)line); | |
162 | data1.key=_x; |
|
165 | data1.key=_x; | |
163 | data2.key=_x; |
|
166 | data2.key=_x; | |
164 | data3.key=_x; |
|
167 | data3.key=_x; | |
165 | data1.value=__decodeVal(((i*58)+27),(unsigned char*)line); |
|
168 | data1.value=__decodeVal(((i*58)+27),(unsigned char*)line); | |
166 | data2.value=__decodeVal(((i*58)+38),(unsigned char*)line); |
|
169 | data2.value=__decodeVal(((i*58)+38),(unsigned char*)line); | |
167 | data3.value=__decodeVal(((i*58)+49),(unsigned char*)line); |
|
170 | data3.value=__decodeVal(((i*58)+49),(unsigned char*)line); | |
168 | ch1->insertMulti(_x,data1); |
|
171 | ||
169 |
|
|
172 | //ch1->insertMulti(_x,data1); | |
170 |
|
|
173 | //ch2->insertMulti(_x,data2); | |
|
174 | //ch3->insertMulti(_x,data3); | |||
|
175 | // x->append(_x); | |||
|
176 | ch1->append(data1); | |||
|
177 | ch2->append(data2); | |||
|
178 | ch3->append(data3); | |||
171 | curLine++; |
|
179 | curLine++; | |
172 |
if(lastLineUpdate++> |
|
180 | if(lastLineUpdate++>20000) | |
173 | { |
|
181 | { | |
174 | lastLineUpdate=0; |
|
182 | lastLineUpdate=0; | |
175 | int test=(curLine *100/ (lineCnt)); |
|
183 | int test=(curLine *100/ (lineCnt)); |
@@ -35,6 +35,7 public: | |||||
35 | void run(); |
|
35 | void run(); | |
36 | signals: |
|
36 | signals: | |
37 | void dataReady(QCPDataMap *ch1,QCPDataMap *ch2,QCPDataMap *ch3); |
|
37 | void dataReady(QCPDataMap *ch1,QCPDataMap *ch2,QCPDataMap *ch3); | |
|
38 | void dataReady(QVector<QCPData> *ch1,QVector<QCPData> *ch2,QVector<QCPData> *ch3); | |||
38 | void updateProgress(int percentProgress); |
|
39 | void updateProgress(int percentProgress); | |
39 | void updateProgress(int threadId,int percentProgress); |
|
40 | void updateProgress(int threadId,int percentProgress); | |
40 | public slots: |
|
41 | public slots: |
General Comments 0
You need to be logged in to leave comments.
Login now