diff --git a/ch_22/Exercise22_11.java b/ch_22/Exercise22_11.java
index c8371c0..5abab62 100644
--- a/ch_22/Exercise22_11.java
+++ b/ch_22/Exercise22_11.java
@@ -22,7 +22,7 @@
* public void setRightMostLowestPoint(MyPoint p) {
* rightMostLowestPoint = p;
* }
- * \ @Override public int compareTo(MyPoint o) {
+ * \@Override public int compareTo(MyPoint o) {
* // Implement it to compare this point with point o
* // angularly along the x-axis with rightMostLowestPoint
* // as the center, as shown in Figure 22.10b. By implementing
@@ -67,72 +67,99 @@ public static void main(String[] args) {
}
public static ArrayList getConvexHull(double[][] s) {
- /* Find Lowest and Rightest Point */
- double yMin = s[0][1];
- int minPos = 0;
- // Find the bottom most point
+ /* Grahams Algorithm:
+ Step 1: Given a list of points S, select the rightmost lowest.
+ */
+ double[] lowestRightMostPt = s[0]; // initialize to first point
for (int i = 1; i < s.length; i++) {
- double y = s[i][1];
+ double[] nextPt = s[i];
// Pick the bottom-most or chose the right
// most point in case of tie
- if ((y < yMin) || (yMin == y && s[i][0] > s[minPos][0])) {
- yMin = s[i][1];
- minPos = i;
-
- }
+ lowestRightMostPt = getLowestRightMostPoint(lowestRightMostPt, nextPt);
}
- // Swamp the bottom-most point for first position
- double[] temp = s[0];
- s[0] = s[minPos];
- s[minPos] = temp;
- MyPoint rightMostLowestPoint = new MyPoint(s[0][0], s[0][1]);
- ArrayList rawPoints = new ArrayList<>();
- rawPoints.add(rightMostLowestPoint);
- // Create array of MyPoint objects and set rightMostLowestPoint
- for (int i = 1; i < s.length; i++) {
- MyPoint pt = new MyPoint(s[i][0], s[i][1]);
- pt.setRightMostLowestPoint(rightMostLowestPoint);
- rawPoints.add(pt);
- }
- ArrayList cleanedPoints = new ArrayList<>();
- cleanedPoints.add(rightMostLowestPoint);
- //Clean points with same angle
- for (int i = 1; i < rawPoints.size() - 1; i++) {
- // Only add points where the angle of p[i] and p[i+1] is NOT the same with respect to p0
- if (orientation(rightMostLowestPoint, rawPoints.get(i), rawPoints.get(i + 1)) != 0) {
- cleanedPoints.add(rawPoints.get(i));
- }
+ MyPoint rightMostLowestPoint = new MyPoint(lowestRightMostPt[0], lowestRightMostPt[1]);
+ /*
+ Step 2: Sort the points in S angularly along the x-axis with p0 as the
+ center, as shown in Figure 22.10b. If there is a tie and two points have
+ the same angle, discard the one that is closer to p0. The points in S are
+ now sorted as p0, p1, p2, ..., pn-1.
+ */
+ // For Step 2 - We use Comparable interface to sort the points to simplify coding.
+ ArrayList pointsList = new ArrayList<>();
+ for (double[] pt : s) {
+ MyPoint p = new MyPoint(pt[0], pt[1]);
+ p.setRightMostLowestPoint(rightMostLowestPoint);
+ pointsList.add(p);
}
+
// If modified array of points has less than 3 points,
// convex hull is not possible
- if (cleanedPoints.size() < 3) {
+ if (pointsList.size() < 3) {
throw new RuntimeException("Graham's Algorithm for ConvexHull requires " +
"at least 3 points with different angles...");
}
- Collections.sort(cleanedPoints);
+ Collections.sort(pointsList);
// Graham scan
// Create an empty stack and push first three points to it
+ /* Step 3: Push p0, p1, and p2 into stack H. (After the algorithm finishes,
+ H contains all the points in the convex hull.)
+ i = 3;
+ while (i < n) {
+ Let t1 and t2 be the top first and second element in stack H;
+ if (pi is on the left side of the direct line from t2 to t1) {
+ Push pi to H;
+ i++; // Consider the next point in S.
+ }
+ else
+ Pop the top element off stack H.
+ }
+ Step 5: The points in H form a convex hull.
+ */
Stack stack = new Stack<>();
- int m = cleanedPoints.size();
- stack.push(cleanedPoints.get(0)); // p0 (lowest and rightest point)
- stack.push(cleanedPoints.get(1)); // p1
- stack.push(cleanedPoints.get(2)); // p2
+ int m = pointsList.size();
+ MyPoint p0 = pointsList.get(0);
+ MyPoint p1 = pointsList.get(1);
+ MyPoint p2 = pointsList.get(2);
+ stack.push(p0);
+ stack.push(p1);
+ stack.push(p2);
// Process remaining n-3 points
- for (int i = 3; i < m; i++) {
+ int i = 3;
+ while (i < m) {
// Keep removing top while the angle formed by
// points next-to-top, top, and points[i] makes
// a non-left turn
- while (orientation(nextToTop(stack), stack.peek(), cleanedPoints.get(i)) != 2) {
- stack.pop();
- stack.push(cleanedPoints.get(i));
+ MyPoint p3 = pointsList.get(i);
+ int orientation = orientation(p2, p1, p3);
+ if (orientation == 2) {
+ stack.push(p3);
+ } else if (orientation == 1) {
+ stack.pop(); // pop p2
+ stack.push(p3);
+ } else {
+ stack.pop(); // pop p2
}
+ p2 = stack.peek();
+ p1 = stack.get(stack.size() - 2);
+ i++;
}
// Now stack has the output points, print contents of stack
-
return new ArrayList<>(stack);
}
+
+ static double[] getLowestRightMostPoint(double[] pt1, double[] pt2) {
+ if (pt2[1] < pt1[1]) {
+ return pt2;
+ } else if (pt2[1] == pt1[1]) {
+ if (pt2[0] > pt1[0]) {
+ return pt2;
+ }
+ }
+ return pt1;
+ }
+
/**
* To find orientation of ordered triplet (p, q, r).
*
@@ -159,17 +186,6 @@ static double distSq(MyPoint p1, MyPoint p2) {
(p1.y - p2.y) * (p1.y - p2.y);
}
- /**
- * A utility function to find next to top in a stack
- */
- static MyPoint nextToTop(Stack s) {
- MyPoint p = s.pop();
- MyPoint res = s.peek();
- s.push(p);
- return res;
- }
-
-
private static class MyPoint implements Comparable {
double x, y;
MyPoint rightMostLowestPoint;
@@ -195,15 +211,18 @@ public int compareTo(MyPoint o) {
// Find orientation
int orientation = orientation(rightMostLowestPoint, this, o);
if (orientation == 0) {
- return distSq(rightMostLowestPoint, o) >= distSq(rightMostLowestPoint, this) ? -1 : 1;
+ double distSqObj1 = distSq(rightMostLowestPoint, this);
+ double distSqObj2 = distSq(rightMostLowestPoint, o);
+ return Double.compare(distSqObj1, distSqObj2);
}
- return (orientation == 2) ? -1 : 1;
+ return (orientation == 2) ? 1 : -1;
}
@Override
public String toString() {
return "(" + x + ", " + y + ")";
}
+
}
}
diff --git a/ch_22/Exercise22_13.java b/ch_22/Exercise22_13.java
new file mode 100644
index 0000000..c918326
--- /dev/null
+++ b/ch_22/Exercise22_13.java
@@ -0,0 +1,191 @@
+package ch_22;
+
+import java.util.*;
+
+/**
+ * **22.13 (Geometry: convex hull animation) Programming Exercise 22.11 finds a convex hull for a set of points
+ * entered from the console. Write a program that enables the user to add/remove points by clicking the left/right
+ * mouse button, and displays a convex hull, as shown in Figure 22.8c.
+ */
+public class Exercise22_13 {
+ public static void main(String[] args) {
+ Scanner scanner = new Scanner(System.in);
+ System.out.print("How many points are in the set? ");
+ int numPoints = scanner.nextInt();
+ if (numPoints < 3) {
+ throw new RuntimeException("Graham's Algorithm for ConvexHull requires at least 3 points...");
+ }
+
+ double[][] points = new double[numPoints][2];
+ System.out.print("Enter " + numPoints + " points: ");
+
+ for (int i = 0; i < points.length; i++) {
+ for (int j = 0; j < 2; j++) {
+ points[i][j] = scanner.nextDouble();
+ }
+ }
+ List result = getConvexHull(points);
+ System.out.println("The convex hull is: ");
+ System.out.println(Arrays.toString(result.toArray()));
+ }
+
+ public static ArrayList getConvexHull(double[][] s) {
+ /* Grahams Algorithm:
+ Step 1: Given a list of points S, select the rightmost lowest.
+ */
+ double[] lowestRightMostPt = s[0]; // initialize to first point
+ for (int i = 1; i < s.length; i++) {
+ double[] nextPt = s[i];
+ // Pick the bottom-most or chose the right
+ // most point in case of tie
+ lowestRightMostPt = getLowestRightMostPoint(lowestRightMostPt, nextPt);
+ }
+ MyPoint rightMostLowestPoint = new MyPoint(lowestRightMostPt[0], lowestRightMostPt[1]);
+ /*
+ Step 2: Sort the points in S angularly along the x-axis with p0 as the
+ center, as shown in Figure 22.10b. If there is a tie and two points have
+ the same angle, discard the one that is closer to p0. The points in S are
+ now sorted as p0, p1, p2, ..., pn-1.
+ */
+ // For Step 2 - We use Comparable interface to sort the points to simplify coding.
+ ArrayList pointsList = new ArrayList<>();
+ for (double[] pt : s) {
+ MyPoint p = new MyPoint(pt[0], pt[1]);
+ p.setRightMostLowestPoint(rightMostLowestPoint);
+ pointsList.add(p);
+ }
+
+ // If modified array of points has less than 3 points,
+ // convex hull is not possible
+ if (pointsList.size() < 3) {
+ throw new RuntimeException("Graham's Algorithm for ConvexHull requires " +
+ "at least 3 points with different angles...");
+ }
+ Collections.sort(pointsList);
+ // Graham scan
+ // Create an empty stack and push first three points to it
+ /* Step 3: Push p0, p1, and p2 into stack H. (After the algorithm finishes,
+ H contains all the points in the convex hull.)
+ i = 3;
+ while (i < n) {
+ Let t1 and t2 be the top first and second element in stack H;
+ if (pi is on the left side of the direct line from t2 to t1) {
+ Push pi to H;
+ i++; // Consider the next point in S.
+ }
+ else
+ Pop the top element off stack H.
+ }
+ Step 5: The points in H form a convex hull.
+ */
+ Stack stack = new Stack<>();
+ int m = pointsList.size();
+ MyPoint p0 = pointsList.get(0);
+ MyPoint p1 = pointsList.get(1);
+ MyPoint p2 = pointsList.get(2);
+ stack.push(p0);
+ stack.push(p1);
+ stack.push(p2);
+ // Process remaining n-3 points
+ int i = 3;
+ while (i < m) {
+ // Keep removing top while the angle formed by
+ // points next-to-top, top, and points[i] makes
+ // a non-left turn
+ MyPoint p3 = pointsList.get(i);
+ int orientation = orientation(p2, p1, p3);
+ if (orientation == 2) {
+ stack.push(p3);
+ } else if (orientation == 1) {
+ stack.pop(); // pop p2
+ stack.push(p3);
+ } else {
+ stack.pop(); // pop p2
+ }
+ p2 = stack.peek();
+ p1 = stack.get(stack.size() - 2);
+ i++;
+
+ }
+ // Now stack has the output points, print contents of stack
+ return new ArrayList<>(stack);
+ }
+
+
+ static double[] getLowestRightMostPoint(double[] pt1, double[] pt2) {
+ if (pt2[1] < pt1[1]) {
+ return pt2;
+ } else if (pt2[1] == pt1[1]) {
+ if (pt2[0] > pt1[0]) {
+ return pt2;
+ }
+ }
+ return pt1;
+ }
+
+ /**
+ * To find orientation of ordered triplet (p, q, r).
+ *
+ * @param p first point
+ * @param q second point
+ * @param r third point
+ * @return 0 --> p, q and r are co-linear
+ * 1 --> Clockwise
+ * 2 --> Counterclockwise
+ */
+ static int orientation(MyPoint p, MyPoint q, MyPoint r) {
+ double val = (q.y - p.y) * (r.x - q.x) - (q.x - p.x) * (r.y - q.y);
+ if (val == 0) return 0; // co-linear
+ return (val > 0) ? 1 : 2; // clock or counter-clock wise
+ }
+
+
+ /**
+ * A utility function to return square of distance
+ * between p1 and p2
+ */
+ static double distSq(MyPoint p1, MyPoint p2) {
+ return (p1.x - p2.x) * (p1.x - p2.x) +
+ (p1.y - p2.y) * (p1.y - p2.y);
+ }
+
+ private static class MyPoint implements Comparable {
+ double x, y;
+ MyPoint rightMostLowestPoint;
+
+ MyPoint(double x, double y) {
+ this.x = x;
+ this.y = y;
+ }
+
+ public void setRightMostLowestPoint(MyPoint p) {
+ rightMostLowestPoint = p;
+ }
+
+ /**
+ * Implement it to compare this point with point o
+ * angularly along the x-axis with rightMostLowestPoint
+ * as the center, as shown in Figure 22.10b. By implementing
+ * the Comparable interface, you can use the Array.sort()
+ * method to sort the points to simplify coding.
+ */
+ @Override
+ public int compareTo(MyPoint o) {
+ // Find orientation
+ int orientation = orientation(rightMostLowestPoint, this, o);
+ if (orientation == 0) {
+ double distSqObj1 = distSq(rightMostLowestPoint, this);
+ double distSqObj2 = distSq(rightMostLowestPoint, o);
+ return Double.compare(distSqObj1, distSqObj2);
+ }
+ return (orientation == 2) ? 1 : -1;
+ }
+
+ @Override
+ public String toString() {
+ return "(" + x + ", " + y + ")";
+ }
+
+ }
+
+}
\ No newline at end of file