File indexing completed on 2025-01-18 09:35:44
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 #ifndef BOOST_GEOMETRY_PROJECTIONS_NSPER_HPP
0041 #define BOOST_GEOMETRY_PROJECTIONS_NSPER_HPP
0042
0043 #include <boost/config.hpp>
0044
0045 #include <boost/geometry/srs/projections/impl/base_static.hpp>
0046 #include <boost/geometry/srs/projections/impl/base_dynamic.hpp>
0047 #include <boost/geometry/srs/projections/impl/factory_entry.hpp>
0048 #include <boost/geometry/srs/projections/impl/pj_param.hpp>
0049 #include <boost/geometry/srs/projections/impl/projects.hpp>
0050
0051 #include <boost/geometry/util/math.hpp>
0052
0053 #include <boost/math/special_functions/hypot.hpp>
0054
0055 namespace boost { namespace geometry
0056 {
0057
0058 namespace projections
0059 {
0060 #ifndef DOXYGEN_NO_DETAIL
0061 namespace detail { namespace nsper
0062 {
0063
0064 static const double epsilon10 = 1.e-10;
0065 enum mode_type {
0066 n_pole = 0,
0067 s_pole = 1,
0068 equit = 2,
0069 obliq = 3
0070 };
0071
0072 template <typename T>
0073 struct par_nsper
0074 {
0075 T height;
0076 T sinph0;
0077 T cosph0;
0078 T p;
0079 T rp;
0080 T pn1;
0081 T pfact;
0082 T h;
0083 T cg;
0084 T sg;
0085 T sw;
0086 T cw;
0087 mode_type mode;
0088 bool tilt;
0089 };
0090
0091 template <typename T, typename Parameters>
0092 struct base_nsper_spheroid
0093 {
0094 par_nsper<T> m_proj_parm;
0095
0096
0097
0098 inline void fwd(Parameters const& , T const& lp_lon, T const& lp_lat, T& xy_x, T& xy_y) const
0099 {
0100 T coslam, cosphi, sinphi;
0101
0102 sinphi = sin(lp_lat);
0103 cosphi = cos(lp_lat);
0104 coslam = cos(lp_lon);
0105 switch (this->m_proj_parm.mode) {
0106 case obliq:
0107 xy_y = this->m_proj_parm.sinph0 * sinphi + this->m_proj_parm.cosph0 * cosphi * coslam;
0108 break;
0109 case equit:
0110 xy_y = cosphi * coslam;
0111 break;
0112 case s_pole:
0113 xy_y = - sinphi;
0114 break;
0115 case n_pole:
0116 xy_y = sinphi;
0117 break;
0118 }
0119 if (xy_y < this->m_proj_parm.rp) {
0120 BOOST_THROW_EXCEPTION( projection_exception(error_tolerance_condition) );
0121 }
0122 xy_y = this->m_proj_parm.pn1 / (this->m_proj_parm.p - xy_y);
0123 xy_x = xy_y * cosphi * sin(lp_lon);
0124 switch (this->m_proj_parm.mode) {
0125 case obliq:
0126 xy_y *= (this->m_proj_parm.cosph0 * sinphi -
0127 this->m_proj_parm.sinph0 * cosphi * coslam);
0128 break;
0129 case equit:
0130 xy_y *= sinphi;
0131 break;
0132 case n_pole:
0133 coslam = - coslam;
0134 BOOST_FALLTHROUGH;
0135 case s_pole:
0136 xy_y *= cosphi * coslam;
0137 break;
0138 }
0139 if (this->m_proj_parm.tilt) {
0140 T yt, ba;
0141
0142 yt = xy_y * this->m_proj_parm.cg + xy_x * this->m_proj_parm.sg;
0143 ba = 1. / (yt * this->m_proj_parm.sw * this->m_proj_parm.h + this->m_proj_parm.cw);
0144 xy_x = (xy_x * this->m_proj_parm.cg - xy_y * this->m_proj_parm.sg) * this->m_proj_parm.cw * ba;
0145 xy_y = yt * ba;
0146 }
0147 }
0148
0149
0150
0151 inline void inv(Parameters const& par, T xy_x, T xy_y, T& lp_lon, T& lp_lat) const
0152 {
0153 T rh, cosz, sinz;
0154
0155 if (this->m_proj_parm.tilt) {
0156 T bm, bq, yt;
0157
0158 yt = 1./(this->m_proj_parm.pn1 - xy_y * this->m_proj_parm.sw);
0159 bm = this->m_proj_parm.pn1 * xy_x * yt;
0160 bq = this->m_proj_parm.pn1 * xy_y * this->m_proj_parm.cw * yt;
0161 xy_x = bm * this->m_proj_parm.cg + bq * this->m_proj_parm.sg;
0162 xy_y = bq * this->m_proj_parm.cg - bm * this->m_proj_parm.sg;
0163 }
0164 rh = boost::math::hypot(xy_x, xy_y);
0165 if ((sinz = 1. - rh * rh * this->m_proj_parm.pfact) < 0.) {
0166 BOOST_THROW_EXCEPTION( projection_exception(error_tolerance_condition) );
0167 }
0168 sinz = (this->m_proj_parm.p - sqrt(sinz)) / (this->m_proj_parm.pn1 / rh + rh / this->m_proj_parm.pn1);
0169 cosz = sqrt(1. - sinz * sinz);
0170 if (fabs(rh) <= epsilon10) {
0171 lp_lon = 0.;
0172 lp_lat = par.phi0;
0173 } else {
0174 switch (this->m_proj_parm.mode) {
0175 case obliq:
0176 lp_lat = asin(cosz * this->m_proj_parm.sinph0 + xy_y * sinz * this->m_proj_parm.cosph0 / rh);
0177 xy_y = (cosz - this->m_proj_parm.sinph0 * sin(lp_lat)) * rh;
0178 xy_x *= sinz * this->m_proj_parm.cosph0;
0179 break;
0180 case equit:
0181 lp_lat = asin(xy_y * sinz / rh);
0182 xy_y = cosz * rh;
0183 xy_x *= sinz;
0184 break;
0185 case n_pole:
0186 lp_lat = asin(cosz);
0187 xy_y = -xy_y;
0188 break;
0189 case s_pole:
0190 lp_lat = - asin(cosz);
0191 break;
0192 }
0193 lp_lon = atan2(xy_x, xy_y);
0194 }
0195 }
0196
0197 static inline std::string get_name()
0198 {
0199 return "nsper_spheroid";
0200 }
0201
0202 };
0203
0204 template <typename Params, typename Parameters, typename T>
0205 inline void setup(Params const& params, Parameters& par, par_nsper<T>& proj_parm)
0206 {
0207 proj_parm.height = pj_get_param_f<T, srs::spar::h>(params, "h", srs::dpar::h);
0208 if (proj_parm.height <= 0.)
0209 BOOST_THROW_EXCEPTION( projection_exception(error_h_less_than_zero) );
0210
0211 if (fabs(fabs(par.phi0) - geometry::math::half_pi<T>()) < epsilon10)
0212 proj_parm.mode = par.phi0 < 0. ? s_pole : n_pole;
0213 else if (fabs(par.phi0) < epsilon10)
0214 proj_parm.mode = equit;
0215 else {
0216 proj_parm.mode = obliq;
0217 proj_parm.sinph0 = sin(par.phi0);
0218 proj_parm.cosph0 = cos(par.phi0);
0219 }
0220 proj_parm.pn1 = proj_parm.height / par.a;
0221 proj_parm.p = 1. + proj_parm.pn1;
0222 proj_parm.rp = 1. / proj_parm.p;
0223 proj_parm.h = 1. / proj_parm.pn1;
0224 proj_parm.pfact = (proj_parm.p + 1.) * proj_parm.h;
0225 par.es = 0.;
0226 }
0227
0228
0229
0230 template <typename Params, typename Parameters, typename T>
0231 inline void setup_nsper(Params const& params, Parameters& par, par_nsper<T>& proj_parm)
0232 {
0233 proj_parm.tilt = false;
0234
0235 setup(params, par, proj_parm);
0236 }
0237
0238
0239 template <typename Params, typename Parameters, typename T>
0240 inline void setup_tpers(Params const& params, Parameters& par, par_nsper<T>& proj_parm)
0241 {
0242 T const omega = pj_get_param_r<T, srs::spar::tilt>(params, "tilt", srs::dpar::tilt);
0243 T const gamma = pj_get_param_r<T, srs::spar::azi>(params, "azi", srs::dpar::azi);
0244 proj_parm.tilt = true;
0245 proj_parm.cg = cos(gamma); proj_parm.sg = sin(gamma);
0246 proj_parm.cw = cos(omega); proj_parm.sw = sin(omega);
0247
0248 setup(params, par, proj_parm);
0249 }
0250
0251 }}
0252 #endif
0253
0254
0255
0256
0257
0258
0259
0260
0261
0262
0263
0264
0265
0266
0267
0268 template <typename T, typename Parameters>
0269 struct nsper_spheroid : public detail::nsper::base_nsper_spheroid<T, Parameters>
0270 {
0271 template <typename Params>
0272 inline nsper_spheroid(Params const& params, Parameters & par)
0273 {
0274 detail::nsper::setup_nsper(params, par, this->m_proj_parm);
0275 }
0276 };
0277
0278
0279
0280
0281
0282
0283
0284
0285
0286
0287
0288
0289
0290
0291
0292
0293
0294 template <typename T, typename Parameters>
0295 struct tpers_spheroid : public detail::nsper::base_nsper_spheroid<T, Parameters>
0296 {
0297 template <typename Params>
0298 inline tpers_spheroid(Params const& params, Parameters & par)
0299 {
0300 detail::nsper::setup_tpers(params, par, this->m_proj_parm);
0301 }
0302 };
0303
0304 #ifndef DOXYGEN_NO_DETAIL
0305 namespace detail
0306 {
0307
0308
0309 BOOST_GEOMETRY_PROJECTIONS_DETAIL_STATIC_PROJECTION_F(srs::spar::proj_nsper, nsper_spheroid)
0310 BOOST_GEOMETRY_PROJECTIONS_DETAIL_STATIC_PROJECTION_F(srs::spar::proj_tpers, tpers_spheroid)
0311
0312
0313 BOOST_GEOMETRY_PROJECTIONS_DETAIL_FACTORY_ENTRY_FI(nsper_entry, nsper_spheroid)
0314 BOOST_GEOMETRY_PROJECTIONS_DETAIL_FACTORY_ENTRY_FI(tpers_entry, tpers_spheroid)
0315
0316 BOOST_GEOMETRY_PROJECTIONS_DETAIL_FACTORY_INIT_BEGIN(nsper_init)
0317 {
0318 BOOST_GEOMETRY_PROJECTIONS_DETAIL_FACTORY_INIT_ENTRY(nsper, nsper_entry)
0319 BOOST_GEOMETRY_PROJECTIONS_DETAIL_FACTORY_INIT_ENTRY(tpers, tpers_entry)
0320 }
0321
0322 }
0323 #endif
0324
0325 }
0326
0327 }}
0328
0329 #endif
0330