Updated 2011-07-04 22:14:28 by RLE

There are several ways to represent longitude and latitude. The most common ones are:

  • Degree, minutes, seconds
  • Degree, decimal minutes
  • Decimal degrees.

Most web-based map services such as for example MapQuest [1] seem to be using decimal degrees. The following routine converts all these formats to the (D)DDMMSS.SSS format instead. I EF uses this to store positions in a database at regular intervals. I felt that the format was best for storage as a float.
 # Command Name     --  convert
 # Original Author  --  Emmanuel Frecon - emmanuel@sics.se
 #
 # This command converts a longitude or latitude expressed in one of
 # the ISO 6709:1983 formats into a (D)DDMMSS.SS string.  It generates
 # error if the string does not comply to the standard.
 #
 # Arguments:
 #    ll        - Longitude or latitude.
 proc convert { ll } { 
     # see
     # http://ioc.unesco.org/oceanteacher/OceanTeacher2/06_OcDtaMgtProc/01_DataOps/06_OcDtaForm/01_OcDtaFormFunda/02_Geography/01_Locations/ISOLatLonStd.htm
     # and http://maps2.nris.state.mt.us/topofinder1/LatLong.asp for
     # more practical explanations.
 
     if { [regexp {(\+|-)?\d+:\d+:\d+(\.\d+)?} $ll] } {
        # (D)DD:MM:SS.SSSSSSSS
        set l [split $ll ":"]
        set deg [lindex $l 0]
        set min [lindex $l 1]
        set sec [lindex $l 2]
     } elseif { [regexp {(\+|-)?\d+\.\d+} $ll] } {
        set li [expr int($ll)]
        set ld [expr $ll - $li]
        set len [string length [expr abs($li)]]
        if { $len >= 1 && $len <= 3 } {
            # (D)DD.DDD
            set deg $li
            set dmin [expr $ld * 60]
            set min [expr int($dmin)]
            set sec [expr ($dmin - $min) * 60]
        } elseif { $len >= 4 && $len <= 5 } {
            # (D)DDMM.MMMM
            set deg [string range $li 0 end-2]
            set min [string range $li end-1 end]
            set sec [expr $ld * 60]
        } elseif { $len >= 6 && $len <= 7 } {
            # (D)DDMMSS.SSSS
            set sec [string range $li end-1 end]
            set sec [expr $sec + $ld]
            set min [string range $li end-3 end-2]
            set deg [string range $li 0 end-4]
        } else {
            return -code error "$ll is not in ISO 6709:1983 format!"
        }
     } else {
        return -code error "$ll is not a recognised ISO longitude/latitude"
     }
 
     if { [string length $deg] == 1 } {
        set deg "0${deg}"
     }
     if { [string length $min] == 1 } {
        set min "0${min}"
     }
     if { [string length [expr int($sec)]] == 1 } {
        set sec "0${sec}"
     }
     return "${deg}${min}${sec}"
 }

AMG: This may be a little bit off topic, but I'd like a utility to calculate great circle distances between pairs of latitude/longitude coordinates. This would be quite useful here at work (COMPANY: L-3 Communications, Titan Group, except I have never heard of the Titan Group; I'm in Link Simulation & Training). I wrote such a thing in MS Excel but it only gives rough approximations.

(Later.) Ah, geodesy gives the solution. Thanks!