File indexing completed on 2025-01-18 09:35:46
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
0045
0046
0047
0048
0049
0050
0051
0052
0053
0054
0055
0056
0057
0058
0059
0060
0061
0062
0063
0064
0065
0066
0067
0068
0069
0070
0071
0072
0073
0074
0075
0076
0077 #ifndef BOOST_GEOMETRY_PROJECTIONS_QSC_HPP
0078 #define BOOST_GEOMETRY_PROJECTIONS_QSC_HPP
0079
0080 #include <boost/core/ignore_unused.hpp>
0081 #include <boost/geometry/util/math.hpp>
0082
0083 #include <boost/geometry/srs/projections/impl/base_static.hpp>
0084 #include <boost/geometry/srs/projections/impl/base_dynamic.hpp>
0085 #include <boost/geometry/srs/projections/impl/projects.hpp>
0086 #include <boost/geometry/srs/projections/impl/factory_entry.hpp>
0087
0088 namespace boost { namespace geometry
0089 {
0090
0091 namespace projections
0092 {
0093 #ifndef DOXYGEN_NO_DETAIL
0094 namespace detail { namespace qsc
0095 {
0096
0097
0098 enum face_type {
0099 face_front = 0,
0100 face_right = 1,
0101 face_back = 2,
0102 face_left = 3,
0103 face_top = 4,
0104 face_bottom = 5
0105 };
0106
0107 template <typename T>
0108 struct par_qsc
0109 {
0110 T a_squared;
0111 T b;
0112 T one_minus_f;
0113 T one_minus_f_squared;
0114 face_type face;
0115 };
0116
0117 static const double epsilon10 = 1.e-10;
0118
0119
0120
0121 enum area_type {
0122 area_0 = 0,
0123 area_1 = 1,
0124 area_2 = 2,
0125 area_3 = 3
0126 };
0127
0128
0129
0130 template <typename T>
0131 inline T qsc_fwd_equat_face_theta(T const& phi, T const& y, T const& x, area_type *area)
0132 {
0133 static const T fourth_pi = detail::fourth_pi<T>();
0134 static const T half_pi = detail::half_pi<T>();
0135 static const T pi = detail::pi<T>();
0136
0137 T theta;
0138 if (phi < epsilon10) {
0139 *area = area_0;
0140 theta = 0.0;
0141 } else {
0142 theta = atan2(y, x);
0143 if (fabs(theta) <= fourth_pi) {
0144 *area = area_0;
0145 } else if (theta > fourth_pi && theta <= half_pi + fourth_pi) {
0146 *area = area_1;
0147 theta -= half_pi;
0148 } else if (theta > half_pi + fourth_pi || theta <= -(half_pi + fourth_pi)) {
0149 *area = area_2;
0150 theta = (theta >= 0.0 ? theta - pi : theta + pi);
0151 } else {
0152 *area = area_3;
0153 theta += half_pi;
0154 }
0155 }
0156 return theta;
0157 }
0158
0159
0160 template <typename T>
0161 inline T qsc_shift_lon_origin(T const& lon, T const& offset)
0162 {
0163 static const T pi = detail::pi<T>();
0164 static const T two_pi = detail::two_pi<T>();
0165
0166 T slon = lon + offset;
0167 if (slon < -pi) {
0168 slon += two_pi;
0169 } else if (slon > +pi) {
0170 slon -= two_pi;
0171 }
0172 return slon;
0173 }
0174
0175
0176
0177 template <typename T, typename Parameters>
0178 struct base_qsc_ellipsoid
0179 {
0180 par_qsc<T> m_proj_parm;
0181
0182
0183
0184 inline void fwd(Parameters const& par, T const& lp_lon, T const& lp_lat, T& xy_x, T& xy_y) const
0185 {
0186 static const T fourth_pi = detail::fourth_pi<T>();
0187 static const T half_pi = detail::half_pi<T>();
0188 static const T pi = detail::pi<T>();
0189
0190 T lat, lon;
0191 T theta, phi;
0192 T t, mu;
0193 area_type area;
0194
0195
0196
0197
0198 if (par.es != 0.0) {
0199 lat = atan(this->m_proj_parm.one_minus_f_squared * tan(lp_lat));
0200 } else {
0201 lat = lp_lat;
0202 }
0203
0204
0205
0206
0207
0208
0209 lon = lp_lon;
0210 if (this->m_proj_parm.face == face_top) {
0211 phi = half_pi - lat;
0212 if (lon >= fourth_pi && lon <= half_pi + fourth_pi) {
0213 area = area_0;
0214 theta = lon - half_pi;
0215 } else if (lon > half_pi + fourth_pi || lon <= -(half_pi + fourth_pi)) {
0216 area = area_1;
0217 theta = (lon > 0.0 ? lon - pi : lon + pi);
0218 } else if (lon > -(half_pi + fourth_pi) && lon <= -fourth_pi) {
0219 area = area_2;
0220 theta = lon + half_pi;
0221 } else {
0222 area = area_3;
0223 theta = lon;
0224 }
0225 } else if (this->m_proj_parm.face == face_bottom) {
0226 phi = half_pi + lat;
0227 if (lon >= fourth_pi && lon <= half_pi + fourth_pi) {
0228 area = area_0;
0229 theta = -lon + half_pi;
0230 } else if (lon < fourth_pi && lon >= -fourth_pi) {
0231 area = area_1;
0232 theta = -lon;
0233 } else if (lon < -fourth_pi && lon >= -(half_pi + fourth_pi)) {
0234 area = area_2;
0235 theta = -lon - half_pi;
0236 } else {
0237 area = area_3;
0238 theta = (lon > 0.0 ? -lon + pi : -lon - pi);
0239 }
0240 } else {
0241 T q, r, s;
0242 T sinlat, coslat;
0243 T sinlon, coslon;
0244
0245 if (this->m_proj_parm.face == face_right) {
0246 lon = qsc_shift_lon_origin(lon, +half_pi);
0247 } else if (this->m_proj_parm.face == face_back) {
0248 lon = qsc_shift_lon_origin(lon, +pi);
0249 } else if (this->m_proj_parm.face == face_left) {
0250 lon = qsc_shift_lon_origin(lon, -half_pi);
0251 }
0252 sinlat = sin(lat);
0253 coslat = cos(lat);
0254 sinlon = sin(lon);
0255 coslon = cos(lon);
0256 q = coslat * coslon;
0257 r = coslat * sinlon;
0258 s = sinlat;
0259
0260 if (this->m_proj_parm.face == face_front) {
0261 phi = acos(q);
0262 theta = qsc_fwd_equat_face_theta(phi, s, r, &area);
0263 } else if (this->m_proj_parm.face == face_right) {
0264 phi = acos(r);
0265 theta = qsc_fwd_equat_face_theta(phi, s, -q, &area);
0266 } else if (this->m_proj_parm.face == face_back) {
0267 phi = acos(-q);
0268 theta = qsc_fwd_equat_face_theta(phi, s, -r, &area);
0269 } else if (this->m_proj_parm.face == face_left) {
0270 phi = acos(-r);
0271 theta = qsc_fwd_equat_face_theta(phi, s, q, &area);
0272 } else {
0273
0274 phi = theta = 0.0;
0275 area = area_0;
0276 }
0277 }
0278
0279
0280
0281
0282 mu = atan((12.0 / pi) * (theta + acos(sin(theta) * cos(fourth_pi)) - half_pi));
0283
0284 t = sqrt((1.0 - cos(phi)) / (cos(mu) * cos(mu)) / (1.0 - cos(atan(1.0 / cos(theta)))));
0285
0286
0287
0288 if (area == area_1) {
0289 mu += half_pi;
0290 } else if (area == area_2) {
0291 mu += pi;
0292 } else if (area == area_3) {
0293 mu += half_pi + pi;
0294 }
0295
0296
0297
0298 xy_x = t * cos(mu);
0299 xy_y = t * sin(mu);
0300 }
0301
0302
0303
0304
0305 inline void inv(Parameters const& par, T const& xy_x, T const& xy_y, T& lp_lon, T& lp_lat) const
0306 {
0307 static const T half_pi = detail::half_pi<T>();
0308 static const T pi = detail::pi<T>();
0309
0310 T mu, nu, cosmu, tannu;
0311 T tantheta, theta, cosphi, phi;
0312 T t;
0313 int area;
0314
0315
0316
0317 nu = atan(sqrt(xy_x * xy_x + xy_y * xy_y));
0318 mu = atan2(xy_y, xy_x);
0319 if (xy_x >= 0.0 && xy_x >= fabs(xy_y)) {
0320 area = area_0;
0321 } else if (xy_y >= 0.0 && xy_y >= fabs(xy_x)) {
0322 area = area_1;
0323 mu -= half_pi;
0324 } else if (xy_x < 0.0 && -xy_x >= fabs(xy_y)) {
0325 area = area_2;
0326 mu = (mu < 0.0 ? mu + pi : mu - pi);
0327 } else {
0328 area = area_3;
0329 mu += half_pi;
0330 }
0331
0332
0333
0334
0335
0336
0337 t = (pi / 12.0) * tan(mu);
0338 tantheta = sin(t) / (cos(t) - (1.0 / sqrt(2.0)));
0339 theta = atan(tantheta);
0340 cosmu = cos(mu);
0341 tannu = tan(nu);
0342 cosphi = 1.0 - cosmu * cosmu * tannu * tannu * (1.0 - cos(atan(1.0 / cos(theta))));
0343 if (cosphi < -1.0) {
0344 cosphi = -1.0;
0345 } else if (cosphi > +1.0) {
0346 cosphi = +1.0;
0347 }
0348
0349
0350
0351
0352
0353 if (this->m_proj_parm.face == face_top) {
0354 phi = acos(cosphi);
0355 lp_lat = half_pi - phi;
0356 if (area == area_0) {
0357 lp_lon = theta + half_pi;
0358 } else if (area == area_1) {
0359 lp_lon = (theta < 0.0 ? theta + pi : theta - pi);
0360 } else if (area == area_2) {
0361 lp_lon = theta - half_pi;
0362 } else {
0363 lp_lon = theta;
0364 }
0365 } else if (this->m_proj_parm.face == face_bottom) {
0366 phi = acos(cosphi);
0367 lp_lat = phi - half_pi;
0368 if (area == area_0) {
0369 lp_lon = -theta + half_pi;
0370 } else if (area == area_1) {
0371 lp_lon = -theta;
0372 } else if (area == area_2) {
0373 lp_lon = -theta - half_pi;
0374 } else {
0375 lp_lon = (theta < 0.0 ? -theta - pi : -theta + pi);
0376 }
0377 } else {
0378
0379 T q, r, s;
0380 q = cosphi;
0381 t = q * q;
0382 if (t >= 1.0) {
0383 s = 0.0;
0384 } else {
0385 s = sqrt(1.0 - t) * sin(theta);
0386 }
0387 t += s * s;
0388 if (t >= 1.0) {
0389 r = 0.0;
0390 } else {
0391 r = sqrt(1.0 - t);
0392 }
0393
0394 if (area == area_1) {
0395 t = r;
0396 r = -s;
0397 s = t;
0398 } else if (area == area_2) {
0399 r = -r;
0400 s = -s;
0401 } else if (area == area_3) {
0402 t = r;
0403 r = s;
0404 s = -t;
0405 }
0406
0407 if (this->m_proj_parm.face == face_right) {
0408 t = q;
0409 q = -r;
0410 r = t;
0411 } else if (this->m_proj_parm.face == face_back) {
0412 q = -q;
0413 r = -r;
0414 } else if (this->m_proj_parm.face == face_left) {
0415 t = q;
0416 q = r;
0417 r = -t;
0418 }
0419
0420 lp_lat = acos(-s) - half_pi;
0421 lp_lon = atan2(r, q);
0422 if (this->m_proj_parm.face == face_right) {
0423 lp_lon = qsc_shift_lon_origin(lp_lon, -half_pi);
0424 } else if (this->m_proj_parm.face == face_back) {
0425 lp_lon = qsc_shift_lon_origin(lp_lon, -pi);
0426 } else if (this->m_proj_parm.face == face_left) {
0427 lp_lon = qsc_shift_lon_origin(lp_lon, +half_pi);
0428 }
0429 }
0430
0431
0432
0433 if (par.es != 0.0) {
0434 int invert_sign;
0435 T tanphi, xa;
0436 invert_sign = (lp_lat < 0.0 ? 1 : 0);
0437 tanphi = tan(lp_lat);
0438 xa = this->m_proj_parm.b / sqrt(tanphi * tanphi + this->m_proj_parm.one_minus_f_squared);
0439 lp_lat = atan(sqrt(par.a * par.a - xa * xa) / (this->m_proj_parm.one_minus_f * xa));
0440 if (invert_sign) {
0441 lp_lat = -lp_lat;
0442 }
0443 }
0444 }
0445
0446 static inline std::string get_name()
0447 {
0448 return "qsc_ellipsoid";
0449 }
0450
0451 };
0452
0453
0454 template <typename Parameters, typename T>
0455 inline void setup_qsc(Parameters const& par, par_qsc<T>& proj_parm)
0456 {
0457 static const T fourth_pi = detail::fourth_pi<T>();
0458 static const T half_pi = detail::half_pi<T>();
0459
0460
0461 if (par.phi0 >= half_pi - fourth_pi / 2.0) {
0462 proj_parm.face = face_top;
0463 } else if (par.phi0 <= -(half_pi - fourth_pi / 2.0)) {
0464 proj_parm.face = face_bottom;
0465 } else if (fabs(par.lam0) <= fourth_pi) {
0466 proj_parm.face = face_front;
0467 } else if (fabs(par.lam0) <= half_pi + fourth_pi) {
0468 proj_parm.face = (par.lam0 > 0.0 ? face_right : face_left);
0469 } else {
0470 proj_parm.face = face_back;
0471 }
0472
0473
0474 if (par.es != 0.0) {
0475 proj_parm.a_squared = par.a * par.a;
0476 proj_parm.b = par.a * sqrt(1.0 - par.es);
0477 proj_parm.one_minus_f = 1.0 - (par.a - proj_parm.b) / par.a;
0478 proj_parm.one_minus_f_squared = proj_parm.one_minus_f * proj_parm.one_minus_f;
0479 }
0480 }
0481
0482 }}
0483 #endif
0484
0485
0486
0487
0488
0489
0490
0491
0492
0493
0494
0495
0496
0497 template <typename T, typename Parameters>
0498 struct qsc_ellipsoid : public detail::qsc::base_qsc_ellipsoid<T, Parameters>
0499 {
0500 template <typename Params>
0501 inline qsc_ellipsoid(Params const& , Parameters const& par)
0502 {
0503 detail::qsc::setup_qsc(par, this->m_proj_parm);
0504 }
0505 };
0506
0507 #ifndef DOXYGEN_NO_DETAIL
0508 namespace detail
0509 {
0510
0511
0512 BOOST_GEOMETRY_PROJECTIONS_DETAIL_STATIC_PROJECTION_FI(srs::spar::proj_qsc, qsc_ellipsoid)
0513
0514
0515 BOOST_GEOMETRY_PROJECTIONS_DETAIL_FACTORY_ENTRY_FI(qsc_entry, qsc_ellipsoid)
0516
0517 BOOST_GEOMETRY_PROJECTIONS_DETAIL_FACTORY_INIT_BEGIN(qsc_init)
0518 {
0519 BOOST_GEOMETRY_PROJECTIONS_DETAIL_FACTORY_INIT_ENTRY(qsc, qsc_entry)
0520 }
0521
0522 }
0523 #endif
0524
0525 }
0526
0527 }}
0528
0529 #endif
0530