File indexing completed on 2025-01-18 09:35:40
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026
0027
0028
0029
0030
0031
0032
0033
0034
0035
0036
0037
0038
0039
0040
0041
0042
0043
0044 #ifndef BOOST_GEOMETRY_PROJECTIONS_AEQD_HPP
0045 #define BOOST_GEOMETRY_PROJECTIONS_AEQD_HPP
0046
0047
0048 #include <type_traits>
0049
0050 #include <boost/config.hpp>
0051
0052 #include <boost/geometry/formulas/vincenty_direct.hpp>
0053 #include <boost/geometry/formulas/vincenty_inverse.hpp>
0054
0055 #include <boost/geometry/srs/projections/impl/aasincos.hpp>
0056 #include <boost/geometry/srs/projections/impl/base_static.hpp>
0057 #include <boost/geometry/srs/projections/impl/base_dynamic.hpp>
0058 #include <boost/geometry/srs/projections/impl/factory_entry.hpp>
0059 #include <boost/geometry/srs/projections/impl/pj_mlfn.hpp>
0060 #include <boost/geometry/srs/projections/impl/pj_param.hpp>
0061 #include <boost/geometry/srs/projections/impl/projects.hpp>
0062
0063 #include <boost/geometry/util/math.hpp>
0064
0065 #include <boost/math/special_functions/hypot.hpp>
0066
0067
0068 namespace boost { namespace geometry
0069 {
0070
0071 namespace projections
0072 {
0073 #ifndef DOXYGEN_NO_DETAIL
0074 namespace detail { namespace aeqd
0075 {
0076
0077 static const double epsilon10 = 1.e-10;
0078 static const double tolerance = 1.e-14;
0079 enum mode_type {
0080 n_pole = 0,
0081 s_pole = 1,
0082 equit = 2,
0083 obliq = 3
0084 };
0085
0086 template <typename T>
0087 struct par_aeqd
0088 {
0089 T sinph0;
0090 T cosph0;
0091 detail::en<T> en;
0092 T M1;
0093
0094 T Mp;
0095
0096
0097 T b;
0098 mode_type mode;
0099 };
0100
0101 template <typename T, typename Par, typename ProjParm>
0102 inline void e_forward(T const& lp_lon, T const& lp_lat, T& xy_x, T& xy_y, Par const& par, ProjParm const& proj_parm)
0103 {
0104 T coslam, cosphi, sinphi, rho;
0105
0106
0107
0108 coslam = cos(lp_lon);
0109 cosphi = cos(lp_lat);
0110 sinphi = sin(lp_lat);
0111 switch (proj_parm.mode) {
0112 case n_pole:
0113 coslam = - coslam;
0114 BOOST_FALLTHROUGH;
0115 case s_pole:
0116 xy_x = (rho = fabs(proj_parm.Mp - pj_mlfn(lp_lat, sinphi, cosphi, proj_parm.en))) *
0117 sin(lp_lon);
0118 xy_y = rho * coslam;
0119 break;
0120 case equit:
0121 case obliq:
0122 if (fabs(lp_lon) < epsilon10 && fabs(lp_lat - par.phi0) < epsilon10) {
0123 xy_x = xy_y = 0.;
0124 break;
0125 }
0126
0127
0128
0129
0130 formula::result_inverse<T> const inv =
0131 formula::vincenty_inverse
0132 <
0133 T, true, true
0134 >::apply(par.lam0, par.phi0, lp_lon + par.lam0, lp_lat, srs::spheroid<T>(par.a, proj_parm.b));
0135
0136 xy_x = inv.distance * sin(inv.azimuth) / par.a;
0137 xy_y = inv.distance * cos(inv.azimuth) / par.a;
0138 break;
0139 }
0140 }
0141
0142 template <typename T, typename Par, typename ProjParm>
0143 inline void e_inverse(T const& xy_x, T const& xy_y, T& lp_lon, T& lp_lat, Par const& par, ProjParm const& proj_parm)
0144 {
0145 T c;
0146
0147 if ((c = boost::math::hypot(xy_x, xy_y)) < epsilon10) {
0148 lp_lat = par.phi0;
0149 lp_lon = 0.;
0150 return;
0151 }
0152 if (proj_parm.mode == obliq || proj_parm.mode == equit) {
0153 T const x2 = xy_x * par.a;
0154 T const y2 = xy_y * par.a;
0155
0156
0157 T const azi1 = atan2(x2, y2);
0158 T const s12 = sqrt(x2 * x2 + y2 * y2);
0159 formula::result_direct<T> const dir =
0160 formula::vincenty_direct
0161 <
0162 T, true
0163 >::apply(par.lam0, par.phi0, s12, azi1, srs::spheroid<T>(par.a, proj_parm.b));
0164 lp_lat = dir.lat2;
0165 lp_lon = dir.lon2;
0166 lp_lon -= par.lam0;
0167 } else {
0168 lp_lat = pj_inv_mlfn(proj_parm.mode == n_pole ? proj_parm.Mp - c : proj_parm.Mp + c,
0169 par.es, proj_parm.en);
0170 lp_lon = atan2(xy_x, proj_parm.mode == n_pole ? -xy_y : xy_y);
0171 }
0172 }
0173
0174 template <typename T, typename Par, typename ProjParm>
0175 inline void e_guam_fwd(T const& lp_lon, T const& lp_lat, T& xy_x, T& xy_y, Par const& par, ProjParm const& proj_parm)
0176 {
0177 T cosphi, sinphi, t;
0178
0179 cosphi = cos(lp_lat);
0180 sinphi = sin(lp_lat);
0181 t = 1. / sqrt(1. - par.es * sinphi * sinphi);
0182 xy_x = lp_lon * cosphi * t;
0183 xy_y = pj_mlfn(lp_lat, sinphi, cosphi, proj_parm.en) - proj_parm.M1 +
0184 .5 * lp_lon * lp_lon * cosphi * sinphi * t;
0185 }
0186
0187 template <typename T, typename Par, typename ProjParm>
0188 inline void e_guam_inv(T const& xy_x, T const& xy_y, T& lp_lon, T& lp_lat, Par const& par, ProjParm const& proj_parm)
0189 {
0190 T x2, t = 0.0;
0191 int i;
0192
0193 x2 = 0.5 * xy_x * xy_x;
0194 lp_lat = par.phi0;
0195 for (i = 0; i < 3; ++i) {
0196 t = par.e * sin(lp_lat);
0197 lp_lat = pj_inv_mlfn(proj_parm.M1 + xy_y -
0198 x2 * tan(lp_lat) * (t = sqrt(1. - t * t)), par.es, proj_parm.en);
0199 }
0200 lp_lon = xy_x * t / cos(lp_lat);
0201 }
0202
0203 template <typename T, typename Par, typename ProjParm>
0204 inline void s_forward(T const& lp_lon, T lp_lat, T& xy_x, T& xy_y, Par const& , ProjParm const& proj_parm)
0205 {
0206 static const T half_pi = detail::half_pi<T>();
0207
0208 T coslam, cosphi, sinphi;
0209
0210 sinphi = sin(lp_lat);
0211 cosphi = cos(lp_lat);
0212 coslam = cos(lp_lon);
0213 switch (proj_parm.mode) {
0214 case equit:
0215 xy_y = cosphi * coslam;
0216 goto oblcon;
0217 case obliq:
0218 xy_y = proj_parm.sinph0 * sinphi + proj_parm.cosph0 * cosphi * coslam;
0219 oblcon:
0220 if (fabs(fabs(xy_y) - 1.) < tolerance)
0221 if (xy_y < 0.)
0222 BOOST_THROW_EXCEPTION( projection_exception(error_tolerance_condition) );
0223 else
0224 xy_x = xy_y = 0.;
0225 else {
0226 xy_y = acos(xy_y);
0227 xy_y /= sin(xy_y);
0228 xy_x = xy_y * cosphi * sin(lp_lon);
0229 xy_y *= (proj_parm.mode == equit) ? sinphi :
0230 proj_parm.cosph0 * sinphi - proj_parm.sinph0 * cosphi * coslam;
0231 }
0232 break;
0233 case n_pole:
0234 lp_lat = -lp_lat;
0235 coslam = -coslam;
0236 BOOST_FALLTHROUGH;
0237 case s_pole:
0238 if (fabs(lp_lat - half_pi) < epsilon10)
0239 BOOST_THROW_EXCEPTION( projection_exception(error_tolerance_condition) );
0240 xy_x = (xy_y = (half_pi + lp_lat)) * sin(lp_lon);
0241 xy_y *= coslam;
0242 break;
0243 }
0244 }
0245
0246 template <typename T, typename Par, typename ProjParm>
0247 inline void s_inverse(T xy_x, T xy_y, T& lp_lon, T& lp_lat, Par const& par, ProjParm const& proj_parm)
0248 {
0249 static const T pi = detail::pi<T>();
0250 static const T half_pi = detail::half_pi<T>();
0251
0252 T cosc, c_rh, sinc;
0253
0254 if ((c_rh = boost::math::hypot(xy_x, xy_y)) > pi) {
0255 if (c_rh - epsilon10 > pi)
0256 BOOST_THROW_EXCEPTION( projection_exception(error_tolerance_condition) );
0257 c_rh = pi;
0258 } else if (c_rh < epsilon10) {
0259 lp_lat = par.phi0;
0260 lp_lon = 0.;
0261 return;
0262 }
0263 if (proj_parm.mode == obliq || proj_parm.mode == equit) {
0264 sinc = sin(c_rh);
0265 cosc = cos(c_rh);
0266 if (proj_parm.mode == equit) {
0267 lp_lat = aasin(xy_y * sinc / c_rh);
0268 xy_x *= sinc;
0269 xy_y = cosc * c_rh;
0270 } else {
0271 lp_lat = aasin(cosc * proj_parm.sinph0 + xy_y * sinc * proj_parm.cosph0 /
0272 c_rh);
0273 xy_y = (cosc - proj_parm.sinph0 * sin(lp_lat)) * c_rh;
0274 xy_x *= sinc * proj_parm.cosph0;
0275 }
0276 lp_lon = xy_y == 0. ? 0. : atan2(xy_x, xy_y);
0277 } else if (proj_parm.mode == n_pole) {
0278 lp_lat = half_pi - c_rh;
0279 lp_lon = atan2(xy_x, -xy_y);
0280 } else {
0281 lp_lat = c_rh - half_pi;
0282 lp_lon = atan2(xy_x, xy_y);
0283 }
0284 }
0285
0286
0287 template <typename Params, typename Parameters, typename T>
0288 inline void setup_aeqd(Params const& params, Parameters& par, par_aeqd<T>& proj_parm, bool is_sphere, bool is_guam)
0289 {
0290 static const T half_pi = detail::half_pi<T>();
0291
0292 par.phi0 = pj_get_param_r<T, srs::spar::lat_0>(params, "lat_0", srs::dpar::lat_0);
0293 if (fabs(fabs(par.phi0) - half_pi) < epsilon10) {
0294 proj_parm.mode = par.phi0 < 0. ? s_pole : n_pole;
0295 proj_parm.sinph0 = par.phi0 < 0. ? -1. : 1.;
0296 proj_parm.cosph0 = 0.;
0297 } else if (fabs(par.phi0) < epsilon10) {
0298 proj_parm.mode = equit;
0299 proj_parm.sinph0 = 0.;
0300 proj_parm.cosph0 = 1.;
0301 } else {
0302 proj_parm.mode = obliq;
0303 proj_parm.sinph0 = sin(par.phi0);
0304 proj_parm.cosph0 = cos(par.phi0);
0305 }
0306 if (is_sphere) {
0307
0308 } else {
0309 proj_parm.en = pj_enfn<T>(par.es);
0310 if (is_guam) {
0311 proj_parm.M1 = pj_mlfn(par.phi0, proj_parm.sinph0, proj_parm.cosph0, proj_parm.en);
0312 } else {
0313 switch (proj_parm.mode) {
0314 case n_pole:
0315 proj_parm.Mp = pj_mlfn<T>(half_pi, 1., 0., proj_parm.en);
0316 break;
0317 case s_pole:
0318 proj_parm.Mp = pj_mlfn<T>(-half_pi, -1., 0., proj_parm.en);
0319 break;
0320 case equit:
0321 case obliq:
0322
0323
0324
0325 break;
0326 }
0327
0328 proj_parm.b = math::sqrt(math::sqr(par.a) * (1. - par.es));
0329 }
0330 }
0331 }
0332
0333 template <typename T, typename Parameters>
0334 struct base_aeqd_e
0335 {
0336 par_aeqd<T> m_proj_parm;
0337
0338
0339
0340 inline void fwd(Parameters const& par, T const& lp_lon, T const& lp_lat, T& xy_x, T& xy_y) const
0341 {
0342 e_forward(lp_lon, lp_lat, xy_x, xy_y, par, this->m_proj_parm);
0343 }
0344
0345
0346
0347 inline void inv(Parameters const& par, T const& xy_x, T const& xy_y, T& lp_lon, T& lp_lat) const
0348 {
0349 e_inverse(xy_x, xy_y, lp_lon, lp_lat, par, this->m_proj_parm);
0350 }
0351
0352 static inline std::string get_name()
0353 {
0354 return "aeqd_e";
0355 }
0356
0357 };
0358
0359 template <typename T, typename Parameters>
0360 struct base_aeqd_e_guam
0361 {
0362 par_aeqd<T> m_proj_parm;
0363
0364
0365
0366 inline void fwd(Parameters const& par, T const& lp_lon, T const& lp_lat, T& xy_x, T& xy_y) const
0367 {
0368 e_guam_fwd(lp_lon, lp_lat, xy_x, xy_y, par, this->m_proj_parm);
0369 }
0370
0371
0372
0373 inline void inv(Parameters const& par, T const& xy_x, T const& xy_y, T& lp_lon, T& lp_lat) const
0374 {
0375 e_guam_inv(xy_x, xy_y, lp_lon, lp_lat, par, this->m_proj_parm);
0376 }
0377
0378 static inline std::string get_name()
0379 {
0380 return "aeqd_e_guam";
0381 }
0382
0383 };
0384
0385 template <typename T, typename Parameters>
0386 struct base_aeqd_s
0387 {
0388 par_aeqd<T> m_proj_parm;
0389
0390
0391
0392 inline void fwd(Parameters const& par, T const& lp_lon, T const& lp_lat, T& xy_x, T& xy_y) const
0393 {
0394 s_forward(lp_lon, lp_lat, xy_x, xy_y, par, this->m_proj_parm);
0395 }
0396
0397
0398
0399 inline void inv(Parameters const& par, T const& xy_x, T const& xy_y, T& lp_lon, T& lp_lat) const
0400 {
0401 s_inverse(xy_x, xy_y, lp_lon, lp_lat, par, this->m_proj_parm);
0402 }
0403
0404 static inline std::string get_name()
0405 {
0406 return "aeqd_s";
0407 }
0408
0409 };
0410
0411 }}
0412 #endif
0413
0414
0415
0416
0417
0418
0419
0420
0421
0422
0423
0424
0425
0426
0427
0428
0429
0430 template <typename T, typename Parameters>
0431 struct aeqd_e : public detail::aeqd::base_aeqd_e<T, Parameters>
0432 {
0433 template <typename Params>
0434 inline aeqd_e(Params const& params, Parameters & par)
0435 {
0436 detail::aeqd::setup_aeqd(params, par, this->m_proj_parm, false, false);
0437 }
0438 };
0439
0440
0441
0442
0443
0444
0445
0446
0447
0448
0449
0450
0451
0452
0453
0454
0455
0456 template <typename T, typename Parameters>
0457 struct aeqd_e_guam : public detail::aeqd::base_aeqd_e_guam<T, Parameters>
0458 {
0459 template <typename Params>
0460 inline aeqd_e_guam(Params const& params, Parameters & par)
0461 {
0462 detail::aeqd::setup_aeqd(params, par, this->m_proj_parm, false, true);
0463 }
0464 };
0465
0466
0467
0468
0469
0470
0471
0472
0473
0474
0475
0476
0477
0478
0479
0480
0481
0482 template <typename T, typename Parameters>
0483 struct aeqd_s : public detail::aeqd::base_aeqd_s<T, Parameters>
0484 {
0485 template <typename Params>
0486 inline aeqd_s(Params const& params, Parameters & par)
0487 {
0488 detail::aeqd::setup_aeqd(params, par, this->m_proj_parm, true, false);
0489 }
0490 };
0491
0492 #ifndef DOXYGEN_NO_DETAIL
0493 namespace detail
0494 {
0495
0496
0497 template <typename BGP, typename CT, typename P>
0498 struct static_projection_type<srs::spar::proj_aeqd, srs_sphere_tag, BGP, CT, P>
0499 {
0500 typedef static_wrapper_fi<aeqd_s<CT, P>, P> type;
0501 };
0502 template <typename BGP, typename CT, typename P>
0503 struct static_projection_type<srs::spar::proj_aeqd, srs_spheroid_tag, BGP, CT, P>
0504 {
0505 typedef static_wrapper_fi
0506 <
0507 std::conditional_t
0508 <
0509 std::is_void
0510 <
0511 typename geometry::tuples::find_if
0512 <
0513 BGP,
0514
0515 srs::spar::detail::is_param<srs::spar::guam>::pred
0516 >::type
0517 >::value,
0518 aeqd_e<CT, P>,
0519 aeqd_e_guam<CT, P>
0520 >
0521 , P
0522 > type;
0523 };
0524
0525 BOOST_GEOMETRY_PROJECTIONS_DETAIL_FACTORY_ENTRY_BEGIN(aeqd_entry)
0526 {
0527 bool const guam = pj_get_param_b<srs::spar::guam>(params, "guam", srs::dpar::guam);
0528
0529 if (parameters.es && ! guam)
0530 return new dynamic_wrapper_fi<aeqd_e<T, Parameters>, T, Parameters>(params, parameters);
0531 else if (parameters.es && guam)
0532 return new dynamic_wrapper_fi<aeqd_e_guam<T, Parameters>, T, Parameters>(params, parameters);
0533 else
0534 return new dynamic_wrapper_fi<aeqd_s<T, Parameters>, T, Parameters>(params, parameters);
0535 }
0536 BOOST_GEOMETRY_PROJECTIONS_DETAIL_FACTORY_ENTRY_END
0537
0538 BOOST_GEOMETRY_PROJECTIONS_DETAIL_FACTORY_INIT_BEGIN(aeqd_init)
0539 {
0540 BOOST_GEOMETRY_PROJECTIONS_DETAIL_FACTORY_INIT_ENTRY(aeqd, aeqd_entry)
0541 }
0542
0543 }
0544 #endif
0545
0546 }
0547
0548 }}
0549
0550 #endif
0551