# DMS To Decimal Degree Conversions And More

Working with satellite data I often have to convert a coordinate value or an
angle value from the DMS notation (*degree@minute’second"*) to a decimal
degree in the floating point number format and vice versa.

## DMS to Decimal Degree

Of course, I want to do this directly in an Emacs buffer, so I wrote a
simple function that uses `deg`

and `hms`

functions provided by the
built-in superb **calc** package.

```
(defun dms2deg (p1 p2)
"Converts a region from the DMS (dd@mm'ss\")
to a decimal degree.
P1,P2 are the beginning and the end of the region
(selection) respectively."
(interactive "r")
(let (s)
(if (region-active-p)
(progn
(setq s (calc-eval
(concat "deg(" (buffer-substring-no-properties p1 p2) ")")))
(delete-active-region)
(insert s))
(message "No active region!"))
)
)
```

I’ve bound this function to the `Ctrl+F6`

key chord (`C-f6`

in the Emacs
notation) globally. Of course, you can use your own key combination.

```
(global-set-key [(control f6)] #'dms2deg)
```

Now I can select a region in a buffer, press `C-f6`

and *replace* the
selection with its decimal value, so `30@15'54"`

becomes `30.265`

.

## Decimal Degree to DMS

The inverse function (bound to `S-f6`

or `Shift+F6`

) *replaces* a floating
point with the corresponding DMS string.

```
(defun deg2dms (p1 p2)
"Converts a region from a decimal degree
to the DMS format (dd@ mm' ss\").
P1,P2 - beginning and end of the region
(selection) respectively."
(interactive "r")
(let (s)
(if (region-active-p)
(progn
(setq s (calc-eval
(concat "hms(" (buffer-substring-no-properties p1 p2) ")")))
(delete-active-region)
(insert s))
(message "No active region!"))
)
)
(global-set-key [(shift f6)] #'deg2dms)
```

Now if you select a region in a buffer and then press `S-f6`

, your `30.265`

becomes `30@ 15' 54."`

## Enhanced Version

After a while, I decided to enhance the first conversion function by
adding an *‘inline calculator’* feature. It works quite simple: if a
selected region contains the ‘@’ character, the region is considered
as a coordinate (angle) value in the DMS notation, and it should be *replaced*
with its decimal value. Otherwise, the region is considered as an
arithmetic expression (in terms of the Emacs’ calc) and its calculated
value will be *inserted* just after the region.

```
(defun avs/calc-region (p1 p2)
"Calculates a region or converts DMS to decimal.
P1,P2 - beginning and end of the region
respectively."
(interactive "r")
(if (region-active-p)
(let ((b (buffer-substring-no-properties p1 p2)))
(cond ((string-match-p "@" b) ; convert DMS to decimal ...
(delete-active-region)
(insert (calc-eval (concat "deg(" b ")"))))
(t ; ... otherwise calculate a region
(goto-char (region-end))
(pop-mark)
(insert " = " (calc-eval b))))
)
(message "No active region!"))
)
(global-set-key [(f6)] 'avs/calc-region)
```

The enhanced function is bound to `f6`

. So now if you press `F6`

,
`15@45'20"`

becomes `15.7555555556`

, and `((350.0 / 7) + 48.314)`

becomes `((350.0 / 7) + 48.314) = 98.314`

.

## Conclusion

Emacs’ **calc** is great.

## Next

As a next step, I want to implement DMS and Decimal degree conversions to the DD:MM:SS format used by the excellent Generic Mapping Tools (GMT) toolbox.