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

Last change on this file since 12164 was 12163, checked in by michael2402, 7 years ago

Make use of ILatLon#getEastNorth

  • Property svn:eol-style set to native
File size: 25.6 KB
Line 
1// License: GPL. For details, see LICENSE file.
2package org.openstreetmap.josm.data.coor;
3
4import static java.lang.Math.PI;
5import static java.lang.Math.asin;
6import static java.lang.Math.atan2;
7import static java.lang.Math.cos;
8import static java.lang.Math.sin;
9import static java.lang.Math.sqrt;
10import static org.openstreetmap.josm.data.projection.Ellipsoid.WGS84;
11import static org.openstreetmap.josm.tools.I18n.trc;
12import static org.openstreetmap.josm.tools.Utils.toRadians;
13
14import java.awt.geom.Area;
15import java.text.DecimalFormat;
16import java.text.NumberFormat;
17import java.util.ArrayList;
18import java.util.Arrays;
19import java.util.List;
20import java.util.Locale;
21import java.util.Objects;
22import java.util.regex.Matcher;
23import java.util.regex.Pattern;
24
25import org.openstreetmap.gui.jmapviewer.interfaces.ICoordinate;
26import org.openstreetmap.josm.Main;
27import org.openstreetmap.josm.data.Bounds;
28import org.openstreetmap.josm.tools.Utils;
29
30/**
31 * LatLon are unprojected latitude / longitude coordinates.
32 * <br>
33 * <b>Latitude</b> specifies the north-south position in degrees
34 * where valid values are in the [-90,90] and positive values specify positions north of the equator.
35 * <br>
36 * <b>Longitude</b> specifies the east-west position in degrees
37 * where valid values are in the [-180,180] and positive values specify positions east of the prime meridian.
38 * <br>
39 * <img alt="lat/lon" src="https://upload.wikimedia.org/wikipedia/commons/6/62/Latitude_and_Longitude_of_the_Earth.svg">
40 * <br>
41 * This class is immutable.
42 *
43 * @author Imi
44 */
45public class LatLon extends Coordinate implements ILatLon {
46
47 private static final long serialVersionUID = 1L;
48
49 /**
50 * Minimum difference in location to not be represented as the same position.
51 * The API returns 7 decimals.
52 */
53 public static final double MAX_SERVER_PRECISION = 1e-7;
54 public static final double MAX_SERVER_INV_PRECISION = 1e7;
55
56 /**
57 * The (0,0) coordinates.
58 * @since 6178
59 */
60 public static final LatLon ZERO = new LatLon(0, 0);
61
62 /** North pole. */
63 public static final LatLon NORTH_POLE = new LatLon(90, 0);
64 /** South pole. */
65 public static final LatLon SOUTH_POLE = new LatLon(-90, 0);
66
67 private static DecimalFormat cDmsMinuteFormatter = new DecimalFormat("00");
68 private static DecimalFormat cDmsSecondFormatter = new DecimalFormat(
69 Main.pref == null ? "00.0" : Main.pref.get("latlon.dms.decimal-format", "00.0"));
70 private static DecimalFormat cDmMinuteFormatter = new DecimalFormat(
71 Main.pref == null ? "00.000" : Main.pref.get("latlon.dm.decimal-format", "00.000"));
72 public static final DecimalFormat cDdFormatter;
73 public static final DecimalFormat cDdHighPecisionFormatter;
74 static {
75 // Don't use the localized decimal separator. This way we can present
76 // a comma separated list of coordinates.
77 cDdFormatter = (DecimalFormat) NumberFormat.getInstance(Locale.UK);
78 cDdFormatter.applyPattern("###0.0######");
79 cDdHighPecisionFormatter = (DecimalFormat) NumberFormat.getInstance(Locale.UK);
80 cDdHighPecisionFormatter.applyPattern("###0.0##########");
81 }
82
83 private static final String cDms60 = cDmsSecondFormatter.format(60.0);
84 private static final String cDms00 = cDmsSecondFormatter.format(0.0);
85 private static final String cDm60 = cDmMinuteFormatter.format(60.0);
86 private static final String cDm00 = cDmMinuteFormatter.format(0.0);
87
88 /** Character denoting South, as string */
89 public static final String SOUTH = trc("compass", "S");
90 /** Character denoting North, as string */
91 public static final String NORTH = trc("compass", "N");
92 /** Character denoting West, as string */
93 public static final String WEST = trc("compass", "W");
94 /** Character denoting East, as string */
95 public static final String EAST = trc("compass", "E");
96
97 private static final char N_TR = NORTH.charAt(0);
98 private static final char S_TR = SOUTH.charAt(0);
99 private static final char E_TR = EAST.charAt(0);
100 private static final char W_TR = WEST.charAt(0);
101
102 private static final String DEG = "\u00B0";
103 private static final String MIN = "\u2032";
104 private static final String SEC = "\u2033";
105
106 private static final Pattern P = Pattern.compile(
107 "([+|-]?\\d+[.,]\\d+)|" // (1)
108 + "([+|-]?\\d+)|" // (2)
109 + "("+DEG+"|o|deg)|" // (3)
110 + "('|"+MIN+"|min)|" // (4)
111 + "(\"|"+SEC+"|sec)|" // (5)
112 + "(,|;)|" // (6)
113 + "([NSEW"+N_TR+S_TR+E_TR+W_TR+"])|"// (7)
114 + "\\s+|"
115 + "(.+)", Pattern.CASE_INSENSITIVE);
116
117 private static final Pattern P_XML = Pattern.compile(
118 "lat=[\"']([+|-]?\\d+[.,]\\d+)[\"']\\s+lon=[\"']([+|-]?\\d+[.,]\\d+)[\"']");
119
120 /**
121 * Replies true if lat is in the range [-90,90]
122 *
123 * @param lat the latitude
124 * @return true if lat is in the range [-90,90]
125 */
126 public static boolean isValidLat(double lat) {
127 return lat >= -90d && lat <= 90d;
128 }
129
130 /**
131 * Replies true if lon is in the range [-180,180]
132 *
133 * @param lon the longitude
134 * @return true if lon is in the range [-180,180]
135 */
136 public static boolean isValidLon(double lon) {
137 return lon >= -180d && lon <= 180d;
138 }
139
140 /**
141 * Make sure longitude value is within <code>[-180, 180]</code> range.
142 * @param lon the longitude in degrees
143 * @return lon plus/minus multiples of <code>360</code>, as needed to get
144 * in <code>[-180, 180]</code> range
145 */
146 public static double normalizeLon(double lon) {
147 if (lon >= -180 && lon <= 180)
148 return lon;
149 else {
150 lon = lon % 360.0;
151 if (lon > 180) {
152 return lon - 360;
153 } else if (lon < -180) {
154 return lon + 360;
155 }
156 return lon;
157 }
158 }
159
160 /**
161 * Replies true if lat is in the range [-90,90] and lon is in the range [-180,180]
162 *
163 * @return true if lat is in the range [-90,90] and lon is in the range [-180,180]
164 */
165 public boolean isValid() {
166 return isValidLat(lat()) && isValidLon(lon());
167 }
168
169 /**
170 * Clamp the lat value to be inside the world.
171 * @param value The value
172 * @return The value clamped to the world.
173 */
174 public static double toIntervalLat(double value) {
175 return Utils.clamp(value, -90, 90);
176 }
177
178 /**
179 * Returns a valid OSM longitude [-180,+180] for the given extended longitude value.
180 * For example, a value of -181 will return +179, a value of +181 will return -179.
181 * @param value A longitude value not restricted to the [-180,+180] range.
182 * @return a valid OSM longitude [-180,+180]
183 */
184 public static double toIntervalLon(double value) {
185 if (isValidLon(value))
186 return value;
187 else {
188 int n = (int) (value + Math.signum(value)*180.0) / 360;
189 return value - n*360.0;
190 }
191 }
192
193 /**
194 * Replies the coordinate in degrees/minutes/seconds format
195 * @param pCoordinate The coordinate to convert
196 * @return The coordinate in degrees/minutes/seconds format
197 */
198 public static String dms(double pCoordinate) {
199
200 double tAbsCoord = Math.abs(pCoordinate);
201 int tDegree = (int) tAbsCoord;
202 double tTmpMinutes = (tAbsCoord - tDegree) * 60;
203 int tMinutes = (int) tTmpMinutes;
204 double tSeconds = (tTmpMinutes - tMinutes) * 60;
205
206 String sDegrees = Integer.toString(tDegree);
207 String sMinutes = cDmsMinuteFormatter.format(tMinutes);
208 String sSeconds = cDmsSecondFormatter.format(tSeconds);
209
210 if (cDms60.equals(sSeconds)) {
211 sSeconds = cDms00;
212 sMinutes = cDmsMinuteFormatter.format(tMinutes+1L);
213 }
214 if ("60".equals(sMinutes)) {
215 sMinutes = "00";
216 sDegrees = Integer.toString(tDegree+1);
217 }
218
219 return sDegrees + '\u00B0' + sMinutes + '\'' + sSeconds + '\"';
220 }
221
222 /**
223 * Replies the coordinate in degrees/minutes format
224 * @param pCoordinate The coordinate to convert
225 * @return The coordinate in degrees/minutes format
226 */
227 public static String dm(double pCoordinate) {
228
229 double tAbsCoord = Math.abs(pCoordinate);
230 int tDegree = (int) tAbsCoord;
231 double tMinutes = (tAbsCoord - tDegree) * 60;
232
233 String sDegrees = Integer.toString(tDegree);
234 String sMinutes = cDmMinuteFormatter.format(tMinutes);
235
236 if (sMinutes.equals(cDm60)) {
237 sMinutes = cDm00;
238 sDegrees = Integer.toString(tDegree+1);
239 }
240
241 return sDegrees + '\u00B0' + sMinutes + '\'';
242 }
243
244 /**
245 * Constructs a new object representing the given latitude/longitude.
246 * @param lat the latitude, i.e., the north-south position in degrees
247 * @param lon the longitude, i.e., the east-west position in degrees
248 */
249 public LatLon(double lat, double lon) {
250 super(lon, lat);
251 }
252
253 /**
254 * Creates a new LatLon object for the given coordinate
255 * @param coor The coordinates to copy from.
256 */
257 public LatLon(ILatLon coor) {
258 super(coor.lon(), coor.lat());
259 }
260
261 /**
262 * Constructs a new object for the given coordinate
263 * @param coor the coordinate
264 */
265 public LatLon(ICoordinate coor) {
266 this(coor.getLat(), coor.getLon());
267 }
268
269 @Override
270 public double lat() {
271 return y;
272 }
273
274 /**
275 * Formats the latitude part according to the given format
276 * @param d the coordinate format to use
277 * @return the formatted latitude
278 */
279 public String latToString(CoordinateFormat d) {
280 switch(d) {
281 case DECIMAL_DEGREES: return cDdFormatter.format(y);
282 case DEGREES_MINUTES_SECONDS: return dms(y) + ((y < 0) ? SOUTH : NORTH);
283 case NAUTICAL: return dm(y) + ((y < 0) ? SOUTH : NORTH);
284 case EAST_NORTH: return cDdFormatter.format(this.getEastNorth().north());
285 default: return "ERR";
286 }
287 }
288
289 @Override
290 public double lon() {
291 return x;
292 }
293
294 /**
295 * Formats the longitude part according to the given format
296 * @param d the coordinate format to use
297 * @return the formatted longitude
298 */
299 public String lonToString(CoordinateFormat d) {
300 switch(d) {
301 case DECIMAL_DEGREES: return cDdFormatter.format(x);
302 case DEGREES_MINUTES_SECONDS: return dms(x) + ((x < 0) ? WEST : EAST);
303 case NAUTICAL: return dm(x) + ((x < 0) ? WEST : EAST);
304 case EAST_NORTH: return cDdFormatter.format(this.getEastNorth().east());
305 default: return "ERR";
306 }
307 }
308
309 /**
310 * @param other other lat/lon
311 * @return <code>true</code> if the other point has almost the same lat/lon
312 * values, only differing by no more than 1 / {@link #MAX_SERVER_PRECISION MAX_SERVER_PRECISION}.
313 */
314 public boolean equalsEpsilon(LatLon other) {
315 double p = MAX_SERVER_PRECISION / 2;
316 return Math.abs(lat()-other.lat()) <= p && Math.abs(lon()-other.lon()) <= p;
317 }
318
319 /**
320 * Determines if this lat/lon is outside of the world
321 * @return <code>true</code>, if the coordinate is outside the world, compared by using lat/lon.
322 */
323 public boolean isOutSideWorld() {
324 Bounds b = Main.getProjection().getWorldBoundsLatLon();
325 return lat() < b.getMinLat() || lat() > b.getMaxLat() ||
326 lon() < b.getMinLon() || lon() > b.getMaxLon();
327 }
328
329 /**
330 * Determines if this lat/lon is within the given bounding box.
331 * @param b bounding box
332 * @return <code>true</code> if this is within the given bounding box.
333 */
334 public boolean isWithin(Bounds b) {
335 return b.contains(this);
336 }
337
338 /**
339 * Check if this is contained in given area or area is null.
340 *
341 * @param a Area
342 * @return <code>true</code> if this is contained in given area or area is null.
343 */
344 public boolean isIn(Area a) {
345 return a == null || a.contains(x, y);
346 }
347
348 /**
349 * Computes the distance between this lat/lon and another point on the earth.
350 * Uses Haversine formular.
351 * @param other the other point.
352 * @return distance in metres.
353 */
354 public double greatCircleDistance(LatLon other) {
355 double sinHalfLat = sin(toRadians(other.lat() - this.lat()) / 2);
356 double sinHalfLon = sin(toRadians(other.lon() - this.lon()) / 2);
357 double d = 2 * WGS84.a * asin(
358 sqrt(sinHalfLat*sinHalfLat +
359 cos(toRadians(this.lat()))*cos(toRadians(other.lat()))*sinHalfLon*sinHalfLon));
360 // For points opposite to each other on the sphere,
361 // rounding errors could make the argument of asin greater than 1
362 // (This should almost never happen.)
363 if (java.lang.Double.isNaN(d)) {
364 Main.error("NaN in greatCircleDistance");
365 d = PI * WGS84.a;
366 }
367 return d;
368 }
369
370 /**
371 * Returns the heading that you have to use to get from this lat/lon to another.
372 *
373 * Angle starts from north and increases counterclockwise (!), PI/2 means west.
374 * You can get usual clockwise angle from {@link #bearing(LatLon)} method.
375 * This method is kept as deprecated because it is called from many plugins.
376 *
377 * (I don't know the original source of this formula, but see
378 * <a href="https://math.stackexchange.com/questions/720/how-to-calculate-a-heading-on-the-earths-surface">this question</a>
379 * for some hints how it is derived.)
380 *
381 * @deprecated see bearing method
382 * @param other the "destination" position
383 * @return heading in radians in the range 0 &lt;= hd &lt; 2*PI
384 */
385 @Deprecated
386 public double heading(LatLon other) {
387 double hd = atan2(sin(toRadians(this.lon() - other.lon())) * cos(toRadians(other.lat())),
388 cos(toRadians(this.lat())) * sin(toRadians(other.lat())) -
389 sin(toRadians(this.lat())) * cos(toRadians(other.lat())) * cos(toRadians(this.lon() - other.lon())));
390 hd %= 2 * PI;
391 if (hd < 0) {
392 hd += 2 * PI;
393 }
394 return hd;
395 }
396
397 /**
398 * Returns bearing from this point to another.
399 *
400 * Angle starts from north and increases clockwise, PI/2 means east.
401 * Old deprecated method {@link #heading(LatLon)} used unusual reverse angle.
402 *
403 * Please note that reverse bearing (from other point to this point) should NOT be
404 * calculated from return value of this method, because great circle path
405 * between the two points have different bearings at each position.
406 *
407 * To get bearing from another point to this point call other.bearing(this)
408 *
409 * @param other the "destination" position
410 * @return heading in radians in the range 0 &lt;= hd &lt; 2*PI
411 */
412 public double bearing(LatLon other) {
413 double lat1 = toRadians(this.lat());
414 double lat2 = toRadians(other.lat());
415 double dlon = toRadians(other.lon() - this.lon());
416 double bearing = atan2(
417 sin(dlon) * cos(lat2),
418 cos(lat1) * sin(lat2) - sin(lat1) * cos(lat2) * cos(dlon)
419 );
420 bearing %= 2 * PI;
421 if (bearing < 0) {
422 bearing += 2 * PI;
423 }
424 return bearing;
425 }
426
427 /**
428 * Returns this lat/lon pair in human-readable format.
429 *
430 * @return String in the format "lat=1.23456 deg, lon=2.34567 deg"
431 */
432 public String toDisplayString() {
433 NumberFormat nf = NumberFormat.getInstance();
434 nf.setMaximumFractionDigits(5);
435 return "lat=" + nf.format(lat()) + "\u00B0, lon=" + nf.format(lon()) + '\u00B0';
436 }
437
438 /**
439 * Returns this lat/lon pair in human-readable format separated by {@code separator}.
440 * @param separator values separator
441 * @return String in the format {@code "1.23456[separator]2.34567"}
442 */
443 public String toStringCSV(String separator) {
444 return Utils.join(separator, Arrays.asList(
445 latToString(CoordinateFormat.DECIMAL_DEGREES),
446 lonToString(CoordinateFormat.DECIMAL_DEGREES)
447 ));
448 }
449
450 /**
451 * Interpolate between this and a other latlon
452 * @param ll2 The other lat/lon object
453 * @param proportion The proportion to interpolate
454 * @return a new latlon at this position if proportion is 0, at the other position it proportion is 1 and lineary interpolated otherwise.
455 */
456 public LatLon interpolate(LatLon ll2, double proportion) {
457 // this is an alternate form of this.lat() + proportion * (ll2.lat() - this.lat()) that is slightly faster
458 return new LatLon((1 - proportion) * this.lat() + proportion * ll2.lat(),
459 (1 - proportion) * this.lon() + proportion * ll2.lon());
460 }
461
462 /**
463 * Get the center between two lat/lon points
464 * @param ll2 The other {@link LatLon}
465 * @return The center at the average coordinates of the two points. Does not take the 180° meridian into account.
466 */
467 public LatLon getCenter(LatLon ll2) {
468 // The JIT will inline this for us, it is as fast as the normal /2 approach
469 return interpolate(ll2, .5);
470 }
471
472 /**
473 * Returns the euclidean distance from this {@code LatLon} to a specified {@code LatLon}.
474 *
475 * @param ll the specified coordinate to be measured against this {@code LatLon}
476 * @return the euclidean distance from this {@code LatLon} to a specified {@code LatLon}
477 * @since 6166
478 */
479 public double distance(final LatLon ll) {
480 return super.distance(ll);
481 }
482
483 /**
484 * Returns the square of the euclidean distance from this {@code LatLon} to a specified {@code LatLon}.
485 *
486 * @param ll the specified coordinate to be measured against this {@code LatLon}
487 * @return the square of the euclidean distance from this {@code LatLon} to a specified {@code LatLon}
488 * @since 6166
489 */
490 public double distanceSq(final LatLon ll) {
491 return super.distanceSq(ll);
492 }
493
494 @Override
495 public String toString() {
496 return "LatLon[lat="+lat()+",lon="+lon()+']';
497 }
498
499 /**
500 * Returns the value rounded to OSM precisions, i.e. to {@link #MAX_SERVER_PRECISION}.
501 * @param value lat/lon value
502 *
503 * @return rounded value
504 */
505 public static double roundToOsmPrecision(double value) {
506 return Math.round(value * MAX_SERVER_INV_PRECISION) / MAX_SERVER_INV_PRECISION;
507 }
508
509 /**
510 * Replies a clone of this lat LatLon, rounded to OSM precisions, i.e. to {@link #MAX_SERVER_PRECISION}
511 *
512 * @return a clone of this lat LatLon
513 */
514 public LatLon getRoundedToOsmPrecision() {
515 return new LatLon(
516 roundToOsmPrecision(lat()),
517 roundToOsmPrecision(lon())
518 );
519 }
520
521 @Override
522 public int hashCode() {
523 return Objects.hash(x, y);
524 }
525
526 @Override
527 public boolean equals(Object obj) {
528 if (this == obj) return true;
529 if (obj == null || getClass() != obj.getClass()) return false;
530 LatLon that = (LatLon) obj;
531 return Double.compare(that.x, x) == 0 &&
532 Double.compare(that.y, y) == 0;
533 }
534
535 /**
536 * Converts this latitude/longitude to an instance of {@link ICoordinate}.
537 * @return a {@link ICoordinate} instance of this latitude/longitude
538 */
539 public ICoordinate toCoordinate() {
540 return new org.openstreetmap.gui.jmapviewer.Coordinate(lat(), lon());
541 }
542
543 private static class LatLonHolder {
544 private double lat = Double.NaN;
545 private double lon = Double.NaN;
546 }
547
548 private static void setLatLonObj(final LatLonHolder latLon,
549 final Object coord1deg, final Object coord1min, final Object coord1sec, final Object card1,
550 final Object coord2deg, final Object coord2min, final Object coord2sec, final Object card2) {
551
552 setLatLon(latLon,
553 (Double) coord1deg, (Double) coord1min, (Double) coord1sec, (String) card1,
554 (Double) coord2deg, (Double) coord2min, (Double) coord2sec, (String) card2);
555 }
556
557 private static void setLatLon(final LatLonHolder latLon,
558 final double coord1deg, final double coord1min, final double coord1sec, final String card1,
559 final double coord2deg, final double coord2min, final double coord2sec, final String card2) {
560
561 setLatLon(latLon, coord1deg, coord1min, coord1sec, card1);
562 setLatLon(latLon, coord2deg, coord2min, coord2sec, card2);
563 if (Double.isNaN(latLon.lat) || Double.isNaN(latLon.lon)) {
564 throw new IllegalArgumentException("invalid lat/lon parameters");
565 }
566 }
567
568 private static void setLatLon(final LatLonHolder latLon, final double coordDeg, final double coordMin, final double coordSec,
569 final String card) {
570 if (coordDeg < -180 || coordDeg > 180 || coordMin < 0 || coordMin >= 60 || coordSec < 0 || coordSec > 60) {
571 throw new IllegalArgumentException("out of range");
572 }
573
574 double coord = (coordDeg < 0 ? -1 : 1) * (Math.abs(coordDeg) + coordMin / 60 + coordSec / 3600);
575 coord = "N".equals(card) || "E".equals(card) ? coord : -coord;
576 if ("N".equals(card) || "S".equals(card)) {
577 latLon.lat = coord;
578 } else {
579 latLon.lon = coord;
580 }
581 }
582
583 /**
584 * Parses the given string as lat/lon.
585 * @param coord String to parse
586 * @return parsed lat/lon
587 * @since 11045
588 */
589 public static LatLon parse(String coord) {
590 final LatLonHolder latLon = new LatLonHolder();
591 final Matcher mXml = P_XML.matcher(coord);
592 if (mXml.matches()) {
593 setLatLonObj(latLon,
594 Double.valueOf(mXml.group(1).replace(',', '.')), 0.0, 0.0, "N",
595 Double.valueOf(mXml.group(2).replace(',', '.')), 0.0, 0.0, "E");
596 } else {
597 final Matcher m = P.matcher(coord);
598
599 final StringBuilder sb = new StringBuilder();
600 final List<Object> list = new ArrayList<>();
601
602 while (m.find()) {
603 if (m.group(1) != null) {
604 sb.append('R'); // floating point number
605 list.add(Double.valueOf(m.group(1).replace(',', '.')));
606 } else if (m.group(2) != null) {
607 sb.append('Z'); // integer number
608 list.add(Double.valueOf(m.group(2)));
609 } else if (m.group(3) != null) {
610 sb.append('o'); // degree sign
611 } else if (m.group(4) != null) {
612 sb.append('\''); // seconds sign
613 } else if (m.group(5) != null) {
614 sb.append('"'); // minutes sign
615 } else if (m.group(6) != null) {
616 sb.append(','); // separator
617 } else if (m.group(7) != null) {
618 sb.append('x'); // cardinal direction
619 String c = m.group(7).toUpperCase(Locale.ENGLISH);
620 if ("N".equalsIgnoreCase(c) || "S".equalsIgnoreCase(c) || "E".equalsIgnoreCase(c) || "W".equalsIgnoreCase(c)) {
621 list.add(c);
622 } else {
623 list.add(c.replace(N_TR, 'N').replace(S_TR, 'S')
624 .replace(E_TR, 'E').replace(W_TR, 'W'));
625 }
626 } else if (m.group(8) != null) {
627 throw new IllegalArgumentException("invalid token: " + m.group(8));
628 }
629 }
630
631 final String pattern = sb.toString();
632
633 final Object[] params = list.toArray();
634
635 if (pattern.matches("Ro?,?Ro?")) {
636 setLatLonObj(latLon,
637 params[0], 0.0, 0.0, "N",
638 params[1], 0.0, 0.0, "E");
639 } else if (pattern.matches("xRo?,?xRo?")) {
640 setLatLonObj(latLon,
641 params[1], 0.0, 0.0, params[0],
642 params[3], 0.0, 0.0, params[2]);
643 } else if (pattern.matches("Ro?x,?Ro?x")) {
644 setLatLonObj(latLon,
645 params[0], 0.0, 0.0, params[1],
646 params[2], 0.0, 0.0, params[3]);
647 } else if (pattern.matches("Zo[RZ]'?,?Zo[RZ]'?|Z[RZ],?Z[RZ]")) {
648 setLatLonObj(latLon,
649 params[0], params[1], 0.0, "N",
650 params[2], params[3], 0.0, "E");
651 } else if (pattern.matches("xZo[RZ]'?,?xZo[RZ]'?|xZo?[RZ],?xZo?[RZ]")) {
652 setLatLonObj(latLon,
653 params[1], params[2], 0.0, params[0],
654 params[4], params[5], 0.0, params[3]);
655 } else if (pattern.matches("Zo[RZ]'?x,?Zo[RZ]'?x|Zo?[RZ]x,?Zo?[RZ]x")) {
656 setLatLonObj(latLon,
657 params[0], params[1], 0.0, params[2],
658 params[3], params[4], 0.0, params[5]);
659 } else if (pattern.matches("ZoZ'[RZ]\"?x,?ZoZ'[RZ]\"?x|ZZ[RZ]x,?ZZ[RZ]x")) {
660 setLatLonObj(latLon,
661 params[0], params[1], params[2], params[3],
662 params[4], params[5], params[6], params[7]);
663 } else if (pattern.matches("xZoZ'[RZ]\"?,?xZoZ'[RZ]\"?|xZZ[RZ],?xZZ[RZ]")) {
664 setLatLonObj(latLon,
665 params[1], params[2], params[3], params[0],
666 params[5], params[6], params[7], params[4]);
667 } else if (pattern.matches("ZZ[RZ],?ZZ[RZ]")) {
668 setLatLonObj(latLon,
669 params[0], params[1], params[2], "N",
670 params[3], params[4], params[5], "E");
671 } else {
672 throw new IllegalArgumentException("invalid format: " + pattern);
673 }
674 }
675
676 return new LatLon(latLon.lat, latLon.lon);
677 }
678}
Note: See TracBrowser for help on using the repository browser.