[io][util] Add support for DynamicGeometry in read_wkt()

Replace variant support in wkt write.
Add util::sequence_find_if.
This commit is contained in:
Adam Wulkiewicz 2021-05-20 00:42:04 +02:00
parent 52c2723ef3
commit a1ccbcdea7
4 changed files with 161 additions and 54 deletions

View File

@ -44,12 +44,14 @@
#include <boost/geometry/core/exception.hpp> #include <boost/geometry/core/exception.hpp>
#include <boost/geometry/core/exterior_ring.hpp> #include <boost/geometry/core/exterior_ring.hpp>
#include <boost/geometry/core/geometry_id.hpp> #include <boost/geometry/core/geometry_id.hpp>
#include <boost/geometry/core/geometry_types.hpp>
#include <boost/geometry/core/interior_rings.hpp> #include <boost/geometry/core/interior_rings.hpp>
#include <boost/geometry/core/mutable_range.hpp> #include <boost/geometry/core/mutable_range.hpp>
#include <boost/geometry/core/point_type.hpp> #include <boost/geometry/core/point_type.hpp>
#include <boost/geometry/core/tag.hpp> #include <boost/geometry/core/tag.hpp>
#include <boost/geometry/core/tags.hpp> #include <boost/geometry/core/tags.hpp>
#include <boost/geometry/geometries/adapted/boost_variant.hpp> // For consistency with other functions
#include <boost/geometry/geometries/concepts/check.hpp> #include <boost/geometry/geometries/concepts/check.hpp>
#include <boost/geometry/io/wkt/detail/prefix.hpp> #include <boost/geometry/io/wkt/detail/prefix.hpp>
@ -60,6 +62,7 @@
#include <boost/geometry/util/coordinate_cast.hpp> #include <boost/geometry/util/coordinate_cast.hpp>
#include <boost/geometry/util/range.hpp> #include <boost/geometry/util/range.hpp>
#include <boost/geometry/util/sequence.hpp>
#include <boost/geometry/util/type_traits.hpp> #include <boost/geometry/util/type_traits.hpp>
namespace boost { namespace geometry namespace boost { namespace geometry
@ -791,7 +794,6 @@ struct segment_parser
} }
}; };
}} // namespace detail::wkt }} // namespace detail::wkt
#endif // DOXYGEN_NO_DETAIL #endif // DOXYGEN_NO_DETAIL
@ -799,12 +801,12 @@ struct segment_parser
namespace dispatch namespace dispatch
{ {
template <typename Tag, typename Geometry> template <typename Geometry, typename Tag = typename tag<Geometry>::type>
struct read_wkt {}; struct read_wkt {};
template <typename Point> template <typename Point>
struct read_wkt<point_tag, Point> struct read_wkt<Point, point_tag>
: detail::wkt::geometry_parser : detail::wkt::geometry_parser
< <
Point, Point,
@ -815,7 +817,7 @@ struct read_wkt<point_tag, Point>
template <typename L> template <typename L>
struct read_wkt<linestring_tag, L> struct read_wkt<L, linestring_tag>
: detail::wkt::geometry_parser : detail::wkt::geometry_parser
< <
L, L,
@ -825,7 +827,7 @@ struct read_wkt<linestring_tag, L>
{}; {};
template <typename Ring> template <typename Ring>
struct read_wkt<ring_tag, Ring> struct read_wkt<Ring, ring_tag>
: detail::wkt::geometry_parser : detail::wkt::geometry_parser
< <
Ring, Ring,
@ -835,7 +837,7 @@ struct read_wkt<ring_tag, Ring>
{}; {};
template <typename Geometry> template <typename Geometry>
struct read_wkt<polygon_tag, Geometry> struct read_wkt<Geometry, polygon_tag>
: detail::wkt::geometry_parser : detail::wkt::geometry_parser
< <
Geometry, Geometry,
@ -846,7 +848,7 @@ struct read_wkt<polygon_tag, Geometry>
template <typename MultiGeometry> template <typename MultiGeometry>
struct read_wkt<multi_point_tag, MultiGeometry> struct read_wkt<MultiGeometry, multi_point_tag>
: detail::wkt::multi_point_parser : detail::wkt::multi_point_parser
< <
MultiGeometry, MultiGeometry,
@ -855,7 +857,7 @@ struct read_wkt<multi_point_tag, MultiGeometry>
{}; {};
template <typename MultiGeometry> template <typename MultiGeometry>
struct read_wkt<multi_linestring_tag, MultiGeometry> struct read_wkt<MultiGeometry, multi_linestring_tag>
: detail::wkt::multi_parser : detail::wkt::multi_parser
< <
MultiGeometry, MultiGeometry,
@ -865,7 +867,7 @@ struct read_wkt<multi_linestring_tag, MultiGeometry>
{}; {};
template <typename MultiGeometry> template <typename MultiGeometry>
struct read_wkt<multi_polygon_tag, MultiGeometry> struct read_wkt<MultiGeometry, multi_polygon_tag>
: detail::wkt::multi_parser : detail::wkt::multi_parser
< <
MultiGeometry, MultiGeometry,
@ -877,17 +879,118 @@ struct read_wkt<multi_polygon_tag, MultiGeometry>
// Box (Non-OGC) // Box (Non-OGC)
template <typename Box> template <typename Box>
struct read_wkt<box_tag, Box> struct read_wkt<Box, box_tag>
: detail::wkt::box_parser<Box> : detail::wkt::box_parser<Box>
{}; {};
// Segment (Non-OGC) // Segment (Non-OGC)
template <typename Segment> template <typename Segment>
struct read_wkt<segment_tag, Segment> struct read_wkt<Segment, segment_tag>
: detail::wkt::segment_parser<Segment> : detail::wkt::segment_parser<Segment>
{}; {};
template <typename DynamicGeometry>
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();
if (it == end)
{
throw_unknown_name(wkt);
}
if (boost::iequals(*it, "POINT"))
{
parse_geometry<util::is_point>("POINT", wkt, dynamic_geometry);
}
else if (boost::iequals(*it, "MULTIPOINT"))
{
parse_geometry<util::is_multi_point>("MULTIPOINT", wkt, dynamic_geometry);
}
else if (boost::iequals(*it, "SEGMENT"))
{
parse_geometry<util::is_segment>("SEGMENT", wkt, dynamic_geometry);
}
else if (boost::iequals(*it, "LINESTRING"))
{
parse_geometry<util::is_linestring>("LINESTRING", wkt, dynamic_geometry, false)
|| parse_geometry<util::is_segment>("LINESTRING", wkt, dynamic_geometry);
}
else if (boost::iequals(*it, "MULTILINESTRING"))
{
parse_geometry<util::is_multi_linestring>("MULTILINESTRING", wkt, dynamic_geometry);
}
else if (boost::iequals(*it, "BOX"))
{
parse_geometry<util::is_box>("BOX", wkt, dynamic_geometry);
}
else if (boost::iequals(*it, "POLYGON"))
{
parse_geometry<util::is_polygon>("POLYGON", wkt, dynamic_geometry, false)
|| parse_geometry<util::is_ring>("POLYGON", wkt, dynamic_geometry, false)
|| parse_geometry<util::is_box>("POLYGON", wkt, dynamic_geometry);
}
else if (boost::iequals(*it, "MULTIPOLYGON"))
{
parse_geometry<util::is_multi_polygon>("MULTIPOLYGON", wkt, dynamic_geometry);
}
else
{
throw_unknown_name(wkt);
}
}
static void throw_unknown_name(std::string const& wkt)
{
BOOST_THROW_EXCEPTION(read_wkt_exception(
"Should start with geometry's name, e.g. 'POINT', 'LINESTRING', 'POLYGON', etc.",
wkt));
}
template
<
template <typename> class UnaryPred,
typename Geometry = typename util::sequence_find_if
<
typename traits::geometry_types<DynamicGeometry>::type, UnaryPred
>::type,
std::enable_if_t<! std::is_void<Geometry>::value, int> = 0
>
static bool parse_geometry(const char * , std::string const& wkt, DynamicGeometry & dynamic_geometry, bool = true)
{
Geometry g;
read_wkt<Geometry>::apply(wkt, g);
dynamic_geometry = std::move(g);
return true;
}
template
<
template <typename> class UnaryPred,
typename Geometry = typename util::sequence_find_if
<
typename traits::geometry_types<DynamicGeometry>::type, UnaryPred
>::type,
std::enable_if_t<std::is_void<Geometry>::value, int> = 0
>
static bool parse_geometry(const char * name, std::string const& wkt, DynamicGeometry & , bool throw_on_misfit = true)
{
if (throw_on_misfit)
{
std::string msg = std::string("Unable to store '") + name + "' in this geometry";
BOOST_THROW_EXCEPTION(read_wkt_exception(msg, wkt));
}
return false;
}
};
} // namespace dispatch } // namespace dispatch
#endif // DOXYGEN_NO_DISPATCH #endif // DOXYGEN_NO_DISPATCH
@ -904,7 +1007,7 @@ template <typename Geometry>
inline void read_wkt(std::string const& wkt, Geometry& geometry) inline void read_wkt(std::string const& wkt, Geometry& geometry)
{ {
geometry::concepts::check<Geometry>(); geometry::concepts::check<Geometry>();
dispatch::read_wkt<typename tag<Geometry>::type, Geometry>::apply(wkt, geometry); dispatch::read_wkt<Geometry>::apply(wkt, geometry);
} }
/*! /*!
@ -920,7 +1023,7 @@ inline Geometry from_wkt(std::string const& wkt)
{ {
Geometry geometry; Geometry geometry;
geometry::concepts::check<Geometry>(); geometry::concepts::check<Geometry>();
dispatch::read_wkt<typename tag<Geometry>::type, Geometry>::apply(wkt, geometry); dispatch::read_wkt<Geometry>::apply(wkt, geometry);
return geometry; return geometry;
} }

View File

@ -6,8 +6,8 @@
// Copyright (c) 2014-2017 Adam Wulkiewicz, Lodz, Poland. // Copyright (c) 2014-2017 Adam Wulkiewicz, Lodz, Poland.
// Copyright (c) 2020 Baidyanath Kundu, Haldia, India. // Copyright (c) 2020 Baidyanath Kundu, Haldia, India.
// This file was modified by Oracle on 2015-2020. // This file was modified by Oracle on 2015-2021.
// Modifications copyright (c) 2015-2020, Oracle and/or its affiliates. // Modifications copyright (c) 2015-2021, Oracle and/or its affiliates.
// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
@ -30,9 +30,6 @@
#include <boost/range/end.hpp> #include <boost/range/end.hpp>
#include <boost/range/size.hpp> #include <boost/range/size.hpp>
#include <boost/range/value_type.hpp> #include <boost/range/value_type.hpp>
#include <boost/variant/apply_visitor.hpp>
#include <boost/variant/static_visitor.hpp>
#include <boost/variant/variant_fwd.hpp>
#include <boost/geometry/algorithms/detail/interior_iterator.hpp> #include <boost/geometry/algorithms/detail/interior_iterator.hpp>
#include <boost/geometry/algorithms/assign.hpp> #include <boost/geometry/algorithms/assign.hpp>
@ -43,7 +40,9 @@
#include <boost/geometry/core/interior_rings.hpp> #include <boost/geometry/core/interior_rings.hpp>
#include <boost/geometry/core/ring_type.hpp> #include <boost/geometry/core/ring_type.hpp>
#include <boost/geometry/core/tags.hpp> #include <boost/geometry/core/tags.hpp>
#include <boost/geometry/core/visit.hpp>
#include <boost/geometry/geometries/adapted/boost_variant.hpp> // For backward compatibility
#include <boost/geometry/geometries/concepts/check.hpp> #include <boost/geometry/geometries/concepts/check.hpp>
#include <boost/geometry/geometries/ring.hpp> #include <boost/geometry/geometries/ring.hpp>
@ -458,44 +457,16 @@ struct wkt<Multi, multi_polygon_tag>
template <typename Geometry> template <typename Geometry>
struct devarianted_wkt struct wkt<Geometry, dynamic_geometry_tag>
{ {
template <typename OutputStream> template <typename OutputStream>
static inline void apply(OutputStream& os, Geometry const& geometry, static inline void apply(OutputStream& os, Geometry const& geometry,
bool force_closure) bool force_closure)
{ {
wkt<Geometry>::apply(os, geometry, force_closure); traits::visit<Geometry>::apply([&](auto const& g)
}
};
template <BOOST_VARIANT_ENUM_PARAMS(typename T)>
struct devarianted_wkt<variant<BOOST_VARIANT_ENUM_PARAMS(T)> >
{
template <typename OutputStream>
struct visitor: static_visitor<void>
{
OutputStream& m_os;
bool m_force_closure;
visitor(OutputStream& os, bool force_closure)
: m_os(os)
, m_force_closure(force_closure)
{}
template <typename Geometry>
inline void operator()(Geometry const& geometry) const
{ {
devarianted_wkt<Geometry>::apply(m_os, geometry, m_force_closure); wkt<util::remove_cref_t<decltype(g)>>::apply(os, g, force_closure);
} }, geometry);
};
template <typename OutputStream>
static inline void apply(
OutputStream& os,
variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& geometry,
bool force_closure)
{
boost::apply_visitor(visitor<OutputStream>(os, force_closure), geometry);
} }
}; };
@ -534,7 +505,7 @@ public:
std::basic_ostream<Char, Traits>& os, std::basic_ostream<Char, Traits>& os,
wkt_manipulator const& m) wkt_manipulator const& m)
{ {
dispatch::devarianted_wkt<Geometry>::apply(os, m.m_geometry, m.m_force_closure); dispatch::wkt<Geometry>::apply(os, m.m_geometry, m.m_force_closure);
os.flush(); os.flush();
return os; return os;
} }

View File

@ -112,6 +112,36 @@ struct sequence_empty
{}; {};
template
<
typename Sequence,
template <typename> class UnaryPred
>
struct sequence_find_if {};
template
<
typename T, typename ...Ts,
template <typename> class UnaryPred
>
struct sequence_find_if<type_sequence<T, Ts...>, UnaryPred>
: std::conditional
<
UnaryPred<T>::value,
T,
// TODO: prevent instantiation for the rest of the sequence if value is true
typename sequence_find_if<type_sequence<Ts...>, UnaryPred>::type
>
{};
template <template <typename> class UnaryPred>
struct sequence_find_if<type_sequence<>, UnaryPred>
{
// TODO: This is technically incorrect because void can be stored in a type_sequence
typedef void type;
};
// merge<type_sequence<A, B>, type_sequence<C, D>>::type is // merge<type_sequence<A, B>, type_sequence<C, D>>::type is
// type_sequence<A, B, C, D> // type_sequence<A, B, C, D>
// merge<integer_sequence<A, B>, integer_sequence<C, D>>::type is // merge<integer_sequence<A, B>, integer_sequence<C, D>>::type is

View File

@ -5,8 +5,8 @@
// 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.
// This file was modified by Oracle on 2014-2020. // This file was modified by Oracle on 2014-2021.
// Modifications copyright (c) 2014-2020 Oracle and/or its affiliates. // Modifications copyright (c) 2014-2021 Oracle and/or its affiliates.
// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
@ -94,7 +94,10 @@ void test_wkt_read_write(std::string const& wkt, std::string const& expected,
} }
check_wkt(geometry, expected); check_wkt(geometry, expected);
check_wkt(boost::variant<G>(geometry), expected);
boost::variant<G> v;
bg::read_wkt(wkt, v);
check_wkt(v, expected);
} }
template <typename G> template <typename G>