Merge branch 'feature/is_simple' of github.com:mkaravel/geometry into feature/is_simple

This commit is contained in:
Menelaos Karavelas
2014-06-04 12:10:38 +03:00
17 changed files with 2378 additions and 0 deletions

View File

@@ -0,0 +1,66 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// Copyright (c) 2014, Oracle and/or its affiliates.
// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
// Licensed under the Boost Software License version 1.0.
// http://www.boost.org/users/license.html
#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_SIMPLE_HAS_DUPLICATES_HPP
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_SIMPLE_HAS_DUPLICATES_HPP
#include <boost/assert.hpp>
#include <boost/range.hpp>
#include <boost/geometry/policies/compare.hpp>
namespace boost { namespace geometry
{
#ifndef DOXYGEN_NO_DETAIL
namespace detail { namespace is_simple
{
template <typename Range>
struct has_duplicates
{
static inline bool apply(Range const& range)
{
typedef typename boost::range_value<Range>::type point;
typedef typename boost::range_iterator<Range const>::type iterator;
BOOST_ASSERT( boost::size(range) > 0 );
if ( boost::size(range) == 1 )
{
return false;
}
geometry::equal_to<point> equal;
iterator it = boost::begin(range);
iterator next = ++boost::begin(range);
for (; next != boost::end(range); ++it, ++next)
{
if ( equal(*it, *next) )
{
return true;
}
}
return false;
}
};
}} // namespace detail::is_simple
#endif // DOXYGEN_NO_DETAIL
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_SIMPLE_HAS_DUPLICATES_HPP

View File

@@ -0,0 +1,312 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// Copyright (c) 2014, Oracle and/or its affiliates.
// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
// Licensed under the Boost Software License version 1.0.
// http://www.boost.org/users/license.html
#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_SIMPLE_LINEAR_HPP
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_SIMPLE_LINEAR_HPP
#include <algorithm>
#include <deque>
#include <boost/range.hpp>
#include <boost/geometry/core/tags.hpp>
#include <boost/geometry/multi/core/tags.hpp>
#include <boost/geometry/core/coordinate_type.hpp>
#include <boost/geometry/core/point_type.hpp>
#include <boost/geometry/policies/compare.hpp>
#include <boost/geometry/policies/robustness/segment_ratio.hpp>
#include <boost/geometry/algorithms/is_valid.hpp>
#include <boost/geometry/algorithms/detail/is_simple/has_duplicates.hpp>
#include <boost/geometry/algorithms/dispatch/is_simple.hpp>
#include <boost/geometry/multi/multi.hpp>
#include <boost/geometry/multi/algorithms/detail/sections/sectionalize.hpp>
#include <boost/geometry/algorithms/detail/overlay/self_turn_points.hpp>
#include <boost/geometry/io/dsv/write.hpp>
namespace boost { namespace geometry
{
#ifndef DOXYGEN_NO_DETAIL
namespace detail { namespace is_simple
{
template <typename Range>
struct is_simple_range
{
static inline bool apply(Range const& range)
{
// the second argument to apply refers to spikes:
// spikes are disallowed
if ( !dispatch::is_valid<Range>::apply(range, false) )
{
return false;
}
if ( has_duplicates<Range>::apply(range) )
{
return false;
}
return !geometry::intersects(range);
}
};
template <typename MultiRange>
struct is_simple_multi_range
{
static inline bool apply(MultiRange const& multi_range)
{
typedef typename boost::range_value<MultiRange>::type range;
typedef typename boost::range_iterator
<
MultiRange const
>::type iterator;
if ( boost::size(multi_range) == 0 )
{
return false;
}
for (iterator it = boost::begin(multi_range);
it != boost::end(multi_range); ++it)
{
if ( !is_simple_range<range>::apply(*it) )
{
return false;
}
}
return true;
}
};
template <typename MultiLinestring>
struct is_simple_multilinestring
{
template <typename Turn, typename Method, typename Operation>
static inline bool check_turn(Turn const& turn,
Method method,
Operation operation)
{
return turn.method == method
&& turn.operations[0].operation == operation
&& turn.operations[1].operation == operation;
}
template <typename Turn>
static inline bool is_acceptable_turn(Turn const& turn)
{
return check_turn(turn,
detail::overlay::method_none,
detail::overlay::operation_continue)
|| check_turn(turn,
detail::overlay::method_touch,
detail::overlay::operation_intersection)
|| check_turn(turn,
detail::overlay::method_touch,
detail::overlay::operation_blocked)
;
}
template <typename Point, typename Linestring>
static inline bool is_endpoint_of(Point const& point,
Linestring const& linestring)
{
BOOST_ASSERT( boost::size(linestring) > 1 );
return geometry::equals(point, *boost::begin(linestring))
|| geometry::equals(point, *boost::rbegin(linestring));
}
template <typename Linestring1, typename Linestring2>
static inline bool have_same_endpoints(Linestring1 const& ls1,
Linestring2 const& ls2)
{
return
(geometry::equals(*boost::begin(ls1), *boost::begin(ls2))
&& geometry::equals(*boost::rbegin(ls1), *boost::rbegin(ls2)))
||
(geometry::equals(*boost::begin(ls1), *boost::rbegin(ls2))
&& geometry::equals(*boost::rbegin(ls1), *boost::begin(ls2)))
;
}
static inline bool apply(MultiLinestring const& multilinestring)
{
if ( !is_simple_multi_range<MultiLinestring>::apply(multilinestring) )
{
return false;
}
typedef typename boost::range_value<MultiLinestring>::type linestring;
typedef typename point_type<MultiLinestring>::type point_type;
typedef point_type point;
typedef detail::overlay::turn_info
<
point_type,
geometry::segment_ratio
<
typename geometry::coordinate_type<point>::type
>
> turn_info;
std::deque<turn_info> turns;
typedef detail::overlay::get_turn_info
<
detail::disjoint::assign_disjoint_policy
> turn_policy;
detail::self_get_turn_points::no_interrupt_policy
interrupt_policy;
detail::self_get_turn_points::get_turns
<
turn_policy
>::apply(multilinestring,
detail::no_rescale_policy(),
turns,
interrupt_policy);
std::cout << "turns:";
for (typename std::deque<turn_info>::const_iterator tit = turns.begin();
tit != turns.end(); ++tit)
{
std::cout << " [" << geometry::method_char(tit->method);
std::cout << "," << geometry::operation_char(tit->operations[0].operation);
std::cout << "/" << geometry::operation_char(tit->operations[1].operation);
std::cout << " " << geometry::dsv(tit->point);
std::cout << "] ";
}
std::cout << std::endl << std::endl;
if ( turns.size() == 0 )
{
return true;
}
#ifdef GEOMETRY_TEST_DEBUG
std::vector<point_type> endpoints;
typename boost::range_iterator<MultiLinestring const>::type it;
for (it = boost::begin(multilinestring);
it != boost::end(multilinestring); ++it)
{
BOOST_ASSERT ( boost::size(*it) != 1 );
if ( boost::size(*it) != 0 )
{
endpoints.push_back( *boost::begin(*it) );
endpoints.push_back( *(--boost::end(*it)) );
}
}
std::sort(endpoints.begin(), endpoints.end(), geometry::less<point>());
std::cout << "endpoints: ";
for (typename std::vector<point>::iterator pit = endpoints.begin();
pit != endpoints.end(); ++pit)
{
std::cout << " " << geometry::dsv(*pit);
}
std::cout << std::endl << std::endl;
#endif
for (typename std::deque<turn_info>::const_iterator tit = turns.begin();
tit != turns.end(); ++tit)
{
#if 0
if ( !is_acceptable_turn(*tit) )
{
return false;
}
#endif
linestring const& ls1 =
*(boost::begin(multilinestring)
+ tit->operations[0].seg_id.multi_index);
linestring const& ls2 =
*(boost::begin(multilinestring)
+ tit->operations[0].other_id.multi_index);
if ( !is_endpoint_of(tit->point, ls1)
|| !is_endpoint_of(tit->point, ls2) )
{
return false;
}
#if 1
if ( boost::size(ls1) == 2
&& boost::size(ls2) == 2
&& have_same_endpoints(ls1, ls2) )
{
return false;
}
#endif
}
return true;
}
};
}} // namespace detail::is_simple
#endif // DOXYGEN_NO_DETAIL
#ifndef DOXYGEN_NO_DISPATCH
namespace dispatch
{
// A linestring is a curve.
// A curve is simple if it does not pass through the same point twice,
// with the possible exception of its two endpoints
//
// Reference: OGC 06-103r4 (§6.1.6.1)
template <typename Linestring>
struct is_simple<Linestring, linestring_tag>
: detail::is_simple::is_simple_range<Linestring>
{};
// A MultiLinestring is a MultiCurve
// A MultiCurve is simple if all of its elements are simple and the
// only intersections between any two elements occur at Points that
// are on the boundaries of both elements.
//
// Reference: OGC 06-103r4 (§6.1.8.1; Fig. 9)
template <typename MultiLinestring>
struct is_simple<MultiLinestring, multi_linestring_tag>
: detail::is_simple::is_simple_multilinestring<MultiLinestring>
{};
} // namespace dispatch
#endif // DOXYGEN_NO_DISPATCH
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_SIMPLE_LINEAR_HPP

View File

@@ -0,0 +1,102 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// Copyright (c) 2014, Oracle and/or its affiliates.
// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
// Licensed under the Boost Software License version 1.0.
// http://www.boost.org/users/license.html
#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_SIMPLE_POINTLIKE_HPP
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_SIMPLE_POINTLIKE_HPP
#include <algorithm>
#include <boost/range.hpp>
#include <boost/geometry/core/tags.hpp>
#include <boost/geometry/multi/core/tags.hpp>
#include <boost/geometry/core/point_type.hpp>
#include <boost/geometry/policies/compare.hpp>
#include <boost/geometry/algorithms/is_valid.hpp>
#include <boost/geometry/algorithms/detail/is_simple/has_duplicates.hpp>
#include <boost/geometry/algorithms/dispatch/is_simple.hpp>
namespace boost { namespace geometry
{
#ifndef DOXYGEN_NO_DETAIL
namespace detail { namespace is_simple
{
template <typename MultiPoint>
struct is_simple_multipoint
{
static inline bool apply(MultiPoint const& multipoint)
{
typedef typename point_type<MultiPoint>::type Point;
typedef typename boost::range_iterator
<
MultiPoint const
>::type iterator;
if ( !dispatch::is_valid<MultiPoint>::apply(multipoint) )
{
return false;
}
MultiPoint mp(multipoint);
std::sort(boost::begin(mp), boost::end(mp), geometry::less<Point>());
return !has_duplicates<MultiPoint>::apply(mp);
}
};
}} // namespace detail::is_simple
#endif // DOXYGEN_NO_DETAIL
#ifndef DOXYGEN_NO_DISPATCH
namespace dispatch
{
// A point is always simple
template <typename Point>
struct is_simple<Point, point_tag>
{
static inline bool apply(Point const&)
{
return true;
}
};
// A MultiPoint is simple if no two Points in the MultiPoint are equal
// (have identical coordinate values in X and Y)
//
// Reference: OGC 06-103r4 (§6.1.5)
template <typename MultiPoint>
struct is_simple<MultiPoint, multi_point_tag>
: detail::is_simple::is_simple_multipoint<MultiPoint>
{};
} // namespace dispatch
#endif // DOXYGEN_NO_DISPATCH
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_SIMPLE_POINTLIKE_HPP

View File

@@ -0,0 +1,86 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// Copyright (c) 2014, Oracle and/or its affiliates.
// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
// Licensed under the Boost Software License version 1.0.
// http://www.boost.org/users/license.html
#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_VALID_BOX_HPP
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_VALID_BOX_HPP
#include <cstddef>
#include <boost/geometry/core/access.hpp>
#include <boost/geometry/core/tags.hpp>
#include <boost/geometry/core/coordinate_dimension.hpp>
#include <boost/geometry/algorithms/dispatch/is_valid.hpp>
namespace boost { namespace geometry
{
#ifndef DOXYGEN_NO_DETAIL
namespace detail { namespace is_valid
{
template <typename Box, std::size_t I>
struct has_valid_corners
{
static inline bool apply(Box const& box)
{
if ( geometry::get<geometry::max_corner, I-1>(box)
<=
geometry::get<geometry::min_corner, I-1>(box) )
{
return false;
}
return has_valid_corners<Box, I-1>::apply(box);
}
};
template <typename Box>
struct has_valid_corners<Box, 0>
{
static inline bool apply(Box const& box)
{
return true;
}
};
}} // namespace detail::is_valid
#endif // DOXYGEN_NO_DETAIL
#ifndef DOXYGEN_NO_DISPATCH
namespace dispatch
{
// A box is always simple
// A box is a Polygon, and it satisfies the conditions for Polygon validity.
//
// The only thing we have to check is whether the max corner lies in
// the upper-right quadrant as defined by the min corner
//
// Reference (for polygon validity): OGC 06-103r4 (§6.1.11.1)
template <typename Box>
struct is_valid<Box, box_tag>
: detail::is_valid::has_valid_corners<Box, dimension<Box>::value>
{};
} // namespace dispatch
#endif // DOXYGEN_NO_DISPATCH
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_VALID_BOX_HPP

View File

@@ -0,0 +1,140 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// Copyright (c) 2014, Oracle and/or its affiliates.
// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
// Licensed under the Boost Software License version 1.0.
// http://www.boost.org/users/license.html
#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_VALID_HAS_SPIKES_HPP
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_VALID_HAS_SPIKES_HPP
#include <algorithm>
#include <boost/assert.hpp>
#include <boost/range.hpp>
#include <boost/geometry/core/closure.hpp>
#include <boost/geometry/core/point_type.hpp>
#include <boost/geometry/algorithms/equals.hpp>
#include <boost/geometry/algorithms/detail/point_is_spike_or_equal.hpp>
#include <boost/geometry/views/closeable_view.hpp>
namespace boost { namespace geometry
{
#ifndef DOXYGEN_NO_DETAIL
namespace detail { namespace is_valid
{
template <typename Point>
struct equal_to
{
Point const& m_point;
equal_to(Point const& point)
: m_point(point)
{}
template <typename OtherPoint>
inline bool operator()(OtherPoint const& other) const
{
return geometry::equals(m_point, other);
}
};
template <typename Point>
struct not_equal_to
{
Point const& m_point;
not_equal_to(Point const& point)
: m_point(point)
{}
template <typename OtherPoint>
inline bool operator()(OtherPoint const& other) const
{
return !geometry::equals(other, m_point);
}
};
template <typename Range, closure_selector Closure = closed>
struct has_spikes
{
static inline bool apply(Range const& range)
{
typedef typename point_type<Range>::type point;
typedef typename boost::range_iterator<Range const>::type iterator;
typedef not_equal_to<point> not_equal;
BOOST_ASSERT( boost::size(range) > 2 );
iterator prev = boost::begin(range);
iterator cur = std::find_if(prev, boost::end(range), not_equal(*prev));
BOOST_ASSERT( cur != boost::end(range) );
iterator next = std::find_if(cur, boost::end(range), not_equal(*cur));
BOOST_ASSERT( next != boost::end(range) );
while ( next != boost::end(range) )
{
if ( geometry::detail::point_is_spike_or_equal(*prev,
*next,
*cur) )
{
return true;
}
prev = cur;
cur = next;
next = std::find_if(cur, boost::end(range), not_equal(*cur));
}
if ( geometry::equals(*boost::begin(range), *boost::rbegin(range)) )
{
iterator cur = boost::begin(range);
typename boost::range_reverse_iterator
<
Range const
>::type prev = std::find_if(boost::rbegin(range),
boost::rend(range),
not_equal(*boost::rbegin(range)));
iterator next = std::find_if(cur, boost::end(range), not_equal(*cur));
return detail::point_is_spike_or_equal(*prev, *next, *cur);
}
return false;
}
};
template <typename Range>
struct has_spikes<Range, open>
{
static inline bool apply(Range const& range)
{
typedef typename closeable_view<Range, open>::type closed_view_type;
closed_view_type closed_range(const_cast<Range&>(range));
return has_spikes<closed_view_type, closed>::apply(closed_range);
}
};
}} // namespace detail::is_valid
#endif // DOXYGEN_NO_DETAIL
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_VALID_HAS_SPIKES_HPP

View File

@@ -0,0 +1,159 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// Copyright (c) 2014, Oracle and/or its affiliates.
// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
// Licensed under the Boost Software License version 1.0.
// http://www.boost.org/users/license.html
#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_VALID_LINESTRING_HPP
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_VALID_LINESTRING_HPP
#include <algorithm>
#include <boost/assert.hpp>
#include <boost/range.hpp>
#include <boost/geometry/core/point_type.hpp>
#include <boost/geometry/core/tags.hpp>
#include <boost/geometry/algorithms/equals.hpp>
#include <boost/geometry/algorithms/detail/is_valid/has_spikes.hpp>
#include <boost/geometry/algorithms/dispatch/is_valid.hpp>
namespace boost { namespace geometry
{
#ifndef DOXYGEN_NO_DETAIL
namespace detail { namespace is_valid
{
template <typename Range>
struct is_single_point
{
static inline bool apply(Range const& range)
{
typedef typename point_type<Range>::type point;
BOOST_ASSERT( boost::size(range) > 1 );
return std::find_if(++boost::begin(range),
boost::end(range),
not_equal_to<point>(*boost::begin(range))
)
== boost::end(range);
}
};
template <typename Range>
struct has_three_distinct_points
{
static inline bool apply(Range const& range)
{
typedef typename point_type<Range>::type point;
typedef typename boost::range_iterator<Range const>::type iterator;
BOOST_ASSERT( boost::size(range) > 1 );
iterator it1 =
std::find_if(boost::begin(range),
boost::end(range),
not_equal_to<point>(*boost::begin(range)));
BOOST_ASSERT( it1 != boost::end(range) );
iterator it2 =
std::find_if(it1,
boost::end(range),
not_equal_to<point>(*it1));
return it2 != boost::end(range)
&& !geometry::equals(*boost::begin(range), *it2);
}
};
template <typename Linestring>
struct is_valid_linestring
{
static inline bool apply(Linestring const& linestring,
bool allow_spikes)
{
std::size_t linestring_size = boost::size(linestring);
if ( linestring_size < 2 )
{
// if it has zero or one points is cannot be valid
return false;
}
if ( is_single_point<Linestring>::apply(linestring) )
{
// if it is an one-point linestring its dimension is 0,
// so not valid
return false;
}
BOOST_ASSERT( boost::size(linestring) > 1 );
if ( !has_three_distinct_points<Linestring>::apply(linestring) )
{
return !geometry::equals(*boost::begin(linestring),
*--boost::end(linestring));
}
return allow_spikes || !has_spikes<Linestring>::apply(linestring);
}
};
}} // namespace detail::is_valid
#endif // DOXYGEN_NO_DETAIL
#ifndef DOXYGEN_NO_DISPATCH
namespace dispatch
{
// A linestring is a curve.
// A curve is 1-dimensional so it has to have at least two distinct
// points.
// A curve is simple if it does not pass through the same point twice,
// with the possible exception of its two endpoints
//
// There is an open issue as to whether spikes are allowed for
// linestrings; here we pass this as an additional parameter: allow_spikes
// If allow_spikes is set to true, spikes are allowed, false otherwise.
// By default, spikes are disallowed
//
// Reference: OGC 06-103r4 (§6.1.6.1)
template <typename Linestring>
struct is_valid<Linestring, linestring_tag>
{
static inline bool apply(Linestring const& linestring,
bool allow_spikes = false)
{
return detail::is_valid::is_valid_linestring
<
Linestring
>::apply(linestring, allow_spikes);
}
};
} // namespace dispatch
#endif // DOXYGEN_NO_DISPATCH
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_VALID_LINESTRING_HPP

View File

@@ -0,0 +1,82 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// Copyright (c) 2014, Oracle and/or its affiliates.
// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
// Licensed under the Boost Software License version 1.0.
// http://www.boost.org/users/license.html
#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_VALID_MULTI_RANGE_HPP
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_VALID_MULTI_RANGE_HPP
#include <boost/range.hpp>
#include <boost/geometry/multi/core/tags.hpp>
#include <boost/geometry/algorithms/dispatch/is_valid.hpp>
namespace boost { namespace geometry
{
#ifndef DOXYGEN_NO_DETAIL
namespace detail { namespace is_valid
{
template <typename RangeValue>
struct is_valid_multi_range
{
template <typename RangeIterator>
static inline bool apply(RangeIterator first, RangeIterator beyond)
{
for (RangeIterator it = first; it != beyond; ++it)
{
if ( !dispatch::is_valid<RangeValue>::apply(*it) )
{
return false;
}
}
return first != beyond;
};
};
}} //namespace detail::is_valid
#endif // DOXYGEN_NO_DETAIL
#ifndef DOXYGEN_NO_DISPATCH
namespace dispatch
{
// A MultiLinestring is a MultiCurve
// A MultiCurve is simple if all of its elements are simple and the
// only intersections between any two elements occur at Points that
// are on the boundaries of both elements.
//
// Reference: OGC 06-103r4 (§6.1.8.1; Fig. 9)
template <typename MultiLinestring>
struct is_valid<MultiLinestring, multi_linestring_tag>
{
static inline bool apply(MultiLinestring const& multilinestring)
{
return detail::is_valid::is_valid_multi_range
<
typename boost::range_value<MultiLinestring>::type
>::apply(boost::begin(multilinestring),
boost::end(multilinestring));
}
};
} // namespace dispatch
#endif // DOXYGEN_NO_DISPATCH
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_VALID_MULTI_RANGE_HPP

View File

@@ -0,0 +1,63 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// Copyright (c) 2014, Oracle and/or its affiliates.
// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
// Licensed under the Boost Software License version 1.0.
// http://www.boost.org/users/license.html
#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_VALID_POINTLIKE_HPP
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_VALID_POINTLIKE_HPP
#include <boost/range.hpp>
#include <boost/geometry/core/tags.hpp>
#include <boost/geometry/multi/core/tags.hpp>
#include <boost/geometry/algorithms/dispatch/is_valid.hpp>
namespace boost { namespace geometry
{
#ifndef DOXYGEN_NO_DISPATCH
namespace dispatch
{
// A point is always simple
template <typename Point>
struct is_valid<Point, point_tag>
{
static inline bool apply(Point const&)
{
return true;
}
};
// A MultiPoint is simple if no two Points in the MultiPoint are equal
// (have identical coordinate values in X and Y)
//
// Reference: OGC 06-103r4 (§6.1.5)
template <typename MultiPoint>
struct is_valid<MultiPoint, multi_point_tag>
{
static inline bool apply(MultiPoint const& multipoint)
{
return boost::size(multipoint) > 0;
}
};
} // namespace dispatch
#endif // DOXYGEN_NO_DISPATCH
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_VALID_POINTLIKE_HPP

View File

@@ -0,0 +1,36 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// Copyright (c) 2014, Oracle and/or its affiliates.
// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
// Licensed under the Boost Software License version 1.0.
// http://www.boost.org/users/license.html
#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_VALID_POLYGON_HPP
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_VALID_POLYGON_HPP
namespace boost { namespace geometry
{
#ifndef DOXYGEN_NO_DETAIL
namespace detail { namespace is_valid
{
}} // namespace dispatch
#endif // DOXYGEN_NO_DETAIL
#ifndef DOXYGEN_NO_DISPATCH
namespace dispatch
{
} // namespace dispatch
#endif // DOXYGEN_NO_DISPATCH
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_VALID_POLYGON_HPP

View File

@@ -0,0 +1,172 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// Copyright (c) 2014, Oracle and/or its affiliates.
// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
// Licensed under the Boost Software License version 1.0.
// http://www.boost.org/users/license.html
#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_VALID_RING_HPP
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_VALID_RING_HPP
#include <boost/geometry/core/closure.hpp>
#include <boost/geometry/core/point_order.hpp>
#include <boost/geometry/algorithms/equals.hpp>
#include <boost/geometry/algorithms/not_implemented.hpp>
#include <boost/geometry/views/reversible_view.hpp>
#include <boost/geometry/views/closeable_view.hpp>
#include <boost/geometry/algorithms/detail/is_valid/has_spikes.hpp>
#include <boost/geometry/algorithms/detail/is_valid/linestring.hpp>
namespace boost { namespace geometry
{
#ifndef DOXYGEN_NO_DETAIL
namespace detail { namespace is_valid
{
// struct to check whether a ring is topologically closed
template <typename Ring, closure_selector Closure>
struct is_topologically_closed
{};
template <typename Ring>
struct is_topologically_closed<Ring, open>
{
static inline bool apply(Ring const&)
{
return true;
}
};
template <typename Ring>
struct is_topologically_closed<Ring, closed>
{
static inline bool apply(Ring const& ring)
{
return geometry::equals(*boost::begin(ring), *boost::rbegin(ring));
}
};
// struct to check if the size is above the minimal one
// (3 for open, 4 for closed)
template <typename Ring, closure_selector Closure>
struct is_below_minimal_size
{};
template <typename Ring>
struct is_below_minimal_size<Ring, closed>
{
static inline bool apply(Ring const& ring)
{
return boost::size(ring) < 4;
}
};
template <typename Ring>
struct is_below_minimal_size<Ring, open>
{
static inline bool apply(Ring const& ring)
{
return boost::size(ring) < 3;
}
};
template
<
typename Ring,
order_selector PointOrder,
closure_selector Closure
>
struct is_valid_ring
: not_implemented<Ring>
{};
template <typename Ring, closure_selector Closure>
struct is_valid_ring<Ring, counterclockwise, Closure>
{
static inline bool apply(Ring const& ring)
{
typedef typename reversible_view
<
Ring, iterate_reverse
>::type reversible_view_type;
reversible_view_type reversed_ring(const_cast<Ring&>(ring));
return is_valid_ring<Ring, clockwise, Closure>::apply(reversed_ring);
}
};
template <typename Ring, closure_selector Closure>
struct is_valid_ring<Ring, clockwise, Closure>
{
static inline bool apply(Ring const& ring)
{
// return invalid if any of the following condition holds:
// (a) the ring's size is below the minimal one
// (b) the ring has less than three distinct points
// (c) the ring is not topologically closed
// (d) the ring has spikes
//
// Note: no need to check if the area is zero. If this is the
// case, then the ring must have at least two spikes, which is
// checked by condition (d).
if ( is_below_minimal_size<Ring, Closure>::apply(ring)
|| !has_three_distinct_points<Ring>::apply(ring)
|| !is_topologically_closed<Ring, Closure>::apply(ring)
|| has_spikes<Ring>::apply(ring) )
{
return false;
}
// now call self turns to compute self intersections, if any,
// and analyze them
}
};
}} // namespace dispatch
#endif // DOXYGEN_NO_DETAIL
#ifndef DOXYGEN_NO_DISPATCH
namespace dispatch
{
// A Ring is a Polygon.
// A Polygon is always a simple geometric object provided that it is valid.
//
// Reference (for polygon validity): OGC 06-103r4 (§6.1.11.1)
template <typename Ring>
struct is_valid<Ring, ring_tag>
: detail::is_valid::is_valid_ring
<
Ring,
point_order<Ring>::value,
closure<Ring>::value
>
{};
} // namespace dispatch
#endif // DOXYGEN_NO_DISPATCH
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_VALID_RING_HPP

View File

@@ -0,0 +1,61 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// Copyright (c) 2014, Oracle and/or its affiliates.
// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
// Licensed under the Boost Software License version 1.0.
// http://www.boost.org/users/license.html
#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_VALID_SEGMENT_HPP
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_VALID_SEGMENT_HPP
#include <boost/geometry/core/point_type.hpp>
#include <boost/geometry/core/tags.hpp>
#include <boost/geometry/algorithms/assign.hpp>
#include <boost/geometry/algorithms/equals.hpp>
#include <boost/geometry/algorithms/dispatch/is_valid.hpp>
namespace boost { namespace geometry
{
#ifndef DOXYGEN_NO_DISPATCH
namespace dispatch
{
// A segment is a curve.
// A curve is simple if it does not pass through the same point twice,
// with the possible exception of its two endpoints
// A curve is 1-dimensional, hence we have to check is the two
// endpoints of the segment coincide, since in this case it is
// 0-dimensional.
//
// Reference: OGC 06-103r4 (§6.1.6.1)
template <typename Segment>
struct is_valid<Segment, segment_tag>
{
static inline bool apply(Segment const& segment)
{
typename point_type<Segment>::type p[2];
detail::assign_point_from_index<0>(segment, p[0]);
detail::assign_point_from_index<1>(segment, p[1]);
return !geometry::equals(p[0], p[1]);
}
};
} // namespace dispatch
#endif // DOXYGEN_NO_DISPATCH
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_IS_VALID_SEGMENT_HPP

View File

@@ -0,0 +1,38 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// Copyright (c) 2014, Oracle and/or its affiliates.
// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
// Licensed under the Boost Software License version 1.0.
// http://www.boost.org/users/license.html
#ifndef BOOST_GEOMETRY_ALGORITHMS_DISPATCH_IS_SIMPLE_HPP
#define BOOST_GEOMETRY_ALGORITHMS_DISPATCH_IS_SIMPLE_HPP
#include <boost/geometry/core/tag.hpp>
#include <boost/geometry/algorithms/not_implemented.hpp>
namespace boost { namespace geometry
{
#ifndef DOXYGEN_NO_DISPATCH
namespace dispatch
{
template <typename Geometry, typename Tag = typename tag<Geometry>::type>
struct is_simple
: not_implemented<Geometry>
{};
} // namespace dispatch
#endif // DOXYGEN_NO_DISPATCH
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_ALGORITHMS_DISPATCH_IS_SIMPLE_HPP

View File

@@ -0,0 +1,38 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// Copyright (c) 2014, Oracle and/or its affiliates.
// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
// Licensed under the Boost Software License version 1.0.
// http://www.boost.org/users/license.html
#ifndef BOOST_GEOMETRY_ALGORITHMS_DISPATCH_IS_VALID_HPP
#define BOOST_GEOMETRY_ALGORITHMS_DISPATCH_IS_VALID_HPP
#include <boost/geometry/core/tag.hpp>
#include <boost/geometry/algorithms/not_implemented.hpp>
namespace boost { namespace geometry
{
#ifndef DOXYGEN_NO_DISPATCH
namespace dispatch
{
template <typename Geometry, typename Tag = typename tag<Geometry>::type>
struct is_valid
: not_implemented<Geometry>
{};
} // namespace dispatch
#endif // DOXYGEN_NO_DISPATCH
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_ALGORITHMS_DISPATCH_IS_VALID_HPP

View File

@@ -0,0 +1,237 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// Copyright (c) 2014, Oracle and/or its affiliates.
// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
// Licensed under the Boost Software License version 1.0.
// http://www.boost.org/users/license.html
#ifndef BOOST_GEOMETRY_ALGORITHMS_IS_SIMPLE_HPP
#define BOOST_GEOMETRY_ALGORITHMS_IS_SIMPLE_HPP
#include <algorithm>
#include <boost/range.hpp>
#include <boost/geometry/core/tags.hpp>
#include <boost/geometry/multi/core/tags.hpp>
#include <boost/geometry/core/point_type.hpp>
#include <boost/geometry/policies/compare.hpp>
#include <boost/geometry/algorithms/is_valid.hpp>
#include <boost/geometry/algorithms/detail/is_valid/has_spikes.hpp>
#include <boost/geometry/algorithms/dispatch/is_simple.hpp>
#include <boost/geometry/algorithms/detail/is_simple/pointlike.hpp>
#include <boost/geometry/algorithms/detail/is_simple/linear.hpp>
// check includes below
#include <boost/geometry/algorithms/unique.hpp>
#include <boost/geometry/algorithms/equals.hpp>
#include <boost/geometry/algorithms/intersects.hpp>
#include <boost/geometry/algorithms/disjoint.hpp>
#include <boost/geometry/algorithms/detail/point_is_spike_or_equal.hpp>
#include <boost/geometry/views/closeable_view.hpp>
#include <deque>
#include <algorithm>
namespace boost { namespace geometry
{
#ifndef DOXYGEN_NO_DETAIL
namespace detail { namespace is_simple
{
template
<
typename Geometry,
bool AllowEmpty = true,
typename Tag = typename tag<Geometry>::type
>
struct is_below_minimal_size
{
static inline bool apply(Geometry const&)
{
return false;
}
};
template <typename Linestring>
struct is_below_minimal_size<Linestring, true, linestring_tag>
{
static inline bool apply(Linestring const& linestring)
{
return boost::size(linestring) == 1;
}
};
template <typename Polygon>
struct is_simple_polygon
{
static inline bool apply(Polygon const& polygon)
{
typedef typename ring_type<Polygon>::type Ring;
BOOST_AUTO_TPL(it, boost::begin(geometry::interior_rings(polygon)));
for (; it != boost::end(geometry::interior_rings(polygon)); ++it)
{
if ( !is_simple_range<Ring>::apply(*it) )
{
return false;
}
}
return is_simple_range<Ring>::apply(geometry::exterior_ring(polygon));
}
};
template <typename MultiGeometry, bool CheckIntersections>
struct is_simple_multigeometry
{
static inline bool apply(MultiGeometry const& multigeometry)
{
typedef typename boost::range_value<MultiGeometry>::type Geometry;
BOOST_AUTO_TPL(it, boost::begin(multigeometry));
for (; it != boost::end(multigeometry); ++it)
{
if ( !dispatch::is_simple<Geometry>::apply(*it) )
{
return false;
}
}
if ( CheckIntersections )
{
BOOST_AUTO_TPL(it1, boost::begin(multigeometry));
it = it1;
for (; it != boost::end(multigeometry); ++it)
{
for (; it1 != boost::end(multigeometry); ++it1)
{
if ( geometry::intersects(*it, *it1) )
{
return false;
}
}
}
}
return true;
}
};
}} // namespace detail::is_simple
#endif // DOXYGEN_NO_DETAIL
#ifndef DOXYGEN_NO_DISPATCH
namespace dispatch
{
// A segment is always simple.
// A segment is a curve.
// A curve is simple if it does not pass through the same point twice,
// with the possible exception of its two endpoints
//
// Reference: OGC 06-103r4 (§6.1.6.1)
template <typename Segment>
struct is_simple<Segment, segment_tag>
{
static inline bool apply(Segment const& segment)
{
return dispatch::is_valid<Segment>::apply(segment);
}
};
// A box is always simple
// A box is a Polygon, and it satisfies the conditions for Polygon validity.
//
// Reference (for polygon validity): OGC 06-103r4 (§6.1.11.1)
template <typename Box>
struct is_simple<Box, box_tag>
{
static inline bool apply(Box const& box)
{
return dispatch::is_valid<Box>::apply(box);
}
};
// A Ring is a Polygon.
// A Polygon is always a simple geometric object provided that it is valid.
//
// Reference (for polygon validity): OGC 06-103r4 (§6.1.11.1)
template <typename Ring>
struct is_simple<Ring, ring_tag>
: detail::is_simple::is_simple_range<Ring>
{};
// A Polygon is always a simple geometric object provided that it is valid.
//
// Reference (for validity of Polygons): OGC 06-103r4 (§6.1.11.1)
template <typename Polygon>
struct is_simple<Polygon, polygon_tag>
: detail::is_simple::is_simple_polygon<Polygon>
{};
// Not clear what the definition is.
// Right now we check that each element is simple (in fact valid), and
// that the MultiPolygon is also valid.
//
// Reference (for validity of MultiPolygons): OGC 06-103r4 (§6.1.14)
template <typename MultiPolygon>
struct is_simple<MultiPolygon, multi_polygon_tag>
: detail::is_simple::is_simple_multigeometry<MultiPolygon, false>
{};
} // namespace dispatch
#endif // DOXYGEN_NO_DISPATCH
template <typename Geometry>
inline bool is_simple(Geometry const& g)
{
return dispatch::is_simple<Geometry>::apply(g);
}
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_ALGORITHMS_IS_SIMPLE_HPP

View File

@@ -0,0 +1,147 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// Copyright (c) 2014, Oracle and/or its affiliates.
// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
// Licensed under the Boost Software License version 1.0.
// http://www.boost.org/users/license.html
#ifndef BOOST_GEOMETRY_ALGORITHMS_IS_VALID_HPP
#define BOOST_GEOMETRY_ALGORITHMS_IS_VALID_HPP
#include <boost/range.hpp>
#include <boost/geometry/core/closure.hpp>
#include <boost/geometry/core/exterior_ring.hpp>
#include <boost/geometry/core/interior_rings.hpp>
#include <boost/geometry/core/ring_type.hpp>
#include <boost/geometry/core/tag.hpp>
#include <boost/geometry/core/tags.hpp>
#include <boost/geometry/multi/core/tags.hpp>
#include <boost/geometry/algorithms/intersects.hpp>
#include <boost/geometry/algorithms/disjoint.hpp>
#include <boost/geometry/algorithms/dispatch/is_valid.hpp>
#include <boost/geometry/algorithms/detail/is_valid/box.hpp>
#include <boost/geometry/algorithms/detail/is_valid/segment.hpp>
#include <boost/geometry/algorithms/detail/is_valid/linestring.hpp>
#include <boost/geometry/algorithms/detail/is_valid/multi_range.hpp>
#include <boost/geometry/algorithms/detail/is_valid/pointlike.hpp>
#include <boost/geometry/algorithms/detail/is_valid/has_spikes.hpp>
#include <boost/geometry/algorithms/detail/is_valid/ring.hpp>
namespace boost { namespace geometry
{
#ifndef DOXYGEN_NO_DETAIL
namespace detail { namespace is_valid
{
template <typename Polygon>
struct is_valid_polygon
{
static inline bool apply(Polygon const& polygon)
{
typedef typename ring_type<Polygon>::type ring_type;
if ( !dispatch::is_valid<ring_type>::apply(exterior_ring(polygon)) )
{
return false;
}
if ( !is_valid_multi_range<ring_type>::apply
(boost::begin(geometry::interior_rings(polygon)),
boost::end(geometry::interior_rings(polygon))) )
{
return false;
}
// MK::need check for self-intersection points; not done yet
return true;
}
};
template <typename MultiPolygon>
struct is_valid_multipolygon
{
static inline bool apply(MultiPolygon const& multipolygon)
{
typedef typename boost::range_value<MultiPolygon>::type polygon_type;
if ( !is_valid_multi_range
<
polygon_type
>::apply(boost::begin(multipolygon),
boost::end(multipolygon)) )
{
return false;
}
// MK::need to check that they are (almost) disjoint
return true;
}
};
}} // namespace detail::is_valid
#endif // DOXYGEN_NO_DETAIL
#ifndef DOXYGEN_NO_DISPATCH
namespace dispatch
{
// A Polygon is always a simple geometric object provided that it is valid.
//
// Reference (for validity of Polygons): OGC 06-103r4 (§6.1.11.1)
template <typename Polygon>
struct is_valid<Polygon, polygon_tag>
: detail::is_valid::is_valid_polygon<Polygon>
{};
// Not clear what the definition is.
// Right now we check that each element is simple (in fact valid), and
// that the MultiPolygon is also valid.
//
// Reference (for validity of MultiPolygons): OGC 06-103r4 (§6.1.14)
template <typename MultiPolygon>
struct is_valid<MultiPolygon, multi_polygon_tag>
: detail::is_valid::is_valid_multipolygon<MultiPolygon>
{};
} // namespace dispatch
#endif // DOXYGEN_NO_DISPATCH
template <typename Geometry>
inline bool is_valid(Geometry const& g)
{
return dispatch::is_valid<Geometry>::apply(g);
}
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_ALGORITHMS_IS_VALID_HPP

View File

@@ -0,0 +1,314 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// Copyright (c) 2014, Oracle and/or its affiliates.
// Licensed under the Boost Software License version 1.0.
// http://www.boost.org/users/license.html
// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
#include <iostream>
#ifndef BOOST_TEST_MODULE
#define BOOST_TEST_MODULE test_is_simple
#endif
#include <boost/test/included/unit_test.hpp>
#include <boost/geometry/geometries/point_xy.hpp>
#include <boost/geometry/geometries/segment.hpp>
#include <boost/geometry/geometries/linestring.hpp>
#include <boost/geometry/geometries/polygon.hpp>
#include <boost/geometry/multi/geometries/multi_point.hpp>
#include <boost/geometry/multi/geometries/multi_linestring.hpp>
#include <boost/geometry/multi/geometries/multi_polygon.hpp>
#include <boost/geometry/io/wkt/read.hpp>
#include <boost/geometry/io/wkt/write.hpp>
#include <boost/geometry/multi/io/wkt/read.hpp>
#include <boost/geometry/multi/io/wkt/write.hpp>
#include <boost/geometry/algorithms/is_valid.hpp>
#include <boost/geometry/algorithms/is_simple.hpp>
namespace bg = ::boost::geometry;
typedef bg::model::point<double,2,bg::cs::cartesian> point_type;
typedef bg::model::segment<point_type> segment_type;
typedef bg::model::linestring<point_type> linestring_type;
typedef bg::model::multi_linestring<linestring_type> multi_linestring_type;
// ccw open and closed polygons
typedef bg::model::polygon<point_type,false,false> open_polygon_type;
typedef bg::model::polygon<point_type,false,true> closed_polygon_type;
// multi-geometries
typedef bg::model::multi_point<point_type> multi_point_type;
typedef bg::model::multi_polygon<open_polygon_type> multi_polygon_type;
template <typename Geometry>
Geometry from_wkt(std::string const& wkt)
{
Geometry g;
bg::read_wkt(wkt, g);
return g;
}
template<typename Segment>
Segment make_segment(double x1, double y1, double x2, double y2)
{
typename boost::geometry::point_type<Segment>::type p(x1, y1), q(x2, y2);
return Segment(p, q);
}
template <typename Geometry>
void test_simple(Geometry const& g, bool simple_geometry)
{
#ifdef GEOMETRY_TEST_DEBUG
std::cout << "=======" << std::endl;
#endif
bool simple = bg::is_simple(g);
BOOST_CHECK(simple == simple_geometry);
#ifdef GEOMETRY_TEST_DEBUG
std::cout << "Geometry: " << bg::wkt(g) << std::endl;
std::cout << std::boolalpha;
std::cout << "is valid : " << bg::is_valid(g) << std::endl;
std::cout << "is simple: " << simple << std::endl;
std::cout << "expected result: " << simple_geometry << std::endl;
std::cout << "=======" << std::endl;
std::cout << std::endl << std::endl;
std::cout << std::noboolalpha;
#endif
}
//===========================================================================
//===========================================================================
//===========================================================================
BOOST_AUTO_TEST_CASE( test_is_simple_point )
{
#ifdef GEOMETRY_TEST_DEBUG
std::cout << std::endl << std::endl;
std::cout << "************************************" << std::endl;
std::cout << " is_simple: POINT " << std::endl;
std::cout << "************************************" << std::endl;
#endif
typedef point_type G;
test_simple(from_wkt<G>("POINT(0 0)"), true);
}
BOOST_AUTO_TEST_CASE( test_is_simple_segment )
{
#ifdef GEOMETRY_TEST_DEBUG
std::cout << std::endl << std::endl;
std::cout << "************************************" << std::endl;
std::cout << " is_simple: SEGMENT " << std::endl;
std::cout << "************************************" << std::endl;
#endif
typedef segment_type G;
test_simple(make_segment<G>(0, 0, 0, 0), false);
test_simple(make_segment<G>(0, 0, 1, 0), true);
}
BOOST_AUTO_TEST_CASE( test_is_simple_linestring )
{
#ifdef GEOMETRY_TEST_DEBUG
std::cout << std::endl << std::endl;
std::cout << "************************************" << std::endl;
std::cout << " is_simple: LINESTRING " << std::endl;
std::cout << "************************************" << std::endl;
#endif
typedef linestring_type G;
// invalid linestrings
test_simple(from_wkt<G>("LINESTRING()"), false);
test_simple(from_wkt<G>("LINESTRING(0 0)"), false);
test_simple(from_wkt<G>("LINESTRING(0 0,0 0)"), false);
// valid linestrings with multiple points
test_simple(from_wkt<G>("LINESTRING(0 0,0 0,1 0)"), false);
test_simple(from_wkt<G>("LINESTRING(0 0,0 0,1 0,0 0)"), false);
test_simple(from_wkt<G>("LINESTRING(0 0,0 0,1 0,1 0,1 1,0 0)"), false);
test_simple(from_wkt<G>("LINESTRING(0 0,1 0,2 0,1 1,1 0,1 -1)"), false);
// simple open linestrings
test_simple(from_wkt<G>("LINESTRING(0 0,1 2)"), true);
test_simple(from_wkt<G>("LINESTRING(0 0,1 2,2 3)"), true);
// simple closed linestrings
test_simple(from_wkt<G>("LINESTRING(0 0,1 0,1 1,0 0)"), true);
test_simple(from_wkt<G>("LINESTRING(0 0,1 0,1 1,0 1,0 0)"), true);
// non-simple linestrings
test_simple(from_wkt<G>("LINESTRING(0 0,1 0,0 0)"), false);
test_simple(from_wkt<G>("LINESTRING(0 0,1 0,2 10,0.5 -1)"), false);
test_simple(from_wkt<G>("LINESTRING(0 0,1 0,2 1,1 0)"), false);
test_simple(from_wkt<G>("LINESTRING(0 0,1 0,2 1,0.5 0)"), false);
test_simple(from_wkt<G>("LINESTRING(0 0,2 0,1 0)"), false);
test_simple(from_wkt<G>("LINESTRING(0 0,3 0,5 0,1 0)"), false);
test_simple(from_wkt<G>("LINESTRING(0 0,3 0,5 0,4 0)"), false);
test_simple(from_wkt<G>("LINESTRING(0 0,3 0,5 0,4 0,2 0)"), false);
test_simple(from_wkt<G>("LINESTRING(0 0,3 0,2 0,5 0)"), false);
test_simple(from_wkt<G>("LINESTRING(0 0,2 0,2 2,1 0,0 0)"), false);
}
BOOST_AUTO_TEST_CASE( test_is_simple_multipoint )
{
#ifdef GEOMETRY_TEST_DEBUG
std::cout << std::endl << std::endl;
std::cout << "************************************" << std::endl;
std::cout << " is_simple: MULTIPOINT " << std::endl;
std::cout << "************************************" << std::endl;
#endif
typedef multi_point_type G;
test_simple(from_wkt<G>("MULTIPOINT()"), false);
test_simple(from_wkt<G>("MULTIPOINT(0 0)"), true);
test_simple(from_wkt<G>("MULTIPOINT(0 0,1 0,1 1,0 1)"), true);
test_simple(from_wkt<G>("MULTIPOINT(0 0,1 0,1 1,1 0,0 1)"), false);
}
BOOST_AUTO_TEST_CASE( test_is_simple_multilinestring )
{
#ifdef GEOMETRY_TEST_DEBUG
std::cout << std::endl << std::endl;
std::cout << "************************************" << std::endl;
std::cout << " is_simple: MULTILINESTRING " << std::endl;
std::cout << "************************************" << std::endl;
#endif
typedef multi_linestring_type G;
// empty multilinestring
test_simple(from_wkt<G>("MULTILINESTRING()"), false);
// multilinestrings with empty linestrings
test_simple(from_wkt<G>("MULTILINESTRING(())"), false);
test_simple(from_wkt<G>("MULTILINESTRING((),(),())"), false);
test_simple(from_wkt<G>("MULTILINESTRING((),(0 1,1 0))"), false);
// multilinestrings with 1-point linestrings
test_simple(from_wkt<G>("MULTILINESTRING((0 0),(0 1,1 0))"), false);
test_simple(from_wkt<G>("MULTILINESTRING((0 0,0 0),(0 1,1 0))"), false);
test_simple(from_wkt<G>("MULTILINESTRING((0 0),(1 0))"), false);
test_simple(from_wkt<G>("MULTILINESTRING((0 0,0 0),(1 0,1 0))"), false);
test_simple(from_wkt<G>("MULTILINESTRING((0 0),(0 0))"), false);
// multilinestrings with linestrings with spikes
test_simple(from_wkt<G>("MULTILINESTRING((0 0,1 0,0 0),(5 0))"), false);
test_simple(from_wkt<G>("MULTILINESTRING((0 0,1 0,0 0),(5 0,1 0,4 1))"),
false);
test_simple(from_wkt<G>("MULTILINESTRING((0 0,1 0,0 0),(5 0,1 0,4 0))"),
false);
test_simple(from_wkt<G>("MULTILINESTRING((0 0,1 0,0 0),(1 0,2 0))"),
false);
// simple multilinestrings
test_simple(from_wkt<G>("MULTILINESTRING((0 0,1 1),(1 1,1 0))"), true);
test_simple(from_wkt<G>("MULTILINESTRING((0 0,1 1),(1 1,1 0),(0 1,1 1))"),
true);
test_simple(from_wkt<G>("MULTILINESTRING((0 0,2 2),(0 0,1 0,2 0,2 2))"), true);
test_simple(from_wkt<G>("MULTILINESTRING((0 0,2 2),(2 2,2 0,1 0,0 0))"), true);
test_simple(from_wkt<G>("MULTILINESTRING((0 0,1 0),(0 0,-1 0),\
(1 0,2 0))"),
true);
test_simple(from_wkt<G>("MULTILINESTRING((0 0,1 0),(-1 0,0 0),\
(2 0,1 0))"),
true);
test_simple(from_wkt<G>("MULTILINESTRING((0 0,1 0,1 1,0 1,0 0),(-1 0,0 0))"),
true);
// non-simple multilinestrings
test_simple(from_wkt<G>("MULTILINESTRING((0 0,2 2),(0 0,2 2))"), false);
test_simple(from_wkt<G>("MULTILINESTRING((0 0,2 2),(2 2,0 0))"), false);
test_simple(from_wkt<G>("MULTILINESTRING((0 0,2 2),\
(0 0,1 0,1 1,2 0,2 2))"),
false);
test_simple(from_wkt<G>("MULTILINESTRING((0 0,1 1,2 2),\
(0 0,1 0,1 1,2 0,2 2))"),
false);
test_simple(from_wkt<G>("MULTILINESTRING((0 0,1 1,2 2),(2 2,0 0))"), false);
test_simple(from_wkt<G>("MULTILINESTRING((0 0,1 1),(0 1,1 0))"), false);
test_simple(from_wkt<G>("MULTILINESTRING((0 0,2 0),(1 0,0 1))"), false);
test_simple(from_wkt<G>("MULTILINESTRING((0 0,1 1),(1 1,1 0),\
(1 1,0 1,0.5,0.5))"),
false);
test_simple(from_wkt<G>("MULTILINESTRING((0 0,1 0,1 1,0 1,0 0),(1 0,1 -1))"),
false);
}
#if 0
BOOST_AUTO_TEST_CASE( test_is_simple_rest )
{
typedef open_polygon_type op;
typedef closed_polygon_type cp;
typedef multi_polygon_type mpl;
test_simple(from_wkt<op>("POLYGON(())"), true);
test_simple(from_wkt<op>("POLYGON((),())"), true);
test_simple(from_wkt<op>("POLYGON((0 0,1 0,1 1),())"), true);
test_simple(from_wkt<op>("POLYGON((0 0,1 0,1 0,1 1),())"), true);
test_simple(from_wkt<op>("POLYGON((0 0,1 0))"), false);
test_simple(from_wkt<op>("POLYGON((0 0,2 0,0.5 0,0.5 1))"), false);
test_simple(from_wkt<op>("POLYGON((0 0,2 0,0.5 0,0.5 0))"), false);
test_simple(from_wkt<op>("POLYGON((0 0,1 0,1 1,1 0.5))"), false);
test_simple(from_wkt<op>("POLYGON((0 0,1 0,1 1))"), true);
test_simple(from_wkt<op>("POLYGON((0 0,1 0,2 1,2 2,1 3))"), true);
test_simple(from_wkt<op>("POLYGON((0 0,2 0,4 1,1 0))"), false);
test_simple(from_wkt<op>("POLYGON((0 0,1 0,3 1,-1 2,3 3,3 4,0 4))"), false);
test_simple(from_wkt<op>("POLYGON((0 0,1 0,3 1,0 2,3 3,3 4,0 4))"), false);
test_simple(from_wkt<op>("POLYGON((0 0,10 0,10 10,0 10),\
(1 1,1 2,2 2,2 1))"), false);
test_simple(from_wkt<cp>("POLYGON(())"), true);
test_simple(from_wkt<cp>("POLYGON((),())"), true);
test_simple(from_wkt<cp>("POLYGON((0 0,1 0,1 1,0 0),())"), true);
test_simple(from_wkt<cp>("POLYGON((0 0,1 0,1 0,1 1,0 0),())"), true);
test_simple(from_wkt<cp>("POLYGON((0 0,1 0,0 0))"), false);
test_simple(from_wkt<cp>("POLYGON((0 0,2 0,0.5 0,0.5 1,0 0))"), false);
test_simple(from_wkt<cp>("POLYGON((0 0,2 0,0.5 0,0.5 0,0 0))"), false);
test_simple(from_wkt<cp>("POLYGON((0 0,1 0,1 1,1 0.5,0 0))"), false);
test_simple(from_wkt<cp>("POLYGON((0 0,1 0,1 1,0 0))"), true);
test_simple(from_wkt<cp>("POLYGON((0 0,1 0,2 1,2 2,1 3,0 0))"), true);
test_simple(from_wkt<cp>("POLYGON((0 0,2 0,4 1,1 0,0 0))"), false);
test_simple(from_wkt<cp>("POLYGON((0 0,1 0,3 1,-1 2,3 3,3 4,0 4,0 0))"),
false);
test_simple(from_wkt<cp>("POLYGON((0 0,1 0,3 1,0 2,3 3,3 4,0 4,0 0))"),
false);
test_simple(from_wkt<cp>("POLYGON((0 0,10 0,10 10,0 10,0 0),\
(1 1,1 2,2 2,2 1,1 1))"), false);
test_simple(from_wkt<mpl>("MULTIPOLYGON()"), true);
test_simple(from_wkt<mpl>("MULTIPOLYGON( ((),()) )"), true);
test_simple(from_wkt<mpl>("MULTIPOLYGON( (()),(()) )"), true);
test_simple(from_wkt<mpl>("MULTIPOLYGON( ((),()),(()) )"), true);
test_simple(from_wkt<mpl>("MULTIPOLYGON( ((0 0),()),(()) )"), true);
test_simple(from_wkt<mpl>("MULTIPOLYGON( ((0 0),()),((1 1)) )"), true);
#ifdef GEOMETRY_TEST_INCLUDE_FAILING_TESTS
// test_simple(from_wkt<mpl>("MULTIPOLYGON( ((0 0),()),((0 0)) )"), false);
#endif
test_simple(from_wkt<mpl>("MULTIPOLYGON(((0 0,1 0,2 1,2 2,1 3)),\
((10 0,11 0,11 1)))"), true);
test_simple(from_wkt<mpl>("MULTIPOLYGON(((0 0,1 0,1 0,2 1,2 2,1 3)),\
((10 0,11 0,11 1,11 1)))"), true);
test_simple(from_wkt<mpl>("MULTIPOLYGON(((0 0,1 0,3 1,0 2,3 3,3 4,0 4)),\
((10 0,11 0,11 1)))"), false);
}
#endif

View File

@@ -0,0 +1,325 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// Copyright (c) 2014, Oracle and/or its affiliates.
// Licensed under the Boost Software License version 1.0.
// http://www.boost.org/users/license.html
// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
#include <iostream>
#ifndef BOOST_TEST_MODULE
#define BOOST_TEST_MODULE test_is_valid
#endif
#include <boost/test/included/unit_test.hpp>
#include <boost/geometry/geometries/point_xy.hpp>
#include <boost/geometry/geometries/segment.hpp>
#include <boost/geometry/geometries/box.hpp>
#include <boost/geometry/geometries/linestring.hpp>
#include <boost/geometry/geometries/polygon.hpp>
#include <boost/geometry/multi/geometries/multi_point.hpp>
#include <boost/geometry/multi/geometries/multi_linestring.hpp>
#include <boost/geometry/multi/geometries/multi_polygon.hpp>
#include <boost/geometry/io/wkt/read.hpp>
#include <boost/geometry/io/wkt/write.hpp>
#include <boost/geometry/multi/io/wkt/read.hpp>
#include <boost/geometry/multi/io/wkt/write.hpp>
#include <boost/geometry/algorithms/is_valid.hpp>
namespace bg = ::boost::geometry;
typedef bg::model::point<double,2,bg::cs::cartesian> point_type;
typedef bg::model::segment<point_type> segment_type;
typedef bg::model::box<point_type> box_type;
typedef bg::model::linestring<point_type> linestring_type;
typedef bg::model::multi_linestring<linestring_type> multi_linestring_type;
// ccw open and closed polygons
typedef bg::model::polygon<point_type,false,false> open_polygon_type;
typedef bg::model::polygon<point_type,false,true> closed_polygon_type;
// multi-geometries
typedef bg::model::multi_point<point_type> multi_point_type;
typedef bg::model::multi_polygon<open_polygon_type> multi_polygon_type;
template <typename Geometry>
Geometry from_wkt(std::string const& wkt)
{
Geometry g;
bg::read_wkt(wkt, g);
return g;
}
template<typename Segment>
Segment make_segment(double x1, double y1, double x2, double y2)
{
typename boost::geometry::point_type<Segment>::type p(x1, y1), q(x2, y2);
return Segment(p, q);
}
template<typename Box>
Box make_box(double x1, double y1, double x2, double y2)
{
typename boost::geometry::point_type<Box>::type p(x1, y1), q(x2, y2);
return Box(p, q);
}
template <typename Geometry>
void test_valid(Geometry const& g, bool expected_result)
{
#ifdef GEOMETRY_TEST_DEBUG
std::cout << "=======" << std::endl;
#endif
bool valid = bg::is_valid(g);
BOOST_CHECK( valid == expected_result );
#ifdef GEOMETRY_TEST_DEBUG
std::cout << "Geometry: " << bg::wkt(g) << std::endl;
std::cout << std::boolalpha;
std::cout << "is valid:? " << valid << std::endl;
std::cout << "expected result: " << expected_result << std::endl;
std::cout << "=======" << std::endl;
std::cout << std::endl << std::endl;
std::cout << std::noboolalpha;
#endif
}
//===========================================================================
//===========================================================================
//===========================================================================
BOOST_AUTO_TEST_CASE( test_is_valid_point )
{
#ifdef GEOMETRY_TEST_DEBUG
std::cout << std::endl << std::endl;
std::cout << "************************************" << std::endl;
std::cout << " is_valid: POINT " << std::endl;
std::cout << "************************************" << std::endl;
#endif
typedef point_type G;
test_valid(from_wkt<G>("POINT(0 0)"), true);
}
BOOST_AUTO_TEST_CASE( test_is_valid_segment )
{
#ifdef GEOMETRY_TEST_DEBUG
std::cout << std::endl << std::endl;
std::cout << "************************************" << std::endl;
std::cout << " is_valid: SEGMENT " << std::endl;
std::cout << "************************************" << std::endl;
#endif
typedef segment_type G;
test_valid(make_segment<G>(0, 0, 0, 0), false);
test_valid(make_segment<G>(0, 0, 1, 0), true);
}
BOOST_AUTO_TEST_CASE( test_is_valid_box )
{
#ifdef GEOMETRY_TEST_DEBUG
std::cout << std::endl << std::endl;
std::cout << "************************************" << std::endl;
std::cout << " is_valid: BOX " << std::endl;
std::cout << "************************************" << std::endl;
#endif
typedef box_type G;
// boxes where the max corner and below and/or to the left of min corner
test_valid(make_box<G>(0, 0, -1, 0), false);
test_valid(make_box<G>(0, 0, 0, -1), false);
test_valid(make_box<G>(0, 0, -1, -1), false);
// boxes of zero area; they are not 2-dimensional, so invalid
test_valid(make_box<G>(0, 0, 0, 0), false);
test_valid(make_box<G>(0, 0, 1, 0), false);
test_valid(make_box<G>(0, 0, 0, 1), false);
test_valid(make_box<G>(0, 0, 1, 1), true);
}
BOOST_AUTO_TEST_CASE( test_is_valid_linestring )
{
#ifdef GEOMETRY_TEST_DEBUG
std::cout << std::endl << std::endl;
std::cout << "************************************" << std::endl;
std::cout << " is_valid: LINESTRING " << std::endl;
std::cout << "************************************" << std::endl;
#endif
typedef linestring_type G;
// empty linestring
test_valid(from_wkt<G>("LINESTRING()"), false);
// 1-point linestrings
test_valid(from_wkt<G>("LINESTRING(0 0)"), false);
test_valid(from_wkt<G>("LINESTRING(0 0,0 0)"), false);
test_valid(from_wkt<G>("LINESTRING(0 0,0 0,0 0)"), false);
// 2-point linestrings
test_valid(from_wkt<G>("LINESTRING(0 0,1 2)"), true);
test_valid(from_wkt<G>("LINESTRING(0 0,1 2,1 2)"), true);
test_valid(from_wkt<G>("LINESTRING(0 0,0 0,1 2,1 2)"), true);
test_valid(from_wkt<G>("LINESTRING(0 0,0 0,0 0,1 2,1 2)"), true);
// 3-point linestrings
test_valid(from_wkt<G>("LINESTRING(0 0,1 0,2 10)"), true);
test_valid(from_wkt<G>("LINESTRING(0 0,1 0,2 10,0 0)"), true);
test_valid(from_wkt<G>("LINESTRING(0 0,10 0,10 10,5 0)"), true);
test_valid(from_wkt<G>("LINESTRING(0 0,10 0,10 10,5 0,4 0)"), true);
test_valid(from_wkt<G>("LINESTRING(0 0,10 0,10 10,5 0,4 0,3 0)"), true);
test_valid(from_wkt<G>("LINESTRING(0 0,10 0,10 10,5 0,4 0,-1 0)"), true);
test_valid(from_wkt<G>("LINESTRING(0 0,1 0,1 1,-1 1,-1 0,0 0)"), true);
// should this be valid? we have two overlapping segments
test_valid(from_wkt<G>("LINESTRING(0 0,1 0,1 1,-1 1,-1 0,0.5 0)"), true);
// linestrings with spikes
static const bool accept_spikes = false;
test_valid(from_wkt<G>("LINESTRING(0 0,1 2,0 0)"), accept_spikes);
test_valid(from_wkt<G>("LINESTRING(0 0,1 2,1 2,0 0)"), accept_spikes);
test_valid(from_wkt<G>("LINESTRING(0 0,0 0,1 2,1 2,0 0)"), accept_spikes);
test_valid(from_wkt<G>("LINESTRING(0 0,0 0,0 0,1 2,1 2,0 0,0 0)"),
accept_spikes);
test_valid(from_wkt<G>("LINESTRING(0 0,10 0,5 0)"), accept_spikes);
test_valid(from_wkt<G>("LINESTRING(0 0,10 0,10 10,5 0,0 0)"), accept_spikes);
test_valid(from_wkt<G>("LINESTRING(0 0,10 0,10 10,5 0,4 0,6 0)"),
accept_spikes);
test_valid(from_wkt<G>("LINESTRING(0 0,1 0,1 1,5 5,4 4)"), accept_spikes);
test_valid(from_wkt<G>("LINESTRING(0 0,1 0,1 1,5 5,4 4,6 6)"), accept_spikes);
test_valid(from_wkt<G>("LINESTRING(0 0,1 0,1 1,5 5,4 4,4 0)"), accept_spikes);
}
BOOST_AUTO_TEST_CASE( test_is_valid_multipoint )
{
#ifdef GEOMETRY_TEST_DEBUG
std::cout << std::endl << std::endl;
std::cout << "************************************" << std::endl;
std::cout << " is_valid: MULTIPOINT " << std::endl;
std::cout << "************************************" << std::endl;
#endif
typedef multi_point_type G;
test_valid(from_wkt<G>("MULTIPOINT()"), false);
test_valid(from_wkt<G>("MULTIPOINT(0 0,0 0)"), true);
test_valid(from_wkt<G>("MULTIPOINT(0 0,1 0,1 1,0 1)"), true);
test_valid(from_wkt<G>("MULTIPOINT(0 0,1 0,1 1,1 0,0 1)"), true);
}
BOOST_AUTO_TEST_CASE( test_is_valid_multilinestring )
{
#ifdef GEOMETRY_TEST_DEBUG
std::cout << std::endl << std::endl;
std::cout << "************************************" << std::endl;
std::cout << " is_valid: MULTILINESTRING " << std::endl;
std::cout << "************************************" << std::endl;
#endif
typedef multi_linestring_type G;
// empty multilinestring
test_valid(from_wkt<G>("MULTILINESTRING()"), false);
// multilinestring with empty linestring(s)
test_valid(from_wkt<G>("MULTILINESTRING(())"), false);
test_valid(from_wkt<G>("MULTILINESTRING((),(),())"), false);
test_valid(from_wkt<G>("MULTILINESTRING((),(0 1,1 0))"), false);
// multilinestring with invalid linestrings
test_valid(from_wkt<G>("MULTILINESTRING((0 0),(0 1,1 0))"), false);
test_valid(from_wkt<G>("MULTILINESTRING((0 0,0 0),(0 1,1 0))"), false);
test_valid(from_wkt<G>("MULTILINESTRING((0 0),(1 0))"), false);
test_valid(from_wkt<G>("MULTILINESTRING((0 0,0 0),(1 0,1 0))"), false);
test_valid(from_wkt<G>("MULTILINESTRING((0 0),(0 0))"), false);
test_valid(from_wkt<G>("MULTILINESTRING((0 0,1 0,0 0),(5 0))"), false);
test_valid(from_wkt<G>("MULTILINESTRING((0 0,1 0,0 0),(5 0,1 0,4 1))"),
false);
test_valid(from_wkt<G>("MULTILINESTRING((0 0,1 0,0 0),(1 0,2 0))"),
false);
// valid multilinestrings
test_valid(from_wkt<G>("MULTILINESTRING((0 0,1 0,2 0),(5 0,1 0,4 1))"),
true);
test_valid(from_wkt<G>("MULTILINESTRING((0 0,1 0,2 0),(1 0,2 0))"),
true);
test_valid(from_wkt<G>("MULTILINESTRING((0 0,1 1),(0 1,1 0))"), true);
test_valid(from_wkt<G>("MULTILINESTRING((0 0,1 1,2 2),(0 1,1 0,2 2))"), true);
}
#if 0
BOOST_AUTO_TEST_CASE( test_is_valid_rest )
{
typedef open_polygon_type op;
typedef closed_polygon_type cp;
typedef multi_polygon_type mpl;
test_valid(from_wkt<op>("POLYGON(())"), true);
test_valid(from_wkt<op>("POLYGON((),())"), true);
test_valid(from_wkt<op>("POLYGON((0 0,1 0,1 1),())"), true);
test_valid(from_wkt<op>("POLYGON((0 0,1 0,1 0,1 1),())"), true);
test_valid(from_wkt<op>("POLYGON((0 0,1 0))"), false);
test_valid(from_wkt<op>("POLYGON((0 0,2 0,0.5 0,0.5 1))"), false);
test_valid(from_wkt<op>("POLYGON((0 0,2 0,0.5 0,0.5 0))"), false);
test_valid(from_wkt<op>("POLYGON((0 0,1 0,1 1,1 0.5))"), false);
test_valid(from_wkt<op>("POLYGON((0 0,1 0,1 1))"), true);
test_valid(from_wkt<op>("POLYGON((0 0,1 0,2 1,2 2,1 3))"), true);
test_valid(from_wkt<op>("POLYGON((0 0,2 0,4 1,1 0))"), false);
test_valid(from_wkt<op>("POLYGON((0 0,1 0,3 1,-1 2,3 3,3 4,0 4))"), false);
test_valid(from_wkt<op>("POLYGON((0 0,1 0,3 1,0 2,3 3,3 4,0 4))"), false);
test_valid(from_wkt<op>("POLYGON((0 0,10 0,10 10,0 10),\
(1 1,1 2,2 2,2 1))"), false);
test_valid(from_wkt<cp>("POLYGON(())"), true);
test_valid(from_wkt<cp>("POLYGON((),())"), true);
test_valid(from_wkt<cp>("POLYGON((0 0,1 0,1 1,0 0),())"), true);
test_valid(from_wkt<cp>("POLYGON((0 0,1 0,1 0,1 1,0 0),())"), true);
test_valid(from_wkt<cp>("POLYGON((0 0,1 0,0 0))"), false);
test_valid(from_wkt<cp>("POLYGON((0 0,2 0,0.5 0,0.5 1,0 0))"), false);
test_valid(from_wkt<cp>("POLYGON((0 0,2 0,0.5 0,0.5 0,0 0))"), false);
test_valid(from_wkt<cp>("POLYGON((0 0,1 0,1 1,1 0.5,0 0))"), false);
test_valid(from_wkt<cp>("POLYGON((0 0,1 0,1 1,0 0))"), true);
test_valid(from_wkt<cp>("POLYGON((0 0,1 0,2 1,2 2,1 3,0 0))"), true);
test_valid(from_wkt<cp>("POLYGON((0 0,2 0,4 1,1 0,0 0))"), false);
test_valid(from_wkt<cp>("POLYGON((0 0,1 0,3 1,-1 2,3 3,3 4,0 4,0 0))"),
false);
test_valid(from_wkt<cp>("POLYGON((0 0,1 0,3 1,0 2,3 3,3 4,0 4,0 0))"),
false);
test_valid(from_wkt<cp>("POLYGON((0 0,10 0,10 10,0 10,0 0),\
(1 1,1 2,2 2,2 1,1 1))"), false);
test_valid(from_wkt<mpl>("MULTIPOLYGON()"), true);
test_valid(from_wkt<mpl>("MULTIPOLYGON( ((),()) )"), true);
test_valid(from_wkt<mpl>("MULTIPOLYGON( (()),(()) )"), true);
test_valid(from_wkt<mpl>("MULTIPOLYGON( ((),()),(()) )"), true);
test_valid(from_wkt<mpl>("MULTIPOLYGON( ((0 0),()),(()) )"), true);
test_valid(from_wkt<mpl>("MULTIPOLYGON( ((0 0),()),((1 1)) )"), true);
#ifdef GEOMETRY_TEST_INCLUDE_FAILING_TESTS
// test_valid(from_wkt<mpl>("MULTIPOLYGON( ((0 0),()),((0 0)) )"), false);
#endif
test_valid(from_wkt<mpl>("MULTIPOLYGON(((0 0,1 0,2 1,2 2,1 3)),\
((10 0,11 0,11 1)))"), true);
test_valid(from_wkt<mpl>("MULTIPOLYGON(((0 0,1 0,1 0,2 1,2 2,1 3)),\
((10 0,11 0,11 1,11 1)))"), true);
test_valid(from_wkt<mpl>("MULTIPOLYGON(((0 0,1 0,3 1,0 2,3 3,3 4,0 4)),\
((10 0,11 0,11 1)))"), false);
}
#endif