Skip to content

Commit 34dc43e

Browse files
committed
Fix Graham Scan
1 parent bf832a3 commit 34dc43e

File tree

2 files changed

+266
-56
lines changed

2 files changed

+266
-56
lines changed

ch_22/Exercise22_11.java

Lines changed: 75 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222
* public void setRightMostLowestPoint(MyPoint p) {<br>
2323
* rightMostLowestPoint = p;<br>
2424
* }<br>
25-
* \ @Override public int compareTo(MyPoint o) {<br>
25+
* \@Override public int compareTo(MyPoint o) {<br>
2626
* // Implement it to compare this point with point o<br>
2727
* // angularly along the x-axis with rightMostLowestPoint<br>
2828
* // as the center, as shown in Figure 22.10b. By implementing<br>
@@ -67,72 +67,99 @@ public static void main(String[] args) {
6767
}
6868

6969
public static ArrayList<MyPoint> getConvexHull(double[][] s) {
70-
/* Find Lowest and Rightest Point */
71-
double yMin = s[0][1];
72-
int minPos = 0;
73-
// Find the bottom most point
70+
/* Grahams Algorithm:
71+
Step 1: Given a list of points S, select the rightmost lowest.
72+
*/
73+
double[] lowestRightMostPt = s[0]; // initialize to first point
7474
for (int i = 1; i < s.length; i++) {
75-
double y = s[i][1];
75+
double[] nextPt = s[i];
7676
// Pick the bottom-most or chose the right
7777
// most point in case of tie
78-
if ((y < yMin) || (yMin == y && s[i][0] > s[minPos][0])) {
79-
yMin = s[i][1];
80-
minPos = i;
81-
82-
}
78+
lowestRightMostPt = getLowestRightMostPoint(lowestRightMostPt, nextPt);
8379
}
84-
// Swamp the bottom-most point for first position
85-
double[] temp = s[0];
86-
s[0] = s[minPos];
87-
s[minPos] = temp;
88-
MyPoint rightMostLowestPoint = new MyPoint(s[0][0], s[0][1]);
89-
ArrayList<MyPoint> rawPoints = new ArrayList<>();
90-
rawPoints.add(rightMostLowestPoint);
91-
// Create array of MyPoint objects and set rightMostLowestPoint
92-
for (int i = 1; i < s.length; i++) {
93-
MyPoint pt = new MyPoint(s[i][0], s[i][1]);
94-
pt.setRightMostLowestPoint(rightMostLowestPoint);
95-
rawPoints.add(pt);
96-
}
97-
ArrayList<MyPoint> cleanedPoints = new ArrayList<>();
98-
cleanedPoints.add(rightMostLowestPoint);
99-
//Clean points with same angle
100-
for (int i = 1; i < rawPoints.size() - 1; i++) {
101-
// Only add points where the angle of p[i] and p[i+1] is NOT the same with respect to p0
102-
if (orientation(rightMostLowestPoint, rawPoints.get(i), rawPoints.get(i + 1)) != 0) {
103-
cleanedPoints.add(rawPoints.get(i));
104-
}
80+
MyPoint rightMostLowestPoint = new MyPoint(lowestRightMostPt[0], lowestRightMostPt[1]);
81+
/*
82+
Step 2: Sort the points in S angularly along the x-axis with p0 as the
83+
center, as shown in Figure 22.10b. If there is a tie and two points have
84+
the same angle, discard the one that is closer to p0. The points in S are
85+
now sorted as p0, p1, p2, ..., pn-1.
86+
*/
87+
// For Step 2 - We use Comparable interface to sort the points to simplify coding.
88+
ArrayList<MyPoint> pointsList = new ArrayList<>();
89+
for (double[] pt : s) {
90+
MyPoint p = new MyPoint(pt[0], pt[1]);
91+
p.setRightMostLowestPoint(rightMostLowestPoint);
92+
pointsList.add(p);
10593
}
94+
10695
// If modified array of points has less than 3 points,
10796
// convex hull is not possible
108-
if (cleanedPoints.size() < 3) {
97+
if (pointsList.size() < 3) {
10998
throw new RuntimeException("Graham's Algorithm for ConvexHull requires " +
11099
"at least 3 points with different angles...");
111100
}
112-
Collections.sort(cleanedPoints);
101+
Collections.sort(pointsList);
113102
// Graham scan
114103
// Create an empty stack and push first three points to it
104+
/* Step 3: Push p0, p1, and p2 into stack H. (After the algorithm finishes,
105+
H contains all the points in the convex hull.)
106+
i = 3;
107+
while (i < n) {
108+
Let t1 and t2 be the top first and second element in stack H;
109+
if (pi is on the left side of the direct line from t2 to t1) {
110+
Push pi to H;
111+
i++; // Consider the next point in S.
112+
}
113+
else
114+
Pop the top element off stack H.
115+
}
116+
Step 5: The points in H form a convex hull.
117+
*/
115118
Stack<MyPoint> stack = new Stack<>();
116-
int m = cleanedPoints.size();
117-
stack.push(cleanedPoints.get(0)); // p0 (lowest and rightest point)
118-
stack.push(cleanedPoints.get(1)); // p1
119-
stack.push(cleanedPoints.get(2)); // p2
119+
int m = pointsList.size();
120+
MyPoint p0 = pointsList.get(0);
121+
MyPoint p1 = pointsList.get(1);
122+
MyPoint p2 = pointsList.get(2);
123+
stack.push(p0);
124+
stack.push(p1);
125+
stack.push(p2);
120126
// Process remaining n-3 points
121-
for (int i = 3; i < m; i++) {
127+
int i = 3;
128+
while (i < m) {
122129
// Keep removing top while the angle formed by
123130
// points next-to-top, top, and points[i] makes
124131
// a non-left turn
125-
while (orientation(nextToTop(stack), stack.peek(), cleanedPoints.get(i)) != 2) {
126-
stack.pop();
127-
stack.push(cleanedPoints.get(i));
132+
MyPoint p3 = pointsList.get(i);
133+
int orientation = orientation(p2, p1, p3);
134+
if (orientation == 2) {
135+
stack.push(p3);
136+
} else if (orientation == 1) {
137+
stack.pop(); // pop p2
138+
stack.push(p3);
139+
} else {
140+
stack.pop(); // pop p2
128141
}
142+
p2 = stack.peek();
143+
p1 = stack.get(stack.size() - 2);
144+
i++;
129145

130146
}
131147
// Now stack has the output points, print contents of stack
132-
133148
return new ArrayList<>(stack);
134149
}
135150

151+
152+
static double[] getLowestRightMostPoint(double[] pt1, double[] pt2) {
153+
if (pt2[1] < pt1[1]) {
154+
return pt2;
155+
} else if (pt2[1] == pt1[1]) {
156+
if (pt2[0] > pt1[0]) {
157+
return pt2;
158+
}
159+
}
160+
return pt1;
161+
}
162+
136163
/**
137164
* To find orientation of ordered triplet (p, q, r).
138165
*
@@ -159,17 +186,6 @@ static double distSq(MyPoint p1, MyPoint p2) {
159186
(p1.y - p2.y) * (p1.y - p2.y);
160187
}
161188

162-
/**
163-
* A utility function to find next to top in a stack
164-
*/
165-
static MyPoint nextToTop(Stack<MyPoint> s) {
166-
MyPoint p = s.pop();
167-
MyPoint res = s.peek();
168-
s.push(p);
169-
return res;
170-
}
171-
172-
173189
private static class MyPoint implements Comparable<MyPoint> {
174190
double x, y;
175191
MyPoint rightMostLowestPoint;
@@ -195,15 +211,18 @@ public int compareTo(MyPoint o) {
195211
// Find orientation
196212
int orientation = orientation(rightMostLowestPoint, this, o);
197213
if (orientation == 0) {
198-
return distSq(rightMostLowestPoint, o) >= distSq(rightMostLowestPoint, this) ? -1 : 1;
214+
double distSqObj1 = distSq(rightMostLowestPoint, this);
215+
double distSqObj2 = distSq(rightMostLowestPoint, o);
216+
return Double.compare(distSqObj1, distSqObj2);
199217
}
200-
return (orientation == 2) ? -1 : 1;
218+
return (orientation == 2) ? 1 : -1;
201219
}
202220

203221
@Override
204222
public String toString() {
205223
return "(" + x + ", " + y + ")";
206224
}
225+
207226
}
208227

209228
}

ch_22/Exercise22_13.java

Lines changed: 191 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,191 @@
1+
package ch_22;
2+
3+
import java.util.*;
4+
5+
/**
6+
* **22.13 (Geometry: convex hull animation) Programming Exercise 22.11 finds a convex hull for a set of points
7+
* entered from the console. Write a program that enables the user to add/remove points by clicking the left/right
8+
* mouse button, and displays a convex hull, as shown in Figure 22.8c.
9+
*/
10+
public class Exercise22_13 {
11+
public static void main(String[] args) {
12+
Scanner scanner = new Scanner(System.in);
13+
System.out.print("How many points are in the set? ");
14+
int numPoints = scanner.nextInt();
15+
if (numPoints < 3) {
16+
throw new RuntimeException("Graham's Algorithm for ConvexHull requires at least 3 points...");
17+
}
18+
19+
double[][] points = new double[numPoints][2];
20+
System.out.print("Enter " + numPoints + " points: ");
21+
22+
for (int i = 0; i < points.length; i++) {
23+
for (int j = 0; j < 2; j++) {
24+
points[i][j] = scanner.nextDouble();
25+
}
26+
}
27+
List<MyPoint> result = getConvexHull(points);
28+
System.out.println("The convex hull is: ");
29+
System.out.println(Arrays.toString(result.toArray()));
30+
}
31+
32+
public static ArrayList<MyPoint> getConvexHull(double[][] s) {
33+
/* Grahams Algorithm:
34+
Step 1: Given a list of points S, select the rightmost lowest.
35+
*/
36+
double[] lowestRightMostPt = s[0]; // initialize to first point
37+
for (int i = 1; i < s.length; i++) {
38+
double[] nextPt = s[i];
39+
// Pick the bottom-most or chose the right
40+
// most point in case of tie
41+
lowestRightMostPt = getLowestRightMostPoint(lowestRightMostPt, nextPt);
42+
}
43+
MyPoint rightMostLowestPoint = new MyPoint(lowestRightMostPt[0], lowestRightMostPt[1]);
44+
/*
45+
Step 2: Sort the points in S angularly along the x-axis with p0 as the
46+
center, as shown in Figure 22.10b. If there is a tie and two points have
47+
the same angle, discard the one that is closer to p0. The points in S are
48+
now sorted as p0, p1, p2, ..., pn-1.
49+
*/
50+
// For Step 2 - We use Comparable interface to sort the points to simplify coding.
51+
ArrayList<MyPoint> pointsList = new ArrayList<>();
52+
for (double[] pt : s) {
53+
MyPoint p = new MyPoint(pt[0], pt[1]);
54+
p.setRightMostLowestPoint(rightMostLowestPoint);
55+
pointsList.add(p);
56+
}
57+
58+
// If modified array of points has less than 3 points,
59+
// convex hull is not possible
60+
if (pointsList.size() < 3) {
61+
throw new RuntimeException("Graham's Algorithm for ConvexHull requires " +
62+
"at least 3 points with different angles...");
63+
}
64+
Collections.sort(pointsList);
65+
// Graham scan
66+
// Create an empty stack and push first three points to it
67+
/* Step 3: Push p0, p1, and p2 into stack H. (After the algorithm finishes,
68+
H contains all the points in the convex hull.)
69+
i = 3;
70+
while (i < n) {
71+
Let t1 and t2 be the top first and second element in stack H;
72+
if (pi is on the left side of the direct line from t2 to t1) {
73+
Push pi to H;
74+
i++; // Consider the next point in S.
75+
}
76+
else
77+
Pop the top element off stack H.
78+
}
79+
Step 5: The points in H form a convex hull.
80+
*/
81+
Stack<MyPoint> stack = new Stack<>();
82+
int m = pointsList.size();
83+
MyPoint p0 = pointsList.get(0);
84+
MyPoint p1 = pointsList.get(1);
85+
MyPoint p2 = pointsList.get(2);
86+
stack.push(p0);
87+
stack.push(p1);
88+
stack.push(p2);
89+
// Process remaining n-3 points
90+
int i = 3;
91+
while (i < m) {
92+
// Keep removing top while the angle formed by
93+
// points next-to-top, top, and points[i] makes
94+
// a non-left turn
95+
MyPoint p3 = pointsList.get(i);
96+
int orientation = orientation(p2, p1, p3);
97+
if (orientation == 2) {
98+
stack.push(p3);
99+
} else if (orientation == 1) {
100+
stack.pop(); // pop p2
101+
stack.push(p3);
102+
} else {
103+
stack.pop(); // pop p2
104+
}
105+
p2 = stack.peek();
106+
p1 = stack.get(stack.size() - 2);
107+
i++;
108+
109+
}
110+
// Now stack has the output points, print contents of stack
111+
return new ArrayList<>(stack);
112+
}
113+
114+
115+
static double[] getLowestRightMostPoint(double[] pt1, double[] pt2) {
116+
if (pt2[1] < pt1[1]) {
117+
return pt2;
118+
} else if (pt2[1] == pt1[1]) {
119+
if (pt2[0] > pt1[0]) {
120+
return pt2;
121+
}
122+
}
123+
return pt1;
124+
}
125+
126+
/**
127+
* To find orientation of ordered triplet (p, q, r).
128+
*
129+
* @param p first point
130+
* @param q second point
131+
* @param r third point
132+
* @return 0 --> p, q and r are co-linear
133+
* 1 --> Clockwise
134+
* 2 --> Counterclockwise
135+
*/
136+
static int orientation(MyPoint p, MyPoint q, MyPoint r) {
137+
double val = (q.y - p.y) * (r.x - q.x) - (q.x - p.x) * (r.y - q.y);
138+
if (val == 0) return 0; // co-linear
139+
return (val > 0) ? 1 : 2; // clock or counter-clock wise
140+
}
141+
142+
143+
/**
144+
* A utility function to return square of distance
145+
* between p1 and p2
146+
*/
147+
static double distSq(MyPoint p1, MyPoint p2) {
148+
return (p1.x - p2.x) * (p1.x - p2.x) +
149+
(p1.y - p2.y) * (p1.y - p2.y);
150+
}
151+
152+
private static class MyPoint implements Comparable<MyPoint> {
153+
double x, y;
154+
MyPoint rightMostLowestPoint;
155+
156+
MyPoint(double x, double y) {
157+
this.x = x;
158+
this.y = y;
159+
}
160+
161+
public void setRightMostLowestPoint(MyPoint p) {
162+
rightMostLowestPoint = p;
163+
}
164+
165+
/**
166+
* Implement it to compare this point with point o
167+
* angularly along the x-axis with rightMostLowestPoint
168+
* as the center, as shown in Figure 22.10b. By implementing
169+
* the Comparable interface, you can use the Array.sort()
170+
* method to sort the points to simplify coding.
171+
*/
172+
@Override
173+
public int compareTo(MyPoint o) {
174+
// Find orientation
175+
int orientation = orientation(rightMostLowestPoint, this, o);
176+
if (orientation == 0) {
177+
double distSqObj1 = distSq(rightMostLowestPoint, this);
178+
double distSqObj2 = distSq(rightMostLowestPoint, o);
179+
return Double.compare(distSqObj1, distSqObj2);
180+
}
181+
return (orientation == 2) ? 1 : -1;
182+
}
183+
184+
@Override
185+
public String toString() {
186+
return "(" + x + ", " + y + ")";
187+
}
188+
189+
}
190+
191+
}

0 commit comments

Comments
 (0)