123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508 |
- // Boost.Geometry (aka GGL, Generic Geometry Library)
- // Unit Test
- // Copyright (c) 2014-2017, Oracle and/or its affiliates.
- // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
- // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
- // Licensed under the Boost Software License version 1.0.
- // http://www.boost.org/users/license.html
- #ifndef BOOST_GEOMETRY_TEST_IS_VALID_HPP
- #define BOOST_GEOMETRY_TEST_IS_VALID_HPP
- #include <iostream>
- #include <sstream>
- #include <string>
- #include <boost/core/ignore_unused.hpp>
- #include <boost/range.hpp>
- #include <boost/variant/variant.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/point_order.hpp>
- #include <boost/geometry/core/ring_type.hpp>
- #include <boost/geometry/core/tag.hpp>
- #include <boost/geometry/core/tags.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/ring.hpp>
- #include <boost/geometry/geometries/polygon.hpp>
- #include <boost/geometry/geometries/multi_point.hpp>
- #include <boost/geometry/geometries/multi_linestring.hpp>
- #include <boost/geometry/geometries/multi_polygon.hpp>
- #include <boost/geometry/strategies/strategies.hpp>
- #include <boost/geometry/io/wkt/wkt.hpp>
- #include <boost/geometry/algorithms/convert.hpp>
- #include <boost/geometry/algorithms/num_points.hpp>
- #include <boost/geometry/algorithms/is_valid.hpp>
- #include <boost/geometry/algorithms/detail/check_iterator_range.hpp>
- #include <from_wkt.hpp>
- #ifdef BOOST_GEOMETRY_TEST_DEBUG
- #include "pretty_print_geometry.hpp"
- #endif
- 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;
- typedef bg::model::multi_point<point_type> multi_point_type;
- //----------------------------------------------------------------------------
- // returns true if a geometry can be converted to closed
- template
- <
- typename Geometry,
- typename Tag = typename bg::tag<Geometry>::type,
- bg::closure_selector Closure = bg::closure<Geometry>::value
- >
- struct is_convertible_to_closed
- {
- static inline bool apply(Geometry const&)
- {
- return false;
- }
- };
- template <typename Ring>
- struct is_convertible_to_closed<Ring, bg::ring_tag, bg::open>
- {
- static inline bool apply(Ring const& ring)
- {
- return boost::size(ring) > 0;
- }
- };
- template <typename Polygon>
- struct is_convertible_to_closed<Polygon, bg::polygon_tag, bg::open>
- {
- typedef typename bg::ring_type<Polygon>::type ring_type;
- template <typename InteriorRings>
- static inline
- bool apply_to_interior_rings(InteriorRings const& interior_rings)
- {
- return bg::detail::check_iterator_range
- <
- is_convertible_to_closed<ring_type>
- >::apply(boost::begin(interior_rings),
- boost::end(interior_rings));
- }
- static inline bool apply(Polygon const& polygon)
- {
- return boost::size(bg::exterior_ring(polygon)) > 0
- && apply_to_interior_rings(bg::interior_rings(polygon));
- }
- };
- template <typename MultiPolygon>
- struct is_convertible_to_closed<MultiPolygon, bg::multi_polygon_tag, bg::open>
- {
- typedef typename boost::range_value<MultiPolygon>::type polygon;
- static inline bool apply(MultiPolygon const& multi_polygon)
- {
- return bg::detail::check_iterator_range
- <
- is_convertible_to_closed<polygon>,
- false // do not allow empty multi-polygon
- >::apply(boost::begin(multi_polygon),
- boost::end(multi_polygon));
- }
- };
- //----------------------------------------------------------------------------
- // returns true if a geometry can be converted to cw
- template
- <
- typename Geometry,
- typename Tag = typename bg::tag<Geometry>::type,
- bg::order_selector Order = bg::point_order<Geometry>::value
- >
- struct is_convertible_to_cw
- {
- static inline bool apply(Geometry const&)
- {
- return bg::point_order<Geometry>::value == bg::counterclockwise;
- }
- };
- //----------------------------------------------------------------------------
- // returns true if geometry can be converted to polygon
- template
- <
- typename Geometry,
- typename Tag = typename bg::tag<Geometry>::type
- >
- struct is_convertible_to_polygon
- {
- typedef Geometry type;
- static bool const value = false;
- };
- template <typename Ring>
- struct is_convertible_to_polygon<Ring, bg::ring_tag>
- {
- typedef bg::model::polygon
- <
- typename bg::point_type<Ring>::type,
- bg::point_order<Ring>::value == bg::clockwise,
- bg::closure<Ring>::value == bg::closed
- > type;
- static bool const value = true;
- };
- //----------------------------------------------------------------------------
- // returns true if geometry can be converted to multi-polygon
- template
- <
- typename Geometry,
- typename Tag = typename bg::tag<Geometry>::type
- >
- struct is_convertible_to_multipolygon
- {
- typedef Geometry type;
- static bool const value = false;
- };
- template <typename Ring>
- struct is_convertible_to_multipolygon<Ring, bg::ring_tag>
- {
- typedef bg::model::multi_polygon
- <
- typename is_convertible_to_polygon<Ring>::type
- > type;
- static bool const value = true;
- };
- template <typename Polygon>
- struct is_convertible_to_multipolygon<Polygon, bg::polygon_tag>
- {
- typedef bg::model::multi_polygon<Polygon> type;
- static bool const value = true;
- };
- //----------------------------------------------------------------------------
- template <typename ValidityTester>
- struct validity_checker
- {
- template <typename Geometry>
- static inline bool apply(std::string const& case_id,
- Geometry const& geometry,
- bool expected_result,
- std::string& reason)
- {
- bool valid = ValidityTester::apply(geometry);
- std::string const reason_valid
- = bg::validity_failure_type_message(bg::no_failure);
- reason = ValidityTester::reason(geometry);
- std::string reason_short = reason.substr(0, reason_valid.length());
- BOOST_CHECK_MESSAGE(valid == expected_result,
- "case id: " << case_id
- << ", Expected: " << expected_result
- << ", detected: " << valid
- << "; wkt: " << bg::wkt(geometry));
- BOOST_CHECK_MESSAGE(reason != "",
- "case id (empty reason): " << case_id
- << ", Expected: " << valid
- << ", detected reason: " << reason
- << "; wkt: " << bg::wkt(geometry));
- BOOST_CHECK_MESSAGE((valid && reason == reason_valid)
- ||
- (! valid && reason != reason_valid)
- ||
- (! valid && reason_short != reason_valid),
- "case id (reason): " << case_id
- << ", Expected: " << valid
- << ", detected reason: " << reason
- << "; wkt: " << bg::wkt(geometry));
- return valid;
- }
- };
- //----------------------------------------------------------------------------
- struct default_validity_tester
- {
- template <typename Geometry>
- static inline bool apply(Geometry const& geometry)
- {
- return bg::is_valid(geometry);
- }
- template <typename Geometry>
- static inline std::string reason(Geometry const& geometry)
- {
- std::string message;
- bg::is_valid(geometry, message);
- return message;
- }
- };
- template <bool AllowSpikes>
- struct validity_tester_linear
- {
- template <typename Geometry>
- static inline bool apply(Geometry const& geometry)
- {
- bool const irrelevant = true;
- bg::is_valid_default_policy<irrelevant, AllowSpikes> visitor;
- return bg::is_valid(geometry, visitor, bg::default_strategy());
- }
- template <typename Geometry>
- static inline std::string reason(Geometry const& geometry)
- {
- bool const irrelevant = true;
- std::ostringstream oss;
- bg::failing_reason_policy<irrelevant, AllowSpikes> visitor(oss);
- bg::is_valid(geometry, visitor, bg::default_strategy());
- return oss.str();
- }
- };
- template <bool AllowDuplicates>
- struct validity_tester_areal
- {
- template <typename Geometry>
- static inline bool apply(Geometry const& geometry)
- {
- bg::is_valid_default_policy<AllowDuplicates> visitor;
- return bg::is_valid(geometry, visitor, bg::default_strategy());
- }
- template <typename Geometry>
- static inline std::string reason(Geometry const& geometry)
- {
- std::ostringstream oss;
- bg::failing_reason_policy<AllowDuplicates> visitor(oss);
- bg::is_valid(geometry, visitor, bg::default_strategy());
- return oss.str();
- }
- };
- template <bool AllowDuplicates>
- struct validity_tester_geo_areal
- {
- template <typename Geometry>
- static inline bool apply(Geometry const& geometry)
- {
- bg::is_valid_default_policy<AllowDuplicates> visitor;
- bg::strategy::intersection::geographic_segments<> s;
- return bg::is_valid(geometry, visitor, s);
- }
- template <typename Geometry>
- static inline std::string reason(Geometry const& geometry)
- {
- std::ostringstream oss;
- bg::failing_reason_policy<AllowDuplicates> visitor(oss);
- bg::strategy::intersection::geographic_segments<> s;
- bg::is_valid(geometry, visitor, s);
- return oss.str();
- }
- };
- //----------------------------------------------------------------------------
- template
- <
- typename ValidityTester,
- typename Geometry,
- typename ClosedGeometry = Geometry,
- typename CWGeometry = Geometry,
- typename CWClosedGeometry = Geometry,
- typename Tag = typename bg::tag<Geometry>::type
- >
- class test_valid
- {
- protected:
- template <typename G>
- static inline void base_test(std::string const& case_id,
- G const& g,
- bool expected_result)
- {
- #ifdef BOOST_GEOMETRY_TEST_DEBUG
- std::cout << "=======" << std::endl;
- #endif
- std::string reason;
- bool valid = validity_checker
- <
- ValidityTester
- >::apply(case_id, g, expected_result, reason);
- boost::ignore_unused(valid);
- #ifdef BOOST_GEOMETRY_TEST_DEBUG
- std::cout << "case id: " << case_id << ", Geometry: ";
- pretty_print_geometry<G>::apply(std::cout, g);
- std::cout << std::endl;
- std::cout << "wkt: " << 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 << "reason: " << reason << std::endl;
- std::cout << "=======" << std::endl;
- std::cout << std::noboolalpha;
- #endif
- }
- public:
- static inline void apply(std::string const& case_id,
- Geometry const& geometry,
- bool expected_result)
- {
- std::stringstream sstr;
- sstr << case_id << "-original"; // which is: CCW open
- base_test(sstr.str(), geometry, expected_result);
- if ( is_convertible_to_closed<Geometry>::apply(geometry) )
- {
- #ifdef BOOST_GEOMETRY_TEST_DEBUG
- std::cout << "...checking closed geometry..."
- << std::endl;
- #endif
- ClosedGeometry closed_geometry;
- bg::convert(geometry, closed_geometry);
- sstr.str("");
- sstr << case_id << "-2closed";
- base_test(sstr.str(), closed_geometry, expected_result);
- }
- if ( is_convertible_to_cw<Geometry>::apply(geometry) )
- {
- #ifdef BOOST_GEOMETRY_TEST_DEBUG
- std::cout << "...checking cw open geometry..."
- << std::endl;
- #endif
- CWGeometry cw_geometry;
- bg::convert(geometry, cw_geometry);
- sstr.str("");
- sstr << case_id << "-2CW";
- base_test(sstr.str(), cw_geometry, expected_result);
- if ( is_convertible_to_closed<CWGeometry>::apply(cw_geometry) )
- {
- #ifdef BOOST_GEOMETRY_TEST_DEBUG
- std::cout << "...checking cw closed geometry..."
- << std::endl;
- #endif
- CWClosedGeometry cw_closed_geometry;
- bg::convert(cw_geometry, cw_closed_geometry);
- sstr.str("");
- sstr << case_id << "-2CWclosed";
- base_test(sstr.str(), cw_closed_geometry, expected_result);
- }
- }
- if ( BOOST_GEOMETRY_CONDITION(is_convertible_to_polygon<Geometry>::value) )
- {
- #ifdef BOOST_GEOMETRY_TEST_DEBUG
- std::cout << "...checking geometry converted to polygon..."
- << std::endl;
- #endif
- typename is_convertible_to_polygon<Geometry>::type polygon;
- bg::convert(geometry, polygon);
- sstr.str("");
- sstr << case_id << "-2Polygon";
- base_test(sstr.str(), polygon, expected_result);
- }
- if ( BOOST_GEOMETRY_CONDITION(is_convertible_to_multipolygon<Geometry>::value) )
- {
- #ifdef BOOST_GEOMETRY_TEST_DEBUG
- std::cout << "...checking geometry converted to multi-polygon..."
- << std::endl;
- #endif
- typename is_convertible_to_multipolygon
- <
- Geometry
- >::type multipolygon;
- bg::convert(geometry, multipolygon);
- sstr.str("");
- sstr << case_id << "-2MultiPolygon";
- base_test(sstr.str(), multipolygon, expected_result);
- }
- #ifdef BOOST_GEOMETRY_TEST_DEBUG
- std::cout << std::endl << std::endl << std::endl;
- #endif
- }
- static inline void apply(std::string const& case_id,
- std::string const& wkt,
- bool expected_result)
- {
- apply(case_id, from_wkt<Geometry>(wkt), expected_result);
- }
- };
- //----------------------------------------------------------------------------
- template <typename VariantGeometry>
- class test_valid_variant
- : test_valid<default_validity_tester, VariantGeometry>
- {
- private:
- typedef test_valid<default_validity_tester, VariantGeometry> base_type;
- public:
- static inline void apply(std::string const& case_id,
- VariantGeometry const& vg,
- bool expected_result)
- {
- std::ostringstream oss;
- base_type::base_test(case_id, vg, expected_result);
- }
- };
- #endif // BOOST_GEOMETRY_TEST_IS_VALID_HPP
|