core/vgl/vgl_convex.txx
Go to the documentation of this file.
00001 // This is core/vgl/vgl_convex.txx
00002 #ifndef vgl_convex_txx_
00003 #define vgl_convex_txx_
00004 //:
00005 // \file
00006 #include "vgl_convex.h"
00007 #include <vcl_limits.h>
00008 #include <vcl_cmath.h>
00009 #include <vcl_list.h>
00010 
00011 
00012 //: Calculate the negative cosine of the angle from dir to next - current.
00013 // If next and current are on top of each other, pretend it is a high angle.
00014 // Use cosine because it is quicker to calculate and monotonic with angle
00015 // over [0 pi].
00016 template <class T>
00017 static T get_nc_angle(const vgl_vector_2d<T> &last_dir,
00018                       const vgl_point_2d<T> &current,
00019                       const vgl_point_2d<T> &next)
00020 {
00021   vgl_vector_2d<T> v = next - current;
00022   double eps = vcl_sqrt(current.x() * current.x() + current.y() * current.y())
00023     * vcl_numeric_limits<T>::epsilon();
00024 
00025   //if the two points are on top of each other, pretend it is a very bad angle.
00026   // Use an illegal cosine value to indicate this.
00027   if (v.length() <= eps) return (T)2.0;
00028   return T(-cos_angle(last_dir, v));
00029 }
00030 
00031 template <class T>
00032 vgl_polygon<T> vgl_convex_hull(vcl_vector<vgl_point_2d<T> > const& points)
00033 {
00034   vgl_polygon<T> hull(1);
00035   if (points.empty()) return hull;
00036 
00037   typedef typename vcl_list<vgl_point_2d<T> >::iterator ITER;
00038 
00039   // A list of points still not used.
00040   vcl_list<vgl_point_2d<T> > pts(points.begin(), points.end());
00041 
00042   // Find left most point.
00043   ITER start = pts.begin();
00044   for (ITER i=pts.begin(); i != pts.end(); ++i)
00045     if (i->x() < start->x()) start=i;
00046 
00047   vgl_point_2d<T> first = *start; // Closing point on hull.
00048   vgl_point_2d<T> current = first; // Current point on hull.
00049   vgl_vector_2d<T> last_dir(0,1); // Direction of last segment added to hull.
00050   hull.push_back(first);
00051   pts.erase(start);
00052   bool not_starting = false;
00053   // iterate through remaining points
00054   while (true)
00055   {
00056     // if we are out of points, then our poly is the answer.
00057     if (pts.empty()) return hull;
00058 
00059     // Calculate angles to closing point, and all the remaining points.
00060     double nc_angle_to_first = get_nc_angle(last_dir, current, first);
00061 
00062     // If the current point is not the closing point, but is very close to it,
00063     // then we are done.
00064     if (not_starting && nc_angle_to_first > 1.5) return hull;
00065     not_starting=true;
00066 
00067     double best_nc_angle = 1.5;
00068     ITER best;
00069 
00070     for (ITER i=pts.begin(); i != pts.end(); ++i)
00071     {
00072       double nc_angle = get_nc_angle(last_dir, current, *i);
00073       if (nc_angle < best_nc_angle)
00074       {
00075         best_nc_angle = nc_angle;
00076         best = i;
00077       }
00078     }
00079 
00080     // If the closing angle is lowest, the our hull is the answer.
00081     if (nc_angle_to_first <= best_nc_angle) return hull;
00082 
00083 
00084     // Add best point to hull, remove from list, update invariant.
00085     hull.push_back(*best);
00086     last_dir=*best - current;
00087     current = * best;
00088     pts.erase(best);
00089   }
00090 }
00091 
00092 #undef VGL_CONVEX_INSTANTIATE
00093 #define VGL_CONVEX_INSTANTIATE(T) \
00094 template vgl_polygon<T > vgl_convex_hull(const vcl_vector<vgl_point_2d<T > >&)
00095 
00096 
00097 #endif // vgl_convex_txx_