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