File indexing completed on 2025-01-18 09:35:41
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_GNOM_HPP
0041 #define BOOST_GEOMETRY_PROJECTIONS_GNOM_HPP
0042
0043 #include <boost/config.hpp>
0044 #include <boost/geometry/util/math.hpp>
0045 #include <boost/math/special_functions/hypot.hpp>
0046
0047 #include <boost/geometry/srs/projections/impl/base_static.hpp>
0048 #include <boost/geometry/srs/projections/impl/base_dynamic.hpp>
0049 #include <boost/geometry/srs/projections/impl/projects.hpp>
0050 #include <boost/geometry/srs/projections/impl/factory_entry.hpp>
0051
0052 namespace boost { namespace geometry
0053 {
0054
0055 namespace projections
0056 {
0057 #ifndef DOXYGEN_NO_DETAIL
0058 namespace detail { namespace gnom
0059 {
0060
0061 static const double epsilon10 = 1.e-10;
0062 enum mode_type {
0063 n_pole = 0,
0064 s_pole = 1,
0065 equit = 2,
0066 obliq = 3
0067 };
0068
0069 template <typename T>
0070 struct par_gnom
0071 {
0072 T sinph0;
0073 T cosph0;
0074 mode_type mode;
0075 };
0076
0077 template <typename T, typename Parameters>
0078 struct base_gnom_spheroid
0079 {
0080 par_gnom<T> m_proj_parm;
0081
0082
0083
0084 inline void fwd(Parameters const& , T const& lp_lon, T const& lp_lat, T& xy_x, T& xy_y) const
0085 {
0086 T coslam, cosphi, sinphi;
0087
0088 sinphi = sin(lp_lat);
0089 cosphi = cos(lp_lat);
0090 coslam = cos(lp_lon);
0091
0092 switch (this->m_proj_parm.mode) {
0093 case equit:
0094 xy_y = cosphi * coslam;
0095 break;
0096 case obliq:
0097 xy_y = this->m_proj_parm.sinph0 * sinphi + this->m_proj_parm.cosph0 * cosphi * coslam;
0098 break;
0099 case s_pole:
0100 xy_y = - sinphi;
0101 break;
0102 case n_pole:
0103 xy_y = sinphi;
0104 break;
0105 }
0106
0107 if (xy_y <= epsilon10) {
0108 BOOST_THROW_EXCEPTION( projection_exception(error_tolerance_condition) );
0109 }
0110
0111 xy_x = (xy_y = 1. / xy_y) * cosphi * sin(lp_lon);
0112 switch (this->m_proj_parm.mode) {
0113 case equit:
0114 xy_y *= sinphi;
0115 break;
0116 case obliq:
0117 xy_y *= this->m_proj_parm.cosph0 * sinphi - this->m_proj_parm.sinph0 * cosphi * coslam;
0118 break;
0119 case n_pole:
0120 coslam = - coslam;
0121 BOOST_FALLTHROUGH;
0122 case s_pole:
0123 xy_y *= cosphi * coslam;
0124 break;
0125 }
0126 }
0127
0128
0129
0130 inline void inv(Parameters const& par, T xy_x, T xy_y, T& lp_lon, T& lp_lat) const
0131 {
0132 static const T half_pi = detail::half_pi<T>();
0133
0134 T rh, cosz, sinz;
0135
0136 rh = boost::math::hypot(xy_x, xy_y);
0137 sinz = sin(lp_lat = atan(rh));
0138 cosz = sqrt(1. - sinz * sinz);
0139
0140 if (fabs(rh) <= epsilon10) {
0141 lp_lat = par.phi0;
0142 lp_lon = 0.;
0143 } else {
0144 switch (this->m_proj_parm.mode) {
0145 case obliq:
0146 lp_lat = cosz * this->m_proj_parm.sinph0 + xy_y * sinz * this->m_proj_parm.cosph0 / rh;
0147 if (fabs(lp_lat) >= 1.)
0148 lp_lat = lp_lat > 0. ? half_pi : -half_pi;
0149 else
0150 lp_lat = asin(lp_lat);
0151 xy_y = (cosz - this->m_proj_parm.sinph0 * sin(lp_lat)) * rh;
0152 xy_x *= sinz * this->m_proj_parm.cosph0;
0153 break;
0154 case equit:
0155 lp_lat = xy_y * sinz / rh;
0156 if (fabs(lp_lat) >= 1.)
0157 lp_lat = lp_lat > 0. ? half_pi : -half_pi;
0158 else
0159 lp_lat = asin(lp_lat);
0160 xy_y = cosz * rh;
0161 xy_x *= sinz;
0162 break;
0163 case s_pole:
0164 lp_lat -= half_pi;
0165 break;
0166 case n_pole:
0167 lp_lat = half_pi - lp_lat;
0168 xy_y = -xy_y;
0169 break;
0170 }
0171 lp_lon = atan2(xy_x, xy_y);
0172 }
0173 }
0174
0175 static inline std::string get_name()
0176 {
0177 return "gnom_spheroid";
0178 }
0179
0180 };
0181
0182
0183 template <typename Parameters, typename T>
0184 inline void setup_gnom(Parameters& par, par_gnom<T>& proj_parm)
0185 {
0186 static const T half_pi = detail::half_pi<T>();
0187
0188 if (fabs(fabs(par.phi0) - half_pi) < epsilon10) {
0189 proj_parm.mode = par.phi0 < 0. ? s_pole : n_pole;
0190 } else if (fabs(par.phi0) < epsilon10) {
0191 proj_parm.mode = equit;
0192 } else {
0193 proj_parm.mode = obliq;
0194 proj_parm.sinph0 = sin(par.phi0);
0195 proj_parm.cosph0 = cos(par.phi0);
0196 }
0197
0198 par.es = 0.;
0199 }
0200
0201 }}
0202 #endif
0203
0204
0205
0206
0207
0208
0209
0210
0211
0212
0213
0214
0215
0216 template <typename T, typename Parameters>
0217 struct gnom_spheroid : public detail::gnom::base_gnom_spheroid<T, Parameters>
0218 {
0219 template <typename Params>
0220 inline gnom_spheroid(Params const& , Parameters & par)
0221 {
0222 detail::gnom::setup_gnom(par, this->m_proj_parm);
0223 }
0224 };
0225
0226 #ifndef DOXYGEN_NO_DETAIL
0227 namespace detail
0228 {
0229
0230
0231 BOOST_GEOMETRY_PROJECTIONS_DETAIL_STATIC_PROJECTION_FI(srs::spar::proj_gnom, gnom_spheroid)
0232
0233
0234 BOOST_GEOMETRY_PROJECTIONS_DETAIL_FACTORY_ENTRY_FI(gnom_entry, gnom_spheroid)
0235
0236 BOOST_GEOMETRY_PROJECTIONS_DETAIL_FACTORY_INIT_BEGIN(gnom_init)
0237 {
0238 BOOST_GEOMETRY_PROJECTIONS_DETAIL_FACTORY_INIT_ENTRY(gnom, gnom_entry);
0239 }
0240
0241 }
0242 #endif
0243
0244 }
0245
0246 }}
0247
0248 #endif
0249