mirror of
https://github.com/swift-project/pilotclient.git
synced 2026-04-15 01:05:35 +08:00
refs #396 subfolders and renamed callsign list to callsign set
* subfolder audio * subfolder geo * adjusted samples, tests ....
This commit is contained in:
committed by
Roland Winklmeier
parent
32f60722c8
commit
0ab755d510
205
src/blackmisc/geo/coordinategeodetic.cpp
Normal file
205
src/blackmisc/geo/coordinategeodetic.cpp
Normal file
@@ -0,0 +1,205 @@
|
||||
/* Copyright (C) 2013
|
||||
* swift Project Community / Contributors
|
||||
*
|
||||
* This file is part of swift project. It is subject to the license terms in the LICENSE file found in the top-level
|
||||
* directory of this distribution and at http://www.swift-project.org/license.html. No part of Swift Project,
|
||||
* including this file, may be copied, modified, propagated, or distributed except according to the terms
|
||||
* contained in the LICENSE file.
|
||||
*/
|
||||
|
||||
#include "blackmisc/geo/coordinategeodetic.h"
|
||||
#include "blackmisc/blackmiscfreefunctions.h"
|
||||
#include "blackmisc/propertyindex.h"
|
||||
#include "blackmisc/math/mathutils.h"
|
||||
#include "blackmisc/variant.h"
|
||||
#include <QtCore/qmath.h>
|
||||
|
||||
using namespace BlackMisc::PhysicalQuantities;
|
||||
using namespace BlackMisc::Math;
|
||||
|
||||
namespace BlackMisc
|
||||
{
|
||||
namespace Geo
|
||||
{
|
||||
|
||||
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_geodeticHeight.valueRoundedWithUnit(6, i18n));
|
||||
}
|
||||
|
||||
CCoordinateGeodetic CCoordinateGeodetic::fromWgs84(const QString &latitudeWgs84, const QString &longitudeWgs84, const CLength &geodeticHeight)
|
||||
{
|
||||
CLatitude lat = CLatitude::fromWgs84(latitudeWgs84);
|
||||
CLongitude lon = CLongitude::fromWgs84(longitudeWgs84);
|
||||
return CCoordinateGeodetic(lat, lon, geodeticHeight);
|
||||
}
|
||||
|
||||
PhysicalQuantities::CLength calculateGreatCircleDistance(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::m());
|
||||
}
|
||||
|
||||
// first, prelimary distance calculation
|
||||
// http://www.movable-type.co.uk/scripts/latlong.html
|
||||
double earthRadiusM = 6371000.8;
|
||||
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 dLat = lat2rad - lat1rad;
|
||||
double dLon = lon2rad - lon1rad;
|
||||
double a = qSin(dLat / 2.0) * qSin(dLat / 2.0) +
|
||||
qCos(lat1rad) * qCos(lat2rad) * qSin(dLon / 2.0) * qSin(dLon / 2.0);
|
||||
double c = 2.0 * qAtan(qSqrt(a) / qSqrt(1.0 - a));
|
||||
double distance = earthRadiusM * c;
|
||||
|
||||
return CLength(distance, CLengthUnit::m());
|
||||
}
|
||||
|
||||
PhysicalQuantities::CAngle calculateBearing(const ICoordinateGeodetic &coordinate1, const ICoordinateGeodetic &coordinate2)
|
||||
{
|
||||
// same coordinate results in 0 distance
|
||||
if (coordinate1.latitude() == coordinate2.latitude() && coordinate1.longitude() == coordinate2.longitude())
|
||||
{
|
||||
return CAngle(0, CAngleUnit::deg());
|
||||
}
|
||||
|
||||
// http://www.yourhomenow.com/house/haversine.html
|
||||
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 dLon = lon1rad - lon2rad;
|
||||
double y = qSin(dLon) * qCos(lat2rad);
|
||||
double x = qCos(lat1rad) * qSin(lat2rad) -
|
||||
qSin(lat1rad) * qCos(lat2rad) * qCos(dLon);
|
||||
double bearing = qAtan2(y, x);
|
||||
bearing = CMathUtils::rad2deg(bearing); // now in deg
|
||||
bearing = CMathUtils::normalizeDegrees(bearing); // normalize
|
||||
return CAngle(bearing, CAngleUnit::deg());
|
||||
}
|
||||
|
||||
CLength ICoordinateGeodetic::calculateGreatCircleDistance(const ICoordinateGeodetic &otherCoordinate) const
|
||||
{
|
||||
return Geo::calculateGreatCircleDistance((*this), otherCoordinate);
|
||||
}
|
||||
|
||||
CAngle ICoordinateGeodetic::bearing(const ICoordinateGeodetic &otherCoordinate) const
|
||||
{
|
||||
return Geo::calculateBearing((*this), otherCoordinate);
|
||||
}
|
||||
|
||||
CVariant ICoordinateGeodetic::propertyByIndex(const BlackMisc::CPropertyIndex &index) const
|
||||
{
|
||||
if (!index.isMyself())
|
||||
{
|
||||
ColumnIndex i = index.frontCasted<ColumnIndex>();
|
||||
switch (i)
|
||||
{
|
||||
case IndexLatitude:
|
||||
return this->latitude().propertyByIndex(index.copyFrontRemoved());
|
||||
case IndexLongitude:
|
||||
return this->longitude().propertyByIndex(index.copyFrontRemoved());
|
||||
case IndexLatitudeAsString:
|
||||
return CVariant(this->latitudeAsString());
|
||||
case IndexLongitudeAsString:
|
||||
return CVariant(this->longitudeAsString());
|
||||
case IndexGeodeticHeight:
|
||||
return this->geodeticHeight().propertyByIndex(index.copyFrontRemoved());
|
||||
case IndexGeodeticHeightAsString:
|
||||
return CVariant(this->geodeticHeightAsString());
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
const QString m = QString("no property, index ").append(index.toQString());
|
||||
Q_ASSERT_X(false, "ICoordinateGeodetic", m.toLocal8Bit().constData());
|
||||
return CVariant::fromValue(m);
|
||||
}
|
||||
|
||||
CVariant CCoordinateGeodetic::propertyByIndex(const BlackMisc::CPropertyIndex &index) const
|
||||
{
|
||||
if (index.isMyself()) { return this->toCVariant(); }
|
||||
if (ICoordinateGeodetic::canHandleIndex(index))
|
||||
{
|
||||
return ICoordinateGeodetic::propertyByIndex(index);
|
||||
}
|
||||
else
|
||||
{
|
||||
return CValueObject::propertyByIndex(index);
|
||||
}
|
||||
}
|
||||
|
||||
void CCoordinateGeodetic::setPropertyByIndex(const CVariant &variant, const BlackMisc::CPropertyIndex &index)
|
||||
{
|
||||
if (index.isMyself())
|
||||
{
|
||||
this->convertFromCVariant(variant);
|
||||
return;
|
||||
}
|
||||
ICoordinateGeodetic::ColumnIndex i = index.frontCasted<ICoordinateGeodetic::ColumnIndex>();
|
||||
switch (i)
|
||||
{
|
||||
case IndexGeodeticHeight:
|
||||
this->m_geodeticHeight.setPropertyByIndex(variant, index.copyFrontRemoved());
|
||||
break;
|
||||
case IndexLatitude:
|
||||
this->m_latitude.setPropertyByIndex(variant, index.copyFrontRemoved());
|
||||
break;
|
||||
case IndexLongitude:
|
||||
this->m_longitude.setPropertyByIndex(variant, index.copyFrontRemoved());
|
||||
break;
|
||||
case IndexLatitudeAsString:
|
||||
this->setLatitude(CLatitude::fromWgs84(variant.toQString()));
|
||||
break;
|
||||
case IndexLongitudeAsString:
|
||||
this->setLongitude(CLongitude::fromWgs84(variant.toQString()));
|
||||
break;
|
||||
case IndexGeodeticHeightAsString:
|
||||
this->m_geodeticHeight.parseFromString(variant.toQString());
|
||||
break;
|
||||
default:
|
||||
CValueObject::setPropertyByIndex(variant, index);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
CCoordinateGeodetic &CCoordinateGeodetic::switchUnit(const CAngleUnit &unit)
|
||||
{
|
||||
this->m_latitude.switchUnit(unit);
|
||||
this->m_longitude.switchUnit(unit);
|
||||
return *this;
|
||||
}
|
||||
|
||||
CCoordinateGeodetic &CCoordinateGeodetic::switchUnit(const CLengthUnit &unit)
|
||||
{
|
||||
this->m_geodeticHeight.switchUnit(unit);
|
||||
return *this;
|
||||
}
|
||||
|
||||
CLength ICoordinateWithRelativePosition::calculcateDistanceToOwnAircraft(const ICoordinateGeodetic &position, bool updateValues)
|
||||
{
|
||||
if (!updateValues) { return Geo::calculateGreatCircleDistance(*this, position); }
|
||||
this->m_distanceToOwnAircraft = Geo::calculateGreatCircleDistance(*this, position);
|
||||
return this->m_distanceToOwnAircraft;
|
||||
}
|
||||
|
||||
CLength ICoordinateWithRelativePosition::calculcateDistanceAndBearingToOwnAircraft(const ICoordinateGeodetic &position, bool updateValues)
|
||||
{
|
||||
if (!updateValues) { return Geo::calculateGreatCircleDistance(*this, position); }
|
||||
this->m_distanceToOwnAircraft = Geo::calculateGreatCircleDistance(*this, position);
|
||||
this->m_bearingToOwnAircraft = Geo::calculateBearing(*this, position);
|
||||
return this->m_distanceToOwnAircraft;
|
||||
}
|
||||
|
||||
ICoordinateWithRelativePosition::ICoordinateWithRelativePosition()
|
||||
{ }
|
||||
|
||||
} // namespace
|
||||
} // namespace
|
||||
194
src/blackmisc/geo/coordinategeodetic.h
Normal file
194
src/blackmisc/geo/coordinategeodetic.h
Normal file
@@ -0,0 +1,194 @@
|
||||
/* Copyright (C) 2013
|
||||
* swift project Community / Contributors
|
||||
*
|
||||
* This file is part of swift project. It is subject to the license terms in the LICENSE file found in the top-level
|
||||
* directory of this distribution and at http://www.swift-project.org/license.html. No part of swift project,
|
||||
* including this file, may be copied, modified, propagated, or distributed except according to the terms
|
||||
* contained in the LICENSE file.
|
||||
*/
|
||||
|
||||
//! \file
|
||||
|
||||
#ifndef BLACKMISC_COORDINATEGEODETIC_H
|
||||
#define BLACKMISC_COORDINATEGEODETIC_H
|
||||
|
||||
#include "blackmisc/geo/latitude.h"
|
||||
#include "blackmisc/geo/longitude.h"
|
||||
#include "blackmisc/pqlength.h"
|
||||
#include "blackmisc/propertyindex.h"
|
||||
|
||||
namespace BlackMisc
|
||||
{
|
||||
namespace Geo
|
||||
{
|
||||
|
||||
//! Geodetic coordinate
|
||||
//! \sa http://www.esri.com/news/arcuser/0703/geoid1of3.html
|
||||
//! \sa http://http://www.gmat.unsw.edu.au/snap/gps/clynch_pdfs/coordcvt.pdf (page 5)
|
||||
//! \sa http://en.wikipedia.org/wiki/Geodetic_datum#Vertical_datum
|
||||
class ICoordinateGeodetic
|
||||
{
|
||||
public:
|
||||
//! Properties by index
|
||||
enum ColumnIndex
|
||||
{
|
||||
IndexLatitude = BlackMisc::CPropertyIndex::GlobalIndexICoordinateGeodetic,
|
||||
IndexLongitude,
|
||||
IndexLatitudeAsString,
|
||||
IndexLongitudeAsString,
|
||||
IndexGeodeticHeight,
|
||||
IndexGeodeticHeightAsString
|
||||
};
|
||||
|
||||
//! Destructor
|
||||
virtual ~ICoordinateGeodetic() {}
|
||||
|
||||
//! Latitude
|
||||
virtual const CLatitude &latitude() const = 0;
|
||||
|
||||
//! Longitude
|
||||
virtual const CLongitude &longitude() const = 0;
|
||||
|
||||
//! Height, ellipsoidal or geodetic height (used in GPS)
|
||||
//! This is approximately MSL (orthometric) height, aka elevation.
|
||||
//! \sa see http://www.gmat.unsw.edu.au/snap/gps/clynch_pdfs/coordcvt.pdf page 5
|
||||
//! \sa http://www.esri.com/news/arcuser/0703/geoid1of3.html
|
||||
virtual const BlackMisc::PhysicalQuantities::CLength &geodeticHeight() const = 0;
|
||||
|
||||
//! \copydoc CValueObject::propertyByIndex
|
||||
virtual CVariant propertyByIndex(const BlackMisc::CPropertyIndex &index) const;
|
||||
|
||||
//! Latitude as string
|
||||
QString latitudeAsString() const { return this->latitude().toQString(true); }
|
||||
|
||||
//! Longitude as string
|
||||
QString longitudeAsString() const { return this->longitude().toQString(true); }
|
||||
|
||||
//! Height as string
|
||||
QString geodeticHeightAsString() const { return this->geodeticHeight().toQString(true); }
|
||||
|
||||
//! Great circle distance
|
||||
BlackMisc::PhysicalQuantities::CLength calculateGreatCircleDistance(const ICoordinateGeodetic &otherCoordinate) const;
|
||||
|
||||
//! Initial bearing
|
||||
BlackMisc::PhysicalQuantities::CAngle bearing(const ICoordinateGeodetic &otherCoordinate) const;
|
||||
|
||||
//! Can given index be handled
|
||||
static bool canHandleIndex(const BlackMisc::CPropertyIndex &index)
|
||||
{
|
||||
int i = index.frontCasted<int>();
|
||||
return (i >= static_cast<int>(IndexLatitude)) && (i <= static_cast<int>(IndexGeodeticHeightAsString));
|
||||
}
|
||||
};
|
||||
|
||||
//! Great circle distance between points
|
||||
BlackMisc::PhysicalQuantities::CLength calculateGreatCircleDistance(const ICoordinateGeodetic &coordinate1, const ICoordinateGeodetic &coordinate2);
|
||||
|
||||
//! Initial bearing
|
||||
BlackMisc::PhysicalQuantities::CAngle calculateBearing(const ICoordinateGeodetic &coordinate1, const ICoordinateGeodetic &coordinate2);
|
||||
|
||||
//! Interface (actually more an abstract class) of coordinate and
|
||||
//! relative position to own aircraft
|
||||
class ICoordinateWithRelativePosition : public ICoordinateGeodetic
|
||||
{
|
||||
public:
|
||||
//! Get the distance to own plane
|
||||
const BlackMisc::PhysicalQuantities::CLength &getDistanceToOwnAircraft() const { return m_distanceToOwnAircraft; }
|
||||
|
||||
//! Set distance to own plane
|
||||
void setDistanceToOwnAircraft(const BlackMisc::PhysicalQuantities::CLength &distance) { this->m_distanceToOwnAircraft = distance; }
|
||||
|
||||
//! Get the bearing to own plane
|
||||
const BlackMisc::PhysicalQuantities::CAngle &getBearingToOwnAircraft() const { return m_bearingToOwnAircraft; }
|
||||
|
||||
//! Set bearing to own plane
|
||||
void setBearingToOwnAircraft(const BlackMisc::PhysicalQuantities::CAngle &angle) { this->m_bearingToOwnAircraft = angle; }
|
||||
|
||||
//! Valid distance?
|
||||
bool hasValidDistance() const { return !this->m_distanceToOwnAircraft.isNull();}
|
||||
|
||||
//! Valid bearing?
|
||||
bool hasValidBearing() const { return !this->m_bearingToOwnAircraft.isNull();}
|
||||
|
||||
//! Calculcate distance, set it, and return distance
|
||||
BlackMisc::PhysicalQuantities::CLength calculcateDistanceToOwnAircraft(const BlackMisc::Geo::ICoordinateGeodetic &position, bool updateValues = true);
|
||||
|
||||
//! Calculcate distance and bearing to plane, set it, and return distance
|
||||
BlackMisc::PhysicalQuantities::CLength calculcateDistanceAndBearingToOwnAircraft(const BlackMisc::Geo::ICoordinateGeodetic &position, bool updateValues = true);
|
||||
|
||||
protected:
|
||||
//! Constructor
|
||||
ICoordinateWithRelativePosition();
|
||||
|
||||
BlackMisc::PhysicalQuantities::CAngle m_bearingToOwnAircraft; //!< temporary stored value
|
||||
BlackMisc::PhysicalQuantities::CLength m_distanceToOwnAircraft; //!< temporary stored value
|
||||
};
|
||||
|
||||
|
||||
//! Geodetic coordinate
|
||||
class CCoordinateGeodetic : public CValueObject<CCoordinateGeodetic>, public ICoordinateGeodetic
|
||||
{
|
||||
|
||||
public:
|
||||
//! Default constructor
|
||||
CCoordinateGeodetic() = default;
|
||||
|
||||
//! Constructor by values
|
||||
CCoordinateGeodetic(CLatitude latitude, CLongitude longitude, BlackMisc::PhysicalQuantities::CLength height) :
|
||||
m_latitude(latitude), m_longitude(longitude), m_geodeticHeight(height) {}
|
||||
|
||||
//! Constructor by values
|
||||
CCoordinateGeodetic(double latitudeDegrees, double longitudeDegrees, double heightMeters) :
|
||||
m_latitude(latitudeDegrees, BlackMisc::PhysicalQuantities::CAngleUnit::deg()), m_longitude(longitudeDegrees, BlackMisc::PhysicalQuantities::CAngleUnit::deg()), m_geodeticHeight(heightMeters, BlackMisc::PhysicalQuantities::CLengthUnit::m()) {}
|
||||
|
||||
//! \copydoc ICoordinateGeodetic::latitude
|
||||
virtual const CLatitude &latitude() const override { return this->m_latitude; }
|
||||
|
||||
//! \copydoc ICoordinateGeodetic::longitude
|
||||
virtual const CLongitude &longitude() const override { return this->m_longitude; }
|
||||
|
||||
//! \copydoc ICoordinateGeodetic::geodeticHeight
|
||||
virtual const BlackMisc::PhysicalQuantities::CLength &geodeticHeight() const override { return this->m_geodeticHeight; }
|
||||
|
||||
//! \copydoc CValueObject::propertyByIndex
|
||||
virtual CVariant propertyByIndex(const BlackMisc::CPropertyIndex &index) const override;
|
||||
|
||||
//! \copydoc CValueObject::setPropertyByIndex
|
||||
virtual void setPropertyByIndex(const CVariant &variant, const BlackMisc::CPropertyIndex &index) override;
|
||||
|
||||
//! Switch unit of latitude / longitude
|
||||
CCoordinateGeodetic &switchUnit(const BlackMisc::PhysicalQuantities::CAngleUnit &unit);
|
||||
|
||||
//! Switch unit of height
|
||||
CCoordinateGeodetic &switchUnit(const BlackMisc::PhysicalQuantities::CLengthUnit &unit);
|
||||
|
||||
//! Set latitude
|
||||
void setLatitude(const CLatitude &latitude) { this->m_latitude = latitude; }
|
||||
|
||||
//! Set longitude
|
||||
void setLongitude(const CLongitude &longitude) { this->m_longitude = longitude; }
|
||||
|
||||
//! Set height (ellipsoidal or geodetic height)
|
||||
void setGeodeticHeight(const BlackMisc::PhysicalQuantities::CLength &height) { this->m_geodeticHeight = height; }
|
||||
|
||||
//! Coordinate by WGS84 position data
|
||||
static CCoordinateGeodetic fromWgs84(const QString &latitudeWgs84, const QString &longitudeWgs84, const BlackMisc::PhysicalQuantities::CLength &geodeticHeight = {});
|
||||
|
||||
protected:
|
||||
//! \copydoc CValueObject::convertToQString
|
||||
virtual QString convertToQString(bool i18n = false) const override;
|
||||
|
||||
private:
|
||||
BLACK_ENABLE_TUPLE_CONVERSION(CCoordinateGeodetic)
|
||||
BlackMisc::Geo::CLatitude m_latitude; //!< Latitude
|
||||
BlackMisc::Geo::CLongitude m_longitude; //!< Longitude
|
||||
BlackMisc::PhysicalQuantities::CLength m_geodeticHeight { 0, BlackMisc::PhysicalQuantities::CLengthUnit::nullUnit() }; //!< height, ellipsoidal or geodetic height
|
||||
};
|
||||
|
||||
} // namespace
|
||||
} // namespace
|
||||
|
||||
BLACK_DECLARE_TUPLE_CONVERSION(BlackMisc::Geo::CCoordinateGeodetic, (o.m_latitude, o.m_longitude, o.m_geodeticHeight))
|
||||
Q_DECLARE_METATYPE(BlackMisc::Geo::CCoordinateGeodetic)
|
||||
|
||||
#endif // guard
|
||||
79
src/blackmisc/geo/earthangle.cpp
Normal file
79
src/blackmisc/geo/earthangle.cpp
Normal file
@@ -0,0 +1,79 @@
|
||||
/* Copyright (C) 2013
|
||||
* swift project Community / Contributors
|
||||
*
|
||||
* This file is part of swift project. It is subject to the license terms in the LICENSE file found in the top-level
|
||||
* directory of this distribution and at http://www.swift-project.org/license.html. No part of swift project,
|
||||
* including this file, may be copied, modified, propagated, or distributed except according to the terms
|
||||
* contained in the LICENSE file.
|
||||
*/
|
||||
|
||||
#include "blackmisc/geo/earthangle.h"
|
||||
#include "blackmisc/geo/latitude.h"
|
||||
#include "blackmisc/geo/longitude.h"
|
||||
#include "blackmisc/iconlist.h"
|
||||
|
||||
namespace BlackMisc
|
||||
{
|
||||
namespace Geo
|
||||
{
|
||||
|
||||
template <class LATorLON> LATorLON CEarthAngle<LATorLON>::fromWgs84(const QString &wgsCoordinate)
|
||||
{
|
||||
// http://www.regular-expressions.info/floatingpoint.html
|
||||
const QString wgs = wgsCoordinate.simplified().trimmed();
|
||||
QRegExp 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;
|
||||
while ((pos = rx.indexIn(wgs, pos)) != -1)
|
||||
{
|
||||
QString cap = rx.cap(1);
|
||||
pos += rx.matchedLength();
|
||||
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;
|
||||
}
|
||||
}
|
||||
if (fragmentLength > 0)
|
||||
{
|
||||
// we do have given ms in string
|
||||
sec += secFragment / qPow(10, fragmentLength);
|
||||
}
|
||||
|
||||
if (wgs.contains('S', Qt::CaseInsensitive) ||
|
||||
wgs.contains('W', Qt::CaseInsensitive)) deg *= -1;
|
||||
|
||||
PhysicalQuantities::CAngle a(deg, min, sec);
|
||||
return LATorLON(a);
|
||||
}
|
||||
|
||||
template <class LATorLON> CIcon CEarthAngle<LATorLON>::toIcon() const
|
||||
{
|
||||
return BlackMisc::CIconList::iconByIndex(CIcons::GeoPosition);
|
||||
}
|
||||
|
||||
// see here for the reason of thess forward instantiations
|
||||
// http://www.parashift.com/c++-faq/separate-template-class-defn-from-decl.html
|
||||
template class CEarthAngle<CLatitude>;
|
||||
template class CEarthAngle<CLongitude>;
|
||||
|
||||
} // namespace
|
||||
} // namespace
|
||||
132
src/blackmisc/geo/earthangle.h
Normal file
132
src/blackmisc/geo/earthangle.h
Normal file
@@ -0,0 +1,132 @@
|
||||
/* Copyright (C) 2013
|
||||
* swift project Community / Contributors
|
||||
*
|
||||
* This file is part of swift project. It is subject to the license terms in the LICENSE file found in the top-level
|
||||
* directory of this distribution and at http://www.swift-project.org/license.html. No part of swift project,
|
||||
* including this file, may be copied, modified, propagated, or distributed except according to the terms
|
||||
* contained in the LICENSE file.
|
||||
*/
|
||||
|
||||
//! \file
|
||||
|
||||
#ifndef BLACKMISC_GEO_EARTHANGLE_H
|
||||
#define BLACKMISC_GEO_EARTHANGLE_H
|
||||
|
||||
#include "blackmisc/pqangle.h"
|
||||
|
||||
namespace BlackMisc
|
||||
{
|
||||
namespace Geo
|
||||
{
|
||||
/*!
|
||||
* Base class for latitude / longitude
|
||||
*/
|
||||
template <class LATorLON> class CEarthAngle : public CValueObject<CEarthAngle<LATorLON>, PhysicalQuantities::CAngle>
|
||||
{
|
||||
public:
|
||||
//! Plus operator +=
|
||||
CEarthAngle &operator +=(const CEarthAngle &latOrLon)
|
||||
{
|
||||
this->PhysicalQuantities::CAngle::operator +=(latOrLon);
|
||||
return *this;
|
||||
}
|
||||
|
||||
//! Minus operator-=
|
||||
CEarthAngle &operator -=(const CEarthAngle &latOrLon)
|
||||
{
|
||||
this->PhysicalQuantities::CAngle::operator -=(latOrLon);
|
||||
return *this;
|
||||
}
|
||||
|
||||
//! Multiply operator *=
|
||||
CEarthAngle operator *=(double multiply)
|
||||
{
|
||||
this->PhysicalQuantities::CAngle::operator *=(multiply);
|
||||
return *this;
|
||||
}
|
||||
|
||||
//! Greater operator >
|
||||
bool operator >(const CEarthAngle &latOrLon) const
|
||||
{
|
||||
return this->PhysicalQuantities::CAngle::operator >(latOrLon);
|
||||
}
|
||||
|
||||
//! Less operator <
|
||||
bool operator <(const CEarthAngle &latOrLon) const
|
||||
{
|
||||
return this->PhysicalQuantities::CAngle::operator >(latOrLon);
|
||||
}
|
||||
|
||||
//! Less equal operator <=
|
||||
bool operator <=(const CEarthAngle &latOrLon) const
|
||||
{
|
||||
return this->PhysicalQuantities::CAngle::operator <=(latOrLon);
|
||||
}
|
||||
|
||||
//! Greater equal operator >=
|
||||
bool operator >=(const CEarthAngle &latOrLon) const
|
||||
{
|
||||
return this->PhysicalQuantities::CAngle::operator >=(latOrLon);
|
||||
}
|
||||
|
||||
//! Plus operator +
|
||||
LATorLON operator +(const CEarthAngle &latOrLon) const
|
||||
{
|
||||
LATorLON l(*this);
|
||||
l += latOrLon;
|
||||
return l;
|
||||
}
|
||||
|
||||
//! Minus operator -
|
||||
LATorLON operator -(const CEarthAngle &latOrLon) const
|
||||
{
|
||||
LATorLON l(*this);
|
||||
l -= latOrLon;
|
||||
return l;
|
||||
}
|
||||
|
||||
//! Multiply operator *
|
||||
LATorLON operator *(double multiply) const
|
||||
{
|
||||
LATorLON l(*this);
|
||||
l *= multiply;
|
||||
return l;
|
||||
}
|
||||
|
||||
//! \copydoc CValueObject::toIcon
|
||||
CIcon toIcon() const override;
|
||||
|
||||
/*!
|
||||
* Latitude / Longitude from a WGS string such as
|
||||
* \param wgsCoordinate 50° 2′ 0″ N / 8° 34′ 14″ E
|
||||
* \return
|
||||
*/
|
||||
static LATorLON fromWgs84(const QString &wgsCoordinate);
|
||||
|
||||
protected:
|
||||
//! Default constructor
|
||||
CEarthAngle() : CEarthAngle::CValueObject(0.0, BlackMisc::PhysicalQuantities::CAngleUnit::deg()) {}
|
||||
|
||||
//! Init by double value
|
||||
CEarthAngle(double value, const BlackMisc::PhysicalQuantities::CAngleUnit &unit) : CEarthAngle::CValueObject(value, unit) {}
|
||||
|
||||
//! Init by CAngle value
|
||||
CEarthAngle(const BlackMisc::PhysicalQuantities::CAngle &angle) : CEarthAngle::CValueObject(angle) {}
|
||||
|
||||
//! \copydoc CValueObject::convertToQString
|
||||
virtual QString convertToQString(bool i18n = false) const override
|
||||
{
|
||||
return this->valueRoundedWithUnit(BlackMisc::PhysicalQuantities::CAngleUnit::deg(), 6, i18n);
|
||||
}
|
||||
|
||||
private:
|
||||
//! Easy access to derived class (CRTP template parameter)
|
||||
LATorLON const *derived() const { return static_cast<LATorLON const *>(this); }
|
||||
|
||||
//! Easy access to derived class (CRTP template parameter)
|
||||
LATorLON *derived() { return static_cast<LATorLON *>(this); }
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
#endif // guard
|
||||
24
src/blackmisc/geo/geo.h
Normal file
24
src/blackmisc/geo/geo.h
Normal file
@@ -0,0 +1,24 @@
|
||||
/* Copyright (C) 2013
|
||||
* swift project Community / Contributors
|
||||
*
|
||||
* This file is part of swift project. It is subject to the license terms in the LICENSE file found in the top-level
|
||||
* directory of this distribution and at http://www.swift-project.org/license.html. No part of swift project,
|
||||
* including this file, may be copied, modified, propagated, or distributed except according to the terms
|
||||
* contained in the LICENSE file.
|
||||
*/
|
||||
|
||||
#ifndef BLACKMISC_GEO_GEO_H
|
||||
#define BLACKMISC_GEO_GEO_H
|
||||
|
||||
/*!
|
||||
* \namespace BlackMisc::Geo
|
||||
* \brief Geo classes such as latitude, longitude, etc.
|
||||
*/
|
||||
|
||||
#include "blackmisc/geo/earthangle.h"
|
||||
#include "blackmisc/geo/latitude.h"
|
||||
#include "blackmisc/geo/longitude.h"
|
||||
#include "blackmisc/geo/geodesicgrid.h"
|
||||
#include "blackmisc/geo/coordinategeodetic.h"
|
||||
|
||||
#endif // guard
|
||||
185
src/blackmisc/geo/geodesicgrid.h
Normal file
185
src/blackmisc/geo/geodesicgrid.h
Normal file
@@ -0,0 +1,185 @@
|
||||
/* Copyright (C) 2013
|
||||
* swift project Community / Contributors
|
||||
*
|
||||
* This file is part of swift project. It is subject to the license terms in the LICENSE file found in the top-level
|
||||
* directory of this distribution and at http://www.swift-project.org/license.html. No part of swift project,
|
||||
* including this file, may be copied, modified, propagated, or distributed except according to the terms
|
||||
* contained in the LICENSE file.
|
||||
*/
|
||||
|
||||
#ifndef BLACKMISC_GEO_GEODESICGRID_H
|
||||
#define BLACKMISC_GEO_GEODESICGRID_H
|
||||
|
||||
//! \file
|
||||
|
||||
#include "blackmisc/math/mathutils.h"
|
||||
#include "coordinategeodetic.h"
|
||||
#include "blackmisc/range.h"
|
||||
#include "blackmisc/iterator.h"
|
||||
#include <QMultiMap>
|
||||
#include <type_traits>
|
||||
|
||||
namespace BlackMisc
|
||||
{
|
||||
namespace Geo
|
||||
{
|
||||
|
||||
// Compute the integer log2(X) of an integer X at compile time
|
||||
//! \private
|
||||
template <typename T, T X, int Count = 0>
|
||||
struct LogBase2 : std::conditional<bool (X >> 1),
|
||||
LogBase2<T, (X >> 1), Count + 1>,
|
||||
std::integral_constant<int, Count>>::type
|
||||
{};
|
||||
|
||||
/*!
|
||||
* Associative container for efficiently storing and retreiving elements at points on the Earth's surface.
|
||||
* Works by dividing the surface of the Earth into 2N^2 triangular tiles of 21600/N nautical miles each.
|
||||
* Each element is inserted according to which tile it falls within, and elements can later be retrieved by
|
||||
* pointing to specific tiles.
|
||||
*/
|
||||
template <int Slices, class T, class Key = qint32>
|
||||
class CGeodesicGrid
|
||||
{
|
||||
public:
|
||||
//! Iterator
|
||||
typedef typename QMultiMap<Key, T>::const_iterator const_iterator;
|
||||
|
||||
//! Constructor
|
||||
//@{
|
||||
CGeodesicGrid() {}
|
||||
template <template <class...> class C> explicit CGeodesicGrid(const C<T> &container) { for (const auto &v : container) { insert(v); } }
|
||||
template <class I> explicit CGeodesicGrid(CRange<I> range) { for (const auto &v : range) { insert(v); } }
|
||||
//@}
|
||||
|
||||
//! Begin and end iterators of the underlying storage.
|
||||
//! @{
|
||||
const_iterator begin() const { return m_map.begin(); }
|
||||
const_iterator cbegin() const { return m_map.cbegin(); }
|
||||
const_iterator end() const { return m_map.end(); }
|
||||
const_iterator cend() const { return m_map.cend(); }
|
||||
//! @}
|
||||
|
||||
//! Removes all elements from all tiles.
|
||||
void clear() { m_map.clear(); }
|
||||
|
||||
//! Returns true if there are no elements in any tiles.
|
||||
bool isEmpty() const { return m_map.isEmpty(); }
|
||||
|
||||
//! Inserts an element in the tile at the given point.
|
||||
//! \warning Angles are in radians.
|
||||
void insert(double lat, double lon, const T &value) { m_map.insert(coordinateToKey(lat, lon), value); }
|
||||
|
||||
//! If T has latitude() and longitude() methods then this convenience insert() method can be used.
|
||||
void insert(const T &value) { m_map.insert(value.latitude(), value.longitude(), value); }
|
||||
|
||||
//! Returns a range containing the elements in the tile at the given point.
|
||||
//! \warning Angles are in radians.
|
||||
CRange<const_iterator> inTileAt(double lat, double lon) const
|
||||
{
|
||||
Key k = coordinateToKey(lat, lon);
|
||||
return makeRange(m_map.lowerBound(k), m_map.upperBound(k));
|
||||
}
|
||||
|
||||
//! Returns a range containing the elements in every tile adjacent to the one at the given point, including that one.
|
||||
//! \warning Angles are in radians.
|
||||
CRange<Iterators::ConcatIterator<const_iterator>> inAdjacentTiles(double lat, double lon, int degree = 1) const
|
||||
{
|
||||
QVector<const_iterator> its;
|
||||
for (auto k : adjacentKeys(coordinateToKey(lat, lon), degree))
|
||||
{
|
||||
its.push_back(m_map.lowerBound(k));
|
||||
its.push_back(m_map.upperBound(k));
|
||||
}
|
||||
Q_ASSERT(!its.isEmpty());
|
||||
return makeRange(Iterators::makeConcatIterator(its), its.back());
|
||||
}
|
||||
|
||||
//! Overloaded method taking the coordinates in a different form.
|
||||
//! @{
|
||||
void insert(const CLatitude &lat, const CLongitude &lon, const T &value) { insert(lat.value(PhysicalQuantities::CAngleUnit::rad()), lon.value(PhysicalQuantities::CAngleUnit::rad()), value); }
|
||||
void insert(const ICoordinateGeodetic &coord, const T &value) { insert(coord.latitude(), coord.longitude(), value); }
|
||||
CRange<const_iterator> inTileAt(const CLatitude &lat, const CLongitude &lon) const { return inTileAt(lat.value(PhysicalQuantities::CAngleUnit::rad()), lon.value(PhysicalQuantities::CAngleUnit::rad())); }
|
||||
CRange<const_iterator> inTileAt(const ICoordinateGeodetic &coord) const { return inTileAt(coord.latitude(), coord.longitude()); }
|
||||
CRange<Iterators::ConcatIterator<const_iterator>> inAdjacentTiles(const CLatitude &lat, const CLongitude &lon, int degree = 1) const { return inAdjacentTiles(lat.value(PhysicalQuantities::CAngleUnit::rad()), lon.value(PhysicalQuantities::CAngleUnit::rad()), degree); }
|
||||
CRange<Iterators::ConcatIterator<const_iterator>> inAdjacentTiles(const ICoordinateGeodetic &coord, int degree = 1) const { return inAdjacentTiles(coord.latitude(), coord.longitude(), degree); }
|
||||
//! @}
|
||||
|
||||
//! Returns the internal keys corresponding to all the tiles.
|
||||
QList<Key> keys() const { return m_map.uniqueKeys(); }
|
||||
|
||||
//! Returns the number of elements in the tile corresponding to this internal key.
|
||||
int count(Key k) const { return m_map.count(k); }
|
||||
|
||||
private:
|
||||
QMultiMap<Key, T> m_map;
|
||||
|
||||
static_assert(std::is_signed<Key>::value && std::is_integral<Key>::value, "Key must be a signed integer");
|
||||
static_assert(Slices > 1 && !(Slices & (Slices - 1)), "Slices must be a power of two");
|
||||
static_assert(LogBase2<Key, Slices>::value * 3 < sizeof(Key) * 8, "Key is too small to hold all Slices");
|
||||
|
||||
static const Key Zshift = 0;
|
||||
static const Key Zmask = Slices - 1;
|
||||
static const Key Zone = 1;
|
||||
static const Key Yshift = LogBase2<Key, Slices>::value;
|
||||
static const Key Ymask = Zmask << Yshift;
|
||||
static const Key Yone = Zone << Yshift;
|
||||
static const Key Xshift = Yshift * 2;
|
||||
static const Key Xmask = Zmask << Xshift;
|
||||
static const Key Xone = Zone << Xshift;
|
||||
|
||||
static Key coordinateToKey(double lat, double lon)
|
||||
{
|
||||
using namespace std;
|
||||
using namespace BlackMisc::Math;
|
||||
Q_ASSERT(lat >= -CMathUtils::PIHALF() && lat <= CMathUtils::PIHALF());
|
||||
Q_ASSERT(lon >= -CMathUtils::PI() && lon <= CMathUtils::PI());
|
||||
static const double ratio = Slices / CMathUtils::PI();
|
||||
Key x = qFloor(acos(cos(lat) * cos(lon)) * ratio);
|
||||
Key y = qFloor(acos(cos(lat) * sin(lon)) * ratio);
|
||||
Key z = qFloor( (lat + CMathUtils::PIHALF()) * ratio);
|
||||
return (x << Xshift) | (y << Yshift) | (z << Zshift);
|
||||
}
|
||||
|
||||
static QVector<Key> adjacentKeys(Key k, int d)
|
||||
{
|
||||
QVector<Key> adj;
|
||||
for (int dx = -d; dx <= d; ++dx)
|
||||
{
|
||||
for (int dy = -d; dy <= d; ++dy)
|
||||
{
|
||||
for (int dz = -d; dz <= d; ++dz)
|
||||
{
|
||||
adj.push_back(plus(k, dx, dy, dz));
|
||||
}
|
||||
}
|
||||
}
|
||||
return adj;
|
||||
}
|
||||
|
||||
static Key plus(Key k, Key dx, Key dy, Key dz)
|
||||
{
|
||||
Key x = k & Xmask;
|
||||
Key y = k & Ymask;
|
||||
Key z = k & Zmask;
|
||||
dx *= Xone;
|
||||
dy *= Yone;
|
||||
dz *= Zone;
|
||||
if ((dx < 0 ? (-dx > x) : (dx > Xmask - x))
|
||||
|| (dy < 0 ? (-dy > y) : (dy > Ymask - y))
|
||||
|| (dz < 0 ? (-dz > z) : (dz > Zmask - z)))
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
return (x + dx) | (y + dy) | (z + dz);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace
|
||||
} // namespace
|
||||
|
||||
#endif // guard
|
||||
|
||||
99
src/blackmisc/geo/geoobjectlist.cpp
Normal file
99
src/blackmisc/geo/geoobjectlist.cpp
Normal file
@@ -0,0 +1,99 @@
|
||||
/* Copyright (C) 2015
|
||||
* swift project Community / Contributors
|
||||
*
|
||||
* This file is part of swift project. It is subject to the license terms in the LICENSE file found in the top-level
|
||||
* directory of this distribution and at http://www.swift-project.org/license.html. No part of swift project,
|
||||
* including this file, may be copied, modified, propagated, or distributed except according to the terms
|
||||
* contained in the LICENSE file.
|
||||
*/
|
||||
|
||||
#include "blackmisc/geo/geoobjectlist.h"
|
||||
#include "blackmisc/predicates.h"
|
||||
#include "blackmisc/aviation/atcstationlist.h"
|
||||
#include "blackmisc/aviation/aircraftlist.h"
|
||||
#include "blackmisc/aviation/airportlist.h"
|
||||
#include "blackmisc/simulation/simulatedaircraftlist.h"
|
||||
|
||||
using namespace BlackMisc::PhysicalQuantities;
|
||||
|
||||
namespace BlackMisc
|
||||
{
|
||||
namespace Geo
|
||||
{
|
||||
template <class OBJ, class CONTAINER>
|
||||
IGeoObjectList<OBJ, CONTAINER>::IGeoObjectList()
|
||||
{ }
|
||||
|
||||
template <class OBJ, class CONTAINER>
|
||||
IGeoObjectWithRelativePositionList<OBJ, CONTAINER>::IGeoObjectWithRelativePositionList()
|
||||
{ }
|
||||
|
||||
template <class OBJ, class CONTAINER>
|
||||
CONTAINER IGeoObjectList<OBJ, CONTAINER>::findWithinRange(const ICoordinateGeodetic &coordinate, const PhysicalQuantities::CLength &range) const
|
||||
{
|
||||
return this->container().findBy([&](const OBJ & geoObj)
|
||||
{
|
||||
return calculateGreatCircleDistance(geoObj, coordinate) <= range;
|
||||
});
|
||||
}
|
||||
|
||||
template <class OBJ, class CONTAINER>
|
||||
void IGeoObjectWithRelativePositionList<OBJ, CONTAINER>::calculcateDistanceAndBearingToPosition(const ICoordinateGeodetic &position)
|
||||
{
|
||||
for (OBJ &geoObj : this->container())
|
||||
{
|
||||
geoObj.calculcateDistanceAndBearingToOwnAircraft(position);
|
||||
}
|
||||
}
|
||||
|
||||
template <class OBJ, class CONTAINER>
|
||||
void IGeoObjectWithRelativePositionList<OBJ, CONTAINER>::removeIfOutsideRange(const Geo::ICoordinateGeodetic &position, const CLength &maxDistance, bool updateValues)
|
||||
{
|
||||
this->container().removeIf([ & ](OBJ & geoObj)
|
||||
{
|
||||
return geoObj.calculcateDistanceAndBearingToOwnAircraft(position, updateValues) > maxDistance;
|
||||
});
|
||||
}
|
||||
|
||||
template <class OBJ, class CONTAINER>
|
||||
void IGeoObjectWithRelativePositionList<OBJ, CONTAINER>::sortByRange(const BlackMisc::Geo::ICoordinateGeodetic &position, bool updateValues)
|
||||
{
|
||||
if (updateValues)
|
||||
{
|
||||
this->calculcateDistanceAndBearingToPosition(position);
|
||||
}
|
||||
this->container().sort([ & ](const OBJ & a, const OBJ & b) { return a.getDistanceToOwnAircraft() < b.getDistanceToOwnAircraft(); });
|
||||
}
|
||||
|
||||
template <class OBJ, class CONTAINER>
|
||||
void IGeoObjectWithRelativePositionList<OBJ, CONTAINER>::sortByDistanceToOwnAircraft()
|
||||
{
|
||||
this->container().sort([ & ](const OBJ & a, const OBJ & b) { return a.getDistanceToOwnAircraft() < b.getDistanceToOwnAircraft(); });
|
||||
}
|
||||
|
||||
template <class OBJ, class CONTAINER>
|
||||
CONTAINER IGeoObjectWithRelativePositionList<OBJ, CONTAINER>::getClosestObjects(int number) const
|
||||
{
|
||||
if (number < 1) { return CONTAINER(); }
|
||||
if (this->container().size() >= number) { return (this->container()); }
|
||||
CONTAINER closest(this->container());
|
||||
closest.sortByDistanceToOwnAircraft();
|
||||
closest.truncate(number);
|
||||
return closest;
|
||||
}
|
||||
|
||||
// see here for the reason of thess forward instantiations
|
||||
// http://www.parashift.com/c++-faq/separate-template-class-defn-from-decl.html
|
||||
template class IGeoObjectList<BlackMisc::Aviation::CAtcStation, BlackMisc::Aviation::CAtcStationList>;
|
||||
template class IGeoObjectList<BlackMisc::Aviation::CAircraft, BlackMisc::Aviation::CAircraftList>;
|
||||
template class IGeoObjectList<BlackMisc::Aviation::CAirport, BlackMisc::Aviation::CAirportList>;
|
||||
template class IGeoObjectList<BlackMisc::Simulation::CSimulatedAircraft, BlackMisc::Simulation::CSimulatedAircraftList>;
|
||||
|
||||
template class IGeoObjectWithRelativePositionList<BlackMisc::Aviation::CAtcStation, BlackMisc::Aviation::CAtcStationList>;
|
||||
template class IGeoObjectWithRelativePositionList<BlackMisc::Aviation::CAircraft, BlackMisc::Aviation::CAircraftList>;
|
||||
template class IGeoObjectWithRelativePositionList<BlackMisc::Aviation::CAirport, BlackMisc::Aviation::CAirportList>;
|
||||
template class IGeoObjectWithRelativePositionList<BlackMisc::Simulation::CSimulatedAircraft, BlackMisc::Simulation::CSimulatedAircraftList>;
|
||||
|
||||
} // namespace
|
||||
} // namespace
|
||||
|
||||
77
src/blackmisc/geo/geoobjectlist.h
Normal file
77
src/blackmisc/geo/geoobjectlist.h
Normal file
@@ -0,0 +1,77 @@
|
||||
/* Copyright (C) 2015
|
||||
* swift project Community / Contributors
|
||||
*
|
||||
* This file is part of swift project. It is subject to the license terms in the LICENSE file found in the top-level
|
||||
* directory of this distribution and at http://www.swift-project.org/license.html. No part of swift project,
|
||||
* including this file, may be copied, modified, propagated, or distributed except according to the terms
|
||||
* contained in the LICENSE file.
|
||||
*/
|
||||
|
||||
//! \file
|
||||
|
||||
#ifndef BLACKMISC_GEO_GEOOBJECTLIST_H
|
||||
#define BLACKMISC_GEO_GEOOBJECTLIST_H
|
||||
|
||||
#include "blackmisc/collection.h"
|
||||
#include "blackmisc/sequence.h"
|
||||
#include "blackmisc/geo/coordinategeodetic.h"
|
||||
|
||||
namespace BlackMisc
|
||||
{
|
||||
namespace Geo
|
||||
{
|
||||
//! List of objects with geo coordinates.
|
||||
template<class OBJ, class CONTAINER>
|
||||
class IGeoObjectList
|
||||
{
|
||||
public:
|
||||
|
||||
/*!
|
||||
* Find 0..n objects within range of given coordinate
|
||||
* \param coordinate other position
|
||||
* \param range within range of other position
|
||||
* \return
|
||||
*/
|
||||
CONTAINER findWithinRange(const BlackMisc::Geo::ICoordinateGeodetic &coordinate, const BlackMisc::PhysicalQuantities::CLength &range) const;
|
||||
|
||||
protected:
|
||||
//! Constructor
|
||||
IGeoObjectList();
|
||||
|
||||
//! Container
|
||||
virtual const CONTAINER &container() const = 0;
|
||||
|
||||
//! Container
|
||||
virtual CONTAINER &container() = 0;
|
||||
};
|
||||
|
||||
//! List of objects with geo coordinates.
|
||||
template<class OBJ, class CONTAINER>
|
||||
class IGeoObjectWithRelativePositionList : public IGeoObjectList<OBJ, CONTAINER>
|
||||
{
|
||||
public:
|
||||
//! Calculate distances, then sort by range
|
||||
void sortByRange(const BlackMisc::Geo::ICoordinateGeodetic &position, bool updateValues);
|
||||
|
||||
//! If distance is already set, just sort
|
||||
void sortByDistanceToOwnAircraft();
|
||||
|
||||
//! Get n closest objects
|
||||
CONTAINER getClosestObjects(int number) const;
|
||||
|
||||
//! Calculate distances, remove if outside range
|
||||
void removeIfOutsideRange(const BlackMisc::Geo::ICoordinateGeodetic &position, const BlackMisc::PhysicalQuantities::CLength &maxDistance, bool updateValues);
|
||||
|
||||
//! Calculate distances
|
||||
void calculcateDistanceAndBearingToPosition(const BlackMisc::Geo::ICoordinateGeodetic &position);
|
||||
|
||||
protected:
|
||||
//! Constructor
|
||||
IGeoObjectWithRelativePositionList();
|
||||
|
||||
};
|
||||
|
||||
} //namespace
|
||||
} // namespace
|
||||
|
||||
#endif //guard
|
||||
54
src/blackmisc/geo/latitude.h
Normal file
54
src/blackmisc/geo/latitude.h
Normal file
@@ -0,0 +1,54 @@
|
||||
/* Copyright (C) 2013
|
||||
* swift project Community / Contributors
|
||||
*
|
||||
* This file is part of swift project. It is subject to the license terms in the LICENSE file found in the top-level
|
||||
* directory of this distribution and at http://www.swift-project.org/license.html. No part of swift project,
|
||||
* including this file, may be copied, modified, propagated, or distributed except according to the terms
|
||||
* contained in the LICENSE file.
|
||||
*/
|
||||
|
||||
//! \file
|
||||
|
||||
#ifndef BLACKMISC_GEO_LATITUDE_H
|
||||
#define BLACKMISC_GEO_LATITUDE_H
|
||||
|
||||
#include <QtCore/qmath.h>
|
||||
#include "blackmisc/geo/earthangle.h"
|
||||
|
||||
namespace BlackMisc
|
||||
{
|
||||
namespace Geo
|
||||
{
|
||||
|
||||
//! Latitude
|
||||
class CLatitude : public CValueObject<CLatitude, CEarthAngle<CLatitude>>
|
||||
{
|
||||
protected:
|
||||
//! \copydoc CValueObject::convertToQString
|
||||
virtual QString convertToQString(bool i18n = false) const
|
||||
{
|
||||
QString s(CEarthAngle::convertToQString(i18n));
|
||||
if (!this->isZeroEpsilonConsidered())
|
||||
{
|
||||
s.append(this->isNegativeWithEpsilonConsidered() ? " S" : " N");
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
public:
|
||||
//! Default constructor
|
||||
CLatitude() = default;
|
||||
|
||||
//! Constructor
|
||||
explicit CLatitude(const BlackMisc::PhysicalQuantities::CAngle &angle) : CValueObject(angle) {}
|
||||
|
||||
//! Init by double value
|
||||
CLatitude(double value, const BlackMisc::PhysicalQuantities::CAngleUnit &unit) : CValueObject(value, unit) {}
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
Q_DECLARE_METATYPE(BlackMisc::Geo::CLatitude)
|
||||
|
||||
#endif // guard
|
||||
51
src/blackmisc/geo/longitude.h
Normal file
51
src/blackmisc/geo/longitude.h
Normal file
@@ -0,0 +1,51 @@
|
||||
/* Copyright (C) 2013
|
||||
* swift project Community / Contributors
|
||||
*
|
||||
* This file is part of swift project. It is subject to the license terms in the LICENSE file found in the top-level
|
||||
* directory of this distribution and at http://www.swift-project.org/license.html. No part of swift project,
|
||||
* including this file, may be copied, modified, propagated, or distributed except according to the terms
|
||||
* contained in the LICENSE file.
|
||||
*/
|
||||
|
||||
//! \file
|
||||
|
||||
#ifndef BLACKMISC_GEO_LONGITUDE_H
|
||||
#define BLACKMISC_GEO_LONGITUDE_H
|
||||
|
||||
#include "blackmisc/geo/earthangle.h"
|
||||
|
||||
namespace BlackMisc
|
||||
{
|
||||
namespace Geo
|
||||
{
|
||||
|
||||
//! Longitude
|
||||
class CLongitude : public CValueObject<CLongitude, CEarthAngle<CLongitude>>
|
||||
{
|
||||
protected:
|
||||
//! \copydoc CValueObject::convertToQString
|
||||
virtual QString convertToQString(bool i18n = false) const
|
||||
{
|
||||
QString s(CEarthAngle::convertToQString(i18n));
|
||||
if (!this->isZeroEpsilonConsidered())
|
||||
s.append(this->isNegativeWithEpsilonConsidered() ? " W" : " E");
|
||||
return s;
|
||||
}
|
||||
|
||||
public:
|
||||
//! Default constructor
|
||||
CLongitude() = default;
|
||||
|
||||
//! Constructor
|
||||
explicit CLongitude(const BlackMisc::PhysicalQuantities::CAngle &angle) : CValueObject(angle) {}
|
||||
|
||||
//! Init by double value
|
||||
CLongitude(double value, const BlackMisc::PhysicalQuantities::CAngleUnit &unit) : CValueObject(value, unit) {}
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
Q_DECLARE_METATYPE(BlackMisc::Geo::CLongitude)
|
||||
|
||||
#endif // guard
|
||||
Reference in New Issue
Block a user