Skip to content

Commit

Permalink
formatting.
Browse files Browse the repository at this point in the history
  • Loading branch information
swannodette committed Aug 13, 2009
1 parent 7df4567 commit 187eb07
Show file tree
Hide file tree
Showing 4 changed files with 192 additions and 193 deletions.
260 changes: 130 additions & 130 deletions JarvisMarch.java
Original file line number Diff line number Diff line change
@@ -1,139 +1,139 @@
import java.util.*;

public class JarvisMarch {
Points pts;
private Points hullPoints = null;
private List<Double> hy;
private List<Double> hx;
private int startingPoint;
private double currentAngle;
private static final double MAX_ANGLE = 4;

public JarvisMarch(Points pts) {
this.pts = pts;
Points pts;
private Points hullPoints = null;
private List<Double> hy;
private List<Double> hx;
private int startingPoint;
private double currentAngle;
private static final double MAX_ANGLE = 4;

public JarvisMarch(Points pts) {
this.pts = pts;
}

/**
* The Jarvis March, sometimes known as the Gift Wrap Algorithm.
* The next point is the point with the next largest angle.
* <p/>
* Imagine wrapping a string around a set of nails in a board. Tie the string to the leftmost nail
* and hold the string vertical. Now move the string clockwise until you hit the next, then the next, then
* the next. When the string is vertical again, you will have found the hull.
*/
public int calculateHull() {
initializeHull();

startingPoint = getStartingPoint();
currentAngle = 0;

addToHull(startingPoint);
for (int p = getNextPoint(startingPoint); p != startingPoint; p = getNextPoint(p))
addToHull(p);

buildHullPoints();
return hullPoints.x.length;
}

public int getStartingPoint() {
return pts.startingPoint();
}

private int getNextPoint(int p) {
double minAngle = MAX_ANGLE;
int minP = startingPoint;
for (int i = 0; i < pts.x.length; i++) {
if (i != p) {
double thisAngle = relativeAngle(i, p);
if (thisAngle >= currentAngle && thisAngle <= minAngle) {
minP = i;
minAngle = thisAngle;
}
}
}

/**
* The Jarvis March, sometimes known as the Gift Wrap Algorithm.
* The next point is the point with the next largest angle.
* <p/>
* Imagine wrapping a string around a set of nails in a board. Tie the string to the leftmost nail
* and hold the string vertical. Now move the string clockwise until you hit the next, then the next, then
* the next. When the string is vertical again, you will have found the hull.
*/
public int calculateHull() {
initializeHull();

startingPoint = getStartingPoint();
currentAngle = 0;

addToHull(startingPoint);
for (int p = getNextPoint(startingPoint); p != startingPoint; p = getNextPoint(p))
addToHull(p);

buildHullPoints();
return hullPoints.x.length;
}

public int getStartingPoint() {
return pts.startingPoint();
}

private int getNextPoint(int p) {
double minAngle = MAX_ANGLE;
int minP = startingPoint;
for (int i = 0; i < pts.x.length; i++) {
if (i != p) {
double thisAngle = relativeAngle(i, p);
if (thisAngle >= currentAngle && thisAngle <= minAngle) {
minP = i;
minAngle = thisAngle;
}
}
}
currentAngle = minAngle;
return minP;
}

private double relativeAngle(int i, int p) {return pseudoAngle(pts.x[i] - pts.x[p], pts.y[i] - pts.y[p]);}

private void initializeHull() {
hx = new LinkedList<Double>();
hy = new LinkedList<Double>();
}

private void buildHullPoints() {
double[] ax = new double[hx.size()];
double[] ay = new double[hy.size()];
int n = 0;
for (Iterator<Double> ix = hx.iterator(); ix.hasNext();)
ax[n++] = ix.next();

n = 0;
for (Iterator<Double> iy = hy.iterator(); iy.hasNext();)
ay[n++] = iy.next();

hullPoints = new Points(ax, ay);
}

private void addToHull(int p) {
hx.add(pts.x[p]);
hy.add(pts.y[p]);
}

/**
* The PseudoAngle is a number that increases as the angle from vertical increases.
* The current implementation has the maximum pseudo angle < 4. The pseudo angle for each quadrant is 1.
* The algorithm is very simple. It just finds where the angle intesects a square and measures the
* perimeter of the square at that point. The math is in my Sept '06 notebook. UncleBob.
*/
public static double pseudoAngle(double dx, double dy) {
if (dx >= 0 && dy >= 0)
return quadrantOnePseudoAngle(dx, dy);
if (dx >= 0 && dy < 0)
return 1 + quadrantOnePseudoAngle(Math.abs(dy), dx);
if (dx < 0 && dy < 0)
return 2 + quadrantOnePseudoAngle(Math.abs(dx), Math.abs(dy));
if (dx < 0 && dy >= 0)
return 3 + quadrantOnePseudoAngle(dy, Math.abs(dx));
throw new Error("Impossible");
}

public static double quadrantOnePseudoAngle(double dx, double dy) {
return dx / (dy + dx);
currentAngle = minAngle;
return minP;
}

private double relativeAngle(int i, int p) {return pseudoAngle(pts.x[i] - pts.x[p], pts.y[i] - pts.y[p]);}

private void initializeHull() {
hx = new LinkedList<Double>();
hy = new LinkedList<Double>();
}

private void buildHullPoints() {
double[] ax = new double[hx.size()];
double[] ay = new double[hy.size()];
int n = 0;
for (Iterator<Double> ix = hx.iterator(); ix.hasNext();)
ax[n++] = ix.next();

n = 0;
for (Iterator<Double> iy = hy.iterator(); iy.hasNext();)
ay[n++] = iy.next();

hullPoints = new Points(ax, ay);
}

private void addToHull(int p) {
hx.add(pts.x[p]);
hy.add(pts.y[p]);
}

/**
* The PseudoAngle is a number that increases as the angle from vertical increases.
* The current implementation has the maximum pseudo angle < 4. The pseudo angle for each quadrant is 1.
* The algorithm is very simple. It just finds where the angle intesects a square and measures the
* perimeter of the square at that point. The math is in my Sept '06 notebook. UncleBob.
*/
public static double pseudoAngle(double dx, double dy) {
if (dx >= 0 && dy >= 0)
return quadrantOnePseudoAngle(dx, dy);
if (dx >= 0 && dy < 0)
return 1 + quadrantOnePseudoAngle(Math.abs(dy), dx);
if (dx < 0 && dy < 0)
return 2 + quadrantOnePseudoAngle(Math.abs(dx), Math.abs(dy));
if (dx < 0 && dy >= 0)
return 3 + quadrantOnePseudoAngle(dy, Math.abs(dx));
throw new Error("Impossible");
}

public static double quadrantOnePseudoAngle(double dx, double dy) {
return dx / (dy + dx);
}

public Points getHullPoints() {
return hullPoints;
}

public static class Points {
public double x[];
public double y[];

public Points(double[] x, double[] y) {
this.x = x;
this.y = y;
}

public Points getHullPoints() {
return hullPoints;
// The starting point is the point with the lowest X
// With ties going to the lowest Y. This guarantees
// that the next point over is clockwise.
int startingPoint() {
double minY = y[0];
double minX = x[0];
int iMin = 0;
for (int i = 1; i < x.length; i++) {
if (x[i] < minX) {
minX = x[i];
iMin = i;
} else if (minX == x[i] && y[i] < minY) {
minY = y[i];
iMin = i;
}
}
return iMin;
}

public static class Points {
public double x[];
public double y[];

public Points(double[] x, double[] y) {
this.x = x;
this.y = y;
}

// The starting point is the point with the lowest X
// With ties going to the lowest Y. This guarantees
// that the next point over is clockwise.
int startingPoint() {
double minY = y[0];
double minX = x[0];
int iMin = 0;
for (int i = 1; i < x.length; i++) {
if (x[i] < minX) {
minX = x[i];
iMin = i;
} else if (minX == x[i] && y[i] < minY) {
minY = y[i];
iMin = i;
}
}
return iMin;
}

}
}
}
40 changes: 20 additions & 20 deletions TimeJarvisMarch.java
Original file line number Diff line number Diff line change
@@ -1,27 +1,27 @@
import java.util.Random;

public class TimeJarvisMarch {
public void run(String[] args) {
for (int i=0; i<10; i++)
test();
}

public void test() {
final int POINTS = 1000000;
public void run(String[] args) {
for (int i=0; i<10; i++)
test();
}

double x[] = new double[POINTS];
double y[] = new double[POINTS];
Random r = new Random();
for (int i=0; i<POINTS; i++) {
x[i] = r.nextGaussian();
y[i] = r.nextGaussian();
}
public void test() {
final int POINTS = 1000000;

JarvisMarch.Points pts = new JarvisMarch.Points(x,y);
JarvisMarch jm = new JarvisMarch(pts);
double start = System.currentTimeMillis();
int n = jm.calculateHull();
double end = System.currentTimeMillis();
System.out.printf("%d points found %d vertices %f seconds\n", POINTS, n, (end-start)/1000.);
double x[] = new double[POINTS];
double y[] = new double[POINTS];
Random r = new Random();
for (int i=0; i<POINTS; i++) {
x[i] = r.nextGaussian();
y[i] = r.nextGaussian();
}

JarvisMarch.Points pts = new JarvisMarch.Points(x,y);
JarvisMarch jm = new JarvisMarch(pts);
double start = System.currentTimeMillis();
int n = jm.calculateHull();
double end = System.currentTimeMillis();
System.out.printf("%d points found %d vertices %f seconds\n", POINTS, n, (end-start)/1000.);
}
}
Loading

0 comments on commit 187eb07

Please sign in to comment.