Saturday, 5 April 2014

Converting Latitude and Longitude from Decimal Degree to NMEA format and Vice-Versa

Hi Friends,

Introduction - Different formats for representing Latitude and Longitude 
There are three different formats of representing a latitude and longitude value.


Degrees, Minutes and Seconds

DDD° MM' SS.S"
32° 18' 23.1" N 122° 36' 52.5" W

There are sixty seconds in a minute (60" = 1') and
There are sixty minutes in a degree (60' = 1°).


Keeping in mind a few easy conversions between seconds and decimal minutes will help when working with maps that use degrees, minutes and seconds.

15 seconds is one quarter of a minute or 0.25 minutes
30 seconds is one half of a minute or 0.5 minutes
45 seconds is three quarters of a minute or 0.75 minutes


Degrees and Decimal Minutes
DDD° MM.MMM'
32° 18.385' N 122° 36.875' W

This is the format most commonly used when working with electronic navigation equipment and hence also called NMEA (National Marine Electronics Association) format. 

Decimal Degrees
DDD.DDDDD°
32.30642° N 122.61458° W
or +32.30642, -122.61458

This is the format you'll find most computer based mapping systems displaying. The coordinates are stored internally in a floating point data type, and no additional work is required to print them as a floating point number.

Often the N-S and E-W designators are omitted. Positive values of latitude are north of the equator, negative values to the south. Watch the sign on the longitude, most programs use negative values for west longitude, but a few are opposite. This saves a lazy western hemisphere programmer from having to type in a minus sign before most of their longitude values.

Main Topic of Discussion
Supposing the format you have is "decimal degrees" and you want to convert it to Degrees and decimal minutes, and then use the format DDDMM.mmmmm where "DDD" is the number of degrees, MM is the integer part of number of minutes, and "mmmmm" the fractional part of minutes or vice-versa in Java. 

Brief Explanation on what-and-how
Suppose your latitude and longitude in decimal degree is -56.529176 and -33.386666 respectively. 

For latitude you have 56 degrees. Then simply multiply the fractional part with 60 to get the minutes. 60 * 0.529176 = 31.75057. This means the NMEA format will be 5631.75057

And since the Latitude is negative it is the southern hemisphere - 5631.75057,S
A positive number would be the northern hemisphere "N"

For longitude you have 33 degrees. Then simply multiply the fractional part with 60 to get the minutes. 60 * 0.386666 = 23.19997. This means the NMEA format will be 3323.19997

And since the Longitude is negative it is the western hemisphere - 3323.19997,W
A positive decimal degree would be the eastern hemisphere "E". 

So if in-case you want to build function that does the conversions for you, the below functions should come in handy. 

NMEA to Decimal Converter
 public double[] NMEAToDecimalConverter(double lat, double lng) {  
          
           String latDegreeString = null, latMinutesString = null, nmeaLatString = null;  
           double latDegree = 0, latMinutes = 0, nmeaLat = 0, absLat = 0;  
           
           String lngDegreeString = null, lngMinutesString = null, nmeaLngString = null;  
           double lngDegree = 0, lngMinutes = 0, nmeaLng = 0, absLng = 0;  
          
           Log.i("NMEA to Decimal", "Recieved Latitude: " + lat + " Longitude: "  + lng);  
           
           if (lat < 0) {  
                absLat = lat * -1;  
           } else {  
                absLat = lat;  
           }  
           
           Double d = absLat;  
           String[] latSplitter = d.toString().split("\\.");  
           
           if (latSplitter[0].length() <= 4) {  
                latDegreeString = latSplitter[0].substring(0, 2);  
                latMinutesString = d.toString().substring(2, d.toString().length());  
           } else if (latSplitter[0].length() > 4) {  
                latDegreeString = latSplitter[0].substring(0, 3);  
                latMinutesString = d.toString().substring(3, d.toString().length());  
           }  
           
           latDegree = Integer.parseInt(latDegreeString);  
           latMinutes = (Double.parseDouble(latMinutesString) / 60);  
           Log.i("NMEA to Decimal", "Degree: " + latDegree + " Minutes: "  
                     + latMinutes);  
           nmeaLat = latDegree + latMinutes;  
           nmeaLat = Math.round(nmeaLat * 10000.0) / 10000.0;  
          
           if (lat < 0) {  
                nmeaLat *= -1;  
           }  
           Log.i("NMEA to Decimal", "Decimal Value: " + nmeaLat);  
           
           // *******************************************************//  
           if (lng < 0) {  
                absLng = lng * -1;  
           } else {  
                absLng = lng;  
           }  
           
           Double dlng = absLng;  
           String[] lngSplitter = dlng.toString().split("\\.");  
           
           if (lngSplitter[0].length() <= 4) {  
                lngDegreeString = lngSplitter[0].substring(0, 2);  
                lngMinutesString = dlng.toString().substring(2, dlng.toString().length());  
           } else if (latSplitter[0].length() > 4) {  
                lngDegreeString = lngSplitter[0].substring(0, 3);  
                lngMinutesString = dlng.toString().substring(3, dlng.toString().length());  
           }  
          
           lngDegree = Integer.parseInt(lngDegreeString);  
           lngMinutes = (Double.parseDouble(lngMinutesString) / 60);  
           Log.i("NMEA to Decimal", "Degree: " + lngDegree + " Minutes: "  
                     + lngMinutes);  
           nmeaLng = lngDegree + lngMinutes;  
           nmeaLng = Math.round(nmeaLng * 10000.0) / 10000.0;  
           
           if (lng < 0) {  
                nmeaLng *= -1;  
           }  
           Log.i("NMEA to Decimal", "NMEA Longitude: " + nmeaLat + " Longitude: "  
                     + nmeaLng);  
           return (new double[] { nmeaLat, nmeaLng });  
      }  
Decimal to NMEA Converted
 public double[] DecimalToNMEAConverter(double lat, double lng) {  
                String dcmLatString = null;  
                int latDegree = 0;  
                double latMinutes = 0, dcmLat = 0, absLat = 0;  
                
                String dcmLngString = null;  
                int lngDegree = 0;  
                double lngMinutes = 0, dcmLng = 0, absLng = 0;  
                
                Log.i("Decimal to NMEA", "Decimal To NMEA: " + lat + " Longitude: "  + lng);  
                if (lat < 0) {  
                     absLat = lat * -1;  
                } else {  
                     absLat = lat;  
                }  
                
                latDegree = (int) absLat;  
                latMinutes = (absLat - latDegree) * 60;  
                dcmLatString = String.valueOf(latDegree)  
                          + String.valueOf(latMinutes);  
                dcmLat = Double.parseDouble(dcmLatString);  
                dcmLat = Math.round(dcmLat * 10000.0) / 10000.0;  
               
                if (lat < 0) {  
                     dcmLat *= -1;  
                }  
                // ************************************************//  
                if (lng < 0) {  
                     absLng = lng * -1;  
                } else {  
                     absLng = lng;  
                }  
                
                lngDegree = (int) absLng;  
                lngMinutes = (absLng - lngDegree) * 60;  
                dcmLngString = String.valueOf(lngDegree)  
                          + String.valueOf(lngMinutes);  
                dcmLng = Double.parseDouble(dcmLngString);  
                dcmLng = Math.round(dcmLng * 10000.0) / 10000.0;  
               
                if (lng < 0) {  
                     dcmLng *= -1;  
                }  
                Log.i("Decimal to NMEA", "NMEA Lat: " + dcmLat + " Lng: " + dcmLng);  
                return (new double[] { dcmLat, dcmLng });  
           }