]>
Commit | Line | Data |
---|---|---|
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> | |
55 | 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> | |
66 | 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> | |
105 | 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 | > | |
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> | |
157 | 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> | |
223 | 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> | |
243 | 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> | |
348 | 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> | |
363 | 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> | |
384 | 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 | ||
405 | visitor(Geometry2& geometry2, Strategy const& strategy) | |
406 | : m_geometry2(geometry2) | |
407 | , m_strategy(strategy) | |
408 | {} | |
409 | ||
410 | template <typename Geometry1> | |
411 | 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> | |
422 | 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> | |
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> | |
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 |