00001 #include <util/graph_inset.h>
00002
00003 #include <iostream>
00004
00005 #include <QSize>
00006 #include <QString>
00007 #include <QFile>
00008 #include <QTextStream>
00009
00010 #include <viewer.h>
00011 #include <util/palette.h>
00012
00013 #include <util/gl.h>
00014
00015 namespace util
00016 {
00017
00018 using std::endl;
00019 using std::cerr;
00020
00021 GraphInset::GraphInset(int nb_lines)
00022 : _numberOfLines(nb_lines)
00023 , initialized(false)
00024 , closed(true)
00025 {
00026 }
00027
00028 void GraphInset::readParms(const QString& section, util::Parms parms)
00029 {
00030 parms(section, "Size", windowSize);
00031 parms(section, "Position", windowPosition);
00032
00033 parms(section, "ShowAll", showAll);
00034 if(!showAll)
00035 {
00036 parms(section, "Show", showIndices);
00037 }
00038 else
00039 {
00040 showIndices.clear();
00041 for(size_t i = 0 ; i < _numberOfLines ; ++i)
00042 {
00043 showIndices.push_back(i+1);
00044 }
00045 }
00046 cerr << "Number of lines to be shown: " << showIndices.size() << endl;
00047
00048 parms.all(section, "LineColor", linesColor);
00049 parms.all(section, "LineWidth", linesWidth);
00050 parms.all(section, "LineMinMaxView", linesMinMaxView);
00051 parms.all(section, "LineOffset", linesOffset);
00052
00053 parms(section, "ContourColor", contourColor);
00054 parms(section, "ContourWidth", contourWidth);
00055 parms(section, "ContourOffset", contourOffset);
00056 parms(section, "TimeSpan", timeSpan);
00057 parms(section, "BackColor", backColor);
00058 parms(section, "BackOffset", backgroundOffset);
00059 parms(section, "ChangeSourceColor", changeSourceColor);
00060 parms(section, "ChangeSourceWidth", changeSourceWidth);
00061 parms(section, "ChangeSourceOffset", changeSourceOffset);
00062 parms(section, "KeepAllData", keepAllData);
00063 parms(section, "AutoOpenClose", autoOpenClose);
00064 check();
00065 }
00066
00067 void GraphInset::setNumberOfLines(size_t nb_lines)
00068 {
00069 if(_numberOfLines != nb_lines)
00070 {
00071 _numberOfLines = nb_lines;
00072 if(showAll)
00073 {
00074 showIndices.clear();
00075 for(size_t i = 0 ; i < nb_lines ; ++i)
00076 {
00077 showIndices.push_back(i);
00078 }
00079 }
00080 else
00081 {
00082 for(size_t i = 0 ; i < showIndices.size() ; ++i)
00083 {
00084 if(showIndices[i] > nb_lines)
00085 {
00086 cerr << "Warning, you are trying to show line " << showIndices[i] << " when there is only " << nb_lines << " to be seen" << endl;
00087 }
00088 }
00089 }
00090 }
00091 }
00092
00093 void GraphInset::clear()
00094 {
00095 data.clear();
00096 if(autoOpenClose)
00097 closeGraph();
00098 }
00099
00100 void GraphInset::addData( double t, const std::vector<double>& values, bool changed )
00101 {
00102 data.push_back(Data(t,values, changed));
00103 if(autoOpenClose)
00104 openGraph();
00105 if(time < t)
00106 time = t;
00107 }
00108
00109 void GraphInset::dataSourceChanged()
00110 {
00111 if(!data.empty())
00112 data.back().changed = true;
00113 }
00114
00115 void GraphInset::cleanData()
00116 {
00117 while(!data.empty() && (time - data.front().time) > timeSpan)
00118 {
00119 data.pop_front();
00120 }
00121 if(autoOpenClose && data.empty())
00122 closeGraph();
00123 }
00124
00125 void GraphInset::draw(Viewer* viewer, const util::Palette& palette)
00126 {
00127 if(!initialized)
00128 {
00129 cerr << "Trying to draw an uninitialized graph" << endl;
00130 return;
00131 }
00132 if(!keepAllData)
00133 cleanData();
00134 if(!closed)
00135 {
00136 glPushAttrib(GL_LIGHTING_BIT|GL_LINE_BIT|GL_POLYGON_BIT);
00137 glDisable(GL_LIGHTING);
00138 QSize wndSize = viewer->size();
00139 int x1,y1,x2,y2;
00140 if(windowPosition.x() < 0)
00141 x1 = wndSize.width() + windowPosition.x();
00142 else
00143 x1 = windowPosition.x();
00144 if(windowPosition.y() < 0)
00145 y1 = wndSize.height() + windowPosition.y();
00146 else
00147 y1 = windowPosition.y();
00148 x2 = x1+(int)windowSize.x();
00149 y2 = y1+(int)windowSize.y();
00150 viewer->startScreenCoordinatesSystem();
00151
00152 glPolygonMode(GL_FRONT, GL_FILL);
00153 if(backColor >= 0)
00154 {
00155 palette.useColor(backColor);
00156 glBegin(GL_POLYGON);
00157 glVertex3d(x1,y1,backgroundOffset);
00158 glVertex3d(x1,y2,backgroundOffset);
00159 glVertex3d(x2,y2,backgroundOffset);
00160 glVertex3d(x2,y1,backgroundOffset);
00161 glEnd();
00162 }
00163 glPolygonMode(GL_FRONT, GL_LINE);
00164 palette.useColor(contourColor);
00165 glLineWidth(contourWidth);
00166 glBegin(GL_POLYGON);
00167 glVertex3d(x1,y1,contourOffset);
00168 glVertex3d(x1,y2,contourOffset);
00169 glVertex3d(x2,y2,contourOffset);
00170 glVertex3d(x2,y1,contourOffset);
00171 glEnd();
00172 if((data.size() > 1) && (time - data.back().time) < timeSpan)
00173 {
00174 std::list<Data>::reverse_iterator it;
00175 double ratio_x = windowSize.x()/timeSpan;
00176 for(size_t idx = 0 ; idx < showIndices.size() ; ++idx)
00177 {
00178 size_t k = showIndices[idx]-1;
00179 if(k >= _numberOfLines)
00180 continue;
00181 glLineWidth(linesWidth[k]);
00182 double ratio_y = (windowSize.y()-contourWidth)/(linesMinMaxView[k][1] - linesMinMaxView[k][0]);
00183 double shift_y = linesMinMaxView[k][0];
00184 palette.useColor(linesColor[k]);
00185 glBegin(GL_LINE_STRIP);
00186 for(it = data.rbegin() ; it != data.rend() ; ++it)
00187 {
00188 const Data& d = *it;
00189 if((time - d.time) > timeSpan)
00190 break;
00191 const std::vector<double>& values = d.values;
00192 double x = x2 + (d.time - time)*ratio_x;
00193 glVertex3d(x, y2 - std::max(std::min((values[k]-shift_y)*ratio_y,(double)windowSize.y()), 0.0), linesOffset[k]);
00194 if(d.changed)
00195 {
00196 glEnd();
00197 glBegin(GL_LINE_STRIP);
00198 }
00199 }
00200 glEnd();
00201 }
00202 palette.useColor(changeSourceColor);
00203 glLineWidth(changeSourceWidth);
00204 glBegin(GL_LINES);
00205 for(it = data.rbegin() ; it != data.rend() ; ++it)
00206 {
00207 const Data& d = *it;
00208 if((time - d.time) > timeSpan)
00209 break;
00210 if(d.changed)
00211 {
00212
00213 double x = x2 + (d.time - time)*ratio_x;
00214 glVertex3d(x, y1, changeSourceOffset);
00215 glVertex3d(x, y2, changeSourceOffset);
00216 }
00217 }
00218 glEnd();
00219 }
00220 viewer->stopScreenCoordinatesSystem();
00221 glPopAttrib();
00222 }
00223 }
00224
00225 void GraphInset::drawWithName(size_t id, Viewer* viewer)
00226 {
00227 util::Palette palette;
00228 glPushName((GLuint)id);
00229 draw(viewer,palette);
00230 glPopName();
00231 }
00232
00233 void GraphInset::check()
00234 {
00235 initialized = false;
00236 if(_numberOfLines <= 0)
00237 {
00238 cerr << "Number of lines <= 0" << endl;
00239 return;
00240 }
00241 forall(const Data& d, data)
00242 {
00243 if(d.values.size() != _numberOfLines)
00244 {
00245 cerr << "Number of values inconsistant with the number of lines" << endl;
00246 return;
00247 }
00248 }
00249 if(linesWidth.size() < showIndices.size())
00250 {
00251 cerr << "Number of line widths < number of shown lines" << endl;
00252 return;
00253 }
00254 if(linesColor.size() < showIndices.size())
00255 {
00256 cerr << "Number of line colors < number of shown lines" << endl;
00257 return;
00258 }
00259 if(linesMinMaxView.size() < showIndices.size())
00260 {
00261 cerr << "Number of line min max views < number of shown lines" << endl;
00262 return;
00263 }
00264 if(linesOffset.size() < showIndices.size())
00265 {
00266 cerr << "Number of line offsets < number of shown lines" << endl;
00267 return;
00268 }
00269 forall(double& w, linesWidth)
00270 {
00271 if(w < 0)
00272 {
00273 cerr << "Line width < 0" << endl;
00274 return;
00275 }
00276 }
00277 forall(int& c, linesColor)
00278 {
00279 if(c < 0 || c > 255)
00280 {
00281 cerr << "Line color < 0 or > 255" << endl;
00282 return;
00283 }
00284 }
00285 if(contourWidth < 0)
00286 {
00287 cerr << "Contour width < 0" << endl;
00288 return;
00289 }
00290 if(contourColor < 0 || contourColor > 255)
00291 {
00292 cerr << "Contour color < 0 or > 255" << endl;
00293 return;
00294 }
00295 if(changeSourceWidth < 0)
00296 {
00297 cerr << "Source width < 0" << endl;
00298 return;
00299 }
00300 if(changeSourceColor < 0 || changeSourceColor > 255)
00301 {
00302 cerr << "Source color < 0 or > 255" << endl;
00303 return;
00304 }
00305 initialized = true;
00306 }
00307
00308 void GraphInset::closeGraph()
00309 {
00310 closed = true;
00311 }
00312
00313 void GraphInset::openGraph()
00314 {
00315 closed = false;
00316 }
00317
00318 bool GraphInset::writeCSV(const QString& filename)
00319 {
00320 QFile f(filename);
00321 if(!f.open(QIODevice::WriteOnly))
00322 {
00323 cerr << "Error, cannot open file " << filename.toStdString() << " for writing" << endl;
00324 return false;
00325 }
00326 QTextStream ts(&f);
00327 ts << "Time";
00328 for(size_t i = 0 ; i < _numberOfLines ; ++i)
00329 {
00330 ts << ",Data" << i;
00331 }
00332 ts << ",Source Changed\r\n";
00333 ts.setRealNumberNotation(QTextStream::SmartNotation);
00334 ts.setRealNumberPrecision(15);
00335 forall(const Data& d, data)
00336 {
00337 ts << d.time;
00338 for(size_t i = 0 ; i < _numberOfLines ; ++i)
00339 {
00340 ts << "," << d.values[i];
00341 }
00342 ts << (int)d.changed << "\r\n";
00343 }
00344 f.close();
00345 return true;
00346 }
00347
00348 }