1 // Boost.Geometry (aka GGL, Generic Geometry Library)
3 // Copyright (c) 2008-2012 Barend Gehrels, Amsterdam, the Netherlands.
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
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)
13 #ifndef BOOST_GEOMETRY_SRS_PROJECTION_HPP
14 #define BOOST_GEOMETRY_SRS_PROJECTION_HPP
19 #include <boost/geometry/algorithms/convert.hpp>
20 #include <boost/geometry/algorithms/detail/convert_point_to_point.hpp>
22 #include <boost/geometry/core/coordinate_dimension.hpp>
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>
34 #include <boost/geometry/views/detail/indexed_point_view.hpp>
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>
44 namespace boost { namespace geometry
50 #ifndef DOXYGEN_NO_DETAIL
54 template <typename G1, typename G2>
57 static const bool value = boost::is_same
59 typename geometry::tag<G1>::type,
60 typename geometry::tag<G2>::type
64 template <typename CT>
65 struct promote_to_double
67 typedef typename boost::mpl::if_c
69 boost::is_integral<CT>::value || boost::is_same<CT, float>::value,
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)
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,
85 geometry::detail::conversion::point_to_point
87 Point1, Point2, MinDim, lesser_dim
88 > ::apply(point1, point2);
90 // TODO: fill point2 with zeros if dim1 < dim2 ?
91 // currently no need because equal dimensions are checked
95 struct forward_point_projection_policy
97 template <typename LL, typename XY, typename Proj>
98 static inline bool apply(LL const& ll, XY & xy, Proj const& proj)
100 return proj.forward(ll, xy);
104 struct inverse_point_projection_policy
106 template <typename XY, typename LL, typename Proj>
107 static inline bool apply(XY const& xy, LL & ll, Proj const& proj)
109 return proj.inverse(xy, ll);
113 template <typename PointPolicy>
116 template <typename P1, typename P2, typename Proj>
117 static inline bool apply(P1 const& p1, P2 & p2, Proj const& proj)
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);
123 if (! PointPolicy::apply(p1, p2, proj))
125 // For consistency with transformation
126 set_invalid_point(p2);
134 template <typename PointPolicy>
137 template <typename Proj>
138 struct convert_policy
140 explicit convert_policy(Proj const& proj)
145 template <typename Point1, typename Point2>
146 inline void apply(Point1 const& point1, Point2 & point2)
148 if (! project_point<PointPolicy>::apply(point1, point2, m_proj) )
162 template <typename R1, typename R2, typename Proj>
163 static inline bool apply(R1 const& r1, R2 & r2, Proj const& proj)
165 return geometry::detail::conversion::range_to_range
168 geometry::point_order<R1>::value != geometry::point_order<R2>::value
169 >::apply(r1, r2, convert_policy<Proj>(proj)).result();
173 template <typename Policy>
176 template <typename G1, typename G2, typename Proj>
177 static inline bool apply(G1 const& g1, G2 & g2, Proj const& proj)
179 range::resize(g2, boost::size(g1));
180 return apply(boost::begin(g1), boost::end(g1),
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)
190 for ( ; g1_first != g1_last ; ++g1_first, ++g2_first )
192 if (! Policy::apply(*g1_first, *g2_first, proj))
204 typename PointPolicy,
205 typename Tag = typename geometry::tag<Geometry>::type
207 struct project_geometry
210 template <typename Geometry, typename PointPolicy>
211 struct project_geometry<Geometry, PointPolicy, point_tag>
212 : project_point<PointPolicy>
215 template <typename Geometry, typename PointPolicy>
216 struct project_geometry<Geometry, PointPolicy, multi_point_tag>
217 : project_range<PointPolicy>
220 template <typename Geometry, typename PointPolicy>
221 struct project_geometry<Geometry, PointPolicy, segment_tag>
223 template <typename G1, typename G2, typename Proj>
224 static inline bool apply(G1 const& g1, G2 & g2, Proj const& proj)
226 bool r1 = apply<0>(g1, g2, proj);
227 bool r2 = apply<1>(g1, g2, proj);
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)
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);
241 template <typename Geometry, typename PointPolicy>
242 struct project_geometry<Geometry, PointPolicy, linestring_tag>
243 : project_range<PointPolicy>
246 template <typename Geometry, typename PointPolicy>
247 struct project_geometry<Geometry, PointPolicy, multi_linestring_tag>
248 : project_multi< project_range<PointPolicy> >
251 template <typename Geometry, typename PointPolicy>
252 struct project_geometry<Geometry, PointPolicy, ring_tag>
253 : project_range<PointPolicy>
256 template <typename Geometry, typename PointPolicy>
257 struct project_geometry<Geometry, PointPolicy, polygon_tag>
259 template <typename G1, typename G2, typename Proj>
260 static inline bool apply(G1 const& g1, G2 & g2, Proj const& proj)
262 bool r1 = project_range
265 >::apply(geometry::exterior_ring(g1),
266 geometry::exterior_ring(g2),
268 bool r2 = project_multi
270 project_range<PointPolicy>
271 >::apply(geometry::interior_rings(g1),
272 geometry::interior_rings(g2),
278 template <typename MultiPolygon, typename PointPolicy>
279 struct project_geometry<MultiPolygon, PointPolicy, multi_polygon_tag>
284 typename boost::range_value<MultiPolygon>::type,
292 } // namespace detail
293 #endif // DOXYGEN_NO_DETAIL
296 template <typename Params>
297 struct dynamic_parameters
299 static const bool is_specialized = false;
303 struct dynamic_parameters<srs::proj4>
305 static const bool is_specialized = true;
306 static inline srs::detail::proj4_parameters apply(srs::proj4 const& params)
308 return srs::detail::proj4_parameters(params.str());
312 template <typename T>
313 struct dynamic_parameters<srs::dpar::parameters<T> >
315 static const bool is_specialized = true;
316 static inline srs::dpar::parameters<T> const& apply(srs::dpar::parameters<T> const& params)
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>
328 BOOST_MPL_ASSERT_MSG((false),
329 UNKNOWN_PROJECTION_DEFINITION,
333 template <typename CT>
334 class proj_wrapper<srs::dynamic, CT>
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;
340 typedef projections::parameters<calc_t> parameters_type;
341 typedef projections::detail::dynamic_wrapper_b<calc_t, parameters_type> vprj_t;
344 template <typename Params>
345 proj_wrapper(Params const& params,
346 typename boost::enable_if_c
348 dynamic_parameters<Params>::is_specialized
350 : m_ptr(create(dynamic_parameters<Params>::apply(params)))
353 vprj_t const& proj() const { return *m_ptr; }
354 vprj_t & mutable_proj() { return *m_ptr; }
357 template <typename Params>
358 static vprj_t* create(Params const& params)
360 parameters_type parameters = projections::detail::pj_init<calc_t>(params);
362 vprj_t* result = projections::detail::create_new(params, parameters);
366 if (parameters.id.is_unknown())
368 BOOST_THROW_EXCEPTION(projection_not_named_exception());
372 // TODO: handle non-string projection id
373 BOOST_THROW_EXCEPTION(projection_unknown_id_exception());
380 boost::shared_ptr<vprj_t> m_ptr;
383 template <typename StaticParameters, typename CT>
384 class static_proj_wrapper_base
386 typedef typename projections::detail::promote_to_double<CT>::type calc_t;
388 typedef projections::parameters<calc_t> parameters_type;
390 typedef typename srs::spar::detail::pick_proj_tag
395 typedef typename projections::detail::static_projection_type
398 typename projections::detail::static_srs_tag<StaticParameters>::type,
402 >::type projection_type;
405 projection_type const& proj() const { return m_proj; }
406 projection_type & mutable_proj() { return m_proj; }
409 explicit static_proj_wrapper_base(StaticParameters const& s_params)
411 projections::detail::pj_init<calc_t>(s_params))
415 projection_type m_proj;
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>
422 typedef srs::spar::parameters<BOOST_GEOMETRY_PROJECTIONS_DETAIL_PX>
423 static_parameters_type;
424 typedef static_proj_wrapper_base
426 static_parameters_type,
432 : base_t(static_parameters_type())
435 proj_wrapper(static_parameters_type const& s_params)
441 // projection class implements transparent forward/inverse projection interface
442 template <typename Proj, typename CT>
444 : private proj_wrapper<Proj, CT>
446 typedef proj_wrapper<Proj, CT> base_t;
452 template <typename Params>
453 explicit projection(Params const& params)
457 /// Forward projection, from Latitude-Longitude to Cartesian
458 template <typename LL, typename XY>
459 inline bool forward(LL const& ll, XY& xy) const
461 BOOST_MPL_ASSERT_MSG((projections::detail::same_tags<LL, XY>::value),
462 NOT_SUPPORTED_COMBINATION_OF_GEOMETRIES,
465 concepts::check_concepts_and_equal_dimensions<LL const, XY>();
467 return projections::detail::project_geometry
470 projections::detail::forward_point_projection_policy
471 >::apply(ll, xy, base_t::proj());
474 /// Inverse projection, from Cartesian to Latitude-Longitude
475 template <typename XY, typename LL>
476 inline bool inverse(XY const& xy, LL& ll) const
478 BOOST_MPL_ASSERT_MSG((projections::detail::same_tags<XY, LL>::value),
479 NOT_SUPPORTED_COMBINATION_OF_GEOMETRIES,
482 concepts::check_concepts_and_equal_dimensions<XY const, LL>();
484 return projections::detail::project_geometry
487 projections::detail::inverse_point_projection_policy
488 >::apply(xy, ll, base_t::proj());
492 } // namespace projections
500 \brief Representation of projection
501 \details Either dynamic or static projection representation
503 \tparam Parameters default dynamic tag or static projection parameters
504 \tparam CT calculation type used internally
508 typename Parameters = srs::dynamic,
512 : public projections::projection<Parameters, CT>
514 typedef projections::projection<Parameters, CT> base_t;
520 projection(Parameters const& parameters)
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
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.
533 template <typename DynamicParameters>
534 projection(DynamicParameters const& dynamic_parameters,
535 typename boost::enable_if_c
537 projections::dynamic_parameters<DynamicParameters>::is_specialized
539 : base_t(dynamic_parameters)
547 }} // namespace boost::geometry
550 #endif // BOOST_GEOMETRY_SRS_PROJECTION_HPP