diff options
author | Anas Nashif <anas.nashif@intel.com> | 2012-10-30 12:57:26 -0700 |
---|---|---|
committer | Anas Nashif <anas.nashif@intel.com> | 2012-10-30 12:57:26 -0700 |
commit | 1a78a62555be32868418fe52f8e330c9d0f95d5a (patch) | |
tree | d3765a80e7d3b9640ec2e930743630cd6b9fce2b /boost/geometry/io | |
download | boost-1a78a62555be32868418fe52f8e330c9d0f95d5a.tar.gz boost-1a78a62555be32868418fe52f8e330c9d0f95d5a.tar.bz2 boost-1a78a62555be32868418fe52f8e330c9d0f95d5a.zip |
Imported Upstream version 1.49.0upstream/1.49.0
Diffstat (limited to 'boost/geometry/io')
-rw-r--r-- | boost/geometry/io/dsv/write.hpp | 375 | ||||
-rw-r--r-- | boost/geometry/io/io.hpp | 58 | ||||
-rw-r--r-- | boost/geometry/io/wkt/detail/prefix.hpp | 45 | ||||
-rw-r--r-- | boost/geometry/io/wkt/detail/wkt_multi.hpp | 57 | ||||
-rw-r--r-- | boost/geometry/io/wkt/read.hpp | 686 | ||||
-rw-r--r-- | boost/geometry/io/wkt/stream.hpp | 40 | ||||
-rw-r--r-- | boost/geometry/io/wkt/wkt.hpp | 25 | ||||
-rw-r--r-- | boost/geometry/io/wkt/write.hpp | 376 |
8 files changed, 1662 insertions, 0 deletions
diff --git a/boost/geometry/io/dsv/write.hpp b/boost/geometry/io/dsv/write.hpp new file mode 100644 index 0000000000..62929f8073 --- /dev/null +++ b/boost/geometry/io/dsv/write.hpp @@ -0,0 +1,375 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// 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. + +// 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_DSV_WRITE_HPP +#define BOOST_GEOMETRY_IO_DSV_WRITE_HPP + +#include <cstddef> +#include <ostream> +#include <string> + +#include <boost/concept_check.hpp> +#include <boost/range.hpp> +#include <boost/typeof/typeof.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/geometries/concepts/check.hpp> + +namespace boost { namespace geometry +{ + +#ifndef DOXYGEN_NO_DETAIL +namespace detail { namespace dsv +{ + +struct dsv_settings +{ + std::string coordinate_separator; + std::string point_open; + std::string point_close; + std::string point_separator; + std::string list_open; + std::string list_close; + std::string list_separator; + + dsv_settings(std::string const& sep + , std::string const& open + , std::string const& close + , std::string const& psep + , std::string const& lopen + , std::string const& lclose + , std::string const& lsep + ) + : coordinate_separator(sep) + , point_open(open) + , point_close(close) + , point_separator(psep) + , list_open(lopen) + , list_close(lclose) + , list_separator(lsep) + {} +}; + +/*! +\brief Stream coordinate of a point as \ref DSV +*/ +template <typename Point, std::size_t Dimension, std::size_t Count> +struct stream_coordinate +{ + template <typename Char, typename Traits> + static inline void apply(std::basic_ostream<Char, Traits>& os, + Point const& point, + dsv_settings const& settings) + { + os << (Dimension > 0 ? settings.coordinate_separator : "") + << get<Dimension>(point); + + stream_coordinate + < + Point, Dimension + 1, Count + >::apply(os, point, settings); + } +}; + +template <typename Point, std::size_t Count> +struct stream_coordinate<Point, Count, Count> +{ + template <typename Char, typename Traits> + static inline void apply(std::basic_ostream<Char, Traits>&, + Point const&, + dsv_settings const& ) + { + } +}; + +/*! +\brief Stream indexed coordinate of a box/segment as \ref DSV +*/ +template +< + typename Geometry, + std::size_t Index, + std::size_t Dimension, + std::size_t Count +> +struct stream_indexed +{ + template <typename Char, typename Traits> + static inline void apply(std::basic_ostream<Char, Traits>& os, + Geometry const& geometry, + dsv_settings const& settings) + { + os << (Dimension > 0 ? settings.coordinate_separator : "") + << get<Index, Dimension>(geometry); + stream_indexed + < + Geometry, Index, Dimension + 1, Count + >::apply(os, geometry, settings); + } +}; + +template <typename Geometry, std::size_t Index, std::size_t Count> +struct stream_indexed<Geometry, Index, Count, Count> +{ + template <typename Char, typename Traits> + static inline void apply(std::basic_ostream<Char, Traits>&, Geometry const&, + dsv_settings const& ) + { + } +}; + +/*! +\brief Stream points as \ref DSV +*/ +template <typename Point> +struct dsv_point +{ + template <typename Char, typename Traits> + static inline void apply(std::basic_ostream<Char, Traits>& os, + Point const& p, + dsv_settings const& settings) + { + os << settings.point_open; + stream_coordinate<Point, 0, dimension<Point>::type::value>::apply(os, p, settings); + os << settings.point_close; + } +}; + +/*! +\brief Stream ranges as DSV +\note policy is used to stream prefix/postfix, enabling derived classes to override this +*/ +template <typename Range> +struct dsv_range +{ + template <typename Char, typename Traits> + static inline void apply(std::basic_ostream<Char, Traits>& os, + Range const& range, + dsv_settings const& settings) + { + typedef typename boost::range_iterator<Range const>::type iterator_type; + + bool first = true; + + os << settings.list_open; + + for (iterator_type it = boost::begin(range); + it != boost::end(range); + ++it) + { + os << (first ? "" : settings.point_separator) + << settings.point_open; + + stream_coordinate + < + point_type, 0, dimension<point_type>::type::value + >::apply(os, *it, settings); + os << settings.point_close; + + first = false; + } + + os << settings.list_close; + } + +private: + typedef typename boost::range_value<Range>::type point_type; +}; + +/*! +\brief Stream sequence of points as DSV-part, e.g. (1 2),(3 4) +\note Used in polygon, all multi-geometries +*/ + +template <typename Polygon> +struct dsv_poly +{ + template <typename Char, typename Traits> + static inline void apply(std::basic_ostream<Char, Traits>& os, + Polygon const& poly, + dsv_settings const& settings) + { + typedef typename ring_type<Polygon>::type ring; + + os << settings.list_open; + + 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) + { + os << settings.list_separator; + dsv_range<ring>::apply(os, *it, settings); + } + os << settings.list_close; + } +}; + +template <typename Geometry, std::size_t Index> +struct dsv_per_index +{ + typedef typename point_type<Geometry>::type point_type; + + template <typename Char, typename Traits> + static inline void apply(std::basic_ostream<Char, Traits>& os, + Geometry const& geometry, + dsv_settings const& settings) + { + os << settings.point_open; + stream_indexed + < + Geometry, Index, 0, dimension<Geometry>::type::value + >::apply(os, geometry, settings); + os << settings.point_close; + } +}; + +template <typename Geometry> +struct dsv_indexed +{ + typedef typename point_type<Geometry>::type point_type; + + template <typename Char, typename Traits> + static inline void apply(std::basic_ostream<Char, Traits>& os, + Geometry const& geometry, + dsv_settings const& settings) + { + os << settings.list_open; + dsv_per_index<Geometry, 0>::apply(os, geometry, settings); + os << settings.point_separator; + dsv_per_index<Geometry, 1>::apply(os, geometry, settings); + os << settings.list_close; + } +}; + +}} // namespace detail::dsv +#endif // DOXYGEN_NO_DETAIL + +#ifndef DOXYGEN_NO_DISPATCH +namespace dispatch +{ + +template <typename Tag, typename Geometry> +struct dsv {}; + +template <typename Point> +struct dsv<point_tag, Point> + : detail::dsv::dsv_point<Point> +{}; + +template <typename Linestring> +struct dsv<linestring_tag, Linestring> + : detail::dsv::dsv_range<Linestring> +{}; + +template <typename Box> +struct dsv<box_tag, Box> + : detail::dsv::dsv_indexed<Box> +{}; + +template <typename Segment> +struct dsv<segment_tag, Segment> + : detail::dsv::dsv_indexed<Segment> +{}; + +template <typename Ring> +struct dsv<ring_tag, Ring> + : detail::dsv::dsv_range<Ring> +{}; + +template <typename Polygon> +struct dsv<polygon_tag, Polygon> + : detail::dsv::dsv_poly<Polygon> +{}; + +} // namespace dispatch +#endif // DOXYGEN_NO_DISPATCH + +#ifndef DOXYGEN_NO_DETAIL +namespace detail { namespace dsv +{ + +// FIXME: This class is not copyable/assignable but it is used as such --mloskot +template <typename Geometry> +class dsv_manipulator +{ +public: + + inline dsv_manipulator(Geometry const& g, + dsv_settings const& settings) + : m_geometry(g) + , m_settings(settings) + {} + + template <typename Char, typename Traits> + inline friend std::basic_ostream<Char, Traits>& operator<<( + std::basic_ostream<Char, Traits>& os, + dsv_manipulator const& m) + { + dispatch::dsv + < + typename tag_cast + < + typename tag<Geometry>::type, + multi_tag + >::type, + Geometry + >::apply(os, m.m_geometry, m.m_settings); + os.flush(); + return os; + } + +private: + Geometry const& m_geometry; + dsv_settings m_settings; +}; + +}} // namespace detail::dsv +#endif // DOXYGEN_NO_DETAIL + +/*! +\brief Main DSV-streaming function +\details DSV stands for Delimiter Separated Values. Geometries can be streamed + as DSV. There are defaults for all separators. +\note Useful for examples and testing purposes +\note With this function GeoJSON objects can be created, using the right + delimiters +\ingroup utility +*/ +template <typename Geometry> +inline detail::dsv::dsv_manipulator<Geometry> dsv(Geometry const& geometry + , std::string const& coordinate_separator = ", " + , std::string const& point_open = "(" + , std::string const& point_close = ")" + , std::string const& point_separator = ", " + , std::string const& list_open = "(" + , std::string const& list_close = ")" + , std::string const& list_separator = ", " + ) +{ + concept::check<Geometry const>(); + + return detail::dsv::dsv_manipulator<Geometry>(geometry, + detail::dsv::dsv_settings(coordinate_separator, + point_open, point_close, point_separator, + list_open, list_close, list_separator)); +} + +}} // namespace boost::geometry + +#endif // BOOST_GEOMETRY_IO_DSV_WRITE_HPP diff --git a/boost/geometry/io/io.hpp b/boost/geometry/io/io.hpp new file mode 100644 index 0000000000..9340060776 --- /dev/null +++ b/boost/geometry/io/io.hpp @@ -0,0 +1,58 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// 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. + +// 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_HPP +#define BOOST_GEOMETRY_IO_HPP + +#include <boost/geometry/io/wkt/read.hpp> +#include <boost/geometry/io/wkt/write.hpp> + +namespace boost { namespace geometry +{ + +struct format_wkt {}; +struct format_wkb {}; // TODO +struct format_dsv {}; // TODO + +#ifndef DOXYGEN_NO_DISPATCH +namespace dispatch +{ +template <typename Tag, typename Geometry> +struct read +{ +}; + +template <typename Geometry> +struct read<format_wkt, Geometry> +{ + static inline void apply(Geometry& geometry, std::string const& wkt) + { + read_wkt<typename tag<Geometry>::type, Geometry>::apply(wkt, geometry); + } +}; + +} // namespace dispatch +#endif // DOXYGEN_NO_DISPATCH + +template <typename Format, typename Geometry> +inline void read(Geometry& geometry, std::string const& wkt) +{ + geometry::concept::check<Geometry>(); + dispatch::read<Format, Geometry>::apply(geometry, wkt); +} + +// TODO: wriite + +}} // namespace boost::geometry + +#endif // BOOST_GEOMETRY_IO_HPP diff --git a/boost/geometry/io/wkt/detail/prefix.hpp b/boost/geometry/io/wkt/detail/prefix.hpp new file mode 100644 index 0000000000..45e43b88d4 --- /dev/null +++ b/boost/geometry/io/wkt/detail/prefix.hpp @@ -0,0 +1,45 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// 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. + +// 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_WKT_DETAIL_PREFIX_HPP +#define BOOST_GEOMETRY_IO_WKT_DETAIL_PREFIX_HPP + +namespace boost { namespace geometry +{ + +#ifndef DOXYGEN_NO_DETAIL +namespace detail { namespace wkt +{ + +struct prefix_point +{ + static inline const char* apply() { return "POINT"; } +}; + +struct prefix_polygon +{ + static inline const char* apply() { return "POLYGON"; } +}; + +struct prefix_linestring +{ + static inline const char* apply() { return "LINESTRING"; } +}; + +}} // namespace wkt::impl +#endif + + +}} // namespace boost::geometry + +#endif // BOOST_GEOMETRY_IO_WKT_DETAIL_PREFIX_HPP diff --git a/boost/geometry/io/wkt/detail/wkt_multi.hpp b/boost/geometry/io/wkt/detail/wkt_multi.hpp new file mode 100644 index 0000000000..0e5abbca81 --- /dev/null +++ b/boost/geometry/io/wkt/detail/wkt_multi.hpp @@ -0,0 +1,57 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// 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. + +// 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_DOMAINS_GIS_IO_WKT_DETAIL_WKT_MULTI_HPP +#define BOOST_GEOMETRY_DOMAINS_GIS_IO_WKT_DETAIL_WKT_MULTI_HPP + + +#include <boost/geometry/domains/gis/io/wkt/write.hpp> +#include <boost/geometry/multi/core/tags.hpp> + + +namespace boost { namespace geometry +{ + +#ifndef DOXYGEN_NO_DETAIL +namespace detail { namespace wkt +{ + +struct prefix_null +{ + static inline const char* apply() { return ""; } +}; + +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 + + +}} // namespace boost::geometry + +#endif // BOOST_GEOMETRY_DOMAINS_GIS_IO_WKT_DETAIL_WKT_MULTI_HPP diff --git a/boost/geometry/io/wkt/read.hpp b/boost/geometry/io/wkt/read.hpp new file mode 100644 index 0000000000..e926939d51 --- /dev/null +++ b/boost/geometry/io/wkt/read.hpp @@ -0,0 +1,686 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// 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. + +// 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_WKT_READ_HPP +#define BOOST_GEOMETRY_IO_WKT_READ_HPP + +#include <string> + +#include <boost/lexical_cast.hpp> +#include <boost/tokenizer.hpp> + +#include <boost/algorithm/string.hpp> +#include <boost/mpl/if.hpp> +#include <boost/range.hpp> + +#include <boost/type_traits.hpp> + +#include <boost/geometry/algorithms/assign.hpp> +#include <boost/geometry/algorithms/append.hpp> +#include <boost/geometry/algorithms/clear.hpp> + +#include <boost/geometry/core/access.hpp> +#include <boost/geometry/core/coordinate_dimension.hpp> +#include <boost/geometry/core/exception.hpp> +#include <boost/geometry/core/exterior_ring.hpp> +#include <boost/geometry/core/geometry_id.hpp> +#include <boost/geometry/core/interior_rings.hpp> +#include <boost/geometry/core/mutable_range.hpp> + +#include <boost/geometry/geometries/concepts/check.hpp> + +#include <boost/geometry/util/coordinate_cast.hpp> + +#include <boost/geometry/io/wkt/detail/prefix.hpp> + +namespace boost { namespace geometry +{ + +/*! +\brief Exception showing things wrong with WKT parsing +\ingroup wkt +*/ +struct read_wkt_exception : public geometry::exception +{ + template <typename Iterator> + read_wkt_exception(std::string const& msg, + Iterator const& it, Iterator const& end, std::string const& wkt) + : message(msg) + , wkt(wkt) + { + if (it != end) + { + source = " at '"; + source += it->c_str(); + source += "'"; + } + complete = message + source + " in '" + wkt.substr(0, 100) + "'"; + } + + read_wkt_exception(std::string const& msg, std::string const& wkt) + : message(msg) + , wkt(wkt) + { + complete = message + "' in (" + wkt.substr(0, 100) + ")"; + } + + virtual ~read_wkt_exception() throw() {} + + virtual const char* what() const throw() + { + return complete.c_str(); + } +private : + std::string source; + std::string message; + std::string wkt; + std::string complete; +}; + + +#ifndef DOXYGEN_NO_DETAIL +// (wkt: Well Known Text, defined by OGC for all geometries and implemented by e.g. databases (MySQL, PostGIS)) +namespace detail { namespace wkt +{ + +typedef boost::tokenizer<boost::char_separator<char> > tokenizer; + +template <typename Point, std::size_t Dimension, std::size_t DimensionCount> +struct parsing_assigner +{ + static inline void apply(tokenizer::iterator& it, tokenizer::iterator end, + Point& point, std::string const& wkt) + { + typedef typename coordinate_type<Point>::type coordinate_type; + + // Stop at end of tokens, or at "," ot ")" + bool finished = (it == end || *it == "," || *it == ")"); + + try + { + // Initialize missing coordinates to default constructor (zero) + // OR + // Use lexical_cast for conversion to double/int + // Note that it is much slower than atof. However, it is more standard + // and in parsing the change in performance falls probably away against + // the tokenizing + set<Dimension>(point, finished + ? coordinate_type() + : coordinate_cast<coordinate_type>::apply(*it)); + } + catch(boost::bad_lexical_cast const& blc) + { + throw read_wkt_exception(blc.what(), it, end, wkt); + } + catch(std::exception const& e) + { + throw read_wkt_exception(e.what(), it, end, wkt); + } + catch(...) + { + throw read_wkt_exception("", it, end, wkt); + } + + parsing_assigner<Point, Dimension + 1, DimensionCount>::apply( + (finished ? it : ++it), end, point, wkt); + } +}; + +template <typename Point, std::size_t DimensionCount> +struct parsing_assigner<Point, DimensionCount, DimensionCount> +{ + static inline void apply(tokenizer::iterator&, tokenizer::iterator, Point&, + std::string const&) + { + } +}; + + + +template <typename Iterator> +inline void handle_open_parenthesis(Iterator& it, + Iterator const& end, std::string const& wkt) +{ + if (it == end || *it != "(") + { + throw read_wkt_exception("Expected '('", it, end, wkt); + } + ++it; +} + + +template <typename Iterator> +inline void handle_close_parenthesis(Iterator& it, + Iterator const& end, std::string const& wkt) +{ + if (it != end && *it == ")") + { + ++it; + } + else + { + throw read_wkt_exception("Expected ')'", it, end, wkt); + } +} + +template <typename Iterator> +inline void check_end(Iterator& it, + Iterator const& end, std::string const& wkt) +{ + if (it != end) + { + throw read_wkt_exception("Too much tokens", it, end, wkt); + } +} + +/*! +\brief Internal, parses coordinate sequences, strings are formated like "(1 2,3 4,...)" +\param it token-iterator, should be pre-positioned at "(", is post-positions after last ")" +\param end end-token-iterator +\param out Output itererator receiving coordinates +*/ +template <typename Point> +struct container_inserter +{ + // Version with output iterator + template <typename OutputIterator> + static inline void apply(tokenizer::iterator& it, tokenizer::iterator end, + std::string const& wkt, OutputIterator out) + { + handle_open_parenthesis(it, end, wkt); + + Point point; + + // Parse points until closing parenthesis + + while (it != end && *it != ")") + { + parsing_assigner + < + Point, + 0, + dimension<Point>::value + >::apply(it, end, point, wkt); + out = point; + ++out; + if (it != end && *it == ",") + { + ++it; + } + } + + handle_close_parenthesis(it, end, wkt); + } +}; + + +// Geometry is a value-type or reference-type +template <typename Geometry> +struct container_appender +{ + typedef typename geometry::point_type + < + typename boost::remove_reference<Geometry>::type + >::type point_type; + + static inline void apply(tokenizer::iterator& it, tokenizer::iterator end, + std::string const& wkt, Geometry out) + { + handle_open_parenthesis(it, end, wkt); + + point_type point; + + // Parse points until closing parenthesis + + while (it != end && *it != ")") + { + parsing_assigner + < + point_type, + 0, + dimension<point_type>::value + >::apply(it, end, point, wkt); + + geometry::append(out, point); + if (it != end && *it == ",") + { + ++it; + } + } + + handle_close_parenthesis(it, end, wkt); + } +}; + +/*! +\brief Internal, parses a point from a string like this "(x y)" +\note used for parsing points and multi-points +*/ +template <typename P> +struct point_parser +{ + static inline void apply(tokenizer::iterator& it, tokenizer::iterator end, + std::string const& wkt, P& point) + { + handle_open_parenthesis(it, end, wkt); + parsing_assigner<P, 0, dimension<P>::value>::apply(it, end, point, wkt); + handle_close_parenthesis(it, end, wkt); + } +}; + + +template <typename Geometry> +struct linestring_parser +{ + static inline void apply(tokenizer::iterator& it, tokenizer::iterator end, + std::string const& wkt, Geometry& geometry) + { + container_appender<Geometry&>::apply(it, end, wkt, geometry); + } +}; + + +template <typename Ring> +struct ring_parser +{ + static inline void apply(tokenizer::iterator& it, tokenizer::iterator end, + std::string const& wkt, Ring& ring) + { + // A ring should look like polygon((x y,x y,x y...)) + // So handle the extra opening/closing parentheses + // and in between parse using the container-inserter + handle_open_parenthesis(it, end, wkt); + container_appender<Ring&>::apply(it, end, wkt, ring); + handle_close_parenthesis(it, end, wkt); + } +}; + + + + +/*! +\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 +*/ +template <typename Polygon> +struct polygon_parser +{ + typedef typename ring_return_type<Polygon>::type ring_return_type; + typedef container_appender<ring_return_type> appender; + + static inline void apply(tokenizer::iterator& it, tokenizer::iterator end, + std::string const& wkt, Polygon& poly) + { + + handle_open_parenthesis(it, end, wkt); + + int n = -1; + + // Stop at ")" + while (it != end && *it != ")") + { + // Parse ring + if (++n == 0) + { + appender::apply(it, end, wkt, exterior_ring(poly)); + } + else + { + typename ring_type<Polygon>::type ring; + appender::apply(it, end, wkt, ring); + traits::push_back + < + typename boost::remove_reference + < + typename traits::interior_mutable_type<Polygon>::type + >::type + >::apply(interior_rings(poly), ring); + } + + if (it != end && *it == ",") + { + // Skip "," after ring is parsed + ++it; + } + } + + handle_close_parenthesis(it, end, wkt); + } +}; + +inline bool one_of(tokenizer::iterator const& it, std::string const& value, + bool& is_present) +{ + if (boost::iequals(*it, value)) + { + is_present = true; + return true; + } + return false; +} + +inline bool one_of(tokenizer::iterator const& it, std::string const& value, + bool& present1, bool& present2) +{ + if (boost::iequals(*it, value)) + { + present1 = true; + present2 = true; + return true; + } + return false; +} + + +inline void handle_empty_z_m(tokenizer::iterator& it, tokenizer::iterator end, + bool& has_empty, bool& has_z, bool& has_m) +{ + has_empty = false; + has_z = false; + has_m = false; + + // WKT can optionally have Z and M (measured) values as in + // POINT ZM (1 1 5 60), POINT M (1 1 80), POINT Z (1 1 5) + // GGL supports any of them as coordinate values, but is not aware + // of any Measured value. + while (it != end + && (one_of(it, "M", has_m) + || one_of(it, "Z", has_z) + || one_of(it, "EMPTY", has_empty) + || one_of(it, "MZ", has_m, has_z) + || one_of(it, "ZM", has_z, has_m) + ) + ) + { + ++it; + } +} + +/*! +\brief Internal, starts parsing +\param tokens boost tokens, parsed with separator " " and keeping separator "()" +\param geometry string to compare with first token +*/ +template <typename Geometry> +inline bool initialize(tokenizer const& tokens, + std::string const& geometry_name, std::string const& wkt, + tokenizer::iterator& it) +{ + it = tokens.begin(); + if (it != tokens.end() && boost::iequals(*it++, geometry_name)) + { + bool has_empty, has_z, has_m; + + handle_empty_z_m(it, tokens.end(), has_empty, has_z, has_m); + + if (has_z && dimension<Geometry>::type::value < 3) + { + throw read_wkt_exception("Z only allowed for 3 or more dimensions", wkt); + } + if (has_empty) + { + check_end(it, tokens.end(), wkt); + return false; + } + // M is ignored at all. + + return true; + } + throw read_wkt_exception(std::string("Should start with '") + geometry_name + "'", wkt); +} + + +template <typename Geometry, template<typename> class Parser, typename PrefixPolicy> +struct geometry_parser +{ + static inline void apply(std::string const& wkt, Geometry& geometry) + { + geometry::clear(geometry); + + tokenizer tokens(wkt, boost::char_separator<char>(" ", ",()")); + tokenizer::iterator it; + if (initialize<Geometry>(tokens, PrefixPolicy::apply(), wkt, it)) + { + Parser<Geometry>::apply(it, tokens.end(), wkt, geometry); + check_end(it, tokens.end(), wkt); + } + } +}; + + + + + +/*! +\brief Supports box parsing +\note OGC does not define the box geometry, and WKT does not support boxes. + However, to be generic GGL supports reading and writing from and to boxes. + Boxes are outputted as a standard POLYGON. GGL can read boxes from + a standard POLYGON, from a POLYGON with 2 points of from a BOX +\tparam Box the box +*/ +template <typename Box> +struct box_parser +{ + static inline void apply(std::string const& wkt, Box& box) + { + bool should_close = false; + tokenizer tokens(wkt, boost::char_separator<char>(" ", ",()")); + tokenizer::iterator it = tokens.begin(); + tokenizer::iterator end = tokens.end(); + if (it != end && boost::iequals(*it, "POLYGON")) + { + ++it; + bool has_empty, has_z, has_m; + handle_empty_z_m(it, end, has_empty, has_z, has_m); + if (has_empty) + { + assign_zero(box); + return; + } + handle_open_parenthesis(it, end, wkt); + should_close = true; + } + else if (it != end && boost::iequals(*it, "BOX")) + { + ++it; + } + else + { + throw read_wkt_exception("Should start with 'POLYGON' or 'BOX'", wkt); + } + + typedef typename point_type<Box>::type point_type; + std::vector<point_type> points; + container_inserter<point_type>::apply(it, end, wkt, std::back_inserter(points)); + + if (should_close) + { + handle_close_parenthesis(it, end, wkt); + } + check_end(it, end, wkt); + + int index = 0; + int n = boost::size(points); + if (n == 2) + { + index = 1; + } + else if (n == 4 || n == 5) + { + // In case of 4 or 5 points, we do not check the other ones, just + // take the opposite corner which is always 2 + index = 2; + } + else + { + throw read_wkt_exception("Box should have 2,4 or 5 points", wkt); + } + + geometry::detail::assign_point_to_index<min_corner>(points.front(), box); + geometry::detail::assign_point_to_index<max_corner>(points[index], box); + } +}; + + +/*! +\brief Supports segment parsing +\note OGC does not define the segment, and WKT does not support segmentes. + However, it is useful to implement it, also for testing purposes +\tparam Segment the segment +*/ +template <typename Segment> +struct segment_parser +{ + static inline void apply(std::string const& wkt, Segment& segment) + { + tokenizer tokens(wkt, boost::char_separator<char>(" ", ",()")); + tokenizer::iterator it = tokens.begin(); + tokenizer::iterator end = tokens.end(); + if (it != end && + (boost::iequals(*it, "SEGMENT") + || boost::iequals(*it, "LINESTRING") )) + { + ++it; + } + else + { + throw read_wkt_exception("Should start with 'LINESTRING' or 'SEGMENT'", wkt); + } + + typedef typename point_type<Segment>::type point_type; + std::vector<point_type> points; + container_inserter<point_type>::apply(it, end, wkt, std::back_inserter(points)); + + check_end(it, end, wkt); + + if (boost::size(points) == 2) + { + geometry::detail::assign_point_to_index<0>(points.front(), segment); + geometry::detail::assign_point_to_index<1>(points.back(), segment); + } + else + { + throw read_wkt_exception("Segment should have 2 points", wkt); + } + + } +}; + + + +}} // namespace detail::wkt +#endif // DOXYGEN_NO_DETAIL + +#ifndef DOXYGEN_NO_DISPATCH +namespace dispatch +{ + +template <typename Tag, typename Geometry> +struct read_wkt {}; + + +template <typename Point> +struct read_wkt<point_tag, Point> + : detail::wkt::geometry_parser + < + Point, + detail::wkt::point_parser, + detail::wkt::prefix_point + > +{}; + + +template <typename L> +struct read_wkt<linestring_tag, L> + : detail::wkt::geometry_parser + < + L, + detail::wkt::linestring_parser, + detail::wkt::prefix_linestring + > +{}; + +template <typename Ring> +struct read_wkt<ring_tag, Ring> + : detail::wkt::geometry_parser + < + Ring, + detail::wkt::ring_parser, + detail::wkt::prefix_polygon + > +{}; + +template <typename Geometry> +struct read_wkt<polygon_tag, Geometry> + : detail::wkt::geometry_parser + < + Geometry, + detail::wkt::polygon_parser, + detail::wkt::prefix_polygon + > +{}; + + +// Box (Non-OGC) +template <typename Box> +struct read_wkt<box_tag, Box> + : detail::wkt::box_parser<Box> +{}; + +// Segment (Non-OGC) +template <typename Segment> +struct read_wkt<segment_tag, Segment> + : detail::wkt::segment_parser<Segment> +{}; + + +} // namespace dispatch +#endif // DOXYGEN_NO_DISPATCH + +/*! +\brief Parses OGC Well-Known Text (\ref WKT) into a geometry (any geometry) +\ingroup wkt +\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 } +*/ +template <typename Geometry> +inline void read_wkt(std::string const& wkt, Geometry& geometry) +{ + geometry::concept::check<Geometry>(); + dispatch::read_wkt<typename tag<Geometry>::type, Geometry>::apply(wkt, geometry); +} + +}} // namespace boost::geometry + +#endif // BOOST_GEOMETRY_IO_WKT_READ_HPP diff --git a/boost/geometry/io/wkt/stream.hpp b/boost/geometry/io/wkt/stream.hpp new file mode 100644 index 0000000000..86e49fdaf1 --- /dev/null +++ b/boost/geometry/io/wkt/stream.hpp @@ -0,0 +1,40 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// 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. + +// 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_WKT_STREAM_HPP +#define BOOST_GEOMETRY_IO_WKT_STREAM_HPP + +#include <boost/geometry/io/wkt/write.hpp> + +// This short file contains only one manipulator, streaming as WKT +// Don't include this in any standard-included header file. + +// 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 +*/ +template<typename Char, typename Traits, typename Geometry> +inline std::basic_ostream<Char, Traits>& operator<< + ( + std::basic_ostream<Char, Traits> &os, + Geometry const& geom + ) +{ + os << boost::geometry::wkt(geom); + return os; +} + +#endif // BOOST_GEOMETRY_IO_WKT_STREAM_HPP diff --git a/boost/geometry/io/wkt/wkt.hpp b/boost/geometry/io/wkt/wkt.hpp new file mode 100644 index 0000000000..28bd1e42aa --- /dev/null +++ b/boost/geometry/io/wkt/wkt.hpp @@ -0,0 +1,25 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// 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. + +// 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_WKT_WKT_HPP +#define BOOST_GEOMETRY_IO_WKT_WKT_HPP + +#include <boost/geometry/io/wkt/read.hpp> +#include <boost/geometry/io/wkt/write.hpp> + +// BSG 2011-02-03 +// We don't include stream.hpp by default. That tries to stream anything not known +// by default (such as ttmath) and reports errors. +// Users can include stream.hpp themselves (if they want to) + +#endif // BOOST_GEOMETRY_IO_WKT_WKT_HPP diff --git a/boost/geometry/io/wkt/write.hpp b/boost/geometry/io/wkt/write.hpp new file mode 100644 index 0000000000..a3e3173d05 --- /dev/null +++ b/boost/geometry/io/wkt/write.hpp @@ -0,0 +1,376 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// 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. + +// 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_WKT_WRITE_HPP +#define BOOST_GEOMETRY_IO_WKT_WRITE_HPP + +#include <ostream> +#include <string> + +#include <boost/array.hpp> +#include <boost/concept/assert.hpp> +#include <boost/range.hpp> +#include <boost/typeof/typeof.hpp> + +#include <boost/geometry/algorithms/assign.hpp> +#include <boost/geometry/algorithms/convert.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> +#include <boost/geometry/geometries/ring.hpp> + +#include <boost/geometry/io/wkt/detail/prefix.hpp> + +namespace boost { namespace geometry +{ + +#ifndef DOXYGEN_NO_DETAIL +namespace detail { namespace wkt +{ + +template <typename P, int I, int Count> +struct stream_coordinate +{ + template <typename Char, typename Traits> + static inline void apply(std::basic_ostream<Char, Traits>& os, P const& p) + { + os << (I > 0 ? " " : "") << get<I>(p); + stream_coordinate<P, I + 1, Count>::apply(os, p); + } +}; + +template <typename P, int Count> +struct stream_coordinate<P, Count, Count> +{ + template <typename Char, typename Traits> + static inline void apply(std::basic_ostream<Char, Traits>&, P const&) + {} +}; + +struct prefix_linestring_par +{ + static inline const char* apply() { return "LINESTRING("; } +}; + +struct prefix_ring_par_par +{ + // Note, double parentheses are intentional, indicating WKT ring begin/end + static inline const char* apply() { return "POLYGON(("; } +}; + +struct opening_parenthesis +{ + static inline const char* apply() { return "("; } +}; + +struct closing_parenthesis +{ + static inline const char* apply() { return ")"; } +}; + +struct double_closing_parenthesis +{ + static inline const char* apply() { return "))"; } +}; + +/*! +\brief Stream points as \ref WKT +*/ +template <typename Point, typename Policy> +struct wkt_point +{ + template <typename Char, typename Traits> + static inline void apply(std::basic_ostream<Char, Traits>& os, Point const& p) + { + os << Policy::apply() << "("; + stream_coordinate<Point, 0, dimension<Point>::type::value>::apply(os, p); + os << ")"; + } +}; + +/*! +\brief Stream ranges as WKT +\note policy is used to stream prefix/postfix, enabling derived classes to override this +*/ +template <typename Range, typename PrefixPolicy, typename SuffixPolicy> +struct wkt_range +{ + template <typename Char, typename Traits> + static inline void apply(std::basic_ostream<Char, Traits>& os, + Range const& range) + { + typedef typename boost::range_iterator<Range const>::type iterator_type; + + bool first = true; + + os << PrefixPolicy::apply(); + + // TODO: check EMPTY here + + for (iterator_type it = boost::begin(range); + it != boost::end(range); + ++it) + { + os << (first ? "" : ","); + stream_coordinate + < + point_type, 0, dimension<point_type>::type::value + >::apply(os, *it); + first = false; + } + + os << SuffixPolicy::apply(); + } + +private: + typedef typename boost::range_value<Range>::type point_type; +}; + +/*! +\brief Stream sequence of points as WKT-part, e.g. (1 2),(3 4) +\note Used in polygon, all multi-geometries +*/ +template <typename Range> +struct wkt_sequence + : wkt_range + < + Range, + opening_parenthesis, + closing_parenthesis + > +{}; + +template <typename Polygon, typename PrefixPolicy> +struct wkt_poly +{ + template <typename Char, typename Traits> + static inline void apply(std::basic_ostream<Char, Traits>& os, + Polygon const& poly) + { + typedef typename ring_type<Polygon const>::type ring; + + os << PrefixPolicy::apply(); + // TODO: check EMPTY here + os << "("; + wkt_sequence<ring>::apply(os, exterior_ring(poly)); + + typename interior_return_type<Polygon const>::type rings + = interior_rings(poly); + for (BOOST_AUTO_TPL(it, boost::begin(rings)); it != boost::end(rings); ++it) + { + os << ","; + wkt_sequence<ring>::apply(os, *it); + } + os << ")"; + } +}; + +template <typename Box> +struct wkt_box +{ + typedef typename point_type<Box>::type point_type; + + template <typename Char, typename Traits> + static inline void apply(std::basic_ostream<Char, Traits>& os, + Box const& box) + { + // Convert to ring, then stream + typedef model::ring<point_type> ring_type; + ring_type ring; + geometry::convert(box, ring); + os << "POLYGON("; + wkt_sequence<ring_type>::apply(os, ring); + os << ")"; + } + + private: + + inline wkt_box() + { + // Only streaming of boxes with two dimensions is support, otherwise it is a polyhedron! + //assert_dimension<B, 2>(); + } +}; + + +template <typename Segment> +struct wkt_segment +{ + typedef typename point_type<Segment>::type point_type; + + template <typename Char, typename Traits> + static inline void apply(std::basic_ostream<Char, Traits>& os, + Segment const& segment) + { + // Convert to two points, then stream + typedef boost::array<point_type, 2> sequence; + + sequence points; + geometry::detail::assign_point_from_index<0>(segment, points[0]); + geometry::detail::assign_point_from_index<1>(segment, points[1]); + + // In Boost.Geometry a segment is represented + // in WKT-format like (for 2D): LINESTRING(x y,x y) + os << "LINESTRING"; + wkt_sequence<sequence>::apply(os, points); + } + + private: + + inline wkt_segment() + {} +}; + +}} // namespace detail::wkt +#endif // DOXYGEN_NO_DETAIL + +#ifndef DOXYGEN_NO_DISPATCH +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 Point> +struct wkt<point_tag, Point> + : detail::wkt::wkt_point + < + Point, + detail::wkt::prefix_point + > +{}; + +template <typename Linestring> +struct wkt<linestring_tag, Linestring> + : detail::wkt::wkt_range + < + Linestring, + detail::wkt::prefix_linestring_par, + detail::wkt::closing_parenthesis + > +{}; + +/*! +\brief Specialization to stream a box as WKT +\details A "box" does not exist in WKT. +It is therefore streamed as a polygon +*/ +template <typename Box> +struct wkt<box_tag, Box> + : detail::wkt::wkt_box<Box> +{}; + +template <typename Segment> +struct wkt<segment_tag, Segment> + : detail::wkt::wkt_segment<Segment> +{}; + +/*! +\brief Specialization to stream a ring as WKT +\details A ring or "linear_ring" does not exist in WKT. +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> + : detail::wkt::wkt_range + < + Ring, + detail::wkt::prefix_ring_par_par, + detail::wkt::double_closing_parenthesis + > +{}; + +/*! +\brief Specialization to stream polygon as WKT +*/ +template <typename Polygon> +struct wkt<polygon_tag, Polygon> + : detail::wkt::wkt_poly + < + Polygon, + detail::wkt::prefix_polygon + > +{}; + +} // namespace dispatch +#endif // DOXYGEN_NO_DISPATCH + +/*! +\brief Generic geometry template manipulator class, takes corresponding output class from traits class +\ingroup wkt +\details Stream manipulator, streams geometry classes as \ref WKT streams +\par Example: +Small example showing how to use the wkt class +\dontinclude doxygen_1.cpp +\skip example_as_wkt_point +\line { +\until } +*/ +template <typename Geometry> +class wkt_manipulator +{ +public: + + inline wkt_manipulator(Geometry const& g) + : m_geometry(g) + {} + + template <typename Char, typename Traits> + inline friend std::basic_ostream<Char, Traits>& operator<<( + std::basic_ostream<Char, Traits>& os, + wkt_manipulator const& m) + { + dispatch::wkt + < + typename tag<Geometry>::type, + Geometry + >::apply(os, m.m_geometry); + os.flush(); + return os; + } + +private: + Geometry const& m_geometry; +}; + +/*! +\brief Main WKT-streaming function +\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 } +*/ +template <typename Geometry> +inline wkt_manipulator<Geometry> wkt(Geometry const& geometry) +{ + concept::check<Geometry const>(); + + return wkt_manipulator<Geometry>(geometry); +} + +}} // namespace boost::geometry + +#endif // BOOST_GEOMETRY_IO_WKT_WRITE_HPP |