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
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
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
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
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 }