Ref T111, lat/lng/angle changes

* get struct CAngle::DegMinSecFractionalSec to obtain parts
* round to epsilon utility functions and fix (qint64)
This commit is contained in:
Klaus Basan
2017-07-26 14:38:49 +02:00
committed by Mathew Sutcliffe
parent 77546a46b1
commit e55480737e
15 changed files with 328 additions and 102 deletions

View File

@@ -212,6 +212,13 @@ namespace BlackMisc
CCoordinateGeodetic::CCoordinateGeodetic(double latitudeDegrees, double longitudeDegrees, double heightFeet) :
CCoordinateGeodetic( { latitudeDegrees, BlackMisc::PhysicalQuantities::CAngleUnit::deg() }, { longitudeDegrees, BlackMisc::PhysicalQuantities::CAngleUnit::deg() }, { heightFeet, BlackMisc::PhysicalQuantities::CLengthUnit::ft() }) {}
CCoordinateGeodetic::CCoordinateGeodetic(const ICoordinateGeodetic &coordinate) :
m_x(coordinate.normalVectorDouble()[0]),
m_y(coordinate.normalVectorDouble()[1]),
m_z(coordinate.normalVectorDouble()[2]),
m_geodeticHeight(coordinate.geodeticHeight())
{ }
CLatitude CCoordinateGeodetic::latitude() const
{
return { std::atan2(m_z, std::hypot(m_x, m_y)), PhysicalQuantities::CAngleUnit::rad() };

View File

@@ -187,8 +187,7 @@ namespace BlackMisc
{
public:
//! Default constructor
CCoordinateGeodetic() :
CCoordinateGeodetic(0, 0, 0) {}
CCoordinateGeodetic() : CCoordinateGeodetic(0, 0, 0) {}
//! Constructor by normal vector
CCoordinateGeodetic(const QVector3D &normal) : m_x(normal.x()), m_y(normal.y()), m_z(normal.z()) {}
@@ -202,6 +201,9 @@ namespace BlackMisc
//! Constructor by values
CCoordinateGeodetic(double latitudeDegrees, double longitudeDegrees, double heightFeet);
//! Constructor by interface
CCoordinateGeodetic(const ICoordinateGeodetic &coordinate);
//! \copydoc ICoordinateGeodetic::latitude
virtual CLatitude latitude() const override;

View File

@@ -17,11 +17,12 @@
#include <QtGlobal>
#include <QtMath>
using namespace BlackMisc::PhysicalQuantities;
namespace BlackMisc
{
namespace Geo
{
template <class LATorLON>
CEarthAngle<LATorLON> &CEarthAngle<LATorLON>::operator +=(const CEarthAngle &latOrLon)
{
@@ -70,49 +71,64 @@ namespace BlackMisc
template <class LATorLON>
LATorLON CEarthAngle<LATorLON>::fromWgs84(const QString &wgsCoordinate)
{
// http://www.regular-expressions.info/floatingpoint.html
const QString wgs = wgsCoordinate.simplified().trimmed();
thread_local const QRegularExpression rx("([-+]?[0-9]*\\.?[0-9]+)");
qint32 deg = 0;
qint32 min = 0;
double sec = 0.0;
double secFragment = 0.0;
int fragmentLength = 0;
int c = 0;
int pos = 0;
QRegularExpressionMatch match = rx.match(wgs, pos);
while (match.hasMatch())
if (wgs.isEmpty()) { return LATorLON(); }
// support for 5deg, 1.2rad
if (CAngleUnit::deg().endsStringWithNameOrSymbol(wgs) || CAngleUnit::rad().endsStringWithNameOrSymbol(wgs))
{
QString cap = match.captured(1);
pos += match.capturedLength(1);
switch (c++)
{
case 0:
deg = cap.toInt();
break;
case 1:
min = cap.toInt();
break;
case 2:
sec = cap.toDouble();
break;
case 3:
secFragment = cap.toDouble();
fragmentLength = cap.length();
break;
default:
break;
}
match = rx.match(wgs, pos);
}
if (fragmentLength > 0)
{
// we do have given ms in string
sec += secFragment / qPow(10, fragmentLength);
LATorLON latOrLon;
latOrLon.parseFromString(wgs);
return latOrLon;
}
if (wgs.contains('S', Qt::CaseInsensitive) ||
wgs.contains('W', Qt::CaseInsensitive)) deg *= -1;
// number only -> parsed as degrees
bool isDouble;
const double valueDegrees = wgs.toDouble(&isDouble);
if (isDouble)
{
CAngle a(valueDegrees, CAngleUnit::deg());
return LATorLON(a);
}
// http://www.regular-expressions.info/floatingpoint.html
thread_local const QRegularExpression rx("[+-]?\\d+(?:\\.\\d+)?");
int deg = 0;
int min = 0;
double sec = 0.0;
int c = 0;
QRegularExpressionMatchIterator i = rx.globalMatch(wgs);
while (i.hasNext() && c < 3)
{
const QRegularExpressionMatch match = i.next();
bool ok;
if (match.hasMatch())
{
const QString cap = match.captured(0);
switch (c++)
{
case 0:
deg = cap.toInt(&ok);
break;
case 1:
min = cap.toInt(&ok);
break;
case 2:
sec = cap.toDouble(&ok);
break;
default:
break;
}
}
Q_UNUSED(ok); // ok for debugging purposes
}
if (wgs.contains('S', Qt::CaseInsensitive) || wgs.contains('W', Qt::CaseInsensitive))
{
deg *= -1;
min *= -1;
sec *= -1;
}
PhysicalQuantities::CAngle a(deg, min, sec);
return LATorLON(a);
@@ -151,6 +167,19 @@ namespace BlackMisc
return BlackMisc::CIcon::iconByIndex(CIcons::GeoPosition);
}
template<class LATorLON>
QString CEarthAngle<LATorLON>::toWgs84(const QChar pos, const QChar neg, int fractionalDigits) const
{
const CAngle::DegMinSecFractionalSec v = this->asSexagesimalDegMinSec(true);
const QChar pn = v.sign < 0 ? neg : pos;
static const QString vs("%1° %2' %3\" %4");
if (fractionalDigits < 1) { return vs.arg(v.deg).arg(v.min).arg(v.sec).arg(pn); }
static const QString vsf("%1° %2' %3.%4\" %5");
return vsf.arg(v.deg).arg(v.min).arg(v.sec).arg(v.fractionalSecAsString(fractionalDigits)).arg(pn);
}
// see here for the reason of thess forward instantiations
// https://isocpp.org/wiki/faq/templates#separate-template-fn-defn-from-decl
//! \cond PRIVATE

View File

@@ -18,7 +18,6 @@ namespace BlackMisc
{
namespace Geo
{
class CLatitude;
class CLongitude;
@@ -66,6 +65,9 @@ namespace BlackMisc
//! Init by CAngle value
CEarthAngle(const BlackMisc::PhysicalQuantities::CAngle &angle);
//! To WGS84 string
QString toWgs84(const QChar pos, const QChar neg, int fractionalDigits = 3) const;
public:
//! \copydoc BlackMisc::Mixin::String::toQString
QString convertToQString(bool i18n = false) const;
@@ -82,8 +84,7 @@ namespace BlackMisc
extern template class BLACKMISC_EXPORT_DECLARE_TEMPLATE CEarthAngle<CLatitude>;
extern template class BLACKMISC_EXPORT_DECLARE_TEMPLATE CEarthAngle<CLongitude>;
//! \endcond
}
}
} // ns
} // ns
#endif // guard

View File

@@ -19,7 +19,6 @@ namespace BlackMisc
{
namespace Geo
{
//! Latitude
class BLACKMISC_EXPORT CLatitude :
public CEarthAngle<CLatitude>,
@@ -36,6 +35,12 @@ namespace BlackMisc
BLACKMISC_DECLARE_USING_MIXIN_STRING(CLatitude)
BLACKMISC_DECLARE_USING_MIXIN_INDEX(CLatitude)
//! To WGS84 string
QString toWgs84(int fractionalDigits = 3) const
{
return CEarthAngle<CLatitude>::toWgs84('N', 'S', fractionalDigits);
}
//! \copydoc BlackMisc::Mixin::String::toQString
QString convertToQString(bool i18n = false) const
{
@@ -54,11 +59,11 @@ namespace BlackMisc
explicit CLatitude(const BlackMisc::PhysicalQuantities::CAngle &angle) : CEarthAngle(angle) {}
//! Init by double value
//! \remark Latitude measurements range from 0° to (+/)90°
CLatitude(double value, const BlackMisc::PhysicalQuantities::CAngleUnit &unit) : CEarthAngle(value, unit) {}
};
}
}
} // ns
} // ns
Q_DECLARE_METATYPE(BlackMisc::Geo::CLatitude)

View File

@@ -19,7 +19,6 @@ namespace BlackMisc
{
namespace Geo
{
//! Longitude
class BLACKMISC_EXPORT CLongitude :
public CEarthAngle<CLongitude>,
@@ -36,12 +35,20 @@ namespace BlackMisc
BLACKMISC_DECLARE_USING_MIXIN_STRING(CLongitude)
BLACKMISC_DECLARE_USING_MIXIN_INDEX(CLongitude)
//! To WGS84 string
QString toWgs84(int withFragmentSecDigits = 3) const
{
return CEarthAngle<CLongitude>::toWgs84('E', 'W', withFragmentSecDigits);
}
//! \copydoc BlackMisc::Mixin::String::toQString
QString convertToQString(bool i18n = false) const
{
QString s(CEarthAngle::convertToQString(i18n));
if (!this->isZeroEpsilonConsidered())
{
s.append(this->isNegativeWithEpsilonConsidered() ? " W" : " E");
}
return s;
}
@@ -52,11 +59,11 @@ namespace BlackMisc
explicit CLongitude(const BlackMisc::PhysicalQuantities::CAngle &angle) : CEarthAngle(angle) {}
//! Init by double value
//! Longitude measurements range from 0° to (+/)180°.
CLongitude(double value, const BlackMisc::PhysicalQuantities::CAngleUnit &unit) : CEarthAngle(value, unit) {}
};
}
}
} // ns
} // ns
Q_DECLARE_METATYPE(BlackMisc::Geo::CLongitude)

View File

@@ -53,10 +53,12 @@ namespace BlackMisc
double CMathUtils::roundEpsilon(double value, double epsilon)
{
if (epsilon == 0) { return value; } // avoid division by 0
double fractpart, intpart;
fractpart = modf(value, &intpart);
if (fractpart == 0) return value; // do not mess any "integers" to the worse
qint64 ri = qRound(value / epsilon);
if (fractpart == 0) { return value; } // do not mess any "integers" to the worse
const double roundValue = value / epsilon;
qint64 ri = qRound64(roundValue);
double rv = static_cast<double>(ri) * epsilon; // do not loose any range here
return rv;
}
@@ -113,5 +115,15 @@ namespace BlackMisc
return multiplier * divisor;
}
QString CMathUtils::fractionalPartAsString(double value, int width)
{
double intpart;
const double fractpart = modf(value, &intpart);
const QString f = QString::number(fractpart);
const QString fInt = f.length() < 3 ? QString("0") : f.mid(2);
if (width < 0) { return fInt; }
if (fInt.length() >= width) { return fInt.left(width); }
return fInt.leftJustified(width, '0');
}
} // namespace
} // namespace

View File

@@ -21,7 +21,6 @@ namespace BlackMisc
{
namespace Math
{
//! Math utils
class BLACKMISC_EXPORT CMathUtils
{
@@ -103,10 +102,13 @@ namespace BlackMisc
//! Random number between low and high
static int randomInteger(int low, int high);
//! Round numToRound to the nearest multiple of multiple
//! Round numToRound to the nearest multiple of divisor
static int roundToMultipleOf(int value, int divisor);
};
//! Fractional part as integer string, e.g. 3.12 -> 12 / 3.012 -> 012
//! \remark because of leading 0 returned as string
static QString fractionalPartAsString(double value, int width = -1);
};
} // namespace
} // namespace

View File

@@ -14,10 +14,60 @@
#include <cmath>
using namespace BlackMisc::Math;
namespace BlackMisc
{
namespace PhysicalQuantities
{
CAngle::CAngle(int degrees, int minutes, double seconds) :
CPhysicalQuantity(
degrees + minutes / 100.0 + seconds / 10000.0,
CAngleUnit::sexagesimalDeg())
{
Q_ASSERT_X((degrees >= 0 && minutes >= 0 && seconds >= 0) ||
(degrees <= 0 && minutes <= 0 && seconds <= 0), Q_FUNC_INFO, "Same sign required");
}
CAngle::CAngle(int degrees, double minutes) :
CPhysicalQuantity(
degrees + minutes / 100.0,
CAngleUnit::sexagesimalDeg())
{
Q_ASSERT_X((degrees >= 0 && minutes >= 0) || (degrees <= 0 && minutes <= 0),
Q_FUNC_INFO, "Same sign required");
}
void CAngle::unifySign(int &degrees, int &minutes, double &seconds)
{
if (degrees < 0)
{
if (minutes > 0) minutes *= -1;
if (seconds > 0) seconds *= -1.0;
}
else if (degrees > 0)
{
if (minutes < 0) minutes *= -1;
if (seconds < 0) seconds *= -1.0;
}
else
{
// degrees was 0
if ((minutes > 0 && seconds < 0) || (minutes < 0 && seconds > 0))
{
seconds *= -1.0;
}
}
}
void CAngle::unifySign(int &degrees, int &minutes)
{
if ((degrees > 0 && minutes < 0) || (degrees < 0 && minutes > 0))
{
minutes *= -1.0;
}
}
BlackMisc::CIcon CAngle::toIcon() const
{
BlackMisc::CIcon i = CIcon::iconByIndex(CIcons::StandardIconArrowMediumNorth16);
@@ -25,6 +75,37 @@ namespace BlackMisc
return i;
}
CAngle::DegMinSecFractionalSec CAngle::asSexagesimalDegMinSec(bool range180Degrees) const
{
double v = this->value(CAngleUnit::deg());
v = CAngleUnit::deg().roundToEpsilon(v);
// range -179-180 ?
if (range180Degrees)
{
v = std::fmod(v + 180.0, 360.0);
v += (v < 0) ? 180.0 : -180.0;
}
DegMinSecFractionalSec values;
if (v < 0)
{
values.sign = -1;
v *= -1.0;
}
values.deg = v;
v -= values.deg;
v = v * 100.0 * 0.6;
values.min = v;
v -= values.min;
v = v * 100.0 * 0.6;
values.sec = v;
v -= values.sec;
values.fractionalSec = CMathUtils::round(v, 6);
return values;
}
double CAngle::piFactor() const
{
return BlackMisc::Math::CMathUtils::round(this->value(CAngleUnit::rad()) / BlackMisc::Math::CMathUtils::PI() , 6);
@@ -49,5 +130,5 @@ namespace BlackMisc
{
return std::tan(this->value(CAngleUnit::rad()));
}
}
}
} // ns
} // ns

View File

@@ -25,7 +25,6 @@ namespace BlackMisc
{
namespace PhysicalQuantities
{
//! Physical unit angle (radians, degrees)
class BLACKMISC_EXPORT CAngle : public CPhysicalQuantity<CAngleUnit, CAngle>
{
@@ -39,27 +38,50 @@ namespace BlackMisc
//! \copydoc CPhysicalQuantity(const QString &unitString)
CAngle(const QString &unitString) : CPhysicalQuantity(unitString) {}
/*!
* \brief Init as sexagesimal degrees, minutes, seconds
* The sign of all parameters must be the same, either all positive or all negative.
*/
CAngle(int degrees, int minutes, double seconds) :
CPhysicalQuantity(
degrees + minutes / 100.0 + seconds / 10000.0,
CAngleUnit::sexagesimalDeg()) {}
//! Value as individual values
struct DegMinSecFractionalSec
{
int sign = 1; //!< 1/-1
int deg = 0; //!< 0-359
int min = 0; //!< 0-59
int sec = 0; //!< 0-59
double fractionalSec = 0; //!< value < 1.0
/*!
* \brief Init as sexagesimal degrees, minutes
* The sign of both parameters must be the same, either both positive or both negative.
*/
CAngle(int degrees, double minutes) :
CPhysicalQuantity(
degrees + minutes / 100.0,
CAngleUnit::sexagesimalDegMin()) {}
//! Degrees as string
QString degAsString() const { return QString::number(deg); }
//! Minutes as string
QString minAsString() const { return QString::number(min); }
//! Seconds as string
QString secAsString() const { return QString::number(sec); }
//! Fractional seconds as string
QString fractionalSecAsString(int width = -1) const { return BlackMisc::Math::CMathUtils::fractionalPartAsString(fractionalSec, width); }
};
//! \brief Init as sexagesimal degrees, minutes, seconds
//! The sign of all parameters must be the same, either all positive or all negative.
//! \see CAngle::unifySign(int &, int &, double &)
CAngle(int degrees, int minutes, double seconds);
//! \brief Init as sexagesimal degrees, minutes
//! The sign of both parameters must be the same, either both positive or both negative.
//! \see CAngle::unifySign(int &, double &)
CAngle(int degrees, double minutes);
//! Minutes and secods will get same sign as degrees
void static unifySign(int &degrees, int &minutes, double &seconds);
//! Minutes will get same sign as degrees
void static unifySign(int &degrees, int &minutes);
//! \copydoc BlackMisc::Mixin::Icon::toIcon
BlackMisc::CIcon toIcon() const;
//! As individual values
DegMinSecFractionalSec asSexagesimalDegMinSec(bool range180Degrees = false) const;
//! Value as factor of PI (e.g. 0.5PI)
double piFactor() const;
@@ -75,8 +97,8 @@ namespace BlackMisc
//! Tangent of angle
double tan() const;
};
}
}
} // ns
} // ns
Q_DECLARE_METATYPE(BlackMisc::PhysicalQuantities::CAngle)

View File

@@ -17,7 +17,6 @@ namespace BlackMisc
{
namespace PhysicalQuantities
{
bool CMeasurementUnit::operator ==(const CMeasurementUnit &other) const
{
if (this == &other) return true;
@@ -43,17 +42,23 @@ namespace BlackMisc
double CMeasurementUnit::roundValue(double value, int digits) const
{
if (digits < 0) digits = this->m_data->m_displayDigits;
if (digits < 0) { digits = this->m_data->m_displayDigits; }
return CMathUtils::round(value, digits);
}
QString CMeasurementUnit::makeRoundedQString(double value, int digits, bool /* i18n */) const
double CMeasurementUnit::roundToEpsilon(double value) const
{
if (digits < 0) digits = this->m_data->m_displayDigits;
double v = CMathUtils::round(value, digits);
QString s = QLocale::system().toString(v, 'f', digits);
return s;
if (this->getEpsilon() == 0 || this->isNull()) { return value; }
return CMathUtils::roundEpsilon(value, this->getEpsilon());
}
QString CMeasurementUnit::makeRoundedQString(double value, int digits, bool i18n) const
{
Q_UNUSED(i18n);
if (digits < 0) digits = this->m_data->m_displayDigits;
const double v = CMathUtils::round(value, digits);
const QString s = QLocale::system().toString(v, 'f', digits);
return s;
}
} // namespace
} // namespace

View File

@@ -36,7 +36,6 @@ namespace BlackMisc
{
namespace PhysicalQuantities
{
/*!
* Base class for all units, such as meter, hertz.
*/
@@ -219,11 +218,11 @@ namespace BlackMisc
: m_name(name), m_symbol(symbol)
{}
QLatin1String m_name; //!< name, e.g. "meter"
QLatin1String m_symbol; //!< unit name, e.g. "m"
double m_epsilon = 0.0; //!< values with differences below epsilon are the equal
int m_displayDigits = 0; //!< standard rounding for string conversions
ConverterFunction m_toDefault = nullptr; //!< convert from this unit to default unit
QLatin1String m_name; //!< name, e.g. "meter"
QLatin1String m_symbol; //!< unit name, e.g. "m"
double m_epsilon = 0.0; //!< values with differences below epsilon are the equal
int m_displayDigits = 0; //!< standard rounding for string conversions
ConverterFunction m_toDefault = nullptr; //!< convert from this unit to default unit
ConverterFunction m_fromDefault = nullptr; //!< convert to this unit from default unit
};
@@ -291,16 +290,31 @@ namespace BlackMisc
return i18n ? QCoreApplication::translate("CMeasurementUnit", this->m_data->m_symbol.latin1()) : this->m_data->m_symbol;
}
//! Does a string end with name or symbol? E.g. 3meter, 3m, 3deg
bool endsStringWithNameOrSymbol(const QString &candidate, Qt::CaseSensitivity cs = Qt::CaseSensitive)
{
const QString c = candidate.trimmed();
return c.endsWith(this->getName(false), cs) || c.endsWith(this->getName(true)) ||
c.endsWith(this->getSymbol(false), cs) || c.endsWith(this->getSymbol(true));
}
//! Rounded value
//! \note default digits is CMeasurementUnit::getDisplayDigits
double roundValue(double value, int digits = -1) const;
//! Rounded to the nearest CMeasurementUnit::getEpsilon
//! \remark uses CMathUtils::roundEpsilon
double roundToEpsilon(double value) const;
//! Rounded string utility method, virtual so units can have specialized formatting
//! \note default digits is CMeasurementUnit::getDisplayDigits
virtual QString makeRoundedQString(double value, int digits = -1, bool i18n = false) const;
//! Value rounded with unit, e.g. "5.00m", "30kHz"
//! \note default digits is CMeasurementUnit::getDisplayDigits
virtual QString makeRoundedQStringWithUnit(double value, int digits = -1, bool i18n = false) const;
//! Threshold for rounding
//! Threshold for comparions
double getEpsilon() const
{
return this->m_data->m_epsilon;
@@ -371,8 +385,7 @@ namespace BlackMisc
return none;
}
};
}
}
} // ns
} // ns
#endif // guard

View File

@@ -300,6 +300,13 @@ namespace BlackMisc
return this->valueRoundedWithUnit(this->m_unit, digits, i18n);
}
template<class MU, class PQ>
void CPhysicalQuantity<MU, PQ>::roundToEpsilon()
{
if (this->isNull()) { return; }
this->m_value = this->m_unit.roundToEpsilon(this->m_value);
}
template <class MU, class PQ>
double CPhysicalQuantity<MU, PQ>::valueRounded(MU unit, int digits) const
{

View File

@@ -101,20 +101,28 @@ namespace BlackMisc
void setCurrentUnitValue(double value);
//! Rounded value in given unit
//! \note default digits is CMeasurementUnit::getDisplayDigits
double valueRounded(MU unit, int digits = -1) const;
//! As integer value
int valueInteger(MU unit) const;
//! Rounded value in current unit
//! \note default digits is CMeasurementUnit::getDisplayDigits
double valueRounded(int digits = -1) const;
//! Value to QString with the given unit, e.g. "5.00m"
//! \note default digits is CMeasurementUnit::getDisplayDigits
QString valueRoundedWithUnit(MU unit, int digits = -1, bool i18n = false) const;
//! Value to QString with the current unit, e.g. "5.00m"
//! \note default digits is CMeasurementUnit::getDisplayDigits
QString valueRoundedWithUnit(int digits = -1, bool i18n = false) const;
//! Round current value in current unit to epsilon
//! \sa CMeasurementUnit::roundToEpsilon
void roundToEpsilon();
//! Change value without changing unit
void setValueSameUnit(double value);

View File

@@ -31,10 +31,25 @@ namespace BlackMiscTest
{
void CTestGeo::geoBasics()
{
CLatitude lati(10, CAngleUnit::deg());
QVERIFY2(lati * 2 == lati + lati, "Latitude addition should be equal");
lati += CLatitude(20, CAngleUnit::deg());
QVERIFY2(lati.valueRounded() == 30.0, "Latitude should be 30 degrees");
CLatitude lat(10, CAngleUnit::deg());
QVERIFY2(lat * 2 == lat + lat, "Latitude addition should be equal");
lat += CLatitude(20, CAngleUnit::deg());
QVERIFY2(lat.valueRounded() == 30.0, "Latitude should be 30 degrees");
CAngle a(20, 0);
lat = CLatitude(a);
double v = lat.valueRounded(CAngleUnit::deg());
QVERIFY2(v == 20.0, "Values shall be the same");
a = CAngle(28, 0);
lat = CLatitude(a);
v = lat.valueRounded(CAngleUnit::deg());
QVERIFY2(v == 28.0, "Values shall be the same");
a = CAngle(30, 0, 0);
lat = CLatitude(a);
v = lat.valueRounded(CAngleUnit::deg());
QVERIFY2(v == 30.0, "Values shall be the same");
}
void CTestGeo::coordinateGeodetic()
@@ -44,7 +59,17 @@ namespace BlackMiscTest
QCOMPARE(calculateEuclideanDistance(northPole, southPole), 2.0);
CCoordinateGeodetic equator = { 0.0, 70.354683 };
QCOMPARE(calculateEuclideanDistance(northPole, equator), std::sqrt(2.0f));
CCoordinateGeodetic testCoordinate = northPole;
double latValue = testCoordinate.latitude().value(CAngleUnit::deg());
double lngValue = testCoordinate.longitude().value(CAngleUnit::deg());
QVERIFY2(latValue == 90.0, "Latitude value supposed to be 90");
QVERIFY2(lngValue == 0.0, "Longitude value supposed to be 0");
CLatitude newLat(90.0, CAngleUnit::deg());
testCoordinate.setLatitude(newLat);
latValue = testCoordinate.latitude().value(CAngleUnit::deg());
QVERIFY2(latValue == newLat.value(CAngleUnit::deg()), "Latitude value supposed to be equal");
}
} // namespace
} // ns
//! \endcond