Main Page | Modules | Namespace List | Class Hierarchy | Alphabetical List | Class List | Directories | File List | Namespace Members | Class Members | File Members | Related Pages

GenConvexHull.TCC

Go to the documentation of this file.
00001 /*---------------------------------------------------------------------+
00002  | Library QgarLib, graphics analysis and recognition                  |
00003  | Copyright (C) 2002  Qgar Project, LORIA                             |
00004  |                                                                     |
00005  | This library is free software; you can redistribute it and/or       |
00006  | modify it under the terms of the GNU Lesser General Public          |
00007  | License version 2.1, as published by the Free Software Foundation.  |
00008  |                                                                     |
00009  | This library is distributed in the hope that it will be useful,     |
00010  | but WITHOUT ANY WARRANTY; without even the implied warranty of      |
00011  | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.                |
00012  | See the GNU Lesser General Public License for more details.         |
00013  |                                                                     |
00014  | The GNU Lesser General Public License is included in the file       |
00015  | LICENSE.LGPL, in the root directory of the Qgar packaging. See      |
00016  | http://www.gnu.org/licenses/lgpl.html for the terms of the licence. |
00017  | To receive a paper copy, write to the Free Software Foundation,     |
00018  | Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.       |
00019  |                                                                     |
00020  | Contact Project Qgar for any information:                           |
00021  |   LORIA - équipe Qgar                                               |
00022  |   B.P. 239, 54506 Vandoeuvre-lès-Nancy Cedex, France                |
00023  |   email: qgar-contact@loria.fr                                      |
00024  |   http://www.qgar.org/                                              |
00025  *---------------------------------------------------------------------*/
00026 
00027 
00028 /**
00029  * @file   GenConvexHull.TCC
00030  * @brief  Implementation of function members of class qgar::GenConvexHull.
00031  *
00032  * @author <a href="mailto:qgar-develop@loria.fr?subject=Qgar fwd Gérald Masini">Gérald Masini</a>
00033  * @date   January 27, 2005  20:20
00034  * @since  Qgar 2.2
00035  */
00036 
00037 
00038 
00039 // STD
00040 #include <iostream>
00041 #include <list>
00042 #include <set>
00043 #include <utility>
00044 // QGAR
00045 #include <qgarlib/ISerializable.H>
00046 #include <qgarlib/math.H>
00047 #include <qgarlib/primitives.H>
00048 
00049 
00050 
00051 
00052 namespace qgar
00053 {
00054 
00055 
00056 // -------------------------------------------------------------------
00057 // C O N S T R U C T O R S
00058 // -------------------------------------------------------------------
00059 
00060 
00061 // DEFAULT CONSTRUCTOR.
00062 
00063 template <class T>
00064 GenConvexHull<T>::GenConvexHull()
00065 {
00066   // VOID
00067 }
00068 
00069 
00070 // COMPUTE THE CONVEX HULL OF A STL LIST OF POINTS
00071 
00072 template <class T>
00073 GenConvexHull<T>::GenConvexHull(const std::list< GenPoint<T> >& aPtList)
00074 {
00075    PRIVATEgraham_sScan(aPtList);
00076 }
00077 
00078 
00079 // COPY-CONSTRUCTOR
00080 
00081 template <class T>
00082 GenConvexHull<T>::GenConvexHull(const GenConvexHull<T>& aCHull)
00083   : _vertices(aCHull._vertices),
00084     _hull(aCHull._hull),
00085     _pivot(aCHull._pivot)
00086 {
00087   // VOID
00088 }
00089 
00090 
00091 // -------------------------------------------------------------------
00092 // D E S T R U C T O R 
00093 // -------------------------------------------------------------------
00094 
00095 
00096 template <class T>
00097 GenConvexHull<T>::~GenConvexHull()
00098 {
00099   // VOID
00100 }
00101 
00102 
00103 // -------------------------------------------------------------------
00104 // A C C E S S   T O   C H A R A C T E R I S T I C S
00105 // -------------------------------------------------------------------
00106 
00107 
00108 // IS HULL EMPTY?
00109 
00110 template <class T>
00111 bool GenConvexHull<T>::empty() const
00112 {
00113   return _vertices.empty();
00114 }
00115 
00116 
00117 // GET NUMBER OF VERTICES
00118 template <class T>
00119 int
00120 GenConvexHull<T>::size() const
00121 {
00122   return (int) _vertices.size();
00123 }
00124 
00125 
00126 // -------------------------------------------------------------------
00127 // A C C E S S   T O   P O I N T S
00128 // -------------------------------------------------------------------
00129 
00130 
00131 // GET VERTICES
00132 
00133 template <class T>
00134 const std::list< GenPoint<T> >&
00135 GenConvexHull<T>::accessVertices() const
00136 {
00137   return _vertices;
00138 }
00139 
00140 
00141 // GET A COPY OF THE VERTICES
00142 
00143 template <class T>
00144 std::list< GenPoint<T> >
00145 GenConvexHull<T>::vertices() const
00146 {
00147   return _vertices;
00148 }
00149 
00150 
00151 // GET PIVOT
00152 template <class T>
00153 const GenPoint<T>&
00154 GenConvexHull<T>::accessPivot() const
00155 {
00156   return _pivot;
00157 }
00158 
00159 
00160 // GET A COPY OF THE PIVOT
00161 template <class T>
00162 GenPoint<T>
00163 GenConvexHull<T>::pivot() const
00164 {
00165   return _pivot;
00166 }
00167 
00168 
00169 // -------------------------------------------------------------------
00170 // O P E R A T O R S
00171 // -------------------------------------------------------------------
00172 
00173 
00174 // ASSIGNMENT
00175 
00176 template <class T>
00177 GenConvexHull<T>&
00178 GenConvexHull<T>::operator=(const GenConvexHull<T>& aCHull)
00179 {
00180   // Are left hand side and right hand side different objects?
00181   if (this != &aCHull)
00182     {
00183       _vertices = aCHull._vertices;
00184       _hull     = aCHull._hull;
00185       _pivot    = aCHull._pivot;
00186     }
00187 
00188   return *this;
00189 }
00190 
00191 
00192 // -------------------------------------------------------------------
00193 // S E R I A L I Z A T I O N / D E S E R I A L I Z A T I O N
00194 // -------------------------------------------------------------------
00195 
00196 
00197 template <class T>
00198 std::istream& 
00199 GenConvexHull<T>::read(std::istream& anInStream)
00200 {
00201   qgReadObjName(anInStream, "ConvexHull");
00202 
00203   // Retrieve vertices
00204 
00205   std::list< GenPoint<T> > ptList;
00206 
00207   int pointCnt;
00208   qgReadObjData(anInStream, pointCnt);
00209   
00210   for(int iCnt = 0 ; iCnt < pointCnt ; ++iCnt)
00211     {
00212       GenPoint<T> point;
00213       qgReadObjData(anInStream, point);
00214       // Conform to the initial ordering of vertices
00215       ptList.push_back(point);
00216     }
00217   
00218   // Create hull from the list of points
00219   PRIVATEgraham_sScan(ptList);
00220 
00221   return anInStream;
00222 }
00223 
00224 
00225 template <class T>
00226 std::ostream& 
00227 GenConvexHull<T>::write(std::ostream& anOutStream) const
00228 {
00229   anOutStream << "ConvexHull("
00230               << _vertices.size()
00231               << ')';
00232 
00233   // Write the list of vertices to the stream.
00234   
00235   for(typename std::list< GenPoint<T> >::const_iterator
00236         itLP = _vertices.begin();
00237       itLP != _vertices.end();
00238       ++itLP)
00239     {
00240       anOutStream << '('
00241                   << *itLP
00242                   << ')';
00243     }
00244 
00245   return anOutStream;
00246 }
00247 
00248 
00249 // -------------------------------------------------------------------
00250 // A U X I L I A R Y   F U N C T I O N S   ( P R I V A T E )
00251 // -------------------------------------------------------------------
00252 
00253 
00254 // EFFECTIVE CONSTRUCTION OF THE CONVEX HULL
00255 
00256 template <class T>
00257 void
00258 GenConvexHull<T>::PRIVATEgraham_sScan(const std::list< GenPoint<T> >& aPtList)
00259 {
00260 if (aPtList.empty())
00261     {
00262       // Empty list: Nothing to do
00263       return;
00264     }
00265 
00266   //+---------------------------------------------------------------+
00267   //|              Graham's scan works in three steps               |
00268   //+---------------------------------------------------------------+
00269 
00270   // 1. Compute pivot
00271   //    -------------
00272   // Find an extreme point, the so-called pivot, which is guaranteed
00273   // to be on the hull: It is chosen as the point with the minimum
00274   // Y coordinate.
00275 
00276   // Iterator on the given list of points
00277   typename std::list< qgar::GenPoint<T> >::const_iterator
00278     itPL = aPtList.begin();
00279 
00280   // Pointer to the pivot
00281   typename std::list< qgar::GenPoint<T> >::const_iterator
00282     itPivot = itPL;
00283 
00284   // Find the point of minimum Y coordinate
00285   // For equal Y coordinates, choose the minimum X coordinate
00286   for (++itPL ; itPL != aPtList.end() ; ++itPL)
00287     {
00288       T yCurr = itPL->y();
00289       T yPiv  = itPivot->y();
00290 
00291       if (yCurr < yPiv)
00292         {
00293           itPivot = itPL;
00294         }
00295       else if (yCurr == yPiv)
00296         {
00297           if ((itPL->x()) < (itPivot->x()))
00298             {
00299               itPivot = itPL;
00300             }
00301         }
00302     }
00303 
00304   // Save pivot
00305   _pivot = *itPivot;
00306 
00307 
00308   // 2. Sort the points
00309   //    ---------------
00310   // in order of increasing angle about the pivot.
00311   // The result is a star-shaped polygon, in which the pivot can "see"
00312   // the whole polygon.
00313 
00314   for (itPL = aPtList.begin() ; itPL != aPtList.end() ; ++itPL)
00315     {
00316       // Do not process the pivot
00317       if (itPL != itPivot)
00318         {
00319           typename std::pair< double, GenPoint<T> > p(qgAngle(_pivot, *itPL), *itPL);
00320           _hull.insert(p);
00321         }
00322     }
00323 
00324   // Check the number of remaining points (because of possible duplicates)
00325 
00326   if(_hull.size() < 3)
00327     {
00328       // 1, 2 or 3 points: Just copy pivot and selected points
00329       _vertices.push_back(_pivot);
00330 
00331       for(typename std::multiset<QGDpair, _sortPred>::iterator itH = _hull.begin();
00332           itH != _hull.end();
00333           ++itH)
00334         {
00335           _vertices.push_back(itH->second);
00336         }
00337       return;
00338     }
00339 
00340 
00341   // 3. Build the hull
00342   //    --------------
00343   // by marching around the star-shaped poly, adding edges at right turns,
00344   // and backtracking at left turns.
00345 
00346   // THE GIVEN LIST OF POINTS INCLUDES AT LEAST 4 POINTS
00347 
00348   // Previous point
00349   typename std::multiset<QGDpair, _sortPred>::iterator itPrev = _hull.begin();
00350 
00351   // Current point
00352   typename std::multiset<QGDpair, _sortPred>::iterator itCurr = itPrev;
00353   ++itCurr;
00354   
00355   // Next point
00356   typename std::multiset<QGDpair, _sortPred>::iterator itNext = itCurr;
00357   ++itNext;
00358 
00359   for ( ; itNext != _hull.end() ; ++itNext)
00360     {
00361       // Angle between vector formed by previous and current point
00362       // and vector formed by current and next point
00363       if (  qgAngle(itPrev->second, itCurr->second, itNext->second)
00364            >
00365             Math::QG_PI )
00366         {
00367           // The angle is greater than PI: The current point does not
00368           // belong to the hull and must be erased
00369           _hull.erase(itCurr);
00370 
00371           // Backtrack unless at beginning
00372           if (itPrev != _hull.begin())
00373             {
00374               --itPrev;
00375             }
00376         }
00377       else
00378         {
00379           // The angle is less than PI:
00380           // Update previous point for next turn in loop
00381           ++itPrev;
00382         }
00383 
00384       // Update current and next points for next turn in loop
00385       itCurr = itPrev;
00386       ++itCurr;
00387       itNext = itCurr;
00388 
00389     } // END for
00390 
00391 
00392   // CONSTRUCT THE LIST OF VERTICES OF THE HULL
00393   for (itCurr = _hull.begin() ; itCurr != _hull.end() ; ++itCurr)
00394     {
00395       _vertices.push_back(itCurr->second);
00396     }
00397 
00398   // ADD PIVOT
00399   _vertices.push_front(_pivot);
00400 
00401 }
00402 
00403 
00404 // -------------------------------------------------------------------
00405 
00406 
00407 } // namespace qgar