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

« back to all changes in this revision

Viewing changes to include/ggl/extensions/gis/io/wkt/write_wkt.hpp

Tags: upstream-0.15.3+svn20934
ImportĀ upstreamĀ versionĀ 0.15.3+svn20934

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
// Generic Geometry Library
2
 
//
3
 
// Copyright Barend Gehrels 2008-2009, Geodan, Amsterdam, the Netherlands.
4
 
// Use, modification and distribution is subject to the Boost Software License,
5
 
// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
6
 
// http://www.boost.org/LICENSE_1_0.txt)
7
 
 
8
 
#ifndef GGL_EXTENSIONS_GIS_IO_WKT_WRITE_WKT_HPP
9
 
#define GGL_EXTENSIONS_GIS_IO_WKT_WRITE_WKT_HPP
10
 
 
11
 
#include <iostream>
12
 
#include <string>
13
 
 
14
 
#include <boost/concept/assert.hpp>
15
 
#include <boost/range/functions.hpp>
16
 
#include <boost/range/metafunctions.hpp>
17
 
 
18
 
#include <ggl/algorithms/convert.hpp>
19
 
#include <ggl/core/concepts/point_concept.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/linear_ring.hpp>
24
 
 
25
 
#include <ggl/extensions/gis/io/wkt/detail/wkt.hpp>
26
 
 
27
 
/*!
28
 
\defgroup wkt wkt: parse and stream WKT (Well-Known Text)
29
 
The wkt classes stream the specified geometry as \ref OGC Well Known Text (\ref WKT). It is defined for OGC geometries.
30
 
It is therefore not defined for all geometries (e.g. not for circle)
31
 
\note The implementation is independant from point type, point_xy and point_ll are supported,
32
 
as well as points with more than two coordinates.
33
 
*/
34
 
 
35
 
namespace ggl
36
 
{
37
 
 
38
 
#ifndef DOXYGEN_NO_DETAIL
39
 
namespace detail { namespace wkt {
40
 
 
41
 
template <typename P, int I, int Count>
42
 
struct stream_coordinate
43
 
{
44
 
    template <typename Char, typename Traits>
45
 
    static inline void apply(std::basic_ostream<Char, Traits>& os, P const& p)
46
 
    {
47
 
        os << (I > 0 ? " " : "") << get<I>(p);
48
 
        stream_coordinate<P, I + 1, Count>::apply(os, p);
49
 
    }
50
 
};
51
 
 
52
 
template <typename P, int Count>
53
 
struct stream_coordinate<P, Count, Count>
54
 
{
55
 
    template <typename Char, typename Traits>
56
 
    static inline void apply(std::basic_ostream<Char, Traits>&, P const&)
57
 
    {}
58
 
};
59
 
 
60
 
struct prefix_linestring_par
61
 
{
62
 
    static inline const char* apply() { return "LINESTRING("; }
63
 
};
64
 
 
65
 
struct prefix_ring_par_par
66
 
{
67
 
    // Note, double parentheses are intentional, indicating WKT ring begin/end
68
 
    static inline const char* apply() { return "POLYGON(("; }
69
 
};
70
 
 
71
 
struct opening_parenthesis
72
 
{
73
 
    static inline const char* apply() { return "("; }
74
 
};
75
 
 
76
 
struct closing_parenthesis
77
 
{
78
 
    static inline const char* apply() { return ")"; }
79
 
};
80
 
 
81
 
struct double_closing_parenthesis
82
 
{
83
 
    static inline const char* apply() { return "))"; }
84
 
};
85
 
 
86
 
 
87
 
 
88
 
 
89
 
/*!
90
 
\brief Stream points as \ref WKT
91
 
*/
92
 
template <typename Point, typename Policy>
93
 
struct wkt_point
94
 
{
95
 
    template <typename Char, typename Traits>
96
 
    static inline void apply(std::basic_ostream<Char, Traits>& os, Point const& p)
97
 
    {
98
 
        os << Policy::apply() << "(";
99
 
        stream_coordinate<Point, 0, dimension<Point>::type::value>::apply(os, p);
100
 
        os << ")";
101
 
    }
102
 
 
103
 
    private:
104
 
        BOOST_CONCEPT_ASSERT( (concept::ConstPoint<Point>) );
105
 
};
106
 
 
107
 
/*!
108
 
\brief Stream ranges as WKT
109
 
\note policy is used to stream prefix/postfix, enabling derived classes to override this
110
 
*/
111
 
template <typename Range, typename PrefixPolicy, typename SuffixPolicy>
112
 
struct wkt_range
113
 
{
114
 
    template <typename Char, typename Traits>
115
 
    static inline void apply(std::basic_ostream<Char, Traits>& os,
116
 
                Range const& range)
117
 
    {
118
 
        typedef typename boost::range_const_iterator<Range>::type iterator_type;
119
 
 
120
 
        bool first = true;
121
 
 
122
 
        os << PrefixPolicy::apply();
123
 
 
124
 
        // TODO: check EMPTY here
125
 
 
126
 
        for (iterator_type it = boost::begin(range);
127
 
            it != boost::end(range);
128
 
            ++it)
129
 
        {
130
 
            os << (first ? "" : ",");
131
 
            stream_coordinate<point, 0, dimension<point>::type::value>::apply(os, *it);
132
 
            first = false;
133
 
        }
134
 
 
135
 
        os << SuffixPolicy::apply();
136
 
    }
137
 
 
138
 
    private:
139
 
        typedef typename boost::range_value<Range>::type point;
140
 
        BOOST_CONCEPT_ASSERT( (concept::ConstPoint<point>) );
141
 
};
142
 
 
143
 
/*!
144
 
\brief Stream sequence of points as WKT-part, e.g. (1 2),(3 4)
145
 
\note Used in polygon, all multi-geometries
146
 
*/
147
 
 
148
 
 
149
 
 
150
 
template <typename Range>
151
 
struct wkt_sequence
152
 
    : wkt_range
153
 
        <
154
 
            Range,
155
 
            opening_parenthesis,
156
 
            closing_parenthesis
157
 
        >
158
 
{};
159
 
 
160
 
 
161
 
template <typename Polygon, typename PrefixPolicy>
162
 
struct wkt_poly
163
 
{
164
 
    template <typename Char, typename Traits>
165
 
    static inline void apply(std::basic_ostream<Char, Traits>& os,
166
 
                Polygon const& poly)
167
 
    {
168
 
        typedef typename ring_type<Polygon>::type ring;
169
 
        typedef typename boost::range_const_iterator<
170
 
                    typename interior_type<Polygon>::type>::type iterator;
171
 
 
172
 
        os << PrefixPolicy::apply();
173
 
        // TODO: check EMPTY here
174
 
        os << "(";
175
 
        wkt_sequence<ring>::apply(os, exterior_ring(poly));
176
 
        for (iterator it = boost::begin(interior_rings(poly));
177
 
            it != boost::end(interior_rings(poly));
178
 
            ++it)
179
 
        {
180
 
            os << ",";
181
 
            wkt_sequence<ring>::apply(os, *it);
182
 
        }
183
 
        os << ")";
184
 
    }
185
 
 
186
 
    private:
187
 
        BOOST_CONCEPT_ASSERT( (concept::ConstPoint<typename point_type<Polygon>::type>) );
188
 
};
189
 
 
190
 
 
191
 
template <typename Box>
192
 
struct wkt_box
193
 
{
194
 
    typedef typename point_type<Box>::type point_type;
195
 
 
196
 
    template <typename Char, typename Traits>
197
 
    static inline void apply(std::basic_ostream<Char, Traits>& os,
198
 
                Box const& box)
199
 
    {
200
 
        // Convert to linear ring, then stream
201
 
        typedef linear_ring<point_type> ring_type;
202
 
        ring_type ring;
203
 
        ggl::convert(box, ring);
204
 
        os << "POLYGON(";
205
 
        wkt_sequence<ring_type>::apply(os, ring);
206
 
        os << ")";
207
 
    }
208
 
 
209
 
    private:
210
 
        BOOST_CONCEPT_ASSERT( (concept::ConstPoint<point_type>) );
211
 
 
212
 
        inline wkt_box()
213
 
        {
214
 
            // Only streaming of boxes with two dimensions is support, otherwise it is a polyhedron!
215
 
            //assert_dimension<B, 2>();
216
 
        }
217
 
};
218
 
 
219
 
}} // namespace detail::wkt
220
 
#endif // DOXYGEN_NO_DETAIL
221
 
 
222
 
 
223
 
#ifndef DOXYGEN_NO_DISPATCH
224
 
namespace dispatch {
225
 
 
226
 
template <typename Tag, typename Geometry>
227
 
struct wkt {};
228
 
 
229
 
 
230
 
template <typename Point>
231
 
struct wkt<point_tag, Point>
232
 
    : detail::wkt::wkt_point
233
 
        <
234
 
            Point,
235
 
            detail::wkt::prefix_point
236
 
        >
237
 
{};
238
 
 
239
 
 
240
 
template <typename Linestring>
241
 
struct wkt<linestring_tag, Linestring>
242
 
    : detail::wkt::wkt_range
243
 
        <
244
 
            Linestring,
245
 
            detail::wkt::prefix_linestring_par,
246
 
            detail::wkt::closing_parenthesis
247
 
        >
248
 
{};
249
 
 
250
 
 
251
 
/*!
252
 
\brief Specialization to stream a box as WKT
253
 
\details A "box" does not exist in WKT.
254
 
It is therefore streamed as a polygon
255
 
*/
256
 
template <typename Box>
257
 
struct wkt<box_tag, Box>
258
 
    : detail::wkt::wkt_box<Box>
259
 
{};
260
 
 
261
 
 
262
 
/*!
263
 
\brief Specialization to stream a ring as WKT
264
 
\details A "linear_ring" does not exist in WKT.
265
 
A linear ring is equivalent to a polygon without inner rings
266
 
It is therefore streamed as a polygon
267
 
*/
268
 
template <typename Ring>
269
 
struct wkt<ring_tag, Ring>
270
 
    : detail::wkt::wkt_range
271
 
        <
272
 
            Ring,
273
 
            detail::wkt::prefix_ring_par_par,
274
 
            detail::wkt::double_closing_parenthesis
275
 
        >
276
 
{};
277
 
 
278
 
 
279
 
/*!
280
 
\brief Specialization to stream polygon as WKT
281
 
*/
282
 
template <typename Polygon>
283
 
struct wkt<polygon_tag, Polygon>
284
 
    : detail::wkt::wkt_poly
285
 
        <
286
 
            Polygon,
287
 
            detail::wkt::prefix_polygon
288
 
        >
289
 
{};
290
 
 
291
 
 
292
 
} // namespace dispatch
293
 
#endif // DOXYGEN_NO_DISPATCH
294
 
 
295
 
 
296
 
/*!
297
 
\brief Generic geometry template manipulator class, takes corresponding output class from traits class
298
 
\ingroup wkt
299
 
\details Stream manipulator, streams geometry classes as \ref WKT streams
300
 
\par Example:
301
 
Small example showing how to use the wkt class
302
 
\dontinclude doxygen_examples.cpp
303
 
\skip example_as_wkt_point
304
 
\line {
305
 
\until }
306
 
*/
307
 
template <typename Geometry>
308
 
class wkt_manipulator
309
 
{
310
 
public:
311
 
 
312
 
    inline wkt_manipulator(Geometry const& g)
313
 
        : m_geometry(g)
314
 
    {}
315
 
 
316
 
    template <typename Char, typename Traits>
317
 
    inline friend std::basic_ostream<Char, Traits>& operator<<(
318
 
            std::basic_ostream<Char, Traits>& os,
319
 
            wkt_manipulator const& m)
320
 
    {
321
 
        dispatch::wkt
322
 
            <
323
 
                typename tag<Geometry>::type,
324
 
                Geometry
325
 
            >::apply(os, m.m_geometry);
326
 
        os.flush();
327
 
        return os;
328
 
    }
329
 
 
330
 
private:
331
 
    Geometry const& m_geometry;
332
 
};
333
 
 
334
 
/*!
335
 
\brief Main WKT-streaming function
336
 
\ingroup wkt
337
 
\par Example:
338
 
Small example showing how to use the wkt helper function
339
 
\dontinclude doxygen_examples.cpp
340
 
\skip example_as_wkt_vector
341
 
\line {
342
 
\until }
343
 
*/
344
 
template <typename Geometry>
345
 
inline wkt_manipulator<Geometry> wkt(Geometry const& geometry)
346
 
{
347
 
    return wkt_manipulator<Geometry>(geometry);
348
 
}
349
 
 
350
 
 
351
 
// Backward compatibility
352
 
template <typename Geometry>
353
 
inline wkt_manipulator<Geometry> make_wkt(Geometry const& geometry)
354
 
{
355
 
    return wkt_manipulator<Geometry>(geometry);
356
 
}
357
 
 
358
 
} // namespace ggl
359
 
 
360
 
#endif // GGL_EXTENSIONS_GIS_IO_WKT_WRITE_WKT_HPP