import java.util.*;
/*
Shape data for ShapeClient:
"0 0 0 1 1 1 1 0"
"10 10 10 11 11 11 11 10"
"0.5 0.5 0.5 -10 1.5 0"
"0.5 0.5 0.75 0.75 0.75 0.2"
*/
public class Shape {
// This is declared as static in the even that the client wishes to use
// the enum for something.
public static enum Relation {
NO_INTERSECTION, IS_CONTAINED_IN, ENCIRCLES
}
private Point center;
private double radius;
private LinkedList<Point> points;
/**
* Constructs a shape with a given descriptor. The descriptor is a string
* representing an even number of double values separated by spaces.
*
* @param descriptor
*/
public Shape(String descriptor) {
extractPoints(descriptor);
computeCenter();
computeRadius();
}
/**
* Compares self with another shape object to determine if self and the other
* shape "cross." Assumes a valid shape object.
*
* @param s
* @return
*/
public boolean crossesShape(Shape s) {
LinkedList<Point> refToS = s.getPoints();
double last = center.distance(refToS.getFirst());
double current = radius * 2;
for (int i = 1; i < refToS.size(); i++) {
current = center.distance(refToS.get(i));
if(last <= radius && current > radius ||
last > radius && current <= radius) {
return true;
}
last = current;
}
current = center.distance(refToS.getFirst());
return (last <= radius && current > radius || last > radius && current <= radius);
}
/**
* @param s
* @return the ordinal of the enum Relation which corresponds to the relation
* of self and the passed circle.
*/
public int encircles(Shape s) {
double centerDistance = center.distance(s.getCenter());
if (centerDistance <= radius) return Relation.ENCIRCLES.ordinal();
if (centerDistance <= radius + s.getRadius()) return Relation.IS_CONTAINED_IN.ordinal();
return Relation.NO_INTERSECTION.ordinal();
}
/**
* @return a reference to the internal points list.
*/
public LinkedList<Point> getPoints() {
return points;
}
/**
* @return a copy of the shape's center
*/
public Point getCenter() {
return new Point(center);
}
/**
* @return the radius
*/
public double getRadius() {
return radius;
}
// ----------- Private Methods ------------- //
/**
* Extracts the points from the string. Assumes a valid string.
*/
private void extractPoints(String scannerInput) {
points = new LinkedList<Point>();
Scanner s = new Scanner(scannerInput);
/*if (s.match().groupCount() % 2 != 0) {
System.err.println("Invalid input parameter to extractPoints: " + scannerInput);
return;
}*/
while(s.hasNextDouble())
points.add(new Point(s.nextDouble(), s.nextDouble()));
}
/**
* Computes the center of the shape as dictated by the arithmetic mean.
*/
private void computeCenter() {
double xTotal = 0, yTotal = 0;
for (Point p : points) {
xTotal += p.getX();
yTotal += p.getY();
}
center = new Point(xTotal/points.size(), yTotal/points.size());
}
/**
* Computes the radius of the circle defined by the shape. Since the point
* closest to the center lies on the edge of the circle, the distance
* between that point and the center must be the radius of the circle.
*
* I felt computing the radius would be too taxing an operation to perform
* every time, so the value is stored in an instance variable.
*/
private void computeRadius() {
// initialize the radius to a value far larger or equal to
// the actual minimum distance.
radius = center.distance(points.getFirst()) * points.size();
for (Point p : points)
if (center.distance(p) < radius)
radius = center.distance(p);
}
}