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