CGR Localization
 All Classes Namespaces Files Functions Variables Macros Pages
grahams_scan.cpp
1 #include "grahams_scan.h"
2 
3 static const double Epsilon = 0.000001;
4 
5 GrahamsScan::GrahamsScan()
6 {
7  firstPoint = NULL;
8 }
9 
10 GrahamsScan::~GrahamsScan()
11 {
12  deleteAllPoints();
13 }
14 
15 std::vector< vector2f, std::allocator< vector2f > > GrahamsScan::run(vector< vector2f > points)
16 {
17  static const bool debug = false;
18  vector<vector2f> convexPolygon;
19  convexPolygon.clear();
20  int minPoint=0;
21  point *tempPtr;
22  NumPoints = int(points.size());
23  firstPoint=NULL; //INIT FIRSTPOINT POINTER
24 
25  if(NumPoints<4)
26  return points;
27 
28  if(debug) printf("\nGraham scan:\n");
29  for (int k=1;k<NumPoints;k++){ //FIND MIN POINT
30  if(debug)
31  printf("%d. %7.4f , %7.4f\n",k,V2COMP(points[k]));
32  if( (points[k].y==points[minPoint].y && points[k].x<points[minPoint].x) ||
33  (points[k].y<points[minPoint].y) )
34  minPoint=k;
35  }
36 
37  if(debug) printf("%d points, minPoint:%d\n",NumPoints, minPoint);
38  /*
39  if(printDebugStream)
40  debugStream<<NumPoints<<" points, minPoint:"<<minPoint<<"\n";
41  */
42 
44  for (int i=0;i<NumPoints;i++){ //SORT RANDOM POINTS
45  p.loc = points[i];
46  p.angle = findAngle(points[minPoint],points[i]);
47  addPoint(p);
48  }
49 
50  tempPtr=firstPoint;
51  do{ //FIND LAST NODE IN LINKED LIST
52  tempPtr=tempPtr->next;
53  } while (tempPtr->next!=NULL);
54 
55  tempPtr->next=firstPoint; //COMPLETE CIRCULAR LINKED LIST
56  firstPoint->prev=tempPtr; //COMPLETE CIRCULAR LINKED LIST
57  if(debug){
58  tempPtr=firstPoint;
59  int k=0;
60  printf("Sorted list:\n");
61  do{ //FIND LAST NODE IN LINKED LIST
62  printf("%d. %7.4f , %7.4f (%7.4f , %7.4f @ %.7f\u00b0)\n",k,V2COMP(tempPtr->loc),V2COMP(tempPtr->loc-firstPoint->loc), DEG((tempPtr->loc-firstPoint->loc).angle()));
63  tempPtr=tempPtr->next;
64  k++;
65  } while (tempPtr!=firstPoint);
66  printf("Checking Convexity:\n");
67  }
68  grahamScan(firstPoint);
69 
70  tempPtr=firstPoint;
71  for (int i=0;i<NumPoints;i++)
72  {
73  convexPolygon.push_back(tempPtr->loc);
74  tempPtr=tempPtr->next;
75  if(tempPtr==firstPoint)
76  break;
77  }
78  deleteAllPoints();
79  return convexPolygon;
80 }
81 
82 void GrahamsScan::grahamScan(GrahamsScan::point* P)
83 {
84  static const bool debug = false;
85  point *tempPrev, *tempNext;
86  P=P->next;
87  do{
88  while(P!=firstPoint && !isConvexPoint(P)){
89  if(P->prev==firstPoint){
90  tempPrev=P->prev;
91  tempNext=P->next;
92  tempPrev->next=tempNext;
93  tempNext->prev=tempPrev;
94  if(debug) printf("deleting colinear point %f,%f\n",V2COMP(P->loc));
95  delete P; //FREE MEMORY
96  P = tempNext;
97  }else{
98  tempPrev=P->prev;
99  tempNext=P->next;
100  tempPrev->next=tempNext;
101  tempNext->prev=tempPrev;
102  if(debug) printf("deleting non-convex point %f,%f\n",V2COMP(P->loc));
103  delete P; //FREE MEMORY
104  P = tempPrev;
105  }
106  }
107  if(debug) printf("accepting convex point %f,%f\n",V2COMP(P->loc));
108  P = P->next;
109  }while(P != firstPoint);
110 
111 }
112 
113 bool GrahamsScan::isConvexPoint(GrahamsScan::point* P)
114 {
115  return (P->loc - P->prev->loc).cross(P->next->loc - P->loc) > 0.0;
116 }
117 
118 double GrahamsScan::findAngle(vector2f& loc1, vector2f& loc2)
119 {
120  //This function doesn't really return the true angle, it just returns a value x between -2 to 2 such that
121  // there is a one to one mapping between true angle and x, with x(0)=0, x(pi/2)=1, x(pi-eps)=2,
122  // x(-pi/2)=-1, and x(-pi+eps)=-2
123  // This works for Graham's algorithm since the true angle isn't important, only the ordering of angles is.
124 
125  vector2f delta = loc2-loc1;
126 
127  double d = delta.length();
128  if(fabs(delta.x)<DBL_MIN){
129  if(delta.y>0.0)
130  return 1.0;
131  else
132  return -1.0;
133  }else if(delta.x>0.0){
134  return delta.y/d;
135  }else{ //delta.x<0.0
136  if(delta.y>0.0)
137  return 1.0 - delta.x/d;
138  else
139  return -1.0 + delta.x/d;
140  }
141 }
142 
143 void GrahamsScan::addPoint(point& Point)
144 {
145  static const bool debug = false;
146  point *tempPoint,*tempPointA,*tempPointB, *curPoint;
147 
148  //ALLOCATE A NEW POINT STRUCTURE AND INITIALIZE INTERNAL VARIABLES
149  tempPoint = new point;
150  tempPoint->loc = Point.loc;
151  tempPoint->angle=Point.angle;
152  tempPoint->next=NULL;
153  tempPoint->prev=NULL;
154 
155  //TEST IF LIST IS EMPTY
156  if (firstPoint==NULL){
157  firstPoint=tempPoint;
158  return;
159  }
160 
161  //TEST IF ONLY ONE NODE IN LIST AND CURRENT NODE HAS GREATER ANGLE
162  if (firstPoint->next==NULL && tempPoint->angle >= firstPoint->angle){
163  firstPoint->next=tempPoint;
164  tempPoint->prev=firstPoint;
165  return;
166  }
167 
168  curPoint=firstPoint;
169 
170  //CONTINUE THROUGH LIST UNTIL A NODE IS FOUND WITH A GREATER ANGLE THAN CURRENT NODE
171  while ((tempPoint->angle > curPoint->angle || (tempPoint->angle + Epsilon > curPoint->angle && tempPoint->loc.y > curPoint->loc.y) )&& curPoint->next!=NULL)
172  curPoint=curPoint->next;
173 
174  //Check if the point is a duplicate
175  if(curPoint->prev != NULL){
176  if(curPoint->prev->loc==tempPoint->loc)
177  return;
178  }
179 
180  //TEST IF NODE IS FIRSTPOINT. IF SO, ADD AT FRONT OF LIST.
181  if (curPoint==firstPoint){
182  if(debug) printf("Adding %f,%f at the front\n",V2COMP(tempPoint->loc));
183  firstPoint->prev=tempPoint;
184  tempPoint->next=firstPoint;
185  firstPoint=tempPoint;
186  return;
187  }else if(curPoint->next==NULL && tempPoint->angle >= curPoint->angle){
188  //TEST IF WHILE LOOP REACHED FINAL NODE IN LIST. IF SO, ADD AT END OF THE LIST.
189  if(debug) printf("Adding %f,%f at the end\n",V2COMP(tempPoint->loc));
190  curPoint->next=tempPoint;
191  tempPoint->prev=curPoint;
192  return;
193  }else{ //OTHERWISE, INTERMEDIATE NODE HAS BEEN FOUND. INSERT INTO LIST.
194  tempPointA=curPoint->prev;
195  tempPointB=curPoint->prev->next;
196  if(debug) printf("Adding %f,%f after %f,%f\n",V2COMP(tempPoint->loc),V2COMP(tempPointA->loc));
197  tempPoint->next=tempPointB;
198  tempPoint->prev=tempPointA;
199  tempPoint->prev->next=tempPoint;
200  tempPoint->next->prev=tempPoint;
201  }
202 
203  return;
204 }
205 
206 
207 void GrahamsScan::deleteAllPoints()
208 {
209  point *curPtr = firstPoint;
210  point *nextPtr = curPtr->next;
211 
212  while(curPtr != NULL){
213  nextPtr = curPtr->next;
214  delete curPtr;
215  curPtr = nextPtr;
216  if(curPtr==firstPoint)
217  break;
218  }
219  firstPoint = NULL;
220  mzero<GrahamsScan>(*this);
221 }
num length() const MustUseResult
calculate Euclidean length
Definition: gvector.h:882