We will soon (by later today) have completed our study of the object-oriented de
ID: 3817432 • Letter: W
Question
We will soon (by later today) have completed our study of the object-oriented design sections of the course (Encapsulation in chapter 8, Inheritance in chapter 9 and Polymorphism in chapter 10). We will begin to practice OOD by extending one of the Java classes to implement a Waypoint suitable for simple GPS applications.
Note that we can read-in waypoints as X and Y coordinates with a corresponding speed to the next waypoint. You could process the data as it was entered or save the data to parallel arrays and then process it later after the input was complete (which allows for editing the travel plans, and after the chapter on I/O, saving and reusing them).
Let us begin to apply OOP by creating a Class called Waypoint that extends the class Point2D.Double (from the package java.awt.geom) that is already provided with the Java language (you should check the online Java API Documentation for more details). That will provide us with access to x and y coordinates implemented as double-precision values, but we will also add fields for the speed (as a double) from that location to the next, and the street (as a String) that will be travelled from that location to the next.
The speed will be the velocity to the next waypoint and the street will be the name of the street to take to the next waypoint. In the "real world" we would probably create another data structure that associated two waypoints with the speed and street between them, but we are simplifying this for our current assignment. As a result, we will treat routes as if there is only one way to get from any one waypoint to the next, and therefore can store the speed and street with the "from" waypoint, and calculate the distance and time to the "to" waypoint.
The Point2D class that Java provides is a bit strange looking at first because it contains nested classes for the implementation of a Point with either type double or type float members, but you just import thejava.awt.geom.Point2D class and then extend the Point2D.Double nested class (that is, the specific class nested inside Point2D that is designed for double values), so don't worry about the strange syntax with the extra dot (.) for now – it will work. We will learn more about nested classes and inner classes when we study Java Event management during our introduction to GUIs.
Now consider (but don't implement) method toDistance (that takes another Waypoint as a parameter and returns the distance from this Waypoint to the one passed as a parameter, as a type double value; and method toTime that also takes another Waypoint as a parameter and returns the travel time from this Waypoint to the one passed as a parameter, as a type double value, by using the speed of this Waypoint as the velocity to factor in the calculation. Of course these calculations are from the same PythagoreanTheorum we've already developed and coded in the previous lab. We will be adding this feature (in a special way) next time - so just think about how you would do it now.
In summary, make your Waypoint class extend Java's Point2D.Double class. Point2D.Double is provided with the Java JDK so you only provide the Waypoint source file. If you follow our naming, style and development standards with the above specifications there should be no ambiguity in the coding of the solution, which means if it doesn't compile, you didn't follow all that we've learned. The major points therefore begin with an "all or nothing" filter that determines if your solution compiles with my test case and main method. If your solution compiles, then I will differentiate the awarded points based on how well it was implemented (according to our requirements and standards).
Attach the source code for file Waypoint.java. I will compile it with my own application (main method) to test your solution. It must compile with my application for any credit (so watch your use of naming and casing to be sure they are compatible with these specifications).
In another assignment (later), we will create a Travel application that uses this new class and another we will also create. When we do, we will use my version of the code for this assignment, which will be posted. All fields should be private and all methods should be public. Your constructor will take 3 double values and 1 String (for the X and Y coordinates, the speed to the next waypoint, and the name of the street to the next waypoint). All distances will be in miles and all speeds will be in miles per hour (note that the units of measure for distances don't really matter as long as the same units are used consistently).
In summary, be sure Waypoint extends Point2D.Double. Our Waypoint will encapsulate an x and y coordinate (via inheritance) and a speed and street name (just called street). It will also provide for a toString() that formats the Waypoint as a single-line String (no embedded newlines) formatted as:
Where x, y, s and street are the x, y, speed and street fields, respectively, and a 4-parameter Constructor. What other gets and sets do you need? Make sure you have what you need and don't rewrite what you don't (i.e., if it already exists and works in the superclass).
Explanation / Answer
import java.awt.Point;
import java.awt.geom.Point2D;
import java.util.Arrays;
public class Polygon2D {
private int npoints;
private double xpoints[];
private double ypoints[];
private static final int MIN_LENGTH = 4;
/**
* Creates an empty polygon.
*/
public Polygon2D() {
xpoints = new double[MIN_LENGTH];
ypoints = new double[MIN_LENGTH];
}
/**
* Constructs and initializes a <code>Polygon</code> from the specified
* parameters.
* @param xpoints an array of X coordinates
* @param ypoints an array of Y coordinates
* @param npoints the total number of points in the
* <code>Polygon</code>
* @exception NegativeArraySizeException if the value of
* <code>npoints</code> is negative.
* @exception IndexOutOfBoundsException if <code>npoints</code> is
* greater than the length of <code>xpoints</code>
* or the length of <code>ypoints</code>.
* @exception NullPointerException if <code>xpoints</code> or
* <code>ypoints</code> is <code>null</code>.
*/
public Polygon2D(double xpoints[], double ypoints[], int npoints) {
if (npoints > xpoints.length || npoints > ypoints.length) {
throw new IndexOutOfBoundsException("npoints > xpoints.length || "+
"npoints > ypoints.length");
}
if (npoints < 0) {
throw new NegativeArraySizeException("npoints < 0");
}
this.npoints = npoints;
this.xpoints = Arrays.copyOf(xpoints, npoints);
this.ypoints = Arrays.copyOf(ypoints, npoints);
}
/**
* Resets this <code>Polygon</code> object to an empty polygon.
* The coordinate arrays and the data in them are left untouched
* but the number of points is reset to zero to mark the old
* vertex data as invalid and to start accumulating new vertex
* data at the beginning.
* All internally-cached data relating to the old vertices
* are discarded.
* Note that since the coordinate arrays from before the reset
* are reused, creating a new empty <code>Polygon</code> might
* be more memory efficient than resetting the current one if
* the number of vertices in the new polygon data is significantly
* smaller than the number of vertices in the data from before the
* reset.
*/
public void reset() {
npoints = 0;
}
/**
* Appends the specified coordinates to this <code>Polygon</code>.
* <p>
* If an operation that calculates the bounding box of this
* <code>Polygon</code> has already been performed, such as
* <code>getBounds</code> or <code>contains</code>, then this
* method updates the bounding box.
* @param x the specified X coordinate
* @param y the specified Y coordinate
*/
public void addPoint(double x, double y) {
if (npoints >= xpoints.length || npoints >= ypoints.length) {
int newLength = npoints * 2;
// Make sure that newLength will be greater than MIN_LENGTH and
// aligned to the power of 2
if (newLength < MIN_LENGTH) {
newLength = MIN_LENGTH;
} else if ((newLength & (newLength - 1)) != 0) {
newLength = Integer.highestOneBit(newLength);
}
xpoints = Arrays.copyOf(xpoints, newLength);
ypoints = Arrays.copyOf(ypoints, newLength);
}
xpoints[npoints] = x;
ypoints[npoints] = y;
npoints++;
}
/**
* Determines whether the specified {@link Point} is inside this
* <code>Polygon</code>.
* @param p the specified <code>Point</code> to be tested
* @return <code>true</code> if the <code>Polygon</code> contains the
* <code>Point</code>; <code>false</code> otherwise.
* @see #contains(double, double)
*/
public boolean contains(Point p) {
return contains(p.x, p.y);
}
/**
* Determines whether the specified coordinates are inside this
* <code>Polygon</code>.
* <p>
* @param x the specified X coordinate to be tested
* @param y the specified Y coordinate to be tested
* @return {@code true} if this {@code Polygon} contains
* the specified coordinates {@code (x,y)};
* {@code false} otherwise.
* @see #contains(double, double)
*/
public boolean contains(int x, int y) {
return contains((double) x, (double) y);
}
public boolean contains(double x, double y) {
if (npoints <= 2) {
return false;
}
int hits = 0;
double lastx = xpoints[npoints - 1];
double lasty = ypoints[npoints - 1];
double curx, cury;
// Walk the edges of the polygon
for (int i = 0; i < npoints; lastx = curx, lasty = cury, i++) {
curx = xpoints[i];
cury = ypoints[i];
if (cury == lasty) {
continue;
}
double leftx;
if (curx < lastx) {
if (x >= lastx) {
continue;
}
leftx = curx;
} else {
if (x >= curx) {
continue;
}
leftx = lastx;
}
double test1, test2;
if (cury < lasty) {
if (y < cury || y >= lasty) {
continue;
}
if (x < leftx) {
hits++;
continue;
}
test1 = x - curx;
test2 = y - cury;
} else {
if (y < lasty || y >= cury) {
continue;
}
if (x < leftx) {
hits++;
continue;
}
test1 = x - lastx;
test2 = y - lasty;
}
if (test1 < (test2 / (lasty - cury) * (lastx - curx))) {
hits++;
}
}
return ((hits & 1) != 0);
}
public boolean contains(Point2D p) {
return contains(p.getX(), p.getY());
}
}
Related Questions
drjack9650@gmail.com
Navigate
Integrity-first tutoring: explanations and feedback only — we do not complete graded work. Learn more.