#include <GeographicLib/PolygonArea.hpp>
namespace GeographicLib {
using namespace std;
template<class GeodType>
int PolygonAreaT<GeodType>::transit(real lon1, real lon2) {
real lon12 = Math::AngDiff(lon1, lon2);
lon1 = Math::AngNormalize(lon1);
lon2 = Math::AngNormalize(lon2);
return
lon12 > 0 && ((lon1 < 0 && lon2 >= 0) ||
(lon1 > 0 && lon2 == 0)) ? 1 :
(lon12 < 0 && lon1 >= 0 && lon2 < 0 ? -1 : 0);
}
template<class GeodType>
int PolygonAreaT<GeodType>::transitdirect(real lon1, real lon2) {
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) { 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) { 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;
if (!reverse) area *= -1;
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>;
}