summaryrefslogtreecommitdiff
path: root/boost/geometry/io
diff options
context:
space:
mode:
Diffstat (limited to 'boost/geometry/io')
-rw-r--r--boost/geometry/io/dsv/write.hpp64
-rw-r--r--boost/geometry/io/svg/svg_mapper.hpp390
-rw-r--r--boost/geometry/io/svg/write_svg.hpp279
-rw-r--r--boost/geometry/io/svg/write_svg_multi.hpp78
-rw-r--r--boost/geometry/io/wkt/detail/prefix.hpp21
-rw-r--r--boost/geometry/io/wkt/detail/wkt_multi.hpp3
-rw-r--r--boost/geometry/io/wkt/read.hpp169
-rw-r--r--boost/geometry/io/wkt/stream.hpp6
-rw-r--r--boost/geometry/io/wkt/write.hpp215
9 files changed, 1149 insertions, 76 deletions
diff --git a/boost/geometry/io/dsv/write.hpp b/boost/geometry/io/dsv/write.hpp
index 62929f8073..f39a2489ad 100644
--- a/boost/geometry/io/dsv/write.hpp
+++ b/boost/geometry/io/dsv/write.hpp
@@ -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.
@@ -20,12 +21,14 @@
#include <boost/concept_check.hpp>
#include <boost/range.hpp>
-#include <boost/typeof/typeof.hpp>
+
+#include <boost/geometry/algorithms/detail/interior_iterator.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/tag_cast.hpp>
+#include <boost/geometry/core/tags.hpp>
#include <boost/geometry/geometries/concepts/check.hpp>
@@ -209,9 +212,10 @@ struct dsv_poly
dsv_range<ring>::apply(os, exterior_ring(poly), settings);
- 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 << settings.list_separator;
dsv_range<ring>::apply(os, *it, settings);
@@ -339,9 +343,61 @@ private:
dsv_settings m_settings;
};
+
+template <typename MultiGeometry>
+struct dsv_multi
+{
+ typedef dispatch::dsv
+ <
+ typename single_tag_of
+ <
+ typename tag<MultiGeometry>::type
+ >::type,
+ typename boost::range_value<MultiGeometry>::type
+ > dispatch_one;
+
+ typedef typename boost::range_iterator
+ <
+ MultiGeometry const
+ >::type iterator;
+
+
+ template <typename Char, typename Traits>
+ static inline void apply(std::basic_ostream<Char, Traits>& os,
+ MultiGeometry const& multi,
+ dsv_settings const& settings)
+ {
+ os << settings.list_open;
+
+ bool first = true;
+ for(iterator it = boost::begin(multi);
+ it != boost::end(multi);
+ ++it, first = false)
+ {
+ os << (first ? "" : settings.list_separator);
+ dispatch_one::apply(os, *it, settings);
+ }
+ os << settings.list_close;
+ }
+};
+
}} // namespace detail::dsv
#endif // DOXYGEN_NO_DETAIL
+// TODO: The alternative to this could be a forward declaration of dispatch::dsv<>
+// or braking the code into the interface and implementation part
+#ifndef DOXYGEN_NO_DISPATCH
+namespace dispatch
+{
+
+template <typename Geometry>
+struct dsv<multi_tag, Geometry>
+ : detail::dsv::dsv_multi<Geometry>
+{};
+
+} // namespace dispatch
+#endif // DOXYGEN_NO_DISPATCH
+
/*!
\brief Main DSV-streaming function
\details DSV stands for Delimiter Separated Values. Geometries can be streamed
diff --git a/boost/geometry/io/svg/svg_mapper.hpp b/boost/geometry/io/svg/svg_mapper.hpp
new file mode 100644
index 0000000000..b53fef2ceb
--- /dev/null
+++ b/boost/geometry/io/svg/svg_mapper.hpp
@@ -0,0 +1,390 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2009-2012 Barend Gehrels, Amsterdam, the Netherlands.
+
+// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
+// (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
+
+// Use, modification and distribution is subject to the Boost Software License,
+// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef BOOST_GEOMETRY_IO_SVG_MAPPER_HPP
+#define BOOST_GEOMETRY_IO_SVG_MAPPER_HPP
+
+#include <cstdio>
+
+#include <vector>
+
+#include <boost/mpl/assert.hpp>
+#include <boost/noncopyable.hpp>
+#include <boost/scoped_ptr.hpp>
+#include <boost/type_traits/is_same.hpp>
+#include <boost/type_traits/remove_const.hpp>
+
+#include <boost/algorithm/string/split.hpp>
+#include <boost/algorithm/string/classification.hpp>
+
+
+#include <boost/geometry/core/tags.hpp>
+#include <boost/geometry/core/tag_cast.hpp>
+
+#include <boost/geometry/algorithms/envelope.hpp>
+#include <boost/geometry/algorithms/expand.hpp>
+#include <boost/geometry/algorithms/transform.hpp>
+#include <boost/geometry/algorithms/num_points.hpp>
+#include <boost/geometry/strategies/transform.hpp>
+#include <boost/geometry/strategies/transform/map_transformer.hpp>
+#include <boost/geometry/views/segment_view.hpp>
+
+#include <boost/geometry/multi/algorithms/envelope.hpp>
+#include <boost/geometry/multi/algorithms/num_points.hpp>
+
+#include <boost/geometry/io/svg/write_svg.hpp>
+
+// Helper geometries (all points are transformed to integer-points)
+#include <boost/geometry/geometries/geometries.hpp>
+
+
+namespace boost { namespace geometry
+{
+
+#ifndef DOXYGEN_NO_DETAIL
+namespace detail { namespace svg
+{
+ typedef model::point<int, 2, cs::cartesian> svg_point_type;
+}}
+#endif
+
+
+#ifndef DOXYGEN_NO_DISPATCH
+namespace dispatch
+{
+
+
+
+template <typename GeometryTag, typename Geometry>
+struct svg_map
+{
+ BOOST_MPL_ASSERT_MSG
+ (
+ false, NOT_OR_NOT_YET_IMPLEMENTED_FOR_THIS_GEOMETRY_TYPE
+ , (Geometry)
+ );
+};
+
+
+template <typename Point>
+struct svg_map<point_tag, Point>
+{
+ template <typename TransformStrategy>
+ static inline void apply(std::ostream& stream,
+ std::string const& style, int size,
+ Point const& point, TransformStrategy const& strategy)
+ {
+ detail::svg::svg_point_type ipoint;
+ geometry::transform(point, ipoint, strategy);
+ stream << geometry::svg(ipoint, style, size) << std::endl;
+ }
+};
+
+template <typename Box>
+struct svg_map<box_tag, Box>
+{
+ template <typename TransformStrategy>
+ static inline void apply(std::ostream& stream,
+ std::string const& style, int size,
+ Box const& box, TransformStrategy const& strategy)
+ {
+ model::box<detail::svg::svg_point_type> ibox;
+ geometry::transform(box, ibox, strategy);
+
+ stream << geometry::svg(ibox, style, size) << std::endl;
+ }
+};
+
+
+template <typename Range1, typename Range2>
+struct svg_map_range
+{
+ template <typename TransformStrategy>
+ static inline void apply(std::ostream& stream,
+ std::string const& style, int size,
+ Range1 const& range, TransformStrategy const& strategy)
+ {
+ Range2 irange;
+ geometry::transform(range, irange, strategy);
+ stream << geometry::svg(irange, style, size) << std::endl;
+ }
+};
+
+template <typename Segment>
+struct svg_map<segment_tag, Segment>
+{
+ template <typename TransformStrategy>
+ static inline void apply(std::ostream& stream,
+ std::string const& style, int size,
+ Segment const& segment, TransformStrategy const& strategy)
+ {
+ typedef segment_view<Segment> view_type;
+ view_type range(segment);
+ svg_map_range
+ <
+ view_type,
+ model::linestring<detail::svg::svg_point_type>
+ >::apply(stream, style, size, range, strategy);
+ }
+};
+
+
+template <typename Ring>
+struct svg_map<ring_tag, Ring>
+ : svg_map_range<Ring, model::ring<detail::svg::svg_point_type> >
+{};
+
+
+template <typename Linestring>
+struct svg_map<linestring_tag, Linestring>
+ : svg_map_range<Linestring, model::linestring<detail::svg::svg_point_type> >
+{};
+
+
+template <typename Polygon>
+struct svg_map<polygon_tag, Polygon>
+{
+ template <typename TransformStrategy>
+ static inline void apply(std::ostream& stream,
+ std::string const& style, int size,
+ Polygon const& polygon, TransformStrategy const& strategy)
+ {
+ model::polygon<detail::svg::svg_point_type> ipoly;
+ geometry::transform(polygon, ipoly, strategy);
+ stream << geometry::svg(ipoly, style, size) << std::endl;
+ }
+};
+
+
+template <typename Multi>
+struct svg_map<multi_tag, Multi>
+{
+ typedef typename single_tag_of
+ <
+ typename geometry::tag<Multi>::type
+ >::type stag;
+
+ template <typename TransformStrategy>
+ static inline void apply(std::ostream& stream,
+ std::string const& style, int size,
+ Multi const& multi, TransformStrategy const& strategy)
+ {
+ for (typename boost::range_iterator<Multi const>::type it
+ = boost::begin(multi);
+ it != boost::end(multi);
+ ++it)
+ {
+ svg_map
+ <
+ stag,
+ typename boost::range_value<Multi>::type
+ >::apply(stream, style, size, *it, strategy);
+ }
+ }
+};
+
+
+} // namespace dispatch
+#endif
+
+
+template <typename Geometry, typename TransformStrategy>
+inline void svg_map(std::ostream& stream,
+ std::string const& style, int size,
+ Geometry const& geometry, TransformStrategy const& strategy)
+{
+ dispatch::svg_map
+ <
+ typename tag_cast
+ <
+ typename tag<Geometry>::type,
+ multi_tag
+ >::type,
+ typename boost::remove_const<Geometry>::type
+ >::apply(stream, style, size, geometry, strategy);
+}
+
+
+/*!
+\brief Helper class to create SVG maps
+\tparam Point Point type, for input geometries.
+\tparam SameScale Boolean flag indicating if horizontal and vertical scale should
+ be the same. The default value is true
+\ingroup svg
+
+\qbk{[include reference/io/svg.qbk]}
+*/
+template <typename Point, bool SameScale = true>
+class svg_mapper : boost::noncopyable
+{
+ typedef typename geometry::select_most_precise
+ <
+ typename coordinate_type<Point>::type,
+ double
+ >::type calculation_type;
+
+ typedef strategy::transform::map_transformer
+ <
+ calculation_type,
+ geometry::dimension<Point>::type::value,
+ geometry::dimension<Point>::type::value,
+ true,
+ SameScale
+ > transformer_type;
+
+ model::box<Point> m_bounding_box;
+ boost::scoped_ptr<transformer_type> m_matrix;
+ std::ostream& m_stream;
+ int m_width, m_height;
+ std::string m_width_height; // for <svg> tag only, defaults to 2x 100%
+
+ void init_matrix()
+ {
+ if (! m_matrix)
+ {
+ m_matrix.reset(new transformer_type(m_bounding_box,
+ m_width, m_height));
+
+
+ m_stream << "<?xml version=\"1.0\" standalone=\"no\"?>"
+ << std::endl
+ << "<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 1.1//EN\""
+ << std::endl
+ << "\"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd\">"
+ << std::endl
+ << "<svg " << m_width_height << " version=\"1.1\""
+ << std::endl
+ << "xmlns=\"http://www.w3.org/2000/svg\""
+ << std::endl
+ << "xmlns:xlink=\"http://www.w3.org/1999/xlink\""
+ << ">"
+ << std::endl;
+ }
+ }
+
+public :
+
+ /*!
+ \brief Constructor, initializing the SVG map. Opens and initializes the SVG.
+ Should be called explicitly.
+ \param stream Output stream, should be a stream already open
+ \param width Width of the SVG map (in SVG pixels)
+ \param height Height of the SVG map (in SVG pixels)
+ \param width_height Optional information to increase width and/or height
+ */
+ explicit svg_mapper(std::ostream& stream, int width, int height
+ , std::string const& width_height = "width=\"100%\" height=\"100%\"")
+ : m_stream(stream)
+ , m_width(width)
+ , m_height(height)
+ , m_width_height(width_height)
+ {
+ assign_inverse(m_bounding_box);
+ }
+
+ /*!
+ \brief Destructor, called automatically. Closes the SVG by streaming <\/svg>
+ */
+ virtual ~svg_mapper()
+ {
+ m_stream << "</svg>" << std::endl;
+ }
+
+ /*!
+ \brief Adds a geometry to the transformation matrix. After doing this,
+ the specified geometry can be mapped fully into the SVG map
+ \tparam Geometry \tparam_geometry
+ \param geometry \param_geometry
+ */
+ template <typename Geometry>
+ void add(Geometry const& geometry)
+ {
+ if (num_points(geometry) > 0)
+ {
+ expand(m_bounding_box,
+ return_envelope
+ <
+ model::box<Point>
+ >(geometry));
+ }
+ }
+
+ /*!
+ \brief Maps a geometry into the SVG map using the specified style
+ \tparam Geometry \tparam_geometry
+ \param geometry \param_geometry
+ \param style String containing verbatim SVG style information
+ \param size Optional size (used for SVG points) in SVG pixels. For linestrings,
+ specify linewidth in the SVG style information
+ */
+ template <typename Geometry>
+ void map(Geometry const& geometry, std::string const& style,
+ int size = -1)
+ {
+ init_matrix();
+ svg_map(m_stream, style, size, geometry, *m_matrix);
+ }
+
+ /*!
+ \brief Adds a text to the SVG map
+ \tparam TextPoint \tparam_point
+ \param point Location of the text (in map units)
+ \param s The text itself
+ \param style String containing verbatim SVG style information, of the text
+ \param offset_x Offset in SVG pixels, defaults to 0
+ \param offset_y Offset in SVG pixels, defaults to 0
+ \param lineheight Line height in SVG pixels, in case the text contains \n
+ */
+ template <typename TextPoint>
+ void text(TextPoint const& point, std::string const& s,
+ std::string const& style,
+ int offset_x = 0, int offset_y = 0, int lineheight = 10)
+ {
+ init_matrix();
+ detail::svg::svg_point_type map_point;
+ transform(point, map_point, *m_matrix);
+ m_stream
+ << "<text style=\"" << style << "\""
+ << " x=\"" << get<0>(map_point) + offset_x << "\""
+ << " y=\"" << get<1>(map_point) + offset_y << "\""
+ << ">";
+ if (s.find("\n") == std::string::npos)
+ {
+ m_stream << s;
+ }
+ else
+ {
+ // Multi-line modus
+
+ std::vector<std::string> splitted;
+ boost::split(splitted, s, boost::is_any_of("\n"));
+ for (std::vector<std::string>::const_iterator it
+ = splitted.begin();
+ it != splitted.end();
+ ++it, offset_y += lineheight)
+ {
+ m_stream
+ << "<tspan x=\"" << get<0>(map_point) + offset_x
+ << "\""
+ << " y=\"" << get<1>(map_point) + offset_y
+ << "\""
+ << ">" << *it << "</tspan>";
+ }
+ }
+ m_stream << "</text>" << std::endl;
+ }
+};
+
+
+}} // namespace boost::geometry
+
+
+#endif // BOOST_GEOMETRY_IO_SVG_MAPPER_HPP
diff --git a/boost/geometry/io/svg/write_svg.hpp b/boost/geometry/io/svg/write_svg.hpp
new file mode 100644
index 0000000000..fba3cbebaf
--- /dev/null
+++ b/boost/geometry/io/svg/write_svg.hpp
@@ -0,0 +1,279 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2009-2012 Barend Gehrels, Amsterdam, the Netherlands.
+// 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.
+
+// Use, modification and distribution is subject to the Boost Software License,
+// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef BOOST_GEOMETRY_IO_SVG_WRITE_SVG_HPP
+#define BOOST_GEOMETRY_IO_SVG_WRITE_SVG_HPP
+
+#include <ostream>
+#include <string>
+
+#include <boost/config.hpp>
+#include <boost/mpl/assert.hpp>
+#include <boost/range.hpp>
+
+#include <boost/geometry/algorithms/detail/interior_iterator.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/geometries/concepts/check.hpp>
+
+
+namespace boost { namespace geometry
+{
+
+
+#ifndef DOXYGEN_NO_DETAIL
+namespace detail { namespace svg
+{
+
+
+template <typename Point>
+struct svg_point
+{
+ template <typename Char, typename Traits>
+ static inline void apply(std::basic_ostream<Char, Traits>& os,
+ Point const& p, std::string const& style, int size)
+ {
+ os << "<circle cx=\"" << geometry::get<0>(p)
+ << "\" cy=\"" << geometry::get<1>(p)
+ << "\" r=\"" << (size < 0 ? 5 : size)
+ << "\" style=\"" << style << "\"/>";
+ }
+};
+
+
+template <typename Box>
+struct svg_box
+{
+ template <typename Char, typename Traits>
+ static inline void apply(std::basic_ostream<Char, Traits>& os,
+ Box const& box, std::string const& style, int )
+ {
+ // Prevent invisible boxes, making them >=1, using "max"
+ BOOST_USING_STD_MAX();
+
+ typedef typename coordinate_type<Box>::type ct;
+ ct x = geometry::get<geometry::min_corner, 0>(box);
+ ct y = geometry::get<geometry::min_corner, 1>(box);
+ ct width = max BOOST_PREVENT_MACRO_SUBSTITUTION(1,
+ geometry::get<geometry::max_corner, 0>(box) - x);
+ ct height = max BOOST_PREVENT_MACRO_SUBSTITUTION (1,
+ geometry::get<geometry::max_corner, 1>(box) - y);
+
+ os << "<rect x=\"" << x << "\" y=\"" << y
+ << "\" width=\"" << width << "\" height=\"" << height
+ << "\" style=\"" << style << "\"/>";
+ }
+};
+
+
+/*!
+\brief Stream ranges as SVG
+\note policy is used to select type (polyline/polygon)
+*/
+template <typename Range, typename Policy>
+struct svg_range
+{
+ template <typename Char, typename Traits>
+ static inline void apply(std::basic_ostream<Char, Traits>& os,
+ Range const& range, std::string const& style, int )
+ {
+ typedef typename boost::range_iterator<Range const>::type iterator;
+
+ bool first = true;
+
+ os << "<" << Policy::prefix() << " points=\"";
+
+ for (iterator it = boost::begin(range);
+ it != boost::end(range);
+ ++it, first = false)
+ {
+ os << (first ? "" : " " )
+ << geometry::get<0>(*it)
+ << ","
+ << geometry::get<1>(*it);
+ }
+ os << "\" style=\"" << style << Policy::style() << "\"/>";
+ }
+};
+
+
+
+template <typename Polygon>
+struct svg_poly
+{
+ template <typename Char, typename Traits>
+ static inline void apply(std::basic_ostream<Char, Traits>& os,
+ Polygon const& polygon, std::string const& style, int )
+ {
+ typedef typename geometry::ring_type<Polygon>::type ring_type;
+ typedef typename boost::range_iterator<ring_type const>::type iterator_type;
+
+ bool first = true;
+ os << "<g fill-rule=\"evenodd\"><path d=\"";
+
+ ring_type const& ring = geometry::exterior_ring(polygon);
+ for (iterator_type it = boost::begin(ring);
+ it != boost::end(ring);
+ ++it, first = false)
+ {
+ os << (first ? "M" : " L") << " "
+ << geometry::get<0>(*it)
+ << ","
+ << geometry::get<1>(*it);
+ }
+
+ // Inner rings:
+ {
+ typename interior_return_type<Polygon const>::type
+ rings = interior_rings(polygon);
+ for (typename detail::interior_iterator<Polygon const>::type
+ rit = boost::begin(rings); rit != boost::end(rings); ++rit)
+ {
+ first = true;
+ for (typename detail::interior_ring_iterator<Polygon const>::type
+ it = boost::begin(*rit); it != boost::end(*rit);
+ ++it, first = false)
+ {
+ os << (first ? "M" : " L") << " "
+ << geometry::get<0>(*it)
+ << ","
+ << geometry::get<1>(*it);
+ }
+ }
+ }
+ os << " z \" style=\"" << style << "\"/></g>";
+
+ }
+};
+
+
+
+struct prefix_linestring
+{
+ static inline const char* prefix() { return "polyline"; }
+ static inline const char* style() { return ";fill:none"; }
+};
+
+
+struct prefix_ring
+{
+ static inline const char* prefix() { return "polygon"; }
+ static inline const char* style() { return ""; }
+};
+
+
+
+}} // namespace detail::svg
+#endif // DOXYGEN_NO_DETAIL
+
+
+#ifndef DOXYGEN_NO_DISPATCH
+namespace dispatch
+{
+
+/*!
+\brief Dispatching base struct for SVG streaming, specialized below per geometry type
+\details Specializations should implement a static method "stream" to stream a geometry
+The static method should have the signature:
+
+template <typename Char, typename Traits>
+static inline void apply(std::basic_ostream<Char, Traits>& os, G const& geometry)
+*/
+template <typename GeometryTag, typename Geometry>
+struct svg
+{
+ BOOST_MPL_ASSERT_MSG
+ (
+ false, NOT_OR_NOT_YET_IMPLEMENTED_FOR_THIS_GEOMETRY_TYPE
+ , (Geometry)
+ );
+};
+
+template <typename Point>
+struct svg<point_tag, Point> : detail::svg::svg_point<Point> {};
+
+template <typename Box>
+struct svg<box_tag, Box> : detail::svg::svg_box<Box> {};
+
+template <typename Linestring>
+struct svg<linestring_tag, Linestring>
+ : detail::svg::svg_range<Linestring, detail::svg::prefix_linestring> {};
+
+template <typename Ring>
+struct svg<ring_tag, Ring>
+ : detail::svg::svg_range<Ring, detail::svg::prefix_ring> {};
+
+template <typename Polygon>
+struct svg<polygon_tag, Polygon>
+ : detail::svg::svg_poly<Polygon> {};
+
+} // namespace dispatch
+#endif // DOXYGEN_NO_DISPATCH
+
+
+/*!
+\brief Generic geometry template manipulator class, takes corresponding output class from traits class
+\ingroup svg
+\details Stream manipulator, streams geometry classes as SVG (Scalable Vector Graphics)
+*/
+template <typename G>
+class svg_manipulator
+{
+public:
+
+ inline svg_manipulator(G const& g, std::string const& style, int size)
+ : m_geometry(g)
+ , m_style(style)
+ , m_size(size)
+ {}
+
+ template <typename Char, typename Traits>
+ inline friend std::basic_ostream<Char, Traits>& operator<<(
+ std::basic_ostream<Char, Traits>& os, svg_manipulator const& m)
+ {
+ dispatch::svg
+ <
+ typename tag<G>::type, G
+ >::apply(os, m.m_geometry, m.m_style, m.m_size);
+ os.flush();
+ return os;
+ }
+
+private:
+ G const& m_geometry;
+ std::string const& m_style;
+ int m_size;
+};
+
+/*!
+\brief Manipulator to stream geometries as SVG
+\tparam Geometry \tparam_geometry
+\param geometry \param_geometry
+\param style String containing verbatim SVG style information
+\param size Optional size (used for SVG points) in SVG pixels. For linestrings,
+ specify linewidth in the SVG style information
+\ingroup svg
+*/
+template <typename Geometry>
+inline svg_manipulator<Geometry> svg(Geometry const& geometry, std::string const& style, int size = -1)
+{
+ concept::check<Geometry const>();
+
+ return svg_manipulator<Geometry>(geometry, style, size);
+}
+
+}} // namespace boost::geometry
+
+#endif // BOOST_GEOMETRY_IO_SVG_WRITE_SVG_HPP
diff --git a/boost/geometry/io/svg/write_svg_multi.hpp b/boost/geometry/io/svg/write_svg_multi.hpp
new file mode 100644
index 0000000000..a794120c06
--- /dev/null
+++ b/boost/geometry/io/svg/write_svg_multi.hpp
@@ -0,0 +1,78 @@
+// Boost.Geometry (aka GGL, Generic Geometry Library)
+
+// Copyright (c) 2009-2012 Barend Gehrels, Amsterdam, the Netherlands.
+
+// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
+// (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
+
+// Use, modification and distribution is subject to the Boost Software License,
+// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+#ifndef BOOST_GEOMETRY_IO_SVG_WRITE_SVG_MULTI_HPP
+#define BOOST_GEOMETRY_IO_SVG_WRITE_SVG_MULTI_HPP
+
+
+#include <boost/geometry/io/svg/write_svg.hpp>
+
+
+namespace boost { namespace geometry
+{
+
+#ifndef DOXYGEN_NO_DETAIL
+namespace detail { namespace svg
+{
+
+
+template <typename MultiGeometry, typename Policy>
+struct svg_multi
+{
+ template <typename Char, typename Traits>
+ static inline void apply(std::basic_ostream<Char, Traits>& os,
+ MultiGeometry const& multi, std::string const& style, int size)
+ {
+ for (typename boost::range_iterator<MultiGeometry const>::type
+ it = boost::begin(multi);
+ it != boost::end(multi);
+ ++it)
+ {
+ Policy::apply(os, *it, style, size);
+ }
+
+ }
+
+};
+
+
+
+}} // namespace detail::svg
+#endif // DOXYGEN_NO_DETAIL
+
+
+#ifndef DOXYGEN_NO_DISPATCH
+namespace dispatch
+{
+
+
+template <typename MultiPolygon>
+struct svg<multi_polygon_tag, MultiPolygon>
+ : detail::svg::svg_multi
+ <
+ MultiPolygon,
+ detail::svg::svg_poly
+ <
+ typename boost::range_value<MultiPolygon>::type
+ >
+
+ >
+{};
+
+
+} // namespace dispatch
+#endif // DOXYGEN_NO_DISPATCH
+
+
+}} // namespace boost::geometry
+
+
+#endif // BOOST_GEOMETRY_IO_SVG_WRITE_SVG_MULTI_HPP
diff --git a/boost/geometry/io/wkt/detail/prefix.hpp b/boost/geometry/io/wkt/detail/prefix.hpp
index 45e43b88d4..b566e02aa6 100644
--- a/boost/geometry/io/wkt/detail/prefix.hpp
+++ b/boost/geometry/io/wkt/detail/prefix.hpp
@@ -17,10 +17,16 @@
namespace boost { namespace geometry
{
+
#ifndef DOXYGEN_NO_DETAIL
namespace detail { namespace wkt
{
+struct prefix_null
+{
+ static inline const char* apply() { return ""; }
+};
+
struct prefix_point
{
static inline const char* apply() { return "POINT"; }
@@ -36,6 +42,21 @@ struct prefix_linestring
static inline const char* apply() { return "LINESTRING"; }
};
+struct prefix_multipoint
+{
+ static inline const char* apply() { return "MULTIPOINT"; }
+};
+
+struct prefix_multilinestring
+{
+ static inline const char* apply() { return "MULTILINESTRING"; }
+};
+
+struct prefix_multipolygon
+{
+ static inline const char* apply() { return "MULTIPOLYGON"; }
+};
+
}} // namespace wkt::impl
#endif
diff --git a/boost/geometry/io/wkt/detail/wkt_multi.hpp b/boost/geometry/io/wkt/detail/wkt_multi.hpp
index 0e5abbca81..2b2d1946ad 100644
--- a/boost/geometry/io/wkt/detail/wkt_multi.hpp
+++ b/boost/geometry/io/wkt/detail/wkt_multi.hpp
@@ -14,9 +14,8 @@
#ifndef BOOST_GEOMETRY_DOMAINS_GIS_IO_WKT_DETAIL_WKT_MULTI_HPP
#define BOOST_GEOMETRY_DOMAINS_GIS_IO_WKT_DETAIL_WKT_MULTI_HPP
-
+#include <boost/geometry/core/tags.hpp>
#include <boost/geometry/domains/gis/io/wkt/write.hpp>
-#include <boost/geometry/multi/core/tags.hpp>
namespace boost { namespace geometry
diff --git a/boost/geometry/io/wkt/read.hpp b/boost/geometry/io/wkt/read.hpp
index e926939d51..748eecdbe6 100644
--- a/boost/geometry/io/wkt/read.hpp
+++ b/boost/geometry/io/wkt/read.hpp
@@ -14,6 +14,7 @@
#ifndef BOOST_GEOMETRY_IO_WKT_READ_HPP
#define BOOST_GEOMETRY_IO_WKT_READ_HPP
+#include <cstddef>
#include <string>
#include <boost/lexical_cast.hpp>
@@ -36,6 +37,8 @@
#include <boost/geometry/core/geometry_id.hpp>
#include <boost/geometry/core/interior_rings.hpp>
#include <boost/geometry/core/mutable_range.hpp>
+#include <boost/geometry/core/point_type.hpp>
+#include <boost/geometry/core/tags.hpp>
#include <boost/geometry/geometries/concepts/check.hpp>
@@ -306,8 +309,6 @@ struct ring_parser
};
-
-
/*!
\brief Internal, parses a polygon from a string like this "((x y,x y),(x y,x y))"
\note used for parsing polygons and multi-polygons
@@ -358,6 +359,7 @@ struct polygon_parser
}
};
+
inline bool one_of(tokenizer::iterator const& it, std::string const& value,
bool& is_present)
{
@@ -423,10 +425,21 @@ inline bool initialize(tokenizer const& tokens,
handle_empty_z_m(it, tokens.end(), has_empty, has_z, has_m);
+// Silence warning C4127: conditional expression is constant
+#if defined(_MSC_VER)
+#pragma warning(push)
+#pragma warning(disable : 4127)
+#endif
+
if (has_z && dimension<Geometry>::type::value < 3)
{
throw read_wkt_exception("Z only allowed for 3 or more dimensions", wkt);
}
+
+#if defined(_MSC_VER)
+#pragma warning(pop)
+#endif
+
if (has_empty)
{
check_end(it, tokens.end(), wkt);
@@ -458,7 +471,101 @@ struct geometry_parser
};
+template <typename MultiGeometry, template<typename> class Parser, typename PrefixPolicy>
+struct multi_parser
+{
+ static inline void apply(std::string const& wkt, MultiGeometry& geometry)
+ {
+ traits::clear<MultiGeometry>::apply(geometry);
+
+ tokenizer tokens(wkt, boost::char_separator<char>(" ", ",()"));
+ tokenizer::iterator it;
+ if (initialize<MultiGeometry>(tokens, PrefixPolicy::apply(), wkt, it))
+ {
+ handle_open_parenthesis(it, tokens.end(), wkt);
+
+ // Parse sub-geometries
+ while(it != tokens.end() && *it != ")")
+ {
+ traits::resize<MultiGeometry>::apply(geometry, boost::size(geometry) + 1);
+ Parser
+ <
+ typename boost::range_value<MultiGeometry>::type
+ >::apply(it, tokens.end(), wkt, *(boost::end(geometry) - 1));
+ if (it != tokens.end() && *it == ",")
+ {
+ // Skip "," after multi-element is parsed
+ ++it;
+ }
+ }
+
+ handle_close_parenthesis(it, tokens.end(), wkt);
+ }
+
+ check_end(it, tokens.end(), wkt);
+ }
+};
+
+template <typename P>
+struct noparenthesis_point_parser
+{
+ static inline void apply(tokenizer::iterator& it, tokenizer::iterator end,
+ std::string const& wkt, P& point)
+ {
+ parsing_assigner<P, 0, dimension<P>::value>::apply(it, end, point, wkt);
+ }
+};
+
+template <typename MultiGeometry, typename PrefixPolicy>
+struct multi_point_parser
+{
+ static inline void apply(std::string const& wkt, MultiGeometry& geometry)
+ {
+ traits::clear<MultiGeometry>::apply(geometry);
+
+ tokenizer tokens(wkt, boost::char_separator<char>(" ", ",()"));
+ tokenizer::iterator it;
+ if (initialize<MultiGeometry>(tokens, PrefixPolicy::apply(), wkt, it))
+ {
+ handle_open_parenthesis(it, tokens.end(), wkt);
+
+ // If first point definition starts with "(" then parse points as (x y)
+ // otherwise as "x y"
+ bool using_brackets = (it != tokens.end() && *it == "(");
+
+ while(it != tokens.end() && *it != ")")
+ {
+ traits::resize<MultiGeometry>::apply(geometry, boost::size(geometry) + 1);
+
+ if (using_brackets)
+ {
+ point_parser
+ <
+ typename boost::range_value<MultiGeometry>::type
+ >::apply(it, tokens.end(), wkt, *(boost::end(geometry) - 1));
+ }
+ else
+ {
+ noparenthesis_point_parser
+ <
+ typename boost::range_value<MultiGeometry>::type
+ >::apply(it, tokens.end(), wkt, *(boost::end(geometry) - 1));
+ }
+
+ if (it != tokens.end() && *it == ",")
+ {
+ // Skip "," after point is parsed
+ ++it;
+ }
+ }
+
+ handle_close_parenthesis(it, tokens.end(), wkt);
+ }
+
+ check_end(it, tokens.end(), wkt);
+ }
+};
/*!
@@ -511,7 +618,7 @@ struct box_parser
check_end(it, end, wkt);
int index = 0;
- int n = boost::size(points);
+ std::size_t n = boost::size(points);
if (n == 2)
{
index = 1;
@@ -578,7 +685,6 @@ struct segment_parser
};
-
}} // namespace detail::wkt
#endif // DOXYGEN_NO_DETAIL
@@ -632,6 +738,36 @@ struct read_wkt<polygon_tag, Geometry>
{};
+template <typename MultiGeometry>
+struct read_wkt<multi_point_tag, MultiGeometry>
+ : detail::wkt::multi_point_parser
+ <
+ MultiGeometry,
+ detail::wkt::prefix_multipoint
+ >
+{};
+
+template <typename MultiGeometry>
+struct read_wkt<multi_linestring_tag, MultiGeometry>
+ : detail::wkt::multi_parser
+ <
+ MultiGeometry,
+ detail::wkt::linestring_parser,
+ detail::wkt::prefix_multilinestring
+ >
+{};
+
+template <typename MultiGeometry>
+struct read_wkt<multi_polygon_tag, MultiGeometry>
+ : detail::wkt::multi_parser
+ <
+ MultiGeometry,
+ detail::wkt::polygon_parser,
+ detail::wkt::prefix_multipolygon
+ >
+{};
+
+
// Box (Non-OGC)
template <typename Box>
struct read_wkt<box_tag, Box>
@@ -651,28 +787,11 @@ struct read_wkt<segment_tag, Segment>
/*!
\brief Parses OGC Well-Known Text (\ref WKT) into a geometry (any geometry)
\ingroup wkt
+\tparam Geometry \tparam_geometry
\param wkt string containing \ref WKT
-\param geometry output geometry
-\par Example:
-\note It is case insensitive and can have the WKT forms "point", "point m", "point z", "point zm", "point mz"
-\note Empty sequences can have forms as "LINESTRING ()" or "POLYGON(())"
-Small example showing how to use read_wkt to build a point
-\dontinclude doxygen_1.cpp
-\skip example_from_wkt_point
-\line {
-\until }
-\par Example:
-Small example showing how to use read_wkt to build a linestring
-\dontinclude doxygen_1.cpp
-\skip example_from_wkt_linestring
-\line {
-\until }
-\par Example:
-Small example showing how to use read_wkt to build a polygon
-\dontinclude doxygen_1.cpp
-\skip example_from_wkt_polygon
-\line {
-\until }
+\param geometry \param_geometry output geometry
+\ingroup wkt
+\qbk{[include reference/io/read_wkt.qbk]}
*/
template <typename Geometry>
inline void read_wkt(std::string const& wkt, Geometry& geometry)
diff --git a/boost/geometry/io/wkt/stream.hpp b/boost/geometry/io/wkt/stream.hpp
index 86e49fdaf1..3849dda594 100644
--- a/boost/geometry/io/wkt/stream.hpp
+++ b/boost/geometry/io/wkt/stream.hpp
@@ -22,10 +22,8 @@
// Don't use namespace boost::geometry, to enable the library to stream custom
// geometries which are living outside the namespace boost::geometry
-/*!
-\brief Streams a geometry as Well-Known Text
-\ingroup wkt
-*/
+// This is currently not documented on purpose: the Doxygen 2 QBK generator
+// should be updated w.r.t. << which in the end ruins the DocBook XML
template<typename Char, typename Traits, typename Geometry>
inline std::basic_ostream<Char, Traits>& operator<<
(
diff --git a/boost/geometry/io/wkt/write.hpp b/boost/geometry/io/wkt/write.hpp
index a3e3173d05..6c1a2e153e 100644
--- a/boost/geometry/io/wkt/write.hpp
+++ b/boost/geometry/io/wkt/write.hpp
@@ -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.
@@ -18,24 +19,36 @@
#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