Point.java (6135B)
1 package osm.geo; 2 3 import java.util.Collection; 4 5 import osm.common.ArrayIterable; 6 7 /** 8 * Represents a geographical point with latitude and longitude coordinates. 9 */ 10 public interface Point { 11 12 /** Earth radius in kilometers. */ 13 public static final int EARTH_RADIUS = 6371; 14 15 /** Threshold for direct distance in meters squared. */ 16 public static final double DIRECT_DISTANCE_THRESHOLD = 50 * 50; 17 18 /** 19 * Calculates the distance between two points using their latitude and 20 * longitude. 21 * 22 * @param a The first point. 23 * @param b The second point. 24 * @return The distance between the two points in meters. 25 */ 26 public static long distance(Point a, Point b) { 27 return distance(a.getLatitude(), a.getLongitude(), b.getLatitude(), b.getLongitude()); 28 } 29 30 /** 31 * Calculates the distance between a point and specified latitude and longitude. 32 * 33 * @param aLat The latitude of the first point. 34 * @param aLon The longitude of the first point. 35 * @param b The second point. 36 * @return The distance between the two points in meters. 37 */ 38 public static long distance(double aLat, double aLon, Point b) { 39 return distance(aLat, aLon, b.getLatitude(), b.getLongitude()); 40 } 41 42 /** 43 * Calculates the distance between two sets of latitude and longitude 44 * coordinates. 45 * 46 * @param aLat The latitude of the first point. 47 * @param aLon The longitude of the first point. 48 * @param bLat The latitude of the second point. 49 * @param bLon The longitude of the second point. 50 * @return The distance between the two points in meters. 51 */ 52 public static long distance(double aLat, double aLon, double bLat, double bLon) { 53 aLat = Math.toRadians(aLat); 54 bLat = Math.toRadians(bLat); 55 aLon = Math.toRadians(aLon); 56 bLon = Math.toRadians(bLon); 57 58 double a = 0.5 - Math.cos(bLat - aLat) / 2 + Math.cos(aLat) * Math.cos(bLat) * (1 - Math.cos(bLon - aLon)) / 2; 59 60 return Math.round(2.0 * 1000 * EARTH_RADIUS * Math.asin(Math.sqrt(a))); 61 } 62 63 /** 64 * Calculates the center point of a collection of points. 65 * 66 * @param points The collection of points. 67 * @return The center point. 68 */ 69 public static Point center(Collection<? extends Point> points) { 70 double lat = 0; 71 double lon = 0; 72 73 for (Point point : points) { 74 lat += point.getLatitude(); 75 lon += point.getLongitude(); 76 } 77 78 return Point.of(lat / points.size(), lon / points.size()); 79 } 80 81 /** 82 * Calculates the angle formed by three points. 83 * 84 * @param a The first point. 85 * @param b The second point. 86 * @param c The third point. 87 * @return The angle in radians. 88 */ 89 public static double getAngle(Point a, Point b, Point c) { 90 if (a == null) 91 return 0; 92 93 return Math.atan2(c.getLongitude() - a.getLongitude(), c.getLatitude() - a.getLatitude()) - 94 Math.atan2(b.getLongitude() - a.getLongitude(), b.getLatitude() - a.getLatitude()); 95 } 96 97 /** 98 * Calculates the total distance along a path defined by an array of points. 99 * 100 * @param path The array of points defining the path. 101 * @return The total distance along the path in meters. 102 */ 103 public static long distance(Point... path) { 104 return distance(new ArrayIterable<>(path)); 105 } 106 107 /** 108 * Calculates the total distance along a path defined by an iterable collection 109 * of points. 110 * 111 * @param path The iterable collection of points defining the path. 112 * @return The total distance along the path in meters. 113 */ 114 public static long distance(Iterable<? extends Point> path) { 115 long dist = 0; 116 Point prev = null; 117 118 for (Point current : path) { 119 if (prev != null) 120 dist += Point.distance(prev, current); 121 122 prev = current; 123 } 124 125 return dist; 126 } 127 128 /** 129 * Creates a new Point instance with the specified latitude and longitude. 130 * 131 * @param latitude The latitude of the point. 132 * @param longitude The longitude of the point. 133 * @return A new Point instance. 134 */ 135 public static Point of(double latitude, double longitude) { 136 return new Point() { 137 @Override 138 public double getLatitude() { 139 return latitude; 140 } 141 142 @Override 143 public double getLongitude() { 144 return longitude; 145 } 146 147 @Override 148 public boolean equals(Object other) { 149 if (!(other instanceof Point)) 150 return false; 151 152 return latitude == ((Point) other).getLatitude() 153 && longitude == ((Point) other).getLongitude(); 154 } 155 156 @Override 157 public int hashCode() { 158 return Double.hashCode(latitude) + Double.hashCode(longitude); 159 } 160 161 @Override 162 public String toString() { 163 return String.format("Point[%f, %f]", getLatitude(), getLongitude()); 164 } 165 }; 166 } 167 168 /** 169 * Calculates the distance from this point to another point. 170 * 171 * @param other The other point. 172 * @return The distance to the other point in meters. 173 */ 174 default long distanceTo(Point other) { 175 return distance(this, other); 176 } 177 178 /** 179 * Calculates the distance from this point to a specified latitude and 180 * longitude. 181 * 182 * @param latitude The latitude of the target point. 183 * @param longitude The longitude of the target point. 184 * @return The distance to the target point in meters. 185 */ 186 default long distanceTo(double latitude, double longitude) { 187 return distance(latitude, longitude, this); 188 } 189 190 /** 191 * Gets the latitude of the point. 192 * 193 * @return The latitude. 194 */ 195 double getLatitude(); 196 197 /** 198 * Gets the longitude of the point. 199 * 200 * @return The longitude. 201 */ 202 double getLongitude(); 203 }