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)