Files
pilotclient/src/blackmisc/coordinategeodetic.cpp
Mathew Sutcliffe db4c05dd9f refs #84 removed the CValueObject::compare method and added a friend function BlackMisc::compare to replace it.
The new compare is implemented using "multimethods" described in the book Advanced C++ Programming Styles and Idioms by James Coplien.

First, the isA method is used to determine which of the values being compared is the most general. (For example, CLength is more general than CAltitude.)
Then the compareImpl method is called on the most general value, with the other value as an argument.
If there is not a direct inheritance relation between the two values (or they are the same class) then the comparison is invalid and a assert is triggered.
2014-01-17 01:38:27 +00:00

158 lines
5.1 KiB
C++

/* Copyright (C) 2013 VATSIM Community / contributors
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "blackmisc/coordinategeodetic.h"
#include "blackmisc/blackmiscfreefunctions.h"
#include "mathematics.h"
#include <QtCore/qmath.h>
using namespace BlackMisc::PhysicalQuantities;
using namespace BlackMisc::Math;
namespace BlackMisc
{
namespace Geo
{
/*
* String for converter
*/
QString CCoordinateGeodetic::convertToQString(bool i18n) const
{
QString s = "Geodetic: {%1, %2, %3}";
return s.arg(this->m_latitude.valueRoundedWithUnit(6, i18n)).arg(this->m_longitude.valueRoundedWithUnit(6, i18n)).arg(this->m_height.valueRoundedWithUnit(i18n));
}
/*
* metaTypeId
*/
int CCoordinateGeodetic::getMetaTypeId() const
{
return qMetaTypeId<CCoordinateGeodetic>();
}
/*
* is a
*/
bool CCoordinateGeodetic::isA(int metaTypeId) const
{
if (metaTypeId == qMetaTypeId<CCoordinateGeodetic>()) { return true; }
return this->CValueObject::isA(metaTypeId);
}
/*
* Compare
*/
int CCoordinateGeodetic::compareImpl(const CValueObject &otherBase) const
{
const auto &other = static_cast<const CCoordinateGeodetic &>(otherBase);
int cmp = compare(this->m_latitude, other.m_latitude);
if (cmp) { return cmp; }
cmp = compare(this->m_longitude, other.m_longitude);
if (cmp) { return cmp; }
return compare(this->m_height, other.m_height);
}
/*
* Marshall to Dbus
*/
void CCoordinateGeodetic::marshallToDbus(QDBusArgument &argument) const
{
argument << this->m_latitude;
argument << this->m_longitude;
argument << this->m_height;
}
/*
* Unmarshall from Dbus
*/
void CCoordinateGeodetic::unmarshallFromDbus(const QDBusArgument &argument)
{
argument >> this->m_latitude;
argument >> this->m_longitude;
argument >> this->m_height;
}
/*
* Same coordinate
*/
bool CCoordinateGeodetic::operator ==(const CCoordinateGeodetic &other) const
{
if (this == &other) return true;
return this->m_height == other.m_height &&
this->m_latitude == other.m_latitude &&
this->m_longitude == other.m_longitude;
}
/*
* Unequal?
*/
bool CCoordinateGeodetic::operator !=(const CCoordinateGeodetic &other) const
{
return !((*this) == other);
}
/*
* Register metadata
*/
void CCoordinateGeodetic::registerMetadata()
{
qRegisterMetaType<CCoordinateGeodetic>();
qDBusRegisterMetaType<CCoordinateGeodetic>();
}
/*
* Hash
*/
uint CCoordinateGeodetic::getValueHash() const
{
QList<uint> hashs;
hashs << this->m_latitude.getValueHash();
hashs << this->m_longitude.getValueHash();
hashs << this->m_height.getValueHash();
return BlackMisc::calculateHash(hashs, "CCoordinateGeodetic");
}
/*
* From WGS84 coordinates
*/
CCoordinateGeodetic CCoordinateGeodetic::fromWgs84(const QString &latitudeWgs84, const QString &longitudeWgs84, const CLength height)
{
CLatitude lat = CLatitude::fromWgs84(latitudeWgs84);
CLongitude lon = CLongitude::fromWgs84(longitudeWgs84);
return CCoordinateGeodetic(lat, lon, height);
}
/*
* Great circle distance
*/
PhysicalQuantities::CLength greatCircleDistance(const ICoordinateGeodetic &coordinate1, const ICoordinateGeodetic &coordinate2)
{
// same coordinate results in 0 distance
if (coordinate1.latitude() == coordinate2.latitude() && coordinate1.longitude() == coordinate2.longitude())
{
return CLength(0, CLengthUnit::NM());
}
// first, prelimary distance calculation
// http://www.geodatasource.com/developers/c
double dist;
double lon1rad = coordinate1.longitude().value(CAngleUnit::rad());
double lon2rad = coordinate2.longitude().value(CAngleUnit::rad());
double lat1rad = coordinate1.latitude().value(CAngleUnit::rad());
double lat2rad = coordinate2.latitude().value(CAngleUnit::rad());
double theta = lon1rad - lon2rad;
dist = qSin(lat1rad) * qSin(lat2rad) + qCos(lat1rad) * qCos(lat2rad) * cos(theta);
dist = qAcos(dist);
dist = CMath::rad2deg(dist);
dist = dist * 60; // dist in NM
return CLength(qAbs(dist), CLengthUnit::NM());
}
} // namespace
} // namespace