]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
1 | // Boost.Geometry (aka GGL, Generic Geometry Library) |
2 | ||
b32b8144 FG |
3 | // Copyright (c) 2007-2017 Barend Gehrels, Amsterdam, the Netherlands. |
4 | // Copyright (c) 2008-2017 Bruno Lalande, Paris, France. | |
5 | // Copyright (c) 2009-2017 Mateusz Loskot, London, UK. | |
6 | // Copyright (c) 2014-2017 Adam Wulkiewicz, Lodz, Poland. | |
7c673cae FG |
7 | |
8 | // This file was modified by Oracle on 2015. | |
b32b8144 | 9 | // Modifications copyright (c) 2015-2017, Oracle and/or its affiliates. |
7c673cae FG |
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> | |
b32b8144 | 114 | static inline void apply(std::basic_ostream<Char, Traits>& os, Point const& p, bool) |
7c673cae FG |
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 | */ | |
b32b8144 FG |
126 | template |
127 | < | |
128 | typename Range, | |
129 | bool ForceClosurePossible, | |
130 | typename PrefixPolicy, | |
131 | typename SuffixPolicy | |
132 | > | |
7c673cae FG |
133 | struct wkt_range |
134 | { | |
135 | template <typename Char, typename Traits> | |
136 | static inline void apply(std::basic_ostream<Char, Traits>& os, | |
b32b8144 | 137 | Range const& range, bool force_closure = ForceClosurePossible) |
7c673cae FG |
138 | { |
139 | typedef typename boost::range_iterator<Range const>::type iterator_type; | |
140 | ||
141 | typedef stream_coordinate | |
142 | < | |
143 | point_type, 0, dimension<point_type>::type::value | |
144 | > stream_type; | |
145 | ||
146 | bool first = true; | |
147 | ||
148 | os << PrefixPolicy::apply(); | |
149 | ||
150 | // TODO: check EMPTY here | |
151 | ||
152 | iterator_type begin = boost::begin(range); | |
153 | iterator_type end = boost::end(range); | |
154 | for (iterator_type it = begin; it != end; ++it) | |
155 | { | |
156 | os << (first ? "" : ","); | |
157 | stream_type::apply(os, *it); | |
158 | first = false; | |
159 | } | |
160 | ||
161 | // optionally, close range to ring by repeating the first point | |
b32b8144 FG |
162 | if (ForceClosurePossible |
163 | && force_closure | |
7c673cae FG |
164 | && boost::size(range) > 1 |
165 | && detail::disjoint::disjoint_point_point(*begin, *(end - 1))) | |
166 | { | |
167 | os << ","; | |
168 | stream_type::apply(os, *begin); | |
169 | } | |
170 | ||
171 | os << SuffixPolicy::apply(); | |
172 | } | |
173 | ||
7c673cae FG |
174 | |
175 | private: | |
176 | typedef typename boost::range_value<Range>::type point_type; | |
177 | }; | |
178 | ||
179 | /*! | |
180 | \brief Stream sequence of points as WKT-part, e.g. (1 2),(3 4) | |
181 | \note Used in polygon, all multi-geometries | |
182 | */ | |
b32b8144 | 183 | template <typename Range, bool ForceClosurePossible = true> |
7c673cae FG |
184 | struct wkt_sequence |
185 | : wkt_range | |
186 | < | |
187 | Range, | |
b32b8144 | 188 | ForceClosurePossible, |
7c673cae FG |
189 | opening_parenthesis, |
190 | closing_parenthesis | |
191 | > | |
192 | {}; | |
193 | ||
194 | template <typename Polygon, typename PrefixPolicy> | |
195 | struct wkt_poly | |
196 | { | |
197 | template <typename Char, typename Traits> | |
198 | static inline void apply(std::basic_ostream<Char, Traits>& os, | |
b32b8144 | 199 | Polygon const& poly, bool force_closure) |
7c673cae FG |
200 | { |
201 | typedef typename ring_type<Polygon const>::type ring; | |
7c673cae FG |
202 | |
203 | os << PrefixPolicy::apply(); | |
204 | // TODO: check EMPTY here | |
205 | os << "("; | |
b32b8144 | 206 | wkt_sequence<ring>::apply(os, exterior_ring(poly), force_closure); |
7c673cae FG |
207 | |
208 | typename interior_return_type<Polygon const>::type | |
209 | rings = interior_rings(poly); | |
210 | for (typename detail::interior_iterator<Polygon const>::type | |
211 | it = boost::begin(rings); it != boost::end(rings); ++it) | |
212 | { | |
213 | os << ","; | |
b32b8144 | 214 | wkt_sequence<ring>::apply(os, *it, force_closure); |
7c673cae FG |
215 | } |
216 | os << ")"; | |
217 | } | |
b32b8144 | 218 | |
7c673cae FG |
219 | }; |
220 | ||
221 | template <typename Multi, typename StreamPolicy, typename PrefixPolicy> | |
222 | struct wkt_multi | |
223 | { | |
224 | template <typename Char, typename Traits> | |
225 | static inline void apply(std::basic_ostream<Char, Traits>& os, | |
b32b8144 | 226 | Multi const& geometry, bool force_closure) |
7c673cae FG |
227 | { |
228 | os << PrefixPolicy::apply(); | |
229 | // TODO: check EMPTY here | |
230 | os << "("; | |
231 | ||
232 | for (typename boost::range_iterator<Multi const>::type | |
233 | it = boost::begin(geometry); | |
234 | it != boost::end(geometry); | |
235 | ++it) | |
236 | { | |
237 | if (it != boost::begin(geometry)) | |
238 | { | |
239 | os << ","; | |
240 | } | |
b32b8144 | 241 | StreamPolicy::apply(os, *it, force_closure); |
7c673cae FG |
242 | } |
243 | ||
244 | os << ")"; | |
245 | } | |
246 | }; | |
247 | ||
248 | template <typename Box> | |
249 | struct wkt_box | |
250 | { | |
251 | typedef typename point_type<Box>::type point_type; | |
252 | ||
253 | template <typename Char, typename Traits> | |
254 | static inline void apply(std::basic_ostream<Char, Traits>& os, | |
b32b8144 | 255 | Box const& box, bool force_closure) |
7c673cae | 256 | { |
b32b8144 FG |
257 | // Convert to a clockwire ring, then stream. |
258 | // Never close it based on last point (box might be empty and | |
259 | // that should result in POLYGON((0 0,0 0,0 0,0 0, ...)) ) | |
260 | if (force_closure) | |
261 | { | |
262 | do_apply<model::ring<point_type, true, true> >(os, box); | |
263 | } | |
264 | else | |
265 | { | |
266 | do_apply<model::ring<point_type, true, false> >(os, box); | |
267 | } | |
7c673cae FG |
268 | } |
269 | ||
270 | private: | |
271 | ||
272 | inline wkt_box() | |
273 | { | |
274 | // Only streaming of boxes with two dimensions is support, otherwise it is a polyhedron! | |
275 | //assert_dimension<B, 2>(); | |
276 | } | |
b32b8144 FG |
277 | |
278 | template <typename RingType, typename Char, typename Traits> | |
279 | static inline void do_apply(std::basic_ostream<Char, Traits>& os, | |
280 | Box const& box) | |
281 | { | |
282 | RingType ring; | |
283 | geometry::convert(box, ring); | |
284 | os << "POLYGON("; | |
285 | wkt_sequence<RingType, false>::apply(os, ring); | |
286 | os << ")"; | |
287 | } | |
288 | ||
7c673cae FG |
289 | }; |
290 | ||
291 | ||
292 | template <typename Segment> | |
293 | struct wkt_segment | |
294 | { | |
295 | typedef typename point_type<Segment>::type point_type; | |
296 | ||
297 | template <typename Char, typename Traits> | |
298 | static inline void apply(std::basic_ostream<Char, Traits>& os, | |
b32b8144 | 299 | Segment const& segment, bool) |
7c673cae FG |
300 | { |
301 | // Convert to two points, then stream | |
302 | typedef boost::array<point_type, 2> sequence; | |
303 | ||
304 | sequence points; | |
305 | geometry::detail::assign_point_from_index<0>(segment, points[0]); | |
306 | geometry::detail::assign_point_from_index<1>(segment, points[1]); | |
307 | ||
308 | // In Boost.Geometry a segment is represented | |
309 | // in WKT-format like (for 2D): LINESTRING(x y,x y) | |
310 | os << "LINESTRING"; | |
b32b8144 | 311 | wkt_sequence<sequence, false>::apply(os, points); |
7c673cae FG |
312 | } |
313 | ||
314 | private: | |
315 | ||
316 | inline wkt_segment() | |
317 | {} | |
318 | }; | |
319 | ||
320 | }} // namespace detail::wkt | |
321 | #endif // DOXYGEN_NO_DETAIL | |
322 | ||
323 | #ifndef DOXYGEN_NO_DISPATCH | |
324 | namespace dispatch | |
325 | { | |
326 | ||
327 | template <typename Geometry, typename Tag = typename tag<Geometry>::type> | |
328 | struct wkt: not_implemented<Tag> | |
329 | {}; | |
330 | ||
331 | template <typename Point> | |
332 | struct wkt<Point, point_tag> | |
333 | : detail::wkt::wkt_point | |
334 | < | |
335 | Point, | |
336 | detail::wkt::prefix_point | |
337 | > | |
338 | {}; | |
339 | ||
340 | template <typename Linestring> | |
341 | struct wkt<Linestring, linestring_tag> | |
342 | : detail::wkt::wkt_range | |
343 | < | |
344 | Linestring, | |
b32b8144 | 345 | false, |
7c673cae FG |
346 | detail::wkt::prefix_linestring_par, |
347 | detail::wkt::closing_parenthesis | |
348 | > | |
349 | {}; | |
350 | ||
351 | /*! | |
352 | \brief Specialization to stream a box as WKT | |
353 | \details A "box" does not exist in WKT. | |
354 | It is therefore streamed as a polygon | |
355 | */ | |
356 | template <typename Box> | |
357 | struct wkt<Box, box_tag> | |
358 | : detail::wkt::wkt_box<Box> | |
359 | {}; | |
360 | ||
361 | template <typename Segment> | |
362 | struct wkt<Segment, segment_tag> | |
363 | : detail::wkt::wkt_segment<Segment> | |
364 | {}; | |
365 | ||
366 | /*! | |
367 | \brief Specialization to stream a ring as WKT | |
368 | \details A ring or "linear_ring" does not exist in WKT. | |
369 | A ring is equivalent to a polygon without inner rings | |
370 | It is therefore streamed as a polygon | |
371 | */ | |
372 | template <typename Ring> | |
373 | struct wkt<Ring, ring_tag> | |
374 | : detail::wkt::wkt_range | |
375 | < | |
376 | Ring, | |
b32b8144 | 377 | true, |
7c673cae FG |
378 | detail::wkt::prefix_ring_par_par, |
379 | detail::wkt::double_closing_parenthesis | |
380 | > | |
381 | {}; | |
382 | ||
383 | /*! | |
384 | \brief Specialization to stream polygon as WKT | |
385 | */ | |
386 | template <typename Polygon> | |
387 | struct wkt<Polygon, polygon_tag> | |
388 | : detail::wkt::wkt_poly | |
389 | < | |
390 | Polygon, | |
391 | detail::wkt::prefix_polygon | |
392 | > | |
393 | {}; | |
394 | ||
395 | template <typename Multi> | |
396 | struct wkt<Multi, multi_point_tag> | |
397 | : detail::wkt::wkt_multi | |
398 | < | |
399 | Multi, | |
400 | detail::wkt::wkt_point | |
401 | < | |
402 | typename boost::range_value<Multi>::type, | |
403 | detail::wkt::prefix_null | |
404 | >, | |
405 | detail::wkt::prefix_multipoint | |
406 | > | |
407 | {}; | |
408 | ||
409 | template <typename Multi> | |
410 | struct wkt<Multi, multi_linestring_tag> | |
411 | : detail::wkt::wkt_multi | |
412 | < | |
413 | Multi, | |
414 | detail::wkt::wkt_sequence | |
415 | < | |
b32b8144 FG |
416 | typename boost::range_value<Multi>::type, |
417 | false | |
7c673cae FG |
418 | >, |
419 | detail::wkt::prefix_multilinestring | |
420 | > | |
421 | {}; | |
422 | ||
423 | template <typename Multi> | |
424 | struct wkt<Multi, multi_polygon_tag> | |
425 | : detail::wkt::wkt_multi | |
426 | < | |
427 | Multi, | |
428 | detail::wkt::wkt_poly | |
429 | < | |
430 | typename boost::range_value<Multi>::type, | |
431 | detail::wkt::prefix_null | |
432 | >, | |
433 | detail::wkt::prefix_multipolygon | |
434 | > | |
435 | {}; | |
436 | ||
437 | ||
438 | template <typename Geometry> | |
439 | struct devarianted_wkt | |
440 | { | |
441 | template <typename OutputStream> | |
b32b8144 FG |
442 | static inline void apply(OutputStream& os, Geometry const& geometry, |
443 | bool force_closure) | |
7c673cae | 444 | { |
b32b8144 | 445 | wkt<Geometry>::apply(os, geometry, force_closure); |
7c673cae FG |
446 | } |
447 | }; | |
448 | ||
449 | template <BOOST_VARIANT_ENUM_PARAMS(typename T)> | |
450 | struct devarianted_wkt<variant<BOOST_VARIANT_ENUM_PARAMS(T)> > | |
451 | { | |
452 | template <typename OutputStream> | |
453 | struct visitor: static_visitor<void> | |
454 | { | |
455 | OutputStream& m_os; | |
b32b8144 | 456 | bool m_force_closure; |
7c673cae | 457 | |
b32b8144 | 458 | visitor(OutputStream& os, bool force_closure) |
7c673cae | 459 | : m_os(os) |
b32b8144 | 460 | , m_force_closure(force_closure) |
7c673cae FG |
461 | {} |
462 | ||
463 | template <typename Geometry> | |
464 | inline void operator()(Geometry const& geometry) const | |
465 | { | |
b32b8144 | 466 | devarianted_wkt<Geometry>::apply(m_os, geometry, m_force_closure); |
7c673cae FG |
467 | } |
468 | }; | |
469 | ||
470 | template <typename OutputStream> | |
471 | static inline void apply( | |
472 | OutputStream& os, | |
b32b8144 FG |
473 | variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& geometry, |
474 | bool force_closure) | |
7c673cae | 475 | { |
b32b8144 | 476 | boost::apply_visitor(visitor<OutputStream>(os, force_closure), geometry); |
7c673cae FG |
477 | } |
478 | }; | |
479 | ||
480 | ||
481 | } // namespace dispatch | |
482 | #endif // DOXYGEN_NO_DISPATCH | |
483 | ||
484 | /*! | |
485 | \brief Generic geometry template manipulator class, takes corresponding output class from traits class | |
486 | \ingroup wkt | |
487 | \details Stream manipulator, streams geometry classes as \ref WKT streams | |
488 | \par Example: | |
489 | Small example showing how to use the wkt class | |
490 | \dontinclude doxygen_1.cpp | |
491 | \skip example_as_wkt_point | |
492 | \line { | |
493 | \until } | |
494 | */ | |
495 | template <typename Geometry> | |
496 | class wkt_manipulator | |
497 | { | |
b32b8144 FG |
498 | static const bool is_ring = boost::is_same<typename tag<Geometry>::type, ring_tag>::value; |
499 | ||
7c673cae FG |
500 | public: |
501 | ||
b32b8144 FG |
502 | // Boost.Geometry, by default, closes polygons explictly, but not rings |
503 | // NOTE: this might change in the future! | |
504 | inline wkt_manipulator(Geometry const& g, | |
505 | bool force_closure = ! is_ring) | |
7c673cae | 506 | : m_geometry(g) |
b32b8144 | 507 | , m_force_closure(force_closure) |
7c673cae FG |
508 | {} |
509 | ||
510 | template <typename Char, typename Traits> | |
511 | inline friend std::basic_ostream<Char, Traits>& operator<<( | |
512 | std::basic_ostream<Char, Traits>& os, | |
513 | wkt_manipulator const& m) | |
514 | { | |
b32b8144 | 515 | dispatch::devarianted_wkt<Geometry>::apply(os, m.m_geometry, m.m_force_closure); |
7c673cae FG |
516 | os.flush(); |
517 | return os; | |
518 | } | |
519 | ||
520 | private: | |
521 | Geometry const& m_geometry; | |
b32b8144 | 522 | bool m_force_closure; |
7c673cae FG |
523 | }; |
524 | ||
525 | /*! | |
526 | \brief Main WKT-streaming function | |
527 | \tparam Geometry \tparam_geometry | |
528 | \param geometry \param_geometry | |
529 | \ingroup wkt | |
530 | \qbk{[include reference/io/wkt.qbk]} | |
531 | */ | |
532 | template <typename Geometry> | |
533 | inline wkt_manipulator<Geometry> wkt(Geometry const& geometry) | |
534 | { | |
535 | concepts::check<Geometry const>(); | |
536 | ||
537 | return wkt_manipulator<Geometry>(geometry); | |
538 | } | |
539 | ||
540 | #if defined(_MSC_VER) | |
541 | #pragma warning(pop) | |
542 | #endif | |
543 | ||
544 | }} // namespace boost::geometry | |
545 | ||
546 | #endif // BOOST_GEOMETRY_IO_WKT_WRITE_HPP |