Skip to content

Commit

Permalink
Implement the coordinates conversion to string.
Browse files Browse the repository at this point in the history
  • Loading branch information
vahancho committed Feb 6, 2024
1 parent 6ca2dad commit 8bc330e
Show file tree
Hide file tree
Showing 3 changed files with 228 additions and 0 deletions.
10 changes: 10 additions & 0 deletions include/coordinate.h
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,9 @@ class ERKIR_EXPORT Coordinate
//! Constructs a coordinate by the given decimal degrees.
Coordinate(double degrees);

/// Returns string representation of the coordinate in the specified \p format.
virtual std::string toString(Format format, int precision) const = 0;

//! Returns this coordinate's value in decimal degrees.
double degrees() const;

Expand All @@ -64,6 +67,9 @@ class ERKIR_EXPORT Coordinate
/// Constrain degrees to range 0..360.0 (e.g. for bearings); -1 => 359, 361 => 1.
static double wrap360(double degrees);

protected:
std::string toBaseString(Format format, int precision) const;

private:
double m_degrees;
};
Expand All @@ -80,6 +86,8 @@ class ERKIR_EXPORT Latitude : public Coordinate
*/
Latitude(double degree);

std::string toString(Format format, int precision = 2) const override;

/// Returns the latitude from the human readable coordinates (formatted).
/*!
Latitude/Longitude coordinates in three formats: Degrees Minutes Seconds (D° M' S"),
Expand Down Expand Up @@ -114,6 +122,8 @@ class ERKIR_EXPORT Longitude : public Coordinate
*/
Longitude(double degree);

std::string toString(Format format, int precision = 2) const override;

/// Returns the longitude from the human readable coordinates (formatted).
/*!
Latitude/Longitude coordinates in three formats: Degrees Minutes Seconds (D° M' S"),
Expand Down
56 changes: 56 additions & 0 deletions src/coordinate.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,11 @@

#include <cassert>
#include <codecvt>
#include <iomanip>
#include <locale>
#include <math.h>
#include <regex>
#include <sstream>
#include <stdexcept>
#include <unordered_map>

Expand Down Expand Up @@ -210,6 +212,50 @@ double Coordinate::wrap360(double degrees)
return fmod(degrees + 360.0, 360.0);
}

std::string Coordinate::toBaseString(Format format, int precision) const
{
static const std::string degreeSign{ "°"};
static const std::string minSign { "'" };
static const std::string secSign { "\"" };

double degrees{};
const auto min = std::abs(std::modf(m_degrees, &degrees)) * 60.0;

std::ostringstream ss;
ss.fill('0');

switch (format) {
case Format::DMS:
{
const auto sec = std::abs((min - int(min))) * 60.0;

ss << std::setw(2)
<< std::abs(int(degrees)) << degreeSign << ' '
<< std::setw(2)
<< int(min) << minSign << ' '
<< std::setw(2)
<< std::setprecision(precision + 2)
<< sec << secSign;
break;
}
case Format::DDM:
ss << std::setw(2)
<< std::abs(int(degrees)) << degreeSign << ' '
<< std::setw(2)
<< std::setprecision(precision + 2)
<< min << minSign;
break;
case Format::DD:
ss << std::setw(2)
<< m_degrees << degreeSign;
break;
default:
break;
}

return ss.str();
}

////////////////////////////////////////////////////////////////////////////////

Latitude::Latitude(double degree)
Expand Down Expand Up @@ -239,6 +285,11 @@ Latitude Latitude::fromString(const std::string &coord)
return { parseRx(coord, rxList, 'S')};
}

std::string Latitude::toString(Coordinate::Format format, int precision) const
{
return toBaseString(format, precision) + ' ' + (degrees() < 0 ? 'S' : 'N');
}

////////////////////////////////////////////////////////////////////////////////

Longitude::Longitude(double degree)
Expand Down Expand Up @@ -268,5 +319,10 @@ Longitude Longitude::fromString(const std::string &coord)
return { parseRx(coord, rxList, 'W')};
}

std::string Longitude::toString(Coordinate::Format format, int precision) const
{
return toBaseString(format, precision) + ' ' + (degrees() < 0 ? 'W' : 'E');
}

} // namespace erkir

162 changes: 162 additions & 0 deletions test/test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,18 @@ static bool verifyDouble(double value, double expected, const std::string &locat
return true;
}

static bool verifyString(const std::string &expected, const std::string &actual)
{
if (expected != actual) {
fprintf(stderr, "%s VALUE ERROR: expected '%s' but got '%s'\n", LOCATION.c_str(),
expected.c_str(), actual.c_str());
++s_failed;
return false;
}
++s_passed;
return true;
}

static bool verifyPoint(const Point &point, const Point &expectedPoint,
const std::string &location)
{
Expand Down Expand Up @@ -329,6 +341,156 @@ int main()
}
}

// Coordinates to string DMS
{
static const std::vector<std::pair<std::string, std::string>> lonVariants =
{
{ "45.76260" , "45° 45' 45.36\" E"},
{ "-45.76260" , "45° 45' 45.36\" W" },
{ " 45.76260 " , "45° 45' 45.36\" E"},
{ "45.76260°" , "45° 45' 45.36\" E" },
{ "45.76260° W " , "45° 45' 45.36\" W" },
{ "45 E" , "45° 00' 00\" E" },
{ ".76260" , "00° 45' 45.36\" E" },

{ "45° 46.1' " , "45° 46' 06\" E" },
{ " 45° 46.1' E " , "45° 46' 06\" E" },
{ "45°46.756′E" , "45° 46' 45.36\" E" },
{ "45° 46.756′ E" , "45° 46' 45.36\" E" },
{ "45 46.756 W" , "45° 46' 45.36\" W" },
{ "45 46 W" , "45° 45' 60\" W" },
{ "45 .756 W" , "45° 00' 45.36\" W" },
{ "45 59.9999 W" , "45° 59' 59.99\" W" },

{ "45°46′45.36″ " , "45° 46' 45.36\" E" },
{ "45°46′45.36″ E" , "45° 46' 45.36\" E" },
{ "45º46'47.36\" e" , "45° 46' 47.36\" E" },
{ "45º 46' 47.36\" e", "45° 46' 47.36\" E" },
{ "45°46’47.36” E" , "45° 46' 47.36\" E" },
{ "45 46 47.36 W" , "45° 46' 47.36\" W" },
{ "45° 46′ 47.36″ e" , "45° 46' 47.36\" E" },
{ "45° 46’ 47.36” w" , "45° 46' 47.36\" W" },
{ "45° 46’ 47” W" , "45° 46' 47\" W" },
{ "45° 46’ .36” w" , "45° 46' 0.36\" W" },
};

static const std::vector<std::pair<std::string, std::string>> latVariants =
{
{ "45.76260" , "45° 45' 45.36\" N" },
{ "-45.76260" , "45° 45' 45.36\" S" },
{ " 45.76260 " , "45° 45' 45.36\" N"},
{ "45.76260°" , "45° 45' 45.36\" N" },
{ "45.76260° N " , "45° 45' 45.36\" N" },
{ "45" , "45° 00' 00\" N"},
{ ".76260 S" , "00° 45' 45.36\" S" },

{ "45° 46.1' " , "45° 46' 06\" N" },
{ " 45° 46.1' N " , "45° 46' 06\" N" },
{ "45°46.756′N" , "45° 46' 45.36\" N" },
{ "45° 46.756′ N" , "45° 46' 45.36\" N" },
{ "45 46.756 S" , "45° 46' 45.36\" S" },
{ "45 46 S" , "45° 45' 60\" S" },
{ "45 .756 S" , "45° 00' 45.36\" S" },
{ "45 59.9999 S" , "45° 59' 59.99\" S" },

{ "45°46′45.36″ " , "45° 46' 45.36\" N" },
{ "45°46′45.36″ N" , "45° 46' 45.36\" N" },
{ "45º46'47.36\" S" , "45° 46' 47.36\" S" },
{ "45º 46' 47.36\" n", "45° 46' 47.36\" N" },
{ "45°46’47.36” N" , "45° 46' 47.36\" N" },
{ "45 46 47.36 S" , "45° 46' 47.36\" S" },
{ "45° 46′ 47.36″ n" , "45° 46' 47.36\" N" },
{ "45° 46’ 47.36” s" , "45° 46' 47.36\" S" },
{ "45° 46’ 47” S" , "45° 46' 47\" S" },
{ "45° 46’ .36” s" , "45° 46' 0.36\" S" },
};

for (auto && v : lonVariants) {
const auto lon = Longitude::fromString(v.first);
verifyString(v.second, lon.toString(Coordinate::Format::DMS));
}

for (auto && v : latVariants) {
const auto lat = Latitude::fromString(v.first);
verifyString(v.second, lat.toString(Coordinate::Format::DMS));
}
}

// Coordinates to string DDM
{
static const std::vector<std::pair<std::string, std::string>> lonVariants =
{
{ "45.76260" , "45° 45.756' E"},
{ "-45.76260" , "45° 45.756' W" },
{ " 45.76260 " , "45° 45.756' E"},
{ "45.76260°" , "45° 45.756' E" },
{ "45.76260° W " , "45° 45.756' W" },
{ "45 E" , "45° 00' E" },
{ ".76260" , "00° 45.756' E" },

{ "45° 46.1' " , "45° 46.1' E" },
{ " 45° 46.1' E " , "45° 46.1' E" },
{ "45°46.756′E" , "45° 46.756' E" },
{ "45° 46.756′ E" , "45° 46.756' E" },
{ "45 46.756 W" , "45° 46.756' W" },
{ "45 46 W" , "45° 46' W" },
{ "45 .756 W" , "45° 0.756' W" },
{ "45 59.9999 W" , "45° 60' W" },

{ "45°46′45.36″ " , "45° 46.756' E" },
{ "45°46′45.36″ E" , "45° 46.756' E" },
{ "45º46'47.36\" e" , "45° 46.789' E" },
{ "45º 46' 47.36\" e", "45° 46.789' E" },
{ "45°46’47.36” E" , "45° 46.789' E" },
{ "45 46 47.36 W" , "45° 46.789' W" },
{ "45° 46′ 47.36″ e" , "45° 46.789' E" },
{ "45° 46’ 47.36” w" , "45° 46.789' W" },
{ "45° 46’ 47” W" , "45° 46.783' W" },
{ "45° 46’ .36” w" , "45° 46.006' W" },
};

static const std::vector<std::pair<std::string, std::string>> latVariants =
{
{ "45.76260" , "45° 45.756' N" },
{ "-45.76260" , "45° 45.756' S" },
{ " 45.76260 " , "45° 45.756' N"},
{ "45.76260°" , "45° 45.756' N" },
{ "45.76260° N " , "45° 45.756' N" },
{ "45" , "45° 00' N" },
{ ".76260 S" , "00° 45.756' S" },

{ "45° 46.1' " , "45° 46.1' N" },
{ " 45° 46.1' N " , "45° 46.1' N" },
{ "45°46.756′N" , "45° 46.756' N" },
{ "45° 46.756′ N" , "45° 46.756' N" },
{ "45 46.756 S" , "45° 46.756' S" },
{ "45 46 S" , "45° 46' S" },
{ "45 .756 S" , "45° 0.756' S" },
{ "45 59.9999 S" , "45° 60' S" },

{ "45°46′45.36″ " , "45° 46.756' N" },
{ "45°46′45.36″ N" , "45° 46.756' N" },
{ "45º46'47.36\" S" , "45° 46.789' S" },
{ "45º 46' 47.36\" n", "45° 46.789' N" },
{ "45°46’47.36” N" , "45° 46.789' N" },
{ "45 46 47.36 S" , "45° 46.789' S" },
{ "45° 46′ 47.36″ n" , "45° 46.789' N" },
{ "45° 46’ 47.36” s" , "45° 46.789' S" },
{ "45° 46’ 47” S" , "45° 46.783' S" },
{ "45° 46’ .36” s" , "45° 46.006' S" },
};

for (auto &&v : lonVariants) {
const auto lon = Longitude::fromString(v.first);
verifyString(v.second, lon.toString(Coordinate::Format::DDM, 3));
}

for (auto &&v : latVariants) {
const auto lat = Latitude::fromString(v.first);
verifyString(v.second, lat.toString(Coordinate::Format::DDM, 3));
}
}

//////////////////////////////////////////////////////////////////////////////

// Ellipsoidal points
Expand Down

0 comments on commit 8bc330e

Please sign in to comment.