Imported Upstream version 1.72.0
[platform/upstream/boost.git] / boost / geometry / srs / projection.hpp
1 // Boost.Geometry (aka GGL, Generic Geometry Library)
2
3 // Copyright (c) 2008-2012 Barend Gehrels, Amsterdam, the Netherlands.
4
5 // This file was modified by Oracle on 2017, 2018.
6 // Modifications copyright (c) 2017-2018, 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 #ifndef BOOST_GEOMETRY_SRS_PROJECTION_HPP
14 #define BOOST_GEOMETRY_SRS_PROJECTION_HPP
15
16
17 #include <string>
18
19 #include <boost/geometry/algorithms/convert.hpp>
20 #include <boost/geometry/algorithms/detail/convert_point_to_point.hpp>
21
22 #include <boost/geometry/core/coordinate_dimension.hpp>
23
24 #include <boost/geometry/srs/projections/dpar.hpp>
25 #include <boost/geometry/srs/projections/exception.hpp>
26 #include <boost/geometry/srs/projections/factory.hpp>
27 #include <boost/geometry/srs/projections/impl/base_dynamic.hpp>
28 #include <boost/geometry/srs/projections/impl/base_static.hpp>
29 #include <boost/geometry/srs/projections/impl/pj_init.hpp>
30 #include <boost/geometry/srs/projections/invalid_point.hpp>
31 #include <boost/geometry/srs/projections/proj4.hpp>
32 #include <boost/geometry/srs/projections/spar.hpp>
33
34 #include <boost/geometry/views/detail/indexed_point_view.hpp>
35
36 #include <boost/mpl/assert.hpp>
37 #include <boost/mpl/if.hpp>
38 #include <boost/smart_ptr/shared_ptr.hpp>
39 #include <boost/throw_exception.hpp>
40 #include <boost/type_traits/is_integral.hpp>
41 #include <boost/type_traits/is_same.hpp>
42
43
44 namespace boost { namespace geometry
45 {
46     
47 namespace projections
48 {
49
50 #ifndef DOXYGEN_NO_DETAIL
51 namespace detail
52 {
53
54 template <typename G1, typename G2>
55 struct same_tags
56 {
57     static const bool value = boost::is_same
58         <
59             typename geometry::tag<G1>::type,
60             typename geometry::tag<G2>::type
61         >::value;
62 };
63
64 template <typename CT>
65 struct promote_to_double
66 {
67     typedef typename boost::mpl::if_c
68         <
69             boost::is_integral<CT>::value || boost::is_same<CT, float>::value,
70             double, CT
71         >::type type;
72 };
73
74 // Copy coordinates of dimensions >= MinDim
75 template <std::size_t MinDim, typename Point1, typename Point2>
76 inline void copy_higher_dimensions(Point1 const& point1, Point2 & point2)
77 {
78     static const std::size_t dim1 = geometry::dimension<Point1>::value;
79     static const std::size_t dim2 = geometry::dimension<Point2>::value;
80     static const std::size_t lesser_dim = dim1 < dim2 ? dim1 : dim2;
81     BOOST_MPL_ASSERT_MSG((lesser_dim >= MinDim),
82                          THE_DIMENSION_OF_POINTS_IS_TOO_SMALL,
83                          (Point1, Point2));
84
85     geometry::detail::conversion::point_to_point
86         <
87             Point1, Point2, MinDim, lesser_dim
88         > ::apply(point1, point2);
89
90     // TODO: fill point2 with zeros if dim1 < dim2 ?
91     // currently no need because equal dimensions are checked
92 }
93
94
95 struct forward_point_projection_policy
96 {
97     template <typename LL, typename XY, typename Proj>
98     static inline bool apply(LL const& ll, XY & xy, Proj const& proj)
99     {
100         return proj.forward(ll, xy);
101     }
102 };
103
104 struct inverse_point_projection_policy
105 {
106     template <typename XY, typename LL, typename Proj>
107     static inline bool apply(XY const& xy, LL & ll, Proj const& proj)
108     {
109         return proj.inverse(xy, ll);
110     }
111 };
112
113 template <typename PointPolicy>
114 struct project_point
115 {
116     template <typename P1, typename P2, typename Proj>
117     static inline bool apply(P1 const& p1, P2 & p2, Proj const& proj)
118     {
119         // (Geographic -> Cartesian) will be projected, rest will be copied.
120         // So first copy third or higher dimensions
121         projections::detail::copy_higher_dimensions<2>(p1, p2);
122
123         if (! PointPolicy::apply(p1, p2, proj))
124         {
125             // For consistency with transformation
126             set_invalid_point(p2);
127             return false;
128         }
129
130         return true;
131     }
132 };
133
134 template <typename PointPolicy>
135 struct project_range
136 {
137     template <typename Proj>
138     struct convert_policy
139     {
140         explicit convert_policy(Proj const& proj)
141             : m_proj(proj)
142             , m_result(true)
143         {}
144
145         template <typename Point1, typename Point2>
146         inline void apply(Point1 const& point1, Point2 & point2)
147         {
148             if (! project_point<PointPolicy>::apply(point1, point2, m_proj) )
149                 m_result = false;
150         }
151
152         bool result() const
153         {
154             return m_result;
155         }
156
157     private:
158         Proj const& m_proj;
159         bool m_result;
160     };
161
162     template <typename R1, typename R2, typename Proj>
163     static inline bool apply(R1 const& r1, R2 & r2, Proj const& proj)
164     {
165         return geometry::detail::conversion::range_to_range
166             <
167                 R1, R2,
168                 geometry::point_order<R1>::value != geometry::point_order<R2>::value
169             >::apply(r1, r2, convert_policy<Proj>(proj)).result();
170     }
171 };
172
173 template <typename Policy>
174 struct project_multi
175 {
176     template <typename G1, typename G2, typename Proj>
177     static inline bool apply(G1 const& g1, G2 & g2, Proj const& proj)
178     {
179         range::resize(g2, boost::size(g1));
180         return apply(boost::begin(g1), boost::end(g1),
181                      boost::begin(g2),
182                      proj);
183     }
184
185 private:
186     template <typename It1, typename It2, typename Proj>
187     static inline bool apply(It1 g1_first, It1 g1_last, It2 g2_first, Proj const& proj)
188     {
189         bool result = true;
190         for ( ; g1_first != g1_last ; ++g1_first, ++g2_first )
191         {
192             if (! Policy::apply(*g1_first, *g2_first, proj))
193             {
194                 result = false;
195             }
196         }
197         return result;
198     }
199 };
200
201 template
202 <
203     typename Geometry,
204     typename PointPolicy,
205     typename Tag = typename geometry::tag<Geometry>::type
206 >
207 struct project_geometry
208 {};
209
210 template <typename Geometry, typename PointPolicy>
211 struct project_geometry<Geometry, PointPolicy, point_tag>
212     : project_point<PointPolicy>
213 {};
214
215 template <typename Geometry, typename PointPolicy>
216 struct project_geometry<Geometry, PointPolicy, multi_point_tag>
217     : project_range<PointPolicy>
218 {};
219
220 template <typename Geometry, typename PointPolicy>
221 struct project_geometry<Geometry, PointPolicy, segment_tag>
222 {
223     template <typename G1, typename G2, typename Proj>
224     static inline bool apply(G1 const& g1, G2 & g2, Proj const& proj)
225     {
226         bool r1 = apply<0>(g1, g2, proj);
227         bool r2 = apply<1>(g1, g2, proj);
228         return r1 && r2;
229     }
230
231 private:
232     template <std::size_t Index, typename G1, typename G2, typename Proj>
233     static inline bool apply(G1 const& g1, G2 & g2, Proj const& proj)
234     {
235         geometry::detail::indexed_point_view<G1 const, Index> pt1(g1);
236         geometry::detail::indexed_point_view<G2, Index> pt2(g2);
237         return project_point<PointPolicy>::apply(pt1, pt2, proj);
238     }
239 };
240
241 template <typename Geometry, typename PointPolicy>
242 struct project_geometry<Geometry, PointPolicy, linestring_tag>
243     : project_range<PointPolicy>
244 {};
245
246 template <typename Geometry, typename PointPolicy>
247 struct project_geometry<Geometry, PointPolicy, multi_linestring_tag>
248     : project_multi< project_range<PointPolicy> >
249 {};
250
251 template <typename Geometry, typename PointPolicy>
252 struct project_geometry<Geometry, PointPolicy, ring_tag>
253     : project_range<PointPolicy>
254 {};
255
256 template <typename Geometry, typename PointPolicy>
257 struct project_geometry<Geometry, PointPolicy, polygon_tag>
258 {
259     template <typename G1, typename G2, typename Proj>
260     static inline bool apply(G1 const& g1, G2 & g2, Proj const& proj)
261     {
262         bool r1 = project_range
263                     <
264                         PointPolicy
265                     >::apply(geometry::exterior_ring(g1),
266                              geometry::exterior_ring(g2),
267                              proj);
268         bool r2 = project_multi
269                     <
270                         project_range<PointPolicy>
271                     >::apply(geometry::interior_rings(g1),
272                              geometry::interior_rings(g2),
273                              proj);
274         return r1 && r2;
275     }
276 };
277
278 template <typename MultiPolygon, typename PointPolicy>
279 struct project_geometry<MultiPolygon, PointPolicy, multi_polygon_tag>
280     : project_multi
281         <
282             project_geometry
283             <
284                 typename boost::range_value<MultiPolygon>::type,
285                 PointPolicy,
286                 polygon_tag
287             >
288         >
289 {};
290
291
292 } // namespace detail
293 #endif // DOXYGEN_NO_DETAIL
294
295
296 template <typename Params>
297 struct dynamic_parameters
298 {
299     static const bool is_specialized = false;
300 };
301
302 template <>
303 struct dynamic_parameters<srs::proj4>
304 {
305     static const bool is_specialized = true;
306     static inline srs::detail::proj4_parameters apply(srs::proj4 const& params)
307     {
308         return srs::detail::proj4_parameters(params.str());
309     }
310 };
311
312 template <typename T>
313 struct dynamic_parameters<srs::dpar::parameters<T> >
314 {
315     static const bool is_specialized = true;
316     static inline srs::dpar::parameters<T> const& apply(srs::dpar::parameters<T> const& params)
317     {
318         return params;
319     }
320 };
321
322
323 // proj_wrapper class and its specializations wrapps the internal projection
324 // representation and implements transparent creation of projection object
325 template <typename Proj, typename CT>
326 class proj_wrapper
327 {
328     BOOST_MPL_ASSERT_MSG((false),
329                          UNKNOWN_PROJECTION_DEFINITION,
330                          (Proj));
331 };
332
333 template <typename CT>
334 class proj_wrapper<srs::dynamic, CT>
335 {
336     // Some projections do not work with float -> wrong results
337     // select <double> from int/float/double and else selects T
338     typedef typename projections::detail::promote_to_double<CT>::type calc_t;
339
340     typedef projections::parameters<calc_t> parameters_type;
341     typedef projections::detail::dynamic_wrapper_b<calc_t, parameters_type> vprj_t;
342
343 public:
344     template <typename Params>
345     proj_wrapper(Params const& params,
346                  typename boost::enable_if_c
347                     <
348                         dynamic_parameters<Params>::is_specialized
349                     >::type * = 0)
350         : m_ptr(create(dynamic_parameters<Params>::apply(params)))
351     {}
352
353     vprj_t const& proj() const { return *m_ptr; }
354     vprj_t & mutable_proj() { return *m_ptr; }
355
356 private:
357     template <typename Params>
358     static vprj_t* create(Params const& params)
359     {
360         parameters_type parameters = projections::detail::pj_init<calc_t>(params);
361
362         vprj_t* result = projections::detail::create_new(params, parameters);
363
364         if (result == NULL)
365         {
366             if (parameters.id.is_unknown())
367             {
368                 BOOST_THROW_EXCEPTION(projection_not_named_exception());
369             }
370             else
371             {
372                 // TODO: handle non-string projection id
373                 BOOST_THROW_EXCEPTION(projection_unknown_id_exception());
374             }
375         }
376
377         return result;
378     }
379
380     boost::shared_ptr<vprj_t> m_ptr;
381 };
382
383 template <typename StaticParameters, typename CT>
384 class static_proj_wrapper_base
385 {
386     typedef typename projections::detail::promote_to_double<CT>::type calc_t;
387
388     typedef projections::parameters<calc_t> parameters_type;
389
390     typedef typename srs::spar::detail::pick_proj_tag
391         <
392             StaticParameters
393         >::type proj_tag;
394     
395     typedef typename projections::detail::static_projection_type
396         <
397             proj_tag,
398             typename projections::detail::static_srs_tag<StaticParameters>::type,
399             StaticParameters,
400             calc_t,
401             parameters_type
402         >::type projection_type;
403
404 public:
405     projection_type const& proj() const { return m_proj; }
406     projection_type & mutable_proj() { return m_proj; }
407
408 protected:
409     explicit static_proj_wrapper_base(StaticParameters const& s_params)
410         : m_proj(s_params,
411                  projections::detail::pj_init<calc_t>(s_params))
412     {}
413
414 private:
415     projection_type m_proj;
416 };
417
418 template <BOOST_GEOMETRY_PROJECTIONS_DETAIL_TYPENAME_PX, typename CT>
419 class proj_wrapper<srs::spar::parameters<BOOST_GEOMETRY_PROJECTIONS_DETAIL_PX>, CT>
420     : public static_proj_wrapper_base<srs::spar::parameters<BOOST_GEOMETRY_PROJECTIONS_DETAIL_PX>, CT>
421 {
422     typedef srs::spar::parameters<BOOST_GEOMETRY_PROJECTIONS_DETAIL_PX>
423         static_parameters_type;
424     typedef static_proj_wrapper_base
425         <
426             static_parameters_type,
427             CT
428         > base_t;
429
430 public:
431     proj_wrapper()
432         : base_t(static_parameters_type())
433     {}
434
435     proj_wrapper(static_parameters_type const& s_params)
436         : base_t(s_params)
437     {}
438 };
439
440
441 // projection class implements transparent forward/inverse projection interface
442 template <typename Proj, typename CT>
443 class projection
444     : private proj_wrapper<Proj, CT>
445 {
446     typedef proj_wrapper<Proj, CT> base_t;
447
448 public:
449     projection()
450     {}
451
452     template <typename Params>
453     explicit projection(Params const& params)
454         : base_t(params)
455     {}
456
457     /// Forward projection, from Latitude-Longitude to Cartesian
458     template <typename LL, typename XY>
459     inline bool forward(LL const& ll, XY& xy) const
460     {
461         BOOST_MPL_ASSERT_MSG((projections::detail::same_tags<LL, XY>::value),
462                              NOT_SUPPORTED_COMBINATION_OF_GEOMETRIES,
463                              (LL, XY));
464
465         concepts::check_concepts_and_equal_dimensions<LL const, XY>();
466
467         return projections::detail::project_geometry
468                 <
469                     LL,
470                     projections::detail::forward_point_projection_policy
471                 >::apply(ll, xy, base_t::proj());
472     }
473
474     /// Inverse projection, from Cartesian to Latitude-Longitude
475     template <typename XY, typename LL>
476     inline bool inverse(XY const& xy, LL& ll) const
477     {
478         BOOST_MPL_ASSERT_MSG((projections::detail::same_tags<XY, LL>::value),
479                              NOT_SUPPORTED_COMBINATION_OF_GEOMETRIES,
480                              (XY, LL));
481
482         concepts::check_concepts_and_equal_dimensions<XY const, LL>();
483
484         return projections::detail::project_geometry
485                 <
486                     XY,
487                     projections::detail::inverse_point_projection_policy
488                 >::apply(xy, ll, base_t::proj());
489     }
490 };
491
492 } // namespace projections
493
494
495 namespace srs
496 {
497
498     
499 /*!
500     \brief Representation of projection
501     \details Either dynamic or static projection representation
502     \ingroup projection
503     \tparam Parameters default dynamic tag or static projection parameters
504     \tparam CT calculation type used internally
505 */
506 template
507 <
508     typename Parameters = srs::dynamic,
509     typename CT = double
510 >
511 class projection
512     : public projections::projection<Parameters, CT>
513 {
514     typedef projections::projection<Parameters, CT> base_t;
515
516 public:
517     projection()
518     {}
519
520     projection(Parameters const& parameters)
521         : base_t(parameters)
522     {}
523
524     /*!
525     \ingroup projection
526     \brief Initializes a projection as a string, using the format with + and =
527     \details The projection can be initialized with a string (with the same format as the PROJ4 package) for
528       convenient initialization from, for example, the command line
529     \par Example
530         <tt>srs::proj4("+proj=labrd +ellps=intl +lon_0=46d26'13.95E +lat_0=18d54S +azi=18d54 +k_0=.9995 +x_0=400000 +y_0=800000")</tt>
531         for the Madagascar projection.
532     */
533     template <typename DynamicParameters>
534     projection(DynamicParameters const& dynamic_parameters,
535                typename boost::enable_if_c
536                 <
537                     projections::dynamic_parameters<DynamicParameters>::is_specialized
538                 >::type * = 0)
539         : base_t(dynamic_parameters)
540     {}
541 };
542
543
544 } // namespace srs
545
546
547 }} // namespace boost::geometry
548
549
550 #endif // BOOST_GEOMETRY_SRS_PROJECTION_HPP