Point.java (6135B) download
1package osm.geo;
2
3import java.util.Collection;
4
5import osm.common.ArrayIterable;
6
7/**
8 * Represents a geographical point with latitude and longitude coordinates.
9 */
10public 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}