1 // Boost.Geometry (aka GGL, Generic Geometry Library)
2 
3 // Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
4 // Copyright (c) 2008-2012 Bruno Lalande, Paris, France.
5 // Copyright (c) 2009-2012 Mateusz Loskot, London, UK.
6 // Copyright (c) 2014 Adam Wulkiewicz, Lodz, Poland.
7 
8 // Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
9 // (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
10 
11 // Use, modification and distribution is subject to the Boost Software License,
12 // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
13 // http://www.boost.org/LICENSE_1_0.txt)
14 
15 #ifndef BOOST_GEOMETRY_ALGORITHMS_TRANSFORM_HPP
16 #define BOOST_GEOMETRY_ALGORITHMS_TRANSFORM_HPP
17 
18 #include <cmath>
19 #include <iterator>
20 
21 #include <boost/range.hpp>
22 #include <boost/type_traits/remove_reference.hpp>
23 
24 #include <boost/variant/apply_visitor.hpp>
25 #include <boost/variant/static_visitor.hpp>
26 #include <boost/variant/variant_fwd.hpp>
27 
28 #include <boost/geometry/algorithms/assign.hpp>
29 #include <boost/geometry/algorithms/clear.hpp>
30 #include <boost/geometry/algorithms/detail/interior_iterator.hpp>
31 #include <boost/geometry/algorithms/num_interior_rings.hpp>
32 
33 #include <boost/geometry/core/cs.hpp>
34 #include <boost/geometry/core/exterior_ring.hpp>
35 #include <boost/geometry/core/interior_rings.hpp>
36 #include <boost/geometry/core/mutable_range.hpp>
37 #include <boost/geometry/core/ring_type.hpp>
38 #include <boost/geometry/core/tag_cast.hpp>
39 #include <boost/geometry/core/tags.hpp>
40 #include <boost/geometry/geometries/concepts/check.hpp>
41 #include <boost/geometry/strategies/default_strategy.hpp>
42 #include <boost/geometry/strategies/transform.hpp>
43 
44 
45 namespace boost { namespace geometry
46 {
47 
48 #ifndef DOXYGEN_NO_DETAIL
49 namespace detail { namespace transform
50 {
51 
52 struct transform_point
53 {
54     template <typename Point1, typename Point2, typename Strategy>
applyboost::geometry::detail::transform::transform_point55     static inline bool apply(Point1 const& p1, Point2& p2,
56                 Strategy const& strategy)
57     {
58         return strategy.apply(p1, p2);
59     }
60 };
61 
62 
63 struct transform_box
64 {
65     template <typename Box1, typename Box2, typename Strategy>
applyboost::geometry::detail::transform::transform_box66     static inline bool apply(Box1 const& b1, Box2& b2,
67                 Strategy const& strategy)
68     {
69         typedef typename point_type<Box1>::type point_type1;
70         typedef typename point_type<Box2>::type point_type2;
71 
72         point_type1 lower_left, upper_right;
73         geometry::detail::assign::assign_box_2d_corner<min_corner, min_corner>(
74                     b1, lower_left);
75         geometry::detail::assign::assign_box_2d_corner<max_corner, max_corner>(
76                     b1, upper_right);
77 
78         point_type2 p1, p2;
79         if (strategy.apply(lower_left, p1) && strategy.apply(upper_right, p2))
80         {
81             // Create a valid box and therefore swap if necessary
82             typedef typename coordinate_type<point_type2>::type coordinate_type;
83             coordinate_type x1 = geometry::get<0>(p1)
84                     , y1  = geometry::get<1>(p1)
85                     , x2  = geometry::get<0>(p2)
86                     , y2  = geometry::get<1>(p2);
87 
88             if (x1 > x2) { std::swap(x1, x2); }
89             if (y1 > y2) { std::swap(y1, y2); }
90 
91             geometry::set<min_corner, 0>(b2, x1);
92             geometry::set<min_corner, 1>(b2, y1);
93             geometry::set<max_corner, 0>(b2, x2);
94             geometry::set<max_corner, 1>(b2, y2);
95 
96             return true;
97         }
98         return false;
99     }
100 };
101 
102 struct transform_box_or_segment
103 {
104     template <typename Geometry1, typename Geometry2, typename Strategy>
applyboost::geometry::detail::transform::transform_box_or_segment105     static inline bool apply(Geometry1 const& source, Geometry2& target,
106                 Strategy const& strategy)
107     {
108         typedef typename point_type<Geometry1>::type point_type1;
109         typedef typename point_type<Geometry2>::type point_type2;
110 
111         point_type1 source_point[2];
112         geometry::detail::assign_point_from_index<0>(source, source_point[0]);
113         geometry::detail::assign_point_from_index<1>(source, source_point[1]);
114 
115         point_type2 target_point[2];
116         if (strategy.apply(source_point[0], target_point[0])
117             && strategy.apply(source_point[1], target_point[1]))
118         {
119             geometry::detail::assign_point_to_index<0>(target_point[0], target);
120             geometry::detail::assign_point_to_index<1>(target_point[1], target);
121             return true;
122         }
123         return false;
124     }
125 };
126 
127 
128 template
129 <
130     typename PointOut,
131     typename OutputIterator,
132     typename Range,
133     typename Strategy
134 >
transform_range_out(Range const & range,OutputIterator out,Strategy const & strategy)135 inline bool transform_range_out(Range const& range,
136     OutputIterator out, Strategy const& strategy)
137 {
138     PointOut point_out;
139     for(typename boost::range_iterator<Range const>::type
140         it = boost::begin(range);
141         it != boost::end(range);
142         ++it)
143     {
144         if (! transform_point::apply(*it, point_out, strategy))
145         {
146             return false;
147         }
148         *out++ = point_out;
149     }
150     return true;
151 }
152 
153 
154 struct transform_polygon
155 {
156     template <typename Polygon1, typename Polygon2, typename Strategy>
applyboost::geometry::detail::transform::transform_polygon157     static inline bool apply(Polygon1 const& poly1, Polygon2& poly2,
158                 Strategy const& strategy)
159     {
160         typedef typename point_type<Polygon2>::type point2_type;
161 
162         geometry::clear(poly2);
163 
164         if (!transform_range_out<point2_type>(geometry::exterior_ring(poly1),
165                     range::back_inserter(geometry::exterior_ring(poly2)), strategy))
166         {
167             return false;
168         }
169 
170         // Note: here a resizeable container is assumed.
171         traits::resize
172             <
173                 typename boost::remove_reference
174                 <
175                     typename traits::interior_mutable_type<Polygon2>::type
176                 >::type
177             >::apply(geometry::interior_rings(poly2),
178                      geometry::num_interior_rings(poly1));
179 
180         typename geometry::interior_return_type<Polygon1 const>::type
181             rings1 = geometry::interior_rings(poly1);
182         typename geometry::interior_return_type<Polygon2>::type
183             rings2 = geometry::interior_rings(poly2);
184 
185         typename detail::interior_iterator<Polygon1 const>::type
186             it1 = boost::begin(rings1);
187         typename detail::interior_iterator<Polygon2>::type
188             it2 = boost::begin(rings2);
189         for ( ; it1 != boost::end(rings1); ++it1, ++it2)
190         {
191             if ( ! transform_range_out<point2_type>(*it1,
192                                                     range::back_inserter(*it2),
193                                                     strategy) )
194             {
195                 return false;
196             }
197         }
198 
199         return true;
200     }
201 };
202 
203 
204 template <typename Point1, typename Point2>
205 struct select_strategy
206 {
207     typedef typename strategy::transform::services::default_strategy
208         <
209             typename cs_tag<Point1>::type,
210             typename cs_tag<Point2>::type,
211             typename coordinate_system<Point1>::type,
212             typename coordinate_system<Point2>::type,
213             dimension<Point1>::type::value,
214             dimension<Point2>::type::value,
215             typename point_type<Point1>::type,
216             typename point_type<Point2>::type
217         >::type type;
218 };
219 
220 struct transform_range
221 {
222     template <typename Range1, typename Range2, typename Strategy>
applyboost::geometry::detail::transform::transform_range223     static inline bool apply(Range1 const& range1,
224             Range2& range2, Strategy const& strategy)
225     {
226         typedef typename point_type<Range2>::type point_type;
227 
228         // Should NOT be done here!
229         // geometry::clear(range2);
230         return transform_range_out<point_type>(range1,
231                 range::back_inserter(range2), strategy);
232     }
233 };
234 
235 
236 /*!
237     \brief Is able to transform any multi-geometry, calling the single-version as policy
238 */
239 template <typename Policy>
240 struct transform_multi
241 {
242     template <typename Multi1, typename Multi2, typename S>
applyboost::geometry::detail::transform::transform_multi243     static inline bool apply(Multi1 const& multi1, Multi2& multi2, S const& strategy)
244     {
245         traits::resize<Multi2>::apply(multi2, boost::size(multi1));
246 
247         typename boost::range_iterator<Multi1 const>::type it1
248                 = boost::begin(multi1);
249         typename boost::range_iterator<Multi2>::type it2
250                 = boost::begin(multi2);
251 
252         for (; it1 != boost::end(multi1); ++it1, ++it2)
253         {
254             if (! Policy::apply(*it1, *it2, strategy))
255             {
256                 return false;
257             }
258         }
259 
260         return true;
261     }
262 };
263 
264 
265 }} // namespace detail::transform
266 #endif // DOXYGEN_NO_DETAIL
267 
268 
269 #ifndef DOXYGEN_NO_DISPATCH
270 namespace dispatch
271 {
272 
273 template
274 <
275     typename Geometry1, typename Geometry2,
276     typename Tag1 = typename tag_cast<typename tag<Geometry1>::type, multi_tag>::type,
277     typename Tag2 = typename tag_cast<typename tag<Geometry2>::type, multi_tag>::type
278 >
279 struct transform {};
280 
281 template <typename Point1, typename Point2>
282 struct transform<Point1, Point2, point_tag, point_tag>
283     : detail::transform::transform_point
284 {
285 };
286 
287 
288 template <typename Linestring1, typename Linestring2>
289 struct transform
290     <
291         Linestring1, Linestring2,
292         linestring_tag, linestring_tag
293     >
294     : detail::transform::transform_range
295 {
296 };
297 
298 template <typename Range1, typename Range2>
299 struct transform<Range1, Range2, ring_tag, ring_tag>
300     : detail::transform::transform_range
301 {
302 };
303 
304 template <typename Polygon1, typename Polygon2>
305 struct transform<Polygon1, Polygon2, polygon_tag, polygon_tag>
306     : detail::transform::transform_polygon
307 {
308 };
309 
310 template <typename Box1, typename Box2>
311 struct transform<Box1, Box2, box_tag, box_tag>
312     : detail::transform::transform_box
313 {
314 };
315 
316 template <typename Segment1, typename Segment2>
317 struct transform<Segment1, Segment2, segment_tag, segment_tag>
318     : detail::transform::transform_box_or_segment
319 {
320 };
321 
322 template <typename Multi1, typename Multi2>
323 struct transform
324     <
325         Multi1, Multi2,
326         multi_tag, multi_tag
327     >
328     : detail::transform::transform_multi
329         <
330             dispatch::transform
331                 <
332                     typename boost::range_value<Multi1>::type,
333                     typename boost::range_value<Multi2>::type
334                 >
335         >
336 {};
337 
338 
339 } // namespace dispatch
340 #endif // DOXYGEN_NO_DISPATCH
341 
342 
343 namespace resolve_strategy {
344 
345 struct transform
346 {
347     template <typename Geometry1, typename Geometry2, typename Strategy>
applyboost::geometry::resolve_strategy::transform348     static inline bool apply(Geometry1 const& geometry1,
349                              Geometry2& geometry2,
350                              Strategy const& strategy)
351     {
352         concepts::check<Geometry1 const>();
353         concepts::check<Geometry2>();
354 
355         return dispatch::transform<Geometry1, Geometry2>::apply(
356             geometry1,
357             geometry2,
358             strategy
359         );
360     }
361 
362     template <typename Geometry1, typename Geometry2>
applyboost::geometry::resolve_strategy::transform363     static inline bool apply(Geometry1 const& geometry1,
364                              Geometry2& geometry2,
365                              default_strategy)
366     {
367         return apply(
368             geometry1,
369             geometry2,
370             typename detail::transform::select_strategy<Geometry1, Geometry2>::type()
371         );
372     }
373 };
374 
375 } // namespace resolve_strategy
376 
377 
378 namespace resolve_variant {
379 
380 template <typename Geometry1, typename Geometry2>
381 struct transform
382 {
383     template <typename Strategy>
applyboost::geometry::resolve_variant::transform384     static inline bool apply(Geometry1 const& geometry1,
385                              Geometry2& geometry2,
386                              Strategy const& strategy)
387     {
388         return resolve_strategy::transform::apply(
389             geometry1,
390             geometry2,
391             strategy
392         );
393     }
394 };
395 
396 template <BOOST_VARIANT_ENUM_PARAMS(typename T), typename Geometry2>
397 struct transform<boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)>, Geometry2>
398 {
399     template <typename Strategy>
400     struct visitor: static_visitor<bool>
401     {
402         Geometry2& m_geometry2;
403         Strategy const& m_strategy;
404 
visitorboost::geometry::resolve_variant::transform::visitor405         visitor(Geometry2& geometry2, Strategy const& strategy)
406             : m_geometry2(geometry2)
407             , m_strategy(strategy)
408         {}
409 
410         template <typename Geometry1>
operator ()boost::geometry::resolve_variant::transform::visitor411         inline bool operator()(Geometry1 const& geometry1) const
412         {
413             return transform<Geometry1, Geometry2>::apply(
414                 geometry1,
415                 m_geometry2,
416                 m_strategy
417             );
418         }
419     };
420 
421     template <typename Strategy>
applyboost::geometry::resolve_variant::transform422     static inline bool apply(
423         boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& geometry1,
424         Geometry2& geometry2,
425         Strategy const& strategy
426     )
427     {
428         return boost::apply_visitor(visitor<Strategy>(geometry2, strategy), geometry1);
429     }
430 };
431 
432 } // namespace resolve_variant
433 
434 
435 /*!
436 \brief Transforms from one geometry to another geometry  \brief_strategy
437 \ingroup transform
438 \tparam Geometry1 \tparam_geometry
439 \tparam Geometry2 \tparam_geometry
440 \tparam Strategy strategy
441 \param geometry1 \param_geometry
442 \param geometry2 \param_geometry
443 \param strategy The strategy to be used for transformation
444 \return True if the transformation could be done
445 
446 \qbk{distinguish,with strategy}
447 
448 \qbk{[include reference/algorithms/transform_with_strategy.qbk]}
449  */
450 template <typename Geometry1, typename Geometry2, typename Strategy>
transform(Geometry1 const & geometry1,Geometry2 & geometry2,Strategy const & strategy)451 inline bool transform(Geometry1 const& geometry1, Geometry2& geometry2,
452             Strategy const& strategy)
453 {
454     return resolve_variant::transform<Geometry1, Geometry2>
455                           ::apply(geometry1, geometry2, strategy);
456 }
457 
458 
459 /*!
460 \brief Transforms from one geometry to another geometry using a strategy
461 \ingroup transform
462 \tparam Geometry1 \tparam_geometry
463 \tparam Geometry2 \tparam_geometry
464 \param geometry1 \param_geometry
465 \param geometry2 \param_geometry
466 \return True if the transformation could be done
467 
468 \qbk{[include reference/algorithms/transform.qbk]}
469  */
470 template <typename Geometry1, typename Geometry2>
transform(Geometry1 const & geometry1,Geometry2 & geometry2)471 inline bool transform(Geometry1 const& geometry1, Geometry2& geometry2)
472 {
473     return geometry::transform(geometry1, geometry2, default_strategy());
474 }
475 
476 
477 }} // namespace boost::geometry
478 
479 
480 #endif // BOOST_GEOMETRY_ALGORITHMS_TRANSFORM_HPP
481