core/vgl/vgl_polygon.txx
Go to the documentation of this file.
00001 // This is core/vgl/vgl_polygon.txx
00002 #ifndef vgl_polygon_txx_
00003 #define vgl_polygon_txx_
00004 
00005 #include "vgl_polygon.h"
00006 //:
00007 // \file
00008 
00009 #include "vgl_intersection.h"
00010 #include "vgl_line_2d.h"
00011 #include "vgl_tolerance.h"
00012 
00013 #include <vcl_iostream.h>
00014 #include <vcl_set.h>
00015 #include <vcl_cmath.h>
00016 #include <vcl_cassert.h>
00017 #include <vcl_algorithm.h>
00018 
00019 // Constructors/Destructor---------------------------------------------------
00020 
00021 template <class T>
00022 vgl_polygon<T>::vgl_polygon(vgl_point_2d<T> const p[], int n):
00023   sheets_(1, sheet_t(n))
00024 {
00025   for (int i = 0; i < n; ++i)
00026     sheets_[0][i].set(p[i].x(), p[i].y());
00027 }
00028 
00029 template <class T>
00030 vgl_polygon<T>::vgl_polygon(T const* x, T const* y, int n)
00031   : sheets_(1, sheet_t(n))
00032 {
00033   for (int i = 0; i < n; ++i)
00034     sheets_[0][i].set(x[i], y[i]);
00035 }
00036 
00037 template <class T>
00038 vgl_polygon<T>::vgl_polygon(T const x_y[], int n)
00039   : sheets_(1, sheet_t(n))
00040 {
00041   for (int i = 0; i < n; ++i)
00042     sheets_[0][i].set(x_y[2*i], x_y[2*i+1]);
00043 }
00044 
00045 template <class T>
00046 void vgl_polygon<T>::add_contour(point_t const p[], int n)
00047 {
00048   sheet_t s(n);
00049   for (int i = 0; i < n; ++i)
00050     s[i].set(p[i].x(), p[i].y());
00051   sheets_.push_back(s);
00052 }
00053 
00054 template <class T>
00055 void vgl_polygon<T>::add_contour(T const* x, T const* y, int n)
00056 {
00057   sheet_t s(n);
00058   for (int i = 0; i < n; ++i)
00059     s[i].set(x[i], y[i]);
00060   sheets_.push_back(s);
00061 }
00062 
00063 template <class T>
00064 void vgl_polygon<T>::add_contour(T const x_y[], int n)
00065 {
00066   sheet_t s(n);
00067   for (int i = 0; i < n; ++i)
00068     s[i].set(x_y[2*i], x_y[2*i+1]);
00069   sheets_.push_back(s);
00070 }
00071 
00072 // Functions -----------------------------------------------------------------
00073 
00074 template <class T>
00075 void vgl_polygon<T>::push_back(T x, T y)
00076 {
00077   sheets_[sheets_.size()-1].push_back(point_t(x,y));
00078 }
00079 
00080 template <class T>
00081 void vgl_polygon<T>::push_back(point_t const& p)
00082 {
00083   sheets_[sheets_.size()-1].push_back(p);
00084 }
00085 
00086 template <class T>
00087 bool vgl_polygon<T>::contains(T x, T y) const
00088 {
00089   bool c = false;
00090   for (unsigned int s=0; s < sheets_.size(); ++s)
00091   {
00092     sheet_t const& pgon = sheets_[s];
00093     int n = int(pgon.size());
00094     for (int i = 0, j = n-1; i < n; j = i++)
00095     {
00096       const vgl_point_2d<T> &p_i = pgon[i];
00097       const vgl_point_2d<T> &p_j = pgon[j];
00098 
00099       // by definition, corner points and edge points are inside the polygon:
00100       if ((p_j.x() - x) * (p_i.y() - y) == (p_i.x() - x) * (p_j.y() - y) &&
00101           (((p_i.x()<=x) && (x<=p_j.x())) || ((p_j.x()<=x) && (x<=p_i.x()))) &&
00102           (((p_i.y()<=y) && (y<=p_j.y())) || ((p_j.y()<=y) && (y<=p_i.y()))))
00103         return true;
00104       // invert c for each edge crossing:
00105       if ((((p_i.y()<=y) && (y<p_j.y())) || ((p_j.y()<=y) && (y<p_i.y()))) &&
00106           (x < (p_j.x() - p_i.x()) * (y - p_i.y()) / (p_j.y() - p_i.y()) + p_i.x()))
00107         c = !c;
00108     }
00109   }
00110   return c;
00111 }
00112 
00113 template <class T>
00114 vcl_ostream& vgl_polygon<T>::print(vcl_ostream& os) const
00115 {
00116   if (sheets_.size() == 0)
00117     os << "Empty polygon\n";
00118   else {
00119     os << "Polygon with " << num_sheets() << " sheets:\n";
00120     for (unsigned int s = 0; s < sheets_.size(); ++s)
00121     {
00122       os << "Sheet " << s << ' ';
00123       if (sheets_[s].size()==0)
00124         os << "(empty)";
00125       else
00126       for (unsigned int p = 0; p < sheets_[s].size(); ++p)
00127         os << '(' << sheets_[s][p].x() << ',' << sheets_[s][p].y() << ") ";
00128       os << '\n';
00129     }
00130   }
00131   return os;
00132 }
00133 
00134 template <class T>
00135 vgl_polygon_sheet_as_array<T>::vgl_polygon_sheet_as_array(vgl_polygon<T> const& p)
00136 {
00137   assert(p.num_sheets()==1);
00138   n = int(p[0].size());
00139   x = new T[n*2];
00140   y = x + n;
00141   for (int v = 0; v < n; ++v)
00142   {
00143     x[v] = p[0][v].x();
00144     y[v] = p[0][v].y();
00145   }
00146 }
00147 
00148 template <class T>
00149 vgl_polygon_sheet_as_array<T>::vgl_polygon_sheet_as_array(typename vgl_polygon<T>::sheet_t const& p)
00150 {
00151   n = int(p.size());
00152   x = new T[n*2];
00153   y = x + n;
00154   for (int v = 0; v < n; ++v)
00155   {
00156     x[v] = p[v].x();
00157     y[v] = p[v].y();
00158   }
00159 }
00160 
00161 template <class T>
00162 vgl_polygon_sheet_as_array<T>::~vgl_polygon_sheet_as_array()
00163 {
00164   delete [] x;
00165   // do not delete [] y; only one alloc in ctor.
00166 }
00167 
00168 //: Compute all self-intersections between all edges on all sheets.
00169 // \returns three arrays \a e1, \a e2, and \a ip of equal size.
00170 // Corresponding elements from these arrays describe an intersection.
00171 // e1[k].first is the sheet index containing edge (e1[k].second, e1[k].second+1)
00172 // involved in the k-th intersection.  Similarly, e2[k] indexes the other
00173 // edge involved in the k-th intersection.  The corresponding intersection
00174 // point is returned in ip[k].
00175 template <class T>
00176 void vgl_selfintersections(vgl_polygon<T> const& p,
00177                            vcl_vector<vcl_pair<unsigned int,unsigned int> >& e1,
00178                            vcl_vector<vcl_pair<unsigned int,unsigned int> >& e2,
00179                            vcl_vector<vgl_point_2d<T> >& ip)
00180 {
00181   const T tol = vcl_sqrt(vgl_tolerance<T>::position);
00182   vcl_vector<unsigned int> offsets(p.num_sheets()+1,0);
00183   for (unsigned int s = 0; s < p.num_sheets(); ++s) {
00184     offsets[s+1] = offsets[s]+(unsigned int)(p[s].size());
00185   }
00186   e1.clear();
00187   e2.clear();
00188   ip.clear();
00189 
00190   typedef vcl_pair<unsigned int, unsigned int> upair;
00191   vcl_set<upair> isect_set;
00192   for (unsigned int s1 = 0; s1 < p.num_sheets(); ++s1)
00193   {
00194     const typename vgl_polygon<T>::sheet_t& sheet1 = p[s1];
00195     if (sheet1.size() < 2)
00196       continue;
00197     for (unsigned int i1=(unsigned int)(sheet1.size()-1), i1n=0; i1n < sheet1.size(); i1=i1n, ++i1n)
00198     {
00199       const vgl_point_2d<T>& v1 = sheet1[i1];
00200       const vgl_point_2d<T>& v2 = sheet1[i1n];
00201       // coefficients for linear equation for testing intersections
00202       // for (x,y) if cx*x+cy*y+c changes sign then we have intersection
00203       T cx = v1.y()-v2.y();
00204       T cy = v2.x()-v1.x();
00205       T c = v1.x()*v2.y()-v2.x()*v1.y();
00206       T norm = 1/vcl_sqrt(cx*cx+cy*cy);
00207       cx *= norm;
00208       cy *= norm;
00209       c *= norm;
00210 
00211       unsigned int idx1 = offsets[s1]+i1;
00212 
00213       // inner loop - compare against self
00214       for (unsigned int s2 = 0; s2 < p.num_sheets(); ++s2)
00215       {
00216         const typename vgl_polygon<T>::sheet_t& sheet2 = p[s2];
00217         const unsigned int size2 = (unsigned int)(sheet2.size());
00218         if (size2 < 2)
00219           continue;
00220         unsigned int start = 0, end = 0;
00221         if (s1 == s2) {
00222           start = (i1n+1)%size2;
00223           end = (i1+size2-1)%size2;
00224         }
00225 
00226         T dist = cx*sheet2[start].x()+cy*sheet2[start].y()+c;
00227         bool last_sign = dist > 0;
00228         bool last_zero = vcl_abs(dist) <= tol;
00229         bool first = true;
00230         for (unsigned int i2=start, i2n=(start+1)%size2; i2!=end || first; i2=i2n, i2n=(i2n+1)%size2)
00231         {
00232           const vgl_point_2d<T>& v3 = sheet2[i2];
00233           const vgl_point_2d<T>& v4 = sheet2[i2n];
00234           dist = cx*v4.x()+cy*v4.y()+c;
00235           bool sign = dist > 0;
00236           bool zero = vcl_abs(dist) <= tol;
00237           if (sign != last_sign || zero || last_zero)
00238           {
00239             unsigned int idx2 = offsets[s2]+i2;
00240             upair pair_idx(idx1,idx2);
00241             if (pair_idx.first > pair_idx.second) {
00242               pair_idx = upair(idx2,idx1);
00243             }
00244             vcl_set<upair>::iterator f = isect_set.find(pair_idx);
00245             if (f == isect_set.end())
00246               isect_set.insert(pair_idx);
00247             // use vgl_intersection to verify some degenerate false positives
00248             else if (vgl_intersection(v1,v2,v3,v4,tol)) {
00249               // make intersection point
00250               vgl_point_2d<T> ipt;
00251               if (!vgl_intersection(vgl_line_2d<T>(v1,v2),vgl_line_2d<T>(v3,v4),ipt)
00252                   || parallel(v2-v1,v4-v3,tol)) // vgl_intersection test is not accurate enough
00253               {
00254                 // use the median point when lines are parallel
00255                 vgl_vector_2d<T> dir = v2-v1;
00256                 normalize(dir);
00257                 T t1 = 0;
00258                 T t2 = dot_product(dir,v2-v1);
00259                 T t3 = dot_product(dir,v3-v1);
00260                 T t4 = dot_product(dir,v4-v1);
00261                 T t = t1+t2+t3+t4;
00262                 t -= vcl_min(vcl_min(t1,t2),vcl_min(t3,t4));
00263                 t -= vcl_max(vcl_max(t1,t2),vcl_max(t3,t4));
00264                 t /= 2;
00265                 ipt = v1 + t*dir;
00266               }
00267               e1.push_back(upair(s2,i2));
00268               e2.push_back(upair(s1,i1));
00269               ip.push_back(ipt);
00270             }
00271           }
00272           last_sign = sign;
00273           last_zero = zero;
00274           first = false;
00275         }
00276       }
00277     }
00278   }
00279 }
00280 
00281 
00282 #undef VGL_POLYGON_INSTANTIATE
00283 #define VGL_POLYGON_INSTANTIATE(T) \
00284 template class vgl_polygon<T >; \
00285 template struct vgl_polygon_sheet_as_array<T >; \
00286 template vcl_ostream& operator<<(vcl_ostream&,vgl_polygon<T > const&); \
00287 template void vgl_selfintersections(vgl_polygon<T > const& p, \
00288                                     vcl_vector<vcl_pair<unsigned int,unsigned int> >& e1, \
00289                                     vcl_vector<vcl_pair<unsigned int,unsigned int> >& e2, \
00290                                     vcl_vector<vgl_point_2d<T > >& ip)
00291 
00292 #endif // vgl_polygon_txx_