Back when I was developing ship handling 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”