]> git.proxmox.com Git - ceph.git/blame - ceph/src/boost/boost/geometry/srs/transformation.hpp
import new upstream nautilus stable release 14.2.8
[ceph.git] / ceph / src / boost / boost / geometry / srs / transformation.hpp
CommitLineData
11fdf7f2
TL
1// Boost.Geometry (aka GGL, Generic Geometry Library)
2
92f5a8d4 3// Copyright (c) 2017-2018, Oracle and/or its affiliates.
11fdf7f2
TL
4// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
5
6// Use, modification and distribution is subject to the Boost Software License,
7// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
8// http://www.boost.org/LICENSE_1_0.txt)
9
10#ifndef BOOST_GEOMETRY_SRS_TRANSFORMATION_HPP
11#define BOOST_GEOMETRY_SRS_TRANSFORMATION_HPP
12
13
14#include <string>
15
16#include <boost/geometry/algorithms/convert.hpp>
17
18#include <boost/geometry/core/coordinate_dimension.hpp>
19
20#include <boost/geometry/geometries/point.hpp>
21#include <boost/geometry/geometries/multi_point.hpp>
22#include <boost/geometry/geometries/linestring.hpp>
23#include <boost/geometry/geometries/ring.hpp>
24#include <boost/geometry/geometries/segment.hpp>
25
26#include <boost/geometry/srs/projection.hpp>
92f5a8d4 27#include <boost/geometry/srs/projections/grids.hpp>
11fdf7f2
TL
28#include <boost/geometry/srs/projections/impl/pj_transform.hpp>
29
30#include <boost/geometry/views/detail/indexed_point_view.hpp>
31
32#include <boost/mpl/assert.hpp>
33#include <boost/mpl/if.hpp>
34#include <boost/smart_ptr/shared_ptr.hpp>
35#include <boost/throw_exception.hpp>
36#include <boost/type_traits/is_integral.hpp>
37#include <boost/type_traits/is_same.hpp>
38
39
40namespace boost { namespace geometry
41{
42
43namespace projections { namespace detail
44{
45
46template <typename T1, typename T2>
47inline bool same_object(T1 const& , T2 const& )
48{
49 return false;
50}
51
52template <typename T>
53inline bool same_object(T const& o1, T const& o2)
54{
55 return boost::addressof(o1) == boost::addressof(o2);
56}
57
58template
59<
60 typename PtIn,
61 typename PtOut,
92f5a8d4 62 bool SameUnits = boost::is_same
11fdf7f2 63 <
92f5a8d4
TL
64 typename geometry::detail::cs_angular_units<PtIn>::type,
65 typename geometry::detail::cs_angular_units<PtOut>::type
66 >::value
11fdf7f2
TL
67>
68struct transform_geometry_point_coordinates
69{
70 static inline void apply(PtIn const& in, PtOut & out, bool /*enable_angles*/)
71 {
72 geometry::set<0>(out, geometry::get<0>(in));
73 geometry::set<1>(out, geometry::get<1>(in));
74 }
75};
76
77template <typename PtIn, typename PtOut>
78struct transform_geometry_point_coordinates<PtIn, PtOut, false>
79{
80 static inline void apply(PtIn const& in, PtOut & out, bool enable_angles)
81 {
82 if (enable_angles)
83 {
84 geometry::set_from_radian<0>(out, geometry::get_as_radian<0>(in));
85 geometry::set_from_radian<1>(out, geometry::get_as_radian<1>(in));
86 }
87 else
88 {
89 geometry::set<0>(out, geometry::get<0>(in));
90 geometry::set<1>(out, geometry::get<1>(in));
91 }
92 }
93};
94
95template <typename Geometry, typename CT>
96struct transform_geometry_point
97{
98 typedef typename geometry::point_type<Geometry>::type point_type;
99
100 typedef geometry::model::point
101 <
102 typename select_most_precise
103 <
104 typename geometry::coordinate_type<point_type>::type,
105 CT
106 >::type,
107 geometry::dimension<point_type>::type::value,
108 typename geometry::coordinate_system<point_type>::type
109 > type;
110
111 template <typename PtIn, typename PtOut>
112 static inline void apply(PtIn const& in, PtOut & out, bool enable_angles)
113 {
114 transform_geometry_point_coordinates<PtIn, PtOut>::apply(in, out, enable_angles);
115 projections::detail::copy_higher_dimensions<2>(in, out);
116 }
117};
118
119template <typename Geometry, typename CT>
120struct transform_geometry_range_base
121{
122 struct convert_strategy
123 {
124 convert_strategy(bool enable_angles)
125 : m_enable_angles(enable_angles)
126 {}
127
128 template <typename PtIn, typename PtOut>
129 void apply(PtIn const& in, PtOut & out)
130 {
131 transform_geometry_point<Geometry, CT>::apply(in, out, m_enable_angles);
132 }
133
134 bool m_enable_angles;
135 };
136
137 template <typename In, typename Out>
138 static inline void apply(In const& in, Out & out, bool enable_angles)
139 {
140 // Change the order and/or closure if needed
141 // In - arbitrary geometry
142 // Out - either Geometry or std::vector
143 // So the order and closure of In and Geometry shoudl be compared
144 // std::vector's order is assumed to be the same as of Geometry
145 geometry::detail::conversion::range_to_range
146 <
147 In,
148 Out,
149 geometry::point_order<In>::value != geometry::point_order<Out>::value
150 >::apply(in, out, convert_strategy(enable_angles));
151 }
152};
153
154template
155<
156 typename Geometry,
157 typename CT,
158 typename Tag = typename geometry::tag<Geometry>::type
159>
160struct transform_geometry
161{};
162
163template <typename Point, typename CT>
164struct transform_geometry<Point, CT, point_tag>
165 : transform_geometry_point<Point, CT>
166{};
167
168template <typename Segment, typename CT>
169struct transform_geometry<Segment, CT, segment_tag>
170{
171 typedef geometry::model::segment
172 <
173 typename transform_geometry_point<Segment, CT>::type
174 > type;
175
176 template <typename In, typename Out>
177 static inline void apply(In const& in, Out & out, bool enable_angles)
178 {
179 apply<0>(in, out, enable_angles);
180 apply<1>(in, out, enable_angles);
181 }
182
183private:
184 template <std::size_t Index, typename In, typename Out>
185 static inline void apply(In const& in, Out & out, bool enable_angles)
186 {
187 geometry::detail::indexed_point_view<In const, Index> in_pt(in);
188 geometry::detail::indexed_point_view<Out, Index> out_pt(out);
189 transform_geometry_point<Segment, CT>::apply(in_pt, out_pt, enable_angles);
190 }
191};
192
193template <typename MultiPoint, typename CT>
194struct transform_geometry<MultiPoint, CT, multi_point_tag>
195 : transform_geometry_range_base<MultiPoint, CT>
196{
197 typedef model::multi_point
198 <
199 typename transform_geometry_point<MultiPoint, CT>::type
200 > type;
201};
202
203template <typename LineString, typename CT>
204struct transform_geometry<LineString, CT, linestring_tag>
205 : transform_geometry_range_base<LineString, CT>
206{
207 typedef model::linestring
208 <
209 typename transform_geometry_point<LineString, CT>::type
210 > type;
211};
212
213template <typename Ring, typename CT>
214struct transform_geometry<Ring, CT, ring_tag>
215 : transform_geometry_range_base<Ring, CT>
216{
217 typedef model::ring
218 <
219 typename transform_geometry_point<Ring, CT>::type,
220 geometry::point_order<Ring>::value == clockwise,
221 geometry::closure<Ring>::value == closed
222 > type;
223};
224
225
226template
227<
228 typename OutGeometry,
229 typename CT,
230 bool EnableTemporary = ! boost::is_same
231 <
232 typename select_most_precise
233 <
234 typename geometry::coordinate_type<OutGeometry>::type,
235 CT
236 >::type,
237 typename geometry::coordinate_type<OutGeometry>::type
238 >::type::value
239>
240struct transform_geometry_wrapper
241{
242 typedef transform_geometry<OutGeometry, CT> transform;
243 typedef typename transform::type type;
244
245 template <typename InGeometry>
246 transform_geometry_wrapper(InGeometry const& in, OutGeometry & out, bool input_angles)
247 : m_out(out)
248 {
249 transform::apply(in, m_temp, input_angles);
250 }
251
252 type & get() { return m_temp; }
253 void finish() { geometry::convert(m_temp, m_out); } // this is always copy 1:1 without changing the order or closure
254
255private:
256 type m_temp;
257 OutGeometry & m_out;
258};
259
260template
261<
262 typename OutGeometry,
263 typename CT
264>
265struct transform_geometry_wrapper<OutGeometry, CT, false>
266{
267 typedef transform_geometry<OutGeometry, CT> transform;
268 typedef OutGeometry type;
269
270 transform_geometry_wrapper(OutGeometry const& in, OutGeometry & out, bool input_angles)
271 : m_out(out)
272 {
273 if (! same_object(in, out))
274 transform::apply(in, out, input_angles);
275 }
276
277 template <typename InGeometry>
278 transform_geometry_wrapper(InGeometry const& in, OutGeometry & out, bool input_angles)
279 : m_out(out)
280 {
281 transform::apply(in, out, input_angles);
282 }
283
284 OutGeometry & get() { return m_out; }
285 void finish() {}
286
287private:
288 OutGeometry & m_out;
289};
290
291template <typename CT>
292struct transform_range
293{
294 template
295 <
296 typename Proj1, typename Par1,
297 typename Proj2, typename Par2,
92f5a8d4
TL
298 typename RangeIn, typename RangeOut,
299 typename Grids
11fdf7f2
TL
300 >
301 static inline bool apply(Proj1 const& proj1, Par1 const& par1,
302 Proj2 const& proj2, Par2 const& par2,
92f5a8d4
TL
303 RangeIn const& in, RangeOut & out,
304 Grids const& grids1, Grids const& grids2)
11fdf7f2
TL
305 {
306 // NOTE: this has to be consistent with pj_transform()
307 bool const input_angles = !par1.is_geocent && par1.is_latlong;
308
309 transform_geometry_wrapper<RangeOut, CT> wrapper(in, out, input_angles);
310
311 bool res = true;
312 try
313 {
92f5a8d4 314 res = pj_transform(proj1, par1, proj2, par2, wrapper.get(), grids1, grids2);
11fdf7f2 315 }
92f5a8d4 316 catch (projection_exception const&)
11fdf7f2
TL
317 {
318 res = false;
319 }
320 catch(...)
321 {
322 BOOST_RETHROW
323 }
324
325 wrapper.finish();
326
327 return res;
328 }
329};
330
331template <typename Policy>
332struct transform_multi
333{
334 template
335 <
336 typename Proj1, typename Par1,
337 typename Proj2, typename Par2,
92f5a8d4
TL
338 typename MultiIn, typename MultiOut,
339 typename Grids
11fdf7f2
TL
340 >
341 static inline bool apply(Proj1 const& proj1, Par1 const& par1,
342 Proj2 const& proj2, Par2 const& par2,
92f5a8d4
TL
343 MultiIn const& in, MultiOut & out,
344 Grids const& grids1, Grids const& grids2)
11fdf7f2
TL
345 {
346 if (! same_object(in, out))
347 range::resize(out, boost::size(in));
348
349 return apply(proj1, par1, proj2, par2,
350 boost::begin(in), boost::end(in),
92f5a8d4
TL
351 boost::begin(out),
352 grids1, grids2);
11fdf7f2
TL
353 }
354
355private:
356 template
357 <
358 typename Proj1, typename Par1,
359 typename Proj2, typename Par2,
92f5a8d4
TL
360 typename InIt, typename OutIt,
361 typename Grids
11fdf7f2
TL
362 >
363 static inline bool apply(Proj1 const& proj1, Par1 const& par1,
364 Proj2 const& proj2, Par2 const& par2,
92f5a8d4
TL
365 InIt in_first, InIt in_last, OutIt out_first,
366 Grids const& grids1, Grids const& grids2)
11fdf7f2
TL
367 {
368 bool res = true;
369 for ( ; in_first != in_last ; ++in_first, ++out_first )
370 {
92f5a8d4 371 if ( ! Policy::apply(proj1, par1, proj2, par2, *in_first, *out_first, grids1, grids2) )
11fdf7f2
TL
372 {
373 res = false;
374 }
375 }
376 return res;
377 }
378};
379
380template
381<
382 typename Geometry,
383 typename CT,
384 typename Tag = typename geometry::tag<Geometry>::type
385>
386struct transform
387 : not_implemented<Tag>
388{};
389
390template <typename Point, typename CT>
391struct transform<Point, CT, point_tag>
392{
393 template
394 <
395 typename Proj1, typename Par1,
396 typename Proj2, typename Par2,
92f5a8d4
TL
397 typename PointIn, typename PointOut,
398 typename Grids
11fdf7f2
TL
399 >
400 static inline bool apply(Proj1 const& proj1, Par1 const& par1,
401 Proj2 const& proj2, Par2 const& par2,
92f5a8d4
TL
402 PointIn const& in, PointOut & out,
403 Grids const& grids1, Grids const& grids2)
11fdf7f2
TL
404 {
405 // NOTE: this has to be consistent with pj_transform()
406 bool const input_angles = !par1.is_geocent && par1.is_latlong;
407
408 transform_geometry_wrapper<PointOut, CT> wrapper(in, out, input_angles);
409
410 typedef typename transform_geometry_wrapper<PointOut, CT>::type point_type;
411 point_type * ptr = boost::addressof(wrapper.get());
412
413 std::pair<point_type *, point_type *> range = std::make_pair(ptr, ptr + 1);
414
415 bool res = true;
416 try
417 {
92f5a8d4 418 res = pj_transform(proj1, par1, proj2, par2, range, grids1, grids2);
11fdf7f2 419 }
92f5a8d4 420 catch (projection_exception const&)
11fdf7f2
TL
421 {
422 res = false;
423 }
424 catch(...)
425 {
426 BOOST_RETHROW
427 }
428
429 wrapper.finish();
430
431 return res;
432 }
433};
434
435template <typename MultiPoint, typename CT>
436struct transform<MultiPoint, CT, multi_point_tag>
437 : transform_range<CT>
438{};
439
440template <typename Segment, typename CT>
441struct transform<Segment, CT, segment_tag>
442{
443 template
444 <
445 typename Proj1, typename Par1,
446 typename Proj2, typename Par2,
92f5a8d4
TL
447 typename SegmentIn, typename SegmentOut,
448 typename Grids
11fdf7f2
TL
449 >
450 static inline bool apply(Proj1 const& proj1, Par1 const& par1,
451 Proj2 const& proj2, Par2 const& par2,
92f5a8d4
TL
452 SegmentIn const& in, SegmentOut & out,
453 Grids const& grids1, Grids const& grids2)
11fdf7f2
TL
454 {
455 // NOTE: this has to be consistent with pj_transform()
456 bool const input_angles = !par1.is_geocent && par1.is_latlong;
457
458 transform_geometry_wrapper<SegmentOut, CT> wrapper(in, out, input_angles);
459
460 typedef typename geometry::point_type
461 <
462 typename transform_geometry_wrapper<SegmentOut, CT>::type
463 >::type point_type;
464
465 point_type points[2];
466
467 geometry::detail::assign_point_from_index<0>(wrapper.get(), points[0]);
468 geometry::detail::assign_point_from_index<1>(wrapper.get(), points[1]);
469
470 std::pair<point_type*, point_type*> range = std::make_pair(points, points + 2);
471
472 bool res = true;
473 try
474 {
92f5a8d4 475 res = pj_transform(proj1, par1, proj2, par2, range, grids1, grids2);
11fdf7f2 476 }
92f5a8d4 477 catch (projection_exception const&)
11fdf7f2
TL
478 {
479 res = false;
480 }
481 catch(...)
482 {
483 BOOST_RETHROW
484 }
485
486 geometry::detail::assign_point_to_index<0>(points[0], wrapper.get());
487 geometry::detail::assign_point_to_index<1>(points[1], wrapper.get());
488
489 wrapper.finish();
490
491 return res;
492 }
493};
494
495template <typename Linestring, typename CT>
496struct transform<Linestring, CT, linestring_tag>
497 : transform_range<CT>
498{};
499
500template <typename MultiLinestring, typename CT>
501struct transform<MultiLinestring, CT, multi_linestring_tag>
502 : transform_multi<transform_range<CT> >
503{};
504
505template <typename Ring, typename CT>
506struct transform<Ring, CT, ring_tag>
507 : transform_range<CT>
508{};
509
510template <typename Polygon, typename CT>
511struct transform<Polygon, CT, polygon_tag>
512{
513 template
514 <
515 typename Proj1, typename Par1,
516 typename Proj2, typename Par2,
92f5a8d4
TL
517 typename PolygonIn, typename PolygonOut,
518 typename Grids
11fdf7f2
TL
519 >
520 static inline bool apply(Proj1 const& proj1, Par1 const& par1,
521 Proj2 const& proj2, Par2 const& par2,
92f5a8d4
TL
522 PolygonIn const& in, PolygonOut & out,
523 Grids const& grids1, Grids const& grids2)
11fdf7f2
TL
524 {
525 bool r1 = transform_range
526 <
527 CT
528 >::apply(proj1, par1, proj2, par2,
529 geometry::exterior_ring(in),
92f5a8d4
TL
530 geometry::exterior_ring(out),
531 grids1, grids2);
11fdf7f2
TL
532 bool r2 = transform_multi
533 <
534 transform_range<CT>
535 >::apply(proj1, par1, proj2, par2,
536 geometry::interior_rings(in),
92f5a8d4
TL
537 geometry::interior_rings(out),
538 grids1, grids2);
11fdf7f2
TL
539 return r1 && r2;
540 }
541};
542
543template <typename MultiPolygon, typename CT>
544struct transform<MultiPolygon, CT, multi_polygon_tag>
545 : transform_multi
546 <
547 transform
548 <
549 typename boost::range_value<MultiPolygon>::type,
550 CT,
551 polygon_tag
552 >
553 >
554{};
555
556
557}} // namespace projections::detail
558
559namespace srs
560{
561
562
563/*!
564 \brief Representation of projection
565 \details Either dynamic or static projection representation
566 \ingroup projection
567 \tparam Proj1 default_dynamic or static projection parameters
568 \tparam Proj2 default_dynamic or static projection parameters
569 \tparam CT calculation type used internally
570*/
571template
572<
573 typename Proj1 = srs::dynamic,
574 typename Proj2 = srs::dynamic,
575 typename CT = double
576>
577class transformation
578{
579 typedef typename projections::detail::promote_to_double<CT>::type calc_t;
580
581public:
92f5a8d4 582 // Both static and default constructed
11fdf7f2
TL
583 transformation()
584 {}
585
92f5a8d4 586 // First dynamic, second static and default constructed
11fdf7f2 587 template <typename Parameters1>
92f5a8d4
TL
588 explicit transformation(Parameters1 const& parameters1,
589 typename boost::enable_if_c
590 <
591 boost::is_same<Proj1, srs::dynamic>::value
592 && projections::dynamic_parameters<Parameters1>::is_specialized
593 >::type * = 0)
594 : m_proj1(parameters1)
595 {}
596
597 // First static, second static and default constructed
598 explicit transformation(Proj1 const& parameters1)
11fdf7f2
TL
599 : m_proj1(parameters1)
600 {}
601
92f5a8d4 602 // Both dynamic
11fdf7f2 603 template <typename Parameters1, typename Parameters2>
92f5a8d4
TL
604 transformation(Parameters1 const& parameters1,
605 Parameters2 const& parameters2,
606 typename boost::enable_if_c
607 <
608 boost::is_same<Proj1, srs::dynamic>::value
609 && boost::is_same<Proj2, srs::dynamic>::value
610 && projections::dynamic_parameters<Parameters1>::is_specialized
611 && projections::dynamic_parameters<Parameters2>::is_specialized
612 > * = 0)
613 : m_proj1(parameters1)
614 , m_proj2(parameters2)
615 {}
616
617 // First dynamic, second static
618 template <typename Parameters1>
619 transformation(Parameters1 const& parameters1,
620 Proj2 const& parameters2,
621 typename boost::enable_if_c
622 <
623 boost::is_same<Proj1, srs::dynamic>::value
624 && projections::dynamic_parameters<Parameters1>::is_specialized
625 > * = 0)
626 : m_proj1(parameters1)
627 , m_proj2(parameters2)
628 {}
629
630 // First static, second dynamic
631 template <typename Parameters2>
632 transformation(Proj1 const& parameters1,
633 Parameters2 const& parameters2,
634 typename boost::enable_if_c
635 <
636 boost::is_same<Proj2, srs::dynamic>::value
637 && projections::dynamic_parameters<Parameters2>::is_specialized
638 > * = 0)
639 : m_proj1(parameters1)
640 , m_proj2(parameters2)
641 {}
642
643 // Both static
644 transformation(Proj1 const& parameters1,
645 Proj2 const& parameters2)
11fdf7f2
TL
646 : m_proj1(parameters1)
647 , m_proj2(parameters2)
648 {}
649
650 template <typename GeometryIn, typename GeometryOut>
651 bool forward(GeometryIn const& in, GeometryOut & out) const
92f5a8d4
TL
652 {
653 return forward(in, out, transformation_grids<detail::empty_grids_storage>());
654 }
655
656 template <typename GeometryIn, typename GeometryOut>
657 bool inverse(GeometryIn const& in, GeometryOut & out) const
658 {
659 return inverse(in, out, transformation_grids<detail::empty_grids_storage>());
660 }
661
662 template <typename GeometryIn, typename GeometryOut, typename GridsStorage>
663 bool forward(GeometryIn const& in, GeometryOut & out,
664 transformation_grids<GridsStorage> const& grids) const
11fdf7f2
TL
665 {
666 BOOST_MPL_ASSERT_MSG((projections::detail::same_tags<GeometryIn, GeometryOut>::value),
667 NOT_SUPPORTED_COMBINATION_OF_GEOMETRIES,
668 (GeometryIn, GeometryOut));
669
670 return projections::detail::transform
671 <
672 GeometryOut,
673 calc_t
674 >::apply(m_proj1.proj(), m_proj1.proj().params(),
675 m_proj2.proj(), m_proj2.proj().params(),
92f5a8d4
TL
676 in, out,
677 grids.src_grids,
678 grids.dst_grids);
11fdf7f2
TL
679 }
680
92f5a8d4
TL
681 template <typename GeometryIn, typename GeometryOut, typename GridsStorage>
682 bool inverse(GeometryIn const& in, GeometryOut & out,
683 transformation_grids<GridsStorage> const& grids) const
11fdf7f2
TL
684 {
685 BOOST_MPL_ASSERT_MSG((projections::detail::same_tags<GeometryIn, GeometryOut>::value),
686 NOT_SUPPORTED_COMBINATION_OF_GEOMETRIES,
687 (GeometryIn, GeometryOut));
688
689 return projections::detail::transform
690 <
691 GeometryOut,
692 calc_t
693 >::apply(m_proj2.proj(), m_proj2.proj().params(),
694 m_proj1.proj(), m_proj1.proj().params(),
92f5a8d4
TL
695 in, out,
696 grids.dst_grids,
697 grids.src_grids);
698 }
699
700 template <typename GridsStorage>
701 inline transformation_grids<GridsStorage> initialize_grids(GridsStorage & grids_storage) const
702 {
703 transformation_grids<GridsStorage> result(grids_storage);
704
705 using namespace projections::detail;
706 pj_gridlist_from_nadgrids(m_proj1.proj().params(),
707 result.src_grids);
708 pj_gridlist_from_nadgrids(m_proj2.proj().params(),
709 result.dst_grids);
710
711 return result;
11fdf7f2
TL
712 }
713
714private:
715 projections::proj_wrapper<Proj1, CT> m_proj1;
716 projections::proj_wrapper<Proj2, CT> m_proj2;
717};
718
92f5a8d4 719
11fdf7f2
TL
720} // namespace srs
721
722
723}} // namespace boost::geometry
724
725
726#endif // BOOST_GEOMETRY_SRS_TRANSFORMATION_HPP