00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00024
00025 #include <qvcore/qvdefines.h>
00026 #include <qvip/qvpolylinef.h>
00027 #include <qvip/qvpolyline.h>
00028 #include <qvmath/qvmatrixalgebra.h>
00029
00030 #include <iostream>
00031 #include <float.h>
00032
00034
00035
00036
00037 #ifndef DOXYGEN_IGNORE_THIS
00038 class ClassAuxIPE_F
00039 {
00040 public:
00041 double cost;
00042 int index;
00043 ClassAuxIPE_F *prev,*next;
00044 };
00045
00046 bool costLessThan(ClassAuxIPE_F* &s1,ClassAuxIPE_F* &s2)
00047 {
00048 return s1->cost < s2->cost;
00049 }
00050
00051 bool indexLessThan(ClassAuxIPE_F* &s1,ClassAuxIPE_F* &s2)
00052 {
00053 return s1->index < s2->index;
00054 }
00055
00056 inline double costElimination(const QVPolylineF &polyline,int ia, int ib, int ic)
00057 {
00058 double xA,yA,xB,yB,xC,yC;
00059 xA = polyline[ia].x(); yA=polyline[ia].y();
00060 xB = polyline[ib].x(); yB=polyline[ib].y();
00061 xC = polyline[ic].x(); yC=polyline[ic].y();
00062 if((xA != xC) or (yA != yC))
00063 return ABS(xA*(yC-yB) + xB*(yA-yC) + xC*(yB-yA)) / sqrt((xA-xC)*(xA-xC)+(yA-yC)*(yA-yC));
00064 else
00065 return sqrt((xB-xC)*(xB-xC)+(yB-yC)*(yB-yC));
00066 }
00067
00068 class auxLine_F {
00069 public:
00070 auxLine_F(double l1,double l2,double l3,bool ok) : l1(l1),l2(l2),l3(l3),ok(ok) {};
00071 double l1,l2,l3;
00072 bool ok;
00073 };
00074 #endif
00075
00076 double IterativePointElimination(const QVPolylineF &polyline, QVPolylineF &result,
00077 const double param, bool maxNumberOfPointsMethod,bool intersectLines,
00078 double *max_removed_cost)
00079 {
00080 const uInt tot_siz = polyline.size();
00081 QList<ClassAuxIPE_F*> list;
00082
00083
00084 result.clear();
00085
00086
00087 if(max_removed_cost != NULL) *max_removed_cost = 0.0;
00088
00089
00090
00091 if(polyline.size()<3)
00092 {
00093 result = polyline;
00094 return FLT_MAX;
00095 }
00096
00097
00098 for(uInt i=0;i<tot_siz;i++)
00099 list.push_back(new ClassAuxIPE_F);
00100
00101 for(uInt i=0;i<tot_siz;i++)
00102 {
00103 int ia = (i==0)?tot_siz-1:i-1, ib = i, ic = (i==tot_siz-1)?0:i+1;
00104 list[i]->cost = costElimination(polyline,ia,ib,ic);
00105 list[i]->index = ib;
00106 list[i]->prev = list[ia];
00107 list[i]->next = list[ic];
00108 }
00109 if(not polyline.closed)
00110 {
00111 list[0]->cost = FLT_MAX;
00112 list[tot_siz-1]->cost = FLT_MAX;
00113 }
00114 qSort(list.begin(),list.end(),costLessThan);
00115
00116
00117 while(TRUE)
00118 {
00119
00120 if( (list.size() == 3) or
00121 ((not maxNumberOfPointsMethod) and (list[0]->cost > param)) or
00122 ((maxNumberOfPointsMethod) and
00123 (list.size() <= static_cast<int>(param))) )
00124 break;
00125
00126
00127 ClassAuxIPE_F *elem = list.takeAt(0),
00128 *elemPrev = list.takeAt(list.indexOf(elem->prev)),
00129 *elemNext = list.takeAt(list.indexOf(elem->next));
00130 elemPrev->next = elem->next;
00131 elemNext->prev = elem->prev;
00132 if(elemPrev->cost != FLT_MAX)
00133 elemPrev->cost = costElimination(polyline,elemPrev->prev->index,
00134 elemPrev->index,
00135 elemPrev->next->index);
00136 if(elemNext->cost != FLT_MAX)
00137 elemNext->cost = costElimination(polyline,elemNext->prev->index,
00138 elemNext->index,
00139 elemNext->next->index);
00140
00141
00142 int here;
00143 for(int i=0;i<2;i++)
00144 {
00145 ClassAuxIPE_F* newelem = ((i==0)?elemNext:elemPrev);
00146 int first=0,last=list.size()-1;
00147 while (first <= last) {
00148 int mid = (first + last) / 2;
00149 if (newelem->cost > list[mid]->cost)
00150 first = mid + 1;
00151 else if (newelem->cost < list[mid]->cost)
00152 last = mid - 1;
00153 else
00154 {
00155 here = mid;
00156 break;
00157 }
00158 }
00159 if(first>last)
00160 here=first;
00161 list.insert(here,newelem);
00162
00163 }
00164
00165 if(max_removed_cost != NULL)
00166 if(elem->cost > *max_removed_cost)
00167 *max_removed_cost = elem->cost;
00168 delete elem;
00169 }
00170
00171
00172 double return_value = list.first()->cost;
00173
00174
00175 qSort(list.begin(),list.end(),indexLessThan);
00176
00177
00178 QList<ClassAuxIPE_F*>::iterator it = list.begin();
00179 if(intersectLines)
00180 {
00181
00182 double ratio_eig=1.0;
00183 QList<auxLine_F> lines;
00184 for(int i=0;i<list.size();i++)
00185 {
00186
00187 if((not polyline.closed) and (i==list.size()-1))
00188 break;
00189 int i1 = list[i]->index;
00190 int i2 = list[(i+1)%list.size()]->index;
00191 if(i2<i1) i2 += tot_siz;
00192 int dist = i2-i1+1;
00193 #define MIN_PIXELS_IPE_LINE 15
00194 if(dist >= MIN_PIXELS_IPE_LINE)
00195 {
00196 i1 = (i1+dist/5)%tot_siz;
00197 i2 = (i2-dist/5)%tot_siz;
00198 dist = dist-2*(dist/5);
00199 }
00200 else
00201 {
00202 dist = i2-i1+1;
00203 i1 = i1%tot_siz;
00204 i2 = i2%tot_siz;
00205 }
00206
00207 double x=0,y=0,xx=0,xy=0,yy=0;
00208 uInt j=i1;
00209 do
00210 {
00211 x += polyline[j].x();
00212 y += polyline[j].y();
00213 xx += polyline[j].x()*polyline[j].x();
00214 xy += polyline[j].x()*polyline[j].y();
00215 yy += polyline[j].y()*polyline[j].y();
00216 j = (j+1)%tot_siz;
00217 } while(j!=(i2+1)%tot_siz);
00218 double l1,l2,l3;
00219 x /= dist; y /= dist; xx /= dist; xy /= dist; yy /= dist;
00220
00221 ratio_eig = homogLineFromMoments(x,y,xx,xy,yy,l1,l2,l3);
00222 lines.push_back(auxLine_F(l1,l2,l3,ratio_eig < 0.1));
00223 }
00224
00225 for(int i=0;i<list.size();i++)
00226 {
00227 QPointF oldPoint = polyline[list[i]->index];
00228 if( (not polyline.closed) and ((i==0) or (i==list.size()-1)))
00229 {
00230
00231 result.append(oldPoint);
00232 continue;
00233 }
00234 int ant = (i-1+list.size())%list.size();
00235 int post = (i+1)%list.size();
00236 double newx = (lines[i].l2)*(lines[ant].l3) - (lines[i].l3)*(lines[ant].l2);
00237 double newy = -(lines[i].l1)*(lines[ant].l3) + (lines[i].l3)*(lines[ant].l1);
00238 double newz = (lines[i].l1)*(lines[ant].l2) - (lines[i].l2)*(lines[ant].l1);
00239 if ( (not lines[i].ok) or (not lines[ant].ok) or
00240 (fabs(newz) < EPSILON) )
00241 result.append(oldPoint);
00242 else
00243 {
00244 int nx = qRound(newx/newz);
00245 int ny = qRound(newy/newz);
00246
00247
00248
00249
00250 double dist =
00251 sqrt((nx-oldPoint.x())*(nx-oldPoint.x()) +
00252 (ny-oldPoint.y())*(ny-oldPoint.y()));
00253 QPointF prevPoint = polyline[list[ant]->index],
00254 nextPoint = polyline[list[post]->index];
00255 double minDist =
00256 qMin(
00257 sqrt((prevPoint.x()-oldPoint.x())*(prevPoint.x()-oldPoint.x()) +
00258 (prevPoint.y()-oldPoint.y())*(prevPoint.y()-oldPoint.y())),
00259 sqrt((nextPoint.x()-oldPoint.x())*(nextPoint.x()-oldPoint.x()) +
00260 (nextPoint.y()-oldPoint.y())*(nextPoint.y()-oldPoint.y()))
00261 );
00262 if(dist < 0.2*minDist)
00263 result.append(QPoint(nx,ny));
00264 else
00265 result.append(oldPoint);
00266 }
00267 }
00268 }
00269 else
00270 {
00271
00272 it = list.begin();
00273 while(it != list.end())
00274 {
00275 result.append(polyline.at((*it)->index));
00276 it++;
00277 }
00278 }
00279
00280
00281 while (!list.isEmpty())
00282 delete list.takeFirst();
00283
00284
00285 result.closed = polyline.closed;
00286 result.direction = polyline.direction;
00287
00288
00289 return return_value;
00290 }
00291
00292
00293 QVPolylineF::QVPolylineF(): QList<QPointF>(),
00294 closed(false), direction(false)
00295 {
00296 qDebug() << "QVPolylineF()";
00297 qDebug() << "QVPolylineF() <~ return";
00298 };
00299
00300 QVPolylineF::QVPolylineF(const QVPolyline &polyline): QList<QPointF>(),
00301 closed(polyline.closed), direction(polyline.direction)
00302 {
00303 foreach(QPoint point, polyline)
00304 {
00305 append(QPointF(point));
00306 }
00307 qDebug() << "QVPolylineF(const QVPolylineF &)";
00308 qDebug() << "QVPolylineF(const QVPolylineF &) <~ return";
00309 };
00310
00311 QVPolylineF::QVPolylineF(const QVPolylineF &polyline): QList<QPointF>(polyline),
00312 closed(polyline.closed), direction(polyline.direction)
00313 {
00314 qDebug() << "QVPolylineF(const QVPolylineF &)";
00315 qDebug() << "QVPolylineF(const QVPolylineF &) <~ return";
00316 };
00317
00318
00319
00320
00321
00322
00323
00324
00325
00326
00327
00328
00329
00330
00331
00332
00333
00334
00335
00336
00337
00338
00339
00340
00342
00343 QVPolylineF QVPolylineF::ellipse(uInt n, float x, float y, float maxRadio, float minRadio, float ang)
00344 {
00345 QVPolylineF ellipse;
00346 float w = 2*PI/(n-1);
00347 float maxArg = (maxRadio+minRadio)/2;
00348 float minArg = (maxRadio-minRadio)/2;
00349
00350 for (uInt t = 0; t < n; t++)
00351 ellipse.append(QPointF ( (uInt) (x + maxArg*cos(ang+w*t) + minArg*cos(ang-w*t)),
00352 (uInt) (y + maxArg*sin(ang+w*t) + minArg*sin(ang-w*t))
00353 ));
00354 return ellipse;
00355 }
00356
00357 QVPolylineF QVPolylineF::rectangle(float x1, float y1, float x2, float y2)
00358 {
00359 QVPolylineF rectangle;
00360 rectangle.append(QPointF( x1, y1 ));
00361 rectangle.append(QPointF( x1, y2 ));
00362 rectangle.append(QPointF( x2, y2 ));
00363 rectangle.append(QPointF( x2, y1 ));
00364 rectangle.append(QPointF( x1, y1 ));
00365 return rectangle;
00366 }
00367
00368 QVPolylineF::operator QVPolyline() const
00369 {
00370 QVPolyline polyline;
00371 foreach(QPointF pointf, *this)
00372 {
00373 polyline.append( QPoint(pointf.toPoint()) );
00374 }
00375 return polyline;
00376 }
00377