@@ -13,8 +13,12 TEMPLATE = app | |||
|
13 | 13 | |
|
14 | 14 | INCLUDEPATH += src/QCustomPlot src |
|
15 | 15 | |
|
16 | QMAKE_CXXFLAGS += -O5 -fopenmp -march=corei7-avx -mtune=corei7-avx -mavx | |
|
17 | QMAKE_LFLAGS += -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_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 | 23 | SOURCES += src/main.cpp\ |
|
20 | 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 | 5256 | if (p.at(i)->keyAxis() == this) |
|
5257 | 5257 | plottableRange = p.at(i)->getKeyRange(currentFoundRange, signDomain); |
|
5258 | 5258 | else |
|
5259 | plottableRange = p.at(i)->getValueRange(currentFoundRange, signDomain); | |
|
5259 | plottableRange = p.at(i)->getValueRange(currentFoundRange, signDomain); | |
|
5260 | 5260 | if (currentFoundRange) |
|
5261 | 5261 | { |
|
5262 | 5262 | if (!haveRange) |
@@ -9369,6 +9369,7 void QCustomPlot::setMultiSelectModifier | |||
|
9369 | 9369 | mMultiSelectModifier = modifier; |
|
9370 | 9370 | } |
|
9371 | 9371 | |
|
9372 | ||
|
9372 | 9373 | /*! |
|
9373 | 9374 | Sets the viewport of this QCustomPlot. The Viewport is the area that the top level layout |
|
9374 | 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 | 14503 | QCPAbstractPlottable(keyAxis, valueAxis) |
|
14503 | 14504 | { |
|
14504 | 14505 | mData = new QCPDataMap; |
|
14505 | ||
|
14506 | mDataVector = new QVector<QCPData>(); | |
|
14506 | 14507 | setPen(QPen(Qt::blue, 0)); |
|
14507 | 14508 | setErrorPen(QPen(Qt::black)); |
|
14508 | 14509 | setBrush(Qt::NoBrush); |
@@ -14515,6 +14516,7 QCPGraph::QCPGraph(QCPAxis *keyAxis, QCP | |||
|
14515 | 14516 | setErrorBarSkipSymbol(true); |
|
14516 | 14517 | setChannelFillGraph(0); |
|
14517 | 14518 | setAdaptiveSampling(true); |
|
14519 | setUseFastVectors(false); | |
|
14518 | 14520 | } |
|
14519 | 14521 | |
|
14520 | 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 | 14584 | Replaces the current data with the provided points in \a key and \a value pairs. Additionally the |
|
14574 | 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 | 14880 | mAdaptiveSampling = enabled; |
|
14870 | 14881 | } |
|
14871 | 14882 | |
|
14883 | void QCPGraph::setUseFastVectors(bool useFastVectors) | |
|
14884 | { | |
|
14885 | mUseFastVectors=useFastVectors; | |
|
14886 | } | |
|
14887 | ||
|
14872 | 14888 | /*! |
|
14873 | 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 | 15111 | void QCPGraph::draw(QCPPainter *painter) |
|
15096 | 15112 | { |
|
15097 | 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 | 15115 | if (mLineStyle == lsNone && mScatterStyle.isNone()) return; |
|
15100 | 15116 | |
|
15101 | 15117 | // allocate line and (if necessary) point vectors: |
@@ -15239,7 +15255,10 void QCPGraph::getLinePlotData(QVector<Q | |||
|
15239 | 15255 | if (!linePixelData) { qDebug() << Q_FUNC_INFO << "null pointer passed as linePixelData"; return; } |
|
15240 | 15256 | |
|
15241 | 15257 | QVector<QCPData> lineData; |
|
15242 | getPreparedData(&lineData, scatterData); | |
|
15258 | if(mUseFastVectors) | |
|
15259 | getPreparedDataVector(&lineData, scatterData); | |
|
15260 | else | |
|
15261 | getPreparedData(&lineData, scatterData); | |
|
15243 | 15262 | linePixelData->reserve(lineData.size()+2); // added 2 to reserve memory for lower/upper fill base points that might be needed for fill |
|
15244 | 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 | 16056 | /*! \internal |
|
15854 | 16057 | |
|
15855 | 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 | 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 | 16375 | /*! \internal |
|
15992 | 16376 | |
|
15993 | 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 | 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 | 16413 | /*! \internal |
|
16016 | 16414 | |
|
16017 | 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 | 16896 | // just call the specialized version which takes an additional argument whether error bars |
|
16499 | 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 | 16900 | return getKeyRange(foundRange, inSignDomain, true); |
|
16501 | 16901 | } |
|
16502 | 16902 | |
@@ -16505,6 +16905,8 QCPRange QCPGraph::getValueRange(bool &f | |||
|
16505 | 16905 | { |
|
16506 | 16906 | // just call the specialized version which takes an additional argument whether error bars |
|
16507 | 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 | 16910 | return getValueRange(foundRange, inSignDomain, true); |
|
16509 | 16911 | } |
|
16510 | 16912 | |
@@ -16614,6 +17016,106 QCPRange QCPGraph::getKeyRange(bool &fou | |||
|
16614 | 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 | 17119 | /*! \overload |
|
16618 | 17120 | |
|
16619 | 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 | 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 | 17326 | //////////////////// QCPCurveData |
@@ -1862,6 +1862,7 protected: | |||
|
1862 | 1862 | QCPLayer *mCurrentLayer; |
|
1863 | 1863 | QCP::PlottingHints mPlottingHints; |
|
1864 | 1864 | Qt::KeyboardModifier mMultiSelectModifier; |
|
1865 | bool mUseFastVectors; | |
|
1865 | 1866 | |
|
1866 | 1867 | // non-property members: |
|
1867 | 1868 | QPixmap mPaintBuffer; |
@@ -2538,10 +2539,12 public: | |||
|
2538 | 2539 | bool errorBarSkipSymbol() const { return mErrorBarSkipSymbol; } |
|
2539 | 2540 | QCPGraph *channelFillGraph() const { return mChannelFillGraph.data(); } |
|
2540 | 2541 | bool adaptiveSampling() const { return mAdaptiveSampling; } |
|
2542 | bool useFastVectors() const { return mUseFastVectors; } | |
|
2541 | 2543 | |
|
2542 | 2544 | // setters: |
|
2543 | 2545 | void setData(QCPDataMap *data, bool copy=false); |
|
2544 | 2546 | void setData(const QVector<double> &key, const QVector<double> &value); |
|
2547 | void setData(QVector<QCPData> *data); | |
|
2545 | 2548 | void setDataKeyError(const QVector<double> &key, const QVector<double> &value, const QVector<double> &keyError); |
|
2546 | 2549 | void setDataKeyError(const QVector<double> &key, const QVector<double> &value, const QVector<double> &keyErrorMinus, const QVector<double> &keyErrorPlus); |
|
2547 | 2550 | void setDataValueError(const QVector<double> &key, const QVector<double> &value, const QVector<double> &valueError); |
@@ -2556,6 +2559,7 public: | |||
|
2556 | 2559 | void setErrorBarSkipSymbol(bool enabled); |
|
2557 | 2560 | void setChannelFillGraph(QCPGraph *targetGraph); |
|
2558 | 2561 | void setAdaptiveSampling(bool enabled); |
|
2562 | void setUseFastVectors(bool useFastVectors); | |
|
2559 | 2563 | |
|
2560 | 2564 | // non-property methods: |
|
2561 | 2565 | void addData(const QCPDataMap &dataMap); |
@@ -2580,6 +2584,7 public: | |||
|
2580 | 2584 | protected: |
|
2581 | 2585 | // property members: |
|
2582 | 2586 | QCPDataMap *mData; |
|
2587 | QVector<QCPData>* mDataVector; | |
|
2583 | 2588 | QPen mErrorPen; |
|
2584 | 2589 | LineStyle mLineStyle; |
|
2585 | 2590 | QCPScatterStyle mScatterStyle; |
@@ -2588,6 +2593,7 protected: | |||
|
2588 | 2593 | bool mErrorBarSkipSymbol; |
|
2589 | 2594 | QPointer<QCPGraph> mChannelFillGraph; |
|
2590 | 2595 | bool mAdaptiveSampling; |
|
2596 | bool mUseFastVectors; | |
|
2591 | 2597 | |
|
2592 | 2598 | // reimplemented virtual methods: |
|
2593 | 2599 | virtual void draw(QCPPainter *painter); |
@@ -2595,8 +2601,9 protected: | |||
|
2595 | 2601 | virtual QCPRange getKeyRange(bool &foundRange, SignDomain inSignDomain=sdBoth) const; |
|
2596 | 2602 | virtual QCPRange getValueRange(bool &foundRange, SignDomain inSignDomain=sdBoth) const; |
|
2597 | 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 | 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 | 2607 | // introduced virtual methods: |
|
2601 | 2608 | virtual void drawFill(QCPPainter *painter, QVector<QPointF> *lineData) const; |
|
2602 | 2609 | virtual void drawScatterPlot(QCPPainter *painter, QVector<QCPData> *scatterData) const; |
@@ -2605,6 +2612,7 protected: | |||
|
2605 | 2612 | |
|
2606 | 2613 | // non-virtual methods: |
|
2607 | 2614 | void getPreparedData(QVector<QCPData> *lineData, QVector<QCPData> *scatterData) const; |
|
2615 | void getPreparedDataVector(QVector<QCPData> *lineData, QVector<QCPData> *scatterData) const; | |
|
2608 | 2616 | void getPlotData(QVector<QPointF> *lineData, QVector<QCPData> *scatterData) const; |
|
2609 | 2617 | void getScatterPlotData(QVector<QCPData> *scatterData) const; |
|
2610 | 2618 | void getLinePlotData(QVector<QPointF> *linePixelData, QVector<QCPData> *scatterData) const; |
@@ -2614,7 +2622,9 protected: | |||
|
2614 | 2622 | void getImpulsePlotData(QVector<QPointF> *linePixelData, QVector<QCPData> *scatterData) const; |
|
2615 | 2623 | void drawError(QCPPainter *painter, double x, double y, const QCPData &data) const; |
|
2616 | 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 | 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 | 2628 | void addFillBasePoints(QVector<QPointF> *lineData) const; |
|
2619 | 2629 | void removeFillBasePoints(QVector<QPointF> *lineData) const; |
|
2620 | 2630 | QPointF lowerFillBasePoint(double lowerKey) const; |
@@ -43,7 +43,6 SocExplorerPlot::SocExplorerPlot(QWidget | |||
|
43 | 43 | this->m_plot->setNoAntialiasingOnDrag(true); |
|
44 | 44 | this->show(); |
|
45 | 45 | this->m_plot->legend->setVisible(true); |
|
46 | ||
|
47 | 46 | } |
|
48 | 47 | |
|
49 | 48 | SocExplorerPlot::~SocExplorerPlot() |
@@ -117,6 +116,11 void SocExplorerPlot::setAdaptativeSampl | |||
|
117 | 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 | 124 | int SocExplorerPlot::addGraph() |
|
121 | 125 | { |
|
122 | 126 | this->m_plot->addGraph(); |
@@ -192,6 +196,16 void SocExplorerPlot::setGraphData(int g | |||
|
192 | 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 | 209 | void SocExplorerPlot::addGraphData(int graphIndex, QList<QVariant> x, QList<QVariant> y) |
|
196 | 210 | { |
|
197 | 211 | if((graphIndex<this->m_plot->graphCount()) && (x.count()==y.count()))// && (x.at(0).type()==QVariant::Double)) |
@@ -43,12 +43,14 public: | |||
|
43 | 43 | void setLegendFont(QFont font); |
|
44 | 44 | void setLegendSelectedFont(QFont font); |
|
45 | 45 | void setAdaptativeSampling(int graphIndex,bool enable); |
|
46 | void setUseFastVector(int graphIndex,bool enable); | |
|
46 | 47 | int addGraph(); |
|
47 | 48 | bool removeGraph(int graphIndex); |
|
48 | 49 | void removeAllGraphs(); |
|
49 | 50 | void setGraphName(int graphIndex,QString name); |
|
50 | 51 | void setGraphData(int graphIndex, QList<QVariant> x, QList<QVariant> y); |
|
51 | 52 | void setGraphData(int graphIndex, QCPDataMap* data,bool copy = true,bool replot=true); |
|
53 | void setGraphData(int graphIndex, QVector<QCPData> *data, bool replot); | |
|
52 | 54 | void addGraphData(int graphIndex, QList<QVariant> x, QList<QVariant> y); |
|
53 | 55 | void addGraphData(int graphIndex, QVariant x, QVariant y); |
|
54 | 56 | void setGraphPen(int graphIndex,QPen pen); |
@@ -36,11 +36,13 MainWindow::MainWindow(int OMP_THREADS, | |||
|
36 | 36 | |
|
37 | 37 | connect(this->ui->addViewerQpb,SIGNAL(clicked()),this,SLOT(addFolderView())); |
|
38 | 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 | 40 | connect(this->ui->calendar,SIGNAL(activated(QDate)),this,SLOT(downloadData(QDate))); |
|
40 | 41 | for(int i=0;i<3;i++) |
|
41 | 42 | { |
|
42 | 43 | this->ui->Plot->addGraph(); |
|
43 | 44 | this->ui->Plot->setAdaptativeSampling(i,true); |
|
45 | this->ui->Plot->setUseFastVector(i,true); | |
|
44 | 46 | } |
|
45 | 47 | QPen pen = this->ui->Plot->getGraphPen(0); |
|
46 | 48 | pen.setColor(Qt::blue); |
@@ -124,6 +126,23 void MainWindow::dataReady(QCPDataMap *c | |||
|
124 | 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 | 146 | void MainWindow::downloadData(const QDate & date ) |
|
128 | 147 | { |
|
129 | 148 | QDate tmpDate; |
@@ -49,6 +49,7 public slots: | |||
|
49 | 49 | void itemDoubleClicked(QListWidgetItem *item); |
|
50 | 50 | void plotFile(const QString& File); |
|
51 | 51 | void dataReady(QCPDataMap *ch1,QCPDataMap *ch2,QCPDataMap *ch3); |
|
52 | void dataReady(QVector<QCPData> *ch1,QVector<QCPData> *ch2,QVector<QCPData> *ch3); | |
|
52 | 53 | void downloadData(const QDate &date); |
|
53 | 54 | void updateProgress(int threadId,int percentProgress); |
|
54 | 55 | void addFolderView(); |
@@ -129,9 +129,12 void ThemisDataFile::run() | |||
|
129 | 129 | { |
|
130 | 130 | FILE* dataFile; |
|
131 | 131 | dataFile = fopen(fileName.toStdString().c_str(),"r"); |
|
132 | QCPDataMap *ch1=new QCPDataMap(); | |
|
133 | QCPDataMap *ch2=new QCPDataMap(); | |
|
134 | QCPDataMap *ch3=new QCPDataMap(); | |
|
132 | // QCPDataMap *ch1=new QCPDataMap(); | |
|
133 | // QCPDataMap *ch2=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 | 138 | QElapsedTimer timr; |
|
136 | 139 | |
|
137 | 140 | double _x=0.0; |
@@ -157,19 +160,24 void ThemisDataFile::run() | |||
|
157 | 160 | timr.start(); |
|
158 | 161 | for(int i=0;i<(FileSize/(58));i++) |
|
159 | 162 | { |
|
160 |
|
|
|
161 | _x= __decodeTimeFromEpoch((i*58),(unsigned char*)line); | |
|
163 | _x= i; | |
|
164 | //_x= __decodeTimeFromEpoch((i*58),(unsigned char*)line); | |
|
162 | 165 | data1.key=_x; |
|
163 | 166 | data2.key=_x; |
|
164 | 167 | data3.key=_x; |
|
165 | 168 | data1.value=__decodeVal(((i*58)+27),(unsigned char*)line); |
|
166 | 169 | data2.value=__decodeVal(((i*58)+38),(unsigned char*)line); |
|
167 | 170 | data3.value=__decodeVal(((i*58)+49),(unsigned char*)line); |
|
168 | ch1->insertMulti(_x,data1); | |
|
169 |
|
|
|
170 |
|
|
|
171 | ||
|
172 | //ch1->insertMulti(_x,data1); | |
|
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 | 179 | curLine++; |
|
172 |
if(lastLineUpdate++> |
|
|
180 | if(lastLineUpdate++>20000) | |
|
173 | 181 | { |
|
174 | 182 | lastLineUpdate=0; |
|
175 | 183 | int test=(curLine *100/ (lineCnt)); |
@@ -35,6 +35,7 public: | |||
|
35 | 35 | void run(); |
|
36 | 36 | signals: |
|
37 | 37 | void dataReady(QCPDataMap *ch1,QCPDataMap *ch2,QCPDataMap *ch3); |
|
38 | void dataReady(QVector<QCPData> *ch1,QVector<QCPData> *ch2,QVector<QCPData> *ch3); | |
|
38 | 39 | void updateProgress(int percentProgress); |
|
39 | 40 | void updateProgress(int threadId,int percentProgress); |
|
40 | 41 | public slots: |
General Comments 0
You need to be logged in to leave comments.
Login now