summaryrefslogtreecommitdiff
path: root/boost/geometry/srs/projection.hpp
diff options
context:
space:
mode:
Diffstat (limited to 'boost/geometry/srs/projection.hpp')
-rw-r--r--boost/geometry/srs/projection.hpp591
1 files changed, 591 insertions, 0 deletions
diff --git a/boost/geometry/srs/projection.hpp b/boost/geometry/srs/projection.hpp
new file mode 100644
index 0000000000..59c3e8c047
--- /dev/null
+++ b/boost/geometry/srs/projection.hpp
@@ -0,0 +1,591 @@
+// 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 <string>
+
+#include <boost/geometry/algorithms/convert.hpp>
+#include <boost/geometry/algorithms/detail/convert_point_to_point.hpp>
+
+#include <boost/geometry/core/coordinate_dimension.hpp>
+
+#include <boost/geometry/srs/projections/exception.hpp>
+#include <boost/geometry/srs/projections/factory.hpp>
+#include <boost/geometry/srs/projections/impl/base_dynamic.hpp>
+#include <boost/geometry/srs/projections/impl/base_static.hpp>
+#include <boost/geometry/srs/projections/impl/pj_init.hpp>
+#include <boost/geometry/srs/projections/invalid_point.hpp>
+#include <boost/geometry/srs/projections/par4.hpp>
+#include <boost/geometry/srs/projections/proj4.hpp>
+
+#include <boost/geometry/views/detail/indexed_point_view.hpp>
+
+#include <boost/mpl/assert.hpp>
+#include <boost/mpl/if.hpp>
+#include <boost/smart_ptr/shared_ptr.hpp>
+#include <boost/throw_exception.hpp>
+#include <boost/type_traits/is_integral.hpp>
+#include <boost/type_traits/is_same.hpp>
+
+
+namespace boost { namespace geometry
+{
+
+namespace projections
+{
+
+#ifndef DOXYGEN_NO_DETAIL
+namespace detail
+{
+
+template <typename G1, typename G2>
+struct same_tags
+{
+ static const bool value = boost::is_same
+ <
+ typename geometry::tag<G1>::type,
+ typename geometry::tag<G2>::type
+ >::value;
+};
+
+template <typename CT>
+struct promote_to_double
+{
+ typedef typename boost::mpl::if_c
+ <
+ boost::is_integral<CT>::value || boost::is_same<CT, float>::value,
+ double, CT
+ >::type type;
+};
+
+// Copy coordinates of dimensions >= MinDim
+template <std::size_t MinDim, typename Point1, typename Point2>
+inline void copy_higher_dimensions(Point1 const& point1, Point2 & point2)
+{
+ static const std::size_t dim1 = geometry::dimension<Point1>::value;
+ static const std::size_t dim2 = geometry::dimension<Point2>::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 <typename LL, typename XY, typename Proj>
+ static inline bool apply(LL const& ll, XY & xy, Proj const& proj)
+ {
+ return proj.forward(ll, xy);
+ }
+};
+
+struct inverse_point_projection_policy
+{
+ template <typename XY, typename LL, typename Proj>
+ static inline bool apply(XY const& xy, LL & ll, Proj const& proj)
+ {
+ return proj.inverse(xy, ll);
+ }
+};
+
+template <typename PointPolicy>
+struct project_point
+{
+ template <typename P1, typename P2, typename Proj>
+ 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 <typename PointPolicy>
+struct project_range
+{
+ template <typename Proj>
+ struct convert_policy
+ {
+ explicit convert_policy(Proj const& proj)
+ : m_proj(proj)
+ , m_result(true)
+ {}
+
+ template <typename Point1, typename Point2>
+ inline void apply(Point1 const& point1, Point2 & point2)
+ {
+ if (! project_point<PointPolicy>::apply(point1, point2, m_proj) )
+ m_result = false;
+ }
+
+ bool result() const
+ {
+ return m_result;
+ }
+
+ private:
+ Proj const& m_proj;
+ bool m_result;
+ };
+
+ template <typename R1, typename R2, typename Proj>
+ static inline bool apply(R1 const& r1, R2 & r2, Proj const& proj)
+ {
+ return geometry::detail::conversion::range_to_range
+ <
+ R1, R2,
+ geometry::point_order<R1>::value != geometry::point_order<R2>::value
+ >::apply(r1, r2, convert_policy<Proj>(proj)).result();
+ }
+};
+
+template <typename Policy>
+struct project_multi
+{
+ template <typename G1, typename G2, typename Proj>
+ 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 <typename It1, typename It2, typename Proj>
+ 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<Geometry>::type
+>
+struct project_geometry
+{};
+
+template <typename Geometry, typename PointPolicy>
+struct project_geometry<Geometry, PointPolicy, point_tag>
+ : project_point<PointPolicy>
+{};
+
+template <typename Geometry, typename PointPolicy>
+struct project_geometry<Geometry, PointPolicy, multi_point_tag>
+ : project_range<PointPolicy>
+{};
+
+template <typename Geometry, typename PointPolicy>
+struct project_geometry<Geometry, PointPolicy, segment_tag>
+{
+ template <typename G1, typename G2, typename Proj>
+ 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 <std::size_t Index, typename G1, typename G2, typename Proj>
+ static inline bool apply(G1 const& g1, G2 & g2, Proj const& proj)
+ {
+ geometry::detail::indexed_point_view<G1 const, Index> pt1(g1);
+ geometry::detail::indexed_point_view<G2, Index> pt2(g2);
+ return project_point<PointPolicy>::apply(pt1, pt2, proj);
+ }
+};
+
+template <typename Geometry, typename PointPolicy>
+struct project_geometry<Geometry, PointPolicy, linestring_tag>
+ : project_range<PointPolicy>
+{};
+
+template <typename Geometry, typename PointPolicy>
+struct project_geometry<Geometry, PointPolicy, multi_linestring_tag>
+ : project_multi< project_range<PointPolicy> >
+{};
+
+template <typename Geometry, typename PointPolicy>
+struct project_geometry<Geometry, PointPolicy, ring_tag>
+ : project_range<PointPolicy>
+{};
+
+template <typename Geometry, typename PointPolicy>
+struct project_geometry<Geometry, PointPolicy, polygon_tag>
+{
+ template <typename G1, typename G2, typename Proj>
+ 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<PointPolicy>
+ >::apply(geometry::interior_rings(g1),
+ geometry::interior_rings(g2),
+ proj);
+ return r1 && r2;
+ }
+};
+
+template <typename MultiPolygon, typename PointPolicy>
+struct project_geometry<MultiPolygon, PointPolicy, multi_polygon_tag>
+ : project_multi
+ <
+ project_geometry
+ <
+ typename boost::range_value<MultiPolygon>::type,
+ PointPolicy,
+ polygon_tag
+ >
+ >
+{};
+
+
+} // namespace detail
+#endif // DOXYGEN_NO_DETAIL
+
+
+template <typename Params, typename CT>
+struct dynamic_parameters
+{
+ BOOST_MPL_ASSERT_MSG((false),
+ NOT_IMPLEMENTED_FOR_THESE_PARAMETERS,
+ (Params));
+};
+
+template <typename CT>
+struct dynamic_parameters<srs::proj4, CT>
+{
+ static inline projections::parameters<CT> apply(srs::proj4 const& params)
+ {
+ return projections::detail::pj_init_plus<CT>(srs::dynamic(), params.str);
+ }
+};
+
+// proj_wrapper class and its specializations wrapps the internal projection
+// representation and implements transparent creation of projection object
+template <typename Proj, typename CT>
+class proj_wrapper
+{
+ BOOST_MPL_ASSERT_MSG((false),
+ NOT_IMPLEMENTED_FOR_THIS_PROJECTION,
+ (Proj));
+};
+
+template <typename CT>
+class proj_wrapper<srs::dynamic, CT>
+{
+ // Some projections do not work with float -> wrong results
+ // select <double> from int/float/double and else selects T
+ typedef typename projections::detail::promote_to_double<CT>::type calc_t;
+
+ typedef projections::parameters<calc_t> parameters_type;
+ typedef projections::detail::base_v<calc_t, parameters_type> vprj_t;
+
+public:
+ template <typename Params>
+ proj_wrapper(Params const& params)
+ : m_ptr(create(projections::dynamic_parameters<Params, calc_t>::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<vprj_t> m_ptr;
+};
+
+template <typename StaticParameters, typename CT>
+class static_proj_wrapper_base
+{
+ typedef typename projections::detail::promote_to_double<CT>::type calc_t;
+
+ typedef projections::parameters<calc_t> 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<calc_t>(s_params, params_str, use_defaults);
+ }
+
+ projection_type m_proj;
+};
+
+template <BOOST_GEOMETRY_PROJECTIONS_DETAIL_TYPENAME_PX, typename CT>
+class proj_wrapper<srs::static_proj4<BOOST_GEOMETRY_PROJECTIONS_DETAIL_PX>, CT>
+ : public static_proj_wrapper_base<srs::static_proj4<BOOST_GEOMETRY_PROJECTIONS_DETAIL_PX>, CT>
+{
+ typedef srs::static_proj4<BOOST_GEOMETRY_PROJECTIONS_DETAIL_PX>
+ 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 <typename Proj, typename CT>
+class projection
+ : private proj_wrapper<Proj, CT>
+{
+ typedef proj_wrapper<Proj, CT> base_t;
+
+public:
+ projection()
+ {}
+
+ template <typename Params>
+ explicit projection(Params const& params)
+ : base_t(params)
+ {}
+
+ template <typename SParams, typename Params>
+ projection(SParams const& s_params, Params const& params)
+ : base_t(s_params, params)
+ {}
+
+ /// Forward projection, from Latitude-Longitude to Cartesian
+ template <typename LL, typename XY>
+ inline bool forward(LL const& ll, XY& xy) const
+ {
+ BOOST_MPL_ASSERT_MSG((projections::detail::same_tags<LL, XY>::value),
+ NOT_SUPPORTED_COMBINATION_OF_GEOMETRIES,
+ (LL, XY));
+
+ concepts::check_concepts_and_equal_dimensions<LL const, XY>();
+
+ 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 <typename XY, typename LL>
+ inline bool inverse(XY const& xy, LL& ll) const
+ {
+ BOOST_MPL_ASSERT_MSG((projections::detail::same_tags<XY, LL>::value),
+ NOT_SUPPORTED_COMBINATION_OF_GEOMETRIES,
+ (XY, LL));
+
+ concepts::check_concepts_and_equal_dimensions<XY const, LL>();
+
+ 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 <typename CT>
+class projection<srs::dynamic, CT>
+ : public projections::projection<srs::dynamic, CT>
+{
+ typedef projections::projection<srs::dynamic, CT> 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
+ <tt>+proj=labrd +ellps=intl +lon_0=46d26'13.95E +lat_0=18d54S +azi=18d54 +k_0=.9995 +x_0=400000 +y_0=800000</tt>
+ for the Madagascar projection.
+ \note Parameters are described in the group
+ */
+ template <typename Params>
+ projection(Params const& params)
+ : base_t(params)
+ {}
+};
+
+template <BOOST_GEOMETRY_PROJECTIONS_DETAIL_TYPENAME_PX, typename CT>
+class projection<srs::static_proj4<BOOST_GEOMETRY_PROJECTIONS_DETAIL_PX>, CT>
+ : public projections::projection<srs::static_proj4<BOOST_GEOMETRY_PROJECTIONS_DETAIL_PX>, CT>
+{
+ typedef projections::projection<srs::static_proj4<BOOST_GEOMETRY_PROJECTIONS_DETAIL_PX>, CT> base_t;
+
+public:
+ projection()
+ {}
+
+ projection(srs::static_proj4<BOOST_GEOMETRY_PROJECTIONS_DETAIL_PX> 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<BOOST_GEOMETRY_PROJECTIONS_DETAIL_PX> const& s_params,
+ srs::proj4 const& params)
+ : base_t(s_params, params)
+ {}
+#endif
+};
+
+} // namespace srs
+
+
+}} // namespace boost::geometry
+
+
+#endif // BOOST_GEOMETRY_SRS_PROJECTION_HPP