vgl_convex.hxx
Go to the documentation of this file.
1 // This is core/vgl/vgl_convex.hxx
2 #ifndef vgl_convex_hxx_
3 #define vgl_convex_hxx_
4 //:
5 // \file
6 #include <limits>
7 #include <cmath>
8 #include <list>
9 #include "vgl_convex.h"
10 #ifdef _MSC_VER
11 # include <vcl_msvc_warnings.h>
12 #endif
13 
14 
15 //: Calculate the negative cosine of the angle from dir to next - current.
16 // If next and current are on top of each other, pretend it is a high angle.
17 // Use cosine because it is quicker to calculate and monotonic with angle
18 // over [0 pi].
19 template <class T>
20 static T get_nc_angle(const vgl_vector_2d<T> &last_dir,
21  const vgl_point_2d<T> &current,
22  const vgl_point_2d<T> &next)
23 {
24  vgl_vector_2d<T> v = next - current;
25  double eps = std::sqrt(current.x() * current.x() + current.y() * current.y())
26  * std::numeric_limits<T>::epsilon();
27 
28  //if the two points are on top of each other, pretend it is a very bad angle.
29  // Use an illegal cosine value to indicate this.
30  if (v.length() <= eps) return (T)2.0;
31  return T(-cos_angle(last_dir, v));
32 }
33 
34 template <class T>
35 vgl_polygon<T> vgl_convex_hull(std::vector<vgl_point_2d<T> > const& points)
36 {
37  vgl_polygon<T> hull(1);
38  if (points.empty()) return hull;
39 
40  typedef typename std::list<vgl_point_2d<T> >::iterator ITER;
41 
42  // A list of points still not used.
43  std::list<vgl_point_2d<T> > pts(points.begin(), points.end());
44 
45  // Find left most point.
46  ITER start = pts.begin();
47  for (ITER i=pts.begin(); i != pts.end(); ++i)
48  if (i->x() < start->x()) start=i;
49 
50  vgl_point_2d<T> first = *start; // Closing point on hull.
51  vgl_point_2d<T> current = first; // Current point on hull.
52  vgl_vector_2d<T> last_dir(0,1); // Direction of last segment added to hull.
53  hull.push_back(first);
54  pts.erase(start);
55  bool not_starting = false;
56  // iterate through remaining points
57  while (true)
58  {
59  // if we are out of points, then our poly is the answer.
60  if (pts.empty()) return hull;
61 
62  // Calculate angles to closing point, and all the remaining points.
63  double nc_angle_to_first = get_nc_angle(last_dir, current, first);
64 
65  // If the current point is not the closing point, but is very close to it,
66  // then we are done.
67  if (not_starting && nc_angle_to_first > 1.5) return hull;
68  not_starting=true;
69 
70  double best_nc_angle = 1.5;
71  ITER best;
72 
73  for (ITER i=pts.begin(); i != pts.end(); ++i)
74  {
75  double nc_angle = get_nc_angle(last_dir, current, *i);
76  if (nc_angle < best_nc_angle)
77  {
78  best_nc_angle = nc_angle;
79  best = i;
80  }
81  }
82 
83  // If the closing angle is lowest, the our hull is the answer.
84  if (nc_angle_to_first <= best_nc_angle) return hull;
85 
86 
87  // Add best point to hull, remove from list, update invariant.
88  hull.push_back(*best);
89  last_dir=*best - current;
90  current = * best;
91  pts.erase(best);
92  }
93 }
94 
95 #undef VGL_CONVEX_INSTANTIATE
96 #define VGL_CONVEX_INSTANTIATE(T) \
97 template vgl_polygon<T > vgl_convex_hull(const std::vector<vgl_point_2d<T > >&)
98 
99 
100 #endif // vgl_convex_hxx_
Direction vector in Euclidean 2D space, templated by type of element.
Definition: vgl_fwd.h:12
vgl_polygon< T > vgl_convex_hull(std::vector< vgl_point_2d< T > > const &points)
Return a single-sheet polygon which is the smallest one containing all given points.
Functions such as convex hull, convex union, convexify polygon, ...
#define v
Definition: vgl_vector_2d.h:74
void push_back(T x, T y)
Add a new point to the last sheet.
Definition: vgl_polygon.hxx:81
Store a polygon.
Definition: vgl_area.h:6
double cos_angle(v const &a, v const &b)
cosine of the angle between two vectors.