src/qvdta/qvpolyline.cpp

Go to the documentation of this file.
00001 /*
00002  *      Copyright (C) 2007. PARP Research Group.
00003  *      <http://perception.inf.um.es>
00004  *      University of Murcia, Spain.
00005  *
00006  *      This file is part of the QVision library.
00007  *
00008  *      QVision is free software: you can redistribute it and/or modify
00009  *      it under the terms of the GNU Lesser General Public License as
00010  *      published by the Free Software Foundation, version 3 of the License.
00011  *
00012  *      QVision is distributed in the hope that it will be useful,
00013  *      but WITHOUT ANY WARRANTY; without even the implied warranty of
00014  *      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015  *      GNU Lesser General Public License for more details.
00016  *
00017  *      You should have received a copy of the GNU Lesser General Public
00018  *      License along with QVision. If not, see <http://www.gnu.org/licenses/>.
00019  */
00020 
00024 
00025 #include <qvdta/qvpolyline.h>
00026 
00027 #define CONST_PI        ((double)3.14159)
00028 #define SIGN(X)         (((X)>=0)?1:-1)
00029 
00031 // QVPolylines
00032 QVPolyline::QVPolyline(): QList<QPoint>(), loop(false), direction(false), dir(0)
00033         {
00034         qDebug() << "QVPolyline()";
00035         qDebug() << "QVPolyline() <~ return";
00036         };
00037 
00038 QVPolyline::QVPolyline(const QVPolyline &polyline): QList<QPoint>(polyline), loop(polyline.loop), direction(polyline.direction), dir(polyline.dir)
00039         {
00040         qDebug() << "QVPolyline(const QVPolyline &)";
00041         qDebug() << "QVPolyline(const QVPolyline &) <~ return";
00042         };
00043 
00044 /*QVPolyline::QVPolyline(const QVSegment &segment)
00045         {
00046         qDebug() << "QVPolyline(const QVSegment &)";
00047         append(QPoint( (int) segment.x1, (int) segment.y1 ));
00048         append(QPoint( (int) segment.x2, (int) segment.y2 ));
00049         qDebug() << "QVPolyline(const QVSegment &) <~ return";
00050         }*/
00051 
00052 QPoint  linesIntersection(QPoint a, QPoint b, QPoint c, QPoint d)
00053         // calcula el punto de interseccion de las rectas ab y cd
00054         {
00055         double x1 = a.rx(), x2 = b.rx(), x3 = c.rx(), x4 = d.rx();
00056         double y1 = a.ry(), y2 = b.ry(), y3 = c.ry(), y4 = d.ry();
00057 
00058         double denominador = (y4 - y3)*(x2 - x1) - (x4 - x3)*(y2 - y1);
00059         if (denominador == 0)
00060                 return QPoint( (int)(b.rx() + c.rx())/2, (int)(b.ry() + c.ry())/2 );
00061 
00062         double  ua = (x4 - x3)*(y1 - y3) - (y4 - y3)*(x1 - x3),
00063                 ub = (x2 - x1)*(y1 - y3) - (y2 - y1)*(x1 - x3);
00064 
00065         QPoint p = QPoint(
00066                         (int) (x1 + ua*(x2 - x1) / denominador),
00067                         (int) (y1 + ub*(y2 - y1) / denominador)
00068                         );
00069         return p;
00070         }
00071 
00073 
00074 void drawPoints(const QList<QPoint> &hotPoints, QVImage<uChar,3> &dest)
00075         {
00076         QListIterator<QPoint> iterator(hotPoints);
00077         uChar pixel[3] = { 255,0,0 };
00078 
00079         while(iterator.hasNext())
00080                 {
00081                 QPoint p = iterator.next();
00082                 QVPolyline rectangle = QVPolyline::rectangle(p.x()-2, p.y()-2, p.x()+2, p.y()+2);
00083                 draw(dest, rectangle, pixel,true,true);
00084                 }
00085         }
00086 
00087 void drawPoints(const QList<QPoint> &hotPoints, QVImage<uChar> &dest)
00088         {
00089         QListIterator<QPoint> iterator(hotPoints);
00090         while(iterator.hasNext())
00091                 {
00092                 QPoint p = iterator.next();
00093                 QVPolyline rectangle = QVPolyline::rectangle(p.x()-2, p.y()-2, p.x()+2, p.y()+2);
00094                 draw(dest, rectangle, 255,true,true);
00095                 }
00096         }
00097 
00098 
00099 void draw(QVImage<uChar> &image, const QVPolyline &polyline, uChar constant, bool linked, bool safe)
00100         {
00101         Q_ASSERT_X(polyline.size() > 0, "drawPolyline()", "polyline size equals zero");
00102 
00103         QListIterator<QPoint> iterator(polyline);
00104         QRect roi = image.getROI();
00105 
00106         QPoint previous;
00107 
00108         if (linked)
00109                 previous = iterator.next();
00110 
00111         QVIMAGE_INIT_WRITE(uChar,image);
00112         while (iterator.hasNext())
00113                 {
00114                 QPoint actual = iterator.next();
00115                 int x = actual.x(), y = actual.y();
00116                 if (!linked && !safe)
00117                         QVIMAGE_PIXEL(image, x, y,0) = constant;
00118                 else if (linked)
00119                         {
00120                         QVPolyline line = QVPolyline::line(x, y, previous.rx(), previous.ry());
00121                         draw(image, line, constant, false, safe);
00122                         previous = actual;
00123                         }
00124                 else if (roi.contains(x, y))
00125                         QVIMAGE_PIXEL(image, x, y,0) = constant;
00126                 }
00127         }
00128 
00129 void draw(QVImage<uChar,3> &image, const QVPolyline &polyline, uChar constant[3], bool linked, bool safe)
00130         {
00131         Q_ASSERT_X(polyline.size() > 0, "drawPolyline()", "polyline size equals zero");
00132         //if (polyline.size() == 0) return;
00133 
00134         QListIterator<QPoint> iterator(polyline);
00135         QRect roi = image.getROI();
00136 
00137         QPoint previous;
00138 
00139         if (linked)
00140                 previous = iterator.next();
00141 
00142         QVIMAGE_INIT_WRITE(uChar,image);
00143         while (iterator.hasNext())
00144                 {
00145                 QPoint actual = iterator.next();
00146                 int x = actual.x(), y = actual.y();
00147                 if (!linked && !safe)
00148                         {
00149                         QVIMAGE_PIXEL(image, x, y,0) = constant[0];
00150                         QVIMAGE_PIXEL(image, x, y,1) = constant[1];
00151                         QVIMAGE_PIXEL(image, x, y,2) = constant[2];
00152                         //image(actual.rx(), actual.ry(),0) = constant[0];
00153                         //image(actual.rx(), actual.ry(),1) = constant[1];
00154                         //image(actual.rx(), actual.ry(),2) = constant[2];
00155                         }
00156                 else if (linked)
00157                         {
00158                         QVPolyline line = QVPolyline::line(actual.rx(), actual.ry(), previous.rx(), previous.ry());
00159                         draw(image, line, constant, false, safe);
00160                         previous = actual;
00161                         }
00162                 else if (roi.contains(actual.rx(), actual.ry()))
00163                         {
00164                         QVIMAGE_PIXEL(image, x, y,0) = constant[0];
00165                         QVIMAGE_PIXEL(image, x, y,1) = constant[1];
00166                         QVIMAGE_PIXEL(image, x, y,2) = constant[2];
00167                         /*image(actual.rx(), actual.ry(),0) = constant[0];
00168                         image(actual.rx(), actual.ry(),1) = constant[1];
00169                         image(actual.rx(), actual.ry(),2) = constant[2];*/
00170                         }
00171                 }
00172         }
00173 
00174 
00175 void draw(QVImage<uChar> &img, const QList< QVPolyline > &polylineList, uChar constant, bool linked, bool safe)
00176         {
00177         QListIterator<QVPolyline> iterator(polylineList);
00178         while (iterator.hasNext())
00179                 draw(img, iterator.next(), constant, linked, safe);
00180         }
00181 
00182 void draw(QVImage<uChar,3> &img,const QList< QVPolyline > &polylineList, uChar constant[3],bool linked,bool safe)
00183         {
00184         QListIterator<QVPolyline> iterator(polylineList);
00185         while (iterator.hasNext())
00186                 draw(img, iterator.next(), constant, linked, safe);
00187         }
00188 
00189 
00190 QVPolyline QVPolyline::ellipse(uInt n, float x, float y, float maxRadio, float minRadio, float ang)
00191         {
00192         QVPolyline ellipse;
00193         float w = 2*CONST_PI/(n-1);
00194         float maxArg = (maxRadio+minRadio)/2;
00195         float minArg = (maxRadio-minRadio)/2;
00196 
00197         for (uInt t = 0; t < n; t++)
00198                 ellipse.append(QPoint ( (uInt) (x + maxArg*cos(ang+w*t) + minArg*cos(ang-w*t)),
00199                                                 (uInt) (y + maxArg*sin(ang+w*t) + minArg*sin(ang-w*t))
00200                                                 ));
00201         return ellipse;
00202         }
00203 
00204 QVPolyline QVPolyline::rectangle(int x1, int y1, int x2, int y2)
00205         {
00206         QVPolyline rectangle;
00207         rectangle.append(QPoint( x1, y1 ));
00208         rectangle.append(QPoint( x1, y2 ));
00209         rectangle.append(QPoint( x2, y2 ));
00210         rectangle.append(QPoint( x2, y1 ));
00211         rectangle.append(QPoint( x1, y1 ));
00212         return rectangle;
00213         }
00214 
00215 QVPolyline QVPolyline::line(int x1, int y1, int x2, int y2)
00216         {
00217         QVPolyline line;
00218 
00219         line.append(QPoint( x1, y1 ));
00220 
00221         if (x1 == x2 && y1 == y2)
00222                 return line;
00223 
00224         int i,dx,dy,sdx,sdy,dxabs,dyabs,x,y,px,py;
00225         
00226         dx=x2-x1;      // the horizontal distance of the line
00227         dy=y2-y1;      // the vertical distance of the line
00228         dxabs=abs(dx);
00229         dyabs=abs(dy);
00230         sdx=SIGN(dx);
00231         sdy=SIGN(dy);
00232         x=dyabs>>1;
00233         y=dxabs>>1;
00234         px=x1;
00235         py=y1;
00236         
00237         if (dxabs>=dyabs) // the line is more horizontal than vertical
00238                 for(i=0;i<dxabs;i++)
00239                         {
00240                         y+=dyabs;
00241                         if (y>=dxabs)
00242                                 {
00243                                 y-=dxabs;
00244                                 py+=sdy;
00245                                 }
00246                         px+=sdx;
00247                         line.append(QPoint( px, py ));
00248                         }
00249         else    // the line is more vertical than horizontal
00250                 for(i=0;i<dyabs;i++)
00251                         {
00252                         x+=dxabs;
00253                         if (x>=dyabs)
00254                                 {
00255                                 x-=dyabs;
00256                                 px+=sdx;
00257                                 }
00258                         py+=sdy;
00259                         line.append(QPoint( px, py ));
00260                         }
00261 
00262         return line;
00263         }
00264 
00265 /*void joinExtremes(QVPolyline &main, QVPolyline &second)
00266         {
00267         QPoint a1 = main.takeLast(), a2 = main.last(), b1 = second.at(0), b2 = second.at(1);
00268 
00269         main.append(linesIntersection(a1,a2, b1,b2));
00270 
00271         for (int i = 1; i< second.size(); i++)
00272                 main.append(second.at(i));
00273         }
00274 
00275 double dist2(QPoint p1, QPoint p2)
00276         { return (p1.x() - p2.x())*(p1.x() - p2.x()) + (p1.y() - p2.y())*(p1.y() - p2.y()); }
00277 
00278 template <typename T>QList<T> & reverse(QList<T> &p)
00279         {
00280         for (int i = 0; i< p.size()/2; i++)
00281                 p.swap(i, p.size()-i-1);
00282         return p;
00283         }
00284 
00285 QList<QVPolyline> * compactPolylines(const QList<QVPolyline> &polylineList, double maxDist)
00286         {
00287         //qDebug() << "compactPolylines()";
00288         uInt n = polylineList.size();
00289         //qDebug() << "compactPolylines(): size"<<n;
00290         //if (n < 2) return new QList<QVPolyline>(polylineList);
00291 
00292         bool * segmentUsed = new bool[n];
00293         QList<QVPolyline> * result = new QList<QVPolyline>();
00294 
00295         for (uInt i=0; i<n; i++)
00296                 segmentUsed[i] = false;
00297 
00298         for (uInt i=0; i<n-1; i++)
00299                 {
00300                 //qDebug() << "compactPolylines(): segmento" << i << segmentUsed[i];
00301                 if (segmentUsed[i]) continue;
00302                 QVPolyline actual = polylineList.at(i);
00303                 if (actual.size() < 2) continue;
00304 
00305                 for (uInt j= i+1; j<n; j++)
00306                         {
00307                         if (segmentUsed[j]) continue;
00308                         QVPolyline next = polylineList.at(j);
00309                         if (next.size() < 2) continue;
00310 
00311                         if (dist2(actual.back(), next.front()) < maxDist)
00312                                 { append(actual, next); segmentUsed[j] = true; }
00313 
00314                         else if (dist2(actual.back(), next.back()) < maxDist)
00315                                 { reverse(next); append(actual, next); segmentUsed[j] = true; }
00316 
00317                         else if (dist2(actual.front(), next.front()) < maxDist)
00318                                 { reverse(actual); append(actual, next); segmentUsed[j] = true; }
00319 
00320                         else if (dist2(actual.front(), next.back()) < maxDist)
00321                                 { reverse(actual); reverse(next); append(actual, next); segmentUsed[j] = true; }
00322                         }
00323 
00324                 if ( (actual.size() > 3) && (dist2(actual.back(), actual.front()) < maxDist) )
00325                         {
00326                         QPoint a1 = actual.takeLast(), a2 = actual.last(), b1 = actual.takeFirst(), b2 = actual.front();
00327                         QPoint p = linesIntersection(a1,a2, b1,b2);
00328                         actual.push_back(p);
00329                         actual.push_front(p);
00330                         }
00331 
00332                 result->append(actual);
00333                 }
00334 
00335         if (!segmentUsed[n-1])
00336                 result->append(polylineList.back());
00337 
00338         delete [] segmentUsed;
00339 
00340         return result;
00341         }*/
00342 
00343 /*void qvEllipse(QVPolyline &ellipse, uInt n, float x, float y, float maxRadio, float minRadio, float ang)
00344         {
00345         float w = 2*CONST_PI/(n-1);
00346         float maxArg = (maxRadio+minRadio)/2;
00347         float minArg = (maxRadio-minRadio)/2;
00348 
00349         for (uInt t = 0; t < n; t++)
00350                 ellipse.append(QPoint ( (uInt) (x + maxArg*cos(ang+w*t) + minArg*cos(ang-w*t)),
00351                                                 (uInt) (y + maxArg*sin(ang+w*t) + minArg*sin(ang-w*t))
00352                                                 ));
00353         }
00354 
00355 void qvRectangle(QVPolyline &rectangle, int x1, int y1, int x2, int y2)
00356         {
00357         rectangle.append(QPoint( x1, y1 ));
00358         rectangle.append(QPoint( x1, y2 ));
00359         rectangle.append(QPoint( x2, y2 ));
00360         rectangle.append(QPoint( x2, y1 ));
00361         rectangle.append(QPoint( x1, y1 ));
00362         }
00363 
00364 void qvLine(QVPolyline &line, int x1, int y1, int x2, int y2)
00365         {
00366         line.append(QPoint( x1, y1 ));
00367         if (x1 == x2 && y1 == y2)
00368                 return;
00369 
00370         int i,dx,dy,sdx,sdy,dxabs,dyabs,x,y,px,py;
00371         
00372         dx=x2-x1;
00373         dy=y2-y1;
00374         dxabs=abs(dx);
00375         dyabs=abs(dy);
00376         sdx=SIGN(dx);
00377         sdy=SIGN(dy);
00378         x=dyabs>>1;
00379         y=dxabs>>1;
00380         px=x1;
00381         py=y1;
00382         
00383         if (dxabs>=dyabs)
00384                 for(i=0;i<dxabs;i++)
00385                         {
00386                         y+=dyabs;
00387                         if (y>=dxabs)
00388                                 {
00389                                 y-=dxabs;
00390                                 py+=sdy;
00391                                 }
00392                         px+=sdx;
00393                         line.append(QPoint( px, py ));
00394                         }
00395         else
00396                 for(i=0;i<dyabs;i++)
00397                         {
00398                         x+=dxabs;
00399                         if (x>=dyabs)
00400                                 {
00401                                 x-=dyabs;
00402                                 px+=sdx;
00403                                 }
00404                         py+=sdy;
00405                         line.append(QPoint( px, py ));
00406                         }
00407         }*/
00408         
00409 
00411 #define dist2(A,B)      (((A).rx() -(B).rx())*((A).rx() -(B).rx()) + ((A).ry() -(B).ry())*((A).ry() -(B).ry()))
00412 #define dot(A,B)        ( (A).rx()*(B).rx() + (A).ry()*(B).ry() )
00413 
00414 // simplifyDP():
00415 //  This is the Douglas-Peucker recursive simplification routine
00416 //  It just marks vertices that are part of the simplified polyline
00417 //  for approximating the polyline subchain v[j] to v[k].
00418 //    Input:  tol = approximation tolerance
00419 //            v[] = polyline array of vertex points 
00420 //            j,k = indices for the subchain v[j] to v[k]
00421 //    Output: mk[] = array of markers matching vertex array v[]
00422 /*void simplifyDP( float tol, QPoint* v, int j, int k, int* mk )
00423         {
00424         if (k <= j+1) // there is nothing to simplify
00425                 return;
00426 
00427         // check for adequate approximation by segment S from v[j] to v[k]
00428         int     maxi = j;          // index of vertex farthest from S
00429         float   maxd2 = 0;         // distance squared of farthest vertex
00430 
00431         QPoint S_P0 = v[j],
00432                 S_P1 = v[k];
00433 
00434         QPoint u = QPoint( S_P1.rx() - S_P0.rx(), S_P1.ry() - S_P0.ry() );
00435         double  cu = dot(u,u);     // segment length squared
00436         
00437         // test each vertex v[i] for max distance from S
00438         // compute using the Feb 2001 Algorithm's dist_Point_to_Segment()
00439         // Note: this works in any dimension (2D, 3D, ...)
00440         QPoint  w;   // vector
00441         QPoint   Pb;                // base of perpendicular from v[i] to S
00442         double  b, cw, dv2;        // dv2 = distance v[i] to S squared
00443         
00444         for (int i=j+1; i<k; i++)
00445                 {
00446                 // compute distance squared
00447                 w = QPoint( v[i].rx() - S_P0.rx(), v[i].ry() - S_P0.ry() );
00448                 cw = dot(w,u);
00449                 if ( cw <= 0 )   // if perp line doesnt fall on u, it calculates the dist2 to the nearest vertex
00450                         dv2 = dist2(v[i], S_P0);
00451                 else if ( cu <= cw )
00452                         dv2 = dist2(v[i], S_P1);
00453                 else
00454                         {
00455                         // if perp line does fall on u, it calculates the height^2 of the triangle
00456                         b = cw / cu;
00457                         Pb = QPoint( S_P0.rx() + (int) (b * u.rx()), S_P0.ry() + (int)(b*u.ry()) );
00458                         dv2 = dist2(v[i], Pb);
00459                         }
00460                 // test with current max distance squared
00461                 if (dv2 <= maxd2) 
00462                         continue;
00463                 // v[i] is a new max vertex
00464                 maxi = i;
00465                 maxd2 = dv2;
00466                 }
00467         if (maxd2 > tol * tol)        // error is worse than the tolerance
00468                 {
00469                 // split the polyline at the farthest vertex from S
00470                 mk[maxi] = 1;                           // mark v[maxi] for the simplified polyline
00471                                                         // recursively simplify the two subpolylines at v[maxi]
00472                 simplifyDP( tol, v, j, maxi, mk );      // polyline v[j] to v[maxi]
00473                 simplifyDP( tol, v, maxi, k, mk );      // polyline v[maxi] to v[k]
00474                 }
00475         // else the approximation is OK, so ignore intermediate vertices
00476         return;
00477         }*/
00478 
00479 // poly_simplify():
00480 //    Input:  tol = approximation tolerance
00481 //            V[] = polyline array of vertex points 
00482 //            n   = the number of points in V[]
00483 //    Output: sV[]= simplified polyline vertices (max is n)
00484 //    Return: m   = the number of points in sV[]
00485 /*QVPolyline IPE2( float tol, const QVPolyline &V )
00486         {
00487         int n=V.size();
00488         if (n == 0) return V;
00489 
00490         QVPolyline sV;
00491 
00492         QPoint* vt = new QPoint[n];      // vertex buffer
00493         int*   mk = new int[n];         // marker buffer
00494         
00495         // STAGE 1.  Vertex Reduction within tolerance of prior vertex cluster
00496         vt[0] = V.at(0);              // start at the beginning
00497 
00498         int i,k,pv;
00499         for (i=k=1, pv=0; i<n; i++)
00500                 {
00501                 // TODO: ERROR de compilación.
00502                 //if (dist2(V.at(i), V.at(pv)) < tol*tol)
00503                 //      continue;
00504                 vt[k++] = V.at(i);
00505                 pv = i;
00506                 }
00507         if (pv < n-1)
00508         vt[k++] = V.at(n-1);      // finish at the end
00509         
00510         // STAGE 2.  Douglas-Peucker polyline simplification
00511         for(int i=0; i<n; ++i)
00512                 mk[i]=0;
00513         mk[0] = mk[k-1] = 1;       // mark the first and last vertices
00514         simplifyDP( tol, vt, 0, k-1, mk );
00515         
00516         // copy marked vertices to the output simplified polyline
00517         for (int i=0; i<k; i++)
00518                 {
00519                 if (mk[i])
00520                         sV.append(vt[i]);
00521                         //sV.push_back(vt[i]);
00522                 }
00523         delete vt;
00524         delete mk;
00525         return sV;         // simplyfied polyline
00526         }*/

Generated on Fri Dec 7 12:20:59 2007 for QVision by  doxygen 1.5.3