2018-01-08 23:47:45 +01:00
|
|
|
/*
|
|
|
|
* Based on libgeotrans with the following Source Code Disclaimer:
|
|
|
|
|
|
|
|
1. The GEOTRANS source code ("the software") is provided free of charge by
|
|
|
|
the National Imagery and Mapping Agency (NIMA) of the United States
|
|
|
|
Department of Defense. Although NIMA makes no copyright claim under Title 17
|
|
|
|
U.S.C., NIMA claims copyrights in the source code under other legal regimes.
|
|
|
|
NIMA hereby grants to each user of the software a license to use and
|
|
|
|
distribute the software, and develop derivative works.
|
|
|
|
|
|
|
|
2. Warranty Disclaimer: The software was developed to meet only the internal
|
|
|
|
requirements of the U.S. National Imagery and Mapping Agency. The software
|
|
|
|
is provided "as is," and no warranty, express or implied, including but not
|
|
|
|
limited to the implied warranties of merchantability and fitness for
|
|
|
|
particular purpose or arising by statute or otherwise in law or from a
|
|
|
|
course of dealing or usage in trade, is made by NIMA as to the accuracy and
|
|
|
|
functioning of the software.
|
|
|
|
|
|
|
|
3. NIMA and its personnel are not required to provide technical support or
|
|
|
|
general assistance with respect to the software.
|
|
|
|
|
|
|
|
4. Neither NIMA nor its personnel will be liable for any claims, losses, or
|
|
|
|
damages arising from or connected with the use of the software. The user
|
|
|
|
agrees to hold harmless the United States National Imagery and Mapping
|
|
|
|
Agency. The user's sole and exclusive remedy is to stop using the software.
|
|
|
|
|
|
|
|
5. NIMA requests that products developed using the software credit the
|
|
|
|
source of the software with the following statement, "The product was
|
|
|
|
developed using GEOTRANS, a product of the National Imagery and Mapping
|
|
|
|
Agency and U.S. Army Engineering Research and Development Center."
|
|
|
|
|
|
|
|
6. For any products developed using the software, NIMA requires a disclaimer
|
|
|
|
that use of the software does not indicate endorsement or approval of the
|
|
|
|
product by the Secretary of Defense or the National Imagery and Mapping
|
|
|
|
Agency. Pursuant to the United States Code, 10 U.S.C. Sec. 2797, the name of
|
|
|
|
the National Imagery and Mapping Agency, the initials "NIMA", the seal of
|
|
|
|
the National Imagery and Mapping Agency, or any colorable imitation thereof
|
|
|
|
shall not be used to imply approval, endorsement, or authorization of a
|
|
|
|
product without prior written permission from United States Secretary of
|
|
|
|
Defense.
|
|
|
|
|
|
|
|
*/
|
|
|
|
|
2017-04-02 22:17:16 +02:00
|
|
|
#include <cmath>
|
2018-02-26 19:13:57 +01:00
|
|
|
#include "ellipsoid.h"
|
2017-04-02 22:17:16 +02:00
|
|
|
#include "lambertconic.h"
|
|
|
|
|
2018-01-08 23:47:45 +01:00
|
|
|
|
|
|
|
#define LAMBERT_m(clat, essin) (clat / sqrt(1.0 - essin * essin))
|
|
|
|
#define LAMBERT2_t(lat, essin, es_over_2) \
|
|
|
|
(tan(M_PI_4 - lat / 2) * pow((1.0 + essin) / (1.0 - essin), es_over_2))
|
|
|
|
#define LAMBERT1_t(lat, essin, es_over_2) \
|
|
|
|
(tan(M_PI_4 - lat / 2) / pow((1.0 - essin) / (1.0 + essin), es_over_2))
|
2017-04-09 10:26:09 +02:00
|
|
|
|
|
|
|
|
2018-01-20 20:13:56 +01:00
|
|
|
LambertConic1::LambertConic1(const Ellipsoid *ellipsoid, double latitudeOrigin,
|
2018-01-08 23:47:45 +01:00
|
|
|
double longitudeOrigin, double scale, double falseEasting,
|
|
|
|
double falseNorthing)
|
2017-04-09 10:26:09 +02:00
|
|
|
{
|
2018-05-17 22:41:56 +02:00
|
|
|
double e_sin;
|
2018-01-08 23:47:45 +01:00
|
|
|
double m0;
|
|
|
|
double lat_orig;
|
2017-04-09 10:26:09 +02:00
|
|
|
|
|
|
|
|
2018-01-08 23:47:45 +01:00
|
|
|
lat_orig = deg2rad(latitudeOrigin);
|
|
|
|
_longitudeOrigin = deg2rad(longitudeOrigin);
|
|
|
|
if (_longitudeOrigin > M_PI)
|
2018-05-15 21:51:56 +02:00
|
|
|
_longitudeOrigin -= M_2_PI;
|
2018-01-08 23:47:45 +01:00
|
|
|
|
|
|
|
_falseEasting = falseEasting;
|
|
|
|
_falseNorthing = falseNorthing;
|
|
|
|
|
2018-05-17 22:41:56 +02:00
|
|
|
_e = sqrt(ellipsoid->es());
|
|
|
|
_e_over_2 = _e / 2.0;
|
2018-01-08 23:47:45 +01:00
|
|
|
|
|
|
|
_n = sin(lat_orig);
|
|
|
|
|
2018-05-17 22:41:56 +02:00
|
|
|
e_sin = _e * sin(lat_orig);
|
|
|
|
m0 = LAMBERT_m(cos(lat_orig), e_sin);
|
|
|
|
_t0 = LAMBERT1_t(lat_orig, e_sin, _e_over_2);
|
2018-01-08 23:47:45 +01:00
|
|
|
|
2018-01-20 20:13:56 +01:00
|
|
|
_rho0 = ellipsoid->radius() * scale * m0 / _n;
|
2018-01-08 23:47:45 +01:00
|
|
|
|
|
|
|
_rho_olat = _rho0;
|
2017-04-09 10:26:09 +02:00
|
|
|
}
|
|
|
|
|
2018-04-15 16:27:47 +02:00
|
|
|
PointD LambertConic1::ll2xy(const Coordinates &c) const
|
2017-04-09 10:26:09 +02:00
|
|
|
{
|
2018-01-08 23:47:45 +01:00
|
|
|
double t;
|
|
|
|
double rho;
|
|
|
|
double dlam;
|
|
|
|
double theta;
|
|
|
|
double lat = deg2rad(c.lat());
|
|
|
|
|
|
|
|
|
|
|
|
if (fabs(fabs(lat) - M_PI_2) > 1.0e-10) {
|
2018-05-17 22:41:56 +02:00
|
|
|
t = LAMBERT1_t(lat, _e * sin(lat), _e_over_2);
|
2018-01-08 23:47:45 +01:00
|
|
|
rho = _rho0 * pow(t / _t0, _n);
|
|
|
|
} else
|
|
|
|
rho = 0.0;
|
|
|
|
|
|
|
|
dlam = deg2rad(c.lon()) - _longitudeOrigin;
|
|
|
|
|
|
|
|
if (dlam > M_PI)
|
2018-05-15 21:51:56 +02:00
|
|
|
dlam -= M_2_PI;
|
2018-01-08 23:47:45 +01:00
|
|
|
if (dlam < -M_PI)
|
2018-05-15 21:51:56 +02:00
|
|
|
dlam += M_2_PI;
|
2018-01-08 23:47:45 +01:00
|
|
|
|
|
|
|
theta = _n * dlam;
|
|
|
|
|
2018-04-15 16:27:47 +02:00
|
|
|
return PointD(rho * sin(theta) + _falseEasting, _rho_olat - rho
|
2018-01-08 23:47:45 +01:00
|
|
|
* cos(theta) + _falseNorthing);
|
2017-04-09 10:26:09 +02:00
|
|
|
}
|
2017-04-02 22:17:16 +02:00
|
|
|
|
2018-04-15 16:27:47 +02:00
|
|
|
Coordinates LambertConic1::xy2ll(const PointD &p) const
|
2017-04-02 22:17:16 +02:00
|
|
|
{
|
2018-01-08 23:47:45 +01:00
|
|
|
double dx;
|
|
|
|
double dy;
|
|
|
|
double rho;
|
|
|
|
double rho_olat_minus_dy;
|
|
|
|
double t;
|
|
|
|
double PHI;
|
|
|
|
double es_sin;
|
|
|
|
double tempPHI = 0.0;
|
|
|
|
double theta = 0.0;
|
|
|
|
double tolerance = 4.85e-10;
|
|
|
|
int count = 30;
|
|
|
|
double lat, lon;
|
|
|
|
|
|
|
|
|
|
|
|
dy = p.y() - _falseNorthing;
|
|
|
|
dx = p.x() - _falseEasting;
|
|
|
|
rho_olat_minus_dy = _rho_olat - dy;
|
|
|
|
rho = sqrt(dx * dx + (rho_olat_minus_dy) * (rho_olat_minus_dy));
|
|
|
|
|
|
|
|
if (_n < 0.0) {
|
|
|
|
rho *= -1.0;
|
|
|
|
dx *= -1.0;
|
|
|
|
rho_olat_minus_dy *= -1.0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (rho != 0.0) {
|
|
|
|
theta = atan2(dx, rho_olat_minus_dy) / _n;
|
|
|
|
t = _t0 * pow(rho / _rho0, 1 / _n);
|
|
|
|
PHI = M_PI_2 - 2.0 * atan(t);
|
|
|
|
while (fabs(PHI - tempPHI) > tolerance && count) {
|
|
|
|
tempPHI = PHI;
|
2018-05-17 22:41:56 +02:00
|
|
|
es_sin = _e * sin(PHI);
|
2018-01-08 23:47:45 +01:00
|
|
|
PHI = M_PI_2 - 2.0 * atan(t * pow((1.0 - es_sin) / (1.0 + es_sin),
|
2018-05-17 22:41:56 +02:00
|
|
|
_e_over_2));
|
2018-01-08 23:47:45 +01:00
|
|
|
count--;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!count)
|
|
|
|
return Coordinates();
|
2017-04-02 22:17:16 +02:00
|
|
|
|
2018-01-08 23:47:45 +01:00
|
|
|
lat = PHI;
|
|
|
|
lon = theta + _longitudeOrigin;
|
2017-04-02 22:17:16 +02:00
|
|
|
|
2018-01-08 23:47:45 +01:00
|
|
|
if (fabs(lat) < 2.0e-7)
|
|
|
|
lat = 0.0;
|
|
|
|
if (lat > M_PI_2)
|
|
|
|
lat = M_PI_2;
|
|
|
|
else if (lat < -M_PI_2)
|
|
|
|
lat = -M_PI_2;
|
2017-04-02 22:17:16 +02:00
|
|
|
|
2018-01-08 23:47:45 +01:00
|
|
|
if (lon > M_PI) {
|
|
|
|
if (lon - M_PI < 3.5e-6)
|
|
|
|
lon = M_PI;
|
|
|
|
else
|
2018-05-15 21:51:56 +02:00
|
|
|
lon -= M_2_PI;
|
2018-01-08 23:47:45 +01:00
|
|
|
}
|
|
|
|
if (lon < -M_PI) {
|
|
|
|
if (fabs(lon + M_PI) < 3.5e-6)
|
|
|
|
lon = -M_PI;
|
|
|
|
else
|
2018-05-15 21:51:56 +02:00
|
|
|
lon += M_2_PI;
|
2018-01-08 23:47:45 +01:00
|
|
|
}
|
2017-04-02 22:17:16 +02:00
|
|
|
|
2018-01-08 23:47:45 +01:00
|
|
|
if (fabs(lon) < 2.0e-7)
|
|
|
|
lon = 0.0;
|
|
|
|
if (lon > M_PI)
|
|
|
|
lon = M_PI;
|
|
|
|
else if (lon < -M_PI)
|
|
|
|
lon = -M_PI;
|
|
|
|
} else {
|
|
|
|
if (_n > 0.0)
|
|
|
|
lat = M_PI_2;
|
|
|
|
else
|
|
|
|
lat = -M_PI_2;
|
|
|
|
lon = _longitudeOrigin;
|
|
|
|
}
|
|
|
|
|
|
|
|
return Coordinates(rad2deg(lon), rad2deg(lat));
|
2017-04-02 22:17:16 +02:00
|
|
|
}
|
|
|
|
|
2018-01-20 20:13:56 +01:00
|
|
|
LambertConic2::LambertConic2(const Ellipsoid *ellipsoid,
|
2018-01-08 23:47:45 +01:00
|
|
|
double standardParallel1, double standardParallel2, double latitudeOrigin,
|
|
|
|
double longitudeOrigin, double falseEasting, double falseNorthing)
|
2017-04-02 22:17:16 +02:00
|
|
|
{
|
2018-05-18 00:21:59 +02:00
|
|
|
double e, e_over_2, e_sin;
|
2018-01-08 23:47:45 +01:00
|
|
|
double lat0;
|
|
|
|
double k0;
|
|
|
|
double t0;
|
|
|
|
double t1, t2;
|
|
|
|
double t_olat;
|
|
|
|
double m0;
|
|
|
|
double m1;
|
|
|
|
double m2;
|
|
|
|
double n;
|
|
|
|
double const_value;
|
|
|
|
double sp1, sp2;
|
|
|
|
double lat_orig;
|
|
|
|
|
|
|
|
|
|
|
|
lat_orig = deg2rad(latitudeOrigin);
|
|
|
|
sp1 = deg2rad(standardParallel1);
|
|
|
|
sp2 = deg2rad(standardParallel2);
|
|
|
|
|
|
|
|
if (fabs(sp1 - sp2) > 1.0e-10) {
|
2018-05-18 00:21:59 +02:00
|
|
|
e = sqrt(ellipsoid->es());
|
|
|
|
e_over_2 = e / 2.0;
|
2018-01-08 23:47:45 +01:00
|
|
|
|
2018-05-18 00:21:59 +02:00
|
|
|
e_sin = e * sin(lat_orig);
|
|
|
|
t_olat = LAMBERT2_t(lat_orig, e_sin, e_over_2);
|
2017-04-02 22:17:16 +02:00
|
|
|
|
2018-05-18 00:21:59 +02:00
|
|
|
e_sin = e * sin(sp1);
|
|
|
|
m1 = LAMBERT_m(cos(sp1), e_sin);
|
|
|
|
t1 = LAMBERT2_t(sp1, e_sin, e_over_2);
|
2018-01-08 23:47:45 +01:00
|
|
|
|
2018-05-18 00:21:59 +02:00
|
|
|
e_sin = e * sin(sp2);
|
|
|
|
m2 = LAMBERT_m(cos(sp2), e_sin);
|
|
|
|
t2 = LAMBERT2_t(sp2, e_sin, e_over_2);
|
2018-01-08 23:47:45 +01:00
|
|
|
|
|
|
|
n = log(m1 / m2) / log(t1 / t2);
|
|
|
|
|
|
|
|
lat0 = asin(n);
|
|
|
|
|
2018-05-18 00:21:59 +02:00
|
|
|
e_sin = e * sin(lat0);
|
|
|
|
m0 = LAMBERT_m(cos(lat0), e_sin);
|
|
|
|
t0 = LAMBERT2_t(lat0, e_sin, e_over_2);
|
2018-01-08 23:47:45 +01:00
|
|
|
|
|
|
|
k0 = (m1 / m0) * (pow(t0 / t1, n));
|
|
|
|
|
2018-01-20 20:13:56 +01:00
|
|
|
const_value = ((ellipsoid->radius() * m2) / (n * pow(t2, n)));
|
2018-01-08 23:47:45 +01:00
|
|
|
|
|
|
|
falseNorthing += (const_value * pow(t_olat, n)) - (const_value
|
|
|
|
* pow(t0, n));
|
|
|
|
} else {
|
|
|
|
lat0 = sp1;
|
|
|
|
k0 = 1.0;
|
|
|
|
}
|
|
|
|
|
|
|
|
_lc1 = LambertConic1(ellipsoid, rad2deg(lat0), longitudeOrigin, k0,
|
|
|
|
falseEasting, falseNorthing);
|
2017-04-02 22:17:16 +02:00
|
|
|
}
|
|
|
|
|
2018-04-15 16:27:47 +02:00
|
|
|
PointD LambertConic2::ll2xy(const Coordinates &c) const
|
2017-04-02 22:17:16 +02:00
|
|
|
{
|
2018-01-08 23:47:45 +01:00
|
|
|
return _lc1.ll2xy(c);
|
|
|
|
}
|
2017-04-02 22:17:16 +02:00
|
|
|
|
2018-04-15 16:27:47 +02:00
|
|
|
Coordinates LambertConic2::xy2ll(const PointD &p) const
|
2018-01-08 23:47:45 +01:00
|
|
|
{
|
|
|
|
return _lc1.xy2ll(p);
|
2017-04-02 22:17:16 +02:00
|
|
|
}
|