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;
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user