ADD: new track message, Entity class and Position class
This commit is contained in:
229
libs/geographiclib/src/PolygonArea.cpp
Normal file
229
libs/geographiclib/src/PolygonArea.cpp
Normal file
@@ -0,0 +1,229 @@
|
||||
/**
|
||||
* \file PolygonArea.cpp
|
||||
* \brief Implementation for GeographicLib::PolygonAreaT class
|
||||
*
|
||||
* Copyright (c) Charles Karney (2010-2022) <charles@karney.com> and licensed
|
||||
* under the MIT/X11 License. For more information, see
|
||||
* https://geographiclib.sourceforge.io/
|
||||
**********************************************************************/
|
||||
|
||||
#include <GeographicLib/PolygonArea.hpp>
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
// Squelch warnings about enum-float expressions
|
||||
# pragma warning (disable: 5055)
|
||||
#endif
|
||||
|
||||
namespace GeographicLib {
|
||||
|
||||
using namespace std;
|
||||
|
||||
template<class GeodType>
|
||||
int PolygonAreaT<GeodType>::transit(real lon1, real lon2) {
|
||||
// Return 1 or -1 if crossing prime meridian in east or west direction.
|
||||
// Otherwise return zero. longitude = +/-0 considered to be positive.
|
||||
// This is (should be?) compatible with transitdirect which computes
|
||||
// exactly the parity of
|
||||
// int(floor((lon1 + lon12) / 360)) - int(floor(lon1 / 360)))
|
||||
real lon12 = Math::AngDiff(lon1, lon2);
|
||||
lon1 = Math::AngNormalize(lon1);
|
||||
lon2 = Math::AngNormalize(lon2);
|
||||
// N.B. lon12 == 0 gives cross = 0
|
||||
return
|
||||
// edge case lon1 = 180, lon2 = 360->0, lon12 = 180 to give 1
|
||||
lon12 > 0 && ((lon1 < 0 && lon2 >= 0) ||
|
||||
// lon12 > 0 && lon1 > 0 && lon2 == 0 implies lon1 == 180
|
||||
(lon1 > 0 && lon2 == 0)) ? 1 :
|
||||
// non edge case lon1 = -180, lon2 = -360->-0, lon12 = -180
|
||||
(lon12 < 0 && lon1 >= 0 && lon2 < 0 ? -1 : 0);
|
||||
// This was the old method (treating +/- 0 as negative). However, with the
|
||||
// new scheme for handling longitude differences this fails on:
|
||||
// lon1 = -180, lon2 = -360->-0, lon12 = -180 gives 0 not -1.
|
||||
// return
|
||||
// lon1 <= 0 && lon2 > 0 && lon12 > 0 ? 1 :
|
||||
// (lon2 <= 0 && lon1 > 0 && lon12 < 0 ? -1 : 0);
|
||||
}
|
||||
|
||||
// an alternate version of transit to deal with longitudes in the direct
|
||||
// problem.
|
||||
template<class GeodType>
|
||||
int PolygonAreaT<GeodType>::transitdirect(real lon1, real lon2) {
|
||||
// Compute exactly the parity of
|
||||
// int(floor(lon2 / 360)) - int(floor(lon1 / 360))
|
||||
using std::remainder;
|
||||
// C++ C remainder -> [-360, 360]
|
||||
// Java % -> (-720, 720) switch to IEEEremainder -> [-360, 360]
|
||||
// JS % -> (-720, 720)
|
||||
// Python fmod -> (-720, 720) swith to Math.remainder
|
||||
// Fortran, Octave skip
|
||||
// If mod function gives result in [-360, 360]
|
||||
// [0, 360) -> 0; [-360, 0) or 360 -> 1
|
||||
// If mod function gives result in (-720, 720)
|
||||
// [0, 360) or [-inf, -360) -> 0; [-360, 0) or [360, inf) -> 1
|
||||
lon1 = remainder(lon1, real(2 * Math::td));
|
||||
lon2 = remainder(lon2, real(2 * Math::td));
|
||||
return ( (lon2 >= 0 && lon2 < Math::td ? 0 : 1) -
|
||||
(lon1 >= 0 && lon1 < Math::td ? 0 : 1) );
|
||||
}
|
||||
|
||||
template<class GeodType>
|
||||
void PolygonAreaT<GeodType>::AddPoint(real lat, real lon) {
|
||||
if (_num == 0) {
|
||||
_lat0 = _lat1 = lat;
|
||||
_lon0 = _lon1 = lon;
|
||||
} else {
|
||||
real s12, S12, t;
|
||||
_earth.GenInverse(_lat1, _lon1, lat, lon, _mask,
|
||||
s12, t, t, t, t, t, S12);
|
||||
_perimetersum += s12;
|
||||
if (!_polyline) {
|
||||
_areasum += S12;
|
||||
_crossings += transit(_lon1, lon);
|
||||
}
|
||||
_lat1 = lat; _lon1 = lon;
|
||||
}
|
||||
++_num;
|
||||
}
|
||||
|
||||
template<class GeodType>
|
||||
void PolygonAreaT<GeodType>::AddEdge(real azi, real s) {
|
||||
if (_num) { // Do nothing if _num is zero
|
||||
real lat, lon, S12, t;
|
||||
_earth.GenDirect(_lat1, _lon1, azi, false, s, _mask,
|
||||
lat, lon, t, t, t, t, t, S12);
|
||||
_perimetersum += s;
|
||||
if (!_polyline) {
|
||||
_areasum += S12;
|
||||
_crossings += transitdirect(_lon1, lon);
|
||||
}
|
||||
_lat1 = lat; _lon1 = lon;
|
||||
++_num;
|
||||
}
|
||||
}
|
||||
|
||||
template<class GeodType>
|
||||
unsigned PolygonAreaT<GeodType>::Compute(bool reverse, bool sign,
|
||||
real& perimeter, real& area) const
|
||||
{
|
||||
real s12, S12, t;
|
||||
if (_num < 2) {
|
||||
perimeter = 0;
|
||||
if (!_polyline)
|
||||
area = 0;
|
||||
return _num;
|
||||
}
|
||||
if (_polyline) {
|
||||
perimeter = _perimetersum();
|
||||
return _num;
|
||||
}
|
||||
_earth.GenInverse(_lat1, _lon1, _lat0, _lon0, _mask,
|
||||
s12, t, t, t, t, t, S12);
|
||||
perimeter = _perimetersum(s12);
|
||||
Accumulator<> tempsum(_areasum);
|
||||
tempsum += S12;
|
||||
int crossings = _crossings + transit(_lon1, _lon0);
|
||||
AreaReduce(tempsum, crossings, reverse, sign);
|
||||
area = real(0) + tempsum();
|
||||
return _num;
|
||||
}
|
||||
|
||||
template<class GeodType>
|
||||
unsigned PolygonAreaT<GeodType>::TestPoint(real lat, real lon,
|
||||
bool reverse, bool sign,
|
||||
real& perimeter, real& area) const
|
||||
{
|
||||
if (_num == 0) {
|
||||
perimeter = 0;
|
||||
if (!_polyline)
|
||||
area = 0;
|
||||
return 1;
|
||||
}
|
||||
perimeter = _perimetersum();
|
||||
real tempsum = _polyline ? 0 : _areasum();
|
||||
int crossings = _crossings;
|
||||
unsigned num = _num + 1;
|
||||
for (int i = 0; i < (_polyline ? 1 : 2); ++i) {
|
||||
real s12, S12, t;
|
||||
_earth.GenInverse(i == 0 ? _lat1 : lat, i == 0 ? _lon1 : lon,
|
||||
i != 0 ? _lat0 : lat, i != 0 ? _lon0 : lon,
|
||||
_mask, s12, t, t, t, t, t, S12);
|
||||
perimeter += s12;
|
||||
if (!_polyline) {
|
||||
tempsum += S12;
|
||||
crossings += transit(i == 0 ? _lon1 : lon,
|
||||
i != 0 ? _lon0 : lon);
|
||||
}
|
||||
}
|
||||
|
||||
if (_polyline)
|
||||
return num;
|
||||
|
||||
AreaReduce(tempsum, crossings, reverse, sign);
|
||||
area = real(0) + tempsum;
|
||||
return num;
|
||||
}
|
||||
|
||||
template<class GeodType>
|
||||
unsigned PolygonAreaT<GeodType>::TestEdge(real azi, real s,
|
||||
bool reverse, bool sign,
|
||||
real& perimeter, real& area) const
|
||||
{
|
||||
if (_num == 0) { // we don't have a starting point!
|
||||
perimeter = Math::NaN();
|
||||
if (!_polyline)
|
||||
area = Math::NaN();
|
||||
return 0;
|
||||
}
|
||||
unsigned num = _num + 1;
|
||||
perimeter = _perimetersum() + s;
|
||||
if (_polyline)
|
||||
return num;
|
||||
|
||||
real tempsum = _areasum();
|
||||
int crossings = _crossings;
|
||||
{
|
||||
real lat, lon, s12, S12, t;
|
||||
_earth.GenDirect(_lat1, _lon1, azi, false, s, _mask,
|
||||
lat, lon, t, t, t, t, t, S12);
|
||||
tempsum += S12;
|
||||
crossings += transitdirect(_lon1, lon);
|
||||
_earth.GenInverse(lat, lon, _lat0, _lon0, _mask,
|
||||
s12, t, t, t, t, t, S12);
|
||||
perimeter += s12;
|
||||
tempsum += S12;
|
||||
crossings += transit(lon, _lon0);
|
||||
}
|
||||
|
||||
AreaReduce(tempsum, crossings, reverse, sign);
|
||||
area = real(0) + tempsum;
|
||||
return num;
|
||||
}
|
||||
|
||||
template<class GeodType>
|
||||
template<typename T>
|
||||
void PolygonAreaT<GeodType>::AreaReduce(T& area, int crossings,
|
||||
bool reverse, bool sign) const {
|
||||
Remainder(area);
|
||||
if (crossings & 1) area += (area < 0 ? 1 : -1) * _area0/2;
|
||||
// area is with the clockwise sense. If !reverse convert to
|
||||
// counter-clockwise convention.
|
||||
if (!reverse) area *= -1;
|
||||
// If sign put area in (-_area0/2, _area0/2], else put area in [0, _area0)
|
||||
if (sign) {
|
||||
if (area > _area0/2)
|
||||
area -= _area0;
|
||||
else if (area <= -_area0/2)
|
||||
area += _area0;
|
||||
} else {
|
||||
if (area >= _area0)
|
||||
area -= _area0;
|
||||
else if (area < 0)
|
||||
area += _area0;
|
||||
}
|
||||
}
|
||||
|
||||
template class GEOGRAPHICLIB_EXPORT PolygonAreaT<Geodesic>;
|
||||
template class GEOGRAPHICLIB_EXPORT PolygonAreaT<GeodesicExact>;
|
||||
template class GEOGRAPHICLIB_EXPORT PolygonAreaT<Rhumb>;
|
||||
|
||||
} // namespace GeographicLib
|
||||
Reference in New Issue
Block a user