Imported Upstream version 1.72.0
[platform/upstream/boost.git] / boost / geometry / srs / projections / proj / ob_tran.hpp
1 // Boost.Geometry - gis-projections (based on PROJ4)
2
3 // Copyright (c) 2008-2015 Barend Gehrels, Amsterdam, the Netherlands.
4
5 // This file was modified by Oracle on 2017, 2018, 2019.
6 // Modifications copyright (c) 2017-2019, Oracle and/or its affiliates.
7 // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle.
8
9 // Use, modification and distribution is subject to the Boost Software License,
10 // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
11 // http://www.boost.org/LICENSE_1_0.txt)
12
13 // This file is converted from PROJ4, http://trac.osgeo.org/proj
14 // PROJ4 is originally written by Gerald Evenden (then of the USGS)
15 // PROJ4 is maintained by Frank Warmerdam
16 // PROJ4 is converted to Boost.Geometry by Barend Gehrels
17
18 // Last updated version of proj: 5.0.0
19
20 // Original copyright notice:
21
22 // Permission is hereby granted, free of charge, to any person obtaining a
23 // copy of this software and associated documentation files (the "Software"),
24 // to deal in the Software without restriction, including without limitation
25 // the rights to use, copy, modify, merge, publish, distribute, sublicense,
26 // and/or sell copies of the Software, and to permit persons to whom the
27 // Software is furnished to do so, subject to the following conditions:
28
29 // The above copyright notice and this permission notice shall be included
30 // in all copies or substantial portions of the Software.
31
32 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
33 // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
34 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
35 // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
36 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
37 // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
38 // DEALINGS IN THE SOFTWARE.
39
40 #ifndef BOOST_GEOMETRY_PROJECTIONS_OB_TRAN_HPP
41 #define BOOST_GEOMETRY_PROJECTIONS_OB_TRAN_HPP
42
43 #include <boost/geometry/util/math.hpp>
44 #include <boost/shared_ptr.hpp>
45
46 #include <boost/geometry/srs/projections/impl/aasincos.hpp>
47 #include <boost/geometry/srs/projections/impl/base_static.hpp>
48 #include <boost/geometry/srs/projections/impl/base_dynamic.hpp>
49 #include <boost/geometry/srs/projections/impl/factory_entry.hpp>
50 #include <boost/geometry/srs/projections/impl/pj_ell_set.hpp>
51 #include <boost/geometry/srs/projections/impl/projects.hpp>
52
53 namespace boost { namespace geometry
54 {
55
56 namespace projections
57 {
58     #ifndef DOXYGEN_NO_DETAIL
59     namespace detail {
60     
61         // fwd declaration needed below
62         template <typename T>
63         inline detail::dynamic_wrapper_b<T, projections::parameters<T> >*
64             create_new(srs::detail::proj4_parameters const& params,
65                        projections::parameters<T> const& parameters);
66
67         template <typename T>
68         inline detail::dynamic_wrapper_b<T, projections::parameters<T> >*
69             create_new(srs::dpar::parameters<T> const& params,
70                        projections::parameters<T> const& parameters);
71
72     } // namespace detail
73
74     namespace detail { namespace ob_tran
75     {
76
77             static const double tolerance = 1e-10;
78
79             template <typename Parameters>
80             inline Parameters o_proj_parameters(srs::detail::proj4_parameters const& params,
81                                                 Parameters const& par)
82             {
83                 /* copy existing header into new */
84                 Parameters pj = par;
85
86                 /* get name of projection to be translated */
87                 pj.id = pj_get_param_s(params, "o_proj");
88                 if (pj.id.is_unknown())
89                     BOOST_THROW_EXCEPTION( projection_exception(error_no_rotation_proj) );
90
91                 /* avoid endless recursion */
92                 if( pj.id.name == "ob_tran")
93                     BOOST_THROW_EXCEPTION( projection_exception(error_failed_to_find_proj) );
94
95                 // Commented out for consistency with Proj4 >= 5.0.0
96                 /* force spherical earth */
97                 //pj.one_es = pj.rone_es = 1.;
98                 //pj.es = pj.e = 0.;
99
100                 return pj;
101             }
102
103             template <typename T, typename Parameters>
104             inline Parameters o_proj_parameters(srs::dpar::parameters<T> const& params,
105                                                 Parameters const& par)
106             {
107                 /* copy existing header into new */
108                 Parameters pj = par;
109
110                 /* get name of projection to be translated */
111                 typename srs::dpar::parameters<T>::const_iterator
112                     it = pj_param_find(params, srs::dpar::o_proj);
113                 if (it != params.end())
114                     pj.id = static_cast<srs::dpar::value_proj>(it->template get_value<int>());
115                 else
116                     BOOST_THROW_EXCEPTION( projection_exception(error_no_rotation_proj) );
117
118                 /* avoid endless recursion */
119                 if( pj.id.id == srs::dpar::proj_ob_tran)
120                     BOOST_THROW_EXCEPTION( projection_exception(error_failed_to_find_proj) );
121
122                 // Commented out for consistency with Proj4 >= 5.0.0
123                 /* force spherical earth */
124                 //pj.one_es = pj.rone_es = 1.;
125                 //pj.es = pj.e = 0.;
126
127                 return pj;
128             }
129
130             template <BOOST_GEOMETRY_PROJECTIONS_DETAIL_TYPENAME_PX, typename Parameters>
131             inline Parameters o_proj_parameters(srs::spar::parameters<BOOST_GEOMETRY_PROJECTIONS_DETAIL_PX> const& /*params*/,
132                                                 Parameters const& par)
133             {
134                 /* copy existing header into new */
135                 Parameters pj = par;
136
137                 /* get name of projection to be translated */
138                 typedef srs::spar::parameters<BOOST_GEOMETRY_PROJECTIONS_DETAIL_PX> params_type;
139                 typedef typename srs::spar::detail::tuples_find_if
140                     <
141                         params_type,
142                         srs::spar::detail::is_param_t<srs::spar::o_proj>::pred
143                     >::type o_proj_type;
144
145                 static const bool is_found = srs::spar::detail::tuples_is_found<o_proj_type>::value;
146                 BOOST_MPL_ASSERT_MSG((is_found), NO_ROTATION_PROJ, (params_type));
147
148                 typedef typename o_proj_type::type proj_type;
149                 static const bool is_specialized = srs::spar::detail::proj_traits<proj_type>::is_specialized;
150                 BOOST_MPL_ASSERT_MSG((is_specialized), NO_ROTATION_PROJ, (params_type));
151
152                 pj.id = srs::spar::detail::proj_traits<proj_type>::id;
153
154                 /* avoid endless recursion */
155                 static const bool is_non_resursive = ! boost::is_same<proj_type, srs::spar::proj_ob_tran>::value;
156                 BOOST_MPL_ASSERT_MSG((is_non_resursive), INVALID_O_PROJ_PARAMETER, (params_type));
157
158                 // Commented out for consistency with Proj4 >= 5.0.0
159                 /* force spherical earth */
160                 //pj.one_es = pj.rone_es = 1.;
161                 //pj.es = pj.e = 0.;
162
163                 return pj;
164             }
165
166             // TODO: It's possible that the original Parameters could be used
167             // instead of a copy in link.
168             // But it's not possible with the current implementation of
169             // dynamic_wrapper_b always storing params
170
171             template <typename T, typename Parameters>
172             struct par_ob_tran
173             {
174                 template <typename Params>
175                 par_ob_tran(Params const& params, Parameters const& par)
176                     : link(projections::detail::create_new(params, o_proj_parameters(params, par)))
177                 {
178                     if (! link.get())
179                         BOOST_THROW_EXCEPTION( projection_exception(error_unknown_projection_id) );
180                 }
181
182                 inline void fwd(T const& lp_lon, T const& lp_lat, T& xy_x, T& xy_y) const
183                 {
184                     link->fwd(link->params(), lp_lon, lp_lat, xy_x, xy_y);
185                 }
186
187                 inline void inv(T const& xy_x, T const& xy_y, T& lp_lon, T& lp_lat) const
188                 {
189                     link->inv(link->params(), xy_x, xy_y, lp_lon, lp_lat);
190                 }
191
192                 boost::shared_ptr<dynamic_wrapper_b<T, Parameters> > link;
193                 T lamp;
194                 T cphip, sphip;
195             };
196
197             template <typename StaticParameters, typename T, typename Parameters>
198             struct par_ob_tran_static
199             {
200                 // this metafunction handles static error handling
201                 typedef typename srs::spar::detail::pick_o_proj_tag
202                     <
203                         StaticParameters
204                     >::type o_proj_tag;
205
206                 /* avoid endless recursion */
207                 static const bool is_o_proj_not_ob_tran = ! boost::is_same<o_proj_tag, srs::spar::proj_ob_tran>::value;
208                 BOOST_MPL_ASSERT_MSG((is_o_proj_not_ob_tran), INVALID_O_PROJ_PARAMETER, (StaticParameters));
209
210                 typedef typename projections::detail::static_projection_type
211                     <
212                         o_proj_tag,
213                         // Commented out for consistency with Proj4 >= 5.0.0
214                         //srs_sphere_tag, // force spherical
215                         typename projections::detail::static_srs_tag<StaticParameters>::type,
216                         StaticParameters,
217                         T,
218                         Parameters
219                     >::type projection_type;
220
221                 par_ob_tran_static(StaticParameters const& params, Parameters const& par)
222                     : link(params, o_proj_parameters(params, par))
223                 {}
224
225                 inline void fwd(T const& lp_lon, T const& lp_lat, T& xy_x, T& xy_y) const
226                 {
227                     link.fwd(link.params(), lp_lon, lp_lat, xy_x, xy_y);
228                 }
229
230                 inline void inv(T const& xy_x, T const& xy_y, T& lp_lon, T& lp_lat) const
231                 {
232                     link.inv(link.params(), xy_x, xy_y, lp_lon, lp_lat);
233                 }
234
235                 projection_type link;
236                 T lamp;
237                 T cphip, sphip;
238             };
239
240             template <typename T, typename Par>
241             inline void o_forward(T lp_lon, T lp_lat, T& xy_x, T& xy_y, Par const& proj_parm)
242             {
243                 T coslam, sinphi, cosphi;
244                 
245                 coslam = cos(lp_lon);
246                 sinphi = sin(lp_lat);
247                 cosphi = cos(lp_lat);
248                 lp_lon = adjlon(aatan2(cosphi * sin(lp_lon), proj_parm.sphip * cosphi * coslam +
249                     proj_parm.cphip * sinphi) + proj_parm.lamp);
250                 lp_lat = aasin(proj_parm.sphip * sinphi - proj_parm.cphip * cosphi * coslam);
251
252                 proj_parm.fwd(lp_lon, lp_lat, xy_x, xy_y);
253             }
254
255             template <typename T, typename Par>
256             inline void o_inverse(T const& xy_x, T const& xy_y, T& lp_lon, T& lp_lat, Par const& proj_parm)
257             {
258                 T coslam, sinphi, cosphi;
259
260                 proj_parm.inv(xy_x, xy_y, lp_lon, lp_lat);
261                 if (lp_lon != HUGE_VAL) {
262                     coslam = cos(lp_lon -= proj_parm.lamp);
263                     sinphi = sin(lp_lat);
264                     cosphi = cos(lp_lat);
265                     lp_lat = aasin(proj_parm.sphip * sinphi + proj_parm.cphip * cosphi * coslam);
266                     lp_lon = aatan2(cosphi * sin(lp_lon), proj_parm.sphip * cosphi * coslam -
267                         proj_parm.cphip * sinphi);
268                 }
269             }
270
271             template <typename T, typename Par>
272             inline void t_forward(T lp_lon, T lp_lat, T& xy_x, T& xy_y, Par const& proj_parm)
273             {
274                 T cosphi, coslam;
275
276                 cosphi = cos(lp_lat);
277                 coslam = cos(lp_lon);
278                 lp_lon = adjlon(aatan2(cosphi * sin(lp_lon), sin(lp_lat)) + proj_parm.lamp);
279                 lp_lat = aasin(- cosphi * coslam);
280
281                 proj_parm.fwd(lp_lon, lp_lat, xy_x, xy_y);
282             }
283
284             template <typename T, typename Par>
285             inline void t_inverse(T const& xy_x, T const& xy_y, T& lp_lon, T& lp_lat, Par const& proj_parm)
286             {
287                 T cosphi, t;
288
289                 proj_parm.inv(xy_x, xy_y, lp_lon, lp_lat);
290                 if (lp_lon != HUGE_VAL) {
291                     cosphi = cos(lp_lat);
292                     t = lp_lon - proj_parm.lamp;
293                     lp_lon = aatan2(cosphi * sin(t), - sin(lp_lat));
294                     lp_lat = aasin(cosphi * cos(t));
295                 }
296             }
297
298             // General Oblique Transformation
299             template <typename T, typename Params, typename Parameters, typename ProjParameters>
300             inline T setup_ob_tran(Params const& params, Parameters & /*par*/, ProjParameters& proj_parm)
301             {
302                 static const T half_pi = detail::half_pi<T>();
303
304                 T phip, alpha;
305
306                 // Commented out for consistency with Proj4 >= 5.0.0
307                 //par.es = 0.; /* force to spherical */
308
309                 // proj_parm.link should be created at this point
310
311                 if (pj_param_r<srs::spar::o_alpha>(params, "o_alpha", srs::dpar::o_alpha, alpha)) {
312                     T lamc, phic;
313
314                     lamc    = pj_get_param_r<T, srs::spar::o_lon_c>(params, "o_lon_c", srs::dpar::o_lon_c);
315                     phic    = pj_get_param_r<T, srs::spar::o_lon_c>(params, "o_lat_c", srs::dpar::o_lat_c);
316                     //alpha   = pj_get_param_r(par.params, "o_alpha");
317             
318                     if (fabs(fabs(phic) - half_pi) <= tolerance)
319                         BOOST_THROW_EXCEPTION( projection_exception(error_lat_0_or_alpha_eq_90) );
320
321                     proj_parm.lamp = lamc + aatan2(-cos(alpha), -sin(alpha) * sin(phic));
322                     phip = aasin(cos(phic) * sin(alpha));
323                 } else if (pj_param_r<srs::spar::o_lat_p>(params, "o_lat_p", srs::dpar::o_lat_p, phip)) { /* specified new pole */
324                     proj_parm.lamp = pj_get_param_r<T, srs::spar::o_lon_p>(params, "o_lon_p", srs::dpar::o_lon_p);
325                     //phip = pj_param_r(par.params, "o_lat_p");
326                 } else { /* specified new "equator" points */
327                     T lam1, lam2, phi1, phi2, con;
328
329                     lam1 = pj_get_param_r<T, srs::spar::o_lon_1>(params, "o_lon_1", srs::dpar::o_lon_1);
330                     phi1 = pj_get_param_r<T, srs::spar::o_lat_1>(params, "o_lat_1", srs::dpar::o_lat_1);
331                     lam2 = pj_get_param_r<T, srs::spar::o_lon_2>(params, "o_lon_2", srs::dpar::o_lon_2);
332                     phi2 = pj_get_param_r<T, srs::spar::o_lat_2>(params, "o_lat_2", srs::dpar::o_lat_2);
333                     if (fabs(phi1 - phi2) <= tolerance || (con = fabs(phi1)) <= tolerance ||
334                         fabs(con - half_pi) <= tolerance || fabs(fabs(phi2) - half_pi) <= tolerance)
335                         BOOST_THROW_EXCEPTION( projection_exception(error_lat_1_or_2_zero_or_90) );
336
337                     proj_parm.lamp = atan2(cos(phi1) * sin(phi2) * cos(lam1) -
338                         sin(phi1) * cos(phi2) * cos(lam2),
339                         sin(phi1) * cos(phi2) * sin(lam2) -
340                         cos(phi1) * sin(phi2) * sin(lam1));
341                     phip = atan(-cos(proj_parm.lamp - lam1) / tan(phi1));
342                 }
343
344                 if (fabs(phip) > tolerance) { /* oblique */
345                     proj_parm.cphip = cos(phip);
346                     proj_parm.sphip = sin(phip);
347                 } else { /* transverse */
348                 }
349
350                 // TODO:
351                 /* Support some rather speculative test cases, where the rotated projection */
352                 /* is actually latlong. We do not want scaling in that case... */
353                 //if (proj_parm.link...mutable_parameters().right==PJ_IO_UNITS_ANGULAR)
354                 //    par.right = PJ_IO_UNITS_PROJECTED;
355
356                 // return phip to choose model
357                 return phip;
358             }
359
360             template <typename T, typename Parameters>
361             struct base_ob_tran_oblique
362             {
363                 par_ob_tran<T, Parameters> m_proj_parm;
364
365                 inline base_ob_tran_oblique(par_ob_tran<T, Parameters> const& proj_parm)
366                     : m_proj_parm(proj_parm)
367                 {}
368
369                 // FORWARD(o_forward)  spheroid
370                 // Project coordinates from geographic (lon, lat) to cartesian (x, y)
371                 inline void fwd(Parameters const& , T const& lp_lon, T const& lp_lat, T& xy_x, T& xy_y) const
372                 {
373                     // NOTE: Parameters ignored, m_proj_parm.link has a copy
374                     o_forward(lp_lon, lp_lat, xy_x, xy_y, this->m_proj_parm);
375                 }
376
377                 // INVERSE(o_inverse)  spheroid
378                 // Project coordinates from cartesian (x, y) to geographic (lon, lat)
379                 inline void inv(Parameters const& , T const& xy_x, T const& xy_y, T& lp_lon, T& lp_lat) const
380                 {
381                     // NOTE: Parameters ignored, m_proj_parm.link has a copy
382                     o_inverse(xy_x, xy_y, lp_lon, lp_lat, this->m_proj_parm);
383                 }
384
385                 static inline std::string get_name()
386                 {
387                     return "ob_tran_oblique";
388                 }
389
390             };
391
392             template <typename T, typename Parameters>
393             struct base_ob_tran_transverse
394             {
395                 par_ob_tran<T, Parameters> m_proj_parm;
396
397                 inline base_ob_tran_transverse(par_ob_tran<T, Parameters> const& proj_parm)
398                     : m_proj_parm(proj_parm)
399                 {}
400
401                 // FORWARD(t_forward)  spheroid
402                 // Project coordinates from geographic (lon, lat) to cartesian (x, y)
403                 inline void fwd(Parameters const& , T const& lp_lon, T const& lp_lat, T& xy_x, T& xy_y) const
404                 {
405                     // NOTE: Parameters ignored, m_proj_parm.link has a copy
406                     t_forward(lp_lon, lp_lat, xy_x, xy_y, this->m_proj_parm);
407                 }
408
409                 // INVERSE(t_inverse)  spheroid
410                 // Project coordinates from cartesian (x, y) to geographic (lon, lat)
411                 inline void inv(Parameters const& , T const& xy_x, T const& xy_y, T& lp_lon, T& lp_lat) const
412                 {
413                     // NOTE: Parameters ignored, m_proj_parm.link has a copy
414                     t_inverse(xy_x, xy_y, lp_lon, lp_lat, this->m_proj_parm);
415                 }
416
417                 static inline std::string get_name()
418                 {
419                     return "ob_tran_transverse";
420                 }
421
422             };
423
424             template <typename StaticParameters, typename T, typename Parameters>
425             struct base_ob_tran_static
426             {
427                 par_ob_tran_static<StaticParameters, T, Parameters> m_proj_parm;
428                 bool m_is_oblique;
429
430                 inline base_ob_tran_static(StaticParameters const& params, Parameters const& par)
431                     : m_proj_parm(params, par)
432                 {}
433
434                 // FORWARD(o_forward)  spheroid
435                 // Project coordinates from geographic (lon, lat) to cartesian (x, y)
436                 inline void fwd(Parameters const& , T const& lp_lon, T const& lp_lat, T& xy_x, T& xy_y) const
437                 {
438                     // NOTE: Parameters ignored, m_proj_parm.link has a copy
439                     if (m_is_oblique) {
440                         o_forward(lp_lon, lp_lat, xy_x, xy_y, this->m_proj_parm);
441                     } else {
442                         t_forward(lp_lon, lp_lat, xy_x, xy_y, this->m_proj_parm);
443                     }
444                 }
445
446                 // INVERSE(o_inverse)  spheroid
447                 // Project coordinates from cartesian (x, y) to geographic (lon, lat)
448                 inline void inv(Parameters const& , T const& xy_x, T const& xy_y, T& lp_lon, T& lp_lat) const
449                 {
450                     // NOTE: Parameters ignored, m_proj_parm.link has a copy
451                     if (m_is_oblique) {
452                         o_inverse(xy_x, xy_y, lp_lon, lp_lat, this->m_proj_parm);
453                     } else {
454                         t_inverse(xy_x, xy_y, lp_lon, lp_lat, this->m_proj_parm);
455                     }
456                 }
457
458                 static inline std::string get_name()
459                 {
460                     return "ob_tran";
461                 }
462
463             };
464
465     }} // namespace detail::ob_tran
466     #endif // doxygen
467
468     /*!
469         \brief General Oblique Transformation projection
470         \ingroup projections
471         \tparam Geographic latlong point type
472         \tparam Cartesian xy point type
473         \tparam Parameters parameter type
474         \par Projection characteristics
475          - Miscellaneous
476          - Spheroid
477         \par Projection parameters
478          - o_proj (string)
479          - Plus projection parameters
480          - o_lat_p (degrees)
481          - o_lon_p (degrees)
482          - New pole
483          - o_alpha: Alpha (degrees)
484          - o_lon_c (degrees)
485          - o_lat_c (degrees)
486          - o_lon_1 (degrees)
487          - o_lat_1: Latitude of first standard parallel (degrees)
488          - o_lon_2 (degrees)
489          - o_lat_2: Latitude of second standard parallel (degrees)
490         \par Example
491         \image html ex_ob_tran.gif
492     */
493     template <typename T, typename Parameters>
494     struct ob_tran_oblique : public detail::ob_tran::base_ob_tran_oblique<T, Parameters>
495     {
496         template <typename Params>
497         inline ob_tran_oblique(Params const& , Parameters const& ,
498                                detail::ob_tran::par_ob_tran<T, Parameters> const& proj_parm)
499             : detail::ob_tran::base_ob_tran_oblique<T, Parameters>(proj_parm)
500         {
501             // already done
502             //detail::ob_tran::setup_ob_tran(this->m_par, this->m_proj_parm);
503         }
504     };
505
506     /*!
507         \brief General Oblique Transformation projection
508         \ingroup projections
509         \tparam Geographic latlong point type
510         \tparam Cartesian xy point type
511         \tparam Parameters parameter type
512         \par Projection characteristics
513          - Miscellaneous
514          - Spheroid
515         \par Projection parameters
516          - o_proj (string)
517          - Plus projection parameters
518          - o_lat_p (degrees)
519          - o_lon_p (degrees)
520          - New pole
521          - o_alpha: Alpha (degrees)
522          - o_lon_c (degrees)
523          - o_lat_c (degrees)
524          - o_lon_1 (degrees)
525          - o_lat_1: Latitude of first standard parallel (degrees)
526          - o_lon_2 (degrees)
527          - o_lat_2: Latitude of second standard parallel (degrees)
528         \par Example
529         \image html ex_ob_tran.gif
530     */
531     template <typename T, typename Parameters>
532     struct ob_tran_transverse : public detail::ob_tran::base_ob_tran_transverse<T, Parameters>
533     {        
534         template <typename Params>
535         inline ob_tran_transverse(Params const& , Parameters const& ,
536                                   detail::ob_tran::par_ob_tran<T, Parameters> const& proj_parm)
537             : detail::ob_tran::base_ob_tran_transverse<T, Parameters>(proj_parm)
538         {
539             // already done
540             //detail::ob_tran::setup_ob_tran(this->m_par, this->m_proj_parm);
541         }
542     };
543
544     /*!
545         \brief General Oblique Transformation projection
546         \ingroup projections
547         \tparam Geographic latlong point type
548         \tparam Cartesian xy point type
549         \tparam Parameters parameter type
550         \par Projection characteristics
551          - Miscellaneous
552          - Spheroid
553         \par Projection parameters
554          - o_proj (string)
555          - Plus projection parameters
556          - o_lat_p (degrees)
557          - o_lon_p (degrees)
558          - New pole
559          - o_alpha: Alpha (degrees)
560          - o_lon_c (degrees)
561          - o_lat_c (degrees)
562          - o_lon_1 (degrees)
563          - o_lat_1: Latitude of first standard parallel (degrees)
564          - o_lon_2 (degrees)
565          - o_lat_2: Latitude of second standard parallel (degrees)
566         \par Example
567         \image html ex_ob_tran.gif
568     */
569     template <typename StaticParameters, typename T, typename Parameters>
570     struct ob_tran_static : public detail::ob_tran::base_ob_tran_static<StaticParameters, T, Parameters>
571     {
572         inline ob_tran_static(StaticParameters const& params, Parameters const& par)
573             : detail::ob_tran::base_ob_tran_static<StaticParameters, T, Parameters>(params, par)
574         {
575             T phip = detail::ob_tran::setup_ob_tran<T>(params, par, this->m_proj_parm);
576             this->m_is_oblique = fabs(phip) > detail::ob_tran::tolerance;
577         }
578     };
579
580     #ifndef DOXYGEN_NO_DETAIL
581     namespace detail
582     {
583
584         // Static projection
585         template <typename SP, typename CT, typename P>
586         struct static_projection_type<srs::spar::proj_ob_tran, srs_sphere_tag, SP, CT, P>
587         {
588             typedef static_wrapper_fi<ob_tran_static<SP, CT, P>, P> type;
589         };
590         template <typename SP, typename CT, typename P>
591         struct static_projection_type<srs::spar::proj_ob_tran, srs_spheroid_tag, SP, CT, P>
592         {
593             typedef static_wrapper_fi<ob_tran_static<SP, CT, P>, P> type;
594         };
595
596         // Factory entry(s)
597         BOOST_GEOMETRY_PROJECTIONS_DETAIL_FACTORY_ENTRY_BEGIN(ob_tran_entry)
598         {
599             Parameters parameters_copy = parameters;
600             detail::ob_tran::par_ob_tran<T, Parameters> proj_parm(params, parameters_copy);
601             T phip = detail::ob_tran::setup_ob_tran<T>(params, parameters_copy, proj_parm);
602
603             if (fabs(phip) > detail::ob_tran::tolerance)
604                 return new dynamic_wrapper_fi<ob_tran_oblique<T, Parameters>, T, Parameters>(params, parameters_copy, proj_parm);
605             else
606                 return new dynamic_wrapper_fi<ob_tran_transverse<T, Parameters>, T, Parameters>(params, parameters_copy, proj_parm);
607         }
608         BOOST_GEOMETRY_PROJECTIONS_DETAIL_FACTORY_ENTRY_END
609
610         BOOST_GEOMETRY_PROJECTIONS_DETAIL_FACTORY_INIT_BEGIN(ob_tran_init)
611         {
612             BOOST_GEOMETRY_PROJECTIONS_DETAIL_FACTORY_INIT_ENTRY(ob_tran, ob_tran_entry)
613         }
614
615     } // namespace detail
616     #endif // doxygen
617
618 } // namespace projections
619
620 }} // namespace boost::geometry
621
622 #endif // BOOST_GEOMETRY_PROJECTIONS_OB_TRAN_HPP
623