core/vgl/algo/vgl_convex_hull_2d.txx
Go to the documentation of this file.
00001 #ifndef vgl_convex_hull_2d_txx_
00002 #define vgl_convex_hull_2d_txx_
00003 #include "vgl_convex_hull_2d.h"
00004 
00005 #include <vcl_cstdlib.h> // vcl_qsort
00006 
00007 //:
00008 // \file
00009 // \brief two-dimensional convex hull
00010 // read points from stdin,
00011 //      one point per line, as two numbers separated by whitespace
00012 // on stdout, points on convex hull in order around hull, given
00013 //      by their numbers in input order
00014 // the results should be "robust", and not return a wildly wrong hull,
00015 //      despite using floating point
00016 // works in O(n log n); I think a bit faster than Graham scan;
00017 //      somewhat like Procedure 8.2 in Edelsbrunner's "Algorithms in Combinatorial
00018 //      Geometry", and very close to:
00019 //        A.M. Andrew, "Another Efficient Algorithm for Convex Hulls in Two Dimensions",
00020 //        Info. Proc. Letters 9, 216-219 (1979)
00021 //      (See also http://geometryalgorithms.com/Archive/algorithm_0110/algorithm_0110.htm)
00022 //
00023 // Ken Clarkson wrote this.  Copyright (c) 1996 by AT&T..
00024 // Permission to use, copy, modify, and distribute this software for any
00025 // purpose without fee is hereby granted, provided that this entire notice
00026 // is included in all copies of any software which is or includes a copy
00027 // or modification of this software and in all copies of the supporting
00028 // documentation for such software.
00029 // THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
00030 // WARRANTY.  IN PARTICULAR, NEITHER THE AUTHORS NOR AT&T MAKE ANY
00031 // REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
00032 // OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
00033 
00034 #if 0
00035 static void print_hull(double **P, int m)
00036 {
00037   for (int i=0; i<m; i++)
00038     vcl_cout << (P[i]-points[0])/2) << ' ';
00039   vcl_cout << vcl_endl;
00040 }
00041 #endif // 0
00042 
00043 static int ccw(double **P, int i, int j, int k)
00044 {
00045   double a = P[i][0] - P[j][0],
00046          b = P[i][1] - P[j][1],
00047          c = P[k][0] - P[j][0],
00048          d = P[k][1] - P[j][1];
00049   return a*d - b*c <= 0;   // true if points i, j, k counterclockwise
00050 }
00051 
00052 
00053 #define CMPM(c,A,B) \
00054   v = (*(double*const*)A)[c] - (*(double*const*)B)[c];\
00055   if (v>0) return 1;\
00056   if (v<0) return -1
00057 
00058 static int cmpl(const void *a, const void *b)
00059 {
00060   double v;
00061   CMPM(0,a,b);
00062   CMPM(1,b,a);
00063   return 0;
00064 }
00065 #undef CMPM
00066 
00067 static int cmph(const void *a, const void *b) {return cmpl(b,a);}
00068 
00069 
00070 static int make_chain(double** V, int n, int (*cmp)(const void*, const void*))
00071 {
00072   vcl_qsort(V, n, sizeof(double*), cmp);
00073   int s = 1;
00074   for (int i=2; i<n; i++) {
00075     while (s>=1 && ccw(V, i, s, s-1)) --s;
00076     ++s;
00077     double* t = V[s]; V[s] = V[i]; V[i] = t;
00078   }
00079   return s;
00080 }
00081 
00082 static int ch2d(double **P, int n)
00083 {
00084   int u = make_chain(P, n, cmpl);         // make lower hull
00085   if (!n) return 0;
00086   P[n] = P[0];
00087   return u+make_chain(P+u, n-u+1, cmph);  // make upper hull
00088 }
00089 
00090 template <class T>
00091 vgl_convex_hull_2d<T>::
00092 vgl_convex_hull_2d (vcl_vector<vgl_point_2d<T> > const& points)
00093 {
00094   hull_valid_ = false;
00095   points_ = points;
00096 }
00097 
00098 template <class T>
00099 void vgl_convex_hull_2d<T>::compute_hull()
00100 {
00101   //convert points to internal data structure
00102   int N = points_.size();
00103   double * array = new double[2*N];
00104   double** points = new double*[N];
00105   double** P = new double*[N+1];
00106   for (int i = 0; i<N; i++)
00107     points[i]=&array[2*i];
00108 
00109   for (int n = 0; n<N; n++)
00110   {
00111     points[n][0]=(double)points_[n].x();
00112     points[n][1]=(double)points_[n].y();
00113     P[n] = &points[n][0];
00114   }
00115   //the main hull routine
00116   int n_hull = ch2d(P, N);
00117 
00118   //convert back to vgl_points
00119   vcl_vector<vgl_point_2d<T> > temp;
00120   for (int i = 0; i<n_hull; i++)
00121   {
00122     vgl_point_2d<T> p((T)P[i][0], (T)P[i][1]);
00123     temp.push_back(p);
00124   }
00125   // Do not add last point if it is identical to the first one - PVr
00126   if (P[0][0] != P[n_hull][0] || P[0][1] != P[n_hull][1])
00127     temp.push_back(vgl_point_2d<T>((T)P[n_hull][0], (T)P[n_hull][1]));
00128 
00129   //construct the hull polygon
00130   hull_ = vgl_polygon<T>(temp);
00131   //clean up memory
00132   delete [] array;
00133   delete [] points;
00134   delete [] P;
00135   hull_valid_ = true;
00136 }
00137 
00138 template <class T>
00139 vgl_polygon<T> vgl_convex_hull_2d<T>::hull()
00140 {
00141   if (!hull_valid_)
00142     this->compute_hull();
00143   return hull_;
00144 }
00145 
00146 //----------------------------------------------------------------------------
00147 #undef VGL_CONVEX_HULL_2D_INSTANTIATE
00148 #define VGL_CONVEX_HULL_2D_INSTANTIATE(T) \
00149 /* template vcl_ostream& operator<<(vcl_ostream& s, vgl_convex_hull_2d<T >const& h); */ \
00150 /* template vcl_istream& operator>>(vcl_istream& s, vgl_convex_hull_2d<T >& h); */ \
00151 template class vgl_convex_hull_2d<T >
00152 
00153 #endif // vgl_convex_hull_2d_txx_