// 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_DISTANCE_COMMON_HPP #define BOOST_GEOMETRY_TEST_DISTANCE_COMMON_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 #ifndef BOOST_GEOMETRY_TEST_DISTANCE_HPP namespace bg = ::boost::geometry; // function copied from BG's test_distance.hpp template void test_empty_input(Geometry1 const& geometry1, Geometry2 const& geometry2) { try { bg::distance(geometry1, geometry2); } catch(bg::empty_input_exception const& ) { return; } BOOST_CHECK_MESSAGE(false, "A empty_input_exception should have been thrown" ); } #endif // BOOST_GEOMETRY_TEST_DISTANCE_HPP //======================================================================== #ifdef BOOST_GEOMETRY_TEST_DEBUG // pretty print geometry -- START template struct pretty_print_geometry_dispatch { template static inline Stream& apply(Geometry const& geometry, Stream& os) { os << bg::wkt(geometry); return os; } }; template struct pretty_print_geometry_dispatch { template static inline Stream& apply(Geometry const& geometry, Stream& os) { os << "SEGMENT" << bg::dsv(geometry); return os; } }; template struct pretty_print_geometry_dispatch { template static inline Stream& apply(Geometry const& geometry, Stream& os) { os << "BOX" << bg::dsv(geometry); return os; } }; template struct pretty_print_geometry { template static inline Stream& apply(Geometry const& geometry, Stream& os) { return pretty_print_geometry_dispatch < Geometry, typename bg::tag::type >::apply(geometry, os); } }; // pretty print geometry -- END #endif // BOOST_GEOMETRY_TEST_DEBUG //======================================================================== template struct check_equal { static inline void apply(T const& detected, T const& expected, bool is_finite) { if (is_finite) { BOOST_CHECK(detected == expected); } else { BOOST_CHECK(! boost::math::isfinite(detected)); } } }; template <> struct check_equal { static inline void apply(double detected, double expected, bool is_finite) { if (is_finite) { BOOST_CHECK_CLOSE(detected, expected, 0.0001); } else { BOOST_CHECK(! boost::math::isfinite(detected)); } } }; //======================================================================== template < typename Geometry1, typename Geometry2, int id1 = bg::geometry_id::value, int id2 = bg::geometry_id::value > struct test_distance_of_geometries : public test_distance_of_geometries {}; #ifdef BOOST_GEOMETRY_TEST_DEBUG #define ENABLE_IF_DEBUG(ID) ID #else #define ENABLE_IF_DEBUG(ID) #endif template class test_distance_of_geometries { private: template < typename G1, typename G2, typename DistanceType, typename ComparableDistanceType, typename Strategy > static inline void base_test(std::string const& ENABLE_IF_DEBUG(header), G1 const& g1, G2 const& g2, DistanceType const& expected_distance, ComparableDistanceType const& expected_comparable_distance, Strategy const& strategy, bool is_finite) { typedef typename bg::default_distance_result < G1, G2 >::type default_distance_result; typedef typename bg::strategy::distance::services::return_type < Strategy, G1, G2 >::type distance_result_from_strategy; static const bool same_regular = boost::is_same < default_distance_result, distance_result_from_strategy >::type::value; BOOST_CHECK( same_regular ); typedef typename bg::default_comparable_distance_result < G1, G2 >::type default_comparable_distance_result; typedef typename bg::strategy::distance::services::return_type < typename bg::strategy::distance::services::comparable_type < Strategy >::type, G1, G2 >::type comparable_distance_result_from_strategy; static const bool same_comparable = boost::is_same < default_comparable_distance_result, comparable_distance_result_from_strategy >::type::value; BOOST_CHECK( same_comparable ); // check distance with default strategy default_distance_result dist_def = bg::distance(g1, g2); check_equal < default_distance_result >::apply(dist_def, expected_distance, is_finite); // check distance with passed strategy distance_result_from_strategy dist = bg::distance(g1, g2, strategy); check_equal < default_distance_result >::apply(dist, expected_distance, is_finite); // check comparable distance with default strategy default_comparable_distance_result cdist_def = bg::comparable_distance(g1, g2); check_equal < default_comparable_distance_result >::apply(cdist_def, expected_comparable_distance, is_finite); // check comparable distance with passed strategy comparable_distance_result_from_strategy cdist = bg::comparable_distance(g1, g2, strategy); check_equal < default_comparable_distance_result >::apply(cdist, expected_comparable_distance, is_finite); #ifdef BOOST_GEOMETRY_TEST_DEBUG std::cout << string_from_type::type>::name() << string_from_type::type>::name() << " -> " << string_from_type::name() << string_from_type::name() << std::endl; std::cout << "distance" << header << " (def. strategy) = " << dist_def << " ; " << "distance" << header <<" (passed strategy) = " << dist << " ; " << "comp. distance" << header <<" (def. strategy) = " << cdist_def << " ; " << "comp. distance" << header <<" (passed strategy) = " << cdist << std::endl; #endif } public: template < typename DistanceType, typename ComparableDistanceType, typename Strategy > static inline void apply(std::string const& wkt1, std::string const& wkt2, DistanceType const& expected_distance, ComparableDistanceType const& expected_comparable_distance, Strategy const& strategy, bool is_finite = true) { Geometry1 geometry1 = from_wkt(wkt1); Geometry2 geometry2 = from_wkt(wkt2); apply(geometry1, geometry2, expected_distance, expected_comparable_distance, strategy, is_finite); } template < typename DistanceType, typename ComparableDistanceType, typename Strategy > static inline void apply(Geometry1 const& geometry1, Geometry2 const& geometry2, DistanceType const& expected_distance, ComparableDistanceType const& expected_comparable_distance, Strategy const& strategy, bool is_finite = true) { #ifdef BOOST_GEOMETRY_TEST_DEBUG typedef pretty_print_geometry PPG1; typedef pretty_print_geometry PPG2; PPG1::apply(geometry1, std::cout); std::cout << " - "; PPG2::apply(geometry2, std::cout); std::cout << std::endl; #endif base_test("", geometry1, geometry2, expected_distance, expected_comparable_distance, strategy, is_finite); base_test("[reversed args]", geometry2, geometry1, expected_distance, expected_comparable_distance, strategy, is_finite); #ifdef BOOST_GEOMETRY_TEST_DEBUG std::cout << std::endl; #endif } }; //======================================================================== template struct test_distance_of_geometries < Segment, Polygon, 92 /* segment */, 3 /* polygon */ > : public test_distance_of_geometries { typedef test_distance_of_geometries base; typedef typename bg::ring_type::type ring_type; template < typename DistanceType, typename ComparableDistanceType, typename Strategy > static inline void apply(std::string const& wkt_segment, std::string const& wkt_polygon, DistanceType const& expected_distance, ComparableDistanceType const& expected_comparable_distance, Strategy const& strategy, bool is_finite = true) { Segment segment = from_wkt(wkt_segment); Polygon polygon = from_wkt(wkt_polygon); apply(segment, polygon, expected_distance, expected_comparable_distance, strategy, is_finite); } template < typename DistanceType, typename ComparableDistanceType, typename Strategy > static inline void apply(Segment const& segment, Polygon const& polygon, DistanceType const& expected_distance, ComparableDistanceType const& expected_comparable_distance, Strategy const& strategy, bool is_finite = true) { base::apply(segment, polygon, expected_distance, expected_comparable_distance, strategy, is_finite); if ( bg::num_interior_rings(polygon) == 0 ) { #ifdef BOOST_GEOMETRY_TEST_DEBUG std::cout << "... testing also exterior ring ..." << std::endl; #endif test_distance_of_geometries < Segment, ring_type >::apply(segment, bg::exterior_ring(polygon), expected_distance, expected_comparable_distance, strategy, is_finite); } } }; //======================================================================== template struct test_distance_of_geometries < Box, Segment, 94 /* box */, 92 /* segment */ > { template < typename DistanceType, typename ComparableDistanceType, typename Strategy > static inline void apply(std::string const& wkt_box, std::string const& wkt_segment, DistanceType const& expected_distance, ComparableDistanceType const& expected_comparable_distance, Strategy const& strategy, bool is_finite = true) { test_distance_of_geometries < Segment, Box, 92, 94 >::apply(wkt_segment, wkt_box, expected_distance, expected_comparable_distance, strategy, is_finite); } }; template struct test_distance_of_geometries < Segment, Box, 92 /* segment */, 94 /* box */ > : public test_distance_of_geometries { typedef test_distance_of_geometries base; template < typename DistanceType, typename ComparableDistanceType, typename Strategy > static inline void apply(std::string const& wkt_segment, std::string const& wkt_box, DistanceType const& expected_distance, ComparableDistanceType const& expected_comparable_distance, Strategy const& strategy, bool is_finite = true) { Segment segment = from_wkt(wkt_segment); Box box = from_wkt(wkt_box); apply(segment, box, expected_distance, expected_comparable_distance, strategy, is_finite); } template < typename DistanceType, typename ComparableDistanceType, typename Strategy > static inline void apply(Segment const& segment, Box const& box, DistanceType const& expected_distance, ComparableDistanceType const& expected_comparable_distance, Strategy const& strategy, bool is_finite = true) { typedef typename bg::strategy::distance::services::return_type < Strategy, Segment, Box >::type distance_result_type; typedef typename bg::strategy::distance::services::comparable_type < Strategy >::type comparable_strategy; typedef typename bg::strategy::distance::services::return_type < comparable_strategy, Segment, Box >::type comparable_distance_result_type; base::apply(segment, box, expected_distance, expected_comparable_distance, strategy, is_finite); comparable_strategy cstrategy = bg::strategy::distance::services::get_comparable < Strategy >::apply(strategy); distance_result_type distance_generic = bg::detail::distance::segment_to_box_2D_generic < Segment, Box, Strategy >::apply(segment, box, strategy); comparable_distance_result_type comparable_distance_generic = bg::detail::distance::segment_to_box_2D_generic < Segment, Box, comparable_strategy >::apply(segment, box, cstrategy); check_equal < distance_result_type >::apply(distance_generic, expected_distance, is_finite); check_equal < comparable_distance_result_type >::apply(comparable_distance_generic, expected_comparable_distance, is_finite); #ifdef BOOST_GEOMETRY_TEST_DEBUG std::cout << "... testing with naive seg-box distance algorithm..." << std::endl; std::cout << "distance (generic algorithm) = " << distance_generic << " ; " << "comp. distance (generic algorithm) = " << comparable_distance_generic << std::endl; std::cout << std::endl << std::endl; #endif } }; //======================================================================== template void test_empty_input(Geometry1 const& geometry1, Geometry2 const& geometry2, Strategy const& strategy) { try { bg::distance(geometry1, geometry2, strategy); } catch(bg::empty_input_exception const& ) { return; } BOOST_CHECK_MESSAGE(false, "A empty_input_exception should have been thrown" ); try { bg::distance(geometry2, geometry1, strategy); } catch(bg::empty_input_exception const& ) { return; } BOOST_CHECK_MESSAGE(false, "A empty_input_exception should have been thrown" ); } #endif // BOOST_GEOMETRY_TEST_DISTANCE_COMMON_HPP