~ubuntu-branches/ubuntu/saucy/merkaartor/saucy

« back to all changes in this revision

Viewing changes to include/ggl/algorithms/transform.hpp

  • Committer: Bazaar Package Importer
  • Author(s): Bernd Zeimetz
  • Date: 2009-09-13 00:52:12 UTC
  • mto: (1.2.7 upstream) (0.1.3 upstream) (3.1.7 sid)
  • mto: This revision was merged to the branch mainline in revision 10.
  • Revision ID: james.westby@ubuntu.com-20090913005212-pjecal8zxm07x0fj
ImportĀ upstreamĀ versionĀ 0.14+svnfixes~20090912

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
// Generic Geometry Library
 
2
//
 
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)
 
8
 
 
9
#ifndef GGL_ALGORITHMS_TRANSFORM_HPP
 
10
#define GGL_ALGORITHMS_TRANSFORM_HPP
 
11
 
 
12
#include <cmath>
 
13
#include <iterator>
 
14
 
 
15
#include <boost/range/functions.hpp>
 
16
#include <boost/range/metafunctions.hpp>
 
17
 
 
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>
 
25
 
 
26
 
 
27
/*!
 
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)
 
32
are transformed.
 
33
 
 
34
There is a version without a strategy, transforming automatically, and there is a version with a strategy.
 
35
 
 
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)
 
41
 
 
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).
 
44
 
 
45
\par Examples:
 
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()
 
49
\skipline XYZ
 
50
\until endl;
 
51
 
 
52
The next example takes another approach and transforms from Cartesian to Cartesian:
 
53
\skipline XY
 
54
\until endl;
 
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.
 
57
 
 
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
 
60
 
 
61
*/
 
62
 
 
63
namespace ggl
 
64
{
 
65
 
 
66
#ifndef DOXYGEN_NO_DETAIL
 
67
namespace detail { namespace transform {
 
68
 
 
69
template <typename P1, typename P2>
 
70
struct transform_point
 
71
{
 
72
    template <typename S>
 
73
    static inline bool apply(P1 const& p1, P2& p2, S const& strategy)
 
74
    {
 
75
        return strategy(p1, p2);
 
76
    }
 
77
};
 
78
 
 
79
template <typename B1, typename B2>
 
80
struct transform_box
 
81
{
 
82
    template <typename S>
 
83
    static inline bool apply(B1 const& b1, B2& b2, S const& strategy)
 
84
    {
 
85
        typedef typename point_type<B1>::type point_type1;
 
86
        typedef typename point_type<B2>::type point_type2;
 
87
 
 
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);
 
91
 
 
92
        point_type2 p1, p2;
 
93
        if (strategy(lower_left, p1) && strategy(upper_right, p2))
 
94
        {
 
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);
 
101
 
 
102
            if (x1 > x2) { std::swap(x1, x2); }
 
103
            if (y1 > y2) { std::swap(y1, y2); }
 
104
 
 
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);
 
109
 
 
110
            return true;
 
111
        }
 
112
        return false;
 
113
    }
 
114
};
 
115
 
 
116
template <typename P, typename OutputIterator, typename R, typename S>
 
117
inline bool transform_range_out(R const& range, OutputIterator out, S const& strategy)
 
118
{
 
119
    P point_out;
 
120
    for(typename boost::range_const_iterator<R>::type it = boost::begin(range);
 
121
        it != boost::end(range); ++it)
 
122
    {
 
123
        if (! transform_point<typename point_type<R>::type, P>::apply(*it, point_out, strategy))
 
124
        {
 
125
            return false;
 
126
        }
 
127
        *out = point_out;
 
128
        ++out;
 
129
    }
 
130
    return true;
 
131
}
 
132
 
 
133
template <typename P1, typename P2>
 
134
struct transform_polygon
 
135
{
 
136
    template <typename S>
 
137
    static inline bool apply(const P1& poly1, P2& poly2, S const& strategy)
 
138
    {
 
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;
 
144
 
 
145
        ggl::clear(poly2);
 
146
 
 
147
        if (!transform_range_out<point2_type>(exterior_ring(poly1),
 
148
                    std::back_inserter(exterior_ring(poly2)), strategy))
 
149
        {
 
150
            return false;
 
151
        }
 
152
 
 
153
        interior_rings(poly2).resize(boost::size(interior_rings(poly1)));
 
154
 
 
155
        typedef typename boost::range_const_iterator<interior1_type>::type iterator1_type;
 
156
        typedef typename boost::range_iterator<interior2_type>::type iterator2_type;
 
157
 
 
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)
 
161
        {
 
162
            if (!transform_range_out<point2_type>(*it1, std::back_inserter(*it2), strategy))
 
163
            {
 
164
                return false;
 
165
            }
 
166
        }
 
167
 
 
168
        return true;
 
169
    }
 
170
};
 
171
 
 
172
 
 
173
template <typename P1, typename P2>
 
174
struct select_strategy
 
175
{
 
176
    typedef typename strategy_transform
 
177
        <
 
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
 
186
        >::type type;
 
187
};
 
188
 
 
189
template <typename R1, typename R2>
 
190
struct transform_range
 
191
{
 
192
    template <typename S>
 
193
    static inline bool apply(R1 const& range1, R2& range2, S const& strategy)
 
194
    {
 
195
        typedef typename point_type<R2>::type point_type;
 
196
 
 
197
        ggl::clear(range2);
 
198
        return transform_range_out<point_type>(range1, std::back_inserter(range2), strategy);
 
199
    }
 
200
};
 
201
 
 
202
}} // namespace detail::transform
 
203
#endif // DOXYGEN_NO_DETAIL
 
204
 
 
205
 
 
206
#ifndef DOXYGEN_NO_DISPATCH
 
207
namespace dispatch
 
208
{
 
209
 
 
210
template <typename Tag1, typename Tag2, typename G1, typename G2>
 
211
struct transform {};
 
212
 
 
213
template <typename P1, typename P2>
 
214
struct transform<point_tag, point_tag, P1, P2>
 
215
    : detail::transform::transform_point<P1, P2>
 
216
{
 
217
};
 
218
 
 
219
 
 
220
template <typename L1, typename L2>
 
221
struct transform<linestring_tag, linestring_tag, L1, L2>
 
222
    : detail::transform::transform_range<L1, L2>
 
223
{
 
224
};
 
225
 
 
226
template <typename R1, typename R2>
 
227
struct transform<ring_tag, ring_tag, R1, R2>
 
228
    : detail::transform::transform_range<R1, R2>
 
229
{
 
230
};
 
231
 
 
232
template <typename P1, typename P2>
 
233
struct transform<polygon_tag, polygon_tag, P1, P2>
 
234
    : detail::transform::transform_polygon<P1, P2>
 
235
{
 
236
};
 
237
 
 
238
template <typename B1, typename B2>
 
239
struct transform<box_tag, box_tag, B1, B2>
 
240
    : detail::transform::transform_box<B1, B2>
 
241
{
 
242
};
 
243
 
 
244
 
 
245
} // namespace dispatch
 
246
#endif // DOXYGEN_NO_DISPATCH
 
247
 
 
248
 
 
249
/*!
 
250
    \brief Transforms from one geometry to another geometry using a strategy
 
251
    \ingroup transform
 
252
    \tparam G1 first geometry type
 
253
    \tparam G2 second geometry type
 
254
    \tparam S strategy
 
255
    \param geometry1 first geometry
 
256
    \param geometry2 second geometry
 
257
    \param strategy the strategy to be used for transformation
 
258
 */
 
259
template <typename G1, typename G2, typename S>
 
260
inline bool transform(G1 const& geometry1, G2& geometry2, S const& strategy)
 
261
{
 
262
    typedef dispatch::transform
 
263
        <
 
264
        typename tag<G1>::type,
 
265
        typename tag<G2>::type,
 
266
        G1,
 
267
        G2
 
268
        > transform_type;
 
269
 
 
270
    return transform_type::apply(geometry1, geometry2, strategy);
 
271
}
 
272
 
 
273
/*!
 
274
    \brief Transforms from one geometry to another geometry using a strategy
 
275
    \ingroup transform
 
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
 
281
 */
 
282
template <typename G1, typename G2>
 
283
inline bool transform(G1 const& geometry1, G2& geometry2)
 
284
{
 
285
    typename detail::transform::select_strategy<G1, G2>::type strategy;
 
286
    return transform(geometry1, geometry2, strategy);
 
287
}
 
288
 
 
289
} // namespace ggl
 
290
 
 
291
#endif // GGL_ALGORITHMS_TRANSFORM_HPP