// Boost.Geometry (aka GGL, Generic Geometry Library) // Copyright (c) 2008-2012 Barend Gehrels, Amsterdam, the Netherlands. // This file was modified by Oracle on 2017. // Modifications copyright (c) 2017, Oracle and/or its affiliates. // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle // Use, modification and distribution is subject to the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) #ifndef BOOST_GEOMETRY_SRS_PROJECTION_HPP #define BOOST_GEOMETRY_SRS_PROJECTION_HPP #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace boost { namespace geometry { namespace projections { #ifndef DOXYGEN_NO_DETAIL namespace detail { template struct same_tags { static const bool value = boost::is_same < typename geometry::tag::type, typename geometry::tag::type >::value; }; template struct promote_to_double { typedef typename boost::mpl::if_c < boost::is_integral::value || boost::is_same::value, double, CT >::type type; }; // Copy coordinates of dimensions >= MinDim template inline void copy_higher_dimensions(Point1 const& point1, Point2 & point2) { static const std::size_t dim1 = geometry::dimension::value; static const std::size_t dim2 = geometry::dimension::value; static const std::size_t lesser_dim = dim1 < dim2 ? dim1 : dim2; BOOST_MPL_ASSERT_MSG((lesser_dim >= MinDim), THE_DIMENSION_OF_POINTS_IS_TOO_SMALL, (Point1, Point2)); geometry::detail::conversion::point_to_point < Point1, Point2, MinDim, lesser_dim > ::apply(point1, point2); // TODO: fill point2 with zeros if dim1 < dim2 ? // currently no need because equal dimensions are checked } struct forward_point_projection_policy { template static inline bool apply(LL const& ll, XY & xy, Proj const& proj) { return proj.forward(ll, xy); } }; struct inverse_point_projection_policy { template static inline bool apply(XY const& xy, LL & ll, Proj const& proj) { return proj.inverse(xy, ll); } }; template struct project_point { template static inline bool apply(P1 const& p1, P2 & p2, Proj const& proj) { // (Geographic -> Cartesian) will be projected, rest will be copied. // So first copy third or higher dimensions projections::detail::copy_higher_dimensions<2>(p1, p2); if (! PointPolicy::apply(p1, p2, proj)) { // For consistency with transformation set_invalid_point(p2); return false; } return true; } }; template struct project_range { template struct convert_policy { explicit convert_policy(Proj const& proj) : m_proj(proj) , m_result(true) {} template inline void apply(Point1 const& point1, Point2 & point2) { if (! project_point::apply(point1, point2, m_proj) ) m_result = false; } bool result() const { return m_result; } private: Proj const& m_proj; bool m_result; }; template static inline bool apply(R1 const& r1, R2 & r2, Proj const& proj) { return geometry::detail::conversion::range_to_range < R1, R2, geometry::point_order::value != geometry::point_order::value >::apply(r1, r2, convert_policy(proj)).result(); } }; template struct project_multi { template static inline bool apply(G1 const& g1, G2 & g2, Proj const& proj) { range::resize(g2, boost::size(g1)); return apply(boost::begin(g1), boost::end(g1), boost::begin(g2), proj); } private: template static inline bool apply(It1 g1_first, It1 g1_last, It2 g2_first, Proj const& proj) { bool result = true; for ( ; g1_first != g1_last ; ++g1_first, ++g2_first ) { if (! Policy::apply(*g1_first, *g2_first, proj)) { result = false; } } return result; } }; template < typename Geometry, typename PointPolicy, typename Tag = typename geometry::tag::type > struct project_geometry {}; template struct project_geometry : project_point {}; template struct project_geometry : project_range {}; template struct project_geometry { template static inline bool apply(G1 const& g1, G2 & g2, Proj const& proj) { bool r1 = apply<0>(g1, g2, proj); bool r2 = apply<1>(g1, g2, proj); return r1 && r2; } private: template static inline bool apply(G1 const& g1, G2 & g2, Proj const& proj) { geometry::detail::indexed_point_view pt1(g1); geometry::detail::indexed_point_view pt2(g2); return project_point::apply(pt1, pt2, proj); } }; template struct project_geometry : project_range {}; template struct project_geometry : project_multi< project_range > {}; template struct project_geometry : project_range {}; template struct project_geometry { template static inline bool apply(G1 const& g1, G2 & g2, Proj const& proj) { bool r1 = project_range < PointPolicy >::apply(geometry::exterior_ring(g1), geometry::exterior_ring(g2), proj); bool r2 = project_multi < project_range >::apply(geometry::interior_rings(g1), geometry::interior_rings(g2), proj); return r1 && r2; } }; template struct project_geometry : project_multi < project_geometry < typename boost::range_value::type, PointPolicy, polygon_tag > > {}; } // namespace detail #endif // DOXYGEN_NO_DETAIL template struct dynamic_parameters { BOOST_MPL_ASSERT_MSG((false), NOT_IMPLEMENTED_FOR_THESE_PARAMETERS, (Params)); }; template struct dynamic_parameters { static inline projections::parameters apply(srs::proj4 const& params) { return projections::detail::pj_init_plus(srs::dynamic(), params.str); } }; // proj_wrapper class and its specializations wrapps the internal projection // representation and implements transparent creation of projection object template class proj_wrapper { BOOST_MPL_ASSERT_MSG((false), NOT_IMPLEMENTED_FOR_THIS_PROJECTION, (Proj)); }; template class proj_wrapper { // Some projections do not work with float -> wrong results // select from int/float/double and else selects T typedef typename projections::detail::promote_to_double::type calc_t; typedef projections::parameters parameters_type; typedef projections::detail::base_v vprj_t; public: template proj_wrapper(Params const& params) : m_ptr(create(projections::dynamic_parameters::apply(params))) {} vprj_t const& proj() const { return *m_ptr; } vprj_t & mutable_proj() { return *m_ptr; } private: static vprj_t* create(parameters_type const& pj_params) { vprj_t* result = projections::detail::create_new(pj_params); if (result == NULL) { if (pj_params.name.empty()) { BOOST_THROW_EXCEPTION(projection_not_named_exception()); } else { BOOST_THROW_EXCEPTION(projection_unknown_id_exception(pj_params.name)); } } return result; } boost::shared_ptr m_ptr; }; template class static_proj_wrapper_base { typedef typename projections::detail::promote_to_double::type calc_t; typedef projections::parameters parameters_type; typedef typename srs::par4::detail::pick_proj_tag < StaticParameters >::type proj_tag; typedef typename srs::par4::detail::pick_ellps < StaticParameters >::type ellps_type; typedef typename projections::detail::static_projection_type < proj_tag, typename geometry::tag < typename srs::par4::detail::ellps_traits < ellps_type >::model_type >::type, StaticParameters, calc_t, parameters_type >::type projection_type; public: projection_type const& proj() const { return m_proj; } projection_type & mutable_proj() { return m_proj; } protected: explicit static_proj_wrapper_base(StaticParameters const& s_params, bool use_defaults = true) : m_proj(get_parameters(s_params, "", use_defaults)) {} static_proj_wrapper_base(StaticParameters const& s_params, srs::proj4 const& params, bool use_defaults = true) : m_proj(get_parameters(s_params, params.str, use_defaults)) {} private: static parameters_type get_parameters(StaticParameters const& s_params, std::string const& params_str, bool use_defaults) { return projections::detail::pj_init_plus(s_params, params_str, use_defaults); } projection_type m_proj; }; template class proj_wrapper, CT> : public static_proj_wrapper_base, CT> { typedef srs::static_proj4 static_parameters_type; typedef static_proj_wrapper_base < static_parameters_type, CT > base_t; public: proj_wrapper() : base_t(static_parameters_type()) {} proj_wrapper(static_parameters_type const& s_params) : base_t(s_params) {} proj_wrapper(srs::proj4 const& params) : base_t(static_parameters_type(), params) {} proj_wrapper(static_parameters_type const& s_params, srs::proj4 const& params) : base_t(s_params, params) {} }; // projection class implements transparent forward/inverse projection interface template class projection : private proj_wrapper { typedef proj_wrapper base_t; public: projection() {} template explicit projection(Params const& params) : base_t(params) {} template projection(SParams const& s_params, Params const& params) : base_t(s_params, params) {} /// Forward projection, from Latitude-Longitude to Cartesian template inline bool forward(LL const& ll, XY& xy) const { BOOST_MPL_ASSERT_MSG((projections::detail::same_tags::value), NOT_SUPPORTED_COMBINATION_OF_GEOMETRIES, (LL, XY)); concepts::check_concepts_and_equal_dimensions(); return projections::detail::project_geometry < LL, projections::detail::forward_point_projection_policy >::apply(ll, xy, base_t::proj()); } /// Inverse projection, from Cartesian to Latitude-Longitude template inline bool inverse(XY const& xy, LL& ll) const { BOOST_MPL_ASSERT_MSG((projections::detail::same_tags::value), NOT_SUPPORTED_COMBINATION_OF_GEOMETRIES, (XY, LL)); concepts::check_concepts_and_equal_dimensions(); return projections::detail::project_geometry < XY, projections::detail::inverse_point_projection_policy >::apply(xy, ll, base_t::proj()); } }; } // namespace projections namespace srs { /*! \brief Representation of projection \details Either dynamic or static projection representation \ingroup projection \tparam Proj default_dynamic or static projection parameters \tparam CT calculation type used internally */ template < typename Proj = srs::dynamic, typename CT = double > class projection { BOOST_MPL_ASSERT_MSG((false), NOT_IMPLEMENTED_FOR_THIS_PROJECTION, (Proj)); }; template class projection : public projections::projection { typedef projections::projection base_t; public: /*! \ingroup projection \brief Initializes a projection as a string, using the format with + and = \details The projection can be initialized with a string (with the same format as the PROJ4 package) for convenient initialization from, for example, the command line \par Example +proj=labrd +ellps=intl +lon_0=46d26'13.95E +lat_0=18d54S +azi=18d54 +k_0=.9995 +x_0=400000 +y_0=800000 for the Madagascar projection. \note Parameters are described in the group */ template projection(Params const& params) : base_t(params) {} }; template class projection, CT> : public projections::projection, CT> { typedef projections::projection, CT> base_t; public: projection() {} projection(srs::static_proj4 const& params) : base_t(params) {} #ifdef BOOST_GEOMETRY_SRS_ENABLE_STATIC_PROJECTION_HYBRID_INTERFACE projection(srs::proj4 const& params) : base_t(params) {} projection(srs::static_proj4 const& s_params, srs::proj4 const& params) : base_t(s_params, params) {} #endif }; } // namespace srs }} // namespace boost::geometry #endif // BOOST_GEOMETRY_SRS_PROJECTION_HPP