##// END OF EJS Templates
plot view export works on cassini fgm data.
jeandet -
r8:c56bc5e5916b default
parent child
Show More
@@ -42,181 +42,202 CassiniDataFile::~CassiniDataFile()
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);
@@ -231,19 +252,51 void CassiniDataFile::run()
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
@@ -33,12 +33,17 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
@@ -57,7 +57,7 void CassiniTools::makePlot()
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
@@ -111,6 +111,17 void CassiniTools::export_view(int PID)
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
@@ -60,6 +60,16 void QCPGraphVect::setData(QVector<QCPDa
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; }
@@ -12,6 +12,7 public:
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);
@@ -93,8 +93,8 void SocExplorerPlot::addAction(SocExplo
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)
General Comments 0
You need to be logged in to leave comments. Login now