Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
com.geotab.model.coordinate.Coordinate Maven / Gradle / Ivy
package com.geotab.model.coordinate;
import static com.geotab.util.Util.listOf;
import static java.lang.Math.PI;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import com.geotab.model.serialization.serdes.CoordinateDeserializer;
import java.util.List;
import java.util.Objects;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
/**
* A coordinate on the earth's surface. "x" is longitude and "y" is latitude.
*/
@Getter @Setter
@NoArgsConstructor
@AllArgsConstructor
@JsonDeserialize(using = CoordinateDeserializer.class)
public class Coordinate {
/**
* The longitude.
*/
private double x;
/**
* The latitude.
*/
private double y;
/**
* Calculates the distance between this point and the supplied point.
*
* @param x1 The fist x coordinate (longitude).
* @param y1 The fist y coordinate (latitude).
* @param x2 The second x coordinate (longitude).
* @param y2 The second y coordinate (latitude).
* @return The distance.
*/
public static double distanceBetween(double x1, double y1, double x2, double y2) {
x1 = x1 * PI / 180;
y1 = y1 * PI / 180;
x2 = x2 * PI / 180;
y2 = y2 * PI / 180;
double t1 = Math.sin((y2 - y1) / 2);
double t2 = Math.sin((x2 - x1) / 2);
double a = t1 * t1 + Math.cos(y1) * Math.cos(y2) * t2 * t2;
double c = 2 * Math.asin(Math.min(1f, Math.sqrt(a)));
return 6367000 * c;
}
/**
* The distance from the closest polygon's border to the point.
*
* @param x The origin's x-coordinate.
* @param y The origin's y-coordinate.
* @param polygon The SimpleCoordinate list represents the the polygon.
* @return The distance from the polygon.
*/
public static double distanceFromPoly(double x, double y, List polygon) {
double minDistance = Double.MAX_VALUE;
int minIndex = -1;
int count = polygon.size();
if (count == 0) {
return Double.MAX_VALUE;
}
for (int i = 0; i < count - 1; i++) {
Coordinate point = polygon.get(i);
double distance = distanceBetween(point.x, point.y, x, y);
if (distance < minDistance) {
minIndex = i;
minDistance = distance;
}
}
minDistance = getDistanceToSegment(x, y, polygon, minIndex, minIndex - 1);
double minDistance1 = getDistanceToSegment(x, y, polygon, minIndex, minIndex + 1);
return Math.min(minDistance, minDistance1);
}
/**
* Calculates a geographical bearing between two points.
*
* @param from The origin coordinates.
* @param to The destination coordinates.
* @return The bearing in degrees.
*/
public static int getBearing(Coordinate from, Coordinate to) {
double latFrom = from.y * 0.0174532925199433;
double longFrom = from.x * 0.0174532925199433;
double latTo = to.y * 0.0174532925199433;
double longTo = to.x * 0.0174532925199433;
double y = Math.sin(longTo - longFrom) * Math.cos(latTo);
double x = Math.cos(latFrom) * Math.sin(latTo) - Math.sin(latFrom) * Math.cos(latTo) * Math
.cos(longFrom - longTo);
int num1 = 360 + (int) (Math.atan2(y, x) * 57.2957795130823);
return num1 % 360;
}
/**
* Recalculate the extent of collection of coordinates.
*
* @param features The features.
* @return List of coordinates.
*/
@SuppressWarnings("LocalVariableName")
public static List getCalculatedExtent(List features) {
if (features == null) {
return null;
}
int count = features.size();
if (count == 0) {
return null;
}
Coordinate point = features.get(0);
double x = point.x;
double y = point.y;
double xMin = x;
double yMin = y;
double xMax = x;
double yMax = y;
for (int i = 1; i < count; i++) {
point = features.get(i);
x = point.x;
y = point.y;
if (x <= xMin) {
xMin = x;
} else if (x >= xMax) {
xMax = x;
}
if (y <= yMin) {
yMin = y;
} else if (y >= yMax) {
yMax = y;
}
}
return rectangleFromLtrb(xMin, yMax, xMax, yMin);
}
/**
* Get the centroid of collection of {@link Coordinate}(s).
*
* @param coordinates The coordinates.
* @return The centroid.
*/
@SuppressWarnings("VariableDeclarationUsageDistance")
public static Coordinate getCentroid(List coordinates) {
if (coordinates == null) {
return null;
}
double x = 0f;
double y = 0f;
double area2 = 0f;
Coordinate basePoint = coordinates.get(0);
double xb = basePoint.x;
double yb = basePoint.y;
double minX = xb;
double minY = yb;
double maxX = xb;
double maxY = yb;
for (int i = 1; i < coordinates.size() - 1; i++) {
Coordinate point1 = coordinates.get(i);
Coordinate point2 = coordinates.get(i + 1);
double x1 = point1.x;
double y1 = point1.y;
double x2 = point2.x;
double y2 = point2.y;
if (minX > x1) {
minX = x1;
}
if (maxX < x1) {
maxX = x1;
}
if (minX > x2) {
minX = x2;
}
if (maxX < x2) {
maxX = x2;
}
if (minY > y1) {
minY = y1;
}
if (maxY < y1) {
maxY = y1;
}
if (minY > y2) {
minY = y2;
}
if (maxY < y2) {
maxY = y2;
}
double triangleCenterX3 = x1 + x2 + xb;
double triangleCenterY3 = y1 + y2 + yb;
double triangleArea2 = (x1 - xb) * (y2 - yb) - (x2 - xb) * (y1 - yb);
x += triangleArea2 * triangleCenterX3;
y += triangleArea2 * triangleCenterY3;
area2 += triangleArea2;
}
if (area2 == 0f) {
return new Coordinate((maxX - minX) / 2, (maxY - minY) / 2);
}
return new Coordinate(x / (3 * area2), y / (3 * area2));
}
/**
* Returns whether the polygon intersects with a specific x and y.
*
* @param x The x-coordinate being tested for intersection.
* @param y The y-coordinate being tested for intersection.
* @param polygon The {@link Coordinate} list (the polygon) being tested for intersection.
* @return true if the coordinate intersects with the polygon.
*/
public static boolean intersectsWithPoly(double x, double y, List polygon) {
if (polygon == null) {
return false;
}
int count = polygon.size();
if (count == 0) {
return false;
}
Coordinate first;
Coordinate p1 = first = polygon.get(0);
Coordinate p2 = polygon.get(1);
int i = 0;
boolean intersects = false;
while (true) {
double p1Y = p1.y;
double p2Y = p2.y;
if (p2Y > y != p1Y > y) {
double p2X = p2.x;
if (x < (p1.x - p2X) * (y - p2Y) / (p1Y - p2Y) + p2X) {
intersects = !intersects;
}
}
if (++i < count) {
p1 = p2;
p2 = polygon.get(i);
continue;
}
if (!(p2 == first || p2.equals(first))) {
throw new IllegalArgumentException("Object must be a polygon");
}
return intersects;
}
}
/**
* Get whether this polygon is a properly formed polygon having the end point equal to the first point.
*
* @param feature The feature
* @return Whether is a polygon or not.
*/
public static boolean isPolygon(List feature) {
int count = feature.size();
if (count == 0) return false;
return Objects.equals(feature.get(count - 1), feature.get(0));
}
/**
* Gets collection of {@link Coordinate}(s) representing rectangular shape.
*
* @param left The left.
* @param top The top.
* @param right The right.
* @param bottom The bottom.
* @return List of {@link Coordinate}(s).
*/
public static List rectangleFromLtrb(double left, double top, double right,
double bottom) {
Coordinate leftTop = new Coordinate(left, top);
return listOf(
leftTop,
new Coordinate(right, top),
new Coordinate(right, bottom),
new Coordinate(left, bottom),
leftTop
);
}
/**
* Returns the distance between this point and the supplied point in meters.
*
* @param coordinate The {@link Coordinate} being checked for distance.
* @return The distance.
*/
public double distanceFrom(Coordinate coordinate) {
return distanceBetween(x, y, coordinate.x, coordinate.y);
}
@Override
public boolean equals(Object obj) {
if (!(obj instanceof Coordinate)) {
return false;
}
double delta = x - ((Coordinate) obj).getX();
if (delta < 0f) {
delta = -delta;
}
if (delta > 1E-07) {
return false;
}
delta = y - ((Coordinate) obj).getY();
if (delta < 0f) {
delta = -delta;
}
return delta <= 1E-07;
}
@Override
public int hashCode() {
return roundToEpsilon(x).hashCode() ^ roundToEpsilon(y).hashCode();
}
@Override
public String toString() {
return "X:" + x + "; Y:" + y;
}
static Coordinate getClosestPointOnSegment(double x, double y, Coordinate start, Coordinate end) {
double x1 = start.x;
double y1 = start.y;
double x2 = end.x;
double y2 = end.y;
double a = x - x1;
double b = y - y1;
double c = x2 - x1;
double d = y2 - y1;
double dot = a * c + b * d;
double lenSq = c * c + d * d;
double param = dot / lenSq;
if (lenSq == 0f || param < 0f) {
return new Coordinate(x1, y1);
}
if (param > 1f) {
return new Coordinate(x2, y2);
}
return new Coordinate(x1 + param * c, y1 + param * d);
}
static double getDistanceToSegment(double x, double y, List polygon, int start,
int end) {
Coordinate point = polygon.get(start);
if (end < 0 || end >= polygon.size()) {
return Double.MAX_VALUE;
}
Coordinate nextPoint = polygon.get(end);
Coordinate closest = getClosestPointOnSegment(x, y, nextPoint, point);
return distanceBetween(x, y, closest.x, closest.y);
}
static Double roundToEpsilon(double value) {
return (int) (value / 1E-07 + 0.5) * 1E-07;
}
}