[wkt] support tabs, newlines and code cleanup

This commit is contained in:
Barend Gehrels 2022-12-27 13:01:09 +01:00
parent 6a7224e369
commit f92671b933
9 changed files with 292 additions and 315 deletions

View File

@ -1,7 +1,7 @@
[/============================================================================
Boost.Geometry (aka GGL, Generic Geometry Library)
Copyright (c) 2009-2022 Barend Gehrels, Geodan, Amsterdam, the Netherlands.
Copyright (c) 2009-2023 Barend Gehrels, Geodan, Amsterdam, the Netherlands.
Copyright (c) 2009-2017 Bruno Lalande, Paris, France.
Copyright (c) 2009-2017 Mateusz Loskot <mateusz@loskot.net>, London, UK.
Copyright (c) 2011-2017 Adam Wulkiewicz, Lodz, Poland.
@ -19,6 +19,22 @@
[section:release_notes Release Notes]
[/=================]
[heading Boost 1.82]
[/=================]
[*Major improvements]
* [@https://github.com/boostorg/geometry/pull/1045 1045] Support geographic buffer for (multi)linestrings and (multi)polygons
[*Solved issues]
* [@https://github.com/boostorg/geometry/issues/705 705] WKT: allow tabs and new lines
[*Breaking changes]
* The WKT output presentation of an empty polygon is now POLYGON() to make it consistent with other geometries
[/=================]
[heading Boost 1.81]
[/=================]

View File

@ -1,6 +1,6 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
// Copyright (c) 2007-2022 Barend Gehrels, Amsterdam, the Netherlands.
// Copyright (c) 2008-2012 Bruno Lalande, Paris, France.
// Copyright (c) 2009-2012 Mateusz Loskot, London, UK.
@ -57,6 +57,20 @@ struct prefix_multipolygon
static inline const char* apply() { return "MULTIPOLYGON"; }
};
struct prefix_segment
{
static inline const char* apply() { return "SEGMENT"; }
};
struct prefix_box
{
static inline const char* apply() { return "BOX"; }
};
struct prefix_geometrycollection
{
static inline const char* apply() { return "GEOMETRYCOLLECTION"; }
};
}} // namespace wkt::impl
#endif

View File

@ -1,6 +1,6 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
// Copyright (c) 2007-2022 Barend Gehrels, Amsterdam, the Netherlands.
// Copyright (c) 2008-2012 Bruno Lalande, Paris, France.
// Copyright (c) 2009-2012 Mateusz Loskot, London, UK.
@ -11,46 +11,13 @@
// 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
#ifndef BOOST_GEOMETRY_IO_WKT_MULTI_HPP
#define BOOST_GEOMETRY_IO_WKT_MULTI_HPP
#include <boost/geometry/core/tags.hpp>
#include <boost/geometry/domains/gis/io/wkt/write.hpp>
#include <boost/config/pragma_message.hpp>
BOOST_PRAGMA_MESSAGE("This include file is deprecated and will be removed in the future.")
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
#endif // BOOST_GEOMETRY_IO_WKT_MULTI_HPP

View File

@ -1,6 +1,6 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
// Copyright (c) 2007-2022 Barend Gehrels, Amsterdam, the Netherlands.
// Copyright (c) 2008-2012 Bruno Lalande, Paris, France.
// Copyright (c) 2009-2012 Mateusz Loskot, London, UK.
// Copyright (c) 2017 Adam Wulkiewicz, Lodz, Poland.
@ -117,19 +117,26 @@ private :
namespace detail { namespace wkt
{
typedef boost::tokenizer<boost::char_separator<char> > tokenizer;
inline auto make_tokenizer(std::string const& wkt)
{
using separator = boost::char_separator<char>;
using tokenizer = boost::tokenizer<separator>;
const tokenizer tokens(wkt, separator(" \n\t\r", ",()"));
return tokens;
}
template <typename Point,
std::size_t Dimension = 0,
std::size_t DimensionCount = geometry::dimension<Point>::value>
struct parsing_assigner
{
static inline void apply(tokenizer::iterator& it,
tokenizer::iterator const& end,
template <typename TokenizerIterator>
static inline void apply(TokenizerIterator& it,
TokenizerIterator const& end,
Point& point,
std::string const& wkt)
{
typedef typename coordinate_type<Point>::type coordinate_type;
using coordinate_type = typename coordinate_type<Point>::type;
// Stop at end of tokens, or at "," ot ")"
bool finished = (it == end || *it == "," || *it == ")");
@ -167,8 +174,9 @@ struct parsing_assigner
template <typename Point, std::size_t DimensionCount>
struct parsing_assigner<Point, DimensionCount, DimensionCount>
{
static inline void apply(tokenizer::iterator&,
tokenizer::iterator const&,
template <typename TokenizerIterator>
static inline void apply(TokenizerIterator&,
TokenizerIterator const&,
Point&,
std::string const&)
{
@ -226,9 +234,9 @@ template <typename Point>
struct container_inserter
{
// Version with output iterator
template <typename OutputIterator>
static inline void apply(tokenizer::iterator& it,
tokenizer::iterator const& end,
template <typename TokenizerIterator, typename OutputIterator>
static inline void apply(TokenizerIterator& it,
TokenizerIterator const& end,
std::string const& wkt,
OutputIterator out)
{
@ -258,10 +266,8 @@ template <typename Geometry,
closure_selector Closure = closure<Geometry>::value>
struct stateful_range_appender
{
typedef typename geometry::point_type<Geometry>::type point_type;
// NOTE: Geometry is a reference
inline void append(Geometry geom, point_type const& point, bool)
inline void append(Geometry geom, typename geometry::point_type<Geometry>::type const& point, bool)
{
geometry::append(geom, point);
}
@ -270,11 +276,11 @@ struct stateful_range_appender
template <typename Geometry>
struct stateful_range_appender<Geometry, open>
{
typedef typename geometry::point_type<Geometry>::type point_type;
typedef typename boost::range_size
using point_type = typename geometry::point_type<Geometry>::type;
using size_type = typename boost::range_size
<
typename util::remove_cptrref<Geometry>::type
>::type size_type;
>::type;
BOOST_STATIC_ASSERT((util::is_ring<Geometry>::value));
@ -290,11 +296,10 @@ struct stateful_range_appender<Geometry, open>
if (pt_index == 0)
{
first_point = point;
//should_append = true;
}
else
{
// NOTE: if there is not enough Points, they're always appended
// NOTE: if there are not enough Points, they're always appended
should_append
= is_next_expected
|| pt_index < core_detail::closure::minimum_ring_size<open>::value
@ -312,10 +317,10 @@ private:
static inline bool disjoint(point_type const& p1, point_type const& p2)
{
// TODO: pass strategy
typedef typename strategies::io::services::default_strategy
using strategy_type = typename strategies::io::services::default_strategy
<
point_type
>::type strategy_type;
>::type;
return detail::disjoint::disjoint_point_point(p1, p2, strategy_type());
}
@ -328,10 +333,11 @@ private:
template <typename Geometry>
struct container_appender
{
typedef typename geometry::point_type<Geometry>::type point_type;
using point_type = typename geometry::point_type<Geometry>::type;
static inline void apply(tokenizer::iterator& it,
tokenizer::iterator const& end,
template <typename TokenizerIterator>
static inline void apply(TokenizerIterator& it,
TokenizerIterator const& end,
std::string const& wkt,
Geometry out)
{
@ -367,8 +373,9 @@ struct container_appender
template <typename P>
struct point_parser
{
static inline void apply(tokenizer::iterator& it,
tokenizer::iterator const& end,
template <typename TokenizerIterator>
static inline void apply(TokenizerIterator& it,
TokenizerIterator const& end,
std::string const& wkt,
P& point)
{
@ -382,8 +389,9 @@ struct point_parser
template <typename Geometry>
struct linestring_parser
{
static inline void apply(tokenizer::iterator& it,
tokenizer::iterator const& end,
template <typename TokenizerIterator>
static inline void apply(TokenizerIterator& it,
TokenizerIterator const& end,
std::string const& wkt,
Geometry& geometry)
{
@ -395,8 +403,9 @@ struct linestring_parser
template <typename Ring>
struct ring_parser
{
static inline void apply(tokenizer::iterator& it,
tokenizer::iterator const& end,
template <typename TokenizerIterator>
static inline void apply(TokenizerIterator& it,
TokenizerIterator const& end,
std::string const& wkt,
Ring& ring)
{
@ -417,11 +426,12 @@ struct ring_parser
template <typename Polygon>
struct polygon_parser
{
typedef typename ring_return_type<Polygon>::type ring_return_type;
typedef container_appender<ring_return_type> appender;
using ring_return_type = typename ring_return_type<Polygon>::type;
using appender = container_appender<ring_return_type>;
static inline void apply(tokenizer::iterator& it,
tokenizer::iterator const& end,
template <typename TokenizerIterator>
static inline void apply(TokenizerIterator& it,
TokenizerIterator const& end,
std::string const& wkt,
Polygon& poly)
{
@ -457,7 +467,8 @@ struct polygon_parser
};
inline bool one_of(tokenizer::iterator const& it,
template <typename TokenizerIterator>
inline bool one_of(TokenizerIterator const& it,
std::string const& value,
bool& is_present)
{
@ -469,7 +480,8 @@ inline bool one_of(tokenizer::iterator const& it,
return false;
}
inline bool one_of(tokenizer::iterator const& it,
template <typename TokenizerIterator>
inline bool one_of(TokenizerIterator const& it,
std::string const& value,
bool& present1,
bool& present2)
@ -484,8 +496,9 @@ inline bool one_of(tokenizer::iterator const& it,
}
inline void handle_empty_z_m(tokenizer::iterator& it,
tokenizer::iterator const& end,
template <typename TokenizerIterator>
inline void handle_empty_z_m(TokenizerIterator& it,
TokenizerIterator const& end,
bool& has_empty,
bool& has_z,
bool& has_m)
@ -535,9 +548,9 @@ struct dimension<Geometry, geometry_collection_tag>
\brief Internal, starts parsing
\param geometry_name string to compare with first token
*/
template <typename Geometry>
inline bool initialize(tokenizer::iterator& it,
tokenizer::iterator const& end,
template <typename Geometry, typename TokenizerIterator>
inline bool initialize(TokenizerIterator& it,
TokenizerIterator const& end,
std::string const& wkt,
std::string const& geometry_name)
{
@ -582,17 +595,18 @@ struct geometry_parser
{
geometry::clear(geometry);
tokenizer tokens(wkt, boost::char_separator<char>(" ", ",()"));
tokenizer::iterator it = tokens.begin();
tokenizer::iterator const end = tokens.end();
auto const tokens{make_tokenizer(wkt)};
auto it = tokens.begin();
auto const end = tokens.end();
apply(it, end, wkt, geometry);
check_end(it, end, wkt);
}
static inline void apply(tokenizer::iterator& it,
tokenizer::iterator const& end,
template <typename TokenizerIterator>
static inline void apply(TokenizerIterator& it,
TokenizerIterator const& end,
std::string const& wkt,
Geometry& geometry)
{
@ -611,17 +625,18 @@ struct multi_parser
{
traits::clear<MultiGeometry>::apply(geometry);
tokenizer tokens(wkt, boost::char_separator<char>(" ", ",()"));
tokenizer::iterator it = tokens.begin();
tokenizer::iterator const end = tokens.end();
auto const tokens{make_tokenizer(wkt)};
auto it = tokens.begin();
auto const end = tokens.end();
apply(it, end, wkt, geometry);
check_end(it, end, wkt);
}
static inline void apply(tokenizer::iterator& it,
tokenizer::iterator const& end,
template <typename TokenizerIterator>
static inline void apply(TokenizerIterator& it,
TokenizerIterator const& end,
std::string const& wkt,
MultiGeometry& geometry)
{
@ -652,8 +667,9 @@ struct multi_parser
template <typename P>
struct noparenthesis_point_parser
{
static inline void apply(tokenizer::iterator& it,
tokenizer::iterator const& end,
template <typename TokenizerIterator>
static inline void apply(TokenizerIterator& it,
TokenizerIterator const& end,
std::string const& wkt,
P& point)
{
@ -668,17 +684,18 @@ struct multi_point_parser
{
traits::clear<MultiGeometry>::apply(geometry);
tokenizer tokens(wkt, boost::char_separator<char>(" ", ",()"));
tokenizer::iterator it = tokens.begin();
tokenizer::iterator const end = tokens.end();
auto const tokens{make_tokenizer(wkt)};
auto it = tokens.begin();
auto const end = tokens.end();
apply(it, end, wkt, geometry);
check_end(it, end, wkt);
}
static inline void apply(tokenizer::iterator& it,
tokenizer::iterator const& end,
template <typename TokenizerIterator>
static inline void apply(TokenizerIterator& it,
TokenizerIterator const& end,
std::string const& wkt,
MultiGeometry& geometry)
{
@ -735,17 +752,18 @@ struct box_parser
{
static inline void apply(std::string const& wkt, Box& box)
{
tokenizer tokens(wkt, boost::char_separator<char>(" ", ",()"));
tokenizer::iterator it = tokens.begin();
tokenizer::iterator end = tokens.end();
auto const tokens{make_tokenizer(wkt)};
auto it = tokens.begin();
auto end = tokens.end();
apply(it, end, wkt, box);
check_end(it, end, wkt);
}
static inline void apply(tokenizer::iterator& it,
tokenizer::iterator const& end,
template <typename TokenizerIterator>
static inline void apply(TokenizerIterator& it,
TokenizerIterator const& end,
std::string const& wkt,
Box& box)
{
@ -772,7 +790,7 @@ struct box_parser
BOOST_THROW_EXCEPTION(read_wkt_exception("Should start with 'POLYGON' or 'BOX'", wkt));
}
typedef typename point_type<Box>::type point_type;
using point_type = typename point_type<Box>::type;
std::vector<point_type> points;
container_inserter<point_type>::apply(it, end, wkt, std::back_inserter(points));
@ -815,21 +833,24 @@ 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();
auto const tokens{make_tokenizer(wkt)};
auto it = tokens.begin();
auto end = tokens.end();
apply(it, end, wkt, segment);
check_end(it, end, wkt);
}
static inline void apply(tokenizer::iterator& it,
tokenizer::iterator const& end,
template <typename TokenizerIterator>
static inline void apply(TokenizerIterator& it,
TokenizerIterator const& end,
std::string const& wkt,
Segment& segment)
{
if (it != end && (boost::iequals(*it, "SEGMENT") || boost::iequals(*it, "LINESTRING")))
if (it != end
&& (boost::iequals(*it, prefix_segment::apply())
|| boost::iequals(*it, prefix_linestring::apply())))
{
++it;
}
@ -838,7 +859,7 @@ struct segment_parser
BOOST_THROW_EXCEPTION(read_wkt_exception("Should start with 'LINESTRING' or 'SEGMENT'", wkt));
}
typedef typename point_type<Segment>::type point_type;
using point_type = typename point_type<Segment>::type;
std::vector<point_type> points;
container_inserter<point_type>::apply(it, end, wkt, std::back_inserter(points));
@ -881,54 +902,67 @@ template
>
struct dynamic_readwkt_caller
{
static inline void apply(tokenizer::iterator& it,
tokenizer::iterator const& end,
template <typename TokenizerIterator>
static inline void apply(TokenizerIterator& it,
TokenizerIterator const& end,
std::string const& wkt,
Geometry& geometry)
{
if (boost::iequals(*it, "POINT"))
static const char* tag_point = prefix_point::apply();
static const char* tag_linestring = prefix_linestring::apply();
static const char* tag_polygon = prefix_polygon::apply();
static const char* tag_multi_point = prefix_multipoint::apply();
static const char* tag_multi_linestring = prefix_multilinestring::apply();
static const char* tag_multi_polygon = prefix_multipolygon::apply();
static const char* tag_segment = prefix_segment::apply();
static const char* tag_box = prefix_box::apply();
static const char* tag_gc = prefix_geometrycollection::apply();
if (boost::iequals(*it, tag_point))
{
parse_geometry<util::is_point>("POINT", it, end, wkt, geometry);
parse_geometry<util::is_point>(tag_point, it, end, wkt, geometry);
}
else if (boost::iequals(*it, "MULTIPOINT"))
else if (boost::iequals(*it, tag_multi_point))
{
parse_geometry<util::is_multi_point>("MULTIPOINT", it, end, wkt, geometry);
parse_geometry<util::is_multi_point>(tag_multi_point, it, end, wkt, geometry);
}
else if (boost::iequals(*it, "SEGMENT"))
else if (boost::iequals(*it, tag_segment))
{
parse_geometry<util::is_segment>("SEGMENT", it, end, wkt, geometry);
parse_geometry<util::is_segment>(tag_segment, it, end, wkt, geometry);
}
else if (boost::iequals(*it, "LINESTRING"))
else if (boost::iequals(*it, tag_linestring))
{
parse_geometry<util::is_linestring>("LINESTRING", it, end, wkt, geometry, false)
|| parse_geometry<util::is_segment>("LINESTRING", it, end, wkt, geometry);
parse_geometry<util::is_linestring>(tag_linestring, it, end, wkt, geometry, false)
|| parse_geometry<util::is_segment>(tag_linestring, it, end, wkt, geometry);
}
else if (boost::iequals(*it, "MULTILINESTRING"))
else if (boost::iequals(*it, tag_multi_linestring))
{
parse_geometry<util::is_multi_linestring>("MULTILINESTRING", it, end, wkt, geometry);
parse_geometry<util::is_multi_linestring>(tag_multi_linestring, it, end, wkt, geometry);
}
else if (boost::iequals(*it, "BOX"))
else if (boost::iequals(*it, tag_box))
{
parse_geometry<util::is_box>("BOX", it, end, wkt, geometry);
parse_geometry<util::is_box>(tag_box, it, end, wkt, geometry);
}
else if (boost::iequals(*it, "POLYGON"))
else if (boost::iequals(*it, tag_polygon))
{
parse_geometry<util::is_polygon>("POLYGON", it, end, wkt, geometry, false)
|| parse_geometry<util::is_ring>("POLYGON", it, end, wkt, geometry, false)
|| parse_geometry<util::is_box>("POLYGON", it, end, wkt, geometry);
parse_geometry<util::is_polygon>(tag_polygon, it, end, wkt, geometry, false)
|| parse_geometry<util::is_ring>(tag_polygon, it, end, wkt, geometry, false)
|| parse_geometry<util::is_box>(tag_polygon, it, end, wkt, geometry);
}
else if (boost::iequals(*it, "MULTIPOLYGON"))
else if (boost::iequals(*it, tag_multi_polygon))
{
parse_geometry<util::is_multi_polygon>("MULTIPOLYGON", it, end, wkt, geometry);
parse_geometry<util::is_multi_polygon>(tag_multi_polygon, it, end, wkt, geometry);
}
else if (boost::iequals(*it, "GEOMETRYCOLLECTION"))
else if (boost::iequals(*it, tag_gc))
{
parse_geometry<util::is_geometry_collection>("GEOMETRYCOLLECTION", it, end, wkt, geometry);
parse_geometry<util::is_geometry_collection>(tag_gc, it, end, wkt, geometry);
}
else
{
BOOST_THROW_EXCEPTION(read_wkt_exception(
"Should start with geometry's name, e.g. 'POINT', 'LINESTRING', 'POLYGON', etc.",
"Should start with geometry's type, for example 'POINT', 'LINESTRING', 'POLYGON'",
wkt));
}
}
@ -937,6 +971,7 @@ private:
template
<
template <typename> class UnaryPred,
typename TokenizerIterator,
typename Geom = typename util::sequence_find_if
<
typename traits::geometry_types<Geometry>::type, UnaryPred
@ -944,8 +979,8 @@ private:
std::enable_if_t<! std::is_void<Geom>::value, int> = 0
>
static bool parse_geometry(const char * ,
tokenizer::iterator& it,
tokenizer::iterator const& end,
TokenizerIterator& it,
TokenizerIterator const& end,
std::string const& wkt,
Geometry& geometry,
bool = true)
@ -959,6 +994,7 @@ private:
template
<
template <typename> class UnaryPred,
typename TokenizerIterator,
typename Geom = typename util::sequence_find_if
<
typename traits::geometry_types<Geometry>::type, UnaryPred
@ -966,8 +1002,8 @@ private:
std::enable_if_t<std::is_void<Geom>::value, int> = 0
>
static bool parse_geometry(const char * name,
tokenizer::iterator& ,
tokenizer::iterator const& ,
TokenizerIterator& ,
TokenizerIterator const& ,
std::string const& wkt,
Geometry& ,
bool throw_on_misfit = true)
@ -1084,13 +1120,13 @@ struct read_wkt<DynamicGeometry, dynamic_geometry_tag>
{
static inline void apply(std::string const& wkt, DynamicGeometry& dynamic_geometry)
{
detail::wkt::tokenizer tokens(wkt, boost::char_separator<char>(" ", ",()"));
detail::wkt::tokenizer::iterator it = tokens.begin();
detail::wkt::tokenizer::iterator end = tokens.end();
auto tokens{detail::wkt::make_tokenizer(wkt)};
auto it = tokens.begin();
auto end = tokens.end();
if (it == end)
{
BOOST_THROW_EXCEPTION(read_wkt_exception(
"Should start with geometry's name, e.g. 'POINT', 'LINESTRING', 'POLYGON', etc.",
"Should start with geometry's type, for example 'POINT', 'LINESTRING', 'POLYGON'",
wkt));
}
@ -1111,21 +1147,23 @@ struct read_wkt<Geometry, geometry_collection_tag>
{
range::clear(geometry);
detail::wkt::tokenizer tokens(wkt, boost::char_separator<char>(" ", ",()"));
detail::wkt::tokenizer::iterator it = tokens.begin();
detail::wkt::tokenizer::iterator const end = tokens.end();
auto tokens{detail::wkt::make_tokenizer(wkt)};
auto it = tokens.begin();
auto const end = tokens.end();
apply(it, end, wkt, geometry);
detail::wkt::check_end(it, end, wkt);
}
static inline void apply(detail::wkt::tokenizer::iterator& it,
detail::wkt::tokenizer::iterator const& end,
template <typename TokenizerIterator>
static inline void apply(TokenizerIterator& it,
TokenizerIterator const& end,
std::string const& wkt,
Geometry& geometry)
{
if (detail::wkt::initialize<Geometry>(it, end, wkt, "GEOMETRYCOLLECTION"))
if (detail::wkt::initialize<Geometry>(it, end, wkt,
detail::wkt::prefix_geometrycollection::apply()))
{
detail::wkt::handle_open_parenthesis(it, end, wkt);

View File

@ -1,6 +1,6 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// Copyright (c) 2007-2017 Barend Gehrels, Amsterdam, the Netherlands.
// Copyright (c) 2007-2022 Barend Gehrels, Amsterdam, the Netherlands.
// Copyright (c) 2008-2017 Bruno Lalande, Paris, France.
// Copyright (c) 2009-2017 Mateusz Loskot, London, UK.
// Copyright (c) 2014-2017 Adam Wulkiewicz, Lodz, Poland.
@ -88,32 +88,6 @@ struct stream_coordinate<P, Count, Count>
{}
};
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
*/
@ -131,14 +105,13 @@ struct wkt_point
/*!
\brief Stream ranges as WKT
\note policy is used to stream prefix/postfix, enabling derived classes to override this
*/
template
<
typename Range,
bool ForceClosurePossible,
typename PrefixPolicy,
typename SuffixPolicy
bool ForceClosurePossible = false,
bool WriteDoubleBrackets = false
>
struct wkt_range
{
@ -146,22 +119,25 @@ struct wkt_range
static inline void apply(std::basic_ostream<Char, Traits>& os,
Range const& range, bool force_closure = ForceClosurePossible)
{
typedef typename boost::range_iterator<Range const>::type iterator_type;
typedef stream_coordinate
using stream_type = stream_coordinate
<
point_type, 0, dimension<point_type>::type::value
> stream_type;
>;
bool first = true;
os << PrefixPolicy::apply();
os << "(";
// TODO: check EMPTY here
iterator_type begin = boost::begin(range);
iterator_type end = boost::end(range);
for (iterator_type it = begin; it != end; ++it)
if (boost::size(range) > 0)
{
if (WriteDoubleBrackets)
{
os << "(";
}
auto begin = boost::begin(range);
auto end = boost::end(range);
for (auto it = begin; it != end; ++it)
{
os << (first ? "" : ",");
stream_type::apply(os, *it);
@ -177,21 +153,26 @@ struct wkt_range
os << ",";
stream_type::apply(os, *begin);
}
if (WriteDoubleBrackets)
{
os << ")";
}
}
os << SuffixPolicy::apply();
os << ")";
}
private:
typedef typename boost::range_value<Range>::type point_type;
using point_type = typename boost::range_value<Range>::type;
static inline bool disjoint(point_type const& p1, point_type const& p2)
{
// TODO: pass strategy
typedef typename strategies::io::services::default_strategy
using strategy_type = typename strategies::io::services::default_strategy
<
point_type
>::type strategy_type;
>::type;
return detail::disjoint::disjoint_point_point(p1, p2, strategy_type());
}
@ -206,9 +187,8 @@ struct wkt_sequence
: wkt_range
<
Range,
ForceClosurePossible,
opening_parenthesis,
closing_parenthesis
prefix_null,
ForceClosurePossible
>
{};
@ -219,21 +199,30 @@ struct wkt_poly
static inline void apply(std::basic_ostream<Char, Traits>& os,
Polygon const& poly, bool force_closure)
{
typedef typename ring_type<Polygon const>::type ring;
using ring = typename ring_type<Polygon const>::type;
auto const exterior = exterior_ring(poly);
auto const rings = interior_rings(poly);
std::size_t point_count = boost::size(exterior);
for (auto it = boost::begin(rings); it != boost::end(rings); ++it)
{
point_count += boost::size(*it);
}
os << PrefixPolicy::apply();
// TODO: check EMPTY here
os << "(";
wkt_sequence<ring>::apply(os, exterior_ring(poly), force_closure);
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 << "(";
if (point_count > 0)
{
wkt_sequence<ring>::apply(os, exterior, force_closure);
for (auto it = boost::begin(rings); it != boost::end(rings); ++it)
{
os << ",";
wkt_sequence<ring>::apply(os, *it, force_closure);
}
}
os << ")";
}
@ -247,13 +236,9 @@ struct wkt_multi
Multi const& geometry, bool force_closure)
{
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)
for (auto it = boost::begin(geometry); it != boost::end(geometry); ++it)
{
if (it != boost::begin(geometry))
{
@ -269,7 +254,7 @@ struct wkt_multi
template <typename Box>
struct wkt_box
{
typedef typename point_type<Box>::type point_type;
using point_type = typename point_type<Box>::type;
template <typename Char, typename Traits>
static inline void apply(std::basic_ostream<Char, Traits>& os,
@ -313,14 +298,14 @@ struct wkt_box
template <typename Segment>
struct wkt_segment
{
typedef typename point_type<Segment>::type point_type;
using point_type = typename point_type<Segment>::type;
template <typename Char, typename Traits>
static inline void apply(std::basic_ostream<Char, Traits>& os,
Segment const& segment, bool)
{
// Convert to two points, then stream
typedef boost::array<point_type, 2> sequence;
using sequence = boost::array<point_type, 2>;
sequence points;
geometry::detail::assign_point_from_index<0>(segment, points[0]);
@ -363,9 +348,7 @@ struct wkt<Linestring, linestring_tag>
: detail::wkt::wkt_range
<
Linestring,
false,
detail::wkt::prefix_linestring_par,
detail::wkt::closing_parenthesis
detail::wkt::prefix_linestring
>
{};
@ -395,9 +378,9 @@ struct wkt<Ring, ring_tag>
: detail::wkt::wkt_range
<
Ring,
detail::wkt::prefix_polygon,
true,
detail::wkt::prefix_ring_par_par,
detail::wkt::double_closing_parenthesis
true
>
{};

View File

@ -14,8 +14,7 @@
#ifndef BOOST_GEOMETRY_MULTI_IO_WKT_DETAIL_PREFIX_HPP
#define BOOST_GEOMETRY_MULTI_IO_WKT_DETAIL_PREFIX_HPP
#include <boost/geometry/io/wkt/detail/prefix.hpp>
#include <boost/config/pragma_message.hpp>
BOOST_PRAGMA_MESSAGE("This include file is deprecated and will be removed in the future.")
#endif // BOOST_GEOMETRY_MULTI_IO_WKT_DETAIL_PREFIX_HPP

View File

@ -87,12 +87,12 @@ void test_all()
"POLYGON EMPTY"
, 0
, "POLYGON(())"
, "POLYGON(())"
, "POLYGON()"
, "POLYGON()"
, ""
, 0
, "POLYGON(())"
, "POLYGON()"
);
test_geometry<bg::model::ring<P, true, false> > // open ring
(

View File

@ -1,7 +1,7 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// Unit Test
// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
// Copyright (c) 2007-2022 Barend Gehrels, Amsterdam, the Netherlands.
// Copyright (c) 2008-2012 Bruno Lalande, Paris, France.
// Copyright (c) 2009-2012 Mateusz Loskot, London, UK.
@ -51,9 +51,8 @@ void check_wkt(G const& geometry, std::string const& expected)
template <typename G>
void check_to_wkt(G const& geometry, std::string const& expected)
{
std::string out_string;
out_string = bg::to_wkt(geometry);
BOOST_CHECK_EQUAL(boost::to_upper_copy(out_string),
std::string const out = bg::to_wkt(geometry);
BOOST_CHECK_EQUAL(boost::to_upper_copy(out),
boost::to_upper_copy(expected));
}
@ -156,7 +155,6 @@ void test_wkt(std::string const& wkt,
template <typename G>
void test_relaxed_wkt_read_write(std::string const& wkt, std::string const& expected)
{
std::string e;
G geometry;
bg::read_wkt(wkt, geometry);
std::ostringstream out;
@ -168,11 +166,9 @@ void test_relaxed_wkt_read_write(std::string const& wkt, std::string const& expe
template <typename G>
void test_relaxed_wkt_to_from(std::string const& wkt, std::string const& expected)
{
std::string e;
G geometry;
geometry = bg::from_wkt<G>(wkt);
std::string out;
out = bg::to_wkt(geometry);
std::string const out = bg::to_wkt(geometry);
BOOST_CHECK_EQUAL(boost::to_upper_copy(out), boost::to_upper_copy(expected));
}
@ -328,29 +324,32 @@ void test_all()
//test_wkt<box<P> >("POLYGON((0 0,0 1,1 1,1 0,0 0))", 4, 0, 1, 4);
test_wkt<bg::model::ring<P> >("POLYGON((0 0,0 1,1 1,1 0,0 0))", 5, 0, 1, 4);
// We accept empty sequences as well (much better than EMPTY)...
// ...or even POINT() (see below)
test_wkt<bg::model::linestring<P> >("LINESTRING()", 0, 0);
test_wkt<bg::model::polygon<P> >("POLYGON(())", 0);
// ... or even with empty holes
test_wkt<bg::model::polygon<P> >("POLYGON((),(),())", 0);
// which all make no valid geometries, but they can exist.
test_relaxed_wkt<bg::model::linestring<P> >("LINESTRING EMPTY", "LINESTRING()");
test_relaxed_wkt<bg::model::polygon<P> >("POLYGON EMPTY", "POLYGON()");
test_relaxed_wkt<bg::model::ring<P> >("POLYGON EMPTY", "POLYGON()");
// Accept empty sequences as well
test_relaxed_wkt<bg::model::linestring<P> >("LINESTRING()", "LINESTRING()");
test_relaxed_wkt<bg::model::polygon<P> >("POLYGON()", "POLYGON()");
test_relaxed_wkt<bg::model::polygon<P> >("POLYGON(())", "POLYGON()");
test_relaxed_wkt<bg::model::polygon<P> >("POLYGON((),(),())", "POLYGON()");
// Invalid polygon with an inner ring coordinate is outputted as such
test_relaxed_wkt<bg::model::polygon<P> >("POLYGON((),(),(1 2))", "POLYGON((),(),(1 2))");
// Non OGC: tabs and returns are allowed and handled as normal white space.
test_relaxed_wkt<P>("POINT(1\n2)", "POINT(1 2)");
test_relaxed_wkt<P>("POINT(1\t2)", "POINT(1 2)");
test_relaxed_wkt<P>("POINT(1\r2)", "POINT(1 2)");
// These WKT's are incomplete or abnormal but they are considered OK
test_relaxed_wkt<P>("POINT(1)", "POINT(1 0)");
test_relaxed_wkt<P>("POINT()", "POINT(0 0)");
test_relaxed_wkt<bg::model::linestring<P> >("LINESTRING(1,2,3)",
"LINESTRING(1 0,2 0,3 0)");
test_relaxed_wkt<bg::model::linestring<P> >("LINESTRING(1,2,3)", "LINESTRING(1 0,2 0,3 0)");
test_relaxed_wkt<P>("POINT ( 1 2) ", "POINT(1 2)");
test_relaxed_wkt<P>("POINT M ( 1 2)", "POINT(1 2)");
test_relaxed_wkt<bg::model::box<P> >("BOX(1 1,2 2)", "POLYGON((1 1,1 2,2 2,2 1,1 1))");
test_relaxed_wkt<bg::model::linestring<P> >("LINESTRING EMPTY", "LINESTRING()");
test_relaxed_wkt<bg::model::polygon<P> >("POLYGON( ( ) , ( ) , ( ) )",
"POLYGON((),(),())");
test_relaxed_wkt<bg::model::polygon<P> >("POLYGON( ( ) , ( ) , ( ) )", "POLYGON()");
// Wrong WKT's
test_wrong_wkt<P>("POINT(1 2", "expected ')'");
@ -398,33 +397,3 @@ int test_main(int, char* [])
return 0;
}
/*
Results can be checked in PostGIS by query below,
or by MySQL (but replace length by glength and remove the perimeter)
Note:
- PostGIS gives "3" for a numpoints of a multi-linestring of 6 points in total (!)
--> "npoints" should be taken for all geometries
- SQL Server 2008 gives "6"
select geometry::STGeomFromText('MULTILINESTRING((1 1,2 2,3 3),(4 4,5 5,6 6))',0).STNumPoints()
- MySQL gives "NULL"
select 1 as code,'np p' as header,npoints(geomfromtext('POINT(1 2)')) as contents
union select 2,'length point', length(geomfromtext('POINT(1 2)'))
union select 3,'peri point', perimeter(geomfromtext('POINT(1 2)'))
union select 4,'area point',area(geomfromtext('POINT(1 2)'))
union select 5,'# ls',npoints(geomfromtext('LINESTRING(1 1,2 2,3 3)'))
union select 6,'length ls',length(geomfromtext('LINESTRING(1 1,2 2,3 3)'))
union select 7,'peri ls',perimeter(geomfromtext('LINESTRING(1 1,2 2,3 3)'))
union select 8,'aera ls',area(geomfromtext('LINESTRING(1 1,2 2,3 3)'))
union select 9,'# poly',npoints(geomfromtext('POLYGON((0 0,0 4,4 4,4 0,0 0),(1 1,1 2,2 2,2 1,1 1),(1 1,1 2,2 2,2 1,1 1))'))
union select 10,'length poly',length(geomfromtext('POLYGON((0 0,0 4,4 4,4 0,0 0),(1 1,1 2,2 2,2 1,1 1),(1 1,1 2,2 2,2 1,1 1))'))
union select 11,'peri poly',perimeter(geomfromtext('POLYGON((0 0,0 4,4 4,4 0,0 0),(1 1,1 2,2 2,2 1,1 1),(1 1,1 2,2 2,2 1,1 1))'))
union select 12,'area poly',area(geomfromtext('POLYGON((0 0,0 4,4 4,4 0,0 0),(1 1,1 2,2 2,2 1,1 1),(1 1,1 2,2 2,2 1,1 1))'))
*/

View File

@ -1,7 +1,7 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// Unit Test
// Copyright (c) 2007-2015 Barend Gehrels, Amsterdam, the Netherlands.
// Copyright (c) 2007-2022 Barend Gehrels, Amsterdam, the Netherlands.
// Copyright (c) 2008-2015 Bruno Lalande, Paris, France.
// Copyright (c) 2009-2015 Mateusz Loskot, London, UK.
@ -76,6 +76,18 @@ void test_all()
test_wkt<bg::model::multi_linestring<bg::model::linestring<P> > >("multilinestring((1 1,2 2,3 3),(4 4,5 5,6 6))", 6, 4 * sqrt(2.0));
test_wkt<bg::model::multi_polygon<bg::model::polygon<P> > >("multipolygon(((0 0,0 2,2 2,2 0,0 0),(1 1,1 2,2 2,2 1,1 1)),((0 0,0 4,4 4,4 0,0 0)))", 15, 0, 21, 28);
// Support tabs, and new lines.
test_relaxed_wkt<bg::model::multi_point<P> >("multipoint((1\t2),\n(3\r4))", "multipoint((1 2),(3 4))");
// Verify empty multi geometries
test_relaxed_wkt<bg::model::multi_point<P> >("multipoint()", "multipoint()");
test_relaxed_wkt<bg::model::multi_linestring<bg::model::linestring<P> >>("multilinestring()", "multilinestring()");
test_relaxed_wkt<bg::model::multi_polygon<bg::model::polygon<P> > >("multipolygon()", "multipolygon()");
test_relaxed_wkt<bg::model::multi_point<P> >("multipoint empty", "multipoint()");
test_relaxed_wkt<bg::model::multi_linestring<bg::model::linestring<P> >>("multilinestring empty", "multilinestring()");
test_relaxed_wkt<bg::model::multi_polygon<bg::model::polygon<P> > >("multipolygon empty", "multipolygon()");
// Support for the official alternative syntax for multipoint
// (provided by Aleksey Tulinov):
test_relaxed_wkt<bg::model::multi_point<P> >("multipoint(1 2,3 4)", "multipoint((1 2),(3 4))");
@ -103,24 +115,3 @@ void test_all()
test_order_closure<T>();
}
/*
... see comments in "wkt.cpp"
union select 13,'# mpoint',npoints(geomfromtext('MULTIPOINT((1 2),(3 4))'))
union select 14,'length mpoint',length(geomfromtext('MULTIPOINT((1 2),(3 4))'))
union select 15,'peri mpoint',perimeter(geomfromtext('MULTIPOINT((1 2),(3 4))'))
union select 16,'area mpoint',area(geomfromtext('MULTIPOINT((1 2),(3 4))'))
union select 17,'# mls',npoints(geomfromtext('MULTILINESTRING((1 1,2 2,3 3),(4 4,5 5,6 6))'))
union select 18,'length mls',length(geomfromtext('MULTILINESTRING((1 1,2 2,3 3),(4 4,5 5,6 6))'))
union select 19,'peri mls',perimeter(geomfromtext('MULTILINESTRING((1 1,2 2,3 3),(4 4,5 5,6 6))'))
union select 20,'area mls',area(geomfromtext('MULTILINESTRING((1 1,2 2,3 3),(4 4,5 5,6 6))'))
union select 21,'# mpoly',npoints(geomfromtext('MULTIPOLYGON(((0 0,0 2,2 2,2 0,0 0),(1 1,1 2,2 2,2 1,1 1)),((0 0,0 4,4 4,4 0,0 0)))'))
union select 22,'length mpoly',length(geomfromtext('MULTIPOLYGON(((0 0,0 2,2 2,2 0,0 0),(1 1,1 2,2 2,2 1,1 1)),((0 0,0 4,4 4,4 0,0 0)))'))
union select 23,'peri mpoly',perimeter(geomfromtext('MULTIPOLYGON(((0 0,0 2,2 2,2 0,0 0),(1 1,1 2,2 2,2 1,1 1)),((0 0,0 4,4 4,4 0,0 0)))'))
union select 24,'area mpoly',area(geomfromtext('MULTIPOLYGON(((0 0,0 2,2 2,2 0,0 0),(1 1,1 2,2 2,2 1,1 1)),((0 0,0 4,4 4,4 0,0 0)))'))
*/