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 |
|
|
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 |
|
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 |
|
|
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