File indexing completed on 2025-10-30 08:19:04
0001 
0002 
0003 
0004 
0005 
0006 
0007 
0008 
0009 
0010 
0011 
0012 
0013 
0014 #ifndef BOOST_GEOMETRY_SRS_PROJECTION_HPP
0015 #define BOOST_GEOMETRY_SRS_PROJECTION_HPP
0016 
0017 
0018 #include <memory>
0019 #include <string>
0020 #include <type_traits>
0021 
0022 #include <boost/range/size.hpp>
0023 #include <boost/throw_exception.hpp>
0024 
0025 #include <boost/geometry/algorithms/convert.hpp>
0026 #include <boost/geometry/algorithms/detail/convert_point_to_point.hpp>
0027 
0028 #include <boost/geometry/core/coordinate_dimension.hpp>
0029 #include <boost/geometry/core/static_assert.hpp>
0030 
0031 #include <boost/geometry/srs/projections/dpar.hpp>
0032 #include <boost/geometry/srs/projections/exception.hpp>
0033 #include <boost/geometry/srs/projections/factory.hpp>
0034 #include <boost/geometry/srs/projections/impl/base_dynamic.hpp>
0035 #include <boost/geometry/srs/projections/impl/base_static.hpp>
0036 #include <boost/geometry/srs/projections/impl/pj_init.hpp>
0037 #include <boost/geometry/srs/projections/invalid_point.hpp>
0038 #include <boost/geometry/srs/projections/proj4.hpp>
0039 #include <boost/geometry/srs/projections/spar.hpp>
0040 
0041 #include <boost/geometry/views/detail/indexed_point_view.hpp>
0042 
0043 
0044 namespace boost { namespace geometry
0045 {
0046 
0047 namespace projections
0048 {
0049 
0050 #ifndef DOXYGEN_NO_DETAIL
0051 namespace detail
0052 {
0053 
0054 template <typename G1, typename G2>
0055 struct same_tags
0056     : std::is_same<geometry::tag_t<G1>, geometry::tag_t<G2>>
0057 {};
0058 
0059 template <typename CT>
0060 struct promote_to_double
0061 {
0062     typedef std::conditional_t
0063         <
0064             std::is_integral<CT>::value || std::is_same<CT, float>::value,
0065             double, CT
0066         > type;
0067 };
0068 
0069 
0070 template <std::size_t MinDim, typename Point1, typename Point2>
0071 inline void copy_higher_dimensions(Point1 const& point1, Point2 & point2)
0072 {
0073     static const std::size_t dim1 = geometry::dimension<Point1>::value;
0074     static const std::size_t dim2 = geometry::dimension<Point2>::value;
0075     static const std::size_t lesser_dim = dim1 < dim2 ? dim1 : dim2;
0076     BOOST_GEOMETRY_STATIC_ASSERT((lesser_dim >= MinDim),
0077         "The dimension of Point1 or Point2 is too small.",
0078         Point1, Point2);
0079 
0080     geometry::detail::conversion::point_to_point
0081         <
0082             Point1, Point2, MinDim, lesser_dim
0083         > ::apply(point1, point2);
0084 
0085     
0086     
0087 }
0088 
0089 
0090 struct forward_point_projection_policy
0091 {
0092     template <typename LL, typename XY, typename Proj>
0093     static inline bool apply(LL const& ll, XY & xy, Proj const& proj)
0094     {
0095         return proj.forward(ll, xy);
0096     }
0097 };
0098 
0099 struct inverse_point_projection_policy
0100 {
0101     template <typename XY, typename LL, typename Proj>
0102     static inline bool apply(XY const& xy, LL & ll, Proj const& proj)
0103     {
0104         return proj.inverse(xy, ll);
0105     }
0106 };
0107 
0108 template <typename PointPolicy>
0109 struct project_point
0110 {
0111     template <typename P1, typename P2, typename Proj>
0112     static inline bool apply(P1 const& p1, P2 & p2, Proj const& proj)
0113     {
0114         
0115         
0116         projections::detail::copy_higher_dimensions<2>(p1, p2);
0117 
0118         if (! PointPolicy::apply(p1, p2, proj))
0119         {
0120             
0121             set_invalid_point(p2);
0122             return false;
0123         }
0124 
0125         return true;
0126     }
0127 };
0128 
0129 template <typename PointPolicy>
0130 struct project_range
0131 {
0132     template <typename Proj>
0133     struct convert_policy
0134     {
0135         explicit convert_policy(Proj const& proj)
0136             : m_proj(proj)
0137             , m_result(true)
0138         {}
0139 
0140         template <typename Point1, typename Point2>
0141         inline void apply(Point1 const& point1, Point2 & point2)
0142         {
0143             if (! project_point<PointPolicy>::apply(point1, point2, m_proj) )
0144                 m_result = false;
0145         }
0146 
0147         bool result() const
0148         {
0149             return m_result;
0150         }
0151 
0152     private:
0153         Proj const& m_proj;
0154         bool m_result;
0155     };
0156 
0157     template <typename R1, typename R2, typename Proj>
0158     static inline bool apply(R1 const& r1, R2 & r2, Proj const& proj)
0159     {
0160         return geometry::detail::conversion::range_to_range
0161             <
0162                 R1, R2,
0163                 geometry::point_order<R1>::value != geometry::point_order<R2>::value
0164             >::apply(r1, r2, convert_policy<Proj>(proj)).result();
0165     }
0166 };
0167 
0168 template <typename Policy>
0169 struct project_multi
0170 {
0171     template <typename G1, typename G2, typename Proj>
0172     static inline bool apply(G1 const& g1, G2 & g2, Proj const& proj)
0173     {
0174         range::resize(g2, boost::size(g1));
0175         return apply(boost::begin(g1), boost::end(g1),
0176                      boost::begin(g2),
0177                      proj);
0178     }
0179 
0180 private:
0181     template <typename It1, typename It2, typename Proj>
0182     static inline bool apply(It1 g1_first, It1 g1_last, It2 g2_first, Proj const& proj)
0183     {
0184         bool result = true;
0185         for ( ; g1_first != g1_last ; ++g1_first, ++g2_first )
0186         {
0187             if (! Policy::apply(*g1_first, *g2_first, proj))
0188             {
0189                 result = false;
0190             }
0191         }
0192         return result;
0193     }
0194 };
0195 
0196 template
0197 <
0198     typename Geometry,
0199     typename PointPolicy,
0200     typename Tag = geometry::tag_t<Geometry>
0201 >
0202 struct project_geometry
0203 {};
0204 
0205 template <typename Geometry, typename PointPolicy>
0206 struct project_geometry<Geometry, PointPolicy, point_tag>
0207     : project_point<PointPolicy>
0208 {};
0209 
0210 template <typename Geometry, typename PointPolicy>
0211 struct project_geometry<Geometry, PointPolicy, multi_point_tag>
0212     : project_range<PointPolicy>
0213 {};
0214 
0215 template <typename Geometry, typename PointPolicy>
0216 struct project_geometry<Geometry, PointPolicy, segment_tag>
0217 {
0218     template <typename G1, typename G2, typename Proj>
0219     static inline bool apply(G1 const& g1, G2 & g2, Proj const& proj)
0220     {
0221         bool r1 = apply<0>(g1, g2, proj);
0222         bool r2 = apply<1>(g1, g2, proj);
0223         return r1 && r2;
0224     }
0225 
0226 private:
0227     template <std::size_t Index, typename G1, typename G2, typename Proj>
0228     static inline bool apply(G1 const& g1, G2 & g2, Proj const& proj)
0229     {
0230         geometry::detail::indexed_point_view<G1 const, Index> pt1(g1);
0231         geometry::detail::indexed_point_view<G2, Index> pt2(g2);
0232         return project_point<PointPolicy>::apply(pt1, pt2, proj);
0233     }
0234 };
0235 
0236 template <typename Geometry, typename PointPolicy>
0237 struct project_geometry<Geometry, PointPolicy, linestring_tag>
0238     : project_range<PointPolicy>
0239 {};
0240 
0241 template <typename Geometry, typename PointPolicy>
0242 struct project_geometry<Geometry, PointPolicy, multi_linestring_tag>
0243     : project_multi< project_range<PointPolicy> >
0244 {};
0245 
0246 template <typename Geometry, typename PointPolicy>
0247 struct project_geometry<Geometry, PointPolicy, ring_tag>
0248     : project_range<PointPolicy>
0249 {};
0250 
0251 template <typename Geometry, typename PointPolicy>
0252 struct project_geometry<Geometry, PointPolicy, polygon_tag>
0253 {
0254     template <typename G1, typename G2, typename Proj>
0255     static inline bool apply(G1 const& g1, G2 & g2, Proj const& proj)
0256     {
0257         bool r1 = project_range
0258                     <
0259                         PointPolicy
0260                     >::apply(geometry::exterior_ring(g1),
0261                              geometry::exterior_ring(g2),
0262                              proj);
0263         bool r2 = project_multi
0264                     <
0265                         project_range<PointPolicy>
0266                     >::apply(geometry::interior_rings(g1),
0267                              geometry::interior_rings(g2),
0268                              proj);
0269         return r1 && r2;
0270     }
0271 };
0272 
0273 template <typename MultiPolygon, typename PointPolicy>
0274 struct project_geometry<MultiPolygon, PointPolicy, multi_polygon_tag>
0275     : project_multi
0276         <
0277             project_geometry
0278             <
0279                 typename boost::range_value<MultiPolygon>::type,
0280                 PointPolicy,
0281                 polygon_tag
0282             >
0283         >
0284 {};
0285 
0286 
0287 } 
0288 #endif 
0289 
0290 
0291 template <typename Params>
0292 struct dynamic_parameters
0293 {
0294     static const bool is_specialized = false;
0295 };
0296 
0297 template <>
0298 struct dynamic_parameters<srs::proj4>
0299 {
0300     static const bool is_specialized = true;
0301     static inline srs::detail::proj4_parameters apply(srs::proj4 const& params)
0302     {
0303         return srs::detail::proj4_parameters(params.str());
0304     }
0305 };
0306 
0307 template <typename T>
0308 struct dynamic_parameters<srs::dpar::parameters<T> >
0309 {
0310     static const bool is_specialized = true;
0311     static inline srs::dpar::parameters<T> const& apply(srs::dpar::parameters<T> const& params)
0312     {
0313         return params;
0314     }
0315 };
0316 
0317 
0318 
0319 
0320 template <typename Proj, typename CT>
0321 class proj_wrapper
0322 {
0323     BOOST_GEOMETRY_STATIC_ASSERT_FALSE(
0324         "Unknown projection definition.",
0325         Proj);
0326 };
0327 
0328 template <typename CT>
0329 class proj_wrapper<srs::dynamic, CT>
0330 {
0331     
0332     
0333     typedef typename projections::detail::promote_to_double<CT>::type calc_t;
0334 
0335     typedef projections::parameters<calc_t> parameters_type;
0336     typedef projections::detail::dynamic_wrapper_b<calc_t, parameters_type> vprj_t;
0337 
0338 public:
0339     template
0340     <
0341         typename Params,
0342         std::enable_if_t
0343             <
0344                 dynamic_parameters<Params>::is_specialized,
0345                 int
0346             > = 0
0347     >
0348     proj_wrapper(Params const& params)
0349         : m_ptr(create(dynamic_parameters<Params>::apply(params)))
0350     {}
0351 
0352     vprj_t const& proj() const { return *m_ptr; }
0353     vprj_t & mutable_proj() { return *m_ptr; }
0354 
0355 private:
0356     template <typename Params>
0357     static vprj_t* create(Params const& params)
0358     {
0359         parameters_type parameters = projections::detail::pj_init<calc_t>(params);
0360 
0361         vprj_t* result = projections::detail::create_new(params, parameters);
0362 
0363         if (result == NULL)
0364         {
0365             if (parameters.id.is_unknown())
0366             {
0367                 BOOST_THROW_EXCEPTION(projection_not_named_exception());
0368             }
0369             else
0370             {
0371                 
0372                 BOOST_THROW_EXCEPTION(projection_unknown_id_exception());
0373             }
0374         }
0375 
0376         return result;
0377     }
0378 
0379     std::shared_ptr<vprj_t> m_ptr;
0380 };
0381 
0382 template <typename StaticParameters, typename CT>
0383 class static_proj_wrapper_base
0384 {
0385     typedef typename projections::detail::promote_to_double<CT>::type calc_t;
0386 
0387     typedef projections::parameters<calc_t> parameters_type;
0388 
0389     typedef typename srs::spar::detail::pick_proj_tag
0390         <
0391             StaticParameters
0392         >::type proj_tag;
0393 
0394     typedef typename projections::detail::static_projection_type
0395         <
0396             proj_tag,
0397             typename projections::detail::static_srs_tag<StaticParameters>::type,
0398             StaticParameters,
0399             calc_t,
0400             parameters_type
0401         >::type projection_type;
0402 
0403 public:
0404     projection_type const& proj() const { return m_proj; }
0405     projection_type & mutable_proj() { return m_proj; }
0406 
0407 protected:
0408     explicit static_proj_wrapper_base(StaticParameters const& s_params)
0409         : m_proj(s_params,
0410                  projections::detail::pj_init<calc_t>(s_params))
0411     {}
0412 
0413 private:
0414     projection_type m_proj;
0415 };
0416 
0417 template <typename ...Ps, typename CT>
0418 class proj_wrapper<srs::spar::parameters<Ps...>, CT>
0419     : public static_proj_wrapper_base<srs::spar::parameters<Ps...>, CT>
0420 {
0421     typedef srs::spar::parameters<Ps...>
0422         static_parameters_type;
0423     typedef static_proj_wrapper_base
0424         <
0425             static_parameters_type,
0426             CT
0427         > base_t;
0428 
0429 public:
0430     proj_wrapper()
0431         : base_t(static_parameters_type())
0432     {}
0433 
0434     proj_wrapper(static_parameters_type const& s_params)
0435         : base_t(s_params)
0436     {}
0437 };
0438 
0439 
0440 
0441 template <typename Proj, typename CT>
0442 class projection
0443     : private proj_wrapper<Proj, CT>
0444 {
0445     typedef proj_wrapper<Proj, CT> base_t;
0446 
0447 public:
0448     projection()
0449     {}
0450 
0451     template <typename Params>
0452     explicit projection(Params const& params)
0453         : base_t(params)
0454     {}
0455 
0456     
0457     template <typename LL, typename XY>
0458     inline bool forward(LL const& ll, XY& xy) const
0459     {
0460         BOOST_GEOMETRY_STATIC_ASSERT(
0461             (projections::detail::same_tags<LL, XY>::value),
0462             "Not supported combination of Geometries.",
0463             LL, XY);
0464 
0465         concepts::check_concepts_and_equal_dimensions<LL const, XY>();
0466 
0467         return projections::detail::project_geometry
0468                 <
0469                     LL,
0470                     projections::detail::forward_point_projection_policy
0471                 >::apply(ll, xy, base_t::proj());
0472     }
0473 
0474     
0475     template <typename XY, typename LL>
0476     inline bool inverse(XY const& xy, LL& ll) const
0477     {
0478         BOOST_GEOMETRY_STATIC_ASSERT(
0479             (projections::detail::same_tags<XY, LL>::value),
0480             "Not supported combination of Geometries.",
0481             XY, LL);
0482 
0483         concepts::check_concepts_and_equal_dimensions<XY const, LL>();
0484 
0485         return projections::detail::project_geometry
0486                 <
0487                     XY,
0488                     projections::detail::inverse_point_projection_policy
0489                 >::apply(xy, ll, base_t::proj());
0490     }
0491 };
0492 
0493 } 
0494 
0495 
0496 namespace srs
0497 {
0498 
0499 
0500 
0501 
0502 
0503 
0504 
0505 
0506 
0507 template
0508 <
0509     typename Parameters = srs::dynamic,
0510     typename CT = double
0511 >
0512 class projection
0513     : public projections::projection<Parameters, CT>
0514 {
0515     typedef projections::projection<Parameters, CT> base_t;
0516 
0517 public:
0518     projection()
0519     {}
0520 
0521     projection(Parameters const& parameters)
0522         : base_t(parameters)
0523     {}
0524 
0525     
0526 
0527 
0528 
0529 
0530 
0531 
0532 
0533 
0534     template
0535     <
0536         typename DynamicParameters,
0537         std::enable_if_t
0538             <
0539                 projections::dynamic_parameters<DynamicParameters>::is_specialized,
0540                 int
0541             > = 0
0542     >
0543     projection(DynamicParameters const& dynamic_parameters)
0544         : base_t(dynamic_parameters)
0545     {}
0546 };
0547 
0548 
0549 } 
0550 
0551 
0552 }} 
0553 
0554 
0555 #endif