123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741 |
- // Boost.Geometry (aka GGL, Generic Geometry Library)
- // Copyright (c) 2017-2020, 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 <type_traits>
- #include <boost/throw_exception.hpp>
- #include <boost/geometry/algorithms/convert.hpp>
- #include <boost/geometry/core/coordinate_dimension.hpp>
- #include <boost/geometry/core/static_assert.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>
- 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 = std::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 = ! std::is_same
- <
- typename select_most_precise
- <
- typename geometry::coordinate_type<OutGeometry>::type,
- CT
- >::type,
- typename geometry::coordinate_type<OutGeometry>::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 closure
- private:
- 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,
- std::enable_if_t
- <
- std::is_same<Proj1, srs::dynamic>::value
- && projections::dynamic_parameters<Parameters1>::is_specialized,
- int
- > = 0
- >
- explicit transformation(Parameters1 const& parameters1)
- : 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,
- std::enable_if_t
- <
- std::is_same<Proj1, srs::dynamic>::value
- && std::is_same<Proj2, srs::dynamic>::value
- && projections::dynamic_parameters<Parameters1>::is_specialized
- && projections::dynamic_parameters<Parameters2>::is_specialized,
- int
- > = 0
- >
- transformation(Parameters1 const& parameters1,
- Parameters2 const& parameters2)
- : m_proj1(parameters1)
- , m_proj2(parameters2)
- {}
- // First dynamic, second static
- template
- <
- typename Parameters1,
- std::enable_if_t
- <
- std::is_same<Proj1, srs::dynamic>::value
- && projections::dynamic_parameters<Parameters1>::is_specialized,
- int
- > = 0
- >
- transformation(Parameters1 const& parameters1,
- Proj2 const& parameters2)
- : m_proj1(parameters1)
- , m_proj2(parameters2)
- {}
- // First static, second dynamic
- template
- <
- typename Parameters2,
- std::enable_if_t
- <
- std::is_same<Proj2, srs::dynamic>::value
- && projections::dynamic_parameters<Parameters2>::is_specialized,
- int
- > = 0
- >
- transformation(Proj1 const& parameters1,
- Parameters2 const& parameters2)
- : 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_GEOMETRY_STATIC_ASSERT(
- (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_GEOMETRY_STATIC_ASSERT(
- (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
|