##// END OF EJS Templates
plot view export works on cassini fgm data.
jeandet -
r8:c56bc5e5916b default
parent child
Show More
@@ -1,249 +1,302
1 /*------------------------------------------------------------------------------
1 /*------------------------------------------------------------------------------
2 -- This file is a part of the QLop Software
2 -- This file is a part of the QLop Software
3 -- Copyright (C) 2015, Plasma Physics Laboratory - CNRS
3 -- Copyright (C) 2015, Plasma Physics Laboratory - CNRS
4 --
4 --
5 -- This program is free software; you can redistribute it and/or modify
5 -- This program is free software; you can redistribute it and/or modify
6 -- it under the terms of the GNU General Public License as published by
6 -- it under the terms of the GNU General Public License as published by
7 -- the Free Software Foundation; either version 2 of the License, or
7 -- the Free Software Foundation; either version 2 of the License, or
8 -- (at your option) any later version.
8 -- (at your option) any later version.
9 --
9 --
10 -- This program is distributed in the hope that it will be useful,
10 -- This program is distributed in the hope that it will be useful,
11 -- but WITHOUT ANY WARRANTY; without even the implied warranty of
11 -- but WITHOUT ANY WARRANTY; without even the implied warranty of
12 -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 -- GNU General Public License for more details.
13 -- GNU General Public License for more details.
14 --
14 --
15 -- You should have received a copy of the GNU General Public License
15 -- You should have received a copy of the GNU General Public License
16 -- along with this program; if not, write to the Free Software
16 -- along with this program; if not, write to the Free Software
17 -- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17 -- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 -------------------------------------------------------------------------------*/
18 -------------------------------------------------------------------------------*/
19 /*-- Author : Alexis Jeandet
19 /*-- Author : Alexis Jeandet
20 -- Mail : alexis.jeandet@member.fsf.org
20 -- Mail : alexis.jeandet@member.fsf.org
21 ----------------------------------------------------------------------------*/
21 ----------------------------------------------------------------------------*/
22 #include "cassinidatafile.h"
22 #include "cassinidatafile.h"
23 #include <QFile>
23 #include <QFile>
24 #include <stdio.h>
24 #include <stdio.h>
25 #include <QDateTime>
25 #include <QDateTime>
26 #include <QVector>
26 #include <QVector>
27 #include <QProgressDialog>
27 #include <QProgressDialog>
28 #include <omp.h>
28 #include <omp.h>
29 #include <QTimer>
29 #include <QTimer>
30 #include <QElapsedTimer>
30 #include <QElapsedTimer>
31 #include <sys/time.h>
31 #include <sys/time.h>
32
32
33 CassiniDataFile::CassiniDataFile(QObject *parent) : AbstractFileLoader(parent)
33 CassiniDataFile::CassiniDataFile(QObject *parent) : AbstractFileLoader(parent)
34 {
34 {
35
35
36 }
36 }
37
37
38 CassiniDataFile::~CassiniDataFile()
38 CassiniDataFile::~CassiniDataFile()
39 {
39 {
40
40
41 }
41 }
42
42
43 void CassiniDataFile::parseFile(const QString &fileName)
43 void CassiniDataFile::parseFile(const QString &fileName)
44 {
44 {
45 this->fileName = fileName;
45 this->fileName = fileName;
46 this->start();
46 m_Write = false;
47 this->start();
48 }
49
50 void CassiniDataFile::saveFile(const QString &fileName, QLopDataList data)
51 {
52 this->fileName = fileName;
53 m_Write = true;
54 m_data = data;
55 this->start();
47 }
56 }
48
57
49 inline double __decodeVal(int ofset,unsigned char* data)
58 inline double __decodeVal(int ofset,unsigned char* data)
50 {
59 {
51 if(data[ofset]=='-')
60 if(data[ofset]=='-')
52 return -0.001 * (double)(
61 return -0.001 * (double)(
53 (10000 * (int)(data[ofset+1] & 0x0F))
62 (10000 * (int)(data[ofset+1] & 0x0F))
54 + (1000 * (int)(data[ofset+2] & 0x0F))
63 + (1000 * (int)(data[ofset+2] & 0x0F))
55 + (100 * (int)(data[ofset+4] & 0x0F))
64 + (100 * (int)(data[ofset+4] & 0x0F))
56 + (10 * (int)(data[ofset+5] & 0x0F))
65 + (10 * (int)(data[ofset+5] & 0x0F))
57 + ( (int)(data[ofset+6] & 0x0F))
66 + ( (int)(data[ofset+6] & 0x0F))
58 );
67 );
59 else
68 else
60 {
69 {
61 if(data[ofset+1]=='-')
70 if(data[ofset+1]=='-')
62 {
71 {
63 return -0.001 * (double)(
72 return -0.001 * (double)(
64 (1000 * (int)(data[ofset+2] & 0x0F))
73 (1000 * (int)(data[ofset+2] & 0x0F))
65 + (100 * (int)(data[ofset+4] & 0x0F))
74 + (100 * (int)(data[ofset+4] & 0x0F))
66 + (10 * (int)(data[ofset+5] & 0x0F))
75 + (10 * (int)(data[ofset+5] & 0x0F))
67 + ( (int)(data[ofset+6] & 0x0F))
76 + ( (int)(data[ofset+6] & 0x0F))
68 );
77 );
69 }
78 }
70 else
79 else
71 {
80 {
72 return 0.001 * (double)(
81 return 0.001 * (double)(
73 (10000 * (int)(data[ofset+1] & 0x0F))
82 (10000 * (int)(data[ofset+1] & 0x0F))
74 + (1000 * (int)(data[ofset+2] & 0x0F))
83 + (1000 * (int)(data[ofset+2] & 0x0F))
75 + (100 * (int)(data[ofset+4] & 0x0F))
84 + (100 * (int)(data[ofset+4] & 0x0F))
76 + (10 * (int)(data[ofset+5] & 0x0F))
85 + (10 * (int)(data[ofset+5] & 0x0F))
77 + ( (int)(data[ofset+6] & 0x0F))
86 + ( (int)(data[ofset+6] & 0x0F))
78 );
87 );
79 }
88 }
80 }
89 }
81 }
90 }
82
91
83 inline QDate __decodeDate(int ofset,unsigned char* data)
92 inline QDate __decodeDate(int ofset,unsigned char* data)
84 {
93 {
85 int y=(1000*(data[ofset] & 0x0F)) + (100*(data[ofset+1] & 0x0F)) + (10*(data[ofset+2] & 0x0F)) + (1*(data[ofset+3] & 0x0F));
94 int y=(1000*(data[ofset] & 0x0F)) + (100*(data[ofset+1] & 0x0F)) + (10*(data[ofset+2] & 0x0F)) + (1*(data[ofset+3] & 0x0F));
86 int m=(10*(data[ofset+5] & 0x0F)) + (1*(data[ofset+6] & 0x0F));
95 int m=(10*(data[ofset+5] & 0x0F)) + (1*(data[ofset+6] & 0x0F));
87 int d=(10*(data[ofset+8] & 0x0F)) + (1*(data[ofset+9] & 0x0F));
96 int d=(10*(data[ofset+8] & 0x0F)) + (1*(data[ofset+9] & 0x0F));
88 return QDate(y,m,d);
97 return QDate(y,m,d);
89 }
98 }
90
99
91 inline QTime __decodeTime(int ofset,unsigned char* data)
100 inline QTime __decodeTime(int ofset,unsigned char* data)
92 {
101 {
93 int h=(10*(data[ofset] & 0x0F)) + (1*(data[ofset+1] & 0x0F));
102 int h=(10*(data[ofset] & 0x0F)) + (1*(data[ofset+1] & 0x0F));
94 int m=(10*(data[ofset+3] & 0x0F)) + (1*(data[ofset+4] & 0x0F));
103 int m=(10*(data[ofset+3] & 0x0F)) + (1*(data[ofset+4] & 0x0F));
95 int s=(10*(data[ofset+6] & 0x0F)) + (1*(data[ofset+7] & 0x0F));
104 int s=(10*(data[ofset+6] & 0x0F)) + (1*(data[ofset+7] & 0x0F));
96 int ms=(100*(data[ofset+9] & 0x0F)) + (10*(data[ofset+10] & 0x0F)) + (1*(data[ofset+11] & 0x0F));
105 int ms=(100*(data[ofset+9] & 0x0F)) + (10*(data[ofset+10] & 0x0F)) + (1*(data[ofset+11] & 0x0F));
97 return QTime(h,m,s,ms);
106 return QTime(h,m,s,ms);
98 }
107 }
99
108
100 double __decodeTimeFromEpochMs(int ofset,unsigned char* data)
109 double __decodeTimeFromEpochMs(int ofset,unsigned char* data)
101 {
110 {
102 struct tm t;
111 struct tm t;
103 time_t t_of_day;
112 time_t t_of_day;
104 t.tm_year=(1000*(data[ofset] & 0x0F)) + (100*(data[ofset+1] & 0x0F)) + (10*(data[ofset+2] & 0x0F)) + ((data[ofset+3] & 0x0F)) -1900;
113 t.tm_year=(1000*(data[ofset] & 0x0F)) + (100*(data[ofset+1] & 0x0F)) + (10*(data[ofset+2] & 0x0F)) + ((data[ofset+3] & 0x0F)) -1900;
105 t.tm_mon=(10*(data[ofset+5] & 0x0F)) + ((data[ofset+6] & 0x0F));
114 t.tm_mon=(10*(data[ofset+5] & 0x0F)) + ((data[ofset+6] & 0x0F));
106 t.tm_mday=(10*(data[ofset+8] & 0x0F)) + ((data[ofset+9] & 0x0F));
115 t.tm_mday=(10*(data[ofset+8] & 0x0F)) + ((data[ofset+9] & 0x0F));
107 t.tm_hour=(10*(data[ofset+11] & 0x0F)) + ((data[ofset+12] & 0x0F));
116 t.tm_hour=(10*(data[ofset+11] & 0x0F)) + ((data[ofset+12] & 0x0F));
108 t.tm_min=(10*(data[ofset+14] & 0x0F)) + ((data[ofset+15] & 0x0F));
117 t.tm_min=(10*(data[ofset+14] & 0x0F)) + ((data[ofset+15] & 0x0F));
109 t.tm_sec=(10*(data[ofset+17] & 0x0F)) + ((data[ofset+18] & 0x0F));
118 t.tm_sec=(10*(data[ofset+17] & 0x0F)) + ((data[ofset+18] & 0x0F));
110 int ms=(100*(data[ofset+20] & 0x0F)) + (10*(data[ofset+21] & 0x0F)) + ((data[ofset+22] & 0x0F));
119 int ms=(100*(data[ofset+20] & 0x0F)) + (10*(data[ofset+21] & 0x0F)) + ((data[ofset+22] & 0x0F));
111 t_of_day = mktime(&t);
120 t_of_day = mktime(&t);
112 return (t_of_day*1000.0)+ms;
121 return (t_of_day*1000.0)+ms;
113 }
122 }
114
123
115 double __decodeTimeFromEpoch(int ofset,unsigned char* data)
124 double __decodeTimeFromEpoch(int ofset,unsigned char* data)
116 {
125 {
117 struct tm t;
126 struct tm t;
118 time_t t_of_day;
127 time_t t_of_day;
119 t.tm_year=(1000*(data[ofset] & 0x0F)) + (100*(data[ofset+1] & 0x0F)) + (10*(data[ofset+2] & 0x0F)) + ((data[ofset+3] & 0x0F)) -1900;
128 t.tm_year=(1000*(data[ofset] & 0x0F)) + (100*(data[ofset+1] & 0x0F)) + (10*(data[ofset+2] & 0x0F)) + ((data[ofset+3] & 0x0F)) -1900;
120 t.tm_mon=(10*(data[ofset+5] & 0x0F)) + ((data[ofset+6] & 0x0F));
129 t.tm_mon=(10*(data[ofset+5] & 0x0F)) + ((data[ofset+6] & 0x0F));
121 t.tm_mday=(10*(data[ofset+8] & 0x0F)) + ((data[ofset+9] & 0x0F));
130 t.tm_mday=(10*(data[ofset+8] & 0x0F)) + ((data[ofset+9] & 0x0F));
122 t.tm_hour=(10*(data[ofset+11] & 0x0F)) + ((data[ofset+12] & 0x0F));
131 t.tm_hour=(10*(data[ofset+11] & 0x0F)) + ((data[ofset+12] & 0x0F));
123 t.tm_min=(10*(data[ofset+14] & 0x0F)) + ((data[ofset+15] & 0x0F));
132 t.tm_min=(10*(data[ofset+14] & 0x0F)) + ((data[ofset+15] & 0x0F));
124 t.tm_sec=(10*(data[ofset+17] & 0x0F)) + ((data[ofset+18] & 0x0F));
133 t.tm_sec=(10*(data[ofset+17] & 0x0F)) + ((data[ofset+18] & 0x0F));
125 double ms=(100*(data[ofset+20] & 0x0F)) + (10*(data[ofset+21] & 0x0F)) + ((data[ofset+22] & 0x0F));
134 double ms=(100*(data[ofset+20] & 0x0F)) + (10*(data[ofset+21] & 0x0F)) + ((data[ofset+22] & 0x0F));
126 t_of_day = mktime(&t);
135 t_of_day = mktime(&t);
127 return (double)t_of_day+((double)ms*(double)0.001);
136 return (double)t_of_day+((double)ms*(double)0.001);
128 }
137 }
129
138
130 double __decodeTimeHMSmS(int ofset,unsigned char* data)
139 double __decodeTimeHMSmS(int ofset,unsigned char* data)
131 {
140 {
132 int h,m,s;
141 int h,m,s;
133 h=(10*(data[ofset+11] & 0x0F)) + ((data[ofset+12] & 0x0F));
142 h=(10*(data[ofset+11] & 0x0F)) + ((data[ofset+12] & 0x0F));
134 m=(10*(data[ofset+14] & 0x0F)) + ((data[ofset+15] & 0x0F));
143 m=(10*(data[ofset+14] & 0x0F)) + ((data[ofset+15] & 0x0F));
135 s=(10*(data[ofset+17] & 0x0F)) + ((data[ofset+18] & 0x0F));
144 s=(10*(data[ofset+17] & 0x0F)) + ((data[ofset+18] & 0x0F));
136 double ms=(100*(data[ofset+20] & 0x0F)) + (10*(data[ofset+21] & 0x0F)) + ((data[ofset+22] & 0x0F));
145 double ms=(100*(data[ofset+20] & 0x0F)) + (10*(data[ofset+21] & 0x0F)) + ((data[ofset+22] & 0x0F));
137 return (double)((h*3600)+(m*60)+s) + (ms*0.001);
146 return (double)((h*3600)+(m*60)+s) + (ms*0.001);
138 }
147 }
139
148
140 double __decodeTimeDHMSmS(int ofset,unsigned char* data)
149 double __decodeTimeDHMSmS(int ofset,unsigned char* data)
141 {
150 {
142 int d,h,m,s;
151 int d,h,m,s;
143 d=(10*(data[ofset+8] & 0x0F)) + ((data[ofset+9] & 0x0F));
152 d=(10*(data[ofset+8] & 0x0F)) + ((data[ofset+9] & 0x0F));
144 h=(10*(data[ofset+11] & 0x0F)) + ((data[ofset+12] & 0x0F));
153 h=(10*(data[ofset+11] & 0x0F)) + ((data[ofset+12] & 0x0F));
145 m=(10*(data[ofset+14] & 0x0F)) + ((data[ofset+15] & 0x0F));
154 m=(10*(data[ofset+14] & 0x0F)) + ((data[ofset+15] & 0x0F));
146 s=(10*(data[ofset+17] & 0x0F)) + ((data[ofset+18] & 0x0F));
155 s=(10*(data[ofset+17] & 0x0F)) + ((data[ofset+18] & 0x0F));
147 double ms=(100*(data[ofset+20] & 0x0F)) + (10*(data[ofset+21] & 0x0F)) + ((data[ofset+22] & 0x0F));
156 double ms=(100*(data[ofset+20] & 0x0F)) + (10*(data[ofset+21] & 0x0F)) + ((data[ofset+22] & 0x0F));
148 return (double)((d*3600*24)+(h*3600)+(m*60)+s) + (ms*0.001);
157 return (double)((d*3600*24)+(h*3600)+(m*60)+s) + (ms*0.001);
149 }
158 }
150
159
151 double __decodeTimeFromEpochDayOnly(int ofset,unsigned char* data)
160 double __decodeTimeFromEpochDayOnly(int ofset,unsigned char* data)
152 {
161 {
153 struct tm t;
162 struct tm t;
154 time_t t_of_day;
163 time_t t_of_day;
155 t.tm_year=(1000*(data[ofset] & 0x0F)) + (100*(data[ofset+1] & 0x0F)) + (10*(data[ofset+2] & 0x0F)) + ((data[ofset+3] & 0x0F)) -1900;
164 t.tm_year=(1000*(data[ofset] & 0x0F)) + (100*(data[ofset+1] & 0x0F)) + (10*(data[ofset+2] & 0x0F)) + ((data[ofset+3] & 0x0F)) -1900;
156 t.tm_mon=(10*(data[ofset+5] & 0x0F)) + ((data[ofset+6] & 0x0F));
165 t.tm_mon=(10*(data[ofset+5] & 0x0F)) + ((data[ofset+6] & 0x0F));
157 t.tm_mday=(10*(data[ofset+8] & 0x0F)) + ((data[ofset+9] & 0x0F));
166 t.tm_mday=(10*(data[ofset+8] & 0x0F)) + ((data[ofset+9] & 0x0F));
158 t.tm_hour=0;
167 t.tm_hour=0;
159 t.tm_min=0;
168 t.tm_min=0;
160 t.tm_sec=0;
169 t.tm_sec=0;
161 t_of_day = mktime(&t);
170 t_of_day = mktime(&t);
162 return (double)t_of_day;
171 return (double)t_of_day;
163 }
172 }
164
173
165 void CassiniDataFile::run()
174 void CassiniDataFile::run()
166 {
175 {
167 FILE* dataFile;
176 if(!m_Write)
168 dataFile = fopen(fileName.toStdString().c_str(),"r");
177 {
178 readFile();
179 }
180 else
181 {
182 writeFile();
183 }
184 }
169
185
170 if(dataFile != NULL)
186 void CassiniDataFile::readFile()
187 {
188 FILE* dataFile;
189 dataFile = fopen(fileName.toStdString().c_str(),"r");
190
191 if(dataFile != NULL)
171 {
192 {
172 fseek(dataFile, 0L, SEEK_END);
193 fseek(dataFile, 0L, SEEK_END);
173 int FileSize=ftell(dataFile);
194 int FileSize=ftell(dataFile);
174 int lineCnt = FileSize/58;
195 int lineCnt = FileSize/58;
175 int curLine=0;
196 int curLine=0;
176 int lastLineUpdate=0;
197 int lastLineUpdate=0;
177 QVector<QCPData> *ch1=new QVector<QCPData>(lineCnt);
198 QVector<QCPData> *ch1=new QVector<QCPData>(lineCnt);
178 QVector<QCPData> *ch2=new QVector<QCPData>(lineCnt);
199 QVector<QCPData> *ch2=new QVector<QCPData>(lineCnt);
179 QVector<QCPData> *ch3=new QVector<QCPData>(lineCnt);
200 QVector<QCPData> *ch3=new QVector<QCPData>(lineCnt);
180 QLopDataList data;
201 QLopDataList data;
181 QLopData* ch1V=new QLopData();
202 QLopData* ch1V=new QLopData();
182 QLopData* ch2V=new QLopData();
203 QLopData* ch2V=new QLopData();
183 QLopData* ch3V=new QLopData();
204 QLopData* ch3V=new QLopData();
184 ch1V->data=ch1;
205 ch1V->data=ch1;
185 ch2V->data=ch2;
206 ch2V->data=ch2;
186 ch3V->data=ch3;
207 ch3V->data=ch3;
187 ch1V->name="r";
208 ch1V->name="r";
188 ch2V->name="theta";
209 ch2V->name="theta";
189 ch3V->name="phi";
210 ch3V->name="phi";
190 ch1V->unit="nT";
211 ch1V->unit="nT";
191 ch2V->unit="nT";
212 ch2V->unit="nT";
192 ch3V->unit="nT";
213 ch3V->unit="nT";
193 data.append(ch1V);
214 data.append(ch1V);
194 data.append(ch2V);
215 data.append(ch2V);
195 data.append(ch3V);
216 data.append(ch3V);
196 QElapsedTimer timr;
217 QElapsedTimer timr;
197
218
198 double _x=0.0,day=0.0;
219 double _x=0.0,day=0.0;
199 char* line;
220 char* line;
200 QCPData data1,data2,data3;
221 QCPData data1,data2,data3;
201 char* fileContent=(char*)malloc(FileSize);
222 char* fileContent=(char*)malloc(FileSize);
202 if(Q_UNLIKELY(fileContent==NULL))return;
223 if(Q_UNLIKELY(fileContent==NULL))return;
203 int threadIndex,numThreads=omp_get_num_threads();
224 int threadIndex,numThreads=omp_get_num_threads();
204 int updateTriger=(lineCnt/100)/numThreads;
225 int updateTriger=(lineCnt/100)/numThreads;
205 fseek(dataFile, 0L, SEEK_SET);
226 fseek(dataFile, 0L, SEEK_SET);
206 char* svglocale=NULL;
227 char* svglocale=NULL;
207 setlocale(LC_NUMERIC,svglocale);
228 setlocale(LC_NUMERIC,svglocale);
208 setlocale(LC_NUMERIC, "en_US");
229 setlocale(LC_NUMERIC, "en_US");
209 if(fread(fileContent,1,FileSize,dataFile))
230 if(fread(fileContent,1,FileSize,dataFile))
210 {
231 {
211 line = fileContent;
232 line = fileContent;
212 QDateTime date;
233 QDateTime date;
213 timr.start();
234 timr.start();
214 day=__decodeTimeFromEpochDayOnly(0,(unsigned char*)line);
235 day=__decodeTimeFromEpochDayOnly(0,(unsigned char*)line);
215 //#pragma omp parallel if ((FileSize > 10000000)) private(date,data1,data2,data3,_x,threadIndex,lastLineUpdate) shared(ch1,ch2,ch3,lineCnt)
236 //#pragma omp parallel if ((FileSize > 10000000)) private(date,data1,data2,data3,_x,threadIndex,lastLineUpdate) shared(ch1,ch2,ch3,lineCnt)
216 // {
237 // {
217 #pragma omp parallel for if ((FileSize > 1024*1024*10)) private(date,data1,data2,data3,_x,threadIndex,lastLineUpdate,curLine) shared(ch1,ch2,ch3,lineCnt,updateTriger)
238 #pragma omp parallel for if ((FileSize > 1024*1024*10)) private(date,data1,data2,data3,_x,threadIndex,lastLineUpdate,curLine) shared(ch1,ch2,ch3,lineCnt,updateTriger)
218 for(int i=0;i<lineCnt;i++)
239 for(int i=0;i<lineCnt;i++)
219 {
240 {
220 // _x= i;
241 // _x= i;
221 _x= day + __decodeTimeDHMSmS((i*58),(unsigned char*)line);
242 _x= day + __decodeTimeDHMSmS((i*58),(unsigned char*)line);
222 // _x=__decodeTimeFromEpoch((i*58),(unsigned char*)line);
243 // _x=__decodeTimeFromEpoch((i*58),(unsigned char*)line);
223 data1.key=_x;
244 data1.key=_x;
224 data2.key=_x;
245 data2.key=_x;
225 data3.key=_x;
246 data3.key=_x;
226 data1.value=__decodeVal(((i*58)+27),(unsigned char*)line);
247 data1.value=__decodeVal(((i*58)+27),(unsigned char*)line);
227 data2.value=__decodeVal(((i*58)+38),(unsigned char*)line);
248 data2.value=__decodeVal(((i*58)+38),(unsigned char*)line);
228 data3.value=__decodeVal(((i*58)+49),(unsigned char*)line);
249 data3.value=__decodeVal(((i*58)+49),(unsigned char*)line);
229 (*ch1)[i]=data1;
250 (*ch1)[i]=data1;
230 (*ch2)[i]=data2;
251 (*ch2)[i]=data2;
231 (*ch3)[i]=data3;
252 (*ch3)[i]=data3;
232 curLine++;
253 curLine++;
233 if(Q_UNLIKELY(lastLineUpdate++>updateTriger))
254 if(Q_UNLIKELY(lastLineUpdate++>updateTriger))
234 {
255 {
235 lastLineUpdate=0;
256 lastLineUpdate=0;
236 int test=((curLine*numThreads *100)/ (lineCnt));
257 int test=((curLine*numThreads *100)/ (lineCnt));
237 emit updateProgress(omp_get_thread_num(),test);
258 emit updateProgress(omp_get_thread_num(),test);
238 }
259 }
239 }
260 }
240 }
261 }
241 //#pragma omp barrier
262 //#pragma omp barrier
242 free(fileContent);
263 free(fileContent);
243 // }
264 // }
244 qDebug()<< lineCnt <<" Points loade in "<< timr.elapsed()<<"ms";
265 qDebug()<< lineCnt <<" Points loade in "<< timr.elapsed()<<"ms";
245 setlocale(LC_NUMERIC,svglocale);
266 setlocale(LC_NUMERIC,svglocale);
246 emit dataReady(data);
267 emit dataReady(data);
247 }
268 }
248 }
269 }
249
270
271 void CassiniDataFile::writeFile()
272 {
273 QFile dataFile(fileName);
274 dataFile.open(QIODevice::WriteOnly);
275 QTextStream out(&dataFile);
276 if(dataFile.isOpen())
277 {
278 if(m_data.count()==3)
279 {
280 QLopData* ch1V=m_data.at(0);
281 QLopData* ch2V=m_data.at(1);
282 QLopData* ch3V=m_data.at(2);
283 if(ch1V->data->count()==ch2V->data->count() && ch1V->data->count()==ch3V->data->count())
284 {
285 for(int i=0;i<ch1V->data->count();i++)
286 {
287 double key = ch1V->data->at(i).key;
288 QDateTime date = QDateTime::fromMSecsSinceEpoch(key*1000);
289 out << date.toString(Qt::ISODate)+QString(".%1").arg(date.time().msec(),3);
290 out << QString("%1%2%3").arg(ch1V->data->at(i).value, 11, 'f', 3).arg(ch2V->data->at(i).value, 11, 'f', 3).arg(ch3V->data->at(i).value, 11, 'f', 3);
291 out << "\r\n";
292 }
293 }
294 dataFile.flush();
295 m_data.clear();
296 delete ch1V;
297 delete ch2V;
298 delete ch3V;
299 }
300 }
301 }
302
@@ -1,45 +1,50
1 /*------------------------------------------------------------------------------
1 /*------------------------------------------------------------------------------
2 -- This file is a part of the QLop Software
2 -- This file is a part of the QLop Software
3 -- Copyright (C) 2015, Plasma Physics Laboratory - CNRS
3 -- Copyright (C) 2015, Plasma Physics Laboratory - CNRS
4 --
4 --
5 -- This program is free software; you can redistribute it and/or modify
5 -- This program is free software; you can redistribute it and/or modify
6 -- it under the terms of the GNU General Public License as published by
6 -- it under the terms of the GNU General Public License as published by
7 -- the Free Software Foundation; either version 2 of the License, or
7 -- the Free Software Foundation; either version 2 of the License, or
8 -- (at your option) any later version.
8 -- (at your option) any later version.
9 --
9 --
10 -- This program is distributed in the hope that it will be useful,
10 -- This program is distributed in the hope that it will be useful,
11 -- but WITHOUT ANY WARRANTY; without even the implied warranty of
11 -- but WITHOUT ANY WARRANTY; without even the implied warranty of
12 -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 -- GNU General Public License for more details.
13 -- GNU General Public License for more details.
14 --
14 --
15 -- You should have received a copy of the GNU General Public License
15 -- You should have received a copy of the GNU General Public License
16 -- along with this program; if not, write to the Free Software
16 -- along with this program; if not, write to the Free Software
17 -- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17 -- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 -------------------------------------------------------------------------------*/
18 -------------------------------------------------------------------------------*/
19 /*-- Author : Alexis Jeandet
19 /*-- Author : Alexis Jeandet
20 -- Mail : alexis.jeandet@member.fsf.org
20 -- Mail : alexis.jeandet@member.fsf.org
21 ----------------------------------------------------------------------------*/
21 ----------------------------------------------------------------------------*/
22 #ifndef CASSINIDATAFILE_H
22 #ifndef CASSINIDATAFILE_H
23 #define CASSINIDATAFILE_H
23 #define CASSINIDATAFILE_H
24
24
25 #include <QObject>
25 #include <QObject>
26 #include <QThread>
26 #include <QThread>
27 #include <qcustomplot.h>
27 #include <qcustomplot.h>
28 #include "abstractfileloader.h"
28 #include "abstractfileloader.h"
29 class CassiniDataFile : public AbstractFileLoader
29 class CassiniDataFile : public AbstractFileLoader
30 {
30 {
31 Q_OBJECT
31 Q_OBJECT
32 public:
32 public:
33 explicit CassiniDataFile(QObject *parent = 0);
33 explicit CassiniDataFile(QObject *parent = 0);
34 ~CassiniDataFile();
34 ~CassiniDataFile();
35 void parseFile(const QString& fileName);
35 void parseFile(const QString& fileName);
36 void saveFile(const QString& fileName,QLopDataList data);
36 void run();
37 void run();
37 signals:
38 signals:
38 public slots:
39 public slots:
39
40
40 private :
41 private :
42 void readFile();
43 void writeFile();
44 bool m_Write;
41 QString fileName;
45 QString fileName;
46 QLopDataList m_data;
42 };
47 };
43
48
44
49
45 #endif // CASSINIDATAFILE_H
50 #endif // CASSINIDATAFILE_H
@@ -1,161 +1,172
1 #include "cassinitools.h"
1 #include "cassinitools.h"
2 #include <qlopplots.h>
2 #include <qlopplots.h>
3 #include <QPen>
3 #include <QPen>
4 #include <QAction>
4 #include <QAction>
5
5
6 CassiniTools* CassiniTools::_self=NULL;
6 CassiniTools* CassiniTools::_self=NULL;
7 QDockWidget* CassiniTools::m_gui=NULL;
7 QDockWidget* CassiniTools::m_gui=NULL;
8 CassiniToolsGUI* CassiniTools::m_CassiniToolsGUI=NULL;
8 CassiniToolsGUI* CassiniTools::m_CassiniToolsGUI=NULL;
9 CassiniDataFile* CassiniTools::m_dataFile=NULL;
9 CassiniDataFile* CassiniTools::m_dataFile=NULL;
10 int CassiniTools::m_defaultPlot=-1;
10 int CassiniTools::m_defaultPlot=-1;
11
11
12 Qt::GlobalColor QLopColours[]= {Qt::black,
12 Qt::GlobalColor QLopColours[]= {Qt::black,
13 Qt::red,
13 Qt::red,
14 Qt::blue,
14 Qt::blue,
15 Qt::green,
15 Qt::green,
16 Qt::darkGreen,
16 Qt::darkGreen,
17 Qt::cyan,
17 Qt::cyan,
18 Qt::darkRed,
18 Qt::darkRed,
19 Qt::gray,
19 Qt::gray,
20 Qt::yellow,
20 Qt::yellow,
21 Qt::darkBlue,
21 Qt::darkBlue,
22 Qt::darkCyan,
22 Qt::darkCyan,
23 Qt::magenta,
23 Qt::magenta,
24 Qt::darkMagenta,
24 Qt::darkMagenta,
25 Qt::darkYellow,
25 Qt::darkYellow,
26 Qt::darkGray,
26 Qt::darkGray,
27 Qt::lightGray};
27 Qt::lightGray};
28
28
29 int QLopColoursCount=16;
29 int QLopColoursCount=16;
30
30
31 #define _INIT() if(Q_UNLIKELY(_self==NULL)){init();}
31 #define _INIT() if(Q_UNLIKELY(_self==NULL)){init();}
32
32
33 CassiniTools::CassiniTools(bool noGUI,QObject *parent) : QLopService(parent)
33 CassiniTools::CassiniTools(bool noGUI,QObject *parent) : QLopService(parent)
34 {
34 {
35 m_dataFile = new CassiniDataFile();
35 m_dataFile = new CassiniDataFile();
36 connect(m_dataFile,SIGNAL(dataReady(QLopDataList)),this,SLOT(dataReady(QLopDataList)));
36 connect(m_dataFile,SIGNAL(dataReady(QLopDataList)),this,SLOT(dataReady(QLopDataList)));
37 m_serviceName="CassiniTools";
37 m_serviceName="CassiniTools";
38 m_noGui=noGUI;
38 m_noGui=noGUI;
39 }
39 }
40
40
41 CassiniTools::~CassiniTools()
41 CassiniTools::~CassiniTools()
42 {
42 {
43 delete m_dataFile;
43 delete m_dataFile;
44 delete m_CassiniToolsGUI;
44 delete m_CassiniToolsGUI;
45 delete m_gui;
45 delete m_gui;
46 }
46 }
47
47
48 void CassiniTools::makePlot()
48 void CassiniTools::makePlot()
49 {
49 {
50 m_defaultPlot = QLopPlots::addPlot();
50 m_defaultPlot = QLopPlots::addPlot();
51 SocExplorerPlot* plot=QLopPlots::getPlot(m_defaultPlot);
51 SocExplorerPlot* plot=QLopPlots::getPlot(m_defaultPlot);
52 if(plot)
52 if(plot)
53 {
53 {
54 plot->setTitle(_self->m_serviceName + " plot");
54 plot->setTitle(_self->m_serviceName + " plot");
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 SocExplorerPlotActions* action=new SocExplorerPlotActions("export view",plot->PID(),_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(int)),_self,SLOT(export_view(int)));
61 }
61 }
62 }
62 }
63
63
64 void CassiniTools::init(bool noGUI, QObject *parent)
64 void CassiniTools::init(bool noGUI, QObject *parent)
65 {
65 {
66 if(Q_UNLIKELY(_self==NULL))
66 if(Q_UNLIKELY(_self==NULL))
67 {
67 {
68 _self=new CassiniTools(noGUI,parent);
68 _self=new CassiniTools(noGUI,parent);
69 }
69 }
70 }
70 }
71
71
72 CassiniTools *CassiniTools::self()
72 CassiniTools *CassiniTools::self()
73 {
73 {
74 _INIT();
74 _INIT();
75 return _self;
75 return _self;
76 }
76 }
77
77
78 void CassiniTools::decodeFGMData(const QString &file)
78 void CassiniTools::decodeFGMData(const QString &file)
79 {
79 {
80 _INIT();
80 _INIT();
81 m_dataFile->parseFile(file);
81 m_dataFile->parseFile(file);
82 }
82 }
83
83
84 void CassiniTools::plotFile(const QString &File)
84 void CassiniTools::plotFile(const QString &File)
85 {
85 {
86 if(!m_dataFile->isRunning())
86 if(!m_dataFile->isRunning())
87 {
87 {
88 m_dataFile->parseFile(File);
88 m_dataFile->parseFile(File);
89 // TODO fixme
89 // TODO fixme
90 SocExplorerPlot* plot = QLopPlots::getPlot(m_defaultPlot);
90 SocExplorerPlot* plot = QLopPlots::getPlot(m_defaultPlot);
91 if(plot==NULL)
91 if(plot==NULL)
92 {
92 {
93 makePlot();
93 makePlot();
94 plot = QLopPlots::getPlot(m_defaultPlot);
94 plot = QLopPlots::getPlot(m_defaultPlot);
95 }
95 }
96 if(plot)
96 if(plot)
97 plot->setTitle(File);
97 plot->setTitle(File);
98 }
98 }
99 }
99 }
100
100
101 void CassiniTools::plot_TAB_File(const QString &fileName)
101 void CassiniTools::plot_TAB_File(const QString &fileName)
102 {
102 {
103 //TODO fix: accent not accepted
103 //TODO fix: accent not accepted
104 plotFile(fileName);
104 plotFile(fileName);
105 }
105 }
106
106
107 void CassiniTools::export_view(int PID)
107 void CassiniTools::export_view(int PID)
108 {
108 {
109 SocExplorerPlot* plot = QLopPlots::getPlot(PID);
109 SocExplorerPlot* plot = QLopPlots::getPlot(PID);
110 if(plot==NULL)
110 if(plot==NULL)
111 return;
111 return;
112 {
112 {
113 QString fileName = QFileDialog::getSaveFileName();
113 QString fileName = QFileDialog::getSaveFileName();
114 if(fileName!="")
115 {
116 QLopDataList vectors;
117 for(int i=0;i<plot->graphCount();i++)
118 {
119 QLopData* vect = new QLopData();
120 vect->data = plot->getVisibleData(i);
121 vectors.append(vect);
122 }
123 m_dataFile->saveFile(fileName,vectors);
124 }
114 }
125 }
115 }
126 }
116
127
117 QDockWidget *CassiniTools::getGUI()
128 QDockWidget *CassiniTools::getGUI()
118 {
129 {
119 if(!m_noGui && (m_gui==NULL))
130 if(!m_noGui && (m_gui==NULL))
120 {
131 {
121 m_gui=new QDockWidget("Cassini Tools");
132 m_gui=new QDockWidget("Cassini Tools");
122 m_CassiniToolsGUI = new CassiniToolsGUI();
133 m_CassiniToolsGUI = new CassiniToolsGUI();
123 m_gui->setWidget(m_CassiniToolsGUI);
134 m_gui->setWidget(m_CassiniToolsGUI);
124 m_gui->setFeatures(QDockWidget::DockWidgetMovable|QDockWidget::DockWidgetFloatable);
135 m_gui->setFeatures(QDockWidget::DockWidgetMovable|QDockWidget::DockWidgetFloatable);
125 }
136 }
126 return m_gui;
137 return m_gui;
127 }
138 }
128
139
129 const QString &CassiniTools::serviceName()
140 const QString &CassiniTools::serviceName()
130 {
141 {
131 _INIT();
142 _INIT();
132 return m_serviceName;
143 return m_serviceName;
133 }
144 }
134
145
135 void CassiniTools::dataReady(QLopDataList data)
146 void CassiniTools::dataReady(QLopDataList data)
136 {
147 {
137 SocExplorerPlot* plot = QLopPlots::getPlot(m_defaultPlot);
148 SocExplorerPlot* plot = QLopPlots::getPlot(m_defaultPlot);
138 if(plot==NULL)
149 if(plot==NULL)
139 {
150 {
140 makePlot();
151 makePlot();
141 plot = QLopPlots::getPlot(m_defaultPlot);
152 plot = QLopPlots::getPlot(m_defaultPlot);
142 }
153 }
143 if(plot)
154 if(plot)
144 {
155 {
145 plot->removeAllGraphs();
156 plot->removeAllGraphs();
146 for(int i=0;i<data.count();i++)
157 for(int i=0;i<data.count();i++)
147 {
158 {
148 plot->addGraph();
159 plot->addGraph();
149 plot->setAdaptativeSampling(i,true);
160 plot->setAdaptativeSampling(i,true);
150 plot->setUseFastVector(i,true);
161 plot->setUseFastVector(i,true);
151 QPen pen = plot->getGraphPen(i);
162 QPen pen = plot->getGraphPen(i);
152 pen.setColor(QLopColours[i%QLopColoursCount]);
163 pen.setColor(QLopColours[i%QLopColoursCount]);
153 plot->setGraphPen(i,pen);
164 plot->setGraphPen(i,pen);
154 plot->setGraphName(i,data.at(i)->name+"("+data.at(i)->unit+")");
165 plot->setGraphName(i,data.at(i)->name+"("+data.at(i)->unit+")");
155 plot->setGraphData(i,data.at(i)->data,false);
166 plot->setGraphData(i,data.at(i)->data,false);
156 }
167 }
157 plot->rescaleAxis();
168 plot->rescaleAxis();
158 plot->replot();
169 plot->replot();
159 }
170 }
160 }
171 }
161
172
@@ -1,619 +1,629
1 #include "qcustomplotvect.h"
1 #include "qcustomplotvect.h"
2 #include <QVector>
2 #include <QVector>
3 #include <QVectorIterator>
3 #include <QVectorIterator>
4 QCustomPlotVect::QCustomPlotVect(QWidget *parent)
4 QCustomPlotVect::QCustomPlotVect(QWidget *parent)
5 :QCustomPlot(parent)
5 :QCustomPlot(parent)
6 {
6 {
7
7
8 }
8 }
9
9
10 QCustomPlotVect::~QCustomPlotVect()
10 QCustomPlotVect::~QCustomPlotVect()
11 {
11 {
12
12
13 }
13 }
14
14
15 QCPGraphVect *QCustomPlotVect::addGraph(QCPAxis *keyAxis, QCPAxis *valueAxis)
15 QCPGraphVect *QCustomPlotVect::addGraph(QCPAxis *keyAxis, QCPAxis *valueAxis)
16 {
16 {
17 if (!keyAxis) keyAxis = xAxis;
17 if (!keyAxis) keyAxis = xAxis;
18 if (!valueAxis) valueAxis = yAxis;
18 if (!valueAxis) valueAxis = yAxis;
19 if (!keyAxis || !valueAxis)
19 if (!keyAxis || !valueAxis)
20 {
20 {
21 qDebug() << Q_FUNC_INFO << "can't use default QCustomPlot xAxis or yAxis, because at least one is invalid (has been deleted)";
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;
22 return 0;
23 }
23 }
24 if (keyAxis->parentPlot() != this || valueAxis->parentPlot() != this)
24 if (keyAxis->parentPlot() != this || valueAxis->parentPlot() != this)
25 {
25 {
26 qDebug() << Q_FUNC_INFO << "passed keyAxis or valueAxis doesn't have this QCustomPlot as parent";
26 qDebug() << Q_FUNC_INFO << "passed keyAxis or valueAxis doesn't have this QCustomPlot as parent";
27 return 0;
27 return 0;
28 }
28 }
29
29
30 QCPGraphVect *newGraph = new QCPGraphVect(keyAxis, valueAxis);
30 QCPGraphVect *newGraph = new QCPGraphVect(keyAxis, valueAxis);
31 if (addPlottable(newGraph))
31 if (addPlottable(newGraph))
32 {
32 {
33 newGraph->setName(QLatin1String("Graph ")+QString::number(mGraphs.size()));
33 newGraph->setName(QLatin1String("Graph ")+QString::number(mGraphs.size()));
34 return newGraph;
34 return newGraph;
35 } else
35 } else
36 {
36 {
37 delete newGraph;
37 delete newGraph;
38 return 0;
38 return 0;
39 }
39 }
40 }
40 }
41
41
42
42
43 QCPGraphVect::QCPGraphVect(QCPAxis *keyAxis, QCPAxis *valueAxis)
43 QCPGraphVect::QCPGraphVect(QCPAxis *keyAxis, QCPAxis *valueAxis)
44 :QCPGraph(keyAxis,valueAxis)
44 :QCPGraph(keyAxis,valueAxis)
45 {
45 {
46 mData = new QVector<QCPData>();
46 mData = new QVector<QCPData>();
47 }
47 }
48
48
49 QCPGraphVect::~QCPGraphVect()
49 QCPGraphVect::~QCPGraphVect()
50 {
50 {
51
51
52 }
52 }
53
53
54 void QCPGraphVect::setData(QVector<QCPData> *data)
54 void QCPGraphVect::setData(QVector<QCPData> *data)
55 {
55 {
56 if(data!=mData)
56 if(data!=mData)
57 {
57 {
58 delete this->mData;
58 delete this->mData;
59 this->mData = data;
59 this->mData = data;
60 }
60 }
61 }
61 }
62
62
63 QVector<QCPData> *QCPGraphVect::getVisibleData()
64 {
65 QVector<QCPData>* data = new QVector<QCPData>();
66 bool mAdaptiveSampling_save = mAdaptiveSampling;
67 mAdaptiveSampling = false;
68 getPreparedData(data,NULL);
69 mAdaptiveSampling = mAdaptiveSampling_save;
70 return data;
71 }
72
63 void QCPGraphVect::draw(QCPPainter *painter)
73 void QCPGraphVect::draw(QCPPainter *painter)
64 {
74 {
65 if (!mKeyAxis || !mValueAxis) { qDebug() << Q_FUNC_INFO << "invalid key or value axis"; return; }
75 if (!mKeyAxis || !mValueAxis) { qDebug() << Q_FUNC_INFO << "invalid key or value axis"; return; }
66 int test = mKeyAxis.data()->range().size();
76 int test = mKeyAxis.data()->range().size();
67 test = mData->count();
77 test = mData->count();
68 if (mKeyAxis.data()->range().size() <= 0 || mData->isEmpty()) return;
78 if (mKeyAxis.data()->range().size() <= 0 || mData->isEmpty()) return;
69 if (mLineStyle == lsNone && mScatterStyle.isNone()) return;
79 if (mLineStyle == lsNone && mScatterStyle.isNone()) return;
70
80
71 // allocate line and (if necessary) point vectors:
81 // allocate line and (if necessary) point vectors:
72 QVector<QPointF> *lineData = new QVector<QPointF>;
82 QVector<QPointF> *lineData = new QVector<QPointF>;
73 QVector<QCPData> *scatterData = 0;
83 QVector<QCPData> *scatterData = 0;
74 if (!mScatterStyle.isNone())
84 if (!mScatterStyle.isNone())
75 scatterData = new QVector<QCPData>;
85 scatterData = new QVector<QCPData>;
76
86
77 // fill vectors with data appropriate to plot style:
87 // fill vectors with data appropriate to plot style:
78 getPlotData(lineData, scatterData);
88 getPlotData(lineData, scatterData);
79
89
80 // check data validity if flag set:
90 // check data validity if flag set:
81 #ifdef QCUSTOMPLOT_CHECK_DATA
91 #ifdef QCUSTOMPLOT_CHECK_DATA
82 QCPDataMap::const_iterator it;
92 QCPDataMap::const_iterator it;
83 for (it = mData->constBegin(); it != mData->constEnd(); ++it)
93 for (it = mData->constBegin(); it != mData->constEnd(); ++it)
84 {
94 {
85 if (QCP::isInvalidData(it.value().key, it.value().value) ||
95 if (QCP::isInvalidData(it.value().key, it.value().value) ||
86 QCP::isInvalidData(it.value().keyErrorPlus, it.value().keyErrorMinus) ||
96 QCP::isInvalidData(it.value().keyErrorPlus, it.value().keyErrorMinus) ||
87 QCP::isInvalidData(it.value().valueErrorPlus, it.value().valueErrorPlus))
97 QCP::isInvalidData(it.value().valueErrorPlus, it.value().valueErrorPlus))
88 qDebug() << Q_FUNC_INFO << "Data point at" << it.key() << "invalid." << "Plottable name:" << name();
98 qDebug() << Q_FUNC_INFO << "Data point at" << it.key() << "invalid." << "Plottable name:" << name();
89 }
99 }
90 #endif
100 #endif
91
101
92 // draw fill of graph:
102 // draw fill of graph:
93 drawFill(painter, lineData);
103 drawFill(painter, lineData);
94
104
95 // draw line:
105 // draw line:
96 if (mLineStyle == lsImpulse)
106 if (mLineStyle == lsImpulse)
97 drawImpulsePlot(painter, lineData);
107 drawImpulsePlot(painter, lineData);
98 else if (mLineStyle != lsNone)
108 else if (mLineStyle != lsNone)
99 drawLinePlot(painter, lineData); // also step plots can be drawn as a line plot
109 drawLinePlot(painter, lineData); // also step plots can be drawn as a line plot
100
110
101 // draw scatters:
111 // draw scatters:
102 if (scatterData)
112 if (scatterData)
103 drawScatterPlot(painter, scatterData);
113 drawScatterPlot(painter, scatterData);
104
114
105 // free allocated line and point vectors:
115 // free allocated line and point vectors:
106 delete lineData;
116 delete lineData;
107 if (scatterData)
117 if (scatterData)
108 delete scatterData;
118 delete scatterData;
109 }
119 }
110
120
111 void QCPGraphVect::getPlotData(QVector<QPointF> *lineData, QVector<QCPData> *scatterData) const
121 void QCPGraphVect::getPlotData(QVector<QPointF> *lineData, QVector<QCPData> *scatterData) const
112 {
122 {
113 switch(mLineStyle)
123 switch(mLineStyle)
114 {
124 {
115 case lsNone: getScatterPlotData(scatterData); break;
125 case lsNone: getScatterPlotData(scatterData); break;
116 case lsLine: getLinePlotData(lineData, scatterData); break;
126 case lsLine: getLinePlotData(lineData, scatterData); break;
117 case lsStepLeft: getStepLeftPlotData(lineData, scatterData); break;
127 case lsStepLeft: getStepLeftPlotData(lineData, scatterData); break;
118 case lsStepRight: getStepRightPlotData(lineData, scatterData); break;
128 case lsStepRight: getStepRightPlotData(lineData, scatterData); break;
119 case lsStepCenter: getStepCenterPlotData(lineData, scatterData); break;
129 case lsStepCenter: getStepCenterPlotData(lineData, scatterData); break;
120 case lsImpulse: getImpulsePlotData(lineData, scatterData); break;
130 case lsImpulse: getImpulsePlotData(lineData, scatterData); break;
121 }
131 }
122 }
132 }
123
133
124 void QCPGraphVect::getLinePlotData(QVector<QPointF> *linePixelData, QVector<QCPData> *scatterData) const
134 void QCPGraphVect::getLinePlotData(QVector<QPointF> *linePixelData, QVector<QCPData> *scatterData) const
125 {
135 {
126 QCPAxis *keyAxis = mKeyAxis.data();
136 QCPAxis *keyAxis = mKeyAxis.data();
127 QCPAxis *valueAxis = mValueAxis.data();
137 QCPAxis *valueAxis = mValueAxis.data();
128 if (!keyAxis || !valueAxis) { qDebug() << Q_FUNC_INFO << "invalid key or value axis"; return; }
138 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; }
139 if (!linePixelData) { qDebug() << Q_FUNC_INFO << "null pointer passed as linePixelData"; return; }
130
140
131 QVector<QCPData> lineData;
141 QVector<QCPData> lineData;
132 getPreparedData(&lineData, scatterData);
142 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
143 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());
144 linePixelData->resize(lineData.size());
135
145
136 // transform lineData points to pixels:
146 // transform lineData points to pixels:
137 if (keyAxis->orientation() == Qt::Vertical)
147 if (keyAxis->orientation() == Qt::Vertical)
138 {
148 {
139 for (int i=0; i<lineData.size(); ++i)
149 for (int i=0; i<lineData.size(); ++i)
140 {
150 {
141 (*linePixelData)[i].setX(valueAxis->coordToPixel(lineData.at(i).value));
151 (*linePixelData)[i].setX(valueAxis->coordToPixel(lineData.at(i).value));
142 (*linePixelData)[i].setY(keyAxis->coordToPixel(lineData.at(i).key));
152 (*linePixelData)[i].setY(keyAxis->coordToPixel(lineData.at(i).key));
143 }
153 }
144 } else // key axis is horizontal
154 } else // key axis is horizontal
145 {
155 {
146 for (int i=0; i<lineData.size(); ++i)
156 for (int i=0; i<lineData.size(); ++i)
147 {
157 {
148 (*linePixelData)[i].setX(keyAxis->coordToPixel(lineData.at(i).key));
158 (*linePixelData)[i].setX(keyAxis->coordToPixel(lineData.at(i).key));
149 (*linePixelData)[i].setY(valueAxis->coordToPixel(lineData.at(i).value));
159 (*linePixelData)[i].setY(valueAxis->coordToPixel(lineData.at(i).value));
150 }
160 }
151 }
161 }
152 }
162 }
153
163
154 QCPRange QCPGraphVect::getKeyRange(bool &foundRange, QCPAbstractPlottable::SignDomain inSignDomain, bool includeErrors) const
164 QCPRange QCPGraphVect::getKeyRange(bool &foundRange, QCPAbstractPlottable::SignDomain inSignDomain, bool includeErrors) const
155 {
165 {
156
166
157 QCPRange range;
167 QCPRange range;
158 bool haveLower = false;
168 bool haveLower = false;
159 bool haveUpper = false;
169 bool haveUpper = false;
160
170
161 double current, currentErrorMinus, currentErrorPlus;
171 double current, currentErrorMinus, currentErrorPlus;
162
172
163 if (inSignDomain == sdBoth) // range may be anywhere
173 if (inSignDomain == sdBoth) // range may be anywhere
164 {
174 {
165 QVector<QCPData>::const_iterator it = mData->constBegin();
175 QVector<QCPData>::const_iterator it = mData->constBegin();
166 while (it != mData->constEnd())
176 while (it != mData->constEnd())
167 {
177 {
168 current = (*it).key;
178 current = (*it).key;
169 currentErrorMinus = (includeErrors ? (*it).keyErrorMinus : 0);
179 currentErrorMinus = (includeErrors ? (*it).keyErrorMinus : 0);
170 currentErrorPlus = (includeErrors ? (*it).keyErrorPlus : 0);
180 currentErrorPlus = (includeErrors ? (*it).keyErrorPlus : 0);
171 if (current-currentErrorMinus < range.lower || !haveLower)
181 if (current-currentErrorMinus < range.lower || !haveLower)
172 {
182 {
173 range.lower = current-currentErrorMinus;
183 range.lower = current-currentErrorMinus;
174 haveLower = true;
184 haveLower = true;
175 }
185 }
176 if (current+currentErrorPlus > range.upper || !haveUpper)
186 if (current+currentErrorPlus > range.upper || !haveUpper)
177 {
187 {
178 range.upper = current+currentErrorPlus;
188 range.upper = current+currentErrorPlus;
179 haveUpper = true;
189 haveUpper = true;
180 }
190 }
181 ++it;
191 ++it;
182 }
192 }
183 } else if (inSignDomain == sdNegative) // range may only be in the negative sign domain
193 } else if (inSignDomain == sdNegative) // range may only be in the negative sign domain
184 {
194 {
185 QVector<QCPData>::const_iterator it = mData->constBegin();
195 QVector<QCPData>::const_iterator it = mData->constBegin();
186 while (it != mData->constEnd())
196 while (it != mData->constEnd())
187 {
197 {
188 current = (*it).key;
198 current = (*it).key;
189 currentErrorMinus = (includeErrors ? (*it).keyErrorMinus : 0);
199 currentErrorMinus = (includeErrors ? (*it).keyErrorMinus : 0);
190 currentErrorPlus = (includeErrors ? (*it).keyErrorPlus : 0);
200 currentErrorPlus = (includeErrors ? (*it).keyErrorPlus : 0);
191 if ((current-currentErrorMinus < range.lower || !haveLower) && current-currentErrorMinus < 0)
201 if ((current-currentErrorMinus < range.lower || !haveLower) && current-currentErrorMinus < 0)
192 {
202 {
193 range.lower = current-currentErrorMinus;
203 range.lower = current-currentErrorMinus;
194 haveLower = true;
204 haveLower = true;
195 }
205 }
196 if ((current+currentErrorPlus > range.upper || !haveUpper) && current+currentErrorPlus < 0)
206 if ((current+currentErrorPlus > range.upper || !haveUpper) && current+currentErrorPlus < 0)
197 {
207 {
198 range.upper = current+currentErrorPlus;
208 range.upper = current+currentErrorPlus;
199 haveUpper = true;
209 haveUpper = true;
200 }
210 }
201 if (includeErrors) // in case point is in valid sign domain but errobars stretch beyond it, we still want to geht that point.
211 if (includeErrors) // in case point is in valid sign domain but errobars stretch beyond it, we still want to geht that point.
202 {
212 {
203 if ((current < range.lower || !haveLower) && current < 0)
213 if ((current < range.lower || !haveLower) && current < 0)
204 {
214 {
205 range.lower = current;
215 range.lower = current;
206 haveLower = true;
216 haveLower = true;
207 }
217 }
208 if ((current > range.upper || !haveUpper) && current < 0)
218 if ((current > range.upper || !haveUpper) && current < 0)
209 {
219 {
210 range.upper = current;
220 range.upper = current;
211 haveUpper = true;
221 haveUpper = true;
212 }
222 }
213 }
223 }
214 ++it;
224 ++it;
215 }
225 }
216 } else if (inSignDomain == sdPositive) // range may only be in the positive sign domain
226 } else if (inSignDomain == sdPositive) // range may only be in the positive sign domain
217 {
227 {
218 QVector<QCPData>::const_iterator it = mData->constBegin();
228 QVector<QCPData>::const_iterator it = mData->constBegin();
219 while (it != mData->constEnd())
229 while (it != mData->constEnd())
220 {
230 {
221 current = (*it).key;
231 current = (*it).key;
222 currentErrorMinus = (includeErrors ? (*it).keyErrorMinus : 0);
232 currentErrorMinus = (includeErrors ? (*it).keyErrorMinus : 0);
223 currentErrorPlus = (includeErrors ? (*it).keyErrorPlus : 0);
233 currentErrorPlus = (includeErrors ? (*it).keyErrorPlus : 0);
224 if ((current-currentErrorMinus < range.lower || !haveLower) && current-currentErrorMinus > 0)
234 if ((current-currentErrorMinus < range.lower || !haveLower) && current-currentErrorMinus > 0)
225 {
235 {
226 range.lower = current-currentErrorMinus;
236 range.lower = current-currentErrorMinus;
227 haveLower = true;
237 haveLower = true;
228 }
238 }
229 if ((current+currentErrorPlus > range.upper || !haveUpper) && current+currentErrorPlus > 0)
239 if ((current+currentErrorPlus > range.upper || !haveUpper) && current+currentErrorPlus > 0)
230 {
240 {
231 range.upper = current+currentErrorPlus;
241 range.upper = current+currentErrorPlus;
232 haveUpper = true;
242 haveUpper = true;
233 }
243 }
234 if (includeErrors) // in case point is in valid sign domain but errobars stretch beyond it, we still want to get that point.
244 if (includeErrors) // in case point is in valid sign domain but errobars stretch beyond it, we still want to get that point.
235 {
245 {
236 if ((current < range.lower || !haveLower) && current > 0)
246 if ((current < range.lower || !haveLower) && current > 0)
237 {
247 {
238 range.lower = current;
248 range.lower = current;
239 haveLower = true;
249 haveLower = true;
240 }
250 }
241 if ((current > range.upper || !haveUpper) && current > 0)
251 if ((current > range.upper || !haveUpper) && current > 0)
242 {
252 {
243 range.upper = current;
253 range.upper = current;
244 haveUpper = true;
254 haveUpper = true;
245 }
255 }
246 }
256 }
247 ++it;
257 ++it;
248 }
258 }
249 }
259 }
250
260
251 foundRange = haveLower && haveUpper;
261 foundRange = haveLower && haveUpper;
252 return range;
262 return range;
253 }
263 }
254
264
255 QCPRange QCPGraphVect::getValueRange(bool &foundRange, QCPAbstractPlottable::SignDomain inSignDomain, bool includeErrors) const
265 QCPRange QCPGraphVect::getValueRange(bool &foundRange, QCPAbstractPlottable::SignDomain inSignDomain, bool includeErrors) const
256 {
266 {
257 QCPRange range;
267 QCPRange range;
258 bool haveLower = false;
268 bool haveLower = false;
259 bool haveUpper = false;
269 bool haveUpper = false;
260
270
261 double current, currentErrorMinus, currentErrorPlus;
271 double current, currentErrorMinus, currentErrorPlus;
262
272
263 if (inSignDomain == sdBoth) // range may be anywhere
273 if (inSignDomain == sdBoth) // range may be anywhere
264 {
274 {
265 QVector<QCPData>::const_iterator it = mData->constBegin();
275 QVector<QCPData>::const_iterator it = mData->constBegin();
266 while (it != mData->constEnd())
276 while (it != mData->constEnd())
267 {
277 {
268 current = (*it).value;
278 current = (*it).value;
269 currentErrorMinus = (includeErrors ? (*it).valueErrorMinus : 0);
279 currentErrorMinus = (includeErrors ? (*it).valueErrorMinus : 0);
270 currentErrorPlus = (includeErrors ? (*it).valueErrorPlus : 0);
280 currentErrorPlus = (includeErrors ? (*it).valueErrorPlus : 0);
271 if (current-currentErrorMinus < range.lower || !haveLower)
281 if (current-currentErrorMinus < range.lower || !haveLower)
272 {
282 {
273 range.lower = current-currentErrorMinus;
283 range.lower = current-currentErrorMinus;
274 haveLower = true;
284 haveLower = true;
275 }
285 }
276 if (current+currentErrorPlus > range.upper || !haveUpper)
286 if (current+currentErrorPlus > range.upper || !haveUpper)
277 {
287 {
278 range.upper = current+currentErrorPlus;
288 range.upper = current+currentErrorPlus;
279 haveUpper = true;
289 haveUpper = true;
280 }
290 }
281 ++it;
291 ++it;
282 }
292 }
283 } else if (inSignDomain == sdNegative) // range may only be in the negative sign domain
293 } else if (inSignDomain == sdNegative) // range may only be in the negative sign domain
284 {
294 {
285 QVector<QCPData>::const_iterator it = mData->constBegin();
295 QVector<QCPData>::const_iterator it = mData->constBegin();
286 while (it != mData->constEnd())
296 while (it != mData->constEnd())
287 {
297 {
288 current = (*it).value;
298 current = (*it).value;
289 currentErrorMinus = (includeErrors ? (*it).valueErrorMinus : 0);
299 currentErrorMinus = (includeErrors ? (*it).valueErrorMinus : 0);
290 currentErrorPlus = (includeErrors ? (*it).valueErrorPlus : 0);
300 currentErrorPlus = (includeErrors ? (*it).valueErrorPlus : 0);
291 if ((current-currentErrorMinus < range.lower || !haveLower) && current-currentErrorMinus < 0)
301 if ((current-currentErrorMinus < range.lower || !haveLower) && current-currentErrorMinus < 0)
292 {
302 {
293 range.lower = current-currentErrorMinus;
303 range.lower = current-currentErrorMinus;
294 haveLower = true;
304 haveLower = true;
295 }
305 }
296 if ((current+currentErrorPlus > range.upper || !haveUpper) && current+currentErrorPlus < 0)
306 if ((current+currentErrorPlus > range.upper || !haveUpper) && current+currentErrorPlus < 0)
297 {
307 {
298 range.upper = current+currentErrorPlus;
308 range.upper = current+currentErrorPlus;
299 haveUpper = true;
309 haveUpper = true;
300 }
310 }
301 if (includeErrors) // in case point is in valid sign domain but errobars stretch beyond it, we still want to get that point.
311 if (includeErrors) // in case point is in valid sign domain but errobars stretch beyond it, we still want to get that point.
302 {
312 {
303 if ((current < range.lower || !haveLower) && current < 0)
313 if ((current < range.lower || !haveLower) && current < 0)
304 {
314 {
305 range.lower = current;
315 range.lower = current;
306 haveLower = true;
316 haveLower = true;
307 }
317 }
308 if ((current > range.upper || !haveUpper) && current < 0)
318 if ((current > range.upper || !haveUpper) && current < 0)
309 {
319 {
310 range.upper = current;
320 range.upper = current;
311 haveUpper = true;
321 haveUpper = true;
312 }
322 }
313 }
323 }
314 ++it;
324 ++it;
315 }
325 }
316 } else if (inSignDomain == sdPositive) // range may only be in the positive sign domain
326 } else if (inSignDomain == sdPositive) // range may only be in the positive sign domain
317 {
327 {
318 QVector<QCPData>::const_iterator it = mData->constBegin();
328 QVector<QCPData>::const_iterator it = mData->constBegin();
319 while (it != mData->constEnd())
329 while (it != mData->constEnd())
320 {
330 {
321 current = (*it).value;
331 current = (*it).value;
322 currentErrorMinus = (includeErrors ? (*it).valueErrorMinus : 0);
332 currentErrorMinus = (includeErrors ? (*it).valueErrorMinus : 0);
323 currentErrorPlus = (includeErrors ? (*it).valueErrorPlus : 0);
333 currentErrorPlus = (includeErrors ? (*it).valueErrorPlus : 0);
324 if ((current-currentErrorMinus < range.lower || !haveLower) && current-currentErrorMinus > 0)
334 if ((current-currentErrorMinus < range.lower || !haveLower) && current-currentErrorMinus > 0)
325 {
335 {
326 range.lower = current-currentErrorMinus;
336 range.lower = current-currentErrorMinus;
327 haveLower = true;
337 haveLower = true;
328 }
338 }
329 if ((current+currentErrorPlus > range.upper || !haveUpper) && current+currentErrorPlus > 0)
339 if ((current+currentErrorPlus > range.upper || !haveUpper) && current+currentErrorPlus > 0)
330 {
340 {
331 range.upper = current+currentErrorPlus;
341 range.upper = current+currentErrorPlus;
332 haveUpper = true;
342 haveUpper = true;
333 }
343 }
334 if (includeErrors) // in case point is in valid sign domain but errobars stretch beyond it, we still want to geht that point.
344 if (includeErrors) // in case point is in valid sign domain but errobars stretch beyond it, we still want to geht that point.
335 {
345 {
336 if ((current < range.lower || !haveLower) && current > 0)
346 if ((current < range.lower || !haveLower) && current > 0)
337 {
347 {
338 range.lower = current;
348 range.lower = current;
339 haveLower = true;
349 haveLower = true;
340 }
350 }
341 if ((current > range.upper || !haveUpper) && current > 0)
351 if ((current > range.upper || !haveUpper) && current > 0)
342 {
352 {
343 range.upper = current;
353 range.upper = current;
344 haveUpper = true;
354 haveUpper = true;
345 }
355 }
346 }
356 }
347 ++it;
357 ++it;
348 }
358 }
349 }
359 }
350
360
351 foundRange = haveLower && haveUpper;
361 foundRange = haveLower && haveUpper;
352 return range;
362 return range;
353 }
363 }
354
364
355 void QCPGraphVect::getPreparedData(QVector<QCPData> *lineData, QVector<QCPData> *scatterData) const
365 void QCPGraphVect::getPreparedData(QVector<QCPData> *lineData, QVector<QCPData> *scatterData) const
356 {
366 {
357 QCPAxis *keyAxis = mKeyAxis.data();
367 QCPAxis *keyAxis = mKeyAxis.data();
358 QCPAxis *valueAxis = mValueAxis.data();
368 QCPAxis *valueAxis = mValueAxis.data();
359 if (!keyAxis || !valueAxis) { qDebug() << Q_FUNC_INFO << "invalid key or value axis"; return; }
369 if (!keyAxis || !valueAxis) { qDebug() << Q_FUNC_INFO << "invalid key or value axis"; return; }
360 // get visible data range:
370 // 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
371 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);
372 getVisibleDataBounds(lower, upper);
363 if (lower == mData->constEnd() || upper == mData->constEnd())
373 if (lower == mData->constEnd() || upper == mData->constEnd())
364 return;
374 return;
365
375
366 // count points in visible range, taking into account that we only need to count to the limit maxCount if using adaptive sampling:
376 // 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();
377 int maxCount = std::numeric_limits<int>::max();
368 if (mAdaptiveSampling)
378 if (mAdaptiveSampling)
369 {
379 {
370 int keyPixelSpan = qAbs(keyAxis->coordToPixel((*lower).key)-keyAxis->coordToPixel((*upper).key));
380 int keyPixelSpan = qAbs(keyAxis->coordToPixel((*lower).key)-keyAxis->coordToPixel((*upper).key));
371 maxCount = 2*keyPixelSpan+2;
381 maxCount = 2*keyPixelSpan+2;
372 }
382 }
373 int dataCount = countDataInBounds(lower, upper, maxCount);
383 int dataCount = countDataInBounds(lower, upper, maxCount);
374
384
375 if (mAdaptiveSampling && dataCount >= maxCount) // use adaptive sampling only if there are at least two points per pixel on average
385 if (mAdaptiveSampling && dataCount >= maxCount) // use adaptive sampling only if there are at least two points per pixel on average
376 {
386 {
377 if (lineData)
387 if (lineData)
378 {
388 {
379 QVector<QCPData>::const_iterator it = lower;
389 QVector<QCPData>::const_iterator it = lower;
380 QVector<QCPData>::const_iterator upperEnd = upper+1;
390 QVector<QCPData>::const_iterator upperEnd = upper+1;
381 double minValue = (*it).value;
391 double minValue = (*it).value;
382 double maxValue = (*it).value;
392 double maxValue = (*it).value;
383 QVector<QCPData>::const_iterator currentIntervalFirstPoint = it;
393 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
394 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
395 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));
396 double currentIntervalStartKey = keyAxis->pixelToCoord((int)(keyAxis->coordToPixel((*lower).key)+reversedRound));
387 double lastIntervalEndKey = currentIntervalStartKey;
397 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
398 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)
399 bool keyEpsilonVariable = keyAxis->scaleType() == QCPAxis::stLogarithmic; // indicates whether keyEpsilon needs to be updated after every interval (for log axes)
390 int intervalDataCount = 1;
400 int intervalDataCount = 1;
391 ++it; // advance iterator to second data point because adaptive sampling works in 1 point retrospect
401 ++it; // advance iterator to second data point because adaptive sampling works in 1 point retrospect
392 while (it != upperEnd)
402 while (it != upperEnd)
393 {
403 {
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
404 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 {
405 {
396 if ((*it).value < minValue)
406 if ((*it).value < minValue)
397 minValue = (*it).value;
407 minValue = (*it).value;
398 else if ((*it).value > maxValue)
408 else if ((*it).value > maxValue)
399 maxValue = (*it).value;
409 maxValue = (*it).value;
400 ++intervalDataCount;
410 ++intervalDataCount;
401 } else // new pixel interval started
411 } else // new pixel interval started
402 {
412 {
403 if (intervalDataCount >= 2) // last pixel had multiple data points, consolidate them to a cluster
413 if (intervalDataCount >= 2) // last pixel had multiple data points, consolidate them to a cluster
404 {
414 {
405 if (lastIntervalEndKey < currentIntervalStartKey-keyEpsilon) // last point is further away, so first point of this cluster must be at a real data point
415 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));
416 lineData->append(QCPData(currentIntervalStartKey+keyEpsilon*0.2, (*currentIntervalFirstPoint).value));
407 lineData->append(QCPData(currentIntervalStartKey+keyEpsilon*0.25, minValue));
417 lineData->append(QCPData(currentIntervalStartKey+keyEpsilon*0.25, minValue));
408 lineData->append(QCPData(currentIntervalStartKey+keyEpsilon*0.75, maxValue));
418 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
419 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));
420 lineData->append(QCPData(currentIntervalStartKey+keyEpsilon*0.8, (*(it-1)).value));
411 } else
421 } else
412 lineData->append(QCPData((*currentIntervalFirstPoint).key, (*currentIntervalFirstPoint).value));
422 lineData->append(QCPData((*currentIntervalFirstPoint).key, (*currentIntervalFirstPoint).value));
413 lastIntervalEndKey = (*(it-1)).key;
423 lastIntervalEndKey = (*(it-1)).key;
414 minValue = (*it).value;
424 minValue = (*it).value;
415 maxValue = (*it).value;
425 maxValue = (*it).value;
416 currentIntervalFirstPoint = it;
426 currentIntervalFirstPoint = it;
417 currentIntervalStartKey = keyAxis->pixelToCoord((int)(keyAxis->coordToPixel((*it).key)+reversedRound));
427 currentIntervalStartKey = keyAxis->pixelToCoord((int)(keyAxis->coordToPixel((*it).key)+reversedRound));
418 if (keyEpsilonVariable)
428 if (keyEpsilonVariable)
419 keyEpsilon = qAbs(currentIntervalStartKey-keyAxis->pixelToCoord(keyAxis->coordToPixel(currentIntervalStartKey)+1.0*reversedFactor));
429 keyEpsilon = qAbs(currentIntervalStartKey-keyAxis->pixelToCoord(keyAxis->coordToPixel(currentIntervalStartKey)+1.0*reversedFactor));
420 intervalDataCount = 1;
430 intervalDataCount = 1;
421 }
431 }
422 ++it;
432 ++it;
423 }
433 }
424 // handle last interval:
434 // handle last interval:
425 if (intervalDataCount >= 2) // last pixel had multiple data points, consolidate them to a cluster
435 if (intervalDataCount >= 2) // last pixel had multiple data points, consolidate them to a cluster
426 {
436 {
427 if (lastIntervalEndKey < currentIntervalStartKey-keyEpsilon) // last point wasn't a cluster, so first point of this cluster must be at a real data point
437 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));
438 lineData->append(QCPData(currentIntervalStartKey+keyEpsilon*0.2, (*currentIntervalFirstPoint).value));
429 lineData->append(QCPData(currentIntervalStartKey+keyEpsilon*0.25, minValue));
439 lineData->append(QCPData(currentIntervalStartKey+keyEpsilon*0.25, minValue));
430 lineData->append(QCPData(currentIntervalStartKey+keyEpsilon*0.75, maxValue));
440 lineData->append(QCPData(currentIntervalStartKey+keyEpsilon*0.75, maxValue));
431 } else
441 } else
432 lineData->append(QCPData((*currentIntervalFirstPoint).key, (*currentIntervalFirstPoint).value));
442 lineData->append(QCPData((*currentIntervalFirstPoint).key, (*currentIntervalFirstPoint).value));
433 }
443 }
434
444
435 if (scatterData)
445 if (scatterData)
436 {
446 {
437 double valueMaxRange = valueAxis->range().upper;
447 double valueMaxRange = valueAxis->range().upper;
438 double valueMinRange = valueAxis->range().lower;
448 double valueMinRange = valueAxis->range().lower;
439 QVector<QCPData>::const_iterator it = lower;
449 QVector<QCPData>::const_iterator it = lower;
440 QVector<QCPData>::const_iterator upperEnd = upper+1;
450 QVector<QCPData>::const_iterator upperEnd = upper+1;
441 double minValue = (*it).value;
451 double minValue = (*it).value;
442 double maxValue = (*it).value;
452 double maxValue = (*it).value;
443 QVector<QCPData>::const_iterator minValueIt = it;
453 QVector<QCPData>::const_iterator minValueIt = it;
444 QVector<QCPData>::const_iterator maxValueIt = it;
454 QVector<QCPData>::const_iterator maxValueIt = it;
445 QVector<QCPData>::const_iterator currentIntervalStart = it;
455 QVector<QCPData>::const_iterator currentIntervalStart = it;
446 int reversedFactor = keyAxis->rangeReversed() ? -1 : 1; // is used to calculate keyEpsilon pixel into the correct direction
456 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
457 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));
458 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
459 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)
460 bool keyEpsilonVariable = keyAxis->scaleType() == QCPAxis::stLogarithmic; // indicates whether keyEpsilon needs to be updated after every interval (for log axes)
451 int intervalDataCount = 1;
461 int intervalDataCount = 1;
452 ++it; // advance iterator to second data point because adaptive sampling works in 1 point retrospect
462 ++it; // advance iterator to second data point because adaptive sampling works in 1 point retrospect
453 while (it != upperEnd)
463 while (it != upperEnd)
454 {
464 {
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
465 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 {
466 {
457 if ((*it).value < minValue && (*it).value > valueMinRange && (*it).value < valueMaxRange)
467 if ((*it).value < minValue && (*it).value > valueMinRange && (*it).value < valueMaxRange)
458 {
468 {
459 minValue = (*it).value;
469 minValue = (*it).value;
460 minValueIt = it;
470 minValueIt = it;
461 } else if ((*it).value > maxValue && (*it).value > valueMinRange && (*it).value < valueMaxRange)
471 } else if ((*it).value > maxValue && (*it).value > valueMinRange && (*it).value < valueMaxRange)
462 {
472 {
463 maxValue = (*it).value;
473 maxValue = (*it).value;
464 maxValueIt = it;
474 maxValueIt = it;
465 }
475 }
466 ++intervalDataCount;
476 ++intervalDataCount;
467 } else // new pixel started
477 } else // new pixel started
468 {
478 {
469 if (intervalDataCount >= 2) // last pixel had multiple data points, consolidate them
479 if (intervalDataCount >= 2) // last pixel had multiple data points, consolidate them
470 {
480 {
471 // determine value pixel span and add as many points in interval to maintain certain vertical data density (this is specific to scatter plot):
481 // 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));
482 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
483 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;
484 QVector<QCPData>::const_iterator intervalIt = currentIntervalStart;
475 int c = 0;
485 int c = 0;
476 while (intervalIt != it)
486 while (intervalIt != it)
477 {
487 {
478 if ((c % dataModulo == 0 || intervalIt == minValueIt || intervalIt == maxValueIt) && (*intervalIt).value > valueMinRange && (*intervalIt).value < valueMaxRange)
488 if ((c % dataModulo == 0 || intervalIt == minValueIt || intervalIt == maxValueIt) && (*intervalIt).value > valueMinRange && (*intervalIt).value < valueMaxRange)
479 scatterData->append((*intervalIt));
489 scatterData->append((*intervalIt));
480 ++c;
490 ++c;
481 ++intervalIt;
491 ++intervalIt;
482 }
492 }
483 } else if ((*currentIntervalStart).value > valueMinRange && (*currentIntervalStart).value < valueMaxRange)
493 } else if ((*currentIntervalStart).value > valueMinRange && (*currentIntervalStart).value < valueMaxRange)
484 scatterData->append((*currentIntervalStart));
494 scatterData->append((*currentIntervalStart));
485 minValue = (*it).value;
495 minValue = (*it).value;
486 maxValue = (*it).value;
496 maxValue = (*it).value;
487 currentIntervalStart = it;
497 currentIntervalStart = it;
488 currentIntervalStartKey = keyAxis->pixelToCoord((int)(keyAxis->coordToPixel((*it).key)+reversedRound));
498 currentIntervalStartKey = keyAxis->pixelToCoord((int)(keyAxis->coordToPixel((*it).key)+reversedRound));
489 if (keyEpsilonVariable)
499 if (keyEpsilonVariable)
490 keyEpsilon = qAbs(currentIntervalStartKey-keyAxis->pixelToCoord(keyAxis->coordToPixel(currentIntervalStartKey)+1.0*reversedFactor));
500 keyEpsilon = qAbs(currentIntervalStartKey-keyAxis->pixelToCoord(keyAxis->coordToPixel(currentIntervalStartKey)+1.0*reversedFactor));
491 intervalDataCount = 1;
501 intervalDataCount = 1;
492 }
502 }
493 ++it;
503 ++it;
494 }
504 }
495 // handle last interval:
505 // handle last interval:
496 if (intervalDataCount >= 2) // last pixel had multiple data points, consolidate them
506 if (intervalDataCount >= 2) // last pixel had multiple data points, consolidate them
497 {
507 {
498 // determine value pixel span and add as many points in interval to maintain certain vertical data density (this is specific to scatter plot):
508 // 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));
509 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
510 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;
511 QVector<QCPData>::const_iterator intervalIt = currentIntervalStart;
502 int c = 0;
512 int c = 0;
503 while (intervalIt != it)
513 while (intervalIt != it)
504 {
514 {
505 if ((c % dataModulo == 0 || intervalIt == minValueIt || intervalIt == maxValueIt) && (*intervalIt).value > valueMinRange && (*intervalIt).value < valueMaxRange)
515 if ((c % dataModulo == 0 || intervalIt == minValueIt || intervalIt == maxValueIt) && (*intervalIt).value > valueMinRange && (*intervalIt).value < valueMaxRange)
506 scatterData->append((*intervalIt));
516 scatterData->append((*intervalIt));
507 ++c;
517 ++c;
508 ++intervalIt;
518 ++intervalIt;
509 }
519 }
510 } else if ((*currentIntervalStart).value > valueMinRange && (*currentIntervalStart).value < valueMaxRange)
520 } else if ((*currentIntervalStart).value > valueMinRange && (*currentIntervalStart).value < valueMaxRange)
511 scatterData->append(*currentIntervalStart);
521 scatterData->append(*currentIntervalStart);
512 }
522 }
513 } else // don't use adaptive sampling algorithm, transfer points one-to-one from the map into the output parameters
523 } else // don't use adaptive sampling algorithm, transfer points one-to-one from the map into the output parameters
514 {
524 {
515 QVector<QCPData> *dataVector = 0;
525 QVector<QCPData> *dataVector = 0;
516 if (lineData)
526 if (lineData)
517 {
527 {
518 dataVector = lineData;
528 dataVector = lineData;
519 }
529 }
520 else if (scatterData)
530 else if (scatterData)
521 dataVector = scatterData;
531 dataVector = scatterData;
522 if (dataVector)
532 if (dataVector)
523 {
533 {
524 QVector<QCPData>::const_iterator it = lower;
534 QVector<QCPData>::const_iterator it = lower;
525 QVector<QCPData>::const_iterator upperEnd = upper+1;
535 QVector<QCPData>::const_iterator upperEnd = upper+1;
526 dataVector->reserve(dataCount+2); // +2 for possible fill end points
536 dataVector->reserve(dataCount+2); // +2 for possible fill end points
527 while (it != upperEnd)
537 while (it != upperEnd)
528 {
538 {
529 dataVector->append(*it);
539 dataVector->append(*it);
530 ++it;
540 ++it;
531 }
541 }
532 }
542 }
533 if (lineData && scatterData)
543 if (lineData && scatterData)
534 *scatterData = *dataVector;
544 *scatterData = *dataVector;
535 }
545 }
536 }
546 }
537
547
538 QVector<QCPData>::const_iterator __lowerBoundDico_vect(QVector<QCPData>* vector,double key)
548 QVector<QCPData>::const_iterator __lowerBoundDico_vect(QVector<QCPData>* vector,double key)
539 {
549 {
540 int DX=vector->size()/2;
550 int DX=vector->size()/2;
541 int pos=DX;
551 int pos=DX;
542 // double test=(*vector)[vector->length()-1].key;
552 // double test=(*vector)[vector->length()-1].key;
543 if(key>((*vector)[vector->length()-1].key))
553 if(key>((*vector)[vector->length()-1].key))
544 return vector->constEnd();
554 return vector->constEnd();
545 if(key<((*vector)[0].key))
555 if(key<((*vector)[0].key))
546 return vector->constBegin();
556 return vector->constBegin();
547 while (DX>1)
557 while (DX>1)
548 {
558 {
549 DX=DX/2;
559 DX=DX/2;
550 if((*vector)[pos].key > key)
560 if((*vector)[pos].key > key)
551 {
561 {
552 pos-=DX;
562 pos-=DX;
553 }
563 }
554 else
564 else
555 {
565 {
556 pos+=DX;
566 pos+=DX;
557 }
567 }
558 }
568 }
559 if((*vector)[pos].key >= key)
569 if((*vector)[pos].key >= key)
560 return vector->constBegin()+pos;
570 return vector->constBegin()+pos;
561 return vector->constBegin()+pos+1;
571 return vector->constBegin()+pos+1;
562 }
572 }
563
573
564
574
565 QVector<QCPData>::const_iterator __upperBoundDico_vect(QVector<QCPData>* vector,double key)
575 QVector<QCPData>::const_iterator __upperBoundDico_vect(QVector<QCPData>* vector,double key)
566 {
576 {
567 int DX=vector->size()/2;
577 int DX=vector->size()/2;
568 int pos=DX;
578 int pos=DX;
569 if(key>((*vector)[vector->length()-1].key))
579 if(key>((*vector)[vector->length()-1].key))
570 return vector->constEnd();
580 return vector->constEnd();
571 if(key<((*vector)[0].key))
581 if(key<((*vector)[0].key))
572 return vector->constBegin();
582 return vector->constBegin();
573 while (DX>1)
583 while (DX>1)
574 {
584 {
575 DX=DX/2;
585 DX=DX/2;
576 if((*vector)[pos].key > key)
586 if((*vector)[pos].key > key)
577 {
587 {
578 pos-=DX;
588 pos-=DX;
579 }
589 }
580 else
590 else
581 {
591 {
582 pos+=DX;
592 pos+=DX;
583 }
593 }
584 }
594 }
585 return vector->constBegin()+pos+1;
595 return vector->constBegin()+pos+1;
586 }
596 }
587
597
588
598
589 void QCPGraphVect::getVisibleDataBounds(QVector<QCPData>::const_iterator &lower, QVector<QCPData>::const_iterator &upper) const
599 void QCPGraphVect::getVisibleDataBounds(QVector<QCPData>::const_iterator &lower, QVector<QCPData>::const_iterator &upper) const
590 {
600 {
591 if (!mKeyAxis) { qDebug() << Q_FUNC_INFO << "invalid key axis"; return; }
601 if (!mKeyAxis) { qDebug() << Q_FUNC_INFO << "invalid key axis"; return; }
592 if (mData->isEmpty())
602 if (mData->isEmpty())
593 {
603 {
594 lower = mData->constEnd();
604 lower = mData->constEnd();
595 upper = mData->constEnd();
605 upper = mData->constEnd();
596 return;
606 return;
597 }
607 }
598 QVector<QCPData>::const_iterator lbound = __lowerBoundDico_vect(mData,mKeyAxis.data()->range().lower);
608 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);
609 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
610 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
611 bool highoutlier = ubound != mData->constEnd(); // indicates whether there exist points above axis range
602
612
603 lower = (lowoutlier ? lbound-1 : lbound); // data point range that will be actually drawn
613 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
614 upper = (highoutlier ? ubound : ubound-1); // data point range that will be actually drawn
605 }
615 }
606
616
607 int QCPGraphVect::countDataInBounds(const QVector<QCPData>::const_iterator &lower, const QVector<QCPData>::const_iterator &upper, int maxCount) const
617 int QCPGraphVect::countDataInBounds(const QVector<QCPData>::const_iterator &lower, const QVector<QCPData>::const_iterator &upper, int maxCount) const
608 {
618 {
609 if (upper == mData->constEnd() && lower == mData->constEnd())
619 if (upper == mData->constEnd() && lower == mData->constEnd())
610 return 0;
620 return 0;
611 QVector<QCPData>::const_iterator it = lower;
621 QVector<QCPData>::const_iterator it = lower;
612 int count = 1;
622 int count = 1;
613 while (it != upper && count < maxCount)
623 while (it != upper && count < maxCount)
614 {
624 {
615 ++it;
625 ++it;
616 ++count;
626 ++count;
617 }
627 }
618 return count;
628 return count;
619 }
629 }
@@ -1,38 +1,39
1 #ifndef QCUSTOMPLOTVECT_H
1 #ifndef QCUSTOMPLOTVECT_H
2 #define QCUSTOMPLOTVECT_H
2 #define QCUSTOMPLOTVECT_H
3
3
4 #include <QWidget>
4 #include <QWidget>
5 #include <qcustomplot.h>
5 #include <qcustomplot.h>
6
6
7 class QCPGraphVect : public QCPGraph
7 class QCPGraphVect : public QCPGraph
8 {
8 {
9 Q_OBJECT
9 Q_OBJECT
10 public:
10 public:
11 explicit QCPGraphVect(QCPAxis *keyAxis, QCPAxis *valueAxis);
11 explicit QCPGraphVect(QCPAxis *keyAxis, QCPAxis *valueAxis);
12 ~QCPGraphVect();
12 ~QCPGraphVect();
13 QVector<QCPData> *data() const { return mData; }
13 QVector<QCPData> *data() const { return mData; }
14 void setData(QVector<QCPData> *data);
14 void setData(QVector<QCPData> *data);
15 QVector<QCPData>* getVisibleData();
15 protected:
16 protected:
16 QVector<QCPData>* mData;
17 QVector<QCPData>* mData;
17 virtual void draw(QCPPainter *painter);
18 virtual void draw(QCPPainter *painter);
18 virtual QCPRange getKeyRange(bool &foundRange, SignDomain inSignDomain, bool includeErrors) const; // overloads base class interface
19 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 virtual QCPRange getValueRange(bool &foundRange, SignDomain inSignDomain, bool includeErrors) const;
20 void getPreparedData(QVector<QCPData> *lineData, QVector<QCPData> *scatterData) const;
21 void getPreparedData(QVector<QCPData> *lineData, QVector<QCPData> *scatterData) const;
21 void getVisibleDataBounds(QVector<QCPData>::const_iterator &lower, QVector<QCPData>::const_iterator &upper) const;
22 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 int countDataInBounds(const QVector<QCPData>::const_iterator &lower, const QVector<QCPData>::const_iterator &upper, int maxCount) const;
23
24
24 void getPlotData(QVector<QPointF> *lineData, QVector<QCPData> *scatterData) const;
25 void getPlotData(QVector<QPointF> *lineData, QVector<QCPData> *scatterData) const;
25 void getLinePlotData(QVector<QPointF> *linePixelData, QVector<QCPData> *scatterData) const;
26 void getLinePlotData(QVector<QPointF> *linePixelData, QVector<QCPData> *scatterData) const;
26 };
27 };
27
28
28 class QCustomPlotVect : public QCustomPlot
29 class QCustomPlotVect : public QCustomPlot
29 {
30 {
30 Q_OBJECT
31 Q_OBJECT
31 public:
32 public:
32 QCustomPlotVect(QWidget *parent = 0);
33 QCustomPlotVect(QWidget *parent = 0);
33 ~QCustomPlotVect();
34 ~QCustomPlotVect();
34 QCPGraphVect *addGraph(QCPAxis *keyAxis=0, QCPAxis *valueAxis=0);
35 QCPGraphVect *addGraph(QCPAxis *keyAxis=0, QCPAxis *valueAxis=0);
35 protected:
36 protected:
36 };
37 };
37
38
38 #endif // QCUSTOMPLOTVECT_H
39 #endif // QCUSTOMPLOTVECT_H
@@ -1,644 +1,644
1 /*------------------------------------------------------------------------------
1 /*------------------------------------------------------------------------------
2 -- This file is a part of the QLop Software
2 -- This file is a part of the QLop Software
3 -- Copyright (C) 2015, Plasma Physics Laboratory - CNRS
3 -- Copyright (C) 2015, Plasma Physics Laboratory - CNRS
4 --
4 --
5 -- This program is free software; you can redistribute it and/or modify
5 -- This program is free software; you can redistribute it and/or modify
6 -- it under the terms of the GNU General Public License as published by
6 -- it under the terms of the GNU General Public License as published by
7 -- the Free Software Foundation; either version 2 of the License, or
7 -- the Free Software Foundation; either version 2 of the License, or
8 -- (at your option) any later version.
8 -- (at your option) any later version.
9 --
9 --
10 -- This program is distributed in the hope that it will be useful,
10 -- This program is distributed in the hope that it will be useful,
11 -- but WITHOUT ANY WARRANTY; without even the implied warranty of
11 -- but WITHOUT ANY WARRANTY; without even the implied warranty of
12 -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 -- GNU General Public License for more details.
13 -- GNU General Public License for more details.
14 --
14 --
15 -- You should have received a copy of the GNU General Public License
15 -- You should have received a copy of the GNU General Public License
16 -- along with this program; if not, write to the Free Software
16 -- along with this program; if not, write to the Free Software
17 -- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17 -- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 -------------------------------------------------------------------------------*/
18 -------------------------------------------------------------------------------*/
19 /*-- Author : Alexis Jeandet
19 /*-- Author : Alexis Jeandet
20 -- Mail : alexis.jeandet@member.fsf.org
20 -- Mail : alexis.jeandet@member.fsf.org
21 ----------------------------------------------------------------------------*/
21 ----------------------------------------------------------------------------*/
22 #include "SocExplorerPlot.h"
22 #include "SocExplorerPlot.h"
23 #include <QSvgGenerator>
23 #include <QSvgGenerator>
24 #include <qcpdocumentobject.h>
24 #include <qcpdocumentobject.h>
25 #include <QPdfWriter>
25 #include <QPdfWriter>
26 #include <QPrinter>
26 #include <QPrinter>
27
27
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 QCustomPlotVect(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);
35 this->m_plot->axisRect()->setRangeZoom(Qt::Horizontal|Qt::Vertical);
35 this->m_plot->axisRect()->setRangeZoom(Qt::Horizontal|Qt::Vertical);
36 this->m_mainlayout = new QGridLayout(this);
36 this->m_mainlayout = new QGridLayout(this);
37 this->setLayout(this->m_mainlayout);
37 this->setLayout(this->m_mainlayout);
38 this->m_mainlayout->addWidget(this->m_plot);
38 this->m_mainlayout->addWidget(this->m_plot);
39 this->setMinimumSize(400,300);
39 this->setMinimumSize(400,300);
40 this->setFocusPolicy(Qt::WheelFocus);
40 this->setFocusPolicy(Qt::WheelFocus);
41 this->m_plot->setAttribute(Qt::WA_TransparentForMouseEvents);
41 this->m_plot->setAttribute(Qt::WA_TransparentForMouseEvents);
42 this->ctrl_hold = false;
42 this->ctrl_hold = false;
43 this->shift_hold = false;
43 this->shift_hold = false;
44 this->mouse_hold = false;
44 this->mouse_hold = false;
45 this->m_plot->setNoAntialiasingOnDrag(true);
45 this->m_plot->setNoAntialiasingOnDrag(true);
46 this->show();
46 this->show();
47 this->m_plot->legend->setVisible(true);
47 this->m_plot->legend->setVisible(true);
48 }
48 }
49
49
50 SocExplorerPlot::~SocExplorerPlot()
50 SocExplorerPlot::~SocExplorerPlot()
51 {
51 {
52 delete mRubberBand;
52 delete mRubberBand;
53 }
53 }
54
54
55 void SocExplorerPlot::show()
55 void SocExplorerPlot::show()
56 {
56 {
57 QWidget::show();
57 QWidget::show();
58 }
58 }
59
59
60 void SocExplorerPlot::replot()
60 void SocExplorerPlot::replot()
61 {
61 {
62 this->m_plot->replot();
62 this->m_plot->replot();
63 }
63 }
64
64
65 void SocExplorerPlot::exportToSVG(const QString &fileName)
65 void SocExplorerPlot::exportToSVG(const QString &fileName)
66 {
66 {
67 QSvgGenerator printer;
67 QSvgGenerator printer;
68 printer.setFileName(fileName);
68 printer.setFileName(fileName);
69 QCPPainter qcpPainter;
69 QCPPainter qcpPainter;
70 qcpPainter.begin(&printer);
70 qcpPainter.begin(&printer);
71 m_plot->toPainter(&qcpPainter, m_plot->width(), m_plot->height());
71 m_plot->toPainter(&qcpPainter, m_plot->width(), m_plot->height());
72 qcpPainter.end();
72 qcpPainter.end();
73 }
73 }
74
74
75 void SocExplorerPlot::exportToPDF(const QString &fileName)
75 void SocExplorerPlot::exportToPDF(const QString &fileName)
76 {
76 {
77 QPrinter printer(QPrinter::HighResolution);
77 QPrinter printer(QPrinter::HighResolution);
78 printer.setOutputFormat(QPrinter::PdfFormat);
78 printer.setOutputFormat(QPrinter::PdfFormat);
79 printer.setOrientation(QPrinter::Landscape);
79 printer.setOrientation(QPrinter::Landscape);
80 printer.setOutputFileName(fileName);
80 printer.setOutputFileName(fileName);
81 printer.setFullPage(true);
81 printer.setFullPage(true);
82 QCPPainter qcpPainter;
82 QCPPainter qcpPainter;
83 qcpPainter.begin(&printer);
83 qcpPainter.begin(&printer);
84 m_plot->toPainter(&qcpPainter, printer.width(), printer.height());
84 m_plot->toPainter(&qcpPainter, printer.width(), printer.height());
85 qcpPainter.end();
85 qcpPainter.end();
86 }
86 }
87
87
88 void SocExplorerPlot::addAction(SocExplorerPlotActions *action)
88 void SocExplorerPlot::addAction(SocExplorerPlotActions *action)
89 {
89 {
90 this->m_actions.append(action);
90 this->m_actions.append(action);
91 QWidget::addAction((QAction*)action);
91 QWidget::addAction((QAction*)action);
92 }
92 }
93
93
94 QVector<QCPData> *SocExplorerPlot::getVisibleData(int graphIndex)
94 QVector<QCPData> *SocExplorerPlot::getVisibleData(int graphIndex)
95 {
95 {
96 QVector<QCPData> *wholeData=((QCPGraphVect*)m_plot->graph(graphIndex))->data();
96 QVector<QCPData> *visibleData=((QCPGraphVect*)m_plot->graph(graphIndex))->getVisibleData();
97 // m_plot->xAxis->
97 return visibleData;
98 }
98 }
99
99
100 void SocExplorerPlot::setTitle(QString title)
100 void SocExplorerPlot::setTitle(QString title)
101 {
101 {
102 Q_UNUSED(title)
102 Q_UNUSED(title)
103 //this->m_plot->setTitle(title);
103 //this->m_plot->setTitle(title);
104 /*!
104 /*!
105 @todo Function borcken fixe this!
105 @todo Function borcken fixe this!
106 */
106 */
107 emit titleChanged(title);
107 emit titleChanged(title);
108 this->repaint();
108 this->repaint();
109 }
109 }
110
110
111 void SocExplorerPlot::setXaxisLabel(QString label)
111 void SocExplorerPlot::setXaxisLabel(QString label)
112 {
112 {
113 this->m_plot->xAxis->setLabel(label);
113 this->m_plot->xAxis->setLabel(label);
114 this->repaint();
114 this->repaint();
115 }
115 }
116
116
117 void SocExplorerPlot::setYaxisLabel(QString label)
117 void SocExplorerPlot::setYaxisLabel(QString label)
118 {
118 {
119 this->m_plot->yAxis->setLabel(label);
119 this->m_plot->yAxis->setLabel(label);
120 this->repaint();
120 this->repaint();
121 }
121 }
122
122
123 void SocExplorerPlot::setXaxisRange(double lower, double upper)
123 void SocExplorerPlot::setXaxisRange(double lower, double upper)
124 {
124 {
125 this->m_plot->xAxis->setRange(lower,upper);
125 this->m_plot->xAxis->setRange(lower,upper);
126 }
126 }
127
127
128 void SocExplorerPlot::setYaxisRange(double lower, double upper)
128 void SocExplorerPlot::setYaxisRange(double lower, double upper)
129 {
129 {
130 this->m_plot->yAxis->setRange(lower,upper);
130 this->m_plot->yAxis->setRange(lower,upper);
131 }
131 }
132
132
133
133
134 void SocExplorerPlot::rescaleAxis()
134 void SocExplorerPlot::rescaleAxis()
135 {
135 {
136 this->m_plot->rescaleAxes();
136 this->m_plot->rescaleAxes();
137 this->m_plot->replot();
137 this->m_plot->replot();
138 }
138 }
139
139
140 void SocExplorerPlot::setLegendFont(QFont font)
140 void SocExplorerPlot::setLegendFont(QFont font)
141 {
141 {
142 this->m_plot->legend->setFont(font);
142 this->m_plot->legend->setFont(font);
143 this->repaint();
143 this->repaint();
144 }
144 }
145
145
146 void SocExplorerPlot::setLegendSelectedFont(QFont font)
146 void SocExplorerPlot::setLegendSelectedFont(QFont font)
147 {
147 {
148 this->m_plot->legend->setSelectedFont(font);
148 this->m_plot->legend->setSelectedFont(font);
149 this->repaint();
149 this->repaint();
150 }
150 }
151
151
152 void SocExplorerPlot::setAdaptativeSampling(int graphIndex, bool enable)
152 void SocExplorerPlot::setAdaptativeSampling(int graphIndex, bool enable)
153 {
153 {
154 this->m_plot->graph(graphIndex)->setAdaptiveSampling(enable);
154 this->m_plot->graph(graphIndex)->setAdaptiveSampling(enable);
155 }
155 }
156
156
157 void SocExplorerPlot::setUseFastVector(int graphIndex, bool enable)
157 void SocExplorerPlot::setUseFastVector(int graphIndex, bool enable)
158 {
158 {
159 // TODO deprecated
159 // TODO deprecated
160 // this->m_plot->graph(graphIndex)->setUseFastVectors(enable);
160 // this->m_plot->graph(graphIndex)->setUseFastVectors(enable);
161 }
161 }
162
162
163 int SocExplorerPlot::addGraph()
163 int SocExplorerPlot::addGraph()
164 {
164 {
165 this->m_plot->addGraph();
165 this->m_plot->addGraph();
166 return this->m_plot->graphCount() -1;
166 return this->m_plot->graphCount() -1;
167 }
167 }
168
168
169 bool SocExplorerPlot::removeGraph(int graphIndex)
169 bool SocExplorerPlot::removeGraph(int graphIndex)
170 {
170 {
171 return this->m_plot->removeGraph(graphIndex);
171 return this->m_plot->removeGraph(graphIndex);
172 }
172 }
173
173
174 int SocExplorerPlot::graphCount()
174 int SocExplorerPlot::graphCount()
175 {
175 {
176 return m_plot->graphCount();
176 return m_plot->graphCount();
177 }
177 }
178
178
179 void SocExplorerPlot::removeAllGraphs()
179 void SocExplorerPlot::removeAllGraphs()
180 {
180 {
181 int graphCount=this->m_plot->graphCount();
181 int graphCount=this->m_plot->graphCount();
182 for(int i=0;i<graphCount;i++)
182 for(int i=0;i<graphCount;i++)
183 {
183 {
184 this->m_plot->removeGraph(0);
184 this->m_plot->removeGraph(0);
185 }
185 }
186 }
186 }
187
187
188
188
189 void SocExplorerPlot::setGraphName(int graphIndex,QString name)
189 void SocExplorerPlot::setGraphName(int graphIndex,QString name)
190 {
190 {
191 if(graphIndex<this->m_plot->graphCount())
191 if(graphIndex<this->m_plot->graphCount())
192 {
192 {
193 this->m_plot->graph(graphIndex)->setName(name);
193 this->m_plot->graph(graphIndex)->setName(name);
194 }
194 }
195 }
195 }
196
196
197
197
198 void SocExplorerPlot::setGraphData(int graphIndex, QList<QVariant> x, QList<QVariant> y)
198 void SocExplorerPlot::setGraphData(int graphIndex, QList<QVariant> x, QList<QVariant> y)
199 {
199 {
200 if((graphIndex<this->m_plot->graphCount()) && (x.count()==y.count()) && (x.at(0).type()==QVariant::Double))
200 if((graphIndex<this->m_plot->graphCount()) && (x.count()==y.count()) && (x.at(0).type()==QVariant::Double))
201 {
201 {
202 QVector<double> _x(x.count()), _y(y.count());
202 QVector<double> _x(x.count()), _y(y.count());
203 for(int i=0;i<x.count();i++)
203 for(int i=0;i<x.count();i++)
204 {
204 {
205 /*_x[i] = x.at(i).value<double>();
205 /*_x[i] = x.at(i).value<double>();
206 _y[i] = y.at(i).value<double>();*/
206 _y[i] = y.at(i).value<double>();*/
207 _x[i] = x.at(i).toDouble();
207 _x[i] = x.at(i).toDouble();
208 _y[i] = y.at(i).toDouble();
208 _y[i] = y.at(i).toDouble();
209 }
209 }
210 this->m_plot->graph(graphIndex)->setData(_x,_y);
210 this->m_plot->graph(graphIndex)->setData(_x,_y);
211 }
211 }
212 else
212 else
213 {
213 {
214 if((graphIndex<this->m_plot->graphCount()) && (x.count()==y.count()) && (x.at(0).type()==QVariant::DateTime))
214 if((graphIndex<this->m_plot->graphCount()) && (x.count()==y.count()) && (x.at(0).type()==QVariant::DateTime))
215 {
215 {
216 QVector<double> _x(x.count()), _y(y.count());
216 QVector<double> _x(x.count()), _y(y.count());
217 for(int i=0;i<x.count();i++)
217 for(int i=0;i<x.count();i++)
218 {
218 {
219 /*_x[i] = x.at(i).value<double>();
219 /*_x[i] = x.at(i).value<double>();
220 _y[i] = y.at(i).value<double>();*/
220 _y[i] = y.at(i).value<double>();*/
221 _x[i] = x.at(i).toDateTime().toMSecsSinceEpoch();
221 _x[i] = x.at(i).toDateTime().toMSecsSinceEpoch();
222 _y[i] = y.at(i).toDouble();
222 _y[i] = y.at(i).toDouble();
223 }
223 }
224 this->m_plot->graph(graphIndex)->setData(_x,_y);
224 this->m_plot->graph(graphIndex)->setData(_x,_y);
225 this->m_plot->xAxis->setTickLabelType(QCPAxis::ltDateTime);
225 this->m_plot->xAxis->setTickLabelType(QCPAxis::ltDateTime);
226 this->m_plot->xAxis->setDateTimeFormat("hh:mm:ss.zzz");
226 this->m_plot->xAxis->setDateTimeFormat("hh:mm:ss.zzz");
227
227
228 }
228 }
229 }
229 }
230 this->m_plot->replot();
230 this->m_plot->replot();
231 }
231 }
232
232
233 void SocExplorerPlot::setGraphData(int graphIndex, QCPDataMap *data, bool copy, bool replot)
233 void SocExplorerPlot::setGraphData(int graphIndex, QCPDataMap *data, bool copy, bool replot)
234 {
234 {
235 if((graphIndex<this->m_plot->graphCount()))// && (x.at(0).type()==QVariant::Double))
235 if((graphIndex<this->m_plot->graphCount()))// && (x.at(0).type()==QVariant::Double))
236 {
236 {
237 this->m_plot->graph(graphIndex)->setData(data,copy);
237 this->m_plot->graph(graphIndex)->setData(data,copy);
238 }
238 }
239 if(replot)
239 if(replot)
240 this->m_plot->replot();
240 this->m_plot->replot();
241 }
241 }
242
242
243 void SocExplorerPlot::setGraphData(int graphIndex,QVector<QCPData> *data, bool replot)
243 void SocExplorerPlot::setGraphData(int graphIndex,QVector<QCPData> *data, bool replot)
244 {
244 {
245 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))
246 {
246 {
247 ((QCPGraphVect*)this->m_plot->graph(graphIndex))->setData(data);
247 ((QCPGraphVect*)this->m_plot->graph(graphIndex))->setData(data);
248 }
248 }
249 if(replot)
249 if(replot)
250 this->m_plot->replot();
250 this->m_plot->replot();
251 }
251 }
252
252
253 void SocExplorerPlot::addGraphData(int graphIndex, QList<QVariant> x, QList<QVariant> y)
253 void SocExplorerPlot::addGraphData(int graphIndex, QList<QVariant> x, QList<QVariant> y)
254 {
254 {
255 if((graphIndex<this->m_plot->graphCount()) && (x.count()==y.count()))// && (x.at(0).type()==QVariant::Double))
255 if((graphIndex<this->m_plot->graphCount()) && (x.count()==y.count()))// && (x.at(0).type()==QVariant::Double))
256 {
256 {
257 QVector<double> _x(x.count()), _y(y.count());
257 QVector<double> _x(x.count()), _y(y.count());
258 for(int i=0;i<x.count();i++)
258 for(int i=0;i<x.count();i++)
259 {
259 {
260 /*_x[i] = x.at(i).value<double>();
260 /*_x[i] = x.at(i).value<double>();
261 _y[i] = y.at(i).value<double>();*/
261 _y[i] = y.at(i).value<double>();*/
262 _x[i] = x.at(i).toDouble();
262 _x[i] = x.at(i).toDouble();
263 _y[i] = y.at(i).toDouble();
263 _y[i] = y.at(i).toDouble();
264 }
264 }
265 this->m_plot->graph(graphIndex)->addData(_x,_y);
265 this->m_plot->graph(graphIndex)->addData(_x,_y);
266 }
266 }
267 this->m_plot->replot();
267 this->m_plot->replot();
268 }
268 }
269
269
270 void SocExplorerPlot::addGraphData(int graphIndex, QVariant x, QVariant y)
270 void SocExplorerPlot::addGraphData(int graphIndex, QVariant x, QVariant y)
271 {
271 {
272 if(graphIndex<this->m_plot->graphCount())// && (x.at(0).type()==QVariant::Double))
272 if(graphIndex<this->m_plot->graphCount())// && (x.at(0).type()==QVariant::Double))
273 {
273 {
274 this->m_plot->graph(graphIndex)->addData(x.toDouble(),y.toDouble());
274 this->m_plot->graph(graphIndex)->addData(x.toDouble(),y.toDouble());
275 }
275 }
276 this->m_plot->replot();
276 this->m_plot->replot();
277 }
277 }
278
278
279 void SocExplorerPlot::setGraphPen(int graphIndex,QPen pen)
279 void SocExplorerPlot::setGraphPen(int graphIndex,QPen pen)
280 {
280 {
281 if(graphIndex<this->m_plot->graphCount())
281 if(graphIndex<this->m_plot->graphCount())
282 {
282 {
283 this->m_plot->graph(graphIndex)->setPen(pen);
283 this->m_plot->graph(graphIndex)->setPen(pen);
284 }
284 }
285 }
285 }
286
286
287 QPen SocExplorerPlot::getGraphPen(int graphIndex)
287 QPen SocExplorerPlot::getGraphPen(int graphIndex)
288 {
288 {
289 if(graphIndex<this->m_plot->graphCount())
289 if(graphIndex<this->m_plot->graphCount())
290 {
290 {
291 return this->m_plot->graph(graphIndex)->pen();
291 return this->m_plot->graph(graphIndex)->pen();
292 }
292 }
293 return this->m_plot->graph()->pen();
293 return this->m_plot->graph()->pen();
294 }
294 }
295
295
296
296
297
297
298 void SocExplorerPlot::setGraphLineStyle(int graphIndex,QString lineStyle)
298 void SocExplorerPlot::setGraphLineStyle(int graphIndex,QString lineStyle)
299 {
299 {
300 if(graphIndex<this->m_plot->graphCount())
300 if(graphIndex<this->m_plot->graphCount())
301 {
301 {
302 if(!lineStyle.compare("none"))
302 if(!lineStyle.compare("none"))
303 {
303 {
304 this->m_plot->graph(graphIndex)->setLineStyle(QCPGraph::lsNone);
304 this->m_plot->graph(graphIndex)->setLineStyle(QCPGraph::lsNone);
305 return;
305 return;
306 }
306 }
307 if(!lineStyle.compare("line"))
307 if(!lineStyle.compare("line"))
308 {
308 {
309 this->m_plot->graph(graphIndex)->setLineStyle(QCPGraph::lsLine);
309 this->m_plot->graph(graphIndex)->setLineStyle(QCPGraph::lsLine);
310 return;
310 return;
311 }
311 }
312 if(!lineStyle.compare("stepleft"))
312 if(!lineStyle.compare("stepleft"))
313 {
313 {
314 this->m_plot->graph(graphIndex)->setLineStyle(QCPGraph::lsStepLeft);
314 this->m_plot->graph(graphIndex)->setLineStyle(QCPGraph::lsStepLeft);
315 return;
315 return;
316 }
316 }
317 if(!lineStyle.compare("stepright"))
317 if(!lineStyle.compare("stepright"))
318 {
318 {
319 this->m_plot->graph(graphIndex)->setLineStyle(QCPGraph::lsStepRight);
319 this->m_plot->graph(graphIndex)->setLineStyle(QCPGraph::lsStepRight);
320 return;
320 return;
321 }
321 }
322 if(!lineStyle.compare("stepcenter"))
322 if(!lineStyle.compare("stepcenter"))
323 {
323 {
324 this->m_plot->graph(graphIndex)->setLineStyle(QCPGraph::lsStepCenter);
324 this->m_plot->graph(graphIndex)->setLineStyle(QCPGraph::lsStepCenter);
325 return;
325 return;
326 }
326 }
327 if(!lineStyle.compare("impulse"))
327 if(!lineStyle.compare("impulse"))
328 {
328 {
329 this->m_plot->graph(graphIndex)->setLineStyle(QCPGraph::lsImpulse);
329 this->m_plot->graph(graphIndex)->setLineStyle(QCPGraph::lsImpulse);
330 return;
330 return;
331 }
331 }
332
332
333
333
334 }
334 }
335 }
335 }
336
336
337 void SocExplorerPlot::setGraphScatterStyle(int graphIndex,QString scatterStyle)
337 void SocExplorerPlot::setGraphScatterStyle(int graphIndex,QString scatterStyle)
338 {
338 {
339 if(graphIndex<this->m_plot->graphCount())
339 if(graphIndex<this->m_plot->graphCount())
340 {
340 {
341 if(!scatterStyle.compare("none"))
341 if(!scatterStyle.compare("none"))
342 {
342 {
343 this->m_plot->graph(graphIndex)->setScatterStyle(QCPScatterStyle::ssNone);
343 this->m_plot->graph(graphIndex)->setScatterStyle(QCPScatterStyle::ssNone);
344 return;
344 return;
345 }
345 }
346 if(!scatterStyle.compare("dot"))
346 if(!scatterStyle.compare("dot"))
347 {
347 {
348 this->m_plot->graph(graphIndex)->setScatterStyle(QCPScatterStyle::ssDot);
348 this->m_plot->graph(graphIndex)->setScatterStyle(QCPScatterStyle::ssDot);
349 return;
349 return;
350 }
350 }
351 if(!scatterStyle.compare("cross"))
351 if(!scatterStyle.compare("cross"))
352 {
352 {
353 this->m_plot->graph(graphIndex)->setScatterStyle(QCPScatterStyle::ssCross);
353 this->m_plot->graph(graphIndex)->setScatterStyle(QCPScatterStyle::ssCross);
354 return;
354 return;
355 }
355 }
356 if(!scatterStyle.compare("plus"))
356 if(!scatterStyle.compare("plus"))
357 {
357 {
358 this->m_plot->graph(graphIndex)->setScatterStyle(QCPScatterStyle::ssPlus);
358 this->m_plot->graph(graphIndex)->setScatterStyle(QCPScatterStyle::ssPlus);
359 return;
359 return;
360 }
360 }
361 if(!scatterStyle.compare("circle"))
361 if(!scatterStyle.compare("circle"))
362 {
362 {
363 this->m_plot->graph(graphIndex)->setScatterStyle(QCPScatterStyle::ssCircle);
363 this->m_plot->graph(graphIndex)->setScatterStyle(QCPScatterStyle::ssCircle);
364 return;
364 return;
365 }
365 }
366 if(!scatterStyle.compare("disc"))
366 if(!scatterStyle.compare("disc"))
367 {
367 {
368 this->m_plot->graph(graphIndex)->setScatterStyle(QCPScatterStyle::ssDisc);
368 this->m_plot->graph(graphIndex)->setScatterStyle(QCPScatterStyle::ssDisc);
369 return;
369 return;
370 }
370 }
371 if(!scatterStyle.compare("square"))
371 if(!scatterStyle.compare("square"))
372 {
372 {
373 this->m_plot->graph(graphIndex)->setScatterStyle(QCPScatterStyle::ssSquare);
373 this->m_plot->graph(graphIndex)->setScatterStyle(QCPScatterStyle::ssSquare);
374 return;
374 return;
375 }
375 }
376 if(!scatterStyle.compare("diamond"))
376 if(!scatterStyle.compare("diamond"))
377 {
377 {
378 this->m_plot->graph(graphIndex)->setScatterStyle(QCPScatterStyle::ssDiamond);
378 this->m_plot->graph(graphIndex)->setScatterStyle(QCPScatterStyle::ssDiamond);
379 return;
379 return;
380 }
380 }
381 if(!scatterStyle.compare("star"))
381 if(!scatterStyle.compare("star"))
382 {
382 {
383 this->m_plot->graph(graphIndex)->setScatterStyle(QCPScatterStyle::ssStar);
383 this->m_plot->graph(graphIndex)->setScatterStyle(QCPScatterStyle::ssStar);
384 return;
384 return;
385 }
385 }
386 if(!scatterStyle.compare("triangle"))
386 if(!scatterStyle.compare("triangle"))
387 {
387 {
388 this->m_plot->graph(graphIndex)->setScatterStyle(QCPScatterStyle::ssTriangle);
388 this->m_plot->graph(graphIndex)->setScatterStyle(QCPScatterStyle::ssTriangle);
389 return;
389 return;
390 }
390 }
391 if(!scatterStyle.compare("invertedtriangle"))
391 if(!scatterStyle.compare("invertedtriangle"))
392 {
392 {
393 this->m_plot->graph(graphIndex)->setScatterStyle(QCPScatterStyle::ssTriangleInverted);
393 this->m_plot->graph(graphIndex)->setScatterStyle(QCPScatterStyle::ssTriangleInverted);
394 return;
394 return;
395 }
395 }
396 if(!scatterStyle.compare("crosssquare"))
396 if(!scatterStyle.compare("crosssquare"))
397 {
397 {
398 this->m_plot->graph(graphIndex)->setScatterStyle(QCPScatterStyle::ssCrossSquare);
398 this->m_plot->graph(graphIndex)->setScatterStyle(QCPScatterStyle::ssCrossSquare);
399 return;
399 return;
400 }
400 }
401 if(!scatterStyle.compare("plussquare"))
401 if(!scatterStyle.compare("plussquare"))
402 {
402 {
403 this->m_plot->graph(graphIndex)->setScatterStyle(QCPScatterStyle::ssPlusSquare);
403 this->m_plot->graph(graphIndex)->setScatterStyle(QCPScatterStyle::ssPlusSquare);
404 return;
404 return;
405 }
405 }
406 if(!scatterStyle.compare("crosscircle"))
406 if(!scatterStyle.compare("crosscircle"))
407 {
407 {
408 this->m_plot->graph(graphIndex)->setScatterStyle(QCPScatterStyle::ssCrossCircle);
408 this->m_plot->graph(graphIndex)->setScatterStyle(QCPScatterStyle::ssCrossCircle);
409 return;
409 return;
410 }
410 }
411 if(!scatterStyle.compare("pluscircle"))
411 if(!scatterStyle.compare("pluscircle"))
412 {
412 {
413 this->m_plot->graph(graphIndex)->setScatterStyle(QCPScatterStyle::ssPlusCircle);
413 this->m_plot->graph(graphIndex)->setScatterStyle(QCPScatterStyle::ssPlusCircle);
414 return;
414 return;
415 }
415 }
416 if(!scatterStyle.compare("peace"))
416 if(!scatterStyle.compare("peace"))
417 {
417 {
418 this->m_plot->graph(graphIndex)->setScatterStyle(QCPScatterStyle::ssPeace);
418 this->m_plot->graph(graphIndex)->setScatterStyle(QCPScatterStyle::ssPeace);
419 return;
419 return;
420 }
420 }
421
421
422 }
422 }
423 }
423 }
424
424
425 void SocExplorerPlot::setXaxisTickLabelType(QCPAxis::LabelType type)
425 void SocExplorerPlot::setXaxisTickLabelType(QCPAxis::LabelType type)
426 {
426 {
427 this->m_plot->xAxis->setTickLabelType(type);
427 this->m_plot->xAxis->setTickLabelType(type);
428 }
428 }
429
429
430 void SocExplorerPlot::setXaxisDateTimeFormat(const QString &format)
430 void SocExplorerPlot::setXaxisDateTimeFormat(const QString &format)
431 {
431 {
432 this->m_plot->xAxis->setDateTimeFormat(format);
432 this->m_plot->xAxis->setDateTimeFormat(format);
433 }
433 }
434
434
435
435
436
436
437
437
438
438
439 void SocExplorerPlot::keyPressEvent(QKeyEvent * event)
439 void SocExplorerPlot::keyPressEvent(QKeyEvent * event)
440 {
440 {
441 switch(event->key())
441 switch(event->key())
442 {
442 {
443 case Qt::Key_Control:
443 case Qt::Key_Control:
444 this->ctrl_hold = true;
444 this->ctrl_hold = true;
445 setCursor(Qt::CrossCursor);
445 setCursor(Qt::CrossCursor);
446 break;
446 break;
447 case Qt::Key_Shift:
447 case Qt::Key_Shift:
448 this->shift_hold = true;
448 this->shift_hold = true;
449 break;
449 break;
450 case Qt::Key_M:
450 case Qt::Key_M:
451 this->rescaleAxis();
451 this->rescaleAxis();
452 break;
452 break;
453 case Qt::Key_Left:
453 case Qt::Key_Left:
454 if(!ctrl_hold)
454 if(!ctrl_hold)
455 {
455 {
456 move(-0.1,Qt::Horizontal);
456 move(-0.1,Qt::Horizontal);
457 }
457 }
458 else
458 else
459 {
459 {
460 zoom(2,this->width()/2,Qt::Horizontal);
460 zoom(2,this->width()/2,Qt::Horizontal);
461 }
461 }
462 break;
462 break;
463 case Qt::Key_Right:
463 case Qt::Key_Right:
464 if(!ctrl_hold)
464 if(!ctrl_hold)
465 {
465 {
466 move(0.1,Qt::Horizontal);
466 move(0.1,Qt::Horizontal);
467 }
467 }
468 else
468 else
469 {
469 {
470 zoom(0.5,this->width()/2,Qt::Horizontal);
470 zoom(0.5,this->width()/2,Qt::Horizontal);
471 }
471 }
472 break;
472 break;
473 case Qt::Key_Up:
473 case Qt::Key_Up:
474 if(!ctrl_hold)
474 if(!ctrl_hold)
475 {
475 {
476 move(0.1,Qt::Vertical);
476 move(0.1,Qt::Vertical);
477 }
477 }
478 else
478 else
479 {
479 {
480 zoom(0.5,this->height()/2,Qt::Vertical);
480 zoom(0.5,this->height()/2,Qt::Vertical);
481 }
481 }
482 break;
482 break;
483 case Qt::Key_Down:
483 case Qt::Key_Down:
484 if(!ctrl_hold)
484 if(!ctrl_hold)
485 {
485 {
486 move(-0.1,Qt::Vertical);
486 move(-0.1,Qt::Vertical);
487 }
487 }
488 else
488 else
489 {
489 {
490 zoom(2,this->height()/2,Qt::Vertical);
490 zoom(2,this->height()/2,Qt::Vertical);
491 }
491 }
492 break;
492 break;
493 default:
493 default:
494 QWidget::keyPressEvent(event);
494 QWidget::keyPressEvent(event);
495 break;
495 break;
496 }
496 }
497 }
497 }
498
498
499 void SocExplorerPlot::keyReleaseEvent(QKeyEvent * event)
499 void SocExplorerPlot::keyReleaseEvent(QKeyEvent * event)
500 {
500 {
501 switch(event->key())
501 switch(event->key())
502 {
502 {
503 case Qt::Key_Control:
503 case Qt::Key_Control:
504 event->accept();
504 event->accept();
505 this->ctrl_hold = false;
505 this->ctrl_hold = false;
506 break;
506 break;
507 case Qt::Key_Shift:
507 case Qt::Key_Shift:
508 event->accept();
508 event->accept();
509 this->shift_hold = false;
509 this->shift_hold = false;
510 break;
510 break;
511 default:
511 default:
512 QWidget::keyReleaseEvent(event);
512 QWidget::keyReleaseEvent(event);
513 break;
513 break;
514 }
514 }
515 setCursor(Qt::ArrowCursor);
515 setCursor(Qt::ArrowCursor);
516 }
516 }
517
517
518 void SocExplorerPlot::wheelEvent(QWheelEvent * event)
518 void SocExplorerPlot::wheelEvent(QWheelEvent * event)
519 {
519 {
520 double factor;
520 double factor;
521 double wheelSteps = event->delta()/120.0; // a single step delta is +/-120 usually
521 double wheelSteps = event->delta()/120.0; // a single step delta is +/-120 usually
522 if(ctrl_hold)
522 if(ctrl_hold)
523 {
523 {
524 if (event->orientation()==Qt::Vertical)//mRangeZoom.testFlag(Qt::Vertical))
524 if (event->orientation()==Qt::Vertical)//mRangeZoom.testFlag(Qt::Vertical))
525 {
525 {
526 setCursor(Qt::SizeVerCursor);
526 setCursor(Qt::SizeVerCursor);
527 factor = pow(this->m_plot->axisRect()->rangeZoomFactor(Qt::Vertical), wheelSteps);
527 factor = pow(this->m_plot->axisRect()->rangeZoomFactor(Qt::Vertical), wheelSteps);
528 zoom(factor,event->pos().y(),Qt::Vertical);
528 zoom(factor,event->pos().y(),Qt::Vertical);
529 }
529 }
530 QWidget::wheelEvent(event);
530 QWidget::wheelEvent(event);
531 return;
531 return;
532 }
532 }
533 if(shift_hold)
533 if(shift_hold)
534 {
534 {
535 if (event->orientation()==Qt::Vertical)//mRangeZoom.testFlag(Qt::Vertical))
535 if (event->orientation()==Qt::Vertical)//mRangeZoom.testFlag(Qt::Vertical))
536 {
536 {
537 setCursor(Qt::SizeHorCursor);
537 setCursor(Qt::SizeHorCursor);
538 factor = pow(this->m_plot->axisRect()->rangeZoomFactor(Qt::Horizontal), wheelSteps);
538 factor = pow(this->m_plot->axisRect()->rangeZoomFactor(Qt::Horizontal), wheelSteps);
539 zoom(factor,event->pos().x(),Qt::Horizontal);
539 zoom(factor,event->pos().x(),Qt::Horizontal);
540 }
540 }
541 QWidget::wheelEvent(event);
541 QWidget::wheelEvent(event);
542 return;
542 return;
543 }
543 }
544 move(wheelSteps/10,Qt::Horizontal);
544 move(wheelSteps/10,Qt::Horizontal);
545 QWidget::wheelEvent(event);
545 QWidget::wheelEvent(event);
546 }
546 }
547
547
548
548
549
549
550
550
551 void SocExplorerPlot::mousePressEvent(QMouseEvent *event)
551 void SocExplorerPlot::mousePressEvent(QMouseEvent *event)
552 {
552 {
553 if(event->button()==Qt::LeftButton)
553 if(event->button()==Qt::LeftButton)
554 {
554 {
555 if(ctrl_hold)
555 if(ctrl_hold)
556 {
556 {
557 setCursor(Qt::CrossCursor);
557 setCursor(Qt::CrossCursor);
558 mOrigin = event->pos();
558 mOrigin = event->pos();
559 mRubberBand->setGeometry(QRect(mOrigin, QSize()));
559 mRubberBand->setGeometry(QRect(mOrigin, QSize()));
560 mRubberBand->show();
560 mRubberBand->show();
561 }
561 }
562 else
562 else
563 {
563 {
564 setCursor(Qt::ClosedHandCursor);
564 setCursor(Qt::ClosedHandCursor);
565 mDragStart = event->pos();
565 mDragStart = event->pos();
566 this->mouse_hold = true;
566 this->mouse_hold = true;
567 DragStartHorzRange = this->m_plot->axisRect()->rangeDragAxis(Qt::Horizontal)->range();
567 DragStartHorzRange = this->m_plot->axisRect()->rangeDragAxis(Qt::Horizontal)->range();
568 DragStartVertRange = this->m_plot->axisRect()->rangeDragAxis(Qt::Vertical)->range();
568 DragStartVertRange = this->m_plot->axisRect()->rangeDragAxis(Qt::Vertical)->range();
569 }
569 }
570 }
570 }
571 QWidget::mousePressEvent(event);
571 QWidget::mousePressEvent(event);
572 }
572 }
573
573
574 void SocExplorerPlot::mouseReleaseEvent(QMouseEvent *event)
574 void SocExplorerPlot::mouseReleaseEvent(QMouseEvent *event)
575 {
575 {
576 if(event->button()==Qt::LeftButton)
576 if(event->button()==Qt::LeftButton)
577 {
577 {
578 this->mouse_hold = false;
578 this->mouse_hold = false;
579 }
579 }
580 if (mRubberBand->isVisible())
580 if (mRubberBand->isVisible())
581 {
581 {
582 const QRect & zoomRect = mRubberBand->geometry();
582 const QRect & zoomRect = mRubberBand->geometry();
583 int xp1, yp1, xp2, yp2;
583 int xp1, yp1, xp2, yp2;
584 zoomRect.getCoords(&xp1, &yp1, &xp2, &yp2);
584 zoomRect.getCoords(&xp1, &yp1, &xp2, &yp2);
585 double x1 = this->m_plot->xAxis->pixelToCoord(xp1);
585 double x1 = this->m_plot->xAxis->pixelToCoord(xp1);
586 double x2 = this->m_plot->xAxis->pixelToCoord(xp2);
586 double x2 = this->m_plot->xAxis->pixelToCoord(xp2);
587 double y1 = this->m_plot->yAxis->pixelToCoord(yp1);
587 double y1 = this->m_plot->yAxis->pixelToCoord(yp1);
588 double y2 = this->m_plot->yAxis->pixelToCoord(yp2);
588 double y2 = this->m_plot->yAxis->pixelToCoord(yp2);
589
589
590 this->m_plot->xAxis->setRange(x1, x2);
590 this->m_plot->xAxis->setRange(x1, x2);
591 this->m_plot->yAxis->setRange(y1, y2);
591 this->m_plot->yAxis->setRange(y1, y2);
592
592
593 mRubberBand->hide();
593 mRubberBand->hide();
594 this->m_plot->replot();
594 this->m_plot->replot();
595 }
595 }
596 setCursor(Qt::ArrowCursor);
596 setCursor(Qt::ArrowCursor);
597 QWidget::mouseReleaseEvent(event);
597 QWidget::mouseReleaseEvent(event);
598 }
598 }
599
599
600 void SocExplorerPlot::zoom(double factor, int center, Qt::Orientation orientation)
600 void SocExplorerPlot::zoom(double factor, int center, Qt::Orientation orientation)
601 {
601 {
602 QCPAxis* axis = this->m_plot->axisRect()->rangeZoomAxis(orientation);
602 QCPAxis* axis = this->m_plot->axisRect()->rangeZoomAxis(orientation);
603 axis->scaleRange(factor, axis->pixelToCoord(center));
603 axis->scaleRange(factor, axis->pixelToCoord(center));
604 this->m_plot->replot();
604 this->m_plot->replot();
605 }
605 }
606
606
607 void SocExplorerPlot::move(double factor, Qt::Orientation orientation)
607 void SocExplorerPlot::move(double factor, Qt::Orientation orientation)
608 {
608 {
609 QCPAxis* axis = this->m_plot->axisRect()->rangeDragAxis(orientation);
609 QCPAxis* axis = this->m_plot->axisRect()->rangeDragAxis(orientation);
610 double rg = (axis->range().upper - axis->range().lower)*(factor);
610 double rg = (axis->range().upper - axis->range().lower)*(factor);
611 axis->setRange(axis->range().lower+(rg), axis->range().upper+(rg));
611 axis->setRange(axis->range().lower+(rg), axis->range().upper+(rg));
612 this->m_plot->replot();
612 this->m_plot->replot();
613 }
613 }
614
614
615
615
616 void SocExplorerPlot::mouseMoveEvent(QMouseEvent *event)
616 void SocExplorerPlot::mouseMoveEvent(QMouseEvent *event)
617 {
617 {
618 if(mouse_hold)
618 if(mouse_hold)
619 {
619 {
620 QCPAxis* Haxis = this->m_plot->axisRect()->rangeDragAxis(Qt::Horizontal);
620 QCPAxis* Haxis = this->m_plot->axisRect()->rangeDragAxis(Qt::Horizontal);
621 QCPAxis* Vaxis = this->m_plot->axisRect()->rangeDragAxis(Qt::Vertical);
621 QCPAxis* Vaxis = this->m_plot->axisRect()->rangeDragAxis(Qt::Vertical);
622 double diff = Haxis->pixelToCoord(mDragStart.x()) - Haxis->pixelToCoord(event->pos().x());
622 double diff = Haxis->pixelToCoord(mDragStart.x()) - Haxis->pixelToCoord(event->pos().x());
623 Haxis->setRange(DragStartHorzRange.lower+diff, DragStartHorzRange.upper+diff);
623 Haxis->setRange(DragStartHorzRange.lower+diff, DragStartHorzRange.upper+diff);
624 diff = Vaxis->pixelToCoord(mDragStart.y()) - Vaxis->pixelToCoord(event->pos().y());
624 diff = Vaxis->pixelToCoord(mDragStart.y()) - Vaxis->pixelToCoord(event->pos().y());
625 Vaxis->setRange(DragStartVertRange.lower+diff, DragStartVertRange.upper+diff);
625 Vaxis->setRange(DragStartVertRange.lower+diff, DragStartVertRange.upper+diff);
626 this->m_plot->replot();
626 this->m_plot->replot();
627 }
627 }
628 if (mRubberBand->isVisible())
628 if (mRubberBand->isVisible())
629 {
629 {
630 mRubberBand->setGeometry(QRect(mOrigin, event->pos()).normalized());
630 mRubberBand->setGeometry(QRect(mOrigin, event->pos()).normalized());
631 }
631 }
632 QWidget::mouseMoveEvent(event);
632 QWidget::mouseMoveEvent(event);
633 }
633 }
634
634
635
635
636
636
637
637
638
638
639
639
640
640
641
641
642
642
643
643
644
644
General Comments 0
You need to be logged in to leave comments. Login now