Imported Upstream version 1.57.0
[platform/upstream/boost.git] / boost / geometry / io / wkt / write.hpp
index a3e3173..6c1a2e1 100644 (file)
@@ -3,6 +3,7 @@
 // Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
 // Copyright (c) 2008-2012 Bruno Lalande, Paris, France.
 // Copyright (c) 2009-2012 Mateusz Loskot, London, UK.
+// Copyright (c) 2014 Adam Wulkiewicz, Lodz, Poland.
 
 // Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
 // (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
 #include <string>
 
 #include <boost/array.hpp>
-#include <boost/concept/assert.hpp>
 #include <boost/range.hpp>
-#include <boost/typeof/typeof.hpp>
+#include <boost/variant/apply_visitor.hpp>
+#include <boost/variant/static_visitor.hpp>
+#include <boost/variant/variant_fwd.hpp>
 
+#include <boost/geometry/algorithms/detail/interior_iterator.hpp>
 #include <boost/geometry/algorithms/assign.hpp>
 #include <boost/geometry/algorithms/convert.hpp>
+#include <boost/geometry/algorithms/disjoint.hpp>
+#include <boost/geometry/algorithms/not_implemented.hpp>
 #include <boost/geometry/core/exterior_ring.hpp>
 #include <boost/geometry/core/interior_rings.hpp>
 #include <boost/geometry/core/ring_type.hpp>
+#include <boost/geometry/core/tags.hpp>
 
 #include <boost/geometry/geometries/concepts/check.hpp>
 #include <boost/geometry/geometries/ring.hpp>
 
 #include <boost/geometry/io/wkt/detail/prefix.hpp>
 
+
 namespace boost { namespace geometry
 {
 
+// Silence warning C4512: 'boost::geometry::wkt_manipulator<Geometry>' : assignment operator could not be generated
+#if defined(_MSC_VER)
+#pragma warning(push)  
+#pragma warning(disable : 4512)  
+#endif
+
 #ifndef DOXYGEN_NO_DETAIL
 namespace detail { namespace wkt
 {
@@ -109,31 +122,49 @@ struct wkt_range
 {
     template <typename Char, typename Traits>
     static inline void apply(std::basic_ostream<Char, Traits>& os,
-                Range const& range)
+                Range const& range, bool force_closed)
     {
         typedef typename boost::range_iterator<Range const>::type iterator_type;
 
+        typedef stream_coordinate
+            <
+                point_type, 0, dimension<point_type>::type::value
+            > stream_type;
+
         bool first = true;
 
         os << PrefixPolicy::apply();
 
         // TODO: check EMPTY here
 
-        for (iterator_type it = boost::begin(range);
-            it != boost::end(range);
-            ++it)
+        iterator_type begin = boost::begin(range);
+        iterator_type end = boost::end(range);
+        for (iterator_type it = begin; it != end; ++it)
         {
             os << (first ? "" : ",");
-            stream_coordinate
-                <
-                    point_type, 0, dimension<point_type>::type::value
-                >::apply(os, *it);
+            stream_type::apply(os, *it);
             first = false;
         }
 
+        // optionally, close range to ring by repeating the first point
+        if (force_closed 
+            && boost::size(range) > 1
+            && geometry::disjoint(*begin, *(end - 1)))
+        {
+            os << ",";
+            stream_type::apply(os, *begin);
+        }
+
         os << SuffixPolicy::apply();
     }
 
+    template <typename Char, typename Traits>
+    static inline void apply(std::basic_ostream<Char, Traits>& os,
+                Range const& range)
+    {
+        apply(os, range, false);
+    }
+
 private:
     typedef typename boost::range_value<Range>::type point_type;
 };
@@ -160,23 +191,52 @@ struct wkt_poly
                 Polygon const& poly)
     {
         typedef typename ring_type<Polygon const>::type ring;
+        bool const force_closed = true;
 
         os << PrefixPolicy::apply();
         // TODO: check EMPTY here
         os << "(";
-        wkt_sequence<ring>::apply(os, exterior_ring(poly));
+        wkt_sequence<ring>::apply(os, exterior_ring(poly), force_closed);
 
-        typename interior_return_type<Polygon const>::type rings
-                    = interior_rings(poly);
-        for (BOOST_AUTO_TPL(it, boost::begin(rings)); it != boost::end(rings); ++it)
+        typename interior_return_type<Polygon const>::type
+            rings = interior_rings(poly);
+        for (typename detail::interior_iterator<Polygon const>::type
+                it = boost::begin(rings); it != boost::end(rings); ++it)
         {
             os << ",";
-            wkt_sequence<ring>::apply(os, *it);
+            wkt_sequence<ring>::apply(os, *it, force_closed);
         }
         os << ")";
     }
 };
 
+template <typename Multi, typename StreamPolicy, typename PrefixPolicy>
+struct wkt_multi
+{
+    template <typename Char, typename Traits>
+    static inline void apply(std::basic_ostream<Char, Traits>& os,
+                Multi const& geometry)
+    {
+        os << PrefixPolicy::apply();
+        // TODO: check EMPTY here
+        os << "(";
+
+        for (typename boost::range_iterator<Multi const>::type
+                    it = boost::begin(geometry);
+            it != boost::end(geometry);
+            ++it)
+        {
+            if (it != boost::begin(geometry))
+            {
+                os << ",";
+            }
+            StreamPolicy::apply(os, *it);
+        }
+
+        os << ")";
+    }
+};
+
 template <typename Box>
 struct wkt_box
 {
@@ -240,18 +300,12 @@ struct wkt_segment
 namespace dispatch
 {
 
-template <typename Tag, typename Geometry>
-struct wkt
-{
-   BOOST_MPL_ASSERT_MSG
-        (
-            false, NOT_YET_IMPLEMENTED_FOR_THIS_GEOMETRY_TYPE
-            , (types<Geometry>)
-        );
-};
+template <typename Geometry, typename Tag = typename tag<Geometry>::type>
+struct wkt: not_implemented<Tag>
+{};
 
 template <typename Point>
-struct wkt<point_tag, Point>
+struct wkt<Point, point_tag>
     : detail::wkt::wkt_point
         <
             Point,
@@ -260,7 +314,7 @@ struct wkt<point_tag, Point>
 {};
 
 template <typename Linestring>
-struct wkt<linestring_tag, Linestring>
+struct wkt<Linestring, linestring_tag>
     : detail::wkt::wkt_range
         <
             Linestring,
@@ -275,12 +329,12 @@ struct wkt<linestring_tag, Linestring>
 It is therefore streamed as a polygon
 */
 template <typename Box>
-struct wkt<box_tag, Box>
+struct wkt<Box, box_tag>
     : detail::wkt::wkt_box<Box>
 {};
 
 template <typename Segment>
-struct wkt<segment_tag, Segment>
+struct wkt<Segment, segment_tag>
     : detail::wkt::wkt_segment<Segment>
 {};
 
@@ -291,7 +345,7 @@ A ring is equivalent to a polygon without inner rings
 It is therefore streamed as a polygon
 */
 template <typename Ring>
-struct wkt<ring_tag, Ring>
+struct wkt<Ring, ring_tag>
     : detail::wkt::wkt_range
         <
             Ring,
@@ -304,7 +358,7 @@ struct wkt<ring_tag, Ring>
 \brief Specialization to stream polygon as WKT
 */
 template <typename Polygon>
-struct wkt<polygon_tag, Polygon>
+struct wkt<Polygon, polygon_tag>
     : detail::wkt::wkt_poly
         <
             Polygon,
@@ -312,6 +366,88 @@ struct wkt<polygon_tag, Polygon>
         >
 {};
 
+template <typename Multi>
+struct wkt<Multi, multi_point_tag>
+    : detail::wkt::wkt_multi
+        <
+            Multi,
+            detail::wkt::wkt_point
+                <
+                    typename boost::range_value<Multi>::type,
+                    detail::wkt::prefix_null
+                >,
+            detail::wkt::prefix_multipoint
+        >
+{};
+
+template <typename Multi>
+struct wkt<Multi, multi_linestring_tag>
+    : detail::wkt::wkt_multi
+        <
+            Multi,
+            detail::wkt::wkt_sequence
+                <
+                    typename boost::range_value<Multi>::type
+                >,
+            detail::wkt::prefix_multilinestring
+        >
+{};
+
+template <typename Multi>
+struct wkt<Multi, multi_polygon_tag>
+    : detail::wkt::wkt_multi
+        <
+            Multi,
+            detail::wkt::wkt_poly
+                <
+                    typename boost::range_value<Multi>::type,
+                    detail::wkt::prefix_null
+                >,
+            detail::wkt::prefix_multipolygon
+        >
+{};
+
+
+template <typename Geometry>
+struct devarianted_wkt
+{
+    template <typename OutputStream>
+    static inline void apply(OutputStream& os, Geometry const& geometry)
+    {
+        wkt<Geometry>::apply(os, geometry);
+    }
+};
+
+template <BOOST_VARIANT_ENUM_PARAMS(typename T)>
+struct devarianted_wkt<variant<BOOST_VARIANT_ENUM_PARAMS(T)> >
+{
+    template <typename OutputStream>
+    struct visitor: static_visitor<void>
+    {
+        OutputStream& m_os;
+
+        visitor(OutputStream& os)
+            : m_os(os)
+        {}
+
+        template <typename Geometry>
+        inline void operator()(Geometry const& geometry) const
+        {
+            devarianted_wkt<Geometry>::apply(m_os, geometry);
+        }
+    };
+
+    template <typename OutputStream>
+    static inline void apply(
+        OutputStream& os,
+        variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& geometry
+    )
+    {
+        apply_visitor(visitor<OutputStream>(os), geometry);
+    }
+};
+
+
 } // namespace dispatch
 #endif // DOXYGEN_NO_DISPATCH
 
@@ -340,11 +476,7 @@ public:
             std::basic_ostream<Char, Traits>& os,
             wkt_manipulator const& m)
     {
-        dispatch::wkt
-            <
-                typename tag<Geometry>::type,
-                Geometry
-            >::apply(os, m.m_geometry);
+        dispatch::devarianted_wkt<Geometry>::apply(os, m.m_geometry);
         os.flush();
         return os;
     }
@@ -355,13 +487,10 @@ private:
 
 /*!
 \brief Main WKT-streaming function
+\tparam Geometry \tparam_geometry
+\param geometry \param_geometry
 \ingroup wkt
-\par Example:
-Small example showing how to use the wkt helper function
-\dontinclude doxygen_1.cpp
-\skip example_as_wkt_vector
-\line {
-\until }
+\qbk{[include reference/io/wkt.qbk]}
 */
 template <typename Geometry>
 inline wkt_manipulator<Geometry> wkt(Geometry const& geometry)
@@ -371,6 +500,10 @@ inline wkt_manipulator<Geometry> wkt(Geometry const& geometry)
     return wkt_manipulator<Geometry>(geometry);
 }
 
+#if defined(_MSC_VER)
+#pragma warning(pop)  
+#endif
+
 }} // namespace boost::geometry
 
 #endif // BOOST_GEOMETRY_IO_WKT_WRITE_HPP