Home Hierarchy Members Alphabetical Related Pages

triangulator.h

Go to the documentation of this file.
00001 #ifndef XDKWRL_TRIANGULATOR_H
00002 #define XDKWRL_TRIANGULATOR_H
00003 
00004 #include <vector>  
00005 #include <list>  
00006 #include <numeric>  
00007 #include <stdexcept>  
00008 
00009 /*!
00010  * A very useful class to triangulate a sequence a of point
00011  * forming a simple polygon (without holes).
00012  *
00013  * The code is fully templated which means it can be used with any type
00014  * of point and any type of sequence.
00015  *
00016  * Here is an exemple of use, where Vec2 is a trivial 2D point type:
00017  \code 
00018  list<Vec2> polygon;
00019  
00020  polygon.push_back(Vec2(0.0f,0.0f));
00021  polygon.push_back(Vec2(1.0f,0.0f));
00022  polygon.push_back(Vec2(1.0f,1.0f));
00023  polygon.push_back(Vec2(0.0f,1.0f));
00024  
00025  Triangulator<Vec2> triangulator(polygon.begin(),polygon.end());
00026  triangulator.process();
00027  for (Triangulator<Vec2>::face_const_iterator fter = triangulator.faces_begin();
00028  fter != triangulator.faces_end();++fter)
00029  {
00030    cout<<"face joining\n"
00031        <<"  "<<*(fter->vertex(0))
00032        <<"  "<<*(fter->vertex(1))<<endl;
00033  }
00034  \endcode
00035  */
00036 template<class P>
00037 class Triangulator
00038 {
00039 public:
00040   class Face;
00041   typedef P PointType;
00042   typedef typename std::list<Face>::const_iterator face_const_iterator;
00043   template<class T>  
00044   inline Triangulator(T first,const T& last);
00045   inline void process() throw(std::runtime_error);
00046   inline unsigned int faces_size() const;
00047   inline face_const_iterator faces_begin() const;
00048   inline face_const_iterator faces_end() const;  
00049 protected:
00050   static inline bool isInTriangle(const PointType& A,
00051                                   const PointType& B,
00052                                   const PointType& C,
00053                                   const PointType& M);
00054   inline bool snip(const int u,const int v,const int w,const int nv);
00055   inline int nbPoints() const;
00056   inline const PointType& point(const int i) const;
00057   inline void addFace(const int u,const int v,const int w);
00058 private:
00059   std::vector<const PointType*> contour_;
00060   std::vector<int>              V_;
00061   std::list<Face>               faces_;
00062 };
00063 //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
00064 // Interface of Triangulator::Face
00065 //++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
00066 template<class P>
00067 class Triangulator<P>::Face
00068 {
00069 public:
00070   inline const Triangulator<P>::PointType* vertex(const int i) const;
00071 protected:
00072   friend class Triangulator;
00073   inline Face(const Triangulator<P>::PointType* const p0,
00074               const Triangulator<P>::PointType* const p1,
00075               const Triangulator<P>::PointType* const p2);
00076 private:
00077   const Triangulator<P>::PointType* vertices_[3];
00078 };
00079 //************************************************************
00080 // Implementation of Triangulator::Face
00081 //************************************************************
00082 template<class P>
00083 inline const typename Triangulator<P>::PointType*
00084 Triangulator<P>::Face::vertex(const int i) const
00085 {
00086   return vertices_[i];
00087 }
00088 template<class P>
00089 inline
00090 Triangulator<P>::Face::Face(const Triangulator<P>::PointType* const p0,
00091                             const Triangulator<P>::PointType* const p1,
00092                             const Triangulator<P>::PointType* const p2)
00093 {
00094   vertices_[0] = p0;
00095   vertices_[1] = p1;
00096   vertices_[2] = p2;
00097 }
00098 //************************************************************
00099 // Implementation of Triangulator::Face
00100 //************************************************************
00101 template<class P>
00102 template<class T>  
00103 inline
00104 Triangulator<P>::Triangulator(T first,const T& last)  
00105 {
00106   while (first != last)
00107   {
00108     contour_.push_back(&(*first++));
00109   }
00110   V_ = std::vector<int>(nbPoints());
00111   float A=0.0f;      
00112   for(int p=nbPoints()-1,q=0; q<nbPoints(); p=q++)
00113   {
00114     A +=
00115       (*contour_[p])[0]*(*contour_[q])[1] -
00116       (*contour_[q])[0]*(*contour_[p])[1];
00117   }
00118   if (A > 0.0f)
00119   {
00120     // This should be done with the iota function but gcc-3.2 seems to have
00121     // lost it on RedHat.
00122 //     iota(V_.begin(),V_.end(),0);
00123     int n=0;
00124     for (std::vector<int>::iterator iter =V_.begin();
00125          iter != V_.end();++iter)
00126     {
00127       *iter = n++;
00128     }
00129   }
00130   else
00131   {
00132     int n=0;
00133     for (std::vector<int>::reverse_iterator iter =V_.rbegin();
00134          iter != V_.rend();++iter)
00135     {
00136       *iter == ++n;
00137     }
00138   }
00139 }
00140 template<class P>
00141 inline void
00142 Triangulator<P>::process() throw(std::runtime_error)
00143 {
00144   if (nbPoints() < 3)
00145   {
00146     throw std::runtime_error("Empty polygon");
00147   }
00148   int nv = nbPoints();
00149   //  remove nv-2 Vertices, creating 1 triangle every time 
00150   int count = 2*nv;   // error detection 
00151   for(int m=0, v=nv-1; nv>2; )
00152   {
00153     // if we loop, it is probably a non-simple polygon 
00154     if (0 >= (count--))
00155     {
00156       throw std::runtime_error("Bad polygon");
00157     }    
00158     // three consecutive vertices in current polygon, <u,v,w> 
00159     const int u = nv <= v   ? 0 : v;     
00160     v           = nv <= u+1 ? 0 : u+1;
00161     const int w = nv <= v+1 ? 0 : v+1;     
00162     if ( snip(u,v,w,nv) )
00163     {
00164       // output Triangle 
00165       addFace(u,v,w);
00166       ++m;
00167       // remove v from remaining polygon 
00168       for(int s=v,t=v+1;t<nv;++s,++t)
00169       {
00170         V_[s] = V_[t];
00171       }
00172       // resest error detection counter 
00173       count = 2*(--nv);
00174     }
00175   }
00176 }
00177 template<class P>
00178 inline unsigned int
00179 Triangulator<P>::faces_size() const
00180 {
00181   return faces_.size();
00182 }
00183 template<class P>
00184 inline typename Triangulator<P>::face_const_iterator
00185 Triangulator<P>::faces_begin() const
00186 {
00187   return faces_.begin();
00188 }
00189 template<class P>
00190 inline typename Triangulator<P>::face_const_iterator
00191 Triangulator<P>::faces_end() const
00192 {
00193   return faces_.end();
00194 }
00195 template<class P>
00196 inline bool
00197 Triangulator<P>::isInTriangle(const Triangulator<P>::PointType& A,
00198                               const Triangulator<P>::PointType& B,
00199                               const Triangulator<P>::PointType& C,
00200                               const Triangulator<P>::PointType& M)
00201 {
00202   const float a[2] = { C[0]-B[0],C[1]-B[1] };
00203   const float b[2] = { A[0]-C[0],A[1]-C[1] };
00204   const float c[2] = { B[0]-A[0],B[1]-A[1] };
00205   const float am[2]= { M[0]-A[0],M[1]-A[1] };
00206   const float bm[2]= { M[0]-B[0],M[1]-B[1] };
00207   const float cm[2]= { M[0]-C[0],M[1]-C[1] };
00208 
00209   return ((a[0]*bm[1] >= a[1]*bm[0]) &&
00210           (c[0]*am[1] >= c[1]*am[0]) &&
00211           (b[0]*cm[1] >= b[1]*cm[0]));
00212 }
00213 template<class P>
00214 inline bool
00215 Triangulator<P>::snip(const int u,const int v,const int w,const int nv)
00216 {
00217   static const float EPSILON=0.0000000001f;
00218   const PointType& A = point(u);
00219   const PointType& B = point(v);
00220   const PointType& C = point(w);
00221   if (EPSILON > (((B[0]-A[0])*(C[1]-A[1]))-((B[1]-A[1])*(C[0]-A[0]))))
00222   {
00223     return false;
00224   }
00225   for (int p=0;p < nv;++p)
00226   {
00227     if( (p == u) || (p == v) || (p == w) )
00228     {
00229       continue;
00230     }
00231     if (isInTriangle(A,B,C,point(p)))
00232     {
00233       return false;
00234     }
00235   }
00236   return true;
00237 }
00238 template<class P>
00239 inline int
00240 Triangulator<P>::nbPoints() const
00241 {
00242   return contour_.size();
00243 }
00244 template<class P>
00245 inline const P&
00246 Triangulator<P>::point(const int i) const
00247 {
00248   return *contour_[V_[i]];
00249 }
00250 template<class P>
00251 inline void
00252 Triangulator<P>::addFace(const int u,const int v,const int w)
00253 {
00254   faces_.push_back(Face(contour_[V_[u]],
00255                         contour_[V_[v]],
00256                         contour_[V_[w]]));
00257 };
00258 #endif // XDKWRL_TRIANGULATOR_H
00259 
00260 // Local variables section.
00261 // This is only used by emacs!
00262 // Local Variables:
00263 // ff-search-directories: ("." "../../../src/xdkwrl/tools/")
00264 // End:

Generated on 24 Feb 2005 with doxygen version 1.3.9.1. Valid HTML 4.0! Valid CSS!