// Boost.Geometry (aka GGL, Generic Geometry Library) // Unit Test // Copyright (c) 2014-2015, 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_TEST_IS_VALID_HPP #define BOOST_GEOMETRY_TEST_IS_VALID_HPP #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef BOOST_GEOMETRY_TEST_DEBUG #include "pretty_print_geometry.hpp" #endif namespace bg = ::boost::geometry; typedef bg::model::point point_type; typedef bg::model::segment segment_type; typedef bg::model::box box_type; typedef bg::model::linestring linestring_type; typedef bg::model::multi_linestring multi_linestring_type; typedef bg::model::multi_point multi_point_type; //---------------------------------------------------------------------------- // returns true if a geometry can be converted to closed template < typename Geometry, typename Tag = typename bg::tag::type, bg::closure_selector Closure = bg::closure::value > struct is_convertible_to_closed { static inline bool apply(Geometry const&) { return false; } }; template struct is_convertible_to_closed { static inline bool apply(Ring const& ring) { return boost::size(ring) > 0; } }; template struct is_convertible_to_closed { typedef typename bg::ring_type::type ring_type; template static inline bool apply_to_interior_rings(InteriorRings const& interior_rings) { return bg::detail::check_iterator_range < is_convertible_to_closed >::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 struct is_convertible_to_closed { typedef typename boost::range_value::type polygon; static inline bool apply(MultiPolygon const& multi_polygon) { return bg::detail::check_iterator_range < is_convertible_to_closed, 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::type, bg::order_selector Order = bg::point_order::value > struct is_convertible_to_cw { static inline bool apply(Geometry const&) { return bg::point_order::value == bg::counterclockwise; } }; //---------------------------------------------------------------------------- // returns true if geometry can be converted to polygon template < typename Geometry, typename Tag = typename bg::tag::type > struct is_convertible_to_polygon { typedef Geometry type; static bool const value = false; }; template struct is_convertible_to_polygon { typedef bg::model::polygon < typename bg::point_type::type, bg::point_order::value == bg::clockwise, bg::closure::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::type > struct is_convertible_to_multipolygon { typedef Geometry type; static bool const value = false; }; template struct is_convertible_to_multipolygon { typedef bg::model::multi_polygon < typename is_convertible_to_polygon::type > type; static bool const value = true; }; template struct is_convertible_to_multipolygon { typedef bg::model::multi_polygon type; static bool const value = true; }; //---------------------------------------------------------------------------- template struct validity_checker { template static inline bool apply(Geometry const& geometry, bool expected_result, std::string const& case_id) { bool valid = ValidityTester::apply(geometry); BOOST_CHECK_MESSAGE(valid == expected_result, "case id: " << case_id << ", Expected: " << expected_result << ", detected: " << valid << "; wkt: " << bg::wkt(geometry)); return valid; } }; //---------------------------------------------------------------------------- struct default_validity_tester { template static inline bool apply(Geometry const& geometry) { return bg::is_valid(geometry); } }; template struct validity_tester_linear { template static inline bool apply(Geometry const& geometry) { return bg::dispatch::is_valid < Geometry, typename bg::tag::type, AllowSpikes >::apply(geometry); } }; template struct validity_tester_areal { template static inline bool apply(Geometry const& geometry) { bool const irrelevant = true; return bg::dispatch::is_valid < Geometry, typename bg::tag::type, irrelevant, AllowDuplicates >::apply(geometry); } }; //---------------------------------------------------------------------------- template < typename ValidityTester, typename Geometry, typename ClosedGeometry = Geometry, typename CWGeometry = Geometry, typename CWClosedGeometry = Geometry, typename Tag = typename bg::tag::type > struct test_valid { template static inline void base_test(G const& g, bool expected_result, std::string const& case_id) { #ifdef BOOST_GEOMETRY_TEST_DEBUG std::cout << "=======" << std::endl; #endif bool valid = validity_checker < ValidityTester >::apply(g, expected_result, case_id); boost::ignore_unused(valid); #ifdef BOOST_GEOMETRY_TEST_DEBUG std::cout << "case id: " << case_id << ", Geometry: "; pretty_print_geometry::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 << "=======" << std::endl; std::cout << std::noboolalpha; #endif } static inline void apply(Geometry const& geometry, bool expected_result, std::string const& case_id) { std::stringstream sstr; sstr << case_id << "-original"; base_test(geometry, expected_result, sstr.str()); if ( is_convertible_to_closed::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(closed_geometry, expected_result, sstr.str()); } if ( is_convertible_to_cw::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(cw_geometry, expected_result, sstr.str()); if ( is_convertible_to_closed::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(cw_closed_geometry, expected_result, sstr.str()); } } if ( BOOST_GEOMETRY_CONDITION(is_convertible_to_polygon::value) ) { #ifdef BOOST_GEOMETRY_TEST_DEBUG std::cout << "...checking geometry converted to polygon..." << std::endl; #endif typename is_convertible_to_polygon::type polygon; bg::convert(geometry, polygon); sstr.str(""); sstr << case_id << "-2Polygon"; base_test(polygon, expected_result, sstr.str()); } if ( BOOST_GEOMETRY_CONDITION(is_convertible_to_multipolygon::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(multipolygon, expected_result, sstr.str()); } #ifdef BOOST_GEOMETRY_TEST_DEBUG std::cout << std::endl << std::endl << std::endl; #endif } }; //---------------------------------------------------------------------------- template struct test_valid_variant { static inline void apply(VariantGeometry const& vg, bool expected_result, std::string const& case_id) { test_valid < default_validity_tester, VariantGeometry >::base_test(vg, expected_result, case_id); } }; #endif // BOOST_GEOMETRY_TEST_IS_VALID_HPP