[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) 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 Bruno Lalande, Paris, France.
Copyright (c) 2009-2017 Mateusz Loskot <mateusz@loskot.net>, London, UK. Copyright (c) 2009-2017 Mateusz Loskot <mateusz@loskot.net>, London, UK.
Copyright (c) 2011-2017 Adam Wulkiewicz, Lodz, Poland. Copyright (c) 2011-2017 Adam Wulkiewicz, Lodz, Poland.
@ -19,6 +19,22 @@
[section:release_notes Release Notes] [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] [heading Boost 1.81]
[/=================] [/=================]

View File

@ -1,6 +1,6 @@
// Boost.Geometry (aka GGL, Generic Geometry Library) // 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) 2008-2012 Bruno Lalande, Paris, France.
// Copyright (c) 2009-2012 Mateusz Loskot, London, UK. // Copyright (c) 2009-2012 Mateusz Loskot, London, UK.
@ -57,6 +57,20 @@ struct prefix_multipolygon
static inline const char* apply() { return "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 }} // namespace wkt::impl
#endif #endif

View File

@ -1,6 +1,6 @@
// Boost.Geometry (aka GGL, Generic Geometry Library) // 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) 2008-2012 Bruno Lalande, Paris, France.
// Copyright (c) 2009-2012 Mateusz Loskot, London, UK. // 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 // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt) // http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_GEOMETRY_DOMAINS_GIS_IO_WKT_DETAIL_WKT_MULTI_HPP #ifndef BOOST_GEOMETRY_IO_WKT_MULTI_HPP
#define BOOST_GEOMETRY_DOMAINS_GIS_IO_WKT_DETAIL_WKT_MULTI_HPP #define BOOST_GEOMETRY_IO_WKT_MULTI_HPP
#include <boost/geometry/core/tags.hpp> #include <boost/geometry/core/tags.hpp>
#include <boost/geometry/domains/gis/io/wkt/write.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 #endif // BOOST_GEOMETRY_IO_WKT_MULTI_HPP
{
#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

View File

@ -1,6 +1,6 @@
// Boost.Geometry (aka GGL, Generic Geometry Library) // 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) 2008-2012 Bruno Lalande, Paris, France.
// Copyright (c) 2009-2012 Mateusz Loskot, London, UK. // Copyright (c) 2009-2012 Mateusz Loskot, London, UK.
// Copyright (c) 2017 Adam Wulkiewicz, Lodz, Poland. // Copyright (c) 2017 Adam Wulkiewicz, Lodz, Poland.
@ -117,19 +117,26 @@ private :
namespace detail { namespace wkt 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, template <typename Point,
std::size_t Dimension = 0, std::size_t Dimension = 0,
std::size_t DimensionCount = geometry::dimension<Point>::value> std::size_t DimensionCount = geometry::dimension<Point>::value>
struct parsing_assigner struct parsing_assigner
{ {
static inline void apply(tokenizer::iterator& it, template <typename TokenizerIterator>
tokenizer::iterator const& end, static inline void apply(TokenizerIterator& it,
TokenizerIterator const& end,
Point& point, Point& point,
std::string const& wkt) 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 ")" // Stop at end of tokens, or at "," ot ")"
bool finished = (it == end || *it == "," || *it == ")"); bool finished = (it == end || *it == "," || *it == ")");
@ -167,8 +174,9 @@ struct parsing_assigner
template <typename Point, std::size_t DimensionCount> template <typename Point, std::size_t DimensionCount>
struct parsing_assigner<Point, DimensionCount, DimensionCount> struct parsing_assigner<Point, DimensionCount, DimensionCount>
{ {
static inline void apply(tokenizer::iterator&, template <typename TokenizerIterator>
tokenizer::iterator const&, static inline void apply(TokenizerIterator&,
TokenizerIterator const&,
Point&, Point&,
std::string const&) std::string const&)
{ {
@ -226,9 +234,9 @@ template <typename Point>
struct container_inserter struct container_inserter
{ {
// Version with output iterator // Version with output iterator
template <typename OutputIterator> template <typename TokenizerIterator, typename OutputIterator>
static inline void apply(tokenizer::iterator& it, static inline void apply(TokenizerIterator& it,
tokenizer::iterator const& end, TokenizerIterator const& end,
std::string const& wkt, std::string const& wkt,
OutputIterator out) OutputIterator out)
{ {
@ -258,10 +266,8 @@ template <typename Geometry,
closure_selector Closure = closure<Geometry>::value> closure_selector Closure = closure<Geometry>::value>
struct stateful_range_appender struct stateful_range_appender
{ {
typedef typename geometry::point_type<Geometry>::type point_type;
// NOTE: Geometry is a reference // 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); geometry::append(geom, point);
} }
@ -270,13 +276,13 @@ struct stateful_range_appender
template <typename Geometry> template <typename Geometry>
struct stateful_range_appender<Geometry, open> struct stateful_range_appender<Geometry, open>
{ {
typedef typename geometry::point_type<Geometry>::type point_type; using point_type = typename geometry::point_type<Geometry>::type;
typedef typename boost::range_size using size_type = typename boost::range_size
< <
typename util::remove_cptrref<Geometry>::type typename util::remove_cptrref<Geometry>::type
>::type size_type; >::type;
BOOST_STATIC_ASSERT(( util::is_ring<Geometry>::value )); BOOST_STATIC_ASSERT((util::is_ring<Geometry>::value));
inline stateful_range_appender() inline stateful_range_appender()
: pt_index(0) : pt_index(0)
@ -290,11 +296,10 @@ struct stateful_range_appender<Geometry, open>
if (pt_index == 0) if (pt_index == 0)
{ {
first_point = point; first_point = point;
//should_append = true;
} }
else 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 should_append
= is_next_expected = is_next_expected
|| pt_index < core_detail::closure::minimum_ring_size<open>::value || 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) static inline bool disjoint(point_type const& p1, point_type const& p2)
{ {
// TODO: pass strategy // TODO: pass strategy
typedef typename strategies::io::services::default_strategy using strategy_type = typename strategies::io::services::default_strategy
< <
point_type point_type
>::type strategy_type; >::type;
return detail::disjoint::disjoint_point_point(p1, p2, strategy_type()); return detail::disjoint::disjoint_point_point(p1, p2, strategy_type());
} }
@ -328,10 +333,11 @@ private:
template <typename Geometry> template <typename Geometry>
struct container_appender 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, template <typename TokenizerIterator>
tokenizer::iterator const& end, static inline void apply(TokenizerIterator& it,
TokenizerIterator const& end,
std::string const& wkt, std::string const& wkt,
Geometry out) Geometry out)
{ {
@ -367,8 +373,9 @@ struct container_appender
template <typename P> template <typename P>
struct point_parser struct point_parser
{ {
static inline void apply(tokenizer::iterator& it, template <typename TokenizerIterator>
tokenizer::iterator const& end, static inline void apply(TokenizerIterator& it,
TokenizerIterator const& end,
std::string const& wkt, std::string const& wkt,
P& point) P& point)
{ {
@ -382,8 +389,9 @@ struct point_parser
template <typename Geometry> template <typename Geometry>
struct linestring_parser struct linestring_parser
{ {
static inline void apply(tokenizer::iterator& it, template <typename TokenizerIterator>
tokenizer::iterator const& end, static inline void apply(TokenizerIterator& it,
TokenizerIterator const& end,
std::string const& wkt, std::string const& wkt,
Geometry& geometry) Geometry& geometry)
{ {
@ -395,8 +403,9 @@ struct linestring_parser
template <typename Ring> template <typename Ring>
struct ring_parser struct ring_parser
{ {
static inline void apply(tokenizer::iterator& it, template <typename TokenizerIterator>
tokenizer::iterator const& end, static inline void apply(TokenizerIterator& it,
TokenizerIterator const& end,
std::string const& wkt, std::string const& wkt,
Ring& ring) Ring& ring)
{ {
@ -417,11 +426,12 @@ struct ring_parser
template <typename Polygon> template <typename Polygon>
struct polygon_parser struct polygon_parser
{ {
typedef typename ring_return_type<Polygon>::type ring_return_type; using ring_return_type = typename ring_return_type<Polygon>::type;
typedef container_appender<ring_return_type> appender; using appender = container_appender<ring_return_type>;
static inline void apply(tokenizer::iterator& it, template <typename TokenizerIterator>
tokenizer::iterator const& end, static inline void apply(TokenizerIterator& it,
TokenizerIterator const& end,
std::string const& wkt, std::string const& wkt,
Polygon& poly) 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, std::string const& value,
bool& is_present) bool& is_present)
{ {
@ -469,7 +480,8 @@ inline bool one_of(tokenizer::iterator const& it,
return false; return false;
} }
inline bool one_of(tokenizer::iterator const& it, template <typename TokenizerIterator>
inline bool one_of(TokenizerIterator const& it,
std::string const& value, std::string const& value,
bool& present1, bool& present1,
bool& present2) bool& present2)
@ -484,8 +496,9 @@ inline bool one_of(tokenizer::iterator const& it,
} }
inline void handle_empty_z_m(tokenizer::iterator& it, template <typename TokenizerIterator>
tokenizer::iterator const& end, inline void handle_empty_z_m(TokenizerIterator& it,
TokenizerIterator const& end,
bool& has_empty, bool& has_empty,
bool& has_z, bool& has_z,
bool& has_m) bool& has_m)
@ -535,9 +548,9 @@ struct dimension<Geometry, geometry_collection_tag>
\brief Internal, starts parsing \brief Internal, starts parsing
\param geometry_name string to compare with first token \param geometry_name string to compare with first token
*/ */
template <typename Geometry> template <typename Geometry, typename TokenizerIterator>
inline bool initialize(tokenizer::iterator& it, inline bool initialize(TokenizerIterator& it,
tokenizer::iterator const& end, TokenizerIterator const& end,
std::string const& wkt, std::string const& wkt,
std::string const& geometry_name) std::string const& geometry_name)
{ {
@ -552,8 +565,8 @@ inline bool initialize(tokenizer::iterator& it,
// Silence warning C4127: conditional expression is constant // Silence warning C4127: conditional expression is constant
#if defined(_MSC_VER) #if defined(_MSC_VER)
#pragma warning(push) #pragma warning(push)
#pragma warning(disable : 4127) #pragma warning(disable : 4127)
#endif #endif
if (has_z && dimension<Geometry>::value < 3) if (has_z && dimension<Geometry>::value < 3)
@ -570,7 +583,7 @@ inline bool initialize(tokenizer::iterator& it,
return false; return false;
} }
// M is ignored at all. // M is ignored at all.
return true; return true;
} }
@ -582,17 +595,18 @@ struct geometry_parser
{ {
geometry::clear(geometry); geometry::clear(geometry);
tokenizer tokens(wkt, boost::char_separator<char>(" ", ",()")); auto const tokens{make_tokenizer(wkt)};
tokenizer::iterator it = tokens.begin(); auto it = tokens.begin();
tokenizer::iterator const end = tokens.end(); auto const end = tokens.end();
apply(it, end, wkt, geometry); apply(it, end, wkt, geometry);
check_end(it, end, wkt); check_end(it, end, wkt);
} }
static inline void apply(tokenizer::iterator& it, template <typename TokenizerIterator>
tokenizer::iterator const& end, static inline void apply(TokenizerIterator& it,
TokenizerIterator const& end,
std::string const& wkt, std::string const& wkt,
Geometry& geometry) Geometry& geometry)
{ {
@ -611,17 +625,18 @@ struct multi_parser
{ {
traits::clear<MultiGeometry>::apply(geometry); traits::clear<MultiGeometry>::apply(geometry);
tokenizer tokens(wkt, boost::char_separator<char>(" ", ",()")); auto const tokens{make_tokenizer(wkt)};
tokenizer::iterator it = tokens.begin(); auto it = tokens.begin();
tokenizer::iterator const end = tokens.end(); auto const end = tokens.end();
apply(it, end, wkt, geometry); apply(it, end, wkt, geometry);
check_end(it, end, wkt); check_end(it, end, wkt);
} }
static inline void apply(tokenizer::iterator& it, template <typename TokenizerIterator>
tokenizer::iterator const& end, static inline void apply(TokenizerIterator& it,
TokenizerIterator const& end,
std::string const& wkt, std::string const& wkt,
MultiGeometry& geometry) MultiGeometry& geometry)
{ {
@ -652,8 +667,9 @@ struct multi_parser
template <typename P> template <typename P>
struct noparenthesis_point_parser struct noparenthesis_point_parser
{ {
static inline void apply(tokenizer::iterator& it, template <typename TokenizerIterator>
tokenizer::iterator const& end, static inline void apply(TokenizerIterator& it,
TokenizerIterator const& end,
std::string const& wkt, std::string const& wkt,
P& point) P& point)
{ {
@ -668,17 +684,18 @@ struct multi_point_parser
{ {
traits::clear<MultiGeometry>::apply(geometry); traits::clear<MultiGeometry>::apply(geometry);
tokenizer tokens(wkt, boost::char_separator<char>(" ", ",()")); auto const tokens{make_tokenizer(wkt)};
tokenizer::iterator it = tokens.begin(); auto it = tokens.begin();
tokenizer::iterator const end = tokens.end(); auto const end = tokens.end();
apply(it, end, wkt, geometry); apply(it, end, wkt, geometry);
check_end(it, end, wkt); check_end(it, end, wkt);
} }
static inline void apply(tokenizer::iterator& it, template <typename TokenizerIterator>
tokenizer::iterator const& end, static inline void apply(TokenizerIterator& it,
TokenizerIterator const& end,
std::string const& wkt, std::string const& wkt,
MultiGeometry& geometry) MultiGeometry& geometry)
{ {
@ -735,17 +752,18 @@ struct box_parser
{ {
static inline void apply(std::string const& wkt, Box& box) static inline void apply(std::string const& wkt, Box& box)
{ {
tokenizer tokens(wkt, boost::char_separator<char>(" ", ",()")); auto const tokens{make_tokenizer(wkt)};
tokenizer::iterator it = tokens.begin(); auto it = tokens.begin();
tokenizer::iterator end = tokens.end(); auto end = tokens.end();
apply(it, end, wkt, box); apply(it, end, wkt, box);
check_end(it, end, wkt); check_end(it, end, wkt);
} }
static inline void apply(tokenizer::iterator& it, template <typename TokenizerIterator>
tokenizer::iterator const& end, static inline void apply(TokenizerIterator& it,
TokenizerIterator const& end,
std::string const& wkt, std::string const& wkt,
Box& box) Box& box)
{ {
@ -772,7 +790,7 @@ struct box_parser
BOOST_THROW_EXCEPTION(read_wkt_exception("Should start with 'POLYGON' or 'BOX'", wkt)); 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; std::vector<point_type> points;
container_inserter<point_type>::apply(it, end, wkt, std::back_inserter(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) static inline void apply(std::string const& wkt, Segment& segment)
{ {
tokenizer tokens(wkt, boost::char_separator<char>(" ", ",()")); auto const tokens{make_tokenizer(wkt)};
tokenizer::iterator it = tokens.begin(); auto it = tokens.begin();
tokenizer::iterator end = tokens.end(); auto end = tokens.end();
apply(it, end, wkt, segment); apply(it, end, wkt, segment);
check_end(it, end, wkt); check_end(it, end, wkt);
} }
static inline void apply(tokenizer::iterator& it, template <typename TokenizerIterator>
tokenizer::iterator const& end, static inline void apply(TokenizerIterator& it,
TokenizerIterator const& end,
std::string const& wkt, std::string const& wkt,
Segment& segment) 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; ++it;
} }
@ -838,7 +859,7 @@ struct segment_parser
BOOST_THROW_EXCEPTION(read_wkt_exception("Should start with 'LINESTRING' or 'SEGMENT'", wkt)); 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; std::vector<point_type> points;
container_inserter<point_type>::apply(it, end, wkt, std::back_inserter(points)); container_inserter<point_type>::apply(it, end, wkt, std::back_inserter(points));
@ -881,54 +902,67 @@ template
> >
struct dynamic_readwkt_caller struct dynamic_readwkt_caller
{ {
static inline void apply(tokenizer::iterator& it, template <typename TokenizerIterator>
tokenizer::iterator const& end, static inline void apply(TokenizerIterator& it,
TokenizerIterator const& end,
std::string const& wkt, std::string const& wkt,
Geometry& geometry) 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_linestring>(tag_linestring, it, end, wkt, geometry, false)
|| parse_geometry<util::is_segment>("LINESTRING", it, end, wkt, geometry); || 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_polygon>(tag_polygon, it, end, wkt, geometry, false)
|| parse_geometry<util::is_ring>("POLYGON", it, end, wkt, geometry, false) || parse_geometry<util::is_ring>(tag_polygon, it, end, wkt, geometry, false)
|| parse_geometry<util::is_box>("POLYGON", it, end, wkt, geometry); || 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 else
{ {
BOOST_THROW_EXCEPTION(read_wkt_exception( 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)); wkt));
} }
} }
@ -937,6 +971,7 @@ private:
template template
< <
template <typename> class UnaryPred, template <typename> class UnaryPred,
typename TokenizerIterator,
typename Geom = typename util::sequence_find_if typename Geom = typename util::sequence_find_if
< <
typename traits::geometry_types<Geometry>::type, UnaryPred typename traits::geometry_types<Geometry>::type, UnaryPred
@ -944,8 +979,8 @@ private:
std::enable_if_t<! std::is_void<Geom>::value, int> = 0 std::enable_if_t<! std::is_void<Geom>::value, int> = 0
> >
static bool parse_geometry(const char * , static bool parse_geometry(const char * ,
tokenizer::iterator& it, TokenizerIterator& it,
tokenizer::iterator const& end, TokenizerIterator const& end,
std::string const& wkt, std::string const& wkt,
Geometry& geometry, Geometry& geometry,
bool = true) bool = true)
@ -959,6 +994,7 @@ private:
template template
< <
template <typename> class UnaryPred, template <typename> class UnaryPred,
typename TokenizerIterator,
typename Geom = typename util::sequence_find_if typename Geom = typename util::sequence_find_if
< <
typename traits::geometry_types<Geometry>::type, UnaryPred typename traits::geometry_types<Geometry>::type, UnaryPred
@ -966,8 +1002,8 @@ private:
std::enable_if_t<std::is_void<Geom>::value, int> = 0 std::enable_if_t<std::is_void<Geom>::value, int> = 0
> >
static bool parse_geometry(const char * name, static bool parse_geometry(const char * name,
tokenizer::iterator& , TokenizerIterator& ,
tokenizer::iterator const& , TokenizerIterator const& ,
std::string const& wkt, std::string const& wkt,
Geometry& , Geometry& ,
bool throw_on_misfit = true) 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) static inline void apply(std::string const& wkt, DynamicGeometry& dynamic_geometry)
{ {
detail::wkt::tokenizer tokens(wkt, boost::char_separator<char>(" ", ",()")); auto tokens{detail::wkt::make_tokenizer(wkt)};
detail::wkt::tokenizer::iterator it = tokens.begin(); auto it = tokens.begin();
detail::wkt::tokenizer::iterator end = tokens.end(); auto end = tokens.end();
if (it == end) if (it == end)
{ {
BOOST_THROW_EXCEPTION(read_wkt_exception( 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)); wkt));
} }
@ -1111,21 +1147,23 @@ struct read_wkt<Geometry, geometry_collection_tag>
{ {
range::clear(geometry); range::clear(geometry);
detail::wkt::tokenizer tokens(wkt, boost::char_separator<char>(" ", ",()")); auto tokens{detail::wkt::make_tokenizer(wkt)};
detail::wkt::tokenizer::iterator it = tokens.begin(); auto it = tokens.begin();
detail::wkt::tokenizer::iterator const end = tokens.end(); auto const end = tokens.end();
apply(it, end, wkt, geometry); apply(it, end, wkt, geometry);
detail::wkt::check_end(it, end, wkt); detail::wkt::check_end(it, end, wkt);
} }
static inline void apply(detail::wkt::tokenizer::iterator& it, template <typename TokenizerIterator>
detail::wkt::tokenizer::iterator const& end, static inline void apply(TokenizerIterator& it,
TokenizerIterator const& end,
std::string const& wkt, std::string const& wkt,
Geometry& geometry) 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); detail::wkt::handle_open_parenthesis(it, end, wkt);

View File

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

View File

@ -14,8 +14,7 @@
#ifndef BOOST_GEOMETRY_MULTI_IO_WKT_DETAIL_PREFIX_HPP #ifndef BOOST_GEOMETRY_MULTI_IO_WKT_DETAIL_PREFIX_HPP
#define BOOST_GEOMETRY_MULTI_IO_WKT_DETAIL_PREFIX_HPP #define BOOST_GEOMETRY_MULTI_IO_WKT_DETAIL_PREFIX_HPP
#include <boost/config/pragma_message.hpp>
#include <boost/geometry/io/wkt/detail/prefix.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 #endif // BOOST_GEOMETRY_MULTI_IO_WKT_DETAIL_PREFIX_HPP

View File

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

View File

@ -1,7 +1,7 @@
// Boost.Geometry (aka GGL, Generic Geometry Library) // Boost.Geometry (aka GGL, Generic Geometry Library)
// Unit Test // 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) 2008-2012 Bruno Lalande, Paris, France.
// Copyright (c) 2009-2012 Mateusz Loskot, London, UK. // 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> template <typename G>
void check_to_wkt(G const& geometry, std::string const& expected) void check_to_wkt(G const& geometry, std::string const& expected)
{ {
std::string out_string; std::string const out = bg::to_wkt(geometry);
out_string = bg::to_wkt(geometry); BOOST_CHECK_EQUAL(boost::to_upper_copy(out),
BOOST_CHECK_EQUAL(boost::to_upper_copy(out_string),
boost::to_upper_copy(expected)); boost::to_upper_copy(expected));
} }
@ -156,7 +155,6 @@ void test_wkt(std::string const& wkt,
template <typename G> template <typename G>
void test_relaxed_wkt_read_write(std::string const& wkt, std::string const& expected) void test_relaxed_wkt_read_write(std::string const& wkt, std::string const& expected)
{ {
std::string e;
G geometry; G geometry;
bg::read_wkt(wkt, geometry); bg::read_wkt(wkt, geometry);
std::ostringstream out; std::ostringstream out;
@ -168,11 +166,9 @@ void test_relaxed_wkt_read_write(std::string const& wkt, std::string const& expe
template <typename G> template <typename G>
void test_relaxed_wkt_to_from(std::string const& wkt, std::string const& expected) void test_relaxed_wkt_to_from(std::string const& wkt, std::string const& expected)
{ {
std::string e;
G geometry; G geometry;
geometry = bg::from_wkt<G>(wkt); geometry = bg::from_wkt<G>(wkt);
std::string out; std::string const out = bg::to_wkt(geometry);
out = bg::to_wkt(geometry);
BOOST_CHECK_EQUAL(boost::to_upper_copy(out), boost::to_upper_copy(expected)); 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<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); 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)... test_relaxed_wkt<bg::model::linestring<P> >("LINESTRING EMPTY", "LINESTRING()");
// ...or even POINT() (see below) test_relaxed_wkt<bg::model::polygon<P> >("POLYGON EMPTY", "POLYGON()");
test_wkt<bg::model::linestring<P> >("LINESTRING()", 0, 0); test_relaxed_wkt<bg::model::ring<P> >("POLYGON EMPTY", "POLYGON()");
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.
// 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 // 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(1)", "POINT(1 0)");
test_relaxed_wkt<P>("POINT()", "POINT(0 0)"); test_relaxed_wkt<P>("POINT()", "POINT(0 0)");
test_relaxed_wkt<bg::model::linestring<P> >("LINESTRING(1,2,3)", test_relaxed_wkt<bg::model::linestring<P> >("LINESTRING(1,2,3)", "LINESTRING(1 0,2 0,3 0)");
"LINESTRING(1 0,2 0,3 0)");
test_relaxed_wkt<P>("POINT ( 1 2) ", "POINT(1 2)"); test_relaxed_wkt<P>("POINT ( 1 2) ", "POINT(1 2)");
test_relaxed_wkt<P>("POINT M ( 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::box<P> >("BOX(1 1,2 2)", "POLYGON((1 1,1 2,2 2,2 1,1 1))");
test_relaxed_wkt<bg::model::polygon<P> >("POLYGON( ( ) , ( ) , ( ) )", "POLYGON()");
test_relaxed_wkt<bg::model::linestring<P> >("LINESTRING EMPTY", "LINESTRING()");
test_relaxed_wkt<bg::model::polygon<P> >("POLYGON( ( ) , ( ) , ( ) )",
"POLYGON((),(),())");
// Wrong WKT's // Wrong WKT's
test_wrong_wkt<P>("POINT(1 2", "expected ')'"); test_wrong_wkt<P>("POINT(1 2", "expected ')'");
@ -398,33 +397,3 @@ int test_main(int, char* [])
return 0; 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) // Boost.Geometry (aka GGL, Generic Geometry Library)
// Unit Test // 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) 2008-2015 Bruno Lalande, Paris, France.
// Copyright (c) 2009-2015 Mateusz Loskot, London, UK. // 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_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); 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 // Support for the official alternative syntax for multipoint
// (provided by Aleksey Tulinov): // (provided by Aleksey Tulinov):
test_relaxed_wkt<bg::model::multi_point<P> >("multipoint(1 2,3 4)", "multipoint((1 2),(3 4))"); 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>(); 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)))'))
*/