C++ functions to convert between decimal degrees and degrees, minutes, and seconds

Back when I was developing shiphandling simulator software, I ran into situations where it was necessary to convert decimal degrees to degrees, minutes, and seconds (for example, nautical types like to express latitude/longitude using degrees, minutes, and seconds while computers prefer decimal degrees).

Here's some C++ functions which handle the conversion between these two formats:


std::string DMS::DegreesMinutesSeconds(double ang,
                                       unsigned int num_dec_places = 2)
std::string DMS::DegreesMinutesSecondsLat(double ang,
                                          unsigned int num_dec_places = 2)
std::string DMS::DegreesMinutesSecondsLon(double ang,
                                          unsigned int num_dec_places = 2)

double DMS::DecimalDegrees(const std::string& dms)

These are inline functions defined in the header file, dms.h:

--- start ---

//==================================================================
/**
 *  dms.h -- C++ functions to convert between decimal degrees
 *           and degrees, minutes, and seconds
 *
 *  Copyright (C) 2005-2008 by James A. Chappell
 *
 *  Permission is hereby granted, free of charge, to any person
 *  obtaining a copy of this software and associated documentation
 *  files (the "Software"), to deal in the Software without
 *  restriction, including without limitation the rights to use,
 *  copy, modify, merge, publish, distribute, sublicense, and/or
 *  sell copies of the Software, and to permit persons to whom the
 *  Software is furnished to do so, subject to the following
 *  conditions:
 *
 *  The above copyright notice and this permission notice shall be
 *  included in all copies or substantial portions of the Software.
 *
 *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 *  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
 *  OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 *  NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
 *  HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 *  WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 *  FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
 *  OTHER DEALINGS IN THE SOFTWARE.
 */
//=================================================================
/*
 * dms.h:  Version 0.02
 * Created by James A. Chappell
 * Created 23 August 2005
 *
 * History:
 * 23-aug-2005  created
 * 25-apr-2008  added latitude/longitude conversions
 * 
 */
//=================================================================

#ifndef __DMS_H__
#define __DMS_H__

#include <sstream>
#include <math.h> // for nearbyint()

namespace DMS
{
  static const char DEG_SIM = 176 ;

//
//  Convert decimal degrees to degrees, minutes and seconds
// 
  inline std::string DegreesMinutesSeconds(double ang,
                                           unsigned int num_dec_places = 2)
  {
    bool neg(false) ;
    if (ang < 0.0)
    {
      neg = true ;
      ang = -ang ;
    }
  
    int deg = (int)ang ;
    double frac = ang - (double)deg ;

    frac *= 60.0 ;

    int min = (int)frac ;

    frac = frac - (double)min ;

    // fix the DDD MM 60 case
    // TODO: nearbyint isn’t alway available (Visual C++,
    //       for example)
    double sec = nearbyint(frac * 600000.0) ;
    sec /= 10000.0 ;

    if (sec >= 60.0)
    {
      min++ ;
      sec -= 60.0 ;
    }

    std::ostringstream oss ;

    if (neg)
    {
      oss << "-" ;
    }

//  TODO: allow user to define delimiters separating
//        degrees, minutes, and seconds.
    oss.setf(std::ios::fixed, std::ios::floatfield);

    oss << deg  
        << DEG_SIM ;
    oss.fill('0') ;
    oss.width(2) ;
    oss << min
        << "\'" ;
    if (num_dec_places == 0)
    {
      oss.width(2) ;
      oss.precision(0) ;
    }
    else
    {
      oss.width(num_dec_places + 3) ;
      oss.precision(num_dec_places) ;
    }
    oss << sec 
        << "\"" ;

    return oss.str() ;
  }


  inline std::string DegreesMinutesSecondsLat(double ang,
                        unsigned int num_dec_places = 2)
  {
    std::string lat(DegreesMinutesSeconds(ang, num_dec_places)) ;
  
    if (lat[0] == '-')
    {
      lat += std::string(" S") ;
      lat.erase(0, 1) ;
    }
    else
    {
      lat += std::string(" N") ;
    }

    lat = std::string(" ") + lat ;

    return lat ;
  }


  inline std::string DegreesMinutesSecondsLon(double ang,
                        unsigned int num_dec_places = 2)
  {
    std::string lon(DegreesMinutesSeconds(ang, num_dec_places)) ;

    if (lon[0] == '-')
    {
      lon += std::string(" W") ;
      lon.erase(0, 1) ;
    }
    else
    {
      lon += std::string(" E") ;
    }

    if (fabs(ang) < 100.0)
    {
      lon = std::string("0") + lon ;
    }

    return lon ;
  }


//
// Convert degrees, minutes and seconds to decimal degrees.
// 
  inline double DecimalDegrees(const std::string& dms)
  {
    std::string tmp(dms) ;

    // need to handle the -0 MM SS case
    // TODO: handle leading spaces before potential minus sign
    bool neg(false) ;

    if ((tmp[tmp.length() - 1] == 'W') || (tmp[tmp.length() - 1] == 'S') ||
        (tmp[0] == '-'))
    {
      neg = true ;
    }

    for (unsigned int i = 0 ; i < tmp.length() ; i++)
    {
      if (!isdigit(tmp[i]) && (tmp[i] != '.'))
      {
        tmp[i] = ' ' ;
      }
    }

    double deg(0.0), min(0.0), sec(0.0) ;
//  TODO: handle other delimiters
    std::istringstream iss(tmp) ;
    iss >> deg >> min >> sec ;

    double ang = deg + ((min + (sec / 60.0)) / 60.0) ;

    if (neg)
    {
      ang = -ang ;
    }

    return ang ;
  }
} ;

#endif

--- end ---

Here's a sample program using the functions in dms.h:

--- start ---

#include <iostream>
#include "dms.h"

using namespace std;
using namespace DMS;

int main()
{
    double ang ;
    
    cout << "Enter angle (decimal degrees): " ;
    cin >> ang ;
    
    string dms ;

    dms = DegreesMinutesSeconds(ang) ;

    cout << dms << endl ;

    ang = DecimalDegrees(dms) ;

    cout << ang << endl ;

    return 0 ;
}

--- end ---

At some point these functions may be incorporated into a class encapsulating angular measure.

UPDATE: 2014-10-01:
This project can now be found on GitHub:
- decimal-degrees-and-degrees-minutes-and-seconds
- HTTPS Clone URL: https://github.com/jachappell/decimal-degrees-and-degrees-minutes-and-seconds.git
- Download ZIP

2 thoughts on “C++ functions to convert between decimal degrees and degrees, minutes, and seconds”

  1. Pingback: dms.h

Leave a Reply

Your email address will not be published.

This site uses Akismet to reduce spam. Learn how your comment data is processed.