/* NOTE: This submitted as a test case because RAC crashes when it encounters a model method in the java.lang.Math spec, which doee not have a real counterpart because java.lang.Math is not RAC-compiled.
* Two-Dimensional Points
* Fall 2013 CSCI181F
* Daniel M. Zimmerman
*/
/**
* A point in the Euclidean plane.
*
* @author Daniel M. Zimmerman
* @version 2013-10-31
*/
public class Point {
public static enum CoordinateSystem {
CARTESIAN, POLAR
}
/**
* The margin of error for double-precision arithmetic.
*/
public static final double ERROR_MARGIN = 1E-10;
/**
* The format string for computing hash codes that will
* work with the error margin.
*/
public static final String ERROR_FORMAT = "%.10f";
/**
* The x-coordinate.
*/
private final double my_x;
/**
* The y-coordinate.
*/
private final double my_y;
/*@ requires the_system == CoordinateSystem.CARTESIAN |
the_system == CoordinateSystem.POLAR; */
/*@ requires the_system == CoordinateSystem.POLAR ==>
0 <= coord_1 & 0 <= coord_2 & coord_2 < 2 * Math.PI; */
//@ requires isFinite(coord_1) & isFinite(coord_2);
/*@ ensures the_system == CoordinateSystem.CARTESIAN ==>
x() == coord_1 & y() == coord_2; */
/*@ ensures the_system == CoordinateSystem.POLAR ==>
approxEquals(rho(), coord_1) & approxEquals(theta(), coord_2); */
/**
* Your Cartesian coordinates are (the_x, the_y)!
* Your polar coordinates are (the_rho, the_theta)!
*
* Constructs a Point with the specified coordinates in
* the specified coordinate system.
*
* @param coord_1 The x-coordinate or rho.
* @param coord_2 The y-coordinate or theta.
* @param the_system The coordinate system.
*/
public Point(final double coord_1, final double coord_2,
final CoordinateSystem the_system) {
switch (the_system) {
case CARTESIAN:
my_x = coord_1;
my_y = coord_2;
break;
case POLAR:
my_x = coord_1 * Math.cos(coord_2);
my_y = coord_1 * Math.sin(coord_2);
break;
default:
throw new IllegalArgumentException
("I don't know coordinate system " + the_system);
}
}
/**
* Compares two numbers for approximate equivalence. They
* must be within ERROR_MARGIN of each other.
*
* @param number_1 The first number.
* @param number_2 The second number.
* @return true if the two specified numbers are approximately
* equivalent, false otherwise.
*/
//@ ensures \result <==> Math.abs(number_1 - number_2) < ERROR_MARGIN;
public static /*@ pure */ boolean approxEquals(final double number_1,
final double number_2) {
return Math.abs(number_1 - number_2) < ERROR_MARGIN;
}
/*@ ensures \result <==> the_number != Double.NEGATIVE_INFINITY &
the_number != Double.POSITIVE_INFINITY &
!Double.isNaN(the_number); */
/**
* Checks a double-precision floating point number for finiteness.
*
* @param the_number The number to check.
* @return true if the_number is finite, false otherwise.
*/
public static /*@ pure */ boolean isFinite(final double the_number) {
return the_number != Double.NEGATIVE_INFINITY &&
the_number != Double.POSITIVE_INFINITY &&
!Double.isNaN(the_number);
}
/**
* Normalizes an angle to be between 0 (inclusive) and 2 * Math.PI
* (exclusive).
*
* @param the_angle The angle.
* @return The normalized angle.
*/
public static /*@ pure */ double normalize(final double the_angle) {
double result = the_angle;
// repeatedly subtract 2 * Math.PI until we're less than 2 * Math.PI
while (result > 2 * Math.PI) {
result = result - 2 * Math.PI;
}
// repeatedly add 2 * Math.PI until we're greater than 0
while (result <= 0) {
result = result + 2 * Math.PI;
}
return result; // should be normalized
}
/**
* @return What is your x-coordinate?
*/
public /*@ pure */ double x() {
return my_x;
}
/**
* @return What is your y-coordinate?
*/
public /*@ pure */ double y() {
return my_y;
}
/**
* @return What is your rho?
*/
public /*@ pure */ double rho() {
return Math.sqrt(my_x * my_x + my_y * my_y);
}
/**
* @return What is your theta?
*/
public /*@ pure */ double theta() {
return Math.atan2(my_y, my_x);
}
/**
* A main method to demonstrate a JML error.
*/
public static void main(final String[] the_args) {
new Point(0.0, 0.0, CoordinateSystem.CARTESIAN).rho();
}
}