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

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

see #15229 - deprecate LatLon#toStringCSV

removes last references of LatLon to CoordinateFormat classes

  • Property svn:eol-style set to native
File size: 24.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.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.conversion.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.conversion.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 * @deprecated method removed without replacment
425 */
426 @Deprecated
427 public String toStringCSV(String separator) {
428 return Utils.join(separator, Arrays.asList(
429 DecimalDegreesCoordinateFormat.INSTANCE.latToString(this),
430 DecimalDegreesCoordinateFormat.INSTANCE.lonToString(this)
431 ));
432 }
433
434 /**
435 * Interpolate between this and a other latlon
436 * @param ll2 The other lat/lon object
437 * @param proportion The proportion to interpolate
438 * @return a new latlon at this position if proportion is 0, at the other position it proportion is 1 and lineary interpolated otherwise.
439 */
440 public LatLon interpolate(LatLon ll2, double proportion) {
441 // this is an alternate form of this.lat() + proportion * (ll2.lat() - this.lat()) that is slightly faster
442 return new LatLon((1 - proportion) * this.lat() + proportion * ll2.lat(),
443 (1 - proportion) * this.lon() + proportion * ll2.lon());
444 }
445
446 /**
447 * Get the center between two lat/lon points
448 * @param ll2 The other {@link LatLon}
449 * @return The center at the average coordinates of the two points. Does not take the 180° meridian into account.
450 */
451 public LatLon getCenter(LatLon ll2) {
452 // The JIT will inline this for us, it is as fast as the normal /2 approach
453 return interpolate(ll2, .5);
454 }
455
456 /**
457 * Returns the euclidean distance from this {@code LatLon} to a specified {@code LatLon}.
458 *
459 * @param ll the specified coordinate to be measured against this {@code LatLon}
460 * @return the euclidean distance from this {@code LatLon} to a specified {@code LatLon}
461 * @since 6166
462 */
463 public double distance(final LatLon ll) {
464 return super.distance(ll);
465 }
466
467 /**
468 * Returns the square of the euclidean distance from this {@code LatLon} to a specified {@code LatLon}.
469 *
470 * @param ll the specified coordinate to be measured against this {@code LatLon}
471 * @return the square of the euclidean distance from this {@code LatLon} to a specified {@code LatLon}
472 * @since 6166
473 */
474 public double distanceSq(final LatLon ll) {
475 return super.distanceSq(ll);
476 }
477
478 @Override
479 public String toString() {
480 return "LatLon[lat="+lat()+",lon="+lon()+']';
481 }
482
483 /**
484 * Returns the value rounded to OSM precisions, i.e. to {@link #MAX_SERVER_PRECISION}.
485 * @param value lat/lon value
486 *
487 * @return rounded value
488 */
489 public static double roundToOsmPrecision(double value) {
490 return Math.round(value * MAX_SERVER_INV_PRECISION) / MAX_SERVER_INV_PRECISION;
491 }
492
493 /**
494 * Replies a clone of this lat LatLon, rounded to OSM precisions, i.e. to {@link #MAX_SERVER_PRECISION}
495 *
496 * @return a clone of this lat LatLon
497 */
498 public LatLon getRoundedToOsmPrecision() {
499 return new LatLon(
500 roundToOsmPrecision(lat()),
501 roundToOsmPrecision(lon())
502 );
503 }
504
505 @Override
506 public int hashCode() {
507 return Objects.hash(x, y);
508 }
509
510 @Override
511 public boolean equals(Object obj) {
512 if (this == obj) return true;
513 if (obj == null || getClass() != obj.getClass()) return false;
514 LatLon that = (LatLon) obj;
515 return Double.compare(that.x, x) == 0 &&
516 Double.compare(that.y, y) == 0;
517 }
518
519 private static class LatLonHolder {
520 private double lat = Double.NaN;
521 private double lon = Double.NaN;
522 }
523
524 private static void setLatLonObj(final LatLonHolder latLon,
525 final Object coord1deg, final Object coord1min, final Object coord1sec, final Object card1,
526 final Object coord2deg, final Object coord2min, final Object coord2sec, final Object card2) {
527
528 setLatLon(latLon,
529 (Double) coord1deg, (Double) coord1min, (Double) coord1sec, (String) card1,
530 (Double) coord2deg, (Double) coord2min, (Double) coord2sec, (String) card2);
531 }
532
533 private static void setLatLon(final LatLonHolder latLon,
534 final double coord1deg, final double coord1min, final double coord1sec, final String card1,
535 final double coord2deg, final double coord2min, final double coord2sec, final String card2) {
536
537 setLatLon(latLon, coord1deg, coord1min, coord1sec, card1);
538 setLatLon(latLon, coord2deg, coord2min, coord2sec, card2);
539 if (Double.isNaN(latLon.lat) || Double.isNaN(latLon.lon)) {
540 throw new IllegalArgumentException("invalid lat/lon parameters");
541 }
542 }
543
544 private static void setLatLon(final LatLonHolder latLon, final double coordDeg, final double coordMin, final double coordSec,
545 final String card) {
546 if (coordDeg < -180 || coordDeg > 180 || coordMin < 0 || coordMin >= 60 || coordSec < 0 || coordSec > 60) {
547 throw new IllegalArgumentException("out of range");
548 }
549
550 double coord = (coordDeg < 0 ? -1 : 1) * (Math.abs(coordDeg) + coordMin / 60 + coordSec / 3600);
551 coord = "N".equals(card) || "E".equals(card) ? coord : -coord;
552 if ("N".equals(card) || "S".equals(card)) {
553 latLon.lat = coord;
554 } else {
555 latLon.lon = coord;
556 }
557 }
558
559 /**
560 * Parses the given string as lat/lon.
561 * @param coord String to parse
562 * @return parsed lat/lon
563 * @since 11045
564 */
565 public static LatLon parse(String coord) {
566 final LatLonHolder latLon = new LatLonHolder();
567 final Matcher mXml = P_XML.matcher(coord);
568 if (mXml.matches()) {
569 setLatLonObj(latLon,
570 Double.valueOf(mXml.group(1).replace(',', '.')), 0.0, 0.0, "N",
571 Double.valueOf(mXml.group(2).replace(',', '.')), 0.0, 0.0, "E");
572 } else {
573 final Matcher m = P.matcher(coord);
574
575 final StringBuilder sb = new StringBuilder();
576 final List<Object> list = new ArrayList<>();
577
578 while (m.find()) {
579 if (m.group(1) != null) {
580 sb.append('R'); // floating point number
581 list.add(Double.valueOf(m.group(1).replace(',', '.')));
582 } else if (m.group(2) != null) {
583 sb.append('Z'); // integer number
584 list.add(Double.valueOf(m.group(2)));
585 } else if (m.group(3) != null) {
586 sb.append('o'); // degree sign
587 } else if (m.group(4) != null) {
588 sb.append('\''); // seconds sign
589 } else if (m.group(5) != null) {
590 sb.append('"'); // minutes sign
591 } else if (m.group(6) != null) {
592 sb.append(','); // separator
593 } else if (m.group(7) != null) {
594 sb.append('x'); // cardinal direction
595 String c = m.group(7).toUpperCase(Locale.ENGLISH);
596 if ("N".equalsIgnoreCase(c) || "S".equalsIgnoreCase(c) || "E".equalsIgnoreCase(c) || "W".equalsIgnoreCase(c)) {
597 list.add(c);
598 } else {
599 list.add(c.replace(N_TR, 'N').replace(S_TR, 'S')
600 .replace(E_TR, 'E').replace(W_TR, 'W'));
601 }
602 } else if (m.group(8) != null) {
603 throw new IllegalArgumentException("invalid token: " + m.group(8));
604 }
605 }
606
607 final String pattern = sb.toString();
608
609 final Object[] params = list.toArray();
610
611 if (pattern.matches("Ro?,?Ro?")) {
612 setLatLonObj(latLon,
613 params[0], 0.0, 0.0, "N",
614 params[1], 0.0, 0.0, "E");
615 } else if (pattern.matches("xRo?,?xRo?")) {
616 setLatLonObj(latLon,
617 params[1], 0.0, 0.0, params[0],
618 params[3], 0.0, 0.0, params[2]);
619 } else if (pattern.matches("Ro?x,?Ro?x")) {
620 setLatLonObj(latLon,
621 params[0], 0.0, 0.0, params[1],
622 params[2], 0.0, 0.0, params[3]);
623 } else if (pattern.matches("Zo[RZ]'?,?Zo[RZ]'?|Z[RZ],?Z[RZ]")) {
624 setLatLonObj(latLon,
625 params[0], params[1], 0.0, "N",
626 params[2], params[3], 0.0, "E");
627 } else if (pattern.matches("xZo[RZ]'?,?xZo[RZ]'?|xZo?[RZ],?xZo?[RZ]")) {
628 setLatLonObj(latLon,
629 params[1], params[2], 0.0, params[0],
630 params[4], params[5], 0.0, params[3]);
631 } else if (pattern.matches("Zo[RZ]'?x,?Zo[RZ]'?x|Zo?[RZ]x,?Zo?[RZ]x")) {
632 setLatLonObj(latLon,
633 params[0], params[1], 0.0, params[2],
634 params[3], params[4], 0.0, params[5]);
635 } else if (pattern.matches("ZoZ'[RZ]\"?x,?ZoZ'[RZ]\"?x|ZZ[RZ]x,?ZZ[RZ]x")) {
636 setLatLonObj(latLon,
637 params[0], params[1], params[2], params[3],
638 params[4], params[5], params[6], params[7]);
639 } else if (pattern.matches("xZoZ'[RZ]\"?,?xZoZ'[RZ]\"?|xZZ[RZ],?xZZ[RZ]")) {
640 setLatLonObj(latLon,
641 params[1], params[2], params[3], params[0],
642 params[5], params[6], params[7], params[4]);
643 } else if (pattern.matches("ZZ[RZ],?ZZ[RZ]")) {
644 setLatLonObj(latLon,
645 params[0], params[1], params[2], "N",
646 params[3], params[4], params[5], "E");
647 } else {
648 throw new IllegalArgumentException("invalid format: " + pattern);
649 }
650 }
651
652 return new LatLon(latLon.lat, latLon.lon);
653 }
654}
Note: See TracBrowser for help on using the repository browser.