import java.lang.Comparable;
import java.util.SortedSet;
import java.util.TreeSet;
interface XY
{
public Double x();
public Double y();
public XY plus(XY other);
public Polar toPolar();
}
interface Polar extends Comparable<Polar>
{
public Double radius();
public Double angle();
public XY toXY();
}
interface PointInAPlane extends XY, Polar
{
public void setLabel(String label);
public String getLabel();
public String toXYString();
public String toPolarString();
}
public class RandomPointsOnACircle
{
/**
* Prints the Cartesian and polar coordinates of a sorted list of points that are
* created based on the program's command-line arguments. The first argument is the
* number of points to create. The second argument is the radius of a circle that
* each point will be on. The third argument is the x-offset of the circle. The
* fourth argument is the y-offset of the circle. All arguments are optional.
* Default values are used if the radius and offset values are not specified.
*/
public static void main(String[] args)
{
int n = args.length > 0 ? Integer.parseInt(args[0]) : 0;
double r = args.length > 1 ? Double.parseDouble(args[1]) : 1.0;
double x = args.length > 2 ? Double.parseDouble(args[2]) : 0;
double y = args.length > 3 ? Double.parseDouble(args[3]) : 0;
SortedSet<PointInAPlane> orderedRandomPoints = new TreeSet<PointInAPlane>();
while (n-- > 0)
{
// 1. Create an object to hold the polar coordinates of a
// random point on the circumference of a circle with radius r.
// 2. Add the x-coordinate and y-coordinate values passed to the
// program via the command-line arguments and the x-coordinate
// and y-coordinate values that correspond to the polar coordinates
// of the object created in the previous step. Store the resulting
// coordinates in an object of type XY.
// 3. Use the XY object from the previous step to create an object
// of type Point2D, and add that object to orderedRandomPoints.
Polar polarCoords = new PolarCoords(r, 2 * Math.PI * Math.random());
XY xyCoords = new CartesianCoords(x, y).plus(polarCoords.toXY());
orderedRandomPoints.add(new Point2D(xyCoords));
}
int pointNumber = 0;
for (PointInAPlane point : orderedRandomPoints)
point.setLabel("p" + ++pointNumber);
System.out.println("Polar Coordinates\n");
for (PointInAPlane point : orderedRandomPoints)
System.out.println(point.toPolarString());
System.out.println("\nCartesian Coordinates\n");
for (PointInAPlane point : orderedRandomPoints)
System.out.println(point.toXYString());
}
}
/**
* Used to determine whether the difference between two
* floating point numbers is significant. (Sometimes we
* want to ignore small differences that are the result
* of rounding or truncation.)
*/
class Difference
{
public static boolean isSignificant(double d1, double d2)
{
// Sometimes (d1 - d2 == 0.0) is true even though (d1 == d2) is false.
return Difference.isSignificant(d1, d2, 0.0);
}
public static boolean isSignificant(double d1, double d2, double epsilon)
{
// If the absolute value of d1 - d2 is greater than epsilon
// then return true; otherwise, return false.
return Math.abs(d2 - d2) > epsilon;
}
}
/**
* A generic ordered pair of objects.
*/
class OrderedPair<T>
{
private final T first, second;
public OrderedPair(T first, T second)
{
// Set the value of the object's immutable instance variables.
this.first = first;
this.second = second;
}
public T first() { return this.first; }
public T second() { return this.second; }
}
/**
* An ordered pair of numbers used to identify a point in 2-dimensional space.
*/
abstract class Coords2D
{
private final OrderedPair<Double> values;
public Coords2D(Double d1, Double d2)
{
// Set the value of the object's immutable instance variable.
this.values = new OrderedPair(d1, d2);
}
protected Double firstValue() { return values.first(); }
protected Double secondValue() { return values.second(); }
public String toString()
{
// Return a string of the form (x, y) where x and y are the
// first and second coordinate values respectively.
return "(" + firstValue() + ", " + secondValue() + ")";
}
}
/**
* An ordered pair of Cartesian coordinates: x and y values.
*/
class CartesianCoords extends Coords2D implements XY
{
public CartesianCoords(Double x, Double y)
{
// Pass the values of x and y to the superclass's (the Coords class's)
// constructor method.
super(x, y);
}
public Double x() { return super.firstValue(); }
public Double y() { return super.secondValue(); }
public XY plus(XY other)
{
return new CartesianCoords(this.x() + other.x(), this.y() + other.y());
}
public Polar toPolar()
{
// 1. Compute the distance between the origin (0, 0) and the point (x, y).
// This is the radius of the corresponding polar coordinates.
// 2. Compute the multi-valued inverse tangent of y and x. This is the
// angle of the corresponding polar coordinates.
// 3. Use the computed values to create an object of type Polar.
// Return the object.
Double x = this.x(), y = this.y();
Double radius = Math.sqrt(x*x + y*y);
Double angle = Math.atan2(y, x);
return new PolarCoords(radius, angle);
}
}
/**
* An ordered pair of polar coordinates: radius and angle values.
*/
class PolarCoords extends Coords2D implements Polar
{
public PolarCoords(Double radius, Double angle)
{
// Call the superclass's constructor. Pass the radius value and a possibly
// modified angle value. Note that the angle conversion must be done inline.
// It can't be performed using statements that precede the call to the
// superclass's constructor, because the superclass constructor call must be
// executed first, before any other statements in this constructor method
// are executed.
//
// Using the mod (%) operator, convert the angle to a value that is greater
// than or equal to -2 * Math.PI and is less than or equal to 2 * Math.PI;
// If the (possibly) converted angle is less than zero, then add 2 * Math.PI
// and pass that value to the superclass's constructor; otherwise, pass the
// converted value.
super(radius, angle < 0 ?
(angle % (2 * Math.PI)) + (2 * Math.PI) : (angle % (2 * Math.PI)) );
}
public Double radius() { return super.firstValue(); }
public Double angle() { return super.secondValue(); }
public XY toXY()
{
// Multiply the value of the radius by Math.cos(this.angle) and by
// Math.sin(this.angle) to get the x and y coordinate values respectively.
// Create and return an object of type XY using the computed x and y values.
Double x = this.radius() * Math.cos(this.angle());
Double y = this.radius() * Math.sin(this.angle());
return new CartesianCoords(x, y);
}
public int compareTo(Polar other)
{
final Double r1 = this.radius(), r2 = other.radius();
final int radiusCompare = r1.compareTo(r2);
return (radiusCompare != 0 && Difference.isSignificant(r1, r2)) ?
radiusCompare : this.angle().compareTo(other.angle());
}
}
/**
* A point in two-dimensional space.
*/
class Point2D implements PointInAPlane
{
private final XY xyCoords;
private final Polar polarCoords;
private String label = null;
public Point2D(Point2D p)
{
this.xyCoords = p.xyCoords;
this.polarCoords = p.polarCoords;
}
public Point2D(XY xyCoords)
{
this.xyCoords = xyCoords;
this.polarCoords = xyCoords.toPolar();
}
public Point2D(Polar coords)
{
this.polarCoords = coords;
this.xyCoords = coords.toXY();
}
public Double x() { return xyCoords.x(); }
public Double y() { return xyCoords.y(); }
public Double radius() { return polarCoords.radius(); }
public Double angle() { return polarCoords.angle(); }
public XY plus(XY other) { return xyCoords.plus(other); }
public XY toXY() { return xyCoords; }
public Polar toPolar() { return polarCoords; }
public int compareTo(Polar other) { return this.polarCoords.compareTo(other); }
public void setLabel(String label) { this.label = label; }
public String getLabel() { return label; }
public String toXYString() { return label + ": " + xyCoords.toString(); }
public String toPolarString() { return label + ": " + polarCoords.toString(); }
}