• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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>
copy_higher_dimensions(Point1 const & point1,Point2 & 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>
applyboost::geometry::projections::detail::forward_point_projection_policy98     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>
applyboost::geometry::projections::detail::inverse_point_projection_policy107     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>
applyboost::geometry::projections::detail::project_point117     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     {
convert_policyboost::geometry::projections::detail::project_range::convert_policy140         explicit convert_policy(Proj const& proj)
141             : m_proj(proj)
142             , m_result(true)
143         {}
144 
145         template <typename Point1, typename Point2>
applyboost::geometry::projections::detail::project_range::convert_policy146         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 
resultboost::geometry::projections::detail::project_range::convert_policy152         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>
applyboost::geometry::projections::detail::project_range163     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>
applyboost::geometry::projections::detail::project_multi177     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>
applyboost::geometry::projections::detail::project_multi187     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>
applyboost::geometry::projections::detail::project_geometry224     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>
applyboost::geometry::projections::detail::project_geometry233     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>
applyboost::geometry::projections::detail::project_geometry260     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;
applyboost::geometry::projections::dynamic_parameters306     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;
applyboost::geometry::projections::dynamic_parameters316     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>
proj_wrapper(Params const & params,typename boost::enable_if_c<dynamic_parameters<Params>::is_specialized>::type * =0)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 
proj() const353     vprj_t const& proj() const { return *m_ptr; }
mutable_proj()354     vprj_t & mutable_proj() { return *m_ptr; }
355 
356 private:
357     template <typename Params>
create(Params const & 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:
proj() const405     projection_type const& proj() const { return m_proj; }
mutable_proj()406     projection_type & mutable_proj() { return m_proj; }
407 
408 protected:
static_proj_wrapper_base(StaticParameters const & s_params)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:
proj_wrapper()431     proj_wrapper()
432         : base_t(static_parameters_type())
433     {}
434 
proj_wrapper(static_parameters_type const & s_params)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:
projection()449     projection()
450     {}
451 
452     template <typename Params>
projection(Params const & 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>
forward(LL const & ll,XY & xy) const459     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>
inverse(XY const & xy,LL & ll) const476     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:
projection()517     projection()
518     {}
519 
projection(Parameters const & parameters)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>
projection(DynamicParameters const & dynamic_parameters,typename boost::enable_if_c<projections::dynamic_parameters<DynamicParameters>::is_specialized>::type * =0)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
551