##// END OF EJS Templates
Removed hack from QCustomPlot, moved to QCustomPlotVect class.
jeandet -
r7:6e23aedd1ca8 default
parent child
Show More
This diff has been collapsed as it changes many lines, (619 lines changed) Show them Hide them
@@ -0,0 +1,619
1 #include "qcustomplotvect.h"
2 #include <QVector>
3 #include <QVectorIterator>
4 QCustomPlotVect::QCustomPlotVect(QWidget *parent)
5 :QCustomPlot(parent)
6 {
7
8 }
9
10 QCustomPlotVect::~QCustomPlotVect()
11 {
12
13 }
14
15 QCPGraphVect *QCustomPlotVect::addGraph(QCPAxis *keyAxis, QCPAxis *valueAxis)
16 {
17 if (!keyAxis) keyAxis = xAxis;
18 if (!valueAxis) valueAxis = yAxis;
19 if (!keyAxis || !valueAxis)
20 {
21 qDebug() << Q_FUNC_INFO << "can't use default QCustomPlot xAxis or yAxis, because at least one is invalid (has been deleted)";
22 return 0;
23 }
24 if (keyAxis->parentPlot() != this || valueAxis->parentPlot() != this)
25 {
26 qDebug() << Q_FUNC_INFO << "passed keyAxis or valueAxis doesn't have this QCustomPlot as parent";
27 return 0;
28 }
29
30 QCPGraphVect *newGraph = new QCPGraphVect(keyAxis, valueAxis);
31 if (addPlottable(newGraph))
32 {
33 newGraph->setName(QLatin1String("Graph ")+QString::number(mGraphs.size()));
34 return newGraph;
35 } else
36 {
37 delete newGraph;
38 return 0;
39 }
40 }
41
42
43 QCPGraphVect::QCPGraphVect(QCPAxis *keyAxis, QCPAxis *valueAxis)
44 :QCPGraph(keyAxis,valueAxis)
45 {
46 mData = new QVector<QCPData>();
47 }
48
49 QCPGraphVect::~QCPGraphVect()
50 {
51
52 }
53
54 void QCPGraphVect::setData(QVector<QCPData> *data)
55 {
56 if(data!=mData)
57 {
58 delete this->mData;
59 this->mData = data;
60 }
61 }
62
63 void QCPGraphVect::draw(QCPPainter *painter)
64 {
65 if (!mKeyAxis || !mValueAxis) { qDebug() << Q_FUNC_INFO << "invalid key or value axis"; return; }
66 int test = mKeyAxis.data()->range().size();
67 test = mData->count();
68 if (mKeyAxis.data()->range().size() <= 0 || mData->isEmpty()) return;
69 if (mLineStyle == lsNone && mScatterStyle.isNone()) return;
70
71 // allocate line and (if necessary) point vectors:
72 QVector<QPointF> *lineData = new QVector<QPointF>;
73 QVector<QCPData> *scatterData = 0;
74 if (!mScatterStyle.isNone())
75 scatterData = new QVector<QCPData>;
76
77 // fill vectors with data appropriate to plot style:
78 getPlotData(lineData, scatterData);
79
80 // check data validity if flag set:
81 #ifdef QCUSTOMPLOT_CHECK_DATA
82 QCPDataMap::const_iterator it;
83 for (it = mData->constBegin(); it != mData->constEnd(); ++it)
84 {
85 if (QCP::isInvalidData(it.value().key, it.value().value) ||
86 QCP::isInvalidData(it.value().keyErrorPlus, it.value().keyErrorMinus) ||
87 QCP::isInvalidData(it.value().valueErrorPlus, it.value().valueErrorPlus))
88 qDebug() << Q_FUNC_INFO << "Data point at" << it.key() << "invalid." << "Plottable name:" << name();
89 }
90 #endif
91
92 // draw fill of graph:
93 drawFill(painter, lineData);
94
95 // draw line:
96 if (mLineStyle == lsImpulse)
97 drawImpulsePlot(painter, lineData);
98 else if (mLineStyle != lsNone)
99 drawLinePlot(painter, lineData); // also step plots can be drawn as a line plot
100
101 // draw scatters:
102 if (scatterData)
103 drawScatterPlot(painter, scatterData);
104
105 // free allocated line and point vectors:
106 delete lineData;
107 if (scatterData)
108 delete scatterData;
109 }
110
111 void QCPGraphVect::getPlotData(QVector<QPointF> *lineData, QVector<QCPData> *scatterData) const
112 {
113 switch(mLineStyle)
114 {
115 case lsNone: getScatterPlotData(scatterData); break;
116 case lsLine: getLinePlotData(lineData, scatterData); break;
117 case lsStepLeft: getStepLeftPlotData(lineData, scatterData); break;
118 case lsStepRight: getStepRightPlotData(lineData, scatterData); break;
119 case lsStepCenter: getStepCenterPlotData(lineData, scatterData); break;
120 case lsImpulse: getImpulsePlotData(lineData, scatterData); break;
121 }
122 }
123
124 void QCPGraphVect::getLinePlotData(QVector<QPointF> *linePixelData, QVector<QCPData> *scatterData) const
125 {
126 QCPAxis *keyAxis = mKeyAxis.data();
127 QCPAxis *valueAxis = mValueAxis.data();
128 if (!keyAxis || !valueAxis) { qDebug() << Q_FUNC_INFO << "invalid key or value axis"; return; }
129 if (!linePixelData) { qDebug() << Q_FUNC_INFO << "null pointer passed as linePixelData"; return; }
130
131 QVector<QCPData> lineData;
132 getPreparedData(&lineData, scatterData);
133 linePixelData->reserve(lineData.size()+2); // added 2 to reserve memory for lower/upper fill base points that might be needed for fill
134 linePixelData->resize(lineData.size());
135
136 // transform lineData points to pixels:
137 if (keyAxis->orientation() == Qt::Vertical)
138 {
139 for (int i=0; i<lineData.size(); ++i)
140 {
141 (*linePixelData)[i].setX(valueAxis->coordToPixel(lineData.at(i).value));
142 (*linePixelData)[i].setY(keyAxis->coordToPixel(lineData.at(i).key));
143 }
144 } else // key axis is horizontal
145 {
146 for (int i=0; i<lineData.size(); ++i)
147 {
148 (*linePixelData)[i].setX(keyAxis->coordToPixel(lineData.at(i).key));
149 (*linePixelData)[i].setY(valueAxis->coordToPixel(lineData.at(i).value));
150 }
151 }
152 }
153
154 QCPRange QCPGraphVect::getKeyRange(bool &foundRange, QCPAbstractPlottable::SignDomain inSignDomain, bool includeErrors) const
155 {
156
157 QCPRange range;
158 bool haveLower = false;
159 bool haveUpper = false;
160
161 double current, currentErrorMinus, currentErrorPlus;
162
163 if (inSignDomain == sdBoth) // range may be anywhere
164 {
165 QVector<QCPData>::const_iterator it = mData->constBegin();
166 while (it != mData->constEnd())
167 {
168 current = (*it).key;
169 currentErrorMinus = (includeErrors ? (*it).keyErrorMinus : 0);
170 currentErrorPlus = (includeErrors ? (*it).keyErrorPlus : 0);
171 if (current-currentErrorMinus < range.lower || !haveLower)
172 {
173 range.lower = current-currentErrorMinus;
174 haveLower = true;
175 }
176 if (current+currentErrorPlus > range.upper || !haveUpper)
177 {
178 range.upper = current+currentErrorPlus;
179 haveUpper = true;
180 }
181 ++it;
182 }
183 } else if (inSignDomain == sdNegative) // range may only be in the negative sign domain
184 {
185 QVector<QCPData>::const_iterator it = mData->constBegin();
186 while (it != mData->constEnd())
187 {
188 current = (*it).key;
189 currentErrorMinus = (includeErrors ? (*it).keyErrorMinus : 0);
190 currentErrorPlus = (includeErrors ? (*it).keyErrorPlus : 0);
191 if ((current-currentErrorMinus < range.lower || !haveLower) && current-currentErrorMinus < 0)
192 {
193 range.lower = current-currentErrorMinus;
194 haveLower = true;
195 }
196 if ((current+currentErrorPlus > range.upper || !haveUpper) && current+currentErrorPlus < 0)
197 {
198 range.upper = current+currentErrorPlus;
199 haveUpper = true;
200 }
201 if (includeErrors) // in case point is in valid sign domain but errobars stretch beyond it, we still want to geht that point.
202 {
203 if ((current < range.lower || !haveLower) && current < 0)
204 {
205 range.lower = current;
206 haveLower = true;
207 }
208 if ((current > range.upper || !haveUpper) && current < 0)
209 {
210 range.upper = current;
211 haveUpper = true;
212 }
213 }
214 ++it;
215 }
216 } else if (inSignDomain == sdPositive) // range may only be in the positive sign domain
217 {
218 QVector<QCPData>::const_iterator it = mData->constBegin();
219 while (it != mData->constEnd())
220 {
221 current = (*it).key;
222 currentErrorMinus = (includeErrors ? (*it).keyErrorMinus : 0);
223 currentErrorPlus = (includeErrors ? (*it).keyErrorPlus : 0);
224 if ((current-currentErrorMinus < range.lower || !haveLower) && current-currentErrorMinus > 0)
225 {
226 range.lower = current-currentErrorMinus;
227 haveLower = true;
228 }
229 if ((current+currentErrorPlus > range.upper || !haveUpper) && current+currentErrorPlus > 0)
230 {
231 range.upper = current+currentErrorPlus;
232 haveUpper = true;
233 }
234 if (includeErrors) // in case point is in valid sign domain but errobars stretch beyond it, we still want to get that point.
235 {
236 if ((current < range.lower || !haveLower) && current > 0)
237 {
238 range.lower = current;
239 haveLower = true;
240 }
241 if ((current > range.upper || !haveUpper) && current > 0)
242 {
243 range.upper = current;
244 haveUpper = true;
245 }
246 }
247 ++it;
248 }
249 }
250
251 foundRange = haveLower && haveUpper;
252 return range;
253 }
254
255 QCPRange QCPGraphVect::getValueRange(bool &foundRange, QCPAbstractPlottable::SignDomain inSignDomain, bool includeErrors) const
256 {
257 QCPRange range;
258 bool haveLower = false;
259 bool haveUpper = false;
260
261 double current, currentErrorMinus, currentErrorPlus;
262
263 if (inSignDomain == sdBoth) // range may be anywhere
264 {
265 QVector<QCPData>::const_iterator it = mData->constBegin();
266 while (it != mData->constEnd())
267 {
268 current = (*it).value;
269 currentErrorMinus = (includeErrors ? (*it).valueErrorMinus : 0);
270 currentErrorPlus = (includeErrors ? (*it).valueErrorPlus : 0);
271 if (current-currentErrorMinus < range.lower || !haveLower)
272 {
273 range.lower = current-currentErrorMinus;
274 haveLower = true;
275 }
276 if (current+currentErrorPlus > range.upper || !haveUpper)
277 {
278 range.upper = current+currentErrorPlus;
279 haveUpper = true;
280 }
281 ++it;
282 }
283 } else if (inSignDomain == sdNegative) // range may only be in the negative sign domain
284 {
285 QVector<QCPData>::const_iterator it = mData->constBegin();
286 while (it != mData->constEnd())
287 {
288 current = (*it).value;
289 currentErrorMinus = (includeErrors ? (*it).valueErrorMinus : 0);
290 currentErrorPlus = (includeErrors ? (*it).valueErrorPlus : 0);
291 if ((current-currentErrorMinus < range.lower || !haveLower) && current-currentErrorMinus < 0)
292 {
293 range.lower = current-currentErrorMinus;
294 haveLower = true;
295 }
296 if ((current+currentErrorPlus > range.upper || !haveUpper) && current+currentErrorPlus < 0)
297 {
298 range.upper = current+currentErrorPlus;
299 haveUpper = true;
300 }
301 if (includeErrors) // in case point is in valid sign domain but errobars stretch beyond it, we still want to get that point.
302 {
303 if ((current < range.lower || !haveLower) && current < 0)
304 {
305 range.lower = current;
306 haveLower = true;
307 }
308 if ((current > range.upper || !haveUpper) && current < 0)
309 {
310 range.upper = current;
311 haveUpper = true;
312 }
313 }
314 ++it;
315 }
316 } else if (inSignDomain == sdPositive) // range may only be in the positive sign domain
317 {
318 QVector<QCPData>::const_iterator it = mData->constBegin();
319 while (it != mData->constEnd())
320 {
321 current = (*it).value;
322 currentErrorMinus = (includeErrors ? (*it).valueErrorMinus : 0);
323 currentErrorPlus = (includeErrors ? (*it).valueErrorPlus : 0);
324 if ((current-currentErrorMinus < range.lower || !haveLower) && current-currentErrorMinus > 0)
325 {
326 range.lower = current-currentErrorMinus;
327 haveLower = true;
328 }
329 if ((current+currentErrorPlus > range.upper || !haveUpper) && current+currentErrorPlus > 0)
330 {
331 range.upper = current+currentErrorPlus;
332 haveUpper = true;
333 }
334 if (includeErrors) // in case point is in valid sign domain but errobars stretch beyond it, we still want to geht that point.
335 {
336 if ((current < range.lower || !haveLower) && current > 0)
337 {
338 range.lower = current;
339 haveLower = true;
340 }
341 if ((current > range.upper || !haveUpper) && current > 0)
342 {
343 range.upper = current;
344 haveUpper = true;
345 }
346 }
347 ++it;
348 }
349 }
350
351 foundRange = haveLower && haveUpper;
352 return range;
353 }
354
355 void QCPGraphVect::getPreparedData(QVector<QCPData> *lineData, QVector<QCPData> *scatterData) const
356 {
357 QCPAxis *keyAxis = mKeyAxis.data();
358 QCPAxis *valueAxis = mValueAxis.data();
359 if (!keyAxis || !valueAxis) { qDebug() << Q_FUNC_INFO << "invalid key or value axis"; return; }
360 // get visible data range:
361 QVector<QCPData>::const_iterator lower, upper; // note that upper is the actual upper point, and not 1 step after the upper point
362 getVisibleDataBounds(lower, upper);
363 if (lower == mData->constEnd() || upper == mData->constEnd())
364 return;
365
366 // count points in visible range, taking into account that we only need to count to the limit maxCount if using adaptive sampling:
367 int maxCount = std::numeric_limits<int>::max();
368 if (mAdaptiveSampling)
369 {
370 int keyPixelSpan = qAbs(keyAxis->coordToPixel((*lower).key)-keyAxis->coordToPixel((*upper).key));
371 maxCount = 2*keyPixelSpan+2;
372 }
373 int dataCount = countDataInBounds(lower, upper, maxCount);
374
375 if (mAdaptiveSampling && dataCount >= maxCount) // use adaptive sampling only if there are at least two points per pixel on average
376 {
377 if (lineData)
378 {
379 QVector<QCPData>::const_iterator it = lower;
380 QVector<QCPData>::const_iterator upperEnd = upper+1;
381 double minValue = (*it).value;
382 double maxValue = (*it).value;
383 QVector<QCPData>::const_iterator currentIntervalFirstPoint = it;
384 int reversedFactor = keyAxis->rangeReversed() != (keyAxis->orientation()==Qt::Vertical) ? -1 : 1; // is used to calculate keyEpsilon pixel into the correct direction
385 int reversedRound = keyAxis->rangeReversed() != (keyAxis->orientation()==Qt::Vertical) ? 1 : 0; // is used to switch between floor (normal) and ceil (reversed) rounding of currentIntervalStartKey
386 double currentIntervalStartKey = keyAxis->pixelToCoord((int)(keyAxis->coordToPixel((*lower).key)+reversedRound));
387 double lastIntervalEndKey = currentIntervalStartKey;
388 double keyEpsilon = qAbs(currentIntervalStartKey-keyAxis->pixelToCoord(keyAxis->coordToPixel(currentIntervalStartKey)+1.0*reversedFactor)); // interval of one pixel on screen when mapped to plot key coordinates
389 bool keyEpsilonVariable = keyAxis->scaleType() == QCPAxis::stLogarithmic; // indicates whether keyEpsilon needs to be updated after every interval (for log axes)
390 int intervalDataCount = 1;
391 ++it; // advance iterator to second data point because adaptive sampling works in 1 point retrospect
392 while (it != upperEnd)
393 {
394 if ((*it).key < currentIntervalStartKey+keyEpsilon) // data point is still within same pixel, so skip it and expand value span of this cluster if necessary
395 {
396 if ((*it).value < minValue)
397 minValue = (*it).value;
398 else if ((*it).value > maxValue)
399 maxValue = (*it).value;
400 ++intervalDataCount;
401 } else // new pixel interval started
402 {
403 if (intervalDataCount >= 2) // last pixel had multiple data points, consolidate them to a cluster
404 {
405 if (lastIntervalEndKey < currentIntervalStartKey-keyEpsilon) // last point is further away, so first point of this cluster must be at a real data point
406 lineData->append(QCPData(currentIntervalStartKey+keyEpsilon*0.2, (*currentIntervalFirstPoint).value));
407 lineData->append(QCPData(currentIntervalStartKey+keyEpsilon*0.25, minValue));
408 lineData->append(QCPData(currentIntervalStartKey+keyEpsilon*0.75, maxValue));
409 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
410 lineData->append(QCPData(currentIntervalStartKey+keyEpsilon*0.8, (*(it-1)).value));
411 } else
412 lineData->append(QCPData((*currentIntervalFirstPoint).key, (*currentIntervalFirstPoint).value));
413 lastIntervalEndKey = (*(it-1)).key;
414 minValue = (*it).value;
415 maxValue = (*it).value;
416 currentIntervalFirstPoint = it;
417 currentIntervalStartKey = keyAxis->pixelToCoord((int)(keyAxis->coordToPixel((*it).key)+reversedRound));
418 if (keyEpsilonVariable)
419 keyEpsilon = qAbs(currentIntervalStartKey-keyAxis->pixelToCoord(keyAxis->coordToPixel(currentIntervalStartKey)+1.0*reversedFactor));
420 intervalDataCount = 1;
421 }
422 ++it;
423 }
424 // handle last interval:
425 if (intervalDataCount >= 2) // last pixel had multiple data points, consolidate them to a cluster
426 {
427 if (lastIntervalEndKey < currentIntervalStartKey-keyEpsilon) // last point wasn't a cluster, so first point of this cluster must be at a real data point
428 lineData->append(QCPData(currentIntervalStartKey+keyEpsilon*0.2, (*currentIntervalFirstPoint).value));
429 lineData->append(QCPData(currentIntervalStartKey+keyEpsilon*0.25, minValue));
430 lineData->append(QCPData(currentIntervalStartKey+keyEpsilon*0.75, maxValue));
431 } else
432 lineData->append(QCPData((*currentIntervalFirstPoint).key, (*currentIntervalFirstPoint).value));
433 }
434
435 if (scatterData)
436 {
437 double valueMaxRange = valueAxis->range().upper;
438 double valueMinRange = valueAxis->range().lower;
439 QVector<QCPData>::const_iterator it = lower;
440 QVector<QCPData>::const_iterator upperEnd = upper+1;
441 double minValue = (*it).value;
442 double maxValue = (*it).value;
443 QVector<QCPData>::const_iterator minValueIt = it;
444 QVector<QCPData>::const_iterator maxValueIt = it;
445 QVector<QCPData>::const_iterator currentIntervalStart = it;
446 int reversedFactor = keyAxis->rangeReversed() ? -1 : 1; // is used to calculate keyEpsilon pixel into the correct direction
447 int reversedRound = keyAxis->rangeReversed() ? 1 : 0; // is used to switch between floor (normal) and ceil (reversed) rounding of currentIntervalStartKey
448 double currentIntervalStartKey = keyAxis->pixelToCoord((int)(keyAxis->coordToPixel((*lower).key)+reversedRound));
449 double keyEpsilon = qAbs(currentIntervalStartKey-keyAxis->pixelToCoord(keyAxis->coordToPixel(currentIntervalStartKey)+1.0*reversedFactor)); // interval of one pixel on screen when mapped to plot key coordinates
450 bool keyEpsilonVariable = keyAxis->scaleType() == QCPAxis::stLogarithmic; // indicates whether keyEpsilon needs to be updated after every interval (for log axes)
451 int intervalDataCount = 1;
452 ++it; // advance iterator to second data point because adaptive sampling works in 1 point retrospect
453 while (it != upperEnd)
454 {
455 if ((*it).key < currentIntervalStartKey+keyEpsilon) // data point is still within same pixel, so skip it and expand value span of this pixel if necessary
456 {
457 if ((*it).value < minValue && (*it).value > valueMinRange && (*it).value < valueMaxRange)
458 {
459 minValue = (*it).value;
460 minValueIt = it;
461 } else if ((*it).value > maxValue && (*it).value > valueMinRange && (*it).value < valueMaxRange)
462 {
463 maxValue = (*it).value;
464 maxValueIt = it;
465 }
466 ++intervalDataCount;
467 } else // new pixel started
468 {
469 if (intervalDataCount >= 2) // last pixel had multiple data points, consolidate them
470 {
471 // determine value pixel span and add as many points in interval to maintain certain vertical data density (this is specific to scatter plot):
472 double valuePixelSpan = qAbs(valueAxis->coordToPixel(minValue)-valueAxis->coordToPixel(maxValue));
473 int dataModulo = qMax(1, qRound(intervalDataCount/(valuePixelSpan/4.0))); // approximately every 4 value pixels one data point on average
474 QVector<QCPData>::const_iterator intervalIt = currentIntervalStart;
475 int c = 0;
476 while (intervalIt != it)
477 {
478 if ((c % dataModulo == 0 || intervalIt == minValueIt || intervalIt == maxValueIt) && (*intervalIt).value > valueMinRange && (*intervalIt).value < valueMaxRange)
479 scatterData->append((*intervalIt));
480 ++c;
481 ++intervalIt;
482 }
483 } else if ((*currentIntervalStart).value > valueMinRange && (*currentIntervalStart).value < valueMaxRange)
484 scatterData->append((*currentIntervalStart));
485 minValue = (*it).value;
486 maxValue = (*it).value;
487 currentIntervalStart = it;
488 currentIntervalStartKey = keyAxis->pixelToCoord((int)(keyAxis->coordToPixel((*it).key)+reversedRound));
489 if (keyEpsilonVariable)
490 keyEpsilon = qAbs(currentIntervalStartKey-keyAxis->pixelToCoord(keyAxis->coordToPixel(currentIntervalStartKey)+1.0*reversedFactor));
491 intervalDataCount = 1;
492 }
493 ++it;
494 }
495 // handle last interval:
496 if (intervalDataCount >= 2) // last pixel had multiple data points, consolidate them
497 {
498 // determine value pixel span and add as many points in interval to maintain certain vertical data density (this is specific to scatter plot):
499 double valuePixelSpan = qAbs(valueAxis->coordToPixel(minValue)-valueAxis->coordToPixel(maxValue));
500 int dataModulo = qMax(1, qRound(intervalDataCount/(valuePixelSpan/4.0))); // approximately every 4 value pixels one data point on average
501 QVector<QCPData>::const_iterator intervalIt = currentIntervalStart;
502 int c = 0;
503 while (intervalIt != it)
504 {
505 if ((c % dataModulo == 0 || intervalIt == minValueIt || intervalIt == maxValueIt) && (*intervalIt).value > valueMinRange && (*intervalIt).value < valueMaxRange)
506 scatterData->append((*intervalIt));
507 ++c;
508 ++intervalIt;
509 }
510 } else if ((*currentIntervalStart).value > valueMinRange && (*currentIntervalStart).value < valueMaxRange)
511 scatterData->append(*currentIntervalStart);
512 }
513 } else // don't use adaptive sampling algorithm, transfer points one-to-one from the map into the output parameters
514 {
515 QVector<QCPData> *dataVector = 0;
516 if (lineData)
517 {
518 dataVector = lineData;
519 }
520 else if (scatterData)
521 dataVector = scatterData;
522 if (dataVector)
523 {
524 QVector<QCPData>::const_iterator it = lower;
525 QVector<QCPData>::const_iterator upperEnd = upper+1;
526 dataVector->reserve(dataCount+2); // +2 for possible fill end points
527 while (it != upperEnd)
528 {
529 dataVector->append(*it);
530 ++it;
531 }
532 }
533 if (lineData && scatterData)
534 *scatterData = *dataVector;
535 }
536 }
537
538 QVector<QCPData>::const_iterator __lowerBoundDico_vect(QVector<QCPData>* vector,double key)
539 {
540 int DX=vector->size()/2;
541 int pos=DX;
542 // double test=(*vector)[vector->length()-1].key;
543 if(key>((*vector)[vector->length()-1].key))
544 return vector->constEnd();
545 if(key<((*vector)[0].key))
546 return vector->constBegin();
547 while (DX>1)
548 {
549 DX=DX/2;
550 if((*vector)[pos].key > key)
551 {
552 pos-=DX;
553 }
554 else
555 {
556 pos+=DX;
557 }
558 }
559 if((*vector)[pos].key >= key)
560 return vector->constBegin()+pos;
561 return vector->constBegin()+pos+1;
562 }
563
564
565 QVector<QCPData>::const_iterator __upperBoundDico_vect(QVector<QCPData>* vector,double key)
566 {
567 int DX=vector->size()/2;
568 int pos=DX;
569 if(key>((*vector)[vector->length()-1].key))
570 return vector->constEnd();
571 if(key<((*vector)[0].key))
572 return vector->constBegin();
573 while (DX>1)
574 {
575 DX=DX/2;
576 if((*vector)[pos].key > key)
577 {
578 pos-=DX;
579 }
580 else
581 {
582 pos+=DX;
583 }
584 }
585 return vector->constBegin()+pos+1;
586 }
587
588
589 void QCPGraphVect::getVisibleDataBounds(QVector<QCPData>::const_iterator &lower, QVector<QCPData>::const_iterator &upper) const
590 {
591 if (!mKeyAxis) { qDebug() << Q_FUNC_INFO << "invalid key axis"; return; }
592 if (mData->isEmpty())
593 {
594 lower = mData->constEnd();
595 upper = mData->constEnd();
596 return;
597 }
598 QVector<QCPData>::const_iterator lbound = __lowerBoundDico_vect(mData,mKeyAxis.data()->range().lower);
599 QVector<QCPData>::const_iterator ubound = __upperBoundDico_vect(mData,mKeyAxis.data()->range().upper);
600 bool lowoutlier = lbound != mData->constBegin(); // indicates whether there exist points below axis range
601 bool highoutlier = ubound != mData->constEnd(); // indicates whether there exist points above axis range
602
603 lower = (lowoutlier ? lbound-1 : lbound); // data point range that will be actually drawn
604 upper = (highoutlier ? ubound : ubound-1); // data point range that will be actually drawn
605 }
606
607 int QCPGraphVect::countDataInBounds(const QVector<QCPData>::const_iterator &lower, const QVector<QCPData>::const_iterator &upper, int maxCount) const
608 {
609 if (upper == mData->constEnd() && lower == mData->constEnd())
610 return 0;
611 QVector<QCPData>::const_iterator it = lower;
612 int count = 1;
613 while (it != upper && count < maxCount)
614 {
615 ++it;
616 ++count;
617 }
618 return count;
619 }
@@ -0,0 +1,38
1 #ifndef QCUSTOMPLOTVECT_H
2 #define QCUSTOMPLOTVECT_H
3
4 #include <QWidget>
5 #include <qcustomplot.h>
6
7 class QCPGraphVect : public QCPGraph
8 {
9 Q_OBJECT
10 public:
11 explicit QCPGraphVect(QCPAxis *keyAxis, QCPAxis *valueAxis);
12 ~QCPGraphVect();
13 QVector<QCPData> *data() const { return mData; }
14 void setData(QVector<QCPData> *data);
15 protected:
16 QVector<QCPData>* mData;
17 virtual void draw(QCPPainter *painter);
18 virtual QCPRange getKeyRange(bool &foundRange, SignDomain inSignDomain, bool includeErrors) const; // overloads base class interface
19 virtual QCPRange getValueRange(bool &foundRange, SignDomain inSignDomain, bool includeErrors) const;
20 void getPreparedData(QVector<QCPData> *lineData, QVector<QCPData> *scatterData) const;
21 void getVisibleDataBounds(QVector<QCPData>::const_iterator &lower, QVector<QCPData>::const_iterator &upper) const;
22 int countDataInBounds(const QVector<QCPData>::const_iterator &lower, const QVector<QCPData>::const_iterator &upper, int maxCount) const;
23
24 void getPlotData(QVector<QPointF> *lineData, QVector<QCPData> *scatterData) const;
25 void getLinePlotData(QVector<QPointF> *linePixelData, QVector<QCPData> *scatterData) const;
26 };
27
28 class QCustomPlotVect : public QCustomPlot
29 {
30 Q_OBJECT
31 public:
32 QCustomPlotVect(QWidget *parent = 0);
33 ~QCustomPlotVect();
34 QCPGraphVect *addGraph(QCPAxis *keyAxis=0, QCPAxis *valueAxis=0);
35 protected:
36 };
37
38 #endif // QCUSTOMPLOTVECT_H
@@ -30,9 +30,7 SOURCES += src/main.cpp\
30 src/mainwindow.cpp \
30 src/mainwindow.cpp \
31 src/SocExplorerPlot.cpp \
31 src/SocExplorerPlot.cpp \
32 src/QCustomPlot/qcustomplot.cpp \
32 src/QCustomPlot/qcustomplot.cpp \
33 src/folderview.cpp \
34 src/toolbarcontainer.cpp \
33 src/toolbarcontainer.cpp \
35 src/folderlistwidget.cpp \
36 src/Core/abstractfileloader.cpp \
34 src/Core/abstractfileloader.cpp \
37 src/Core/filedownloader.cpp \
35 src/Core/filedownloader.cpp \
38 src/Core/filedownloadertask.cpp \
36 src/Core/filedownloadertask.cpp \
@@ -52,14 +50,13 SOURCES += src/main.cpp\
52 src/Core/Widgets/PyWdgt/pythonqtscriptingconsoledandd.cpp \
50 src/Core/Widgets/PyWdgt/pythonqtscriptingconsoledandd.cpp \
53 src/QCustomPlot/qcpdocumentobject.cpp \
51 src/QCustomPlot/qcpdocumentobject.cpp \
54 src/Core/Widgets/filebrowser.cpp \
52 src/Core/Widgets/filebrowser.cpp \
55 src/Core/Widgets/filesystemmodel.cpp
53 src/Core/Widgets/filesystemmodel.cpp \
54 src/Core/Widgets/qcustomplotvect.cpp
56
55
57 HEADERS += src/mainwindow.h \
56 HEADERS += src/mainwindow.h \
58 src/SocExplorerPlot.h \
57 src/SocExplorerPlot.h \
59 src/QCustomPlot/qcustomplot.h \
58 src/QCustomPlot/qcustomplot.h \
60 src/folderview.h \
61 src/toolbarcontainer.h \
59 src/toolbarcontainer.h \
62 src/folderlistwidget.h \
63 src/Core/abstractfileloader.h \
60 src/Core/abstractfileloader.h \
64 src/Core/filedownloader.h \
61 src/Core/filedownloader.h \
65 src/Core/filedownloadertask.h \
62 src/Core/filedownloadertask.h \
@@ -81,10 +78,10 HEADERS += src/mainwindow.h \
81 src/Core/pyqlop.h \
78 src/Core/pyqlop.h \
82 src/QCustomPlot/qcpdocumentobject.h \
79 src/QCustomPlot/qcpdocumentobject.h \
83 src/Core/Widgets/filebrowser.h \
80 src/Core/Widgets/filebrowser.h \
84 src/Core/Widgets/filesystemmodel.h
81 src/Core/Widgets/filesystemmodel.h \
82 src/Core/Widgets/qcustomplotvect.h
85
83
86 FORMS += src/mainwindow.ui \
84 FORMS += src/mainwindow.ui \
87 src/folderview.ui \
88 src/Core/Widgets/downloadhistory.ui \
85 src/Core/Widgets/downloadhistory.ui \
89 src/Core/Widgets/downloadhistoryelement.ui \
86 src/Core/Widgets/downloadhistoryelement.ui \
90 src/Cassini/cassinidatadownloader.ui \
87 src/Cassini/cassinidatadownloader.ui \
@@ -55,7 +55,7 void CassiniTools::makePlot()
55 plot->setXaxisTickLabelType(QCPAxis::ltDateTime);
55 plot->setXaxisTickLabelType(QCPAxis::ltDateTime);
56 plot->setXaxisDateTimeFormat("hh:mm:ss.zzz");
56 plot->setXaxisDateTimeFormat("hh:mm:ss.zzz");
57 plot->setContextMenuPolicy(Qt::ActionsContextMenu);
57 plot->setContextMenuPolicy(Qt::ActionsContextMenu);
58 QAction* action=new QAction("export view",_self);
58 SocExplorerPlotActions* action=new SocExplorerPlotActions("export view",plot->PID(),_self);
59 plot->addAction(action);
59 plot->addAction(action);
60 QObject::connect(action,SIGNAL(triggered()),_self,SLOT(export_view()));
60 QObject::connect(action,SIGNAL(triggered()),_self,SLOT(export_view()));
61 }
61 }
@@ -104,15 +104,11 void CassiniTools::plot_TAB_File(const Q
104 plotFile(fileName);
104 plotFile(fileName);
105 }
105 }
106
106
107 void CassiniTools::export_view()
107 void CassiniTools::export_view(int PID)
108 {
109 SocExplorerPlot* plot = QLopPlots::getPlot(m_defaultPlot);
110 if(plot==NULL)
111 {
108 {
112 makePlot();
109 SocExplorerPlot* plot = QLopPlots::getPlot(PID);
113 plot = QLopPlots::getPlot(m_defaultPlot);
110 if(plot==NULL)
114 }
111 return;
115 if(plot)
116 {
112 {
117 QString fileName = QFileDialog::getSaveFileName();
113 QString fileName = QFileDialog::getSaveFileName();
118 }
114 }
@@ -31,7 +31,7 public:
31 static void plotFile(const QString &File);
31 static void plotFile(const QString &File);
32 public slots:
32 public slots:
33 void plot_TAB_File(const QString& fileName);
33 void plot_TAB_File(const QString& fileName);
34 void export_view();
34 void export_view(int PID);
35 private slots:
35 private slots:
36 void dataReady(QLopDataList data);
36 void dataReady(QLopDataList data);
37 };
37 };
@@ -2,7 +2,6
2 #define CASSINITOOLSGUI_H
2 #define CASSINITOOLSGUI_H
3
3
4 #include <QWidget>
4 #include <QWidget>
5 #include <folderview.h>
6 #include <filebrowser.h>
5 #include <filebrowser.h>
7
6
8 namespace Ui {
7 namespace Ui {
@@ -79,6 +79,7 int QLopPlots::addPlot()
79 if(pid!=-1)
79 if(pid!=-1)
80 {
80 {
81 SocExplorerPlot* plot=new SocExplorerPlot();
81 SocExplorerPlot* plot=new SocExplorerPlot();
82 plot->setPID(pid);
82 m_plots->insert(pid,plot);
83 m_plots->insert(pid,plot);
83 QDockWidget* dock = new QDockWidget();
84 QDockWidget* dock = new QDockWidget();
84 dock->setWidget(plot);
85 dock->setWidget(plot);
@@ -4629,7 +4629,7 void PythonQtWrapper_QCPGraph::setErrorP
4629
4629
4630 void PythonQtWrapper_QCPGraph::setUseFastVectors(QCPGraph* theWrappedObject, bool useFastVectors)
4630 void PythonQtWrapper_QCPGraph::setUseFastVectors(QCPGraph* theWrappedObject, bool useFastVectors)
4631 {
4631 {
4632 ( theWrappedObject->setUseFastVectors(useFastVectors));
4632 // ( theWrappedObject->setUseFastVectors(useFastVectors));
4633 }
4633 }
4634
4634
4635 QPointF PythonQtWrapper_QCPGraph::upperFillBasePoint(QCPGraph* theWrappedObject, double upperKey) const
4635 QPointF PythonQtWrapper_QCPGraph::upperFillBasePoint(QCPGraph* theWrappedObject, double upperKey) const
@@ -4639,7 +4639,7 QPointF PythonQtWrapper_QCPGraph::upper
4639
4639
4640 bool PythonQtWrapper_QCPGraph::useFastVectors(QCPGraph* theWrappedObject) const
4640 bool PythonQtWrapper_QCPGraph::useFastVectors(QCPGraph* theWrappedObject) const
4641 {
4641 {
4642 return ( theWrappedObject->useFastVectors());
4642 return true;//( theWrappedObject->useFastVectors());
4643 }
4643 }
4644
4644
4645
4645
This diff has been collapsed as it changes many lines, (507 lines changed) Show them Hide them
@@ -9369,7 +9369,6 void QCustomPlot::setMultiSelectModifier
9369 mMultiSelectModifier = modifier;
9369 mMultiSelectModifier = modifier;
9370 }
9370 }
9371
9371
9372
9373 /*!
9372 /*!
9374 Sets the viewport of this QCustomPlot. The Viewport is the area that the top level layout
9373 Sets the viewport of this QCustomPlot. The Viewport is the area that the top level layout
9375 (QCustomPlot::plotLayout()) uses as its rect. Normally, the viewport is the entire widget rect.
9374 (QCustomPlot::plotLayout()) uses as its rect. Normally, the viewport is the entire widget rect.
@@ -10685,13 +10684,6 void QCustomPlot::resizeEvent(QResizeEve
10685 mPaintBuffer = QPixmap(event->size());
10684 mPaintBuffer = QPixmap(event->size());
10686 setViewport(rect());
10685 setViewport(rect());
10687 replot(rpQueued); // queued update is important here, to prevent painting issues in some contexts
10686 replot(rpQueued); // queued update is important here, to prevent painting issues in some contexts
10688 // resize and repaint the buffer:
10689 // QSize pbSize = event->size();
10690 // pbSize *= devicePixelRatio();
10691 // mPaintBuffer = QPixmap(pbSize);
10692 // mPaintBuffer.setDevicePixelRatio(devicePixelRatio());
10693 // setViewport(rect());
10694 // replot(rpQueued); // queued update is important here, to prevent painting issues in some contexts
10695 }
10687 }
10696
10688
10697 /*! \internal
10689 /*! \internal
@@ -14510,7 +14502,7 QCPGraph::QCPGraph(QCPAxis *keyAxis, QCP
14510 QCPAbstractPlottable(keyAxis, valueAxis)
14502 QCPAbstractPlottable(keyAxis, valueAxis)
14511 {
14503 {
14512 mData = new QCPDataMap;
14504 mData = new QCPDataMap;
14513 mDataVector = new QVector<QCPData>();
14505
14514 setPen(QPen(Qt::blue, 0));
14506 setPen(QPen(Qt::blue, 0));
14515 setErrorPen(QPen(Qt::black));
14507 setErrorPen(QPen(Qt::black));
14516 setBrush(Qt::NoBrush);
14508 setBrush(Qt::NoBrush);
@@ -14523,13 +14515,11 QCPGraph::QCPGraph(QCPAxis *keyAxis, QCP
14523 setErrorBarSkipSymbol(true);
14515 setErrorBarSkipSymbol(true);
14524 setChannelFillGraph(0);
14516 setChannelFillGraph(0);
14525 setAdaptiveSampling(true);
14517 setAdaptiveSampling(true);
14526 setUseFastVectors(false);
14527 }
14518 }
14528
14519
14529 QCPGraph::~QCPGraph()
14520 QCPGraph::~QCPGraph()
14530 {
14521 {
14531 delete mData;
14522 delete mData;
14532 delete mDataVector;
14533 }
14523 }
14534
14524
14535 /*!
14525 /*!
@@ -14579,15 +14569,6 void QCPGraph::setData(const QVector<dou
14579 }
14569 }
14580 }
14570 }
14581
14571
14582 void QCPGraph::setData(QVector<QCPData> *data)
14583 {
14584 if(data!=mDataVector)
14585 {
14586 delete this->mDataVector;
14587 this->mDataVector = data;
14588 }
14589 }
14590
14591 /*!
14572 /*!
14592 Replaces the current data with the provided points in \a key and \a value pairs. Additionally the
14573 Replaces the current data with the provided points in \a key and \a value pairs. Additionally the
14593 symmetrical value error of the data points are set to the values in \a valueError.
14574 symmetrical value error of the data points are set to the values in \a valueError.
@@ -14888,11 +14869,6 void QCPGraph::setAdaptiveSampling(bool
14888 mAdaptiveSampling = enabled;
14869 mAdaptiveSampling = enabled;
14889 }
14870 }
14890
14871
14891 void QCPGraph::setUseFastVectors(bool useFastVectors)
14892 {
14893 mUseFastVectors=useFastVectors;
14894 }
14895
14896 /*!
14872 /*!
14897 Adds the provided data points in \a dataMap to the current data.
14873 Adds the provided data points in \a dataMap to the current data.
14898
14874
@@ -15119,7 +15095,9 void QCPGraph::rescaleValueAxis(bool onl
15119 void QCPGraph::draw(QCPPainter *painter)
15095 void QCPGraph::draw(QCPPainter *painter)
15120 {
15096 {
15121 if (!mKeyAxis || !mValueAxis) { qDebug() << Q_FUNC_INFO << "invalid key or value axis"; return; }
15097 if (!mKeyAxis || !mValueAxis) { qDebug() << Q_FUNC_INFO << "invalid key or value axis"; return; }
15122 if (mKeyAxis.data()->range().size() <= 0 || (mData->isEmpty() && mDataVector->isEmpty())) return;
15098 int test = mKeyAxis.data()->range().size();
15099 test = mData->count();
15100 if (mKeyAxis.data()->range().size() <= 0 || mData->isEmpty()) return;
15123 if (mLineStyle == lsNone && mScatterStyle.isNone()) return;
15101 if (mLineStyle == lsNone && mScatterStyle.isNone()) return;
15124
15102
15125 // allocate line and (if necessary) point vectors:
15103 // allocate line and (if necessary) point vectors:
@@ -15263,9 +15241,6 void QCPGraph::getLinePlotData(QVector<Q
15263 if (!linePixelData) { qDebug() << Q_FUNC_INFO << "null pointer passed as linePixelData"; return; }
15241 if (!linePixelData) { qDebug() << Q_FUNC_INFO << "null pointer passed as linePixelData"; return; }
15264
15242
15265 QVector<QCPData> lineData;
15243 QVector<QCPData> lineData;
15266 if(mUseFastVectors)
15267 getPreparedDataVector(&lineData, scatterData);
15268 else
15269 getPreparedData(&lineData, scatterData);
15244 getPreparedData(&lineData, scatterData);
15270 linePixelData->reserve(lineData.size()+2); // added 2 to reserve memory for lower/upper fill base points that might be needed for fill
15245 linePixelData->reserve(lineData.size()+2); // added 2 to reserve memory for lower/upper fill base points that might be needed for fill
15271 linePixelData->resize(lineData.size());
15246 linePixelData->resize(lineData.size());
@@ -15856,9 +15831,7 void QCPGraph::getPreparedData(QVector<Q
15856 {
15831 {
15857 QVector<QCPData> *dataVector = 0;
15832 QVector<QCPData> *dataVector = 0;
15858 if (lineData)
15833 if (lineData)
15859 {
15860 dataVector = lineData;
15834 dataVector = lineData;
15861 }
15862 else if (scatterData)
15835 else if (scatterData)
15863 dataVector = scatterData;
15836 dataVector = scatterData;
15864 if (dataVector)
15837 if (dataVector)
@@ -15877,190 +15850,6 void QCPGraph::getPreparedData(QVector<Q
15877 }
15850 }
15878 }
15851 }
15879
15852
15880
15881 void QCPGraph::getPreparedDataVector(QVector<QCPData> *lineData, QVector<QCPData> *scatterData) const
15882 {
15883 QCPAxis *keyAxis = mKeyAxis.data();
15884 QCPAxis *valueAxis = mValueAxis.data();
15885 if (!keyAxis || !valueAxis) { qDebug() << Q_FUNC_INFO << "invalid key or value axis"; return; }
15886 // get visible data range:
15887 QVector<QCPData>::const_iterator lower, upper; // note that upper is the actual upper point, and not 1 step after the upper point
15888 getVisibleDataBoundsVector(lower, upper);
15889 if (lower == mDataVector->constEnd() || upper == mDataVector->constEnd())
15890 return;
15891
15892 // count points in visible range, taking into account that we only need to count to the limit maxCount if using adaptive sampling:
15893 int maxCount = std::numeric_limits<int>::max();
15894 if (mAdaptiveSampling)
15895 {
15896 int keyPixelSpan = qAbs(keyAxis->coordToPixel((*lower).key)-keyAxis->coordToPixel((*upper).key));
15897 maxCount = 2*keyPixelSpan+2;
15898 }
15899 int dataCount = countDataInBoundsVector(lower, upper, maxCount);
15900
15901 if (mAdaptiveSampling && dataCount >= maxCount) // use adaptive sampling only if there are at least two points per pixel on average
15902 {
15903 if (lineData)
15904 {
15905 QVector<QCPData>::const_iterator it = lower;
15906 QVector<QCPData>::const_iterator upperEnd = upper+1;
15907 double minValue = (*it).value;
15908 double maxValue = (*it).value;
15909 QVector<QCPData>::const_iterator currentIntervalFirstPoint = it;
15910 int reversedFactor = keyAxis->rangeReversed() != (keyAxis->orientation()==Qt::Vertical) ? -1 : 1; // is used to calculate keyEpsilon pixel into the correct direction
15911 int reversedRound = keyAxis->rangeReversed() != (keyAxis->orientation()==Qt::Vertical) ? 1 : 0; // is used to switch between floor (normal) and ceil (reversed) rounding of currentIntervalStartKey
15912 double currentIntervalStartKey = keyAxis->pixelToCoord((int)(keyAxis->coordToPixel((*lower).key)+reversedRound));
15913 double lastIntervalEndKey = currentIntervalStartKey;
15914 double keyEpsilon = qAbs(currentIntervalStartKey-keyAxis->pixelToCoord(keyAxis->coordToPixel(currentIntervalStartKey)+1.0*reversedFactor)); // interval of one pixel on screen when mapped to plot key coordinates
15915 bool keyEpsilonVariable = keyAxis->scaleType() == QCPAxis::stLogarithmic; // indicates whether keyEpsilon needs to be updated after every interval (for log axes)
15916 int intervalDataCount = 1;
15917 ++it; // advance iterator to second data point because adaptive sampling works in 1 point retrospect
15918 while (it != upperEnd)
15919 {
15920 if ((*it).key < currentIntervalStartKey+keyEpsilon) // data point is still within same pixel, so skip it and expand value span of this cluster if necessary
15921 {
15922 if ((*it).value < minValue)
15923 minValue = (*it).value;
15924 else if ((*it).value > maxValue)
15925 maxValue = (*it).value;
15926 ++intervalDataCount;
15927 } else // new pixel interval started
15928 {
15929 if (intervalDataCount >= 2) // last pixel had multiple data points, consolidate them to a cluster
15930 {
15931 if (lastIntervalEndKey < currentIntervalStartKey-keyEpsilon) // last point is further away, so first point of this cluster must be at a real data point
15932 lineData->append(QCPData(currentIntervalStartKey+keyEpsilon*0.2, (*currentIntervalFirstPoint).value));
15933 lineData->append(QCPData(currentIntervalStartKey+keyEpsilon*0.25, minValue));
15934 lineData->append(QCPData(currentIntervalStartKey+keyEpsilon*0.75, maxValue));
15935 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
15936 lineData->append(QCPData(currentIntervalStartKey+keyEpsilon*0.8, (*(it-1)).value));
15937 } else
15938 lineData->append(QCPData((*currentIntervalFirstPoint).key, (*currentIntervalFirstPoint).value));
15939 lastIntervalEndKey = (*(it-1)).key;
15940 minValue = (*it).value;
15941 maxValue = (*it).value;
15942 currentIntervalFirstPoint = it;
15943 currentIntervalStartKey = keyAxis->pixelToCoord((int)(keyAxis->coordToPixel((*it).key)+reversedRound));
15944 if (keyEpsilonVariable)
15945 keyEpsilon = qAbs(currentIntervalStartKey-keyAxis->pixelToCoord(keyAxis->coordToPixel(currentIntervalStartKey)+1.0*reversedFactor));
15946 intervalDataCount = 1;
15947 }
15948 ++it;
15949 }
15950 // handle last interval:
15951 if (intervalDataCount >= 2) // last pixel had multiple data points, consolidate them to a cluster
15952 {
15953 if (lastIntervalEndKey < currentIntervalStartKey-keyEpsilon) // last point wasn't a cluster, so first point of this cluster must be at a real data point
15954 lineData->append(QCPData(currentIntervalStartKey+keyEpsilon*0.2, (*currentIntervalFirstPoint).value));
15955 lineData->append(QCPData(currentIntervalStartKey+keyEpsilon*0.25, minValue));
15956 lineData->append(QCPData(currentIntervalStartKey+keyEpsilon*0.75, maxValue));
15957 } else
15958 lineData->append(QCPData((*currentIntervalFirstPoint).key, (*currentIntervalFirstPoint).value));
15959 }
15960
15961 if (scatterData)
15962 {
15963 double valueMaxRange = valueAxis->range().upper;
15964 double valueMinRange = valueAxis->range().lower;
15965 QVector<QCPData>::const_iterator it = lower;
15966 QVector<QCPData>::const_iterator upperEnd = upper+1;
15967 double minValue = (*it).value;
15968 double maxValue = (*it).value;
15969 QVector<QCPData>::const_iterator minValueIt = it;
15970 QVector<QCPData>::const_iterator maxValueIt = it;
15971 QVector<QCPData>::const_iterator currentIntervalStart = it;
15972 int reversedFactor = keyAxis->rangeReversed() ? -1 : 1; // is used to calculate keyEpsilon pixel into the correct direction
15973 int reversedRound = keyAxis->rangeReversed() ? 1 : 0; // is used to switch between floor (normal) and ceil (reversed) rounding of currentIntervalStartKey
15974 double currentIntervalStartKey = keyAxis->pixelToCoord((int)(keyAxis->coordToPixel((*lower).key)+reversedRound));
15975 double keyEpsilon = qAbs(currentIntervalStartKey-keyAxis->pixelToCoord(keyAxis->coordToPixel(currentIntervalStartKey)+1.0*reversedFactor)); // interval of one pixel on screen when mapped to plot key coordinates
15976 bool keyEpsilonVariable = keyAxis->scaleType() == QCPAxis::stLogarithmic; // indicates whether keyEpsilon needs to be updated after every interval (for log axes)
15977 int intervalDataCount = 1;
15978 ++it; // advance iterator to second data point because adaptive sampling works in 1 point retrospect
15979 while (it != upperEnd)
15980 {
15981 if ((*it).key < currentIntervalStartKey+keyEpsilon) // data point is still within same pixel, so skip it and expand value span of this pixel if necessary
15982 {
15983 if ((*it).value < minValue && (*it).value > valueMinRange && (*it).value < valueMaxRange)
15984 {
15985 minValue = (*it).value;
15986 minValueIt = it;
15987 } else if ((*it).value > maxValue && (*it).value > valueMinRange && (*it).value < valueMaxRange)
15988 {
15989 maxValue = (*it).value;
15990 maxValueIt = it;
15991 }
15992 ++intervalDataCount;
15993 } else // new pixel started
15994 {
15995 if (intervalDataCount >= 2) // last pixel had multiple data points, consolidate them
15996 {
15997 // determine value pixel span and add as many points in interval to maintain certain vertical data density (this is specific to scatter plot):
15998 double valuePixelSpan = qAbs(valueAxis->coordToPixel(minValue)-valueAxis->coordToPixel(maxValue));
15999 int dataModulo = qMax(1, qRound(intervalDataCount/(valuePixelSpan/4.0))); // approximately every 4 value pixels one data point on average
16000 QVector<QCPData>::const_iterator intervalIt = currentIntervalStart;
16001 int c = 0;
16002 while (intervalIt != it)
16003 {
16004 if ((c % dataModulo == 0 || intervalIt == minValueIt || intervalIt == maxValueIt) && (*intervalIt).value > valueMinRange && (*intervalIt).value < valueMaxRange)
16005 scatterData->append((*intervalIt));
16006 ++c;
16007 ++intervalIt;
16008 }
16009 } else if ((*currentIntervalStart).value > valueMinRange && (*currentIntervalStart).value < valueMaxRange)
16010 scatterData->append((*currentIntervalStart));
16011 minValue = (*it).value;
16012 maxValue = (*it).value;
16013 currentIntervalStart = it;
16014 currentIntervalStartKey = keyAxis->pixelToCoord((int)(keyAxis->coordToPixel((*it).key)+reversedRound));
16015 if (keyEpsilonVariable)
16016 keyEpsilon = qAbs(currentIntervalStartKey-keyAxis->pixelToCoord(keyAxis->coordToPixel(currentIntervalStartKey)+1.0*reversedFactor));
16017 intervalDataCount = 1;
16018 }
16019 ++it;
16020 }
16021 // handle last interval:
16022 if (intervalDataCount >= 2) // last pixel had multiple data points, consolidate them
16023 {
16024 // determine value pixel span and add as many points in interval to maintain certain vertical data density (this is specific to scatter plot):
16025 double valuePixelSpan = qAbs(valueAxis->coordToPixel(minValue)-valueAxis->coordToPixel(maxValue));
16026 int dataModulo = qMax(1, qRound(intervalDataCount/(valuePixelSpan/4.0))); // approximately every 4 value pixels one data point on average
16027 QVector<QCPData>::const_iterator intervalIt = currentIntervalStart;
16028 int c = 0;
16029 while (intervalIt != it)
16030 {
16031 if ((c % dataModulo == 0 || intervalIt == minValueIt || intervalIt == maxValueIt) && (*intervalIt).value > valueMinRange && (*intervalIt).value < valueMaxRange)
16032 scatterData->append((*intervalIt));
16033 ++c;
16034 ++intervalIt;
16035 }
16036 } else if ((*currentIntervalStart).value > valueMinRange && (*currentIntervalStart).value < valueMaxRange)
16037 scatterData->append(*currentIntervalStart);
16038 }
16039 } else // don't use adaptive sampling algorithm, transfer points one-to-one from the map into the output parameters
16040 {
16041 QVector<QCPData> *dataVector = 0;
16042 if (lineData)
16043 {
16044 dataVector = lineData;
16045 }
16046 else if (scatterData)
16047 dataVector = scatterData;
16048 if (dataVector)
16049 {
16050 QVector<QCPData>::const_iterator it = lower;
16051 QVector<QCPData>::const_iterator upperEnd = upper+1;
16052 dataVector->reserve(dataCount+2); // +2 for possible fill end points
16053 while (it != upperEnd)
16054 {
16055 dataVector->append(*it);
16056 ++it;
16057 }
16058 }
16059 if (lineData && scatterData)
16060 *scatterData = *dataVector;
16061 }
16062 }
16063
16064 /*! \internal
15853 /*! \internal
16065
15854
16066 called by the scatter drawing function (\ref drawScatterPlot) to draw the error bars on one data
15855 called by the scatter drawing function (\ref drawScatterPlot) to draw the error bars on one data
@@ -16199,77 +15988,6 void QCPGraph::getVisibleDataBounds(QCPD
16199 upper = (highoutlier ? ubound : ubound-1); // data point range that will be actually drawn
15988 upper = (highoutlier ? ubound : ubound-1); // data point range that will be actually drawn
16200 }
15989 }
16201
15990
16202
16203
16204
16205 QVector<QCPData>::const_iterator __lowerBoundDico(QVector<QCPData>* vector,double key)
16206 {
16207 int DX=vector->size()/2;
16208 int pos=DX;
16209 double test=(*vector)[vector->length()-1].key;
16210 if(key>((*vector)[vector->length()-1].key))
16211 return vector->constEnd();
16212 if(key<((*vector)[0].key))
16213 return vector->constBegin();
16214 while (DX>1)
16215 {
16216 DX=DX/2;
16217 if((*vector)[pos].key > key)
16218 {
16219 pos-=DX;
16220 }
16221 else
16222 {
16223 pos+=DX;
16224 }
16225 }
16226 if((*vector)[pos].key >= key)
16227 return vector->constBegin()+pos;
16228 return vector->constBegin()+pos+1;
16229 }
16230
16231
16232 QVector<QCPData>::const_iterator __upperBoundDico(QVector<QCPData>* vector,double key)
16233 {
16234 int DX=vector->size()/2;
16235 int pos=DX;
16236 if(key>((*vector)[vector->length()-1].key))
16237 return vector->constEnd();
16238 if(key<((*vector)[0].key))
16239 return vector->constBegin();
16240 while (DX>1)
16241 {
16242 DX=DX/2;
16243 if((*vector)[pos].key > key)
16244 {
16245 pos-=DX;
16246 }
16247 else
16248 {
16249 pos+=DX;
16250 }
16251 }
16252 return vector->constBegin()+pos+1;
16253 }
16254
16255 void QCPGraph::getVisibleDataBoundsVector(QVector<QCPData>::const_iterator &lower, QVector<QCPData>::const_iterator &upper) const
16256 {
16257 if (!mKeyAxis) { qDebug() << Q_FUNC_INFO << "invalid key axis"; return; }
16258 if (mDataVector->isEmpty())
16259 {
16260 lower = mDataVector->constEnd();
16261 upper = mDataVector->constEnd();
16262 return;
16263 }
16264 QVector<QCPData>::const_iterator lbound = __lowerBoundDico(mDataVector,mKeyAxis.data()->range().lower);
16265 QVector<QCPData>::const_iterator ubound = __upperBoundDico(mDataVector,mKeyAxis.data()->range().upper);
16266 bool lowoutlier = lbound != mDataVector->constBegin(); // indicates whether there exist points below axis range
16267 bool highoutlier = ubound != mDataVector->constEnd(); // indicates whether there exist points above axis range
16268
16269 lower = (lowoutlier ? lbound-1 : lbound); // data point range that will be actually drawn
16270 upper = (highoutlier ? ubound : ubound-1); // data point range that will be actually drawn
16271 }
16272
16273 /*! \internal
15991 /*! \internal
16274
15992
16275 Counts the number of data points between \a lower and \a upper (including them), up to a maximum
15993 Counts the number of data points between \a lower and \a upper (including them), up to a maximum
@@ -16294,20 +16012,6 int QCPGraph::countDataInBounds(const QC
16294 return count;
16012 return count;
16295 }
16013 }
16296
16014
16297 int QCPGraph::countDataInBoundsVector(const QVector<QCPData>::const_iterator &lower, const QVector<QCPData>::const_iterator &upper, int maxCount) const
16298 {
16299 if (upper == mDataVector->constEnd() && lower == mDataVector->constEnd())
16300 return 0;
16301 QVector<QCPData>::const_iterator it = lower;
16302 int count = 1;
16303 while (it != upper && count < maxCount)
16304 {
16305 ++it;
16306 ++count;
16307 }
16308 return count;
16309 }
16310
16311 /*! \internal
16015 /*! \internal
16312
16016
16313 The line data vector generated by e.g. getLinePlotData contains only the line that connects the
16017 The line data vector generated by e.g. getLinePlotData contains only the line that connects the
@@ -16793,8 +16497,6 QCPRange QCPGraph::getKeyRange(bool &fou
16793 {
16497 {
16794 // just call the specialized version which takes an additional argument whether error bars
16498 // just call the specialized version which takes an additional argument whether error bars
16795 // should also be taken into consideration for range calculation. We set this to true here.
16499 // should also be taken into consideration for range calculation. We set this to true here.
16796 if(mUseFastVectors)
16797 return getKeyRangeVector(foundRange, inSignDomain, true);
16798 return getKeyRange(foundRange, inSignDomain, true);
16500 return getKeyRange(foundRange, inSignDomain, true);
16799 }
16501 }
16800
16502
@@ -16803,8 +16505,6 QCPRange QCPGraph::getValueRange(bool &f
16803 {
16505 {
16804 // just call the specialized version which takes an additional argument whether error bars
16506 // just call the specialized version which takes an additional argument whether error bars
16805 // should also be taken into consideration for range calculation. We set this to true here.
16507 // should also be taken into consideration for range calculation. We set this to true here.
16806 if(mUseFastVectors)
16807 return getValueRangeVector(foundRange, inSignDomain, true);
16808 return getValueRange(foundRange, inSignDomain, true);
16508 return getValueRange(foundRange, inSignDomain, true);
16809 }
16509 }
16810
16510
@@ -16914,106 +16614,6 QCPRange QCPGraph::getKeyRange(bool &fou
16914 return range;
16614 return range;
16915 }
16615 }
16916
16616
16917 QCPRange QCPGraph::getKeyRangeVector(bool &foundRange, SignDomain inSignDomain, bool includeErrors) const
16918 {
16919 QCPRange range;
16920 bool haveLower = false;
16921 bool haveUpper = false;
16922
16923 double current, currentErrorMinus, currentErrorPlus;
16924
16925 if (inSignDomain == sdBoth) // range may be anywhere
16926 {
16927 QVector<QCPData>::const_iterator it = mDataVector->constBegin();
16928 while (it != mDataVector->constEnd())
16929 {
16930 current = (*it).key;
16931 currentErrorMinus = (includeErrors ? (*it).keyErrorMinus : 0);
16932 currentErrorPlus = (includeErrors ? (*it).keyErrorPlus : 0);
16933 if (current-currentErrorMinus < range.lower || !haveLower)
16934 {
16935 range.lower = current-currentErrorMinus;
16936 haveLower = true;
16937 }
16938 if (current+currentErrorPlus > range.upper || !haveUpper)
16939 {
16940 range.upper = current+currentErrorPlus;
16941 haveUpper = true;
16942 }
16943 ++it;
16944 }
16945 } else if (inSignDomain == sdNegative) // range may only be in the negative sign domain
16946 {
16947 QVector<QCPData>::const_iterator it = mDataVector->constBegin();
16948 while (it != mDataVector->constEnd())
16949 {
16950 current = (*it).key;
16951 currentErrorMinus = (includeErrors ? (*it).keyErrorMinus : 0);
16952 currentErrorPlus = (includeErrors ? (*it).keyErrorPlus : 0);
16953 if ((current-currentErrorMinus < range.lower || !haveLower) && current-currentErrorMinus < 0)
16954 {
16955 range.lower = current-currentErrorMinus;
16956 haveLower = true;
16957 }
16958 if ((current+currentErrorPlus > range.upper || !haveUpper) && current+currentErrorPlus < 0)
16959 {
16960 range.upper = current+currentErrorPlus;
16961 haveUpper = true;
16962 }
16963 if (includeErrors) // in case point is in valid sign domain but errobars stretch beyond it, we still want to geht that point.
16964 {
16965 if ((current < range.lower || !haveLower) && current < 0)
16966 {
16967 range.lower = current;
16968 haveLower = true;
16969 }
16970 if ((current > range.upper || !haveUpper) && current < 0)
16971 {
16972 range.upper = current;
16973 haveUpper = true;
16974 }
16975 }
16976 ++it;
16977 }
16978 } else if (inSignDomain == sdPositive) // range may only be in the positive sign domain
16979 {
16980 QVector<QCPData>::const_iterator it = mDataVector->constBegin();
16981 while (it != mDataVector->constEnd())
16982 {
16983 current = (*it).key;
16984 currentErrorMinus = (includeErrors ? (*it).keyErrorMinus : 0);
16985 currentErrorPlus = (includeErrors ? (*it).keyErrorPlus : 0);
16986 if ((current-currentErrorMinus < range.lower || !haveLower) && current-currentErrorMinus > 0)
16987 {
16988 range.lower = current-currentErrorMinus;
16989 haveLower = true;
16990 }
16991 if ((current+currentErrorPlus > range.upper || !haveUpper) && current+currentErrorPlus > 0)
16992 {
16993 range.upper = current+currentErrorPlus;
16994 haveUpper = true;
16995 }
16996 if (includeErrors) // in case point is in valid sign domain but errobars stretch beyond it, we still want to get that point.
16997 {
16998 if ((current < range.lower || !haveLower) && current > 0)
16999 {
17000 range.lower = current;
17001 haveLower = true;
17002 }
17003 if ((current > range.upper || !haveUpper) && current > 0)
17004 {
17005 range.upper = current;
17006 haveUpper = true;
17007 }
17008 }
17009 ++it;
17010 }
17011 }
17012
17013 foundRange = haveLower && haveUpper;
17014 return range;
17015 }
17016
17017 /*! \overload
16617 /*! \overload
17018
16618
17019 Allows to specify whether the error bars should be included in the range calculation.
16619 Allows to specify whether the error bars should be included in the range calculation.
@@ -17120,105 +16720,6 QCPRange QCPGraph::getValueRange(bool &f
17120 return range;
16720 return range;
17121 }
16721 }
17122
16722
17123 QCPRange QCPGraph::getValueRangeVector(bool &foundRange, SignDomain inSignDomain, bool includeErrors) const
17124 {
17125 QCPRange range;
17126 bool haveLower = false;
17127 bool haveUpper = false;
17128
17129 double current, currentErrorMinus, currentErrorPlus;
17130
17131 if (inSignDomain == sdBoth) // range may be anywhere
17132 {
17133 QVector<QCPData>::const_iterator it = mDataVector->constBegin();
17134 while (it != mDataVector->constEnd())
17135 {
17136 current = (*it).value;
17137 currentErrorMinus = (includeErrors ? (*it).valueErrorMinus : 0);
17138 currentErrorPlus = (includeErrors ? (*it).valueErrorPlus : 0);
17139 if (current-currentErrorMinus < range.lower || !haveLower)
17140 {
17141 range.lower = current-currentErrorMinus;
17142 haveLower = true;
17143 }
17144 if (current+currentErrorPlus > range.upper || !haveUpper)
17145 {
17146 range.upper = current+currentErrorPlus;
17147 haveUpper = true;
17148 }
17149 ++it;
17150 }
17151 } else if (inSignDomain == sdNegative) // range may only be in the negative sign domain
17152 {
17153 QVector<QCPData>::const_iterator it = mDataVector->constBegin();
17154 while (it != mDataVector->constEnd())
17155 {
17156 current = (*it).value;
17157 currentErrorMinus = (includeErrors ? (*it).valueErrorMinus : 0);
17158 currentErrorPlus = (includeErrors ? (*it).valueErrorPlus : 0);
17159 if ((current-currentErrorMinus < range.lower || !haveLower) && current-currentErrorMinus < 0)
17160 {
17161 range.lower = current-currentErrorMinus;
17162 haveLower = true;
17163 }
17164 if ((current+currentErrorPlus > range.upper || !haveUpper) && current+currentErrorPlus < 0)
17165 {
17166 range.upper = current+currentErrorPlus;
17167 haveUpper = true;
17168 }
17169 if (includeErrors) // in case point is in valid sign domain but errobars stretch beyond it, we still want to get that point.
17170 {
17171 if ((current < range.lower || !haveLower) && current < 0)
17172 {
17173 range.lower = current;
17174 haveLower = true;
17175 }
17176 if ((current > range.upper || !haveUpper) && current < 0)
17177 {
17178 range.upper = current;
17179 haveUpper = true;
17180 }
17181 }
17182 ++it;
17183 }
17184 } else if (inSignDomain == sdPositive) // range may only be in the positive sign domain
17185 {
17186 QVector<QCPData>::const_iterator it = mDataVector->constBegin();
17187 while (it != mDataVector->constEnd())
17188 {
17189 current = (*it).value;
17190 currentErrorMinus = (includeErrors ? (*it).valueErrorMinus : 0);
17191 currentErrorPlus = (includeErrors ? (*it).valueErrorPlus : 0);
17192 if ((current-currentErrorMinus < range.lower || !haveLower) && current-currentErrorMinus > 0)
17193 {
17194 range.lower = current-currentErrorMinus;
17195 haveLower = true;
17196 }
17197 if ((current+currentErrorPlus > range.upper || !haveUpper) && current+currentErrorPlus > 0)
17198 {
17199 range.upper = current+currentErrorPlus;
17200 haveUpper = true;
17201 }
17202 if (includeErrors) // in case point is in valid sign domain but errobars stretch beyond it, we still want to geht that point.
17203 {
17204 if ((current < range.lower || !haveLower) && current > 0)
17205 {
17206 range.lower = current;
17207 haveLower = true;
17208 }
17209 if ((current > range.upper || !haveUpper) && current > 0)
17210 {
17211 range.upper = current;
17212 haveUpper = true;
17213 }
17214 }
17215 ++it;
17216 }
17217 }
17218
17219 foundRange = haveLower && haveUpper;
17220 return range;
17221 }
17222
16723
17223 ////////////////////////////////////////////////////////////////////////////////////////////////////
16724 ////////////////////////////////////////////////////////////////////////////////////////////////////
17224 //////////////////// QCPCurveData
16725 //////////////////// QCPCurveData
@@ -1862,7 +1862,6 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;
1866
1865
1867 // non-property members:
1866 // non-property members:
1868 QPixmap mPaintBuffer;
1867 QPixmap mPaintBuffer;
@@ -2539,12 +2538,10 public:
2539 bool errorBarSkipSymbol() const { return mErrorBarSkipSymbol; }
2538 bool errorBarSkipSymbol() const { return mErrorBarSkipSymbol; }
2540 QCPGraph *channelFillGraph() const { return mChannelFillGraph.data(); }
2539 QCPGraph *channelFillGraph() const { return mChannelFillGraph.data(); }
2541 bool adaptiveSampling() const { return mAdaptiveSampling; }
2540 bool adaptiveSampling() const { return mAdaptiveSampling; }
2542 bool useFastVectors() const { return mUseFastVectors; }
2543
2541
2544 // setters:
2542 // setters:
2545 void setData(QCPDataMap *data, bool copy=false);
2543 void setData(QCPDataMap *data, bool copy=false);
2546 void setData(const QVector<double> &key, const QVector<double> &value);
2544 void setData(const QVector<double> &key, const QVector<double> &value);
2547 void setData(QVector<QCPData> *data);
2548 void setDataKeyError(const QVector<double> &key, const QVector<double> &value, const QVector<double> &keyError);
2545 void setDataKeyError(const QVector<double> &key, const QVector<double> &value, const QVector<double> &keyError);
2549 void setDataKeyError(const QVector<double> &key, const QVector<double> &value, const QVector<double> &keyErrorMinus, const QVector<double> &keyErrorPlus);
2546 void setDataKeyError(const QVector<double> &key, const QVector<double> &value, const QVector<double> &keyErrorMinus, const QVector<double> &keyErrorPlus);
2550 void setDataValueError(const QVector<double> &key, const QVector<double> &value, const QVector<double> &valueError);
2547 void setDataValueError(const QVector<double> &key, const QVector<double> &value, const QVector<double> &valueError);
@@ -2559,7 +2556,6 public:
2559 void setErrorBarSkipSymbol(bool enabled);
2556 void setErrorBarSkipSymbol(bool enabled);
2560 void setChannelFillGraph(QCPGraph *targetGraph);
2557 void setChannelFillGraph(QCPGraph *targetGraph);
2561 void setAdaptiveSampling(bool enabled);
2558 void setAdaptiveSampling(bool enabled);
2562 void setUseFastVectors(bool useFastVectors);
2563
2559
2564 // non-property methods:
2560 // non-property methods:
2565 void addData(const QCPDataMap &dataMap);
2561 void addData(const QCPDataMap &dataMap);
@@ -2584,7 +2580,6 public:
2584 protected:
2580 protected:
2585 // property members:
2581 // property members:
2586 QCPDataMap *mData;
2582 QCPDataMap *mData;
2587 QVector<QCPData>* mDataVector;
2588 QPen mErrorPen;
2583 QPen mErrorPen;
2589 LineStyle mLineStyle;
2584 LineStyle mLineStyle;
2590 QCPScatterStyle mScatterStyle;
2585 QCPScatterStyle mScatterStyle;
@@ -2593,7 +2588,6 protected:
2593 bool mErrorBarSkipSymbol;
2588 bool mErrorBarSkipSymbol;
2594 QPointer<QCPGraph> mChannelFillGraph;
2589 QPointer<QCPGraph> mChannelFillGraph;
2595 bool mAdaptiveSampling;
2590 bool mAdaptiveSampling;
2596 bool mUseFastVectors;
2597
2591
2598 // reimplemented virtual methods:
2592 // reimplemented virtual methods:
2599 virtual void draw(QCPPainter *painter);
2593 virtual void draw(QCPPainter *painter);
@@ -2601,9 +2595,8 protected:
2601 virtual QCPRange getKeyRange(bool &foundRange, SignDomain inSignDomain=sdBoth) const;
2595 virtual QCPRange getKeyRange(bool &foundRange, SignDomain inSignDomain=sdBoth) const;
2602 virtual QCPRange getValueRange(bool &foundRange, SignDomain inSignDomain=sdBoth) const;
2596 virtual QCPRange getValueRange(bool &foundRange, SignDomain inSignDomain=sdBoth) const;
2603 virtual QCPRange getKeyRange(bool &foundRange, SignDomain inSignDomain, bool includeErrors) const; // overloads base class interface
2597 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
2605 virtual QCPRange getValueRange(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
2606 virtual QCPRange getValueRangeVector(bool &foundRange, SignDomain inSignDomain, bool includeErrors) const;
2599
2607 // introduced virtual methods:
2600 // introduced virtual methods:
2608 virtual void drawFill(QCPPainter *painter, QVector<QPointF> *lineData) const;
2601 virtual void drawFill(QCPPainter *painter, QVector<QPointF> *lineData) const;
2609 virtual void drawScatterPlot(QCPPainter *painter, QVector<QCPData> *scatterData) const;
2602 virtual void drawScatterPlot(QCPPainter *painter, QVector<QCPData> *scatterData) const;
@@ -2612,7 +2605,6 protected:
2612
2605
2613 // non-virtual methods:
2606 // non-virtual methods:
2614 void getPreparedData(QVector<QCPData> *lineData, QVector<QCPData> *scatterData) const;
2607 void getPreparedData(QVector<QCPData> *lineData, QVector<QCPData> *scatterData) const;
2615 void getPreparedDataVector(QVector<QCPData> *lineData, QVector<QCPData> *scatterData) const;
2616 void getPlotData(QVector<QPointF> *lineData, QVector<QCPData> *scatterData) const;
2608 void getPlotData(QVector<QPointF> *lineData, QVector<QCPData> *scatterData) const;
2617 void getScatterPlotData(QVector<QCPData> *scatterData) const;
2609 void getScatterPlotData(QVector<QCPData> *scatterData) const;
2618 void getLinePlotData(QVector<QPointF> *linePixelData, QVector<QCPData> *scatterData) const;
2610 void getLinePlotData(QVector<QPointF> *linePixelData, QVector<QCPData> *scatterData) const;
@@ -2622,9 +2614,7 protected:
2622 void getImpulsePlotData(QVector<QPointF> *linePixelData, QVector<QCPData> *scatterData) const;
2614 void getImpulsePlotData(QVector<QPointF> *linePixelData, QVector<QCPData> *scatterData) const;
2623 void drawError(QCPPainter *painter, double x, double y, const QCPData &data) const;
2615 void drawError(QCPPainter *painter, double x, double y, const QCPData &data) const;
2624 void getVisibleDataBounds(QCPDataMap::const_iterator &lower, QCPDataMap::const_iterator &upper) const;
2616 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;
2626 int countDataInBounds(const QCPDataMap::const_iterator &lower, const QCPDataMap::const_iterator &upper, int maxCount) const;
2617 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;
2628 void addFillBasePoints(QVector<QPointF> *lineData) const;
2618 void addFillBasePoints(QVector<QPointF> *lineData) const;
2629 void removeFillBasePoints(QVector<QPointF> *lineData) const;
2619 void removeFillBasePoints(QVector<QPointF> *lineData) const;
2630 QPointF lowerFillBasePoint(double lowerKey) const;
2620 QPointF lowerFillBasePoint(double lowerKey) const;
@@ -28,7 +28,7
28 SocExplorerPlot::SocExplorerPlot(QWidget *parent) :
28 SocExplorerPlot::SocExplorerPlot(QWidget *parent) :
29 QWidget(parent), mRubberBand(new QRubberBand(QRubberBand::Rectangle, this))
29 QWidget(parent), mRubberBand(new QRubberBand(QRubberBand::Rectangle, this))
30 {
30 {
31 this->m_plot = new QCustomPlot(this);
31 this->m_plot = new QCustomPlotVect(this);
32 this->m_plot->setInteractions(QCP::iRangeDrag | QCP::iSelectAxes |
32 this->m_plot->setInteractions(QCP::iRangeDrag | QCP::iSelectAxes |
33 QCP::iSelectLegend | QCP::iSelectPlottables);
33 QCP::iSelectLegend | QCP::iSelectPlottables);
34 this->m_plot->axisRect()->setRangeDrag(Qt::Horizontal|Qt::Vertical);
34 this->m_plot->axisRect()->setRangeDrag(Qt::Horizontal|Qt::Vertical);
@@ -85,6 +85,18 void SocExplorerPlot::exportToPDF(const
85 qcpPainter.end();
85 qcpPainter.end();
86 }
86 }
87
87
88 void SocExplorerPlot::addAction(SocExplorerPlotActions *action)
89 {
90 this->m_actions.append(action);
91 QWidget::addAction((QAction*)action);
92 }
93
94 QVector<QCPData> *SocExplorerPlot::getVisibleData(int graphIndex)
95 {
96 QVector<QCPData> *wholeData=((QCPGraphVect*)m_plot->graph(graphIndex))->data();
97 // m_plot->xAxis->
98 }
99
88 void SocExplorerPlot::setTitle(QString title)
100 void SocExplorerPlot::setTitle(QString title)
89 {
101 {
90 Q_UNUSED(title)
102 Q_UNUSED(title)
@@ -144,7 +156,8 void SocExplorerPlot::setAdaptativeSampl
144
156
145 void SocExplorerPlot::setUseFastVector(int graphIndex, bool enable)
157 void SocExplorerPlot::setUseFastVector(int graphIndex, bool enable)
146 {
158 {
147 this->m_plot->graph(graphIndex)->setUseFastVectors(enable);
159 // TODO deprecated
160 // this->m_plot->graph(graphIndex)->setUseFastVectors(enable);
148 }
161 }
149
162
150 int SocExplorerPlot::addGraph()
163 int SocExplorerPlot::addGraph()
@@ -158,6 +171,11 bool SocExplorerPlot::removeGraph(int gr
158 return this->m_plot->removeGraph(graphIndex);
171 return this->m_plot->removeGraph(graphIndex);
159 }
172 }
160
173
174 int SocExplorerPlot::graphCount()
175 {
176 return m_plot->graphCount();
177 }
178
161 void SocExplorerPlot::removeAllGraphs()
179 void SocExplorerPlot::removeAllGraphs()
162 {
180 {
163 int graphCount=this->m_plot->graphCount();
181 int graphCount=this->m_plot->graphCount();
@@ -226,7 +244,7 void SocExplorerPlot::setGraphData(int g
226 {
244 {
227 if((graphIndex<this->m_plot->graphCount()))// && (x.at(0).type()==QVariant::Double))
245 if((graphIndex<this->m_plot->graphCount()))// && (x.at(0).type()==QVariant::Double))
228 {
246 {
229 this->m_plot->graph(graphIndex)->setData(data);
247 ((QCPGraphVect*)this->m_plot->graph(graphIndex))->setData(data);
230 }
248 }
231 if(replot)
249 if(replot)
232 this->m_plot->replot();
250 this->m_plot->replot();
@@ -25,9 +25,37
25 #include <QWidget>
25 #include <QWidget>
26 #include <QGridLayout>
26 #include <QGridLayout>
27 #include <qcustomplot.h>
27 #include <qcustomplot.h>
28 #include <qcustomplotvect.h>
28 #include <QRubberBand>
29 #include <QRubberBand>
29 #include <QPoint>
30 #include <QPoint>
30
31
32 class SocExplorerPlotActions : public QAction
33 {
34 Q_OBJECT
35 public:
36 SocExplorerPlotActions(const QString &text,int PID,QObject* parent=0)
37 :QAction(text,parent)
38 {
39 setPID(PID);
40 connect(this,SIGNAL(triggered()),this,SLOT(trigger()));
41 }
42 SocExplorerPlotActions(const QIcon &icon, const QString &text,int PID, QObject* parent)
43 :QAction(icon,text,parent)
44 {
45 setPID(PID);
46 connect(this,SIGNAL(triggered()),this,SLOT(trigger()));
47 }
48 ~SocExplorerPlotActions(){}
49 void setPID(int PID){this->m_PID=PID;}
50 int PID(){return m_PID;}
51 private slots:
52 void trigger(){emit triggered(m_PID);}
53 signals:
54 void triggered(int PID);
55 private:
56 int m_PID;
57 };
58
31 class SocExplorerPlot : public QWidget
59 class SocExplorerPlot : public QWidget
32 {
60 {
33 Q_OBJECT
61 Q_OBJECT
@@ -46,6 +74,7 public:
46 void setUseFastVector(int graphIndex,bool enable);
74 void setUseFastVector(int graphIndex,bool enable);
47 int addGraph();
75 int addGraph();
48 bool removeGraph(int graphIndex);
76 bool removeGraph(int graphIndex);
77 int graphCount();
49 void removeAllGraphs();
78 void removeAllGraphs();
50 void setGraphName(int graphIndex,QString name);
79 void setGraphName(int graphIndex,QString name);
51 void setGraphData(int graphIndex, QList<QVariant> x, QList<QVariant> y);
80 void setGraphData(int graphIndex, QList<QVariant> x, QList<QVariant> y);
@@ -63,6 +92,10 public:
63 void replot();
92 void replot();
64 void exportToSVG(const QString& fileName);
93 void exportToSVG(const QString& fileName);
65 void exportToPDF(const QString& fileName);
94 void exportToPDF(const QString& fileName);
95 void addAction(SocExplorerPlotActions* action);
96 int PID(){return m_PID;}
97 void setPID(int PID){m_PID = PID;}
98 QVector<QCPData>* getVisibleData(int graphIndex);
66 signals:
99 signals:
67 void titleChanged(const QString& newTitle);
100 void titleChanged(const QString& newTitle);
68 public slots:
101 public slots:
@@ -78,7 +111,7 protected:
78 private:
111 private:
79 void zoom(double factor, int center, Qt::Orientation orientation);
112 void zoom(double factor, int center, Qt::Orientation orientation);
80 void move(double factor, Qt::Orientation orientation);
113 void move(double factor, Qt::Orientation orientation);
81 QCustomPlot* m_plot;
114 QCustomPlotVect* m_plot;
82 QGridLayout* m_mainlayout;
115 QGridLayout* m_mainlayout;
83 bool ctrl_hold;
116 bool ctrl_hold;
84 bool shift_hold;
117 bool shift_hold;
@@ -89,6 +122,8 private:
89 bool mZoomMode;
122 bool mZoomMode;
90 QRubberBand * mRubberBand;
123 QRubberBand * mRubberBand;
91 QPoint mOrigin;
124 QPoint mOrigin;
125 QList<SocExplorerPlotActions*> m_actions;
126 int m_PID;
92 };
127 };
93
128
94 #endif // SOCEXPLORERPLOT_H
129 #endif // SOCEXPLORERPLOT_H
@@ -78,15 +78,15 MainWindow::~MainWindow()
78 delete ui;
78 delete ui;
79 }
79 }
80
80
81 QString MainWindow::getFilePath(const QString &name)
81 //QString MainWindow::getFilePath(const QString &name)
82 {
83 // for(int i=0;i<this->folderViews.count();i++)
84 // {
82 //{
85 // if(folderViews.at(i)->isDraging(name))
83 //// for(int i=0;i<this->folderViews.count();i++)
86 // return folderViews.at(i)->currentFolder();
84 //// {
85 //// if(folderViews.at(i)->isDraging(name))
86 //// return folderViews.at(i)->currentFolder();
87 //// }
88 // return "";
87 // }
89 //}
88 return "";
89 }
90
90
91
91
92
92
@@ -30,7 +30,6
30 #include <QListWidgetItem>
30 #include <QListWidgetItem>
31 #include <QVBoxLayout>
31 #include <QVBoxLayout>
32 #include <QWidget>
32 #include <QWidget>
33 #include "folderview.h"
34 #include "abstractfileloader.h"
33 #include "abstractfileloader.h"
35 #include "cassiniindexfileviewer.h"
34 #include "cassiniindexfileviewer.h"
36 #include <downloadhistory.h>
35 #include <downloadhistory.h>
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
1 NO CONTENT: file was removed
NO CONTENT: file was removed
General Comments 0
You need to be logged in to leave comments. Login now