source: josm/trunk/src/org/openstreetmap/josm/data/coor/LatLon.java@ 2694

Last change on this file since 2694 was 2694, checked in by Gubaer, 14 years ago

fixed one off in getRoundedToOsmPrecision()

  • Property svn:eol-style set to native
File size: 7.5 KB
Line 
1// License: GPL. Copyright 2007 by Immanuel Scholz and others
2package org.openstreetmap.josm.data.coor;
3
4import static java.lang.Math.PI;
5import static java.lang.Math.asin;
6import static java.lang.Math.cos;
7import static java.lang.Math.sin;
8import static java.lang.Math.sqrt;
9import static java.lang.Math.toRadians;
10import static org.openstreetmap.josm.tools.I18n.tr;
11
12import java.text.DecimalFormat;
13import java.text.NumberFormat;
14
15import org.openstreetmap.josm.Main;
16import org.openstreetmap.josm.data.Bounds;
17import org.openstreetmap.josm.data.projection.Projection;
18
19/**
20 * LatLon are unprojected latitude / longitude coordinates.
21 *
22 * This class is immutable.
23 *
24 * @author Imi
25 */
26public class LatLon extends Coordinate {
27
28 private static DecimalFormat cDmsMinuteFormatter = new DecimalFormat("00");
29 private static DecimalFormat cDmsSecondFormatter = new DecimalFormat("00.0");
30 private static DecimalFormat cDdFormatter = new DecimalFormat("###0.0000");
31
32 /**
33 * Replies true if lat is in the range [-90,90]
34 *
35 * @param lat the latitude
36 * @return true if lat is in the range [-90,90]
37 */
38 public static boolean isValidLat(double lat) {
39 return lat >= -90d && lat <= 90d;
40 }
41
42 /**
43 * Replies true if lon is in the range [-180,180]
44 *
45 * @param lon the longitude
46 * @return true if lon is in the range [-180,180]
47 */
48 public static boolean isValidLon(double lon) {
49 return lon >= -180d && lon <= 180d;
50 }
51
52 public static String dms(double pCoordinate) {
53
54 double tAbsCoord = Math.abs(pCoordinate);
55 int tDegree = (int) tAbsCoord;
56 double tTmpMinutes = (tAbsCoord - tDegree) * 60;
57 int tMinutes = (int) tTmpMinutes;
58 double tSeconds = (tTmpMinutes - tMinutes) * 60;
59
60 return tDegree + "\u00B0" + cDmsMinuteFormatter.format(tMinutes) + "\'"
61 + cDmsSecondFormatter.format(tSeconds) + "\"";
62 }
63
64 public LatLon(double lat, double lon) {
65 super(lon, lat);
66 }
67
68 public LatLon(LatLon coor) {
69 super(coor.lon(), coor.lat());
70 }
71
72 public double lat() {
73 return y;
74 }
75
76 public String latToString(CoordinateFormat d) {
77 switch(d) {
78 case DECIMAL_DEGREES: return cDdFormatter.format(y);
79 case DEGREES_MINUTES_SECONDS: return dms(y) + ((y < 0) ?
80 /* short symbol for South */ tr("S") :
81 /* short symbol for North */ tr("N"));
82 default: return "ERR";
83 }
84 }
85
86 public double lon() {
87 return x;
88 }
89
90 public String lonToString(CoordinateFormat d) {
91 switch(d) {
92 case DECIMAL_DEGREES: return cDdFormatter.format(x);
93 case DEGREES_MINUTES_SECONDS: return dms(x) + ((x < 0) ?
94 /* short symbol for West */ tr("W") :
95 /* short symbol for East */ tr("E"));
96 default: return "ERR";
97 }
98 }
99
100 /**
101 * @return <code>true</code> if the other point has almost the same lat/lon
102 * values, only differing by no more than
103 * 1 / {@link org.openstreetmap.josm.data.projection.Projection#MAX_SERVER_PRECISION MAX_SERVER_PRECISION}.
104 */
105 public boolean equalsEpsilon(LatLon other) {
106 final double p = Projection.MAX_SERVER_PRECISION;
107 return Math.abs(lat()-other.lat()) <= p && Math.abs(lon()-other.lon()) <= p;
108 }
109
110 /**
111 * @return <code>true</code>, if the coordinate is outside the world, compared
112 * by using lat/lon.
113 */
114 public boolean isOutSideWorld() {
115 Bounds b = Main.proj.getWorldBoundsLatLon();
116 return lat() < b.getMin().lat() || lat() > b.getMax().lat() ||
117 lon() < b.getMin().lon() || lon() > b.getMax().lon();
118 }
119
120 /**
121 * @return <code>true</code> if this is within the given bounding box.
122 */
123 public boolean isWithin(Bounds b) {
124 return lat() >= b.getMin().lat() && lat() <= b.getMax().lat() && lon() > b.getMin().lon() && lon() < b.getMax().lon();
125 }
126
127 /**
128 * Computes the distance between this lat/lon and another point on the earth.
129 * Uses Haversine formular.
130 * @param other the other point.
131 * @return distance in metres.
132 */
133 public double greatCircleDistance(LatLon other) {
134 double R = 6378135;
135 double sinHalfLat = sin(toRadians(other.lat() - this.lat()) / 2);
136 double sinHalfLon = sin(toRadians(other.lon() - this.lon()) / 2);
137 double d = 2 * R * asin(
138 sqrt(sinHalfLat*sinHalfLat +
139 cos(toRadians(this.lat()))*cos(toRadians(other.lat()))*sinHalfLon*sinHalfLon));
140 // For points opposite to each other on the sphere,
141 // rounding errors could make the argument of asin greater than 1
142 // (This should almost never happen.)
143 if (java.lang.Double.isNaN(d)) {
144 System.err.println("Error: NaN in greatCircleDistance");
145 d = PI * R;
146 }
147 return d;
148 }
149
150 /**
151 * Returns the heading, in radians, that you have to use to get from
152 * this lat/lon to another.
153 *
154 * @param other the "destination" position
155 * @return heading
156 */
157 public double heading(LatLon other) {
158 double rv;
159 if (other.lat() == lat()) {
160 rv = (other.lon()>lon() ? Math.PI / 2 : Math.PI * 3 / 2);
161 } else {
162 rv = Math.atan((other.lon()-lon())/(other.lat()-lat()));
163 if (rv < 0) {
164 rv += Math.PI;
165 }
166 if (other.lon() < lon()) {
167 rv += Math.PI;
168 }
169 }
170 return rv;
171 }
172
173 /**
174 * Returns this lat/lon pair in human-readable format.
175 *
176 * @return String in the format "lat=1.23456°, lon=2.34567°"
177 */
178 public String toDisplayString() {
179 NumberFormat nf = NumberFormat.getInstance();
180 nf.setMaximumFractionDigits(5);
181 return "lat=" + nf.format(lat()) + "\u00B0, lon=" + nf.format(lon()) + "\u00B0";
182 }
183
184 public LatLon interpolate(LatLon ll2, double proportion) {
185 return new LatLon(this.lat() + proportion * (ll2.lat() - this.lat()),
186 this.lon() + proportion * (ll2.lon() - this.lon()));
187 }
188
189 public LatLon getCenter(LatLon ll2) {
190 return new LatLon((this.lat() + ll2.lat())/2.0, (this.lon() + ll2.lon())/2.0);
191 }
192
193 @Override public String toString() {
194 return "LatLon[lat="+lat()+",lon="+lon()+"]";
195 }
196
197 /**
198 * Replies a clone of this lat LatLon, rounded to OSM precisions, i.e. to
199 * 10^-7
200 *
201 * @return a clone of this lat LatLon
202 */
203 public LatLon getRoundedToOsmPrecision() {
204 return new LatLon(
205 Math.round(lat() * 10e6) / 10e6d,
206 Math.round(lon() * 10e6) / 10e6d
207 );
208 }
209
210
211 @Override
212 public int hashCode() {
213 final int prime = 31;
214 int result = super.hashCode();
215 long temp;
216 temp = java.lang.Double.doubleToLongBits(x);
217 result = prime * result + (int) (temp ^ (temp >>> 32));
218 temp = java.lang.Double.doubleToLongBits(y);
219 result = prime * result + (int) (temp ^ (temp >>> 32));
220 return result;
221 }
222
223 @Override
224 public boolean equals(Object obj) {
225 if (this == obj)
226 return true;
227 if (!super.equals(obj))
228 return false;
229 if (getClass() != obj.getClass())
230 return false;
231 Coordinate other = (Coordinate) obj;
232 if (java.lang.Double.doubleToLongBits(x) != java.lang.Double.doubleToLongBits(other.x))
233 return false;
234 if (java.lang.Double.doubleToLongBits(y) != java.lang.Double.doubleToLongBits(other.y))
235 return false;
236 return true;
237 }
238}
Note: See TracBrowser for help on using the repository browser.