Implemented and tested to check if a point is inside or outside of a boundary using a ray tracing algorithm. The function is public static for a GPSCoordinate and takes a list of GPSCoordinates and the comparing coordinate. #story[873]

main
Joseph Gardner 9 years ago
parent 3b2f99b7d7
commit a13899b6a7

@ -1,5 +1,8 @@
package seng302.Model; package seng302.Model;
import java.util.Comparator;
import java.util.List;
/** /**
* GPS Coordinate for the world map. * GPS Coordinate for the world map.
* Created by esa46 on 15/03/17. * Created by esa46 on 15/03/17.
@ -68,5 +71,90 @@ public class GPSCoordinate {
result = 31 * result + (int) (temp ^ (temp >>> 32)); result = 31 * result + (int) (temp ^ (temp >>> 32));
return result; return result;
} }
/**
* Calculates min and max values and passed it to calculate if coordinate is in the boundary
* @param coordinate coordinate of interest
* @param boundary List of points which make a boundry
* @return true if coordinate is in the boundary
*/
public static boolean isInsideBoundary(GPSCoordinate coordinate, List<GPSCoordinate> boundary) {
double maxLatitude = boundary.stream().max(Comparator.comparingDouble(GPSCoordinate::getLatitude)).get().getLatitude();
double maxLongitude = boundary.stream().max(Comparator.comparingDouble(GPSCoordinate::getLongitude)).get().getLongitude();
double minLatitude = boundary.stream().min(Comparator.comparingDouble(GPSCoordinate::getLatitude)).get().getLatitude();
double minLongitude = boundary.stream().min(Comparator.comparingDouble(GPSCoordinate::getLongitude)).get().getLongitude();
return isInsideBoundary(coordinate, boundary, new GPSCoordinate(minLatitude, minLongitude),
new GPSCoordinate(maxLatitude, maxLongitude));
}
/**
* Calculates if the coordinate is in the boundary
* @param coordinate coordinate of interest
* @param boundary List of points which make a boundary
* @param minValues max GPS
* @param maxValues min GPS
* @return true if coordinate is in the boundary
*/
public static boolean isInsideBoundary(GPSCoordinate coordinate, List<GPSCoordinate> boundary, GPSCoordinate minValues, GPSCoordinate maxValues) {
double minLat = minValues.getLatitude();
double minLon = minValues.getLongitude();
double maxLat = maxValues.getLatitude();
double maxLon = maxValues.getLongitude();
double coordinateLat = coordinate.getLatitude();
double coordinateLon = coordinate.getLongitude();
int length = boundary.size();
boolean inside = false;
// End computation early
if (coordinateLat <= minLat || coordinateLat >= maxLat || coordinateLon <= minLon || coordinateLon >= maxLon) {
return false;
}
// Check if inside using ray casting algorithm
for (int i = 0, j = length - 1; i < length; j = i++) {
if (intersects(boundary.get(i), boundary.get(j), coordinate)) {
inside = !inside;
}
}
return inside;
}
/**
* Helper function to find if a point is in a boundary
* @param boundaryA
* @param boundaryB
* @param coordinate
* @return true if a line from the point intersects the two boundary points
*/
private static boolean intersects(GPSCoordinate boundaryA, GPSCoordinate boundaryB, GPSCoordinate coordinate) {
double boundaryALat = boundaryA.getLatitude();
double boundaryALon = boundaryA.getLongitude();
double boundaryBLat = boundaryB.getLatitude();
double boundaryBLon = boundaryB.getLongitude();
double coordinateLat = coordinate.getLatitude();
double coordinateLon = coordinate.getLongitude();
if (boundaryALat > boundaryBLat) {
return intersects(boundaryB, boundaryA, coordinate);
}
if (coordinateLat == boundaryALat || coordinateLat == boundaryBLat) {
// Move coordinate off intersection line
coordinateLat += 1e-9;
}
if (coordinateLat > boundaryBLat || coordinateLat < boundaryALat || coordinateLon > Double.max(boundaryALon, boundaryBLon)) {
return false;
}
if (coordinateLon < Double.min(boundaryALon, boundaryBLon)) {
return true;
}
double aRatio = (coordinateLat - boundaryALat) / (coordinateLon - boundaryALon);
double bRatio = (coordinateLat - boundaryBLat) / (coordinateLon - boundaryBLon);
return aRatio >= bRatio;
}
} }

@ -0,0 +1,121 @@
package seng302.Model;
import org.junit.Before;
import org.junit.Test;
import java.util.ArrayList;
import java.util.List;
import static junit.framework.TestCase.assertTrue;
import static junit.framework.TestCase.assertFalse;
/**
* Created by jjg64 on 11/05/17.
*/
public class GPSCoordinateTest {
List<GPSCoordinate> boundary;
@Before
public void init() {
boundary = new ArrayList<>();
}
/**
* -------
* | |
* | * |
* -------
*/
@Test
public void insideSquareTest() {
boundary.add(new GPSCoordinate(0, 0));
boundary.add(new GPSCoordinate(10, 0));
boundary.add(new GPSCoordinate(10, 10));
boundary.add(new GPSCoordinate(0, 10));
GPSCoordinate coordinate = new GPSCoordinate(2, 8);
boolean inside = GPSCoordinate.isInsideBoundary(coordinate, boundary);
assertTrue(inside);
}
/**
* -------
* | |
* * | |
* -------
*/
@Test
public void outsideSquareTest() {
boundary.add(new GPSCoordinate(0, 0));
boundary.add(new GPSCoordinate(10, 0));
boundary.add(new GPSCoordinate(10, 10));
boundary.add(new GPSCoordinate(0, 10));
GPSCoordinate coordinate = new GPSCoordinate(-2, 8);
boolean inside = GPSCoordinate.isInsideBoundary(coordinate, boundary);
assertFalse(inside);
}
/**
* -------
* | |
* | |
* *------
*/
@Test
public void edgeSquareTest() {
boundary.add(new GPSCoordinate(0, 0));
boundary.add(new GPSCoordinate(10, 0));
boundary.add(new GPSCoordinate(10, 10));
boundary.add(new GPSCoordinate(0, 10));
GPSCoordinate coordinate = new GPSCoordinate(0, 0);
boolean inside = GPSCoordinate.isInsideBoundary(coordinate, boundary);
assertFalse(inside);
}
@Test
public void insideShapeWithObtuseAnglesTest() {
boundary.add(new GPSCoordinate(0, 0));
boundary.add(new GPSCoordinate(4, 4));
boundary.add(new GPSCoordinate(7, 2));
boundary.add(new GPSCoordinate(9, 5));
boundary.add(new GPSCoordinate(10, 10));
boundary.add(new GPSCoordinate(6, 6));
boundary.add(new GPSCoordinate(2, 10));
GPSCoordinate coordinate = new GPSCoordinate(5, 5);
boolean inside = GPSCoordinate.isInsideBoundary(coordinate, boundary);
assertTrue(inside);
}
@Test
public void outsideShapeWithObtuseAnglesTest() {
boundary.add(new GPSCoordinate(0, 0));
boundary.add(new GPSCoordinate(4, 4));
boundary.add(new GPSCoordinate(7, 2));
boundary.add(new GPSCoordinate(9, 5));
boundary.add(new GPSCoordinate(10, 10));
boundary.add(new GPSCoordinate(6, 6));
boundary.add(new GPSCoordinate(2, 10));
GPSCoordinate coordinate = new GPSCoordinate(4, 3);
boolean inside = GPSCoordinate.isInsideBoundary(coordinate, boundary);
assertFalse(inside);
}
@Test
public void edgeOfShapeWithObtuseAnglesTest() {
boundary.add(new GPSCoordinate(0, 0));
boundary.add(new GPSCoordinate(4, 4));
boundary.add(new GPSCoordinate(7, 2));
boundary.add(new GPSCoordinate(9, 5));
boundary.add(new GPSCoordinate(10, 10));
boundary.add(new GPSCoordinate(6, 6));
boundary.add(new GPSCoordinate(2, 10));
GPSCoordinate coordinate = new GPSCoordinate(2, 10);
boolean inside = GPSCoordinate.isInsideBoundary(coordinate, boundary);
assertFalse(inside);
}
}
Loading…
Cancel
Save