| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726 | // Boost.Geometry (aka GGL, Generic Geometry Library)// Copyright (c) 2017-2018, 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_TRANSFORMATION_HPP#define BOOST_GEOMETRY_SRS_TRANSFORMATION_HPP#include <string>#include <boost/geometry/algorithms/convert.hpp>#include <boost/geometry/core/coordinate_dimension.hpp>#include <boost/geometry/geometries/point.hpp>#include <boost/geometry/geometries/multi_point.hpp>#include <boost/geometry/geometries/linestring.hpp>#include <boost/geometry/geometries/ring.hpp>#include <boost/geometry/geometries/segment.hpp>#include <boost/geometry/srs/projection.hpp>#include <boost/geometry/srs/projections/grids.hpp>#include <boost/geometry/srs/projections/impl/pj_transform.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 { namespace detail{template <typename T1, typename T2>inline bool same_object(T1 const& , T2 const& ){    return false;}template <typename T>inline bool same_object(T const& o1, T const& o2){    return boost::addressof(o1) == boost::addressof(o2);}template<    typename PtIn,    typename PtOut,    bool SameUnits = boost::is_same                        <                            typename geometry::detail::cs_angular_units<PtIn>::type,                            typename geometry::detail::cs_angular_units<PtOut>::type                        >::value>struct transform_geometry_point_coordinates{    static inline void apply(PtIn const& in, PtOut & out, bool /*enable_angles*/)    {        geometry::set<0>(out, geometry::get<0>(in));        geometry::set<1>(out, geometry::get<1>(in));    }};template <typename PtIn, typename PtOut>struct transform_geometry_point_coordinates<PtIn, PtOut, false>{    static inline void apply(PtIn const& in, PtOut & out, bool enable_angles)    {        if (enable_angles)        {            geometry::set_from_radian<0>(out, geometry::get_as_radian<0>(in));            geometry::set_from_radian<1>(out, geometry::get_as_radian<1>(in));        }        else        {            geometry::set<0>(out, geometry::get<0>(in));            geometry::set<1>(out, geometry::get<1>(in));        }    }};template <typename Geometry, typename CT>struct transform_geometry_point{    typedef typename geometry::point_type<Geometry>::type point_type;    typedef geometry::model::point        <               typename select_most_precise                <                    typename geometry::coordinate_type<point_type>::type,                    CT                >::type,            geometry::dimension<point_type>::type::value,            typename geometry::coordinate_system<point_type>::type        > type;    template <typename PtIn, typename PtOut>    static inline void apply(PtIn const& in, PtOut & out, bool enable_angles)    {        transform_geometry_point_coordinates<PtIn, PtOut>::apply(in, out, enable_angles);        projections::detail::copy_higher_dimensions<2>(in, out);    }};template <typename Geometry, typename CT>struct transform_geometry_range_base{    struct convert_strategy    {        convert_strategy(bool enable_angles)            : m_enable_angles(enable_angles)        {}        template <typename PtIn, typename PtOut>        void apply(PtIn const& in, PtOut & out)        {            transform_geometry_point<Geometry, CT>::apply(in, out, m_enable_angles);        }        bool m_enable_angles;    };    template <typename In, typename Out>    static inline void apply(In const& in, Out & out, bool enable_angles)    {        // Change the order and/or closure if needed        // In - arbitrary geometry        // Out - either Geometry or std::vector        // So the order and closure of In and Geometry shoudl be compared        // std::vector's order is assumed to be the same as of Geometry        geometry::detail::conversion::range_to_range            <                In,                Out,                geometry::point_order<In>::value != geometry::point_order<Out>::value            >::apply(in, out, convert_strategy(enable_angles));    }};template<    typename Geometry,    typename CT,    typename Tag = typename geometry::tag<Geometry>::type>struct transform_geometry{};template <typename Point, typename CT>struct transform_geometry<Point, CT, point_tag>    : transform_geometry_point<Point, CT>{};template <typename Segment, typename CT>struct transform_geometry<Segment, CT, segment_tag>{    typedef geometry::model::segment        <            typename transform_geometry_point<Segment, CT>::type        > type;    template <typename In, typename Out>    static inline void apply(In const& in, Out & out, bool enable_angles)    {        apply<0>(in, out, enable_angles);        apply<1>(in, out, enable_angles);    }private:    template <std::size_t Index, typename In, typename Out>    static inline void apply(In const& in, Out & out, bool enable_angles)    {        geometry::detail::indexed_point_view<In const, Index> in_pt(in);        geometry::detail::indexed_point_view<Out, Index> out_pt(out);        transform_geometry_point<Segment, CT>::apply(in_pt, out_pt, enable_angles);    }};template <typename MultiPoint, typename CT>struct transform_geometry<MultiPoint, CT, multi_point_tag>    : transform_geometry_range_base<MultiPoint, CT>{    typedef model::multi_point        <            typename transform_geometry_point<MultiPoint, CT>::type        > type;};template <typename LineString, typename CT>struct transform_geometry<LineString, CT, linestring_tag>    : transform_geometry_range_base<LineString, CT>{    typedef model::linestring        <            typename transform_geometry_point<LineString, CT>::type        > type;};template <typename Ring, typename CT>struct transform_geometry<Ring, CT, ring_tag>    : transform_geometry_range_base<Ring, CT>{    typedef model::ring        <            typename transform_geometry_point<Ring, CT>::type,            geometry::point_order<Ring>::value == clockwise,            geometry::closure<Ring>::value == closed        > type;};template<    typename OutGeometry,    typename CT,    bool EnableTemporary = ! boost::is_same                                <                                    typename select_most_precise                                        <                                            typename geometry::coordinate_type<OutGeometry>::type,                                            CT                                        >::type,                                    typename geometry::coordinate_type<OutGeometry>::type                                >::type::value>struct transform_geometry_wrapper{    typedef transform_geometry<OutGeometry, CT> transform;    typedef typename transform::type type;    template <typename InGeometry>    transform_geometry_wrapper(InGeometry const& in, OutGeometry & out, bool input_angles)        : m_out(out)    {        transform::apply(in, m_temp, input_angles);    }    type & get() { return m_temp; }    void finish() { geometry::convert(m_temp, m_out); } // this is always copy 1:1 without changing the order or closureprivate:    type m_temp;    OutGeometry & m_out;};template<    typename OutGeometry,    typename CT>struct transform_geometry_wrapper<OutGeometry, CT, false>{    typedef transform_geometry<OutGeometry, CT> transform;    typedef OutGeometry type;    transform_geometry_wrapper(OutGeometry const& in, OutGeometry & out, bool input_angles)        : m_out(out)    {        if (! same_object(in, out))            transform::apply(in, out, input_angles);    }    template <typename InGeometry>    transform_geometry_wrapper(InGeometry const& in, OutGeometry & out, bool input_angles)        : m_out(out)    {        transform::apply(in, out, input_angles);    }    OutGeometry & get() { return m_out; }    void finish() {}private:    OutGeometry & m_out;};template <typename CT>struct transform_range{    template    <        typename Proj1, typename Par1,        typename Proj2, typename Par2,        typename RangeIn, typename RangeOut,        typename Grids    >    static inline bool apply(Proj1 const& proj1, Par1 const& par1,                             Proj2 const& proj2, Par2 const& par2,                             RangeIn const& in, RangeOut & out,                             Grids const& grids1, Grids const& grids2)    {        // NOTE: this has to be consistent with pj_transform()        bool const input_angles = !par1.is_geocent && par1.is_latlong;        transform_geometry_wrapper<RangeOut, CT> wrapper(in, out, input_angles);        bool res = true;        try        {            res = pj_transform(proj1, par1, proj2, par2, wrapper.get(), grids1, grids2);        }        catch (projection_exception const&)        {            res = false;        }        catch(...)        {            BOOST_RETHROW        }        wrapper.finish();        return res;    }};template <typename Policy>struct transform_multi{    template    <        typename Proj1, typename Par1,        typename Proj2, typename Par2,        typename MultiIn, typename MultiOut,        typename Grids    >    static inline bool apply(Proj1 const& proj1, Par1 const& par1,                             Proj2 const& proj2, Par2 const& par2,                             MultiIn const& in, MultiOut & out,                             Grids const& grids1, Grids const& grids2)    {        if (! same_object(in, out))            range::resize(out, boost::size(in));        return apply(proj1, par1, proj2, par2,                     boost::begin(in), boost::end(in),                     boost::begin(out),                     grids1, grids2);    }private:    template    <        typename Proj1, typename Par1,        typename Proj2, typename Par2,        typename InIt, typename OutIt,        typename Grids    >    static inline bool apply(Proj1 const& proj1, Par1 const& par1,                             Proj2 const& proj2, Par2 const& par2,                             InIt in_first, InIt in_last, OutIt out_first,                             Grids const& grids1, Grids const& grids2)    {        bool res = true;        for ( ; in_first != in_last ; ++in_first, ++out_first )        {            if ( ! Policy::apply(proj1, par1, proj2, par2, *in_first, *out_first, grids1, grids2) )            {                res = false;            }        }        return res;    }};template<    typename Geometry,    typename CT,    typename Tag = typename geometry::tag<Geometry>::type>struct transform    : not_implemented<Tag>{};template <typename Point, typename CT>struct transform<Point, CT, point_tag>{    template    <        typename Proj1, typename Par1,        typename Proj2, typename Par2,        typename PointIn, typename PointOut,        typename Grids    >    static inline bool apply(Proj1 const& proj1, Par1 const& par1,                             Proj2 const& proj2, Par2 const& par2,                             PointIn const& in, PointOut & out,                             Grids const& grids1, Grids const& grids2)    {        // NOTE: this has to be consistent with pj_transform()        bool const input_angles = !par1.is_geocent && par1.is_latlong;        transform_geometry_wrapper<PointOut, CT> wrapper(in, out, input_angles);        typedef typename transform_geometry_wrapper<PointOut, CT>::type point_type;        point_type * ptr = boost::addressof(wrapper.get());        std::pair<point_type *, point_type *> range = std::make_pair(ptr, ptr + 1);        bool res = true;        try        {            res = pj_transform(proj1, par1, proj2, par2, range, grids1, grids2);        }        catch (projection_exception const&)        {            res = false;        }        catch(...)        {            BOOST_RETHROW        }        wrapper.finish();        return res;    }};template <typename MultiPoint, typename CT>struct transform<MultiPoint, CT, multi_point_tag>    : transform_range<CT>{};template <typename Segment, typename CT>struct transform<Segment, CT, segment_tag>{    template    <        typename Proj1, typename Par1,        typename Proj2, typename Par2,        typename SegmentIn, typename SegmentOut,        typename Grids    >    static inline bool apply(Proj1 const& proj1, Par1 const& par1,                             Proj2 const& proj2, Par2 const& par2,                             SegmentIn const& in, SegmentOut & out,                             Grids const& grids1, Grids const& grids2)    {        // NOTE: this has to be consistent with pj_transform()        bool const input_angles = !par1.is_geocent && par1.is_latlong;        transform_geometry_wrapper<SegmentOut, CT> wrapper(in, out, input_angles);        typedef typename geometry::point_type            <                typename transform_geometry_wrapper<SegmentOut, CT>::type            >::type point_type;        point_type points[2];        geometry::detail::assign_point_from_index<0>(wrapper.get(), points[0]);        geometry::detail::assign_point_from_index<1>(wrapper.get(), points[1]);        std::pair<point_type*, point_type*> range = std::make_pair(points, points + 2);        bool res = true;        try        {            res = pj_transform(proj1, par1, proj2, par2, range, grids1, grids2);        }        catch (projection_exception const&)        {            res = false;        }        catch(...)        {            BOOST_RETHROW        }        geometry::detail::assign_point_to_index<0>(points[0], wrapper.get());        geometry::detail::assign_point_to_index<1>(points[1], wrapper.get());        wrapper.finish();        return res;    }};template <typename Linestring, typename CT>struct transform<Linestring, CT, linestring_tag>    : transform_range<CT>{};template <typename MultiLinestring, typename CT>struct transform<MultiLinestring, CT, multi_linestring_tag>    : transform_multi<transform_range<CT> >{};template <typename Ring, typename CT>struct transform<Ring, CT, ring_tag>    : transform_range<CT>{};template <typename Polygon, typename CT>struct transform<Polygon, CT, polygon_tag>{    template    <        typename Proj1, typename Par1,        typename Proj2, typename Par2,        typename PolygonIn, typename PolygonOut,        typename Grids    >    static inline bool apply(Proj1 const& proj1, Par1 const& par1,                             Proj2 const& proj2, Par2 const& par2,                             PolygonIn const& in, PolygonOut & out,                             Grids const& grids1, Grids const& grids2)    {        bool r1 = transform_range                    <                        CT                    >::apply(proj1, par1, proj2, par2,                             geometry::exterior_ring(in),                             geometry::exterior_ring(out),                             grids1, grids2);        bool r2 = transform_multi                    <                        transform_range<CT>                     >::apply(proj1, par1, proj2, par2,                              geometry::interior_rings(in),                              geometry::interior_rings(out),                              grids1, grids2);        return r1 && r2;    }};template <typename MultiPolygon, typename CT>struct transform<MultiPolygon, CT, multi_polygon_tag>    : transform_multi        <            transform                <                    typename boost::range_value<MultiPolygon>::type,                    CT,                    polygon_tag                >        >{};}} // namespace projections::detail    namespace srs{/*!    \brief Representation of projection    \details Either dynamic or static projection representation    \ingroup projection    \tparam Proj1 default_dynamic or static projection parameters    \tparam Proj2 default_dynamic or static projection parameters    \tparam CT calculation type used internally*/template<    typename Proj1 = srs::dynamic,    typename Proj2 = srs::dynamic,    typename CT = double>class transformation{    typedef typename projections::detail::promote_to_double<CT>::type calc_t;public:    // Both static and default constructed    transformation()    {}    // First dynamic, second static and default constructed    template <typename Parameters1>    explicit transformation(Parameters1 const& parameters1,                            typename boost::enable_if_c                                <                                    boost::is_same<Proj1, srs::dynamic>::value                                 && projections::dynamic_parameters<Parameters1>::is_specialized                                >::type * = 0)        : m_proj1(parameters1)    {}    // First static, second static and default constructed    explicit transformation(Proj1 const& parameters1)        : m_proj1(parameters1)    {}    // Both dynamic    template <typename Parameters1, typename Parameters2>    transformation(Parameters1 const& parameters1,                   Parameters2 const& parameters2,                   typename boost::enable_if_c                        <                            boost::is_same<Proj1, srs::dynamic>::value                         && boost::is_same<Proj2, srs::dynamic>::value                         && projections::dynamic_parameters<Parameters1>::is_specialized                         && projections::dynamic_parameters<Parameters2>::is_specialized                        > * = 0)        : m_proj1(parameters1)        , m_proj2(parameters2)    {}    // First dynamic, second static    template <typename Parameters1>    transformation(Parameters1 const& parameters1,                   Proj2 const& parameters2,                   typename boost::enable_if_c                        <                            boost::is_same<Proj1, srs::dynamic>::value                         && projections::dynamic_parameters<Parameters1>::is_specialized                        > * = 0)        : m_proj1(parameters1)        , m_proj2(parameters2)    {}    // First static, second dynamic    template <typename Parameters2>    transformation(Proj1 const& parameters1,                   Parameters2 const& parameters2,                   typename boost::enable_if_c                        <                            boost::is_same<Proj2, srs::dynamic>::value                         && projections::dynamic_parameters<Parameters2>::is_specialized                        > * = 0)        : m_proj1(parameters1)        , m_proj2(parameters2)    {}    // Both static    transformation(Proj1 const& parameters1,                   Proj2 const& parameters2)        : m_proj1(parameters1)        , m_proj2(parameters2)    {}    template <typename GeometryIn, typename GeometryOut>    bool forward(GeometryIn const& in, GeometryOut & out) const    {        return forward(in, out, transformation_grids<detail::empty_grids_storage>());    }    template <typename GeometryIn, typename GeometryOut>    bool inverse(GeometryIn const& in, GeometryOut & out) const    {        return inverse(in, out, transformation_grids<detail::empty_grids_storage>());    }    template <typename GeometryIn, typename GeometryOut, typename GridsStorage>    bool forward(GeometryIn const& in, GeometryOut & out,                 transformation_grids<GridsStorage> const& grids) const    {        BOOST_MPL_ASSERT_MSG((projections::detail::same_tags<GeometryIn, GeometryOut>::value),                             NOT_SUPPORTED_COMBINATION_OF_GEOMETRIES,                             (GeometryIn, GeometryOut));        return projections::detail::transform                <                    GeometryOut,                    calc_t                >::apply(m_proj1.proj(), m_proj1.proj().params(),                         m_proj2.proj(), m_proj2.proj().params(),                         in, out,                         grids.src_grids,                         grids.dst_grids);    }    template <typename GeometryIn, typename GeometryOut, typename GridsStorage>    bool inverse(GeometryIn const& in, GeometryOut & out,                 transformation_grids<GridsStorage> const& grids) const    {        BOOST_MPL_ASSERT_MSG((projections::detail::same_tags<GeometryIn, GeometryOut>::value),                             NOT_SUPPORTED_COMBINATION_OF_GEOMETRIES,                             (GeometryIn, GeometryOut));        return projections::detail::transform                <                    GeometryOut,                    calc_t                >::apply(m_proj2.proj(), m_proj2.proj().params(),                         m_proj1.proj(), m_proj1.proj().params(),                         in, out,                         grids.dst_grids,                         grids.src_grids);    }    template <typename GridsStorage>    inline transformation_grids<GridsStorage> initialize_grids(GridsStorage & grids_storage) const    {        transformation_grids<GridsStorage> result(grids_storage);        using namespace projections::detail;        pj_gridlist_from_nadgrids(m_proj1.proj().params(),                                  result.src_grids);        pj_gridlist_from_nadgrids(m_proj2.proj().params(),                                  result.dst_grids);        return result;    }private:    projections::proj_wrapper<Proj1, CT> m_proj1;    projections::proj_wrapper<Proj2, CT> m_proj2;};} // namespace srs}} // namespace boost::geometry#endif // BOOST_GEOMETRY_SRS_TRANSFORMATION_HPP
 |