• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Boost.Geometry (aka GGL, Generic Geometry Library)
2 
3 // Copyright (c) 2017-2018, Oracle and/or its affiliates.
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>
27 #include <boost/geometry/srs/projections/grids.hpp>
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 
40 namespace boost { namespace geometry
41 {
42 
43 namespace projections { namespace detail
44 {
45 
46 template <typename T1, typename T2>
same_object(T1 const &,T2 const &)47 inline bool same_object(T1 const& , T2 const& )
48 {
49     return false;
50 }
51 
52 template <typename T>
same_object(T const & o1,T const & o2)53 inline bool same_object(T const& o1, T const& o2)
54 {
55     return boost::addressof(o1) == boost::addressof(o2);
56 }
57 
58 template
59 <
60     typename PtIn,
61     typename PtOut,
62     bool SameUnits = boost::is_same
63                         <
64                             typename geometry::detail::cs_angular_units<PtIn>::type,
65                             typename geometry::detail::cs_angular_units<PtOut>::type
66                         >::value
67 >
68 struct transform_geometry_point_coordinates
69 {
applyboost::geometry::projections::detail::transform_geometry_point_coordinates70     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 
77 template <typename PtIn, typename PtOut>
78 struct transform_geometry_point_coordinates<PtIn, PtOut, false>
79 {
applyboost::geometry::projections::detail::transform_geometry_point_coordinates80     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 
95 template <typename Geometry, typename CT>
96 struct 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>
applyboost::geometry::projections::detail::transform_geometry_point112     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 
119 template <typename Geometry, typename CT>
120 struct transform_geometry_range_base
121 {
122     struct convert_strategy
123     {
convert_strategyboost::geometry::projections::detail::transform_geometry_range_base::convert_strategy124         convert_strategy(bool enable_angles)
125             : m_enable_angles(enable_angles)
126         {}
127 
128         template <typename PtIn, typename PtOut>
applyboost::geometry::projections::detail::transform_geometry_range_base::convert_strategy129         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>
applyboost::geometry::projections::detail::transform_geometry_range_base138     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 
154 template
155 <
156     typename Geometry,
157     typename CT,
158     typename Tag = typename geometry::tag<Geometry>::type
159 >
160 struct transform_geometry
161 {};
162 
163 template <typename Point, typename CT>
164 struct transform_geometry<Point, CT, point_tag>
165     : transform_geometry_point<Point, CT>
166 {};
167 
168 template <typename Segment, typename CT>
169 struct 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>
applyboost::geometry::projections::detail::transform_geometry177     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 
183 private:
184     template <std::size_t Index, typename In, typename Out>
applyboost::geometry::projections::detail::transform_geometry185     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 
193 template <typename MultiPoint, typename CT>
194 struct 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 
203 template <typename LineString, typename CT>
204 struct 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 
213 template <typename Ring, typename CT>
214 struct 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 
226 template
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 >
240 struct transform_geometry_wrapper
241 {
242     typedef transform_geometry<OutGeometry, CT> transform;
243     typedef typename transform::type type;
244 
245     template <typename InGeometry>
transform_geometry_wrapperboost::geometry::projections::detail::transform_geometry_wrapper246     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 
getboost::geometry::projections::detail::transform_geometry_wrapper252     type & get() { return m_temp; }
finishboost::geometry::projections::detail::transform_geometry_wrapper253     void finish() { geometry::convert(m_temp, m_out); } // this is always copy 1:1 without changing the order or closure
254 
255 private:
256     type m_temp;
257     OutGeometry & m_out;
258 };
259 
260 template
261 <
262     typename OutGeometry,
263     typename CT
264 >
265 struct transform_geometry_wrapper<OutGeometry, CT, false>
266 {
267     typedef transform_geometry<OutGeometry, CT> transform;
268     typedef OutGeometry type;
269 
transform_geometry_wrapperboost::geometry::projections::detail::transform_geometry_wrapper270     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>
transform_geometry_wrapperboost::geometry::projections::detail::transform_geometry_wrapper278     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 
getboost::geometry::projections::detail::transform_geometry_wrapper284     OutGeometry & get() { return m_out; }
finishboost::geometry::projections::detail::transform_geometry_wrapper285     void finish() {}
286 
287 private:
288     OutGeometry & m_out;
289 };
290 
291 template <typename CT>
292 struct transform_range
293 {
294     template
295     <
296         typename Proj1, typename Par1,
297         typename Proj2, typename Par2,
298         typename RangeIn, typename RangeOut,
299         typename Grids
300     >
applyboost::geometry::projections::detail::transform_range301     static inline bool apply(Proj1 const& proj1, Par1 const& par1,
302                              Proj2 const& proj2, Par2 const& par2,
303                              RangeIn const& in, RangeOut & out,
304                              Grids const& grids1, Grids const& grids2)
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         {
314             res = pj_transform(proj1, par1, proj2, par2, wrapper.get(), grids1, grids2);
315         }
316         catch (projection_exception const&)
317         {
318             res = false;
319         }
320         catch(...)
321         {
322             BOOST_RETHROW
323         }
324 
325         wrapper.finish();
326 
327         return res;
328     }
329 };
330 
331 template <typename Policy>
332 struct transform_multi
333 {
334     template
335     <
336         typename Proj1, typename Par1,
337         typename Proj2, typename Par2,
338         typename MultiIn, typename MultiOut,
339         typename Grids
340     >
applyboost::geometry::projections::detail::transform_multi341     static inline bool apply(Proj1 const& proj1, Par1 const& par1,
342                              Proj2 const& proj2, Par2 const& par2,
343                              MultiIn const& in, MultiOut & out,
344                              Grids const& grids1, Grids const& grids2)
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),
351                      boost::begin(out),
352                      grids1, grids2);
353     }
354 
355 private:
356     template
357     <
358         typename Proj1, typename Par1,
359         typename Proj2, typename Par2,
360         typename InIt, typename OutIt,
361         typename Grids
362     >
applyboost::geometry::projections::detail::transform_multi363     static inline bool apply(Proj1 const& proj1, Par1 const& par1,
364                              Proj2 const& proj2, Par2 const& par2,
365                              InIt in_first, InIt in_last, OutIt out_first,
366                              Grids const& grids1, Grids const& grids2)
367     {
368         bool res = true;
369         for ( ; in_first != in_last ; ++in_first, ++out_first )
370         {
371             if ( ! Policy::apply(proj1, par1, proj2, par2, *in_first, *out_first, grids1, grids2) )
372             {
373                 res = false;
374             }
375         }
376         return res;
377     }
378 };
379 
380 template
381 <
382     typename Geometry,
383     typename CT,
384     typename Tag = typename geometry::tag<Geometry>::type
385 >
386 struct transform
387     : not_implemented<Tag>
388 {};
389 
390 template <typename Point, typename CT>
391 struct transform<Point, CT, point_tag>
392 {
393     template
394     <
395         typename Proj1, typename Par1,
396         typename Proj2, typename Par2,
397         typename PointIn, typename PointOut,
398         typename Grids
399     >
applyboost::geometry::projections::detail::transform400     static inline bool apply(Proj1 const& proj1, Par1 const& par1,
401                              Proj2 const& proj2, Par2 const& par2,
402                              PointIn const& in, PointOut & out,
403                              Grids const& grids1, Grids const& grids2)
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         {
418             res = pj_transform(proj1, par1, proj2, par2, range, grids1, grids2);
419         }
420         catch (projection_exception const&)
421         {
422             res = false;
423         }
424         catch(...)
425         {
426             BOOST_RETHROW
427         }
428 
429         wrapper.finish();
430 
431         return res;
432     }
433 };
434 
435 template <typename MultiPoint, typename CT>
436 struct transform<MultiPoint, CT, multi_point_tag>
437     : transform_range<CT>
438 {};
439 
440 template <typename Segment, typename CT>
441 struct transform<Segment, CT, segment_tag>
442 {
443     template
444     <
445         typename Proj1, typename Par1,
446         typename Proj2, typename Par2,
447         typename SegmentIn, typename SegmentOut,
448         typename Grids
449     >
applyboost::geometry::projections::detail::transform450     static inline bool apply(Proj1 const& proj1, Par1 const& par1,
451                              Proj2 const& proj2, Par2 const& par2,
452                              SegmentIn const& in, SegmentOut & out,
453                              Grids const& grids1, Grids const& grids2)
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         {
475             res = pj_transform(proj1, par1, proj2, par2, range, grids1, grids2);
476         }
477         catch (projection_exception const&)
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 
495 template <typename Linestring, typename CT>
496 struct transform<Linestring, CT, linestring_tag>
497     : transform_range<CT>
498 {};
499 
500 template <typename MultiLinestring, typename CT>
501 struct transform<MultiLinestring, CT, multi_linestring_tag>
502     : transform_multi<transform_range<CT> >
503 {};
504 
505 template <typename Ring, typename CT>
506 struct transform<Ring, CT, ring_tag>
507     : transform_range<CT>
508 {};
509 
510 template <typename Polygon, typename CT>
511 struct transform<Polygon, CT, polygon_tag>
512 {
513     template
514     <
515         typename Proj1, typename Par1,
516         typename Proj2, typename Par2,
517         typename PolygonIn, typename PolygonOut,
518         typename Grids
519     >
applyboost::geometry::projections::detail::transform520     static inline bool apply(Proj1 const& proj1, Par1 const& par1,
521                              Proj2 const& proj2, Par2 const& par2,
522                              PolygonIn const& in, PolygonOut & out,
523                              Grids const& grids1, Grids const& grids2)
524     {
525         bool r1 = transform_range
526                     <
527                         CT
528                     >::apply(proj1, par1, proj2, par2,
529                              geometry::exterior_ring(in),
530                              geometry::exterior_ring(out),
531                              grids1, grids2);
532         bool r2 = transform_multi
533                     <
534                         transform_range<CT>
535                      >::apply(proj1, par1, proj2, par2,
536                               geometry::interior_rings(in),
537                               geometry::interior_rings(out),
538                               grids1, grids2);
539         return r1 && r2;
540     }
541 };
542 
543 template <typename MultiPolygon, typename CT>
544 struct 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 
559 namespace 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 */
571 template
572 <
573     typename Proj1 = srs::dynamic,
574     typename Proj2 = srs::dynamic,
575     typename CT = double
576 >
577 class transformation
578 {
579     typedef typename projections::detail::promote_to_double<CT>::type calc_t;
580 
581 public:
582     // Both static and default constructed
transformation()583     transformation()
584     {}
585 
586     // First dynamic, second static and default constructed
587     template <typename Parameters1>
transformation(Parameters1 const & parameters1,typename boost::enable_if_c<boost::is_same<Proj1,srs::dynamic>::value && projections::dynamic_parameters<Parameters1>::is_specialized>::type * =0)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
transformation(Proj1 const & parameters1)598     explicit transformation(Proj1 const& parameters1)
599         : m_proj1(parameters1)
600     {}
601 
602     // Both dynamic
603     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)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>
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)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>
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)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
transformation(Proj1 const & parameters1,Proj2 const & parameters2)644     transformation(Proj1 const& parameters1,
645                    Proj2 const& parameters2)
646         : m_proj1(parameters1)
647         , m_proj2(parameters2)
648     {}
649 
650     template <typename GeometryIn, typename GeometryOut>
forward(GeometryIn const & in,GeometryOut & out) const651     bool forward(GeometryIn const& in, GeometryOut & out) const
652     {
653         return forward(in, out, transformation_grids<detail::empty_grids_storage>());
654     }
655 
656     template <typename GeometryIn, typename GeometryOut>
inverse(GeometryIn const & in,GeometryOut & out) const657     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>
forward(GeometryIn const & in,GeometryOut & out,transformation_grids<GridsStorage> const & grids) const663     bool forward(GeometryIn const& in, GeometryOut & out,
664                  transformation_grids<GridsStorage> const& grids) const
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(),
676                          in, out,
677                          grids.src_grids,
678                          grids.dst_grids);
679     }
680 
681     template <typename GeometryIn, typename GeometryOut, typename GridsStorage>
inverse(GeometryIn const & in,GeometryOut & out,transformation_grids<GridsStorage> const & grids) const682     bool inverse(GeometryIn const& in, GeometryOut & out,
683                  transformation_grids<GridsStorage> const& grids) const
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(),
695                          in, out,
696                          grids.dst_grids,
697                          grids.src_grids);
698     }
699 
700     template <typename GridsStorage>
initialize_grids(GridsStorage & grids_storage) const701     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;
712     }
713 
714 private:
715     projections::proj_wrapper<Proj1, CT> m_proj1;
716     projections::proj_wrapper<Proj2, CT> m_proj2;
717 };
718 
719 
720 } // namespace srs
721 
722 
723 }} // namespace boost::geometry
724 
725 
726 #endif // BOOST_GEOMETRY_SRS_TRANSFORMATION_HPP
727