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

Last change on this file since 12737 was 12737, checked in by bastiK, 7 years ago

revert last commit - still used in many plugins

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