Chris@16
|
1 // Boost.Geometry (aka GGL, Generic Geometry Library)
|
Chris@16
|
2
|
Chris@16
|
3 // Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
|
Chris@16
|
4 // Copyright (c) 2008-2012 Bruno Lalande, Paris, France.
|
Chris@16
|
5 // Copyright (c) 2009-2012 Mateusz Loskot, London, UK.
|
Chris@16
|
6
|
Chris@16
|
7 // Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
|
Chris@16
|
8 // (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
|
Chris@16
|
9
|
Chris@16
|
10 // Use, modification and distribution is subject to the Boost Software License,
|
Chris@16
|
11 // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
|
Chris@16
|
12 // http://www.boost.org/LICENSE_1_0.txt)
|
Chris@16
|
13
|
Chris@16
|
14 #ifndef BOOST_GEOMETRY_IO_WKT_WRITE_HPP
|
Chris@16
|
15 #define BOOST_GEOMETRY_IO_WKT_WRITE_HPP
|
Chris@16
|
16
|
Chris@16
|
17 #include <ostream>
|
Chris@16
|
18 #include <string>
|
Chris@16
|
19
|
Chris@16
|
20 #include <boost/array.hpp>
|
Chris@16
|
21 #include <boost/range.hpp>
|
Chris@16
|
22 #include <boost/typeof/typeof.hpp>
|
Chris@16
|
23
|
Chris@16
|
24 #include <boost/geometry/algorithms/assign.hpp>
|
Chris@16
|
25 #include <boost/geometry/algorithms/convert.hpp>
|
Chris@16
|
26 #include <boost/geometry/algorithms/not_implemented.hpp>
|
Chris@16
|
27 #include <boost/geometry/core/exterior_ring.hpp>
|
Chris@16
|
28 #include <boost/geometry/core/interior_rings.hpp>
|
Chris@16
|
29 #include <boost/geometry/core/ring_type.hpp>
|
Chris@16
|
30
|
Chris@16
|
31 #include <boost/geometry/geometries/concepts/check.hpp>
|
Chris@16
|
32 #include <boost/geometry/geometries/ring.hpp>
|
Chris@16
|
33
|
Chris@16
|
34 #include <boost/geometry/io/wkt/detail/prefix.hpp>
|
Chris@16
|
35
|
Chris@16
|
36 #include <boost/variant/apply_visitor.hpp>
|
Chris@16
|
37 #include <boost/variant/static_visitor.hpp>
|
Chris@16
|
38 #include <boost/variant/variant_fwd.hpp>
|
Chris@16
|
39
|
Chris@16
|
40 namespace boost { namespace geometry
|
Chris@16
|
41 {
|
Chris@16
|
42
|
Chris@16
|
43 // Silence warning C4512: 'boost::geometry::wkt_manipulator<Geometry>' : assignment operator could not be generated
|
Chris@16
|
44 #if defined(_MSC_VER)
|
Chris@16
|
45 #pragma warning(push)
|
Chris@16
|
46 #pragma warning(disable : 4512)
|
Chris@16
|
47 #endif
|
Chris@16
|
48
|
Chris@16
|
49 #ifndef DOXYGEN_NO_DETAIL
|
Chris@16
|
50 namespace detail { namespace wkt
|
Chris@16
|
51 {
|
Chris@16
|
52
|
Chris@16
|
53 template <typename P, int I, int Count>
|
Chris@16
|
54 struct stream_coordinate
|
Chris@16
|
55 {
|
Chris@16
|
56 template <typename Char, typename Traits>
|
Chris@16
|
57 static inline void apply(std::basic_ostream<Char, Traits>& os, P const& p)
|
Chris@16
|
58 {
|
Chris@16
|
59 os << (I > 0 ? " " : "") << get<I>(p);
|
Chris@16
|
60 stream_coordinate<P, I + 1, Count>::apply(os, p);
|
Chris@16
|
61 }
|
Chris@16
|
62 };
|
Chris@16
|
63
|
Chris@16
|
64 template <typename P, int Count>
|
Chris@16
|
65 struct stream_coordinate<P, Count, Count>
|
Chris@16
|
66 {
|
Chris@16
|
67 template <typename Char, typename Traits>
|
Chris@16
|
68 static inline void apply(std::basic_ostream<Char, Traits>&, P const&)
|
Chris@16
|
69 {}
|
Chris@16
|
70 };
|
Chris@16
|
71
|
Chris@16
|
72 struct prefix_linestring_par
|
Chris@16
|
73 {
|
Chris@16
|
74 static inline const char* apply() { return "LINESTRING("; }
|
Chris@16
|
75 };
|
Chris@16
|
76
|
Chris@16
|
77 struct prefix_ring_par_par
|
Chris@16
|
78 {
|
Chris@16
|
79 // Note, double parentheses are intentional, indicating WKT ring begin/end
|
Chris@16
|
80 static inline const char* apply() { return "POLYGON(("; }
|
Chris@16
|
81 };
|
Chris@16
|
82
|
Chris@16
|
83 struct opening_parenthesis
|
Chris@16
|
84 {
|
Chris@16
|
85 static inline const char* apply() { return "("; }
|
Chris@16
|
86 };
|
Chris@16
|
87
|
Chris@16
|
88 struct closing_parenthesis
|
Chris@16
|
89 {
|
Chris@16
|
90 static inline const char* apply() { return ")"; }
|
Chris@16
|
91 };
|
Chris@16
|
92
|
Chris@16
|
93 struct double_closing_parenthesis
|
Chris@16
|
94 {
|
Chris@16
|
95 static inline const char* apply() { return "))"; }
|
Chris@16
|
96 };
|
Chris@16
|
97
|
Chris@16
|
98 /*!
|
Chris@16
|
99 \brief Stream points as \ref WKT
|
Chris@16
|
100 */
|
Chris@16
|
101 template <typename Point, typename Policy>
|
Chris@16
|
102 struct wkt_point
|
Chris@16
|
103 {
|
Chris@16
|
104 template <typename Char, typename Traits>
|
Chris@16
|
105 static inline void apply(std::basic_ostream<Char, Traits>& os, Point const& p)
|
Chris@16
|
106 {
|
Chris@16
|
107 os << Policy::apply() << "(";
|
Chris@16
|
108 stream_coordinate<Point, 0, dimension<Point>::type::value>::apply(os, p);
|
Chris@16
|
109 os << ")";
|
Chris@16
|
110 }
|
Chris@16
|
111 };
|
Chris@16
|
112
|
Chris@16
|
113 /*!
|
Chris@16
|
114 \brief Stream ranges as WKT
|
Chris@16
|
115 \note policy is used to stream prefix/postfix, enabling derived classes to override this
|
Chris@16
|
116 */
|
Chris@16
|
117 template <typename Range, typename PrefixPolicy, typename SuffixPolicy>
|
Chris@16
|
118 struct wkt_range
|
Chris@16
|
119 {
|
Chris@16
|
120 template <typename Char, typename Traits>
|
Chris@16
|
121 static inline void apply(std::basic_ostream<Char, Traits>& os,
|
Chris@16
|
122 Range const& range)
|
Chris@16
|
123 {
|
Chris@16
|
124 typedef typename boost::range_iterator<Range const>::type iterator_type;
|
Chris@16
|
125
|
Chris@16
|
126 bool first = true;
|
Chris@16
|
127
|
Chris@16
|
128 os << PrefixPolicy::apply();
|
Chris@16
|
129
|
Chris@16
|
130 // TODO: check EMPTY here
|
Chris@16
|
131
|
Chris@16
|
132 for (iterator_type it = boost::begin(range);
|
Chris@16
|
133 it != boost::end(range);
|
Chris@16
|
134 ++it)
|
Chris@16
|
135 {
|
Chris@16
|
136 os << (first ? "" : ",");
|
Chris@16
|
137 stream_coordinate
|
Chris@16
|
138 <
|
Chris@16
|
139 point_type, 0, dimension<point_type>::type::value
|
Chris@16
|
140 >::apply(os, *it);
|
Chris@16
|
141 first = false;
|
Chris@16
|
142 }
|
Chris@16
|
143
|
Chris@16
|
144 os << SuffixPolicy::apply();
|
Chris@16
|
145 }
|
Chris@16
|
146
|
Chris@16
|
147 private:
|
Chris@16
|
148 typedef typename boost::range_value<Range>::type point_type;
|
Chris@16
|
149 };
|
Chris@16
|
150
|
Chris@16
|
151 /*!
|
Chris@16
|
152 \brief Stream sequence of points as WKT-part, e.g. (1 2),(3 4)
|
Chris@16
|
153 \note Used in polygon, all multi-geometries
|
Chris@16
|
154 */
|
Chris@16
|
155 template <typename Range>
|
Chris@16
|
156 struct wkt_sequence
|
Chris@16
|
157 : wkt_range
|
Chris@16
|
158 <
|
Chris@16
|
159 Range,
|
Chris@16
|
160 opening_parenthesis,
|
Chris@16
|
161 closing_parenthesis
|
Chris@16
|
162 >
|
Chris@16
|
163 {};
|
Chris@16
|
164
|
Chris@16
|
165 template <typename Polygon, typename PrefixPolicy>
|
Chris@16
|
166 struct wkt_poly
|
Chris@16
|
167 {
|
Chris@16
|
168 template <typename Char, typename Traits>
|
Chris@16
|
169 static inline void apply(std::basic_ostream<Char, Traits>& os,
|
Chris@16
|
170 Polygon const& poly)
|
Chris@16
|
171 {
|
Chris@16
|
172 typedef typename ring_type<Polygon const>::type ring;
|
Chris@16
|
173
|
Chris@16
|
174 os << PrefixPolicy::apply();
|
Chris@16
|
175 // TODO: check EMPTY here
|
Chris@16
|
176 os << "(";
|
Chris@16
|
177 wkt_sequence<ring>::apply(os, exterior_ring(poly));
|
Chris@16
|
178
|
Chris@16
|
179 typename interior_return_type<Polygon const>::type rings
|
Chris@16
|
180 = interior_rings(poly);
|
Chris@16
|
181 for (BOOST_AUTO_TPL(it, boost::begin(rings)); it != boost::end(rings); ++it)
|
Chris@16
|
182 {
|
Chris@16
|
183 os << ",";
|
Chris@16
|
184 wkt_sequence<ring>::apply(os, *it);
|
Chris@16
|
185 }
|
Chris@16
|
186 os << ")";
|
Chris@16
|
187 }
|
Chris@16
|
188 };
|
Chris@16
|
189
|
Chris@16
|
190 template <typename Box>
|
Chris@16
|
191 struct wkt_box
|
Chris@16
|
192 {
|
Chris@16
|
193 typedef typename point_type<Box>::type point_type;
|
Chris@16
|
194
|
Chris@16
|
195 template <typename Char, typename Traits>
|
Chris@16
|
196 static inline void apply(std::basic_ostream<Char, Traits>& os,
|
Chris@16
|
197 Box const& box)
|
Chris@16
|
198 {
|
Chris@16
|
199 // Convert to ring, then stream
|
Chris@16
|
200 typedef model::ring<point_type> ring_type;
|
Chris@16
|
201 ring_type ring;
|
Chris@16
|
202 geometry::convert(box, ring);
|
Chris@16
|
203 os << "POLYGON(";
|
Chris@16
|
204 wkt_sequence<ring_type>::apply(os, ring);
|
Chris@16
|
205 os << ")";
|
Chris@16
|
206 }
|
Chris@16
|
207
|
Chris@16
|
208 private:
|
Chris@16
|
209
|
Chris@16
|
210 inline wkt_box()
|
Chris@16
|
211 {
|
Chris@16
|
212 // Only streaming of boxes with two dimensions is support, otherwise it is a polyhedron!
|
Chris@16
|
213 //assert_dimension<B, 2>();
|
Chris@16
|
214 }
|
Chris@16
|
215 };
|
Chris@16
|
216
|
Chris@16
|
217
|
Chris@16
|
218 template <typename Segment>
|
Chris@16
|
219 struct wkt_segment
|
Chris@16
|
220 {
|
Chris@16
|
221 typedef typename point_type<Segment>::type point_type;
|
Chris@16
|
222
|
Chris@16
|
223 template <typename Char, typename Traits>
|
Chris@16
|
224 static inline void apply(std::basic_ostream<Char, Traits>& os,
|
Chris@16
|
225 Segment const& segment)
|
Chris@16
|
226 {
|
Chris@16
|
227 // Convert to two points, then stream
|
Chris@16
|
228 typedef boost::array<point_type, 2> sequence;
|
Chris@16
|
229
|
Chris@16
|
230 sequence points;
|
Chris@16
|
231 geometry::detail::assign_point_from_index<0>(segment, points[0]);
|
Chris@16
|
232 geometry::detail::assign_point_from_index<1>(segment, points[1]);
|
Chris@16
|
233
|
Chris@16
|
234 // In Boost.Geometry a segment is represented
|
Chris@16
|
235 // in WKT-format like (for 2D): LINESTRING(x y,x y)
|
Chris@16
|
236 os << "LINESTRING";
|
Chris@16
|
237 wkt_sequence<sequence>::apply(os, points);
|
Chris@16
|
238 }
|
Chris@16
|
239
|
Chris@16
|
240 private:
|
Chris@16
|
241
|
Chris@16
|
242 inline wkt_segment()
|
Chris@16
|
243 {}
|
Chris@16
|
244 };
|
Chris@16
|
245
|
Chris@16
|
246 }} // namespace detail::wkt
|
Chris@16
|
247 #endif // DOXYGEN_NO_DETAIL
|
Chris@16
|
248
|
Chris@16
|
249 #ifndef DOXYGEN_NO_DISPATCH
|
Chris@16
|
250 namespace dispatch
|
Chris@16
|
251 {
|
Chris@16
|
252
|
Chris@16
|
253 template <typename Geometry, typename Tag = typename tag<Geometry>::type>
|
Chris@16
|
254 struct wkt: not_implemented<Tag>
|
Chris@16
|
255 {};
|
Chris@16
|
256
|
Chris@16
|
257 template <typename Point>
|
Chris@16
|
258 struct wkt<Point, point_tag>
|
Chris@16
|
259 : detail::wkt::wkt_point
|
Chris@16
|
260 <
|
Chris@16
|
261 Point,
|
Chris@16
|
262 detail::wkt::prefix_point
|
Chris@16
|
263 >
|
Chris@16
|
264 {};
|
Chris@16
|
265
|
Chris@16
|
266 template <typename Linestring>
|
Chris@16
|
267 struct wkt<Linestring, linestring_tag>
|
Chris@16
|
268 : detail::wkt::wkt_range
|
Chris@16
|
269 <
|
Chris@16
|
270 Linestring,
|
Chris@16
|
271 detail::wkt::prefix_linestring_par,
|
Chris@16
|
272 detail::wkt::closing_parenthesis
|
Chris@16
|
273 >
|
Chris@16
|
274 {};
|
Chris@16
|
275
|
Chris@16
|
276 /*!
|
Chris@16
|
277 \brief Specialization to stream a box as WKT
|
Chris@16
|
278 \details A "box" does not exist in WKT.
|
Chris@16
|
279 It is therefore streamed as a polygon
|
Chris@16
|
280 */
|
Chris@16
|
281 template <typename Box>
|
Chris@16
|
282 struct wkt<Box, box_tag>
|
Chris@16
|
283 : detail::wkt::wkt_box<Box>
|
Chris@16
|
284 {};
|
Chris@16
|
285
|
Chris@16
|
286 template <typename Segment>
|
Chris@16
|
287 struct wkt<Segment, segment_tag>
|
Chris@16
|
288 : detail::wkt::wkt_segment<Segment>
|
Chris@16
|
289 {};
|
Chris@16
|
290
|
Chris@16
|
291 /*!
|
Chris@16
|
292 \brief Specialization to stream a ring as WKT
|
Chris@16
|
293 \details A ring or "linear_ring" does not exist in WKT.
|
Chris@16
|
294 A ring is equivalent to a polygon without inner rings
|
Chris@16
|
295 It is therefore streamed as a polygon
|
Chris@16
|
296 */
|
Chris@16
|
297 template <typename Ring>
|
Chris@16
|
298 struct wkt<Ring, ring_tag>
|
Chris@16
|
299 : detail::wkt::wkt_range
|
Chris@16
|
300 <
|
Chris@16
|
301 Ring,
|
Chris@16
|
302 detail::wkt::prefix_ring_par_par,
|
Chris@16
|
303 detail::wkt::double_closing_parenthesis
|
Chris@16
|
304 >
|
Chris@16
|
305 {};
|
Chris@16
|
306
|
Chris@16
|
307 /*!
|
Chris@16
|
308 \brief Specialization to stream polygon as WKT
|
Chris@16
|
309 */
|
Chris@16
|
310 template <typename Polygon>
|
Chris@16
|
311 struct wkt<Polygon, polygon_tag>
|
Chris@16
|
312 : detail::wkt::wkt_poly
|
Chris@16
|
313 <
|
Chris@16
|
314 Polygon,
|
Chris@16
|
315 detail::wkt::prefix_polygon
|
Chris@16
|
316 >
|
Chris@16
|
317 {};
|
Chris@16
|
318
|
Chris@16
|
319
|
Chris@16
|
320 template <typename Geometry>
|
Chris@16
|
321 struct devarianted_wkt
|
Chris@16
|
322 {
|
Chris@16
|
323 template <typename OutputStream>
|
Chris@16
|
324 static inline void apply(OutputStream& os, Geometry const& geometry)
|
Chris@16
|
325 {
|
Chris@16
|
326 wkt<Geometry>::apply(os, geometry);
|
Chris@16
|
327 }
|
Chris@16
|
328 };
|
Chris@16
|
329
|
Chris@16
|
330 template <BOOST_VARIANT_ENUM_PARAMS(typename T)>
|
Chris@16
|
331 struct devarianted_wkt<variant<BOOST_VARIANT_ENUM_PARAMS(T)> >
|
Chris@16
|
332 {
|
Chris@16
|
333 template <typename OutputStream>
|
Chris@16
|
334 struct visitor: static_visitor<void>
|
Chris@16
|
335 {
|
Chris@16
|
336 OutputStream& m_os;
|
Chris@16
|
337
|
Chris@16
|
338 visitor(OutputStream& os)
|
Chris@16
|
339 : m_os(os)
|
Chris@16
|
340 {}
|
Chris@16
|
341
|
Chris@16
|
342 template <typename Geometry>
|
Chris@16
|
343 inline void operator()(Geometry const& geometry) const
|
Chris@16
|
344 {
|
Chris@16
|
345 devarianted_wkt<Geometry>::apply(m_os, geometry);
|
Chris@16
|
346 }
|
Chris@16
|
347 };
|
Chris@16
|
348
|
Chris@16
|
349 template <typename OutputStream>
|
Chris@16
|
350 static inline void apply(
|
Chris@16
|
351 OutputStream& os,
|
Chris@16
|
352 variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& geometry
|
Chris@16
|
353 )
|
Chris@16
|
354 {
|
Chris@16
|
355 apply_visitor(visitor<OutputStream>(os), geometry);
|
Chris@16
|
356 }
|
Chris@16
|
357 };
|
Chris@16
|
358
|
Chris@16
|
359
|
Chris@16
|
360 } // namespace dispatch
|
Chris@16
|
361 #endif // DOXYGEN_NO_DISPATCH
|
Chris@16
|
362
|
Chris@16
|
363 /*!
|
Chris@16
|
364 \brief Generic geometry template manipulator class, takes corresponding output class from traits class
|
Chris@16
|
365 \ingroup wkt
|
Chris@16
|
366 \details Stream manipulator, streams geometry classes as \ref WKT streams
|
Chris@16
|
367 \par Example:
|
Chris@16
|
368 Small example showing how to use the wkt class
|
Chris@16
|
369 \dontinclude doxygen_1.cpp
|
Chris@16
|
370 \skip example_as_wkt_point
|
Chris@16
|
371 \line {
|
Chris@16
|
372 \until }
|
Chris@16
|
373 */
|
Chris@16
|
374 template <typename Geometry>
|
Chris@16
|
375 class wkt_manipulator
|
Chris@16
|
376 {
|
Chris@16
|
377 public:
|
Chris@16
|
378
|
Chris@16
|
379 inline wkt_manipulator(Geometry const& g)
|
Chris@16
|
380 : m_geometry(g)
|
Chris@16
|
381 {}
|
Chris@16
|
382
|
Chris@16
|
383 template <typename Char, typename Traits>
|
Chris@16
|
384 inline friend std::basic_ostream<Char, Traits>& operator<<(
|
Chris@16
|
385 std::basic_ostream<Char, Traits>& os,
|
Chris@16
|
386 wkt_manipulator const& m)
|
Chris@16
|
387 {
|
Chris@16
|
388 dispatch::devarianted_wkt<Geometry>::apply(os, m.m_geometry);
|
Chris@16
|
389 os.flush();
|
Chris@16
|
390 return os;
|
Chris@16
|
391 }
|
Chris@16
|
392
|
Chris@16
|
393 private:
|
Chris@16
|
394 Geometry const& m_geometry;
|
Chris@16
|
395 };
|
Chris@16
|
396
|
Chris@16
|
397 /*!
|
Chris@16
|
398 \brief Main WKT-streaming function
|
Chris@16
|
399 \ingroup wkt
|
Chris@16
|
400 \par Example:
|
Chris@16
|
401 Small example showing how to use the wkt helper function
|
Chris@16
|
402 \dontinclude doxygen_1.cpp
|
Chris@16
|
403 \skip example_as_wkt_vector
|
Chris@16
|
404 \line {
|
Chris@16
|
405 \until }
|
Chris@16
|
406 */
|
Chris@16
|
407 template <typename Geometry>
|
Chris@16
|
408 inline wkt_manipulator<Geometry> wkt(Geometry const& geometry)
|
Chris@16
|
409 {
|
Chris@16
|
410 concept::check<Geometry const>();
|
Chris@16
|
411
|
Chris@16
|
412 return wkt_manipulator<Geometry>(geometry);
|
Chris@16
|
413 }
|
Chris@16
|
414
|
Chris@16
|
415 #if defined(_MSC_VER)
|
Chris@16
|
416 #pragma warning(pop)
|
Chris@16
|
417 #endif
|
Chris@16
|
418
|
Chris@16
|
419 }} // namespace boost::geometry
|
Chris@16
|
420
|
Chris@16
|
421 #endif // BOOST_GEOMETRY_IO_WKT_WRITE_HPP
|