mirror of
https://github.com/michaelrausch/Party-Parrots-At-Sea.git
synced 2026-05-09 06:18:44 +00:00
Added a method to test if a geo point is located in a triangle which is formed by other three geo points.
The method helps to check the mark rounding. Also unit tests have been done for this method. tags: #story[1124]
This commit is contained in:
@@ -34,14 +34,12 @@ public class GeoUtility {
|
|||||||
*
|
*
|
||||||
* @param p1 the first geographical position, start point
|
* @param p1 the first geographical position, start point
|
||||||
* @param p2 the second geographical position, end point
|
* @param p2 the second geographical position, end point
|
||||||
* @return the initial bearing in degree from p1 to p2, value range (0 ~ 360 deg.).
|
* @return the initial bearing in degree from p1 to p2, value range (0 ~ 360 deg.). vertical up
|
||||||
* vertical up is 0 deg. horizontal right is 90 deg.
|
* is 0 deg. horizontal right is 90 deg.
|
||||||
*
|
*
|
||||||
* NOTE:
|
* NOTE: The final bearing will differ from the initial bearing by varying degrees according to
|
||||||
* The final bearing will differ from the initial bearing by varying degrees
|
* distance and latitude (if you were to go from say 35°N,45°E (≈ Baghdad) to 35°N,135°E (≈
|
||||||
* according to distance and latitude (if you were to go from say 35°N,45°E
|
* Osaka), you would start on a heading of 60° and end up on a heading of 120°
|
||||||
* (≈ Baghdad) to 35°N,135°E (≈ Osaka), you would start on a heading of 60°
|
|
||||||
* and end up on a heading of 120°
|
|
||||||
*/
|
*/
|
||||||
public static Double getBearing(GeoPoint p1, GeoPoint p2) {
|
public static Double getBearing(GeoPoint p1, GeoPoint p2) {
|
||||||
return (Math.toDegrees(getBearingRad(p1, p2)) + 360.0) % 360.0;
|
return (Math.toDegrees(getBearingRad(p1, p2)) + 360.0) % 360.0;
|
||||||
@@ -52,28 +50,27 @@ public class GeoUtility {
|
|||||||
*
|
*
|
||||||
* @param p1 the first geographical position, start point
|
* @param p1 the first geographical position, start point
|
||||||
* @param p2 the second geographical position, end point
|
* @param p2 the second geographical position, end point
|
||||||
* @return the initial bearing in degree from p1 to p2, value range (0 ~ 360 deg.).
|
* @return the initial bearing in degree from p1 to p2, value range (0 ~ 360 deg.). vertical up
|
||||||
* vertical up is 0 deg. horizontal right is 90 deg.
|
* is 0 deg. horizontal right is 90 deg.
|
||||||
*
|
*
|
||||||
* NOTE:
|
* NOTE: The final bearing will differ from the initial bearing by varying degrees according to
|
||||||
* The final bearing will differ from the initial bearing by varying degrees
|
* distance and latitude (if you were to go from say 35°N,45°E (≈ Baghdad) to 35°N,135°E (≈
|
||||||
* according to distance and latitude (if you were to go from say 35°N,45°E
|
* Osaka), you would start on a heading of 60° and end up on a heading of 120°
|
||||||
* (≈ Baghdad) to 35°N,135°E (≈ Osaka), you would start on a heading of 60°
|
|
||||||
* and end up on a heading of 120°
|
|
||||||
*/
|
*/
|
||||||
public static Double getBearingRad(GeoPoint p1, GeoPoint p2) {
|
public static Double getBearingRad(GeoPoint p1, GeoPoint p2) {
|
||||||
double dLon = Math.toRadians(p2.getLng() - p1.getLng());
|
double dLon = Math.toRadians(p2.getLng() - p1.getLng());
|
||||||
|
|
||||||
double y = Math.sin(dLon) * Math.cos(Math.toRadians(p2.getLat()));
|
double y = Math.sin(dLon) * Math.cos(Math.toRadians(p2.getLat()));
|
||||||
double x = Math.cos(Math.toRadians(p1.getLat())) * Math.sin(Math.toRadians(p2.getLat()))
|
double x = Math.cos(Math.toRadians(p1.getLat())) * Math.sin(Math.toRadians(p2.getLat()))
|
||||||
- Math.sin(Math.toRadians(p1.getLat())) * Math.cos(Math.toRadians(p2.getLat())) * Math.cos(dLon);
|
- Math.sin(Math.toRadians(p1.getLat())) * Math.cos(Math.toRadians(p2.getLat())) * Math
|
||||||
|
.cos(dLon);
|
||||||
|
|
||||||
return Math.atan2(y, x);
|
return Math.atan2(y, x);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Given an existing point in lat/lng, distance in (in meter) and bearing
|
* Given an existing point in lat/lng, distance in (in meter) and bearing (in degrees),
|
||||||
* (in degrees), calculates the new lat/lng.
|
* calculates the new lat/lng.
|
||||||
*
|
*
|
||||||
* @param origin the original position within lat / lng
|
* @param origin the original position within lat / lng
|
||||||
* @param bearing the bearing in degree, from original position to the new position
|
* @param bearing the bearing in degree, from original position to the new position
|
||||||
@@ -98,11 +95,11 @@ public class GeoUtility {
|
|||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Performs the line function on two points of a line and a test point to test which side of the line that point is
|
* Performs the line function on two points of a line and a test point to test which side of the
|
||||||
* on. If the return value is
|
* line that point is on. If the return value is return 1, then the point is on one side of the
|
||||||
* return 1, then the point is on one side of the line,
|
* line, return -1 then the point is on the other side of the line return 0 then the point is
|
||||||
* return -1 then the point is on the other side of the line
|
* exactly on the line.
|
||||||
* return 0 then the point is exactly on the line.
|
*
|
||||||
* @param linePoint1 One point of the line
|
* @param linePoint1 One point of the line
|
||||||
* @param linePoint2 Second point of the line
|
* @param linePoint2 Second point of the line
|
||||||
* @param testPoint The point to test with this line
|
* @param testPoint The point to test with this line
|
||||||
@@ -121,25 +118,26 @@ public class GeoUtility {
|
|||||||
|
|
||||||
if (result > 0) {
|
if (result > 0) {
|
||||||
return 1;
|
return 1;
|
||||||
}
|
} else if (result < 0) {
|
||||||
else if (result < 0) {
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Given a point and a vector (angle and vector length) Will create a new point, that vector away from the origin
|
* Given a point and a vector (angle and vector length) Will create a new point, that vector
|
||||||
* point
|
* away from the origin point
|
||||||
|
*
|
||||||
* @param originPoint The point with which to use as the base for our vector addition
|
* @param originPoint The point with which to use as the base for our vector addition
|
||||||
* @param angleInDeg (DEGREES) The angle at which our new point is being created (in degrees!)
|
* @param angleInDeg (DEGREES) The angle at which our new point is being created (in degrees!)
|
||||||
* @param vectorLength The length out on this angle from the origin point to create the new point
|
* @param vectorLength The length out on this angle from the origin point to create the new
|
||||||
|
* point
|
||||||
* @return a Point2D
|
* @return a Point2D
|
||||||
*/
|
*/
|
||||||
public static Point2D makeArbitraryVectorPoint(Point2D originPoint, Double angleInDeg, Double vectorLength) {
|
public static Point2D makeArbitraryVectorPoint(Point2D originPoint, Double angleInDeg,
|
||||||
|
Double vectorLength) {
|
||||||
|
|
||||||
Double endPointX = originPoint.getX() + vectorLength * Math.cos(Math.toRadians(angleInDeg));
|
Double endPointX = originPoint.getX() + vectorLength * Math.cos(Math.toRadians(angleInDeg));
|
||||||
Double endPointY = originPoint.getY() + vectorLength * Math.sin(Math.toRadians(angleInDeg));
|
Double endPointY = originPoint.getY() + vectorLength * Math.sin(Math.toRadians(angleInDeg));
|
||||||
@@ -147,4 +145,42 @@ public class GeoUtility {
|
|||||||
return new Point2D(endPointX, endPointY);
|
return new Point2D(endPointX, endPointY);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Define vector v1 = p1 - p0 to v2 = p2- p0. This function returns the difference of bearing
|
||||||
|
* from v1 to v2. For example, if bearing of v1 is 30 deg and bearing of v2 is 90 deg, then the
|
||||||
|
* difference is 60 deg.
|
||||||
|
*
|
||||||
|
* @param bearing1 the bearing of v1
|
||||||
|
* @param bearing2 the bearing of v2
|
||||||
|
* @return the difference of bearing from v1 to v2
|
||||||
|
*/
|
||||||
|
private static double getBearingDiff(double bearing1, double bearing2) {
|
||||||
|
return ((360 - bearing1) + bearing2) % 360;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Given three geo points to form a triangle, the method returns true if the fourth point is
|
||||||
|
* inside the triangle
|
||||||
|
*
|
||||||
|
* @param v1 the vertex of the triangle
|
||||||
|
* @param v2 the vertex of the triangle
|
||||||
|
* @param v3 the vertex of the triangle
|
||||||
|
* @param point the point to be tested
|
||||||
|
* @return true if the fourth point is inside the triangle
|
||||||
|
*/
|
||||||
|
public static boolean isPointInTriangle(GeoPoint v1, GeoPoint v2, GeoPoint v3, GeoPoint point) {
|
||||||
|
// true, if diff of bearing from (v1->v2) to (v1->p) is less than 180 deg
|
||||||
|
boolean sideFlag = getBearingDiff(getBearing(v1, v2), getBearing(v1, point)) < 180;
|
||||||
|
|
||||||
|
if ((getBearingDiff(getBearing(v2, v3), getBearing(v2, point)) < 180) != sideFlag) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((getBearingDiff(getBearing(v3, v1), getBearing(v3, point)) < 180) != sideFlag) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,9 @@
|
|||||||
package seng302.utilities;
|
package seng302.utilities;
|
||||||
|
|
||||||
import static org.junit.Assert.assertEquals;
|
import static org.junit.Assert.assertEquals;
|
||||||
|
import static org.junit.Assert.assertFalse;
|
||||||
import static org.junit.Assert.assertNotEquals;
|
import static org.junit.Assert.assertNotEquals;
|
||||||
|
import static org.junit.Assert.assertTrue;
|
||||||
|
|
||||||
import javafx.geometry.Point2D;
|
import javafx.geometry.Point2D;
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
@@ -30,6 +32,7 @@ public class GeoUtilityTest {
|
|||||||
private GeoPoint p2 = new GeoPoint(57.671524, 11.844495);
|
private GeoPoint p2 = new GeoPoint(57.671524, 11.844495);
|
||||||
private GeoPoint p3 = new GeoPoint(57.670822, 11.843392);
|
private GeoPoint p3 = new GeoPoint(57.670822, 11.843392);
|
||||||
private GeoPoint p4 = new GeoPoint(25.694829, 98.392049);
|
private GeoPoint p4 = new GeoPoint(25.694829, 98.392049);
|
||||||
|
private GeoPoint p5 = new GeoPoint(57.671829, 11.842049);
|
||||||
|
|
||||||
private double toleranceRate = 0.01;
|
private double toleranceRate = 0.01;
|
||||||
|
|
||||||
@@ -125,4 +128,26 @@ public class GeoUtilityTest {
|
|||||||
assertEquals(expected.getY(), newPoint.getY(), 1E-6);
|
assertEquals(expected.getY(), newPoint.getY(), 1E-6);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testIsPointInTriangle() {
|
||||||
|
GeoPoint v1 = new GeoPoint(57.670333, 11.842833);
|
||||||
|
GeoPoint v2 = new GeoPoint(57.671524, 11.844495);
|
||||||
|
GeoPoint v3 = new GeoPoint(57.671829, 11.842049);
|
||||||
|
GeoPoint p1 = new GeoPoint(57.670822, 11.843192); // inside triangle
|
||||||
|
GeoPoint p2 = new GeoPoint(57.670892, 11.843642); // outside triangle
|
||||||
|
|
||||||
|
// benchmark test. 100,000 calculations for 0.336 seconds
|
||||||
|
// long startTime = System.nanoTime();
|
||||||
|
// for (int i = 0; i < 100000; i++) {
|
||||||
|
// assertTrue(GeoUtility.isPointInTriangle(v1, v2, v3, p1));
|
||||||
|
// }
|
||||||
|
// System.out.println((System.nanoTime() - startTime) / 1000000000.0);
|
||||||
|
|
||||||
|
// test for different orders of vertices, which should not affect the result
|
||||||
|
assertTrue(GeoUtility.isPointInTriangle(v2, v1, v3, p1));
|
||||||
|
assertTrue(GeoUtility.isPointInTriangle(v3, v1, v2, p1));
|
||||||
|
|
||||||
|
assertFalse(GeoUtility.isPointInTriangle(v1, v2, v3, p2));
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user