contour.cpp

00001 #include <cmath>
00002 #include <fstream>
00003 #include "contour.h"
00004 
00005 #include <QFile>
00006 #include <QTextStream>
00007 #include <stdio.h>
00008 #include <QString>
00009 #include <QStringList>
00010 
00011 static QTextStream err(stderr);
00012 
00013 typedef util::Vector<3,double> Point3d;
00014 
00015 #if defined(__APPLE__) || defined(linux)
00016 #  include <sys/file.h>
00017 #endif
00018 
00019 #define REPORT_ERROR(filename, line_nb, error) \
00020   err << "Error in file " << filename << " on line " << line_nb << error << endl
00021 
00022 namespace util
00023 {
00025   Contour::Contour()
00026     : FileObject()
00027     , closed(true)
00028     , regular(true)
00029   {}
00030 
00038   Contour::Contour(std::string filename)
00039     : FileObject(filename)
00040     , closed(true)
00041     , regular(true)
00042   {
00043     reread();
00044   }
00045 
00046   Contour::Contour(const Contour& copy)
00047     : FileObject(copy)
00048     , pts(copy.pts)
00049     , max(copy.max)
00050     , min(copy.min)
00051     , closed(copy.closed)
00052     , regular(copy.regular)
00053   {
00054   }
00055 
00056   void Contour::reread() {
00057     closed = false;
00058     QString fn = QString::fromStdString(filename);
00059     QFile f(fn);
00060     if(!f.open(QIODevice::ReadOnly))
00061     {
00062       err << "Error opening file " << QString::fromStdString(filename) << ": " << f.errorString() << endl;
00063       return;
00064     }
00065 #if defined(__APPLE__) || defined(linux)
00066     flock(f.handle(), LOCK_SH);
00067 #endif
00068     QTextStream ts(&f);
00069     int ptid = 0, line_nb = 1;
00070 
00071     pts.clear();
00072 
00073     QString line = ts.readLine().trimmed();
00074     QStringList ver = line.split(" ");
00075     if(ver.size() != 3 or ver[0] != "cver")
00076     {
00077       err << "The file '" << fn << "' doesn't containt a valid contour" << endl;
00078       return;
00079     }
00080 
00081     bool ok;
00082     int vmaj = ver[1].toInt(&ok);
00083     if(!ok)
00084     {
00085       REPORT_ERROR(fn, line_nb, "The major version number is not a valid integer");
00086       return;
00087     }
00088 
00089     int vmin = ver[2].toInt(&ok);
00090     if(!ok)
00091     {
00092       REPORT_ERROR(fn, line_nb, "The minor version number is not a valid integer");
00093       return;
00094     }
00095 
00096     int version = 100*vmaj+vmin;
00097     if(version == 101)
00098     {
00099       while(!ts.atEnd())
00100       {
00101         ++line_nb;
00102         QString line = ts.readLine().trimmed();
00103         if(line.startsWith("name:"))
00104         {
00105           // Do nothing of the name
00106         }
00107         else if(line.startsWith("points:"))
00108         {
00109           QStringList nbpts = line.mid(7).trimmed().split(" ");
00110           if(nbpts.size() != 2)
00111           {
00112             REPORT_ERROR(fn, line_nb, "Error, there should be two values for the points number, not " << nbpts.size());
00113             return;
00114           }
00115           bool ok;
00116           int nb_pts = nbpts[1].toInt(&ok);
00117           if(!ok)
00118           {
00119             REPORT_ERROR(fn, line_nb, "Error, number of control points is not a number");
00120             return;
00121           }
00122           pts.resize(nb_pts);
00123         }
00124         else if(line.startsWith("type:"))
00125         {
00126           QString type = line.mid(5).trimmed().toLower();
00127           if(type == "closed")
00128             closed = true;
00129           else if(type == "open")
00130             closed = false;
00131           else
00132           {
00133             REPORT_ERROR(fn, line_nb, "Unknown contour type: " << type);
00134             return;
00135           }
00136         }
00137         else
00138         {
00139           if(ptid >= (int)pts.size())
00140           {
00141             REPORT_ERROR(fn, line_nb, "There are more control points defined than declared");
00142             return;
00143           }
00144           QStringList pt = line.split(" ");
00145           if(pt.size() != 4)
00146           {
00147             REPORT_ERROR(fn, line_nb, "A points should be described with four values");
00148             return;
00149           }
00150           bool ok;
00151           double x,y,z,m;
00152           x = pt[0].toDouble(&ok);
00153           if(!ok)
00154           {
00155             REPORT_ERROR(fn, line_nb, "Error, x coordinate is not a valid floating point value");
00156             return;
00157           }
00158           y = pt[1].toDouble(&ok);
00159           if(!ok)
00160           {
00161             REPORT_ERROR(fn, line_nb, "Error, y coordinate is not a valid floating point value");
00162             return;
00163           }
00164           z = pt[2].toDouble(&ok);
00165           if(!ok)
00166           {
00167             REPORT_ERROR(fn, line_nb, "Error, z coordinate is not a valid floating point value");
00168             return;
00169           }
00170           m = pt[3].toDouble(&ok);
00171           if(!ok)
00172           {
00173             REPORT_ERROR(fn, line_nb, "Error, m coordinate is not a valid floating point value");
00174             return;
00175           }
00176           Point3d v(x,y,z);
00177           pts[ptid++] = v;
00178         }
00179       }
00180     }
00181     else if(version == 102)
00182     {
00183       while(!ts.atEnd())
00184       {
00185         ++line_nb;
00186         QString line = ts.readLine().trimmed();
00187         if(line.startsWith("name:"))
00188         {
00189           // Do nothing of the name
00190         }
00191         else if(line.startsWith("points:"))
00192         {
00193           QStringList nbpts = line.mid(7).trimmed().split(" ");
00194           if(nbpts.size() != 2)
00195           {
00196             REPORT_ERROR(fn, line_nb, "Error, there should be two values for the points number, not " << nbpts.size());
00197             return;
00198           }
00199           bool ok;
00200           int nb_pts = nbpts[1].toInt(&ok);
00201           if(!ok)
00202           {
00203             REPORT_ERROR(fn, line_nb, "Error, number of control points is not a number");
00204             return;
00205           }
00206           pts.resize(nb_pts);
00207         }
00208         else if(line.startsWith("type:"))
00209         {
00210           QString type = line.mid(5).trimmed().toLower();
00211           if(type.size() != 2)
00212           {
00213             REPORT_ERROR(fn, line_nb, "Error reading contour type: '" << type << "'");
00214             return;
00215           }
00216           if(type[0] == 'c')
00217             closed = true;
00218           else if(type[0] == 'o')
00219             closed = false;
00220           else
00221           {
00222             REPORT_ERROR(fn, line_nb, "Unknown contour type: " << type);
00223             return;
00224           }
00225           if(type[1] == 'e')
00226           {
00227             regular = false;
00228             err << "Warning, this contour reader doesn't handle contours that are not regular" << endl;
00229           }
00230           else if(type[1] == 'r')
00231           {
00232             regular = true;
00233           }
00234           else
00235           {
00236             REPORT_ERROR(fn, line_nb, "Unknown contour type: " << type);
00237             return;
00238           }
00239         }
00240         else
00241         {
00242           if(ptid >= (int)pts.size())
00243           {
00244             REPORT_ERROR(fn, line_nb, "There are more control points defined than declared");
00245             return;
00246           }
00247           QStringList pt = line.split(" ");
00248           if(pt.size() != 4)
00249           {
00250             REPORT_ERROR(fn, line_nb, "A points should be described with four values");
00251             return;
00252           }
00253           bool ok;
00254           double x,y,z,m;
00255           x = pt[0].toDouble(&ok);
00256           if(!ok)
00257           {
00258             REPORT_ERROR(fn, line_nb, "Error, x coordinate is not a valid floating point value");
00259             return;
00260           }
00261           y = pt[1].toDouble(&ok);
00262           if(!ok)
00263           {
00264             REPORT_ERROR(fn, line_nb, "Error, y coordinate is not a valid floating point value");
00265             return;
00266           }
00267           z = pt[2].toDouble(&ok);
00268           if(!ok)
00269           {
00270             REPORT_ERROR(fn, line_nb, "Error, z coordinate is not a valid floating point value");
00271             return;
00272           }
00273           m = pt[3].toDouble(&ok);
00274           if(!ok)
00275           {
00276             REPORT_ERROR(fn, line_nb, "Error, m coordinate is not a valid floating point value");
00277             return;
00278           }
00279           Point3d v(x,y,z);
00280           pts[ptid++] = v;
00281         }
00282       }
00283     }
00284     else if(version == 103)
00285     {
00286       while(!ts.atEnd())
00287       {
00288         ++line_nb;
00289         QString line = ts.readLine().trimmed();
00290         if(line.startsWith("name:"))
00291         {
00292           // Do nothing of the name
00293         }
00294         else if(line.startsWith("points:"))
00295         {
00296           QStringList nbpts = line.mid(7).trimmed().split(" ");
00297           if(nbpts.size() != 2)
00298           {
00299             REPORT_ERROR(fn, line_nb, "Error, there should be two values for the points number, not " << nbpts.size());
00300             return;
00301           }
00302           bool ok;
00303           int nb_pts = nbpts[1].toInt(&ok);
00304           if(!ok)
00305           {
00306             REPORT_ERROR(fn, line_nb, "Error, number of control points is not a number");
00307             return;
00308           }
00309           pts.resize(nb_pts);
00310         }
00311         else if(line.startsWith("type:"))
00312         {
00313           QString type = line.mid(5).trimmed().toLower();
00314           if(type.size() != 2)
00315           {
00316             REPORT_ERROR(fn, line_nb, "Error reading contour type: '" << type << "'");
00317             return;
00318           }
00319           if(type[0] == 'c')
00320             closed = true;
00321           else if(type[0] == 'o')
00322             closed = false;
00323           else
00324           {
00325             REPORT_ERROR(fn, line_nb, "Unknown contour type: " << type);
00326             return;
00327           }
00328           if(type[1] == 'e')
00329           {
00330             regular = false;
00331             err << "Warning, this contour reader doesn't handle contours that are not regular" << endl;
00332           }
00333           else if(type[1] == 'r')
00334           {
00335             regular = true;
00336           }
00337           else
00338           {
00339             REPORT_ERROR(fn, line_nb, "Unknown contour type: " << type);
00340             return;
00341           }
00342         }
00343         else if(line.startsWith("samples:"))
00344         {
00345           // ignore that
00346         }
00347         else
00348         {
00349           if(ptid >= (int)pts.size())
00350           {
00351             REPORT_ERROR(fn, line_nb, "There are more control points defined than declared");
00352             return;
00353           }
00354           QStringList pt = line.split(" ");
00355           if(pt.size() != 4)
00356           {
00357             REPORT_ERROR(fn, line_nb, "A points should be described with four values");
00358             return;
00359           }
00360           bool ok;
00361           double x,y,z,m;
00362           x = pt[0].toDouble(&ok);
00363           if(!ok)
00364           {
00365             REPORT_ERROR(fn, line_nb, "Error, x coordinate is not a valid floating point value");
00366             return;
00367           }
00368           y = pt[1].toDouble(&ok);
00369           if(!ok)
00370           {
00371             REPORT_ERROR(fn, line_nb, "Error, y coordinate is not a valid floating point value");
00372             return;
00373           }
00374           z = pt[2].toDouble(&ok);
00375           if(!ok)
00376           {
00377             REPORT_ERROR(fn, line_nb, "Error, z coordinate is not a valid floating point value");
00378             return;
00379           }
00380           m = pt[3].toDouble(&ok);
00381           if(!ok)
00382           {
00383             REPORT_ERROR(fn, line_nb, "Error, m coordinate is not a valid floating point value");
00384             return;
00385           }
00386           Point3d v(x,y,z);
00387           pts[ptid++] = v;
00388         }
00389       }
00390     }
00391     else
00392     {
00393       REPORT_ERROR(fn, line_nb, "Cannot handle version " << vmaj << "  " << vmin);
00394       return;
00395     }
00396 
00397     if(ptid < (int)pts.size())
00398     {
00399       REPORT_ERROR(fn, line_nb, "There are less control points defined than declared");
00400       return;
00401     }
00402 
00403     if (closed) {
00404       pts.push_back(pts[0]);
00405       pts.push_back(pts[1]);
00406       pts.push_back(pts[2]);
00407     }
00408 #if defined(__APPLE__) || defined(linux)
00409     flock(f.handle(), LOCK_UN);
00410 #endif
00411     f.close();
00412   }
00413 
00415   Contour& Contour::operator=(const Contour& c) {
00416     pts = c.pts;
00417     max = c.max;
00418     min = c.min;
00419     closed = c.closed;
00420 
00421     return *this;
00422   }
00423 
00431   Vector<3,double> Contour::operator()(double t) const {
00432     if (t < 0.0) t = 0.0;
00433     else if (t > 1.0) t = 1.0;
00434 
00435     double k = 1.0 + double(pts.size() - 3) * t;
00436     int i = int(k) + 2;
00437     double p = k - floor(k);
00438 
00439     return
00440       pts[i - 3] * Basis0(p)
00441       + pts[i - 2] * Basis1(p)
00442       + pts[i - 1] * Basis2(p)
00443       + pts[i]     * Basis3(p);
00444   }
00445 
00447   const Vector<3,double>& Contour::getMax() const {
00448     return max;
00449   }
00450 
00452   const Vector<3,double>& Contour::getMin() const {
00453     return min;
00454   }
00455 
00464   double Contour::length(double a, double b, double dt) {
00465     if (a < 0.0) a = 0.0;
00466     if (a > 1.0) a = 1.0;
00467     if (b > 1.0) b = 1.0;
00468     if (b < a + dt) return 0.0;
00469 
00470     double l = 0.0;
00471     Vector<3,double> p = (*this)(a), q;
00472     while (a <= b) {
00473       a += dt;
00474       q = (*this)(a);
00475       l += norm(p-q);
00476       p = q;
00477     }
00478     return l;
00479   }
00480 
00489   double Contour::travel(double t, double l, double dt) {
00490     if (t < 0.0) t = 0.0;
00491     if (l < 0.0) return 0.0;
00492     if (l < dt) return t;
00493 
00494     Vector<3,double> start = (*this)(t);
00495     double t_length = 0.0;
00496     double u = t + dt;
00497     while (t_length < l && t < 1.0) {
00498       t_length += this->length(t, u, dt);
00499       t = u;
00500       u += dt;
00501     }
00502     return t;
00503   }
00504 
00509   Vector<3,double> Contour::tangent(double t, double dt) {
00510     Vector<3,double> r = (*this)(t + dt) - (*this)(t - dt);
00511     r.normalize();
00512     return r;
00513   }
00514 
00519   Vector<3,double> Contour::normal(double t, double dt) {
00520     Vector<3,double> tvec = tangent(t, dt);
00521     return Vector<3,double>(tvec.y(), tvec.x(), 0);
00522   }
00523 
00525   double Contour::Basis0(double t) const {
00526     return 1.0/6.0 * (-pow(t, 3) + 3 * pow(t, 2) - 3 * t + 1);
00527   }
00528 
00530   double Contour::Basis1(double t) const {
00531     return 1.0/6.0 * (3 * pow(t, 3) - 6 * pow(t, 2) + 4);
00532   }
00533 
00535   double Contour::Basis2(double t) const {
00536     return 1.0/6.0 * (-3 * pow(t, 3) + 3 * pow(t, 2) + 3 * t + 1);
00537   }
00538 
00540   double Contour::Basis3(double t) const {
00541     return 1.0/6.0 * (pow(t, 3));
00542   }
00543 
00544 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines
Generated on Fri May 31 15:37:53 2013 for VVE by  doxygen 1.6.3