View Javadoc

1   /*
2    * Trip Tracker, a real-time position tracking system for the Internet.
3    * Copyright (C) 2006  Team Trip Tracker
4    *
5    * This program is free software; you can redistribute it and/or modify it
6    * under the terms of the GNU General Public License as published by the
7    * Free Software Foundation; either version 2 of the License, or (at your
8    * option) any later version.
9    *
10   * This program is distributed in the hope that it will be useful, but
11   * WITHOUT ANY WARRANTY; without even the implied warranty of
12   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13   * General Public License for more details.
14   *
15   * You should have received a copy of the GNU General Public License along
16   * with this program; if not, write to the Free Software Foundation, Inc.,
17   * 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
18   */
19  
20  package triptracker.core;
21  
22  import static java.lang.Math.*;
23  import java.util.Date;
24  import java.util.Iterator;
25  import java.util.List;
26  
27  /***
28   * Represents a coordinate in a latitude/longitude coordinate system on a
29   * given time and date. Data in a Coordinate object is immutable.
30   * <p>
31   * Latitude is numbered from 0 degrees to 90 degrees north and south. 0 degrees
32   * is the equator, 90 degrees north is the North Pole and 90 degrees south is
33   * the South Pole. The <code>Coordinate</code> class numbers latitudes from -90
34   * degrees to 90 degrees where -90 degrees is the South Pole and 90 degrees is
35   * the North Pole.
36   * <p>
37   * Longitude is numbered from 0 degrees to 180 degrees east and west. 0 degrees
38   * is at Greenwich, England and they continue 180 degrees east and 180 degrees
39   * west where they meet at the International Date Line in the Pacific Ocean. The
40   * <code>Coordinate</code> class numbers longitude from -180 degrees to 180
41   * degrees where negative degrees are west and positive degrees are east of
42   * Greenwich, England at 0 degrees.
43   * <p>
44   * To precisely locate points on the earth's surface, degrees longitude and
45   * latitude have been divided into minutes (') and seconds ("). There are 60
46   * minutes in each degree and each minute is divided into 60 seconds. Seconds can
47   * be further divided into tenths, hundredths, or even thousandths.
48   */
49  public class Coordinate {
50  	/***
51  	 * Earth radius.
52  	 * See <a href="http://www.movable-type.co.uk/scripts/GIS-FAQ-5.1.html">
53  	 * http://www.movable-type.co.uk/scripts/GIS-FAQ-5.1.html</a>
54  	 * section 5.1a or
55  	 * <a href="http://www.movable-type.co.uk/scripts/LatLong.html">
56  	 * http://www.movable-type.co.uk/scripts/LatLong.html</a>.
57  	 */
58  	public static final double EARTH_RADIUS = 6366.7070194937075;
59  //	public static final double EARTH_RADIUS = 6367.45;
60  
61  	/***
62  	 * See <a href="http://www.movable-type.co.uk/scripts/LatLongVincenty.html">
63  	 * http://www.movable-type.co.uk/scripts/LatLongVincenty.html</a>
64  	 */
65  	public static final double WGS84_A = 6378137; // meter
66  	public static final double WGS84_B = 6356752.3142; // meter
67  	public static final double WGS84_F = 1 / 298.257223563;
68  	
69  	private int coordId;
70  	private final double ypos;
71  	private final double xpos;
72  	private final Date date;
73  	
74  	/***
75  	 * Default constructor. Creates a coordinate with x=0 and y=0.
76  	 */
77  	public Coordinate() {
78  		this(-1, 0, 0, null);
79  	}
80  	
81  	/***
82  	 * Creates a coordinate with the given latitude and longitude. The values of
83  	 * latitude and longitude can be retrieved by calling {@link #getY()} and
84  	 * {@link #getX()} respectively. 
85  	 * 
86  	 * @param latitude latitude from 90 degrees (north) to -90 degrees (south)
87  	 * @param longitude longitude from 180 degrees (east) to -180 degrees (west)
88  	 * @throws IllegalArgumentException if latitude or longitude is out of
89  	 * 		range.
90  	 */
91  	public Coordinate(final double latitude, final double longitude) {
92  		this(-1, latitude, longitude, null);
93  	}
94  	
95  	/***
96  	 * Creates a coordinate with the given latitude, longitude and date. The
97  	 * values of latitude and longitude can be retrieved by calling
98  	 * {@link #getY()} and {@link #getX()} respectively. 
99  	 * 
100 	 * @param latitude latitude from 90 degrees (north) to -90 degrees (south)
101 	 * @param longitude longitude from 180 degrees (east) to -180 degrees (west)
102 	 * @param date time associated with coordinate
103 	 * @throws IllegalArgumentException if latitude or longitude is out of
104 	 * 		range.
105 	 */
106 	public Coordinate(final double latitude, final double longitude,
107 			final Date date) {
108 		this(-1, latitude, longitude, date);
109 	}
110 	
111 	public Coordinate(final int coordId, final double latitude,
112 			final double longitude) {
113 		this(coordId, latitude, longitude, null);
114 	}
115 
116 	public Coordinate(final int coordId, final double latitude,
117 			final double longitude, final Date date) {
118 		// Check for invalid values.
119 		if (latitude > 90 || latitude < -90) {
120 			throw new IllegalArgumentException(
121 					"latitude not in range -90 to 90");
122 		} else if (longitude > 180 || longitude < -180) {
123 			throw new IllegalArgumentException(
124 					"longitude not in range -180 to 180");
125 		}
126 		
127 		this.coordId = coordId;
128 		this.ypos = latitude;
129 		this.xpos = longitude;
130 		this.date = date;
131 	}
132 
133 
134 	/***
135 	 * Returns the latitude position of the coordinate. 
136 	 * 
137 	 * @return latitude position of the coordinate
138 	 */
139 	public double getY() {
140 		return ypos;// * 100000000;
141 //		UTMPoint y = llToUTM(22,ypos,xpos);
142 //		return  y.getNorthing();
143 	}
144 	
145 	/***
146 	 * Returns the longitude position of the coordinate.
147 	 * 
148 	 * @return longitude position of the coordinate
149 	 */
150 	public double getX() {
151 //		UTMPoint x = llToUTM(22,ypos,xpos);
152 //		return x.getEasting();
153 		return xpos;// * 100000000;
154 	}
155 
156 	/***
157 	 * Returns the time and date associated with the coordinate.
158 	 * 
159 	 * @return time and date associated with coordinate
160 	 */
161 	public String getDateString() {
162 		if (date == null) {
163 			return "";
164 		} else {
165 			return Utils.dateToString(date);
166 		}
167 	}
168 	
169 	// FIXME Clean up in all toString methods here.
170 	/***
171 	 * Returns the string representation of a latitude/longitude coordinate.
172 	 * Example: 38?53'23.83"N 77?00'27.76"W
173 	 * 
174 	 * @return string representation of a latitude/longitude coordinate
175 	 * @see java.lang.Object#toString()
176 	 */
177 	@Override
178 	public String toString() {
179 		StringBuilder str = new StringBuilder();
180 		
181 		// Latitude
182 		str.append(ypos);
183 		if (ypos < 0) {
184 			str.append("S");
185 		} else {
186 			str.append("N");
187 		}
188 		
189 		// Longitude
190 		str.append(" " + xpos);
191 		if (xpos < 0) {
192 			str.append("W");
193 		} else {
194 			str.append("E");
195 		}
196 		
197 		// Date
198 		str.append(", " + date.toString());
199 		
200 		return str.toString();
201 	}
202 	
203 	/***
204 	 * Returns a string representation of the latitude
205 	 * 
206 	 * @return string representation of latitude
207 	 */
208 	public String getStringLat() {
209 		StringBuilder str = new StringBuilder();
210 
211 		// Latitude
212 		str.append(Sexagesimal.toString(ypos));
213 		if (ypos < 0) 
214 			str.append(" S");
215 		else 
216 			str.append(" N");
217 		
218 		return str.toString();
219 	}
220 	
221 	/***
222 	 * Returns a string representation of the longitude
223 	 * 
224 	 * @return string representation of longitude
225 	 */
226 	public String getStringLon() {
227 		StringBuilder str = new StringBuilder();
228 
229 		// Longitude
230 		str.append(Sexagesimal.toString(xpos));
231 		if (xpos < 0) {
232 			str.append(" W");
233 		} else {
234 			str.append(" E");
235 		}
236 		
237 		return str.toString();
238 	}
239 	
240 	/***
241 	 * Converts degrees in sexagesimal format to decimal format. 
242 	 * 
243 	 * @param sex sexagesimal formatted angle
244 	 * @return degrees in decimal format
245 	 */
246 	public static double sexToDec(final Sexagesimal sex) {
247 		return sexToDec(sex.getDeg(), sex.getMin(), sex.getSec());
248 	}
249 	
250 	/***
251 	 * Converts degrees in sexagesimal format to decimal format. 
252 	 * 
253 	 * @param degrees whole degrees
254 	 * @param minutes whole minutes
255 	 * @param seconds whole or fractional seconds
256 	 * @return degrees in decimal format
257 	 */
258 	public static double sexToDec(final int degrees, final int minutes,
259 			final double seconds) {
260 		return (degrees + ((double)minutes / 60) + (seconds / 3600));
261 	}
262 
263 	/***
264 	 * Converts degrees in decimal format to NMEA sexagesimal format.
265 	 * 
266 	 * @param degrees decimal degrees
267 	 * @return degrees in NMEAs sexagesimal format with degrees and minutes in
268 	 * 		front of the decimal separator and seconds (in 0-99) after in full
269 	 * 		decimal format after.
270 	 */
271 	public static double decToNmea(double degrees) {
272 		int deg = (int)degrees;
273 		degrees = (degrees - deg) * 60;
274 		
275 		int min = (int)degrees;
276 		degrees = degrees - min;
277 		
278 		return  ((deg * 100) + min + degrees);
279 	}
280 
281 	/***
282 	 * Converts degrees in decimal format to NMEA sexagesimal format. This is
283 	 * the old bugged conversion.
284 	 * 
285 	 * @deprecated Replaced by {@link #decToNmea(double)} to correct a
286 	 * 		calculation error.
287 	 * @param degrees decimal degrees
288 	 * @return degrees in NMEAs sexagesimal format with degrees and minutes in
289 	 * 		front of the decimal separator and seconds (in 0-99) after in full
290 	 * 		decimal format after.
291 	 */
292 	@Deprecated
293 	public static double decOldToNmea(double degrees) {
294 		int deg = (int)degrees;
295 		degrees = (degrees - deg) * 60;
296 		
297 		int min = (int)degrees;
298 		degrees = degrees - min;
299 		
300 		double sec = degrees * 60;
301 
302 		return  Utils.round((deg * 100) + min + (sec / 100), 4);
303 	}
304 
305 	/***
306 	 * Converts degrees in NMEA sexagesimal format to decimal format. 
307 	 * 
308 	 * @param degrees in NMEA sexagesimal format with degrees and minutes in
309 	 * 			front of the decimal separator and seconds after
310 	 * @return degrees in decimal format
311 	 */
312 	public static double nmeaToDec(double degrees) {
313 		// Split up the value into sexagesimal format.
314 		degrees = degrees / 100;		
315 		int deg = (int)degrees;
316 		degrees = degrees - deg;
317 	
318 		degrees = degrees * 100;
319 		int min = (int)degrees;
320 		degrees = degrees - min;
321 	
322 		double sec = degrees * 60;
323 	
324 		return sexToDec(deg, min, sec);
325 	}
326 
327 	/***
328 	 * Converts degrees in NMEA sexagesimal format to decimal format. 
329 	 * 
330 	 * @deprecated Replaced by {@link #nmeaToDec(double)} to correct a
331 	 * 		calculation error.
332 	 * @param degrees in NMEA sexagesimal format with degrees and minutes in
333 	 * 		front of the decimal separator and seconds after
334 	 * @return degrees in decimal format
335 	 */
336 	@Deprecated
337 	public static double nmeaOldToDec(double degrees) {
338 		// Split up the value into sexagesimal format.
339 		degrees = degrees / 100;		
340 		int deg = (int)degrees;
341 		degrees = degrees - deg;
342 	
343 		degrees = degrees * 100;
344 		int min = (int)degrees;
345 		degrees = degrees - min;
346 	
347 		double sec = degrees * 100;
348 	
349 		return sexToDec(deg, min, sec);
350 	}
351 
352 	/***
353 	 * Returns the Haversine distance from this to another coordinate.
354 	 * 
355 	 * @param coord destination coordinate
356 	 * @return Haversine distance
357 	 * @see #haversineDist(double, double, double, double)
358 	 */
359 	public double haversineDist(final Coordinate coord) {
360 		return haversineDist(this, coord);
361 	}
362 
363 	/***
364 	 * Returns the Haversine distance between two points.
365 	 * 
366 	 * @param coord1 first coordinate
367 	 * @param coord2 secound coordinate
368 	 * @return Haversine distance between two points
369 	 * @see #haversineDist(double, double, double, double)
370 	 */
371 	public static double haversineDist(final Coordinate coord1,
372 			final Coordinate coord2) {
373 		return haversineDist(coord1.getY(), coord1.getX(),
374 				coord2.getY(), coord2.getX());
375 	}
376 	
377 	/***
378 	 * Returns the Haversine distance between two points. See
379 	 * <a href="http://en.wikipedia.org/wiki/Haversine_formula">Wikipedia</a> or
380 	 * <a href="http://www.movable-type.co.uk/scripts/GIS-FAQ-5.1.html">
381 	 * GIS-FAQ</a> for more in-depth information on the formula.
382 	 * 
383 	 * @param lat1 latitude of first coordinate
384 	 * @param lon1 longitude of first coordinate
385 	 * @param lat2 latitude of second coordinate
386 	 * @param lon2 longitude of second coordinate
387 	 * @return Haversine distance between the two coordinates
388 	 */
389 	public static double haversineDist(final double lat1, final double lon1,
390 			final double lat2, final double lon2) {
391 		final double la1 = toRadians(lat1);
392 		final double la2 = toRadians(lat2);
393 		final double lo1 = toRadians(lon1);
394 		final double lo2 = toRadians(lon2);
395 		
396 		final double dLat = la2 - la1;
397 		final double dLong = lo2 - lo1;
398 
399 		final double a = sin(dLat / 2) * sin(dLat / 2)
400 				+ cos(la1) * cos(la2) * sin(dLong / 2) * sin(dLong / 2);
401 
402 		return (2 * atan2(sqrt(a), sqrt(1 - a)) * EARTH_RADIUS);
403 	}
404 	
405 	/***
406 	 * Returns the sequential Haverside distance between the coordinates. The
407 	 * method takes the distance between each consecutive coordinate and adds it
408 	 * together. Because of the sequencing of calculations, the order of the
409 	 * coordinates in the list determines the total distance.
410 	 * 
411 	 * @param coords list of coordinates used for distance calculation
412 	 * @return total distance between all coordinates
413 	 * @see #haversineDist(double, double, double, double)
414 	 */
415 	public static double haversineDist(final List<Coordinate> coords) {
416 		double dist = 0;
417 		
418 		Iterator<Coordinate> iter = coords.iterator();
419 		Coordinate coord, lastCoord;
420 		
421 		if (iter.hasNext()) {
422 			coord = iter.next();
423 		} else {
424 			return 0;
425 		}
426 		
427 		while (iter.hasNext()) {
428 			lastCoord = coord;
429 			coord = iter.next();
430 			dist += lastCoord.haversineDist(coord); 
431 			
432 //			dist += coord.haversineDist(coord = iter.next());
433 		}
434 		
435 		return dist;
436 	}
437 	
438 	/***
439 	 * Returns the distance between two points according to the law of cosines.
440 	 * Use of this method of distance calculation is HIGHLY DISCOURAGED as it is
441 	 * unreliable for small distances because the inverse cosine is
442 	 * ill-conditioned. 
443 	 * 
444 	 * @param coord1 first coordinate
445 	 * @param coord2 secound coordinate
446 	 * @return cosine distance between two points
447 	 */
448 	public static double cosineDist(final Coordinate coord1,
449 			final Coordinate coord2) {
450 		final double la1 = toRadians(coord1.getY());
451 		final double la2 = toRadians(coord2.getY());
452 		final double lo1 = toRadians(coord1.getX());
453 		final double lo2 = toRadians(coord2.getX());
454 			  
455 		return (acos(sin(la1) * sin(la2)
456 				+ cos(la1) * cos(la2) * cos(lo2 - lo1)) * EARTH_RADIUS);
457 	}
458 	
459 	/***
460 	 * Converts from lat/lon to a UTMpoint containting northing and easting plus
461 	 * zone with zone letter
462 	 * 
463 	 * @param ellipsoidId ellipsoid to use (i.e. WGS84 = 22)
464 	 * @param lat points latitude
465 	 * @param lon points longitude
466 	 * @return UTMPoint with northing/easting + zone and zone letter
467 	 */
468 	public static UTMPoint llToUTM(final int ellipsoidId, final double lat,
469 			final double lon) {
470 		final Ellipsoid ellipsoid = ReferenceEllipsoids
471 				.getEllipsoid(ellipsoidId);
472 		
473 		final double const1 = 0.017453292519943295;
474 		final double const2 = 0.99960000000000004; 
475 		
476 		// Getting the values from the reference ellipsoid
477 		final double radius = ellipsoid.getRadius();
478 		final double eccsq = ellipsoid.getEccentricity();
479 
480 		final double eccsq2 = eccsq * eccsq;	// Created for a "nicer" formula
481 		final double eccsq3 = eccsq2 * eccsq; // Created for a "nicer" formula
482 		
483 		final double d12 = (lon + 180) - ((int)((lon + 180) / 360) * 360) - 180;
484 		final double d13 = lat * const1;
485 		
486 		final int zoneNumber = decideZoneNum(d12, lat);
487 		
488 		final double d5 = ((zoneNumber - 1) * 6 - 180) + 3; // False easting?
489 
490 		final double d14 = d12 * const1;
491 		final double d15 = d5 * const1;
492 		
493 		final double d6 = eccsq / (1 - eccsq);
494 		final double d7 = radius / sqrt(1 - eccsq * sin(d13) * sin(d13));
495 		final double d8 = tan(d13) * tan(d13);
496 		final double d9 = d6 * cos(d13) * cos(d13);
497 		final double d10 = cos(d13) * (d14 - d15);
498 		final double d11 = radius
499 				* ((((1 - eccsq / 4 - (3 * eccsq2) / 64 - (5 * eccsq3) / 256)
500 				* d13 - ((3 * eccsq) / 8 + (3 * eccsq2) / 32
501 				+ (45 * eccsq3) / 1024) * sin(2 * d13))
502 				+ ((15 * eccsq2) / 256 + (45 * eccsq3) / 1024) * sin(4 * d13))
503 				- ((35 * eccsq3) / 3072) * sin(6 * d13));
504 		final double easting = (const2 * d7 * (d10
505 				+ (((1 - d8) + d9) * pow(d10, 3)) / 6
506 				+ ((((5 - 18 * d8) + d8 * d8 + 72 * d9) - 58 * d6)
507 				* pow(d10, 5)) / 120) + 500000);
508 		double northing = (const2 * (d11 + d7 * tan(d13) * ((d10 * d10) / 2
509 				+ (((5 - d8) + 9 * d9 + 4 * d9 * d9) * pow(d10, 4)) / 24
510 				+ ((((3 * d8) + d8 * d8 + 600 * d9) - 330 * d6)
511 				* pow(d10, 6)) / 720)));
512 		
513 		if (lat < 0) {
514 			northing += 1E+007;
515 		}
516 		return new UTMPoint(northing, easting, zoneNumber,
517 				getUTMZoneLetter(lat));
518 	}
519 
520 	/*** 
521 	 * Finds the given zone's letter (most of Norway is 32<b>V</b>)
522 	 * 
523 	 * @param latitude decide zone letter from this value
524 	 * @return zone letter.
525 	 */
526 	private static char getUTMZoneLetter(final double latitude) {
527 		char zoneLetter = 'Z';
528 		if (84 >= latitude && latitude >= 72) {
529 			zoneLetter = 'X';
530 		} else if (72 > latitude && latitude >= 64) {
531 			zoneLetter = 'W';
532 		} else if (64 > latitude && latitude >= 56) {
533 			zoneLetter = 'V';
534 		} else if (56 > latitude && latitude >= 48) {
535 			zoneLetter = 'U';
536 		} else if (48 > latitude && latitude >= 40) {
537 			zoneLetter = 'T';
538 		} else if (40 > latitude && latitude >= 32) {
539 			zoneLetter = 'S';
540 		} else if (32 > latitude && latitude >= 24) {
541 			zoneLetter = 'R';
542 		} else if (24 > latitude && latitude >= 16) {
543 			zoneLetter = 'Q';
544 		} else if (16 > latitude && latitude >= 8) {
545 			zoneLetter = 'P';
546 		} else if (8 > latitude && latitude >= 0) {
547 			zoneLetter = 'N';
548 		} else if (0 > latitude && latitude >= -8) {
549 			zoneLetter = 'M';
550 		} else if (-8 > latitude && latitude >= -16) {
551 			zoneLetter = 'L';
552 		} else if (-16 > latitude && latitude >= -24) {
553 			zoneLetter = 'K';
554 		} else if (-24 > latitude && latitude >= -32) {
555 			zoneLetter = 'J';
556 		} else if (-32 > latitude && latitude >= -40) {
557 			zoneLetter = 'H';
558 		} else if (-40 > latitude && latitude >= -48) {
559 			zoneLetter = 'G';
560 		} else if (-48 > latitude && latitude >= -56) {
561 			zoneLetter = 'F';
562 		} else if (-56 > latitude && latitude >= -64) {
563 			zoneLetter = 'E';
564 		} else if (-64 > latitude && latitude >= -72) {
565 			zoneLetter = 'D';
566 		} else if (-72 > latitude && latitude >= -80) {
567 			zoneLetter = 'C';
568 		}
569 		
570 		return zoneLetter;
571 	}
572 	
573 	
574 	public static Coordinate utmToLl(final int i, final UTMPoint utmpoint) {
575 		return utmToLl(i, utmpoint.getNorthing(), utmpoint.getEasting(),
576 				utmpoint.getZoneNumber(), utmpoint.getZoneLetter());
577 	}
578 
579 	public static Coordinate utmToLl(final int ellipsoidId,
580 			final double northing, final double easting, final int zoneNum,
581 			final char zoneLetter) {
582 		final double const1 = 57.295779513082323;
583 		final double const2 = 0.99960000000000004;
584 		
585 		if (zoneNum < 0 || zoneNum > 60) {
586 			return null;
587 		}
588 		
589 		Ellipsoid ellipsoid = ReferenceEllipsoids.getEllipsoid(ellipsoidId);
590 		
591 		final double radius = ellipsoid.getRadius();
592 		final double eccsq = ellipsoid.getEccentricity();
593 		final double d4 = (1 - sqrt(1 - eccsq)) / (1 + sqrt(1 - eccsq));
594 		
595 		final double d4pow3 = pow(d4, 3);
596 		
597 		double east = easting - 500000;
598 		double north = northing;
599 //		final boolean flag;
600 		
601 		if (zoneLetter >= 'N') {
602 //			flag = true;
603 		} else {
604 //			flag = false;
605 			north -= 10000000;
606 		}
607 		
608 		final double d11 = ((zoneNum - 1) * 6 - 180) + 3;
609 		final double d3 = eccsq / (1 - eccsq);
610 		final double d10 = north / const2;
611 		final double d12 = d10 / (radius * (1 - eccsq / 4 - (3 * pow(eccsq, 2))
612 				/ 64 - (5 * pow(eccsq, 3)) / 256));
613 		final double d14 = d12 + ((3 * d4) / 2 - (27 * d4pow3) / 32)
614 				* sin(2 * d12) + ((21 * d4 * d4) / 16
615 				- (55 * d4 * d4 * d4 * d4) / 32)
616 				* sin(4 * d12) + ((151 * d4pow3) / 96) * sin(6 * d12);
617 //		final double d13 = d14 * const1;
618 		final double d5 = radius / sqrt(1 - eccsq * sin(d14) * sin(d14));
619 		final double d6 = tan(d14) * tan(d14);
620 		final double d7 = d3 * cos(d14) * cos(d14);
621 		final double d8 = (radius * (1 - eccsq)) / pow(1 - eccsq * sin(d14)
622 				* sin(d14), 1.5);
623 		final double d9 = east / (d5 * const2);
624 		
625 		double d17 = d14 - ((d5 * tan(d14)) / d8) * (((d9 * d9) / 2
626 				- (((5 + 3 * d6 + 10 * d7) - 4 * d7 * d7 - 9 * d3)
627 				* pow(d9, 4)) / 24)
628 				+ (((61 + 90 * d6 + 298 * d7 + 45 * d6 * d6)
629 				- 252 * d3 - 3 * d7 * d7) * pow(d9, 6)) / 720);
630 		d17 *= const1;
631 		
632 		double d18 = ((d9 - ((1 + 2 * d6 + d7) * pow(d9, 3)) / 6)
633 				+ (((((5 - 2 * d7) + 28 * d6) - 3 * d7 * d7)
634 				+ 8 * d3 + 24 * d6 * d6) * pow(d9, 5)) / 120) / cos(d14);
635 		d18 = d11 + d18 * const1;
636 		
637 		System.out.println("(TMP) lat " + d17 + ", lon: " + d18);
638 		
639 //		d17 = Coordinate.decToSexD(d17);
640 //		d18 = Coordinate.decToSexD(d18);
641 		
642 		return new Coordinate(d17, d18);
643 	}
644 	
645 	/***
646 	 * Decides a UTM Zone Number for a given latitude and result.
647 	 * 
648 	 * @param result result
649 	 * @param latitude latitude
650 	 * @return the zonenumber
651 	 */
652 	public static int decideZoneNum(final double result,
653 			final double latitude) {
654 		
655 		// Decides zone number
656 		int zoneNumber = (int)((result + 180) / 6) + 1;
657 		
658 		if (latitude >= 56 && latitude < 64 && result >= 3 && result < 12) {
659 			zoneNumber = 32;
660 		}
661 		
662 		if (latitude >= 72 && latitude < 84) {
663 			if (result >= 0 && result < 9) {
664 				zoneNumber = 31;
665 			} else if (result >= 9 && result < 21) {
666 				zoneNumber = 33;
667 			} else if (result >= 21 && result < 33) {
668 				zoneNumber = 35;
669 			} else if (result >= 33 && result < 42) {
670 				zoneNumber = 37;
671 			}
672 		}
673 		return zoneNumber;
674 	}
675 
676 	/*** Returns id of coordinate */
677 	public int getCoordId() {
678 		return coordId;
679 	}
680 
681 	/*** Returns date of coordinate */
682 	public Date getDate() {
683 		return date;
684 	}
685 }
686