diff options
Diffstat (limited to 'boost/geometry/io')
-rw-r--r-- | boost/geometry/io/dsv/write.hpp | 64 | ||||
-rw-r--r-- | boost/geometry/io/svg/svg_mapper.hpp | 390 | ||||
-rw-r--r-- | boost/geometry/io/svg/write_svg.hpp | 279 | ||||
-rw-r--r-- | boost/geometry/io/svg/write_svg_multi.hpp | 78 | ||||
-rw-r--r-- | boost/geometry/io/wkt/detail/prefix.hpp | 21 | ||||
-rw-r--r-- | boost/geometry/io/wkt/detail/wkt_multi.hpp | 3 | ||||
-rw-r--r-- | boost/geometry/io/wkt/read.hpp | 169 | ||||
-rw-r--r-- | boost/geometry/io/wkt/stream.hpp | 6 | ||||
-rw-r--r-- | boost/geometry/io/wkt/write.hpp | 215 |
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 |