Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-18 09:35:44

0001 // Boost.Geometry - gis-projections (based on PROJ4)
0002 
0003 // Copyright (c) 2008-2015 Barend Gehrels, Amsterdam, the Netherlands.
0004 
0005 // This file was modified by Oracle on 2017, 2018, 2019.
0006 // Modifications copyright (c) 2017-2019, Oracle and/or its affiliates.
0007 // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle.
0008 
0009 // Use, modification and distribution is subject to the Boost Software License,
0010 // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
0011 // http://www.boost.org/LICENSE_1_0.txt)
0012 
0013 // This file is converted from PROJ4, http://trac.osgeo.org/proj
0014 // PROJ4 is originally written by Gerald Evenden (then of the USGS)
0015 // PROJ4 is maintained by Frank Warmerdam
0016 // PROJ4 is converted to Boost.Geometry by Barend Gehrels
0017 
0018 // Last updated version of proj: 5.0.0
0019 
0020 // Original copyright notice:
0021 
0022 // Permission is hereby granted, free of charge, to any person obtaining a
0023 // copy of this software and associated documentation files (the "Software"),
0024 // to deal in the Software without restriction, including without limitation
0025 // the rights to use, copy, modify, merge, publish, distribute, sublicense,
0026 // and/or sell copies of the Software, and to permit persons to whom the
0027 // Software is furnished to do so, subject to the following conditions:
0028 
0029 // The above copyright notice and this permission notice shall be included
0030 // in all copies or substantial portions of the Software.
0031 
0032 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
0033 // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
0034 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
0035 // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
0036 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
0037 // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
0038 // DEALINGS IN THE SOFTWARE.
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                 // FORWARD(s_forward)  spheroid
0097                 // Project coordinates from geographic (lon, lat) to cartesian (x, y)
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                 // INVERSE(s_inverse)  spheroid
0150                 // Project coordinates from cartesian (x, y) to geographic (lon, lat)
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; /* normalize by radius */
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             // Near-sided perspective
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             // Tilted perspective
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     }} // namespace detail::nsper
0252     #endif // doxygen
0253 
0254     /*!
0255         \brief Near-sided perspective projection
0256         \ingroup projections
0257         \tparam Geographic latlong point type
0258         \tparam Cartesian xy point type
0259         \tparam Parameters parameter type
0260         \par Projection characteristics
0261          - Azimuthal
0262          - Spheroid
0263         \par Projection parameters
0264          - h: Height
0265         \par Example
0266         \image html ex_nsper.gif
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         \brief Tilted perspective projection
0280         \ingroup projections
0281         \tparam Geographic latlong point type
0282         \tparam Cartesian xy point type
0283         \tparam Parameters parameter type
0284         \par Projection characteristics
0285          - Azimuthal
0286          - Spheroid
0287         \par Projection parameters
0288          - tilt: Tilt, or Omega (real)
0289          - azi: Azimuth (or Gamma) (real)
0290          - h: Height
0291         \par Example
0292         \image html ex_tpers.gif
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         // Static projection
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         // Factory entry(s)
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     } // namespace detail
0323     #endif // doxygen
0324 
0325 } // namespace projections
0326 
0327 }} // namespace boost::geometry
0328 
0329 #endif // BOOST_GEOMETRY_PROJECTIONS_NSPER_HPP
0330