XdkWrl: triangulator.h Source File

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 typename 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 typename 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 5 Jan 2007 with version 1.5.1. |