]> git.proxmox.com Git - ceph.git/blob - ceph/src/boost/boost/geometry/srs/projection.hpp
import new upstream nautilus stable release 14.2.8
[ceph.git] / ceph / src / boost / boost / geometry / srs / projection.hpp
1 // Boost.Geometry (aka GGL, Generic Geometry Library)
2
3 // Copyright (c) 2008-2012 Barend Gehrels, Amsterdam, the Netherlands.
4
5 // This file was modified by Oracle on 2017, 2018.
6 // Modifications copyright (c) 2017-2018, Oracle and/or its affiliates.
7 // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
8
9 // Use, modification and distribution is subject to the Boost Software License,
10 // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
11 // http://www.boost.org/LICENSE_1_0.txt)
12
13 #ifndef BOOST_GEOMETRY_SRS_PROJECTION_HPP
14 #define BOOST_GEOMETRY_SRS_PROJECTION_HPP
15
16
17 #include <string>
18
19 #include <boost/geometry/algorithms/convert.hpp>
20 #include <boost/geometry/algorithms/detail/convert_point_to_point.hpp>
21
22 #include <boost/geometry/core/coordinate_dimension.hpp>
23
24 #include <boost/geometry/srs/projections/dpar.hpp>
25 #include <boost/geometry/srs/projections/exception.hpp>
26 #include <boost/geometry/srs/projections/factory.hpp>
27 #include <boost/geometry/srs/projections/impl/base_dynamic.hpp>
28 #include <boost/geometry/srs/projections/impl/base_static.hpp>
29 #include <boost/geometry/srs/projections/impl/pj_init.hpp>
30 #include <boost/geometry/srs/projections/invalid_point.hpp>
31 #include <boost/geometry/srs/projections/proj4.hpp>
32 #include <boost/geometry/srs/projections/spar.hpp>
33
34 #include <boost/geometry/views/detail/indexed_point_view.hpp>
35
36 #include <boost/mpl/assert.hpp>
37 #include <boost/mpl/if.hpp>
38 #include <boost/smart_ptr/shared_ptr.hpp>
39 #include <boost/throw_exception.hpp>
40 #include <boost/type_traits/is_integral.hpp>
41 #include <boost/type_traits/is_same.hpp>
42
43
44 namespace boost { namespace geometry
45 {
46
47 namespace projections
48 {
49
50 #ifndef DOXYGEN_NO_DETAIL
51 namespace detail
52 {
53
54 template <typename G1, typename G2>
55 struct same_tags
56 {
57 static const bool value = boost::is_same
58 <
59 typename geometry::tag<G1>::type,
60 typename geometry::tag<G2>::type
61 >::value;
62 };
63
64 template <typename CT>
65 struct promote_to_double
66 {
67 typedef typename boost::mpl::if_c
68 <
69 boost::is_integral<CT>::value || boost::is_same<CT, float>::value,
70 double, CT
71 >::type type;
72 };
73
74 // Copy coordinates of dimensions >= MinDim
75 template <std::size_t MinDim, typename Point1, typename Point2>
76 inline void copy_higher_dimensions(Point1 const& point1, Point2 & point2)
77 {
78 static const std::size_t dim1 = geometry::dimension<Point1>::value;
79 static const std::size_t dim2 = geometry::dimension<Point2>::value;
80 static const std::size_t lesser_dim = dim1 < dim2 ? dim1 : dim2;
81 BOOST_MPL_ASSERT_MSG((lesser_dim >= MinDim),
82 THE_DIMENSION_OF_POINTS_IS_TOO_SMALL,
83 (Point1, Point2));
84
85 geometry::detail::conversion::point_to_point
86 <
87 Point1, Point2, MinDim, lesser_dim
88 > ::apply(point1, point2);
89
90 // TODO: fill point2 with zeros if dim1 < dim2 ?
91 // currently no need because equal dimensions are checked
92 }
93
94
95 struct forward_point_projection_policy
96 {
97 template <typename LL, typename XY, typename Proj>
98 static inline bool apply(LL const& ll, XY & xy, Proj const& proj)
99 {
100 return proj.forward(ll, xy);
101 }
102 };
103
104 struct inverse_point_projection_policy
105 {
106 template <typename XY, typename LL, typename Proj>
107 static inline bool apply(XY const& xy, LL & ll, Proj const& proj)
108 {
109 return proj.inverse(xy, ll);
110 }
111 };
112
113 template <typename PointPolicy>
114 struct project_point
115 {
116 template <typename P1, typename P2, typename Proj>
117 static inline bool apply(P1 const& p1, P2 & p2, Proj const& proj)
118 {
119 // (Geographic -> Cartesian) will be projected, rest will be copied.
120 // So first copy third or higher dimensions
121 projections::detail::copy_higher_dimensions<2>(p1, p2);
122
123 if (! PointPolicy::apply(p1, p2, proj))
124 {
125 // For consistency with transformation
126 set_invalid_point(p2);
127 return false;
128 }
129
130 return true;
131 }
132 };
133
134 template <typename PointPolicy>
135 struct project_range
136 {
137 template <typename Proj>
138 struct convert_policy
139 {
140 explicit convert_policy(Proj const& proj)
141 : m_proj(proj)
142 , m_result(true)
143 {}
144
145 template <typename Point1, typename Point2>
146 inline void apply(Point1 const& point1, Point2 & point2)
147 {
148 if (! project_point<PointPolicy>::apply(point1, point2, m_proj) )
149 m_result = false;
150 }
151
152 bool result() const
153 {
154 return m_result;
155 }
156
157 private:
158 Proj const& m_proj;
159 bool m_result;
160 };
161
162 template <typename R1, typename R2, typename Proj>
163 static inline bool apply(R1 const& r1, R2 & r2, Proj const& proj)
164 {
165 return geometry::detail::conversion::range_to_range
166 <
167 R1, R2,
168 geometry::point_order<R1>::value != geometry::point_order<R2>::value
169 >::apply(r1, r2, convert_policy<Proj>(proj)).result();
170 }
171 };
172
173 template <typename Policy>
174 struct project_multi
175 {
176 template <typename G1, typename G2, typename Proj>
177 static inline bool apply(G1 const& g1, G2 & g2, Proj const& proj)
178 {
179 range::resize(g2, boost::size(g1));
180 return apply(boost::begin(g1), boost::end(g1),
181 boost::begin(g2),
182 proj);
183 }
184
185 private:
186 template <typename It1, typename It2, typename Proj>
187 static inline bool apply(It1 g1_first, It1 g1_last, It2 g2_first, Proj const& proj)
188 {
189 bool result = true;
190 for ( ; g1_first != g1_last ; ++g1_first, ++g2_first )
191 {
192 if (! Policy::apply(*g1_first, *g2_first, proj))
193 {
194 result = false;
195 }
196 }
197 return result;
198 }
199 };
200
201 template
202 <
203 typename Geometry,
204 typename PointPolicy,
205 typename Tag = typename geometry::tag<Geometry>::type
206 >
207 struct project_geometry
208 {};
209
210 template <typename Geometry, typename PointPolicy>
211 struct project_geometry<Geometry, PointPolicy, point_tag>
212 : project_point<PointPolicy>
213 {};
214
215 template <typename Geometry, typename PointPolicy>
216 struct project_geometry<Geometry, PointPolicy, multi_point_tag>
217 : project_range<PointPolicy>
218 {};
219
220 template <typename Geometry, typename PointPolicy>
221 struct project_geometry<Geometry, PointPolicy, segment_tag>
222 {
223 template <typename G1, typename G2, typename Proj>
224 static inline bool apply(G1 const& g1, G2 & g2, Proj const& proj)
225 {
226 bool r1 = apply<0>(g1, g2, proj);
227 bool r2 = apply<1>(g1, g2, proj);
228 return r1 && r2;
229 }
230
231 private:
232 template <std::size_t Index, typename G1, typename G2, typename Proj>
233 static inline bool apply(G1 const& g1, G2 & g2, Proj const& proj)
234 {
235 geometry::detail::indexed_point_view<G1 const, Index> pt1(g1);
236 geometry::detail::indexed_point_view<G2, Index> pt2(g2);
237 return project_point<PointPolicy>::apply(pt1, pt2, proj);
238 }
239 };
240
241 template <typename Geometry, typename PointPolicy>
242 struct project_geometry<Geometry, PointPolicy, linestring_tag>
243 : project_range<PointPolicy>
244 {};
245
246 template <typename Geometry, typename PointPolicy>
247 struct project_geometry<Geometry, PointPolicy, multi_linestring_tag>
248 : project_multi< project_range<PointPolicy> >
249 {};
250
251 template <typename Geometry, typename PointPolicy>
252 struct project_geometry<Geometry, PointPolicy, ring_tag>
253 : project_range<PointPolicy>
254 {};
255
256 template <typename Geometry, typename PointPolicy>
257 struct project_geometry<Geometry, PointPolicy, polygon_tag>
258 {
259 template <typename G1, typename G2, typename Proj>
260 static inline bool apply(G1 const& g1, G2 & g2, Proj const& proj)
261 {
262 bool r1 = project_range
263 <
264 PointPolicy
265 >::apply(geometry::exterior_ring(g1),
266 geometry::exterior_ring(g2),
267 proj);
268 bool r2 = project_multi
269 <
270 project_range<PointPolicy>
271 >::apply(geometry::interior_rings(g1),
272 geometry::interior_rings(g2),
273 proj);
274 return r1 && r2;
275 }
276 };
277
278 template <typename MultiPolygon, typename PointPolicy>
279 struct project_geometry<MultiPolygon, PointPolicy, multi_polygon_tag>
280 : project_multi
281 <
282 project_geometry
283 <
284 typename boost::range_value<MultiPolygon>::type,
285 PointPolicy,
286 polygon_tag
287 >
288 >
289 {};
290
291
292 } // namespace detail
293 #endif // DOXYGEN_NO_DETAIL
294
295
296 template <typename Params>
297 struct dynamic_parameters
298 {
299 static const bool is_specialized = false;
300 };
301
302 template <>
303 struct dynamic_parameters<srs::proj4>
304 {
305 static const bool is_specialized = true;
306 static inline srs::detail::proj4_parameters apply(srs::proj4 const& params)
307 {
308 return srs::detail::proj4_parameters(params.str());
309 }
310 };
311
312 template <typename T>
313 struct dynamic_parameters<srs::dpar::parameters<T> >
314 {
315 static const bool is_specialized = true;
316 static inline srs::dpar::parameters<T> const& apply(srs::dpar::parameters<T> const& params)
317 {
318 return params;
319 }
320 };
321
322
323 // proj_wrapper class and its specializations wrapps the internal projection
324 // representation and implements transparent creation of projection object
325 template <typename Proj, typename CT>
326 class proj_wrapper
327 {
328 BOOST_MPL_ASSERT_MSG((false),
329 UNKNOWN_PROJECTION_DEFINITION,
330 (Proj));
331 };
332
333 template <typename CT>
334 class proj_wrapper<srs::dynamic, CT>
335 {
336 // Some projections do not work with float -> wrong results
337 // select <double> from int/float/double and else selects T
338 typedef typename projections::detail::promote_to_double<CT>::type calc_t;
339
340 typedef projections::parameters<calc_t> parameters_type;
341 typedef projections::detail::dynamic_wrapper_b<calc_t, parameters_type> vprj_t;
342
343 public:
344 template <typename Params>
345 proj_wrapper(Params const& params,
346 typename boost::enable_if_c
347 <
348 dynamic_parameters<Params>::is_specialized
349 >::type * = 0)
350 : m_ptr(create(dynamic_parameters<Params>::apply(params)))
351 {}
352
353 vprj_t const& proj() const { return *m_ptr; }
354 vprj_t & mutable_proj() { return *m_ptr; }
355
356 private:
357 template <typename Params>
358 static vprj_t* create(Params const& params)
359 {
360 parameters_type parameters = projections::detail::pj_init<calc_t>(params);
361
362 vprj_t* result = projections::detail::create_new(params, parameters);
363
364 if (result == NULL)
365 {
366 if (parameters.id.is_unknown())
367 {
368 BOOST_THROW_EXCEPTION(projection_not_named_exception());
369 }
370 else
371 {
372 // TODO: handle non-string projection id
373 BOOST_THROW_EXCEPTION(projection_unknown_id_exception());
374 }
375 }
376
377 return result;
378 }
379
380 boost::shared_ptr<vprj_t> m_ptr;
381 };
382
383 template <typename StaticParameters, typename CT>
384 class static_proj_wrapper_base
385 {
386 typedef typename projections::detail::promote_to_double<CT>::type calc_t;
387
388 typedef projections::parameters<calc_t> parameters_type;
389
390 typedef typename srs::spar::detail::pick_proj_tag
391 <
392 StaticParameters
393 >::type proj_tag;
394
395 typedef typename projections::detail::static_projection_type
396 <
397 proj_tag,
398 typename projections::detail::static_srs_tag<StaticParameters>::type,
399 StaticParameters,
400 calc_t,
401 parameters_type
402 >::type projection_type;
403
404 public:
405 projection_type const& proj() const { return m_proj; }
406 projection_type & mutable_proj() { return m_proj; }
407
408 protected:
409 explicit static_proj_wrapper_base(StaticParameters const& s_params)
410 : m_proj(s_params,
411 projections::detail::pj_init<calc_t>(s_params))
412 {}
413
414 private:
415 projection_type m_proj;
416 };
417
418 template <BOOST_GEOMETRY_PROJECTIONS_DETAIL_TYPENAME_PX, typename CT>
419 class proj_wrapper<srs::spar::parameters<BOOST_GEOMETRY_PROJECTIONS_DETAIL_PX>, CT>
420 : public static_proj_wrapper_base<srs::spar::parameters<BOOST_GEOMETRY_PROJECTIONS_DETAIL_PX>, CT>
421 {
422 typedef srs::spar::parameters<BOOST_GEOMETRY_PROJECTIONS_DETAIL_PX>
423 static_parameters_type;
424 typedef static_proj_wrapper_base
425 <
426 static_parameters_type,
427 CT
428 > base_t;
429
430 public:
431 proj_wrapper()
432 : base_t(static_parameters_type())
433 {}
434
435 proj_wrapper(static_parameters_type const& s_params)
436 : base_t(s_params)
437 {}
438 };
439
440
441 // projection class implements transparent forward/inverse projection interface
442 template <typename Proj, typename CT>
443 class projection
444 : private proj_wrapper<Proj, CT>
445 {
446 typedef proj_wrapper<Proj, CT> base_t;
447
448 public:
449 projection()
450 {}
451
452 template <typename Params>
453 explicit projection(Params const& params)
454 : base_t(params)
455 {}
456
457 /// Forward projection, from Latitude-Longitude to Cartesian
458 template <typename LL, typename XY>
459 inline bool forward(LL const& ll, XY& xy) const
460 {
461 BOOST_MPL_ASSERT_MSG((projections::detail::same_tags<LL, XY>::value),
462 NOT_SUPPORTED_COMBINATION_OF_GEOMETRIES,
463 (LL, XY));
464
465 concepts::check_concepts_and_equal_dimensions<LL const, XY>();
466
467 return projections::detail::project_geometry
468 <
469 LL,
470 projections::detail::forward_point_projection_policy
471 >::apply(ll, xy, base_t::proj());
472 }
473
474 /// Inverse projection, from Cartesian to Latitude-Longitude
475 template <typename XY, typename LL>
476 inline bool inverse(XY const& xy, LL& ll) const
477 {
478 BOOST_MPL_ASSERT_MSG((projections::detail::same_tags<XY, LL>::value),
479 NOT_SUPPORTED_COMBINATION_OF_GEOMETRIES,
480 (XY, LL));
481
482 concepts::check_concepts_and_equal_dimensions<XY const, LL>();
483
484 return projections::detail::project_geometry
485 <
486 XY,
487 projections::detail::inverse_point_projection_policy
488 >::apply(xy, ll, base_t::proj());
489 }
490 };
491
492 } // namespace projections
493
494
495 namespace srs
496 {
497
498
499 /*!
500 \brief Representation of projection
501 \details Either dynamic or static projection representation
502 \ingroup projection
503 \tparam Parameters default dynamic tag or static projection parameters
504 \tparam CT calculation type used internally
505 */
506 template
507 <
508 typename Parameters = srs::dynamic,
509 typename CT = double
510 >
511 class projection
512 : public projections::projection<Parameters, CT>
513 {
514 typedef projections::projection<Parameters, CT> base_t;
515
516 public:
517 projection()
518 {}
519
520 projection(Parameters const& parameters)
521 : base_t(parameters)
522 {}
523
524 /*!
525 \ingroup projection
526 \brief Initializes a projection as a string, using the format with + and =
527 \details The projection can be initialized with a string (with the same format as the PROJ4 package) for
528 convenient initialization from, for example, the command line
529 \par Example
530 <tt>srs::proj4("+proj=labrd +ellps=intl +lon_0=46d26'13.95E +lat_0=18d54S +azi=18d54 +k_0=.9995 +x_0=400000 +y_0=800000")</tt>
531 for the Madagascar projection.
532 */
533 template <typename DynamicParameters>
534 projection(DynamicParameters const& dynamic_parameters,
535 typename boost::enable_if_c
536 <
537 projections::dynamic_parameters<DynamicParameters>::is_specialized
538 >::type * = 0)
539 : base_t(dynamic_parameters)
540 {}
541 };
542
543
544 } // namespace srs
545
546
547 }} // namespace boost::geometry
548
549
550 #endif // BOOST_GEOMETRY_SRS_PROJECTION_HPP