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]
This commit is contained in:
@@ -1,5 +1,8 @@
|
||||
package seng302.Model;
|
||||
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* GPS Coordinate for the world map.
|
||||
* Created by esa46 on 15/03/17.
|
||||
@@ -68,5 +71,90 @@ public class GPSCoordinate {
|
||||
result = 31 * result + (int) (temp ^ (temp >>> 32));
|
||||
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);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user