Decimalizing Latitude and Longitude

Xah Lee has reintroduced a challenge from last year. Given a string of latitude/longitude is degrees, minutes, seconds, write a function that returns them as signed decimal numbers. That is,

```"37°26′36.42″N 06°15′14.28″W" → (37.44345 -6.253966666666667)
```

I remember looking at this challenge last year and thinking it wasn’t very interesting but when I started thinking about it this time, I realized that there are a couple of twists that do make it interesting.

Here’s my solution in Elisp:

```(require 'cl)

(defun decimalize-lat-lon (lat-lon)
"Decimalize latitude longitude
\"37°26′36.42″N 06°15′14.28″W\" --> (37.44345 -6.253966666666667)"
(let (result)
(dolist (ll (split-string lat-lon " +"))
(destructuring-bind (deg min sec dir)
(split-string ll "[°′″]")
(if (string= "" dir) (error "malformed lat-lon %s" ll))
(let ((factor (if (member dir '("S" "W")) -1 1)))
(push (* factor (+ (string-to-number deg)
(/ (string-to-number min) 60.0)
(/ (string-to-number sec) 3600.0))) result))))
(reverse result)))
```

Elisp purists might complain about my using `dolist`, `destructuring-bind`, and `push` from the Common Lisp package but they’re convenient and don’t do anything that can’t be done a bit more verbosely in pure Emacs Lisp. The real workhorse in this function is the Elisp `split-string` function. It gets used twice: once to split the original string into latitude and longitude and once to break the latitude and longitude into their constituent parts.

The check on whether `dir` is the empty string really checks for any missing constituents and is just a sanity check. I didn’t bother rounding the numbers to any particular number of decimal places or making the function a command. Either of those are easily done if the user needs them.

Update: Mickey over at Mastering Emacs and Aaron Hawley in the comments give nice solutions using Emacs `calc`. Mickey’s post shows off some of the great features of `calc` so be sure to take a look.

This entry was posted in Programming and tagged , . Bookmark the permalink.

2 Responses to Decimalizing Latitude and Longitude

1. Sam says:

I love your blog, and sometimes I wish i could study your code right away. Would you consider for the future to use paste.lisp.org to share your code?
As an example, I pasted your code here: http://paste.lisp.org/display/129145

I like the syntax highlighting, end especially the paren highlighting.
In case it was not proper for me to do that, I apologize in advance.

2. Aaron Hawley says:

Hi, I’m the Emacs Lisp purist and I’m here to say that you didn’t even use `dolist` from the CL package correctly. I don’t know how we got to this point where *I* am making such corrections. Glad to see the `require 'cl`, though.

I’m really here to suggest the Calc alternative.

`C-x * * [37@26'36.6",_6@15'14.28"] m d V M c d`

This turns on Calculator Mode, enters a vector of the two values, puts Calc in degrees mode, then maps the degree conversion operation over the vector. To go from decimal back to minutes and seconds,

`V M c h`