1
// Generic Geometry Library
3
// Copyright Barend Gehrels 1995-2009, Geodan Holding B.V. Amsterdam, the Netherlands.
4
// Copyright Bruno Lalande 2008, 2009
5
// Use, modification and distribution is subject to the Boost Software License,
6
// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
7
// http://www.boost.org/LICENSE_1_0.txt)
9
#ifndef GGL_ALGORITHMS_TRANSFORM_HPP
10
#define GGL_ALGORITHMS_TRANSFORM_HPP
15
#include <boost/range/functions.hpp>
16
#include <boost/range/metafunctions.hpp>
18
#include <ggl/algorithms/clear.hpp>
19
#include <ggl/core/cs.hpp>
20
#include <ggl/core/exterior_ring.hpp>
21
#include <ggl/core/interior_rings.hpp>
22
#include <ggl/core/ring_type.hpp>
23
#include <ggl/geometries/segment.hpp>
24
#include <ggl/strategies/strategies.hpp>
28
\defgroup transform transformations
29
\brief Transforms from one geometry to another geometry, optionally using a strategy
30
\details The transform algorithm automatically transforms from one coordinate system to another coordinate system.
31
If the coordinate system of both geometries are the same, the geometry is copied. All point(s of the geometry)
34
There is a version without a strategy, transforming automatically, and there is a version with a strategy.
36
This function has a lot of appliances, for example
37
- transform from spherical coordinates to cartesian coordinates, and back
38
- transform from geographic coordinates to cartesian coordinates (projections) and back
39
- transform from degree to radian, and back
40
- transform from and to cartesian coordinates (mapping, translations, etc)
42
The automatic transformations look to the coordinate system family, and dimensions, of the point type and by this
43
apply the strategy (internally bounded by traits classes).
46
The example below shows automatic transformations to go from one coordinate system to another one:
47
\dontinclude doxygen_2.cpp
48
\skip example_for_transform()
52
The next example takes another approach and transforms from Cartesian to Cartesian:
55
See also \link p03_projmap_example.cpp the projmap example \endlink
56
where this last one plus a transformation using a projection are used.
58
\note Not every possibility is yet worked out, e.g. polar coordinate system is ignored until now
59
\note This "transform" is broader then geodetic datum transformations, those are currently not worked out
66
#ifndef DOXYGEN_NO_DETAIL
67
namespace detail { namespace transform {
69
template <typename P1, typename P2>
70
struct transform_point
73
static inline bool apply(P1 const& p1, P2& p2, S const& strategy)
75
return strategy(p1, p2);
79
template <typename B1, typename B2>
83
static inline bool apply(B1 const& b1, B2& b2, S const& strategy)
85
typedef typename point_type<B1>::type point_type1;
86
typedef typename point_type<B2>::type point_type2;
88
point_type1 lower_left, upper_right;
89
assign_box_corner<min_corner, min_corner>(b1, lower_left);
90
assign_box_corner<max_corner, max_corner>(b1, upper_right);
93
if (strategy(lower_left, p1) && strategy(upper_right, p2))
95
// Create a valid box and therefore swap if necessary
96
typedef typename coordinate_type<point_type2>::type coordinate_type;
97
coordinate_type x1 = ggl::get<0>(p1)
98
, y1 = ggl::get<1>(p1)
99
, x2 = ggl::get<0>(p2)
100
, y2 = ggl::get<1>(p2);
102
if (x1 > x2) { std::swap(x1, x2); }
103
if (y1 > y2) { std::swap(y1, y2); }
105
set<min_corner, 0>(b2, x1);
106
set<min_corner, 1>(b2, y1);
107
set<max_corner, 0>(b2, x2);
108
set<max_corner, 1>(b2, y2);
116
template <typename P, typename OutputIterator, typename R, typename S>
117
inline bool transform_range_out(R const& range, OutputIterator out, S const& strategy)
120
for(typename boost::range_const_iterator<R>::type it = boost::begin(range);
121
it != boost::end(range); ++it)
123
if (! transform_point<typename point_type<R>::type, P>::apply(*it, point_out, strategy))
133
template <typename P1, typename P2>
134
struct transform_polygon
136
template <typename S>
137
static inline bool apply(const P1& poly1, P2& poly2, S const& strategy)
139
typedef typename interior_type<P1>::type interior1_type;
140
typedef typename interior_type<P2>::type interior2_type;
141
typedef typename ring_type<P1>::type ring1_type;
142
typedef typename ring_type<P2>::type ring2_type;
143
typedef typename point_type<P2>::type point2_type;
147
if (!transform_range_out<point2_type>(exterior_ring(poly1),
148
std::back_inserter(exterior_ring(poly2)), strategy))
153
interior_rings(poly2).resize(boost::size(interior_rings(poly1)));
155
typedef typename boost::range_const_iterator<interior1_type>::type iterator1_type;
156
typedef typename boost::range_iterator<interior2_type>::type iterator2_type;
158
iterator1_type it1 = boost::begin(interior_rings(poly1));
159
iterator2_type it2 = boost::begin(interior_rings(poly2));
160
for ( ; it1 != boost::end(interior_rings(poly1)); ++it1, ++it2)
162
if (!transform_range_out<point2_type>(*it1, std::back_inserter(*it2), strategy))
173
template <typename P1, typename P2>
174
struct select_strategy
176
typedef typename strategy_transform
178
typename cs_tag<P1>::type,
179
typename cs_tag<P2>::type,
180
typename coordinate_system<P1>::type,
181
typename coordinate_system<P2>::type,
182
dimension<P1>::type::value,
183
dimension<P2>::type::value,
184
typename point_type<P1>::type,
185
typename point_type<P2>::type
189
template <typename R1, typename R2>
190
struct transform_range
192
template <typename S>
193
static inline bool apply(R1 const& range1, R2& range2, S const& strategy)
195
typedef typename point_type<R2>::type point_type;
198
return transform_range_out<point_type>(range1, std::back_inserter(range2), strategy);
202
}} // namespace detail::transform
203
#endif // DOXYGEN_NO_DETAIL
206
#ifndef DOXYGEN_NO_DISPATCH
210
template <typename Tag1, typename Tag2, typename G1, typename G2>
213
template <typename P1, typename P2>
214
struct transform<point_tag, point_tag, P1, P2>
215
: detail::transform::transform_point<P1, P2>
220
template <typename L1, typename L2>
221
struct transform<linestring_tag, linestring_tag, L1, L2>
222
: detail::transform::transform_range<L1, L2>
226
template <typename R1, typename R2>
227
struct transform<ring_tag, ring_tag, R1, R2>
228
: detail::transform::transform_range<R1, R2>
232
template <typename P1, typename P2>
233
struct transform<polygon_tag, polygon_tag, P1, P2>
234
: detail::transform::transform_polygon<P1, P2>
238
template <typename B1, typename B2>
239
struct transform<box_tag, box_tag, B1, B2>
240
: detail::transform::transform_box<B1, B2>
245
} // namespace dispatch
246
#endif // DOXYGEN_NO_DISPATCH
250
\brief Transforms from one geometry to another geometry using a strategy
252
\tparam G1 first geometry type
253
\tparam G2 second geometry type
255
\param geometry1 first geometry
256
\param geometry2 second geometry
257
\param strategy the strategy to be used for transformation
259
template <typename G1, typename G2, typename S>
260
inline bool transform(G1 const& geometry1, G2& geometry2, S const& strategy)
262
typedef dispatch::transform
264
typename tag<G1>::type,
265
typename tag<G2>::type,
270
return transform_type::apply(geometry1, geometry2, strategy);
274
\brief Transforms from one geometry to another geometry using a strategy
276
\tparam G1 first geometry type
277
\tparam G2 second geometry type
278
\param geometry1 first geometry
279
\param geometry2 second geometry
280
\return true if the transformation could be done
282
template <typename G1, typename G2>
283
inline bool transform(G1 const& geometry1, G2& geometry2)
285
typename detail::transform::select_strategy<G1, G2>::type strategy;
286
return transform(geometry1, geometry2, strategy);
291
#endif // GGL_ALGORITHMS_TRANSFORM_HPP