123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530 |
- #ifndef BOOST_GEOMETRY_PROJECTIONS_QSC_HPP
- #define BOOST_GEOMETRY_PROJECTIONS_QSC_HPP
- #include <boost/core/ignore_unused.hpp>
- #include <boost/geometry/util/math.hpp>
- #include <boost/geometry/srs/projections/impl/base_static.hpp>
- #include <boost/geometry/srs/projections/impl/base_dynamic.hpp>
- #include <boost/geometry/srs/projections/impl/projects.hpp>
- #include <boost/geometry/srs/projections/impl/factory_entry.hpp>
- namespace boost { namespace geometry
- {
- namespace projections
- {
- #ifndef DOXYGEN_NO_DETAIL
- namespace detail { namespace qsc
- {
-
- enum face_type {
- face_front = 0,
- face_right = 1,
- face_back = 2,
- face_left = 3,
- face_top = 4,
- face_bottom = 5
- };
- template <typename T>
- struct par_qsc
- {
- T a_squared;
- T b;
- T one_minus_f;
- T one_minus_f_squared;
- face_type face;
- };
- static const double epsilon10 = 1.e-10;
-
- enum area_type {
- area_0 = 0,
- area_1 = 1,
- area_2 = 2,
- area_3 = 3
- };
-
- template <typename T>
- inline T qsc_fwd_equat_face_theta(T const& phi, T const& y, T const& x, area_type *area)
- {
- static const T fourth_pi = detail::fourth_pi<T>();
- static const T half_pi = detail::half_pi<T>();
- static const T pi = detail::pi<T>();
- T theta;
- if (phi < epsilon10) {
- *area = area_0;
- theta = 0.0;
- } else {
- theta = atan2(y, x);
- if (fabs(theta) <= fourth_pi) {
- *area = area_0;
- } else if (theta > fourth_pi && theta <= half_pi + fourth_pi) {
- *area = area_1;
- theta -= half_pi;
- } else if (theta > half_pi + fourth_pi || theta <= -(half_pi + fourth_pi)) {
- *area = area_2;
- theta = (theta >= 0.0 ? theta - pi : theta + pi);
- } else {
- *area = area_3;
- theta += half_pi;
- }
- }
- return theta;
- }
-
- template <typename T>
- inline T qsc_shift_lon_origin(T const& lon, T const& offset)
- {
- static const T pi = detail::pi<T>();
- static const T two_pi = detail::two_pi<T>();
- T slon = lon + offset;
- if (slon < -pi) {
- slon += two_pi;
- } else if (slon > +pi) {
- slon -= two_pi;
- }
- return slon;
- }
-
- template <typename T, typename Parameters>
- struct base_qsc_ellipsoid
- {
- par_qsc<T> m_proj_parm;
-
-
- inline void fwd(Parameters const& par, T const& lp_lon, T const& lp_lat, T& xy_x, T& xy_y) const
- {
- static const T fourth_pi = detail::fourth_pi<T>();
- static const T half_pi = detail::half_pi<T>();
- static const T pi = detail::pi<T>();
- T lat, lon;
- T theta, phi;
- T t, mu;
- area_type area;
-
- if (par.es != 0.0) {
- lat = atan(this->m_proj_parm.one_minus_f_squared * tan(lp_lat));
- } else {
- lat = lp_lat;
- }
-
- lon = lp_lon;
- if (this->m_proj_parm.face == face_top) {
- phi = half_pi - lat;
- if (lon >= fourth_pi && lon <= half_pi + fourth_pi) {
- area = area_0;
- theta = lon - half_pi;
- } else if (lon > half_pi + fourth_pi || lon <= -(half_pi + fourth_pi)) {
- area = area_1;
- theta = (lon > 0.0 ? lon - pi : lon + pi);
- } else if (lon > -(half_pi + fourth_pi) && lon <= -fourth_pi) {
- area = area_2;
- theta = lon + half_pi;
- } else {
- area = area_3;
- theta = lon;
- }
- } else if (this->m_proj_parm.face == face_bottom) {
- phi = half_pi + lat;
- if (lon >= fourth_pi && lon <= half_pi + fourth_pi) {
- area = area_0;
- theta = -lon + half_pi;
- } else if (lon < fourth_pi && lon >= -fourth_pi) {
- area = area_1;
- theta = -lon;
- } else if (lon < -fourth_pi && lon >= -(half_pi + fourth_pi)) {
- area = area_2;
- theta = -lon - half_pi;
- } else {
- area = area_3;
- theta = (lon > 0.0 ? -lon + pi : -lon - pi);
- }
- } else {
- T q, r, s;
- T sinlat, coslat;
- T sinlon, coslon;
- if (this->m_proj_parm.face == face_right) {
- lon = qsc_shift_lon_origin(lon, +half_pi);
- } else if (this->m_proj_parm.face == face_back) {
- lon = qsc_shift_lon_origin(lon, +pi);
- } else if (this->m_proj_parm.face == face_left) {
- lon = qsc_shift_lon_origin(lon, -half_pi);
- }
- sinlat = sin(lat);
- coslat = cos(lat);
- sinlon = sin(lon);
- coslon = cos(lon);
- q = coslat * coslon;
- r = coslat * sinlon;
- s = sinlat;
- if (this->m_proj_parm.face == face_front) {
- phi = acos(q);
- theta = qsc_fwd_equat_face_theta(phi, s, r, &area);
- } else if (this->m_proj_parm.face == face_right) {
- phi = acos(r);
- theta = qsc_fwd_equat_face_theta(phi, s, -q, &area);
- } else if (this->m_proj_parm.face == face_back) {
- phi = acos(-q);
- theta = qsc_fwd_equat_face_theta(phi, s, -r, &area);
- } else if (this->m_proj_parm.face == face_left) {
- phi = acos(-r);
- theta = qsc_fwd_equat_face_theta(phi, s, q, &area);
- } else {
-
- phi = theta = 0.0;
- area = area_0;
- }
- }
-
- mu = atan((12.0 / pi) * (theta + acos(sin(theta) * cos(fourth_pi)) - half_pi));
-
- t = sqrt((1.0 - cos(phi)) / (cos(mu) * cos(mu)) / (1.0 - cos(atan(1.0 / cos(theta)))));
-
-
- if (area == area_1) {
- mu += half_pi;
- } else if (area == area_2) {
- mu += pi;
- } else if (area == area_3) {
- mu += half_pi + pi;
- }
-
-
- xy_x = t * cos(mu);
- xy_y = t * sin(mu);
- }
-
-
-
- inline void inv(Parameters const& par, T const& xy_x, T const& xy_y, T& lp_lon, T& lp_lat) const
- {
- static const T half_pi = detail::half_pi<T>();
- static const T pi = detail::pi<T>();
- T mu, nu, cosmu, tannu;
- T tantheta, theta, cosphi, phi;
- T t;
- int area;
-
- nu = atan(sqrt(xy_x * xy_x + xy_y * xy_y));
- mu = atan2(xy_y, xy_x);
- if (xy_x >= 0.0 && xy_x >= fabs(xy_y)) {
- area = area_0;
- } else if (xy_y >= 0.0 && xy_y >= fabs(xy_x)) {
- area = area_1;
- mu -= half_pi;
- } else if (xy_x < 0.0 && -xy_x >= fabs(xy_y)) {
- area = area_2;
- mu = (mu < 0.0 ? mu + pi : mu - pi);
- } else {
- area = area_3;
- mu += half_pi;
- }
-
- t = (pi / 12.0) * tan(mu);
- tantheta = sin(t) / (cos(t) - (1.0 / sqrt(2.0)));
- theta = atan(tantheta);
- cosmu = cos(mu);
- tannu = tan(nu);
- cosphi = 1.0 - cosmu * cosmu * tannu * tannu * (1.0 - cos(atan(1.0 / cos(theta))));
- if (cosphi < -1.0) {
- cosphi = -1.0;
- } else if (cosphi > +1.0) {
- cosphi = +1.0;
- }
-
- if (this->m_proj_parm.face == face_top) {
- phi = acos(cosphi);
- lp_lat = half_pi - phi;
- if (area == area_0) {
- lp_lon = theta + half_pi;
- } else if (area == area_1) {
- lp_lon = (theta < 0.0 ? theta + pi : theta - pi);
- } else if (area == area_2) {
- lp_lon = theta - half_pi;
- } else {
- lp_lon = theta;
- }
- } else if (this->m_proj_parm.face == face_bottom) {
- phi = acos(cosphi);
- lp_lat = phi - half_pi;
- if (area == area_0) {
- lp_lon = -theta + half_pi;
- } else if (area == area_1) {
- lp_lon = -theta;
- } else if (area == area_2) {
- lp_lon = -theta - half_pi;
- } else {
- lp_lon = (theta < 0.0 ? -theta - pi : -theta + pi);
- }
- } else {
-
- T q, r, s;
- q = cosphi;
- t = q * q;
- if (t >= 1.0) {
- s = 0.0;
- } else {
- s = sqrt(1.0 - t) * sin(theta);
- }
- t += s * s;
- if (t >= 1.0) {
- r = 0.0;
- } else {
- r = sqrt(1.0 - t);
- }
-
- if (area == area_1) {
- t = r;
- r = -s;
- s = t;
- } else if (area == area_2) {
- r = -r;
- s = -s;
- } else if (area == area_3) {
- t = r;
- r = s;
- s = -t;
- }
-
- if (this->m_proj_parm.face == face_right) {
- t = q;
- q = -r;
- r = t;
- } else if (this->m_proj_parm.face == face_back) {
- q = -q;
- r = -r;
- } else if (this->m_proj_parm.face == face_left) {
- t = q;
- q = r;
- r = -t;
- }
-
- lp_lat = acos(-s) - half_pi;
- lp_lon = atan2(r, q);
- if (this->m_proj_parm.face == face_right) {
- lp_lon = qsc_shift_lon_origin(lp_lon, -half_pi);
- } else if (this->m_proj_parm.face == face_back) {
- lp_lon = qsc_shift_lon_origin(lp_lon, -pi);
- } else if (this->m_proj_parm.face == face_left) {
- lp_lon = qsc_shift_lon_origin(lp_lon, +half_pi);
- }
- }
-
- if (par.es != 0.0) {
- int invert_sign;
- T tanphi, xa;
- invert_sign = (lp_lat < 0.0 ? 1 : 0);
- tanphi = tan(lp_lat);
- xa = this->m_proj_parm.b / sqrt(tanphi * tanphi + this->m_proj_parm.one_minus_f_squared);
- lp_lat = atan(sqrt(par.a * par.a - xa * xa) / (this->m_proj_parm.one_minus_f * xa));
- if (invert_sign) {
- lp_lat = -lp_lat;
- }
- }
- }
- static inline std::string get_name()
- {
- return "qsc_ellipsoid";
- }
- };
-
- template <typename Parameters, typename T>
- inline void setup_qsc(Parameters const& par, par_qsc<T>& proj_parm)
- {
- static const T fourth_pi = detail::fourth_pi<T>();
- static const T half_pi = detail::half_pi<T>();
-
- if (par.phi0 >= half_pi - fourth_pi / 2.0) {
- proj_parm.face = face_top;
- } else if (par.phi0 <= -(half_pi - fourth_pi / 2.0)) {
- proj_parm.face = face_bottom;
- } else if (fabs(par.lam0) <= fourth_pi) {
- proj_parm.face = face_front;
- } else if (fabs(par.lam0) <= half_pi + fourth_pi) {
- proj_parm.face = (par.lam0 > 0.0 ? face_right : face_left);
- } else {
- proj_parm.face = face_back;
- }
-
- if (par.es != 0.0) {
- proj_parm.a_squared = par.a * par.a;
- proj_parm.b = par.a * sqrt(1.0 - par.es);
- proj_parm.one_minus_f = 1.0 - (par.a - proj_parm.b) / par.a;
- proj_parm.one_minus_f_squared = proj_parm.one_minus_f * proj_parm.one_minus_f;
- }
- }
- }}
- #endif
-
- template <typename T, typename Parameters>
- struct qsc_ellipsoid : public detail::qsc::base_qsc_ellipsoid<T, Parameters>
- {
- template <typename Params>
- inline qsc_ellipsoid(Params const& , Parameters const& par)
- {
- detail::qsc::setup_qsc(par, this->m_proj_parm);
- }
- };
- #ifndef DOXYGEN_NO_DETAIL
- namespace detail
- {
-
- BOOST_GEOMETRY_PROJECTIONS_DETAIL_STATIC_PROJECTION_FI(srs::spar::proj_qsc, qsc_ellipsoid)
-
- BOOST_GEOMETRY_PROJECTIONS_DETAIL_FACTORY_ENTRY_FI(qsc_entry, qsc_ellipsoid)
- BOOST_GEOMETRY_PROJECTIONS_DETAIL_FACTORY_INIT_BEGIN(qsc_init)
- {
- BOOST_GEOMETRY_PROJECTIONS_DETAIL_FACTORY_INIT_ENTRY(qsc, qsc_entry)
- }
- }
- #endif
- }
- }}
- #endif
|