// Boost.Geometry (aka GGL, Generic Geometry Library) // Unit Test // Copyright (c) 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_TEST_MODULE #define BOOST_TEST_MODULE test_douglas_peucker #endif #ifdef BOOST_GEOMETRY_TEST_DEBUG #ifndef BOOST_GEOMETRY_DEBUG_DOUGLAS_PEUCKER #define BOOST_GEOMETRY_DEBUG_DOUGLAS_PEUCKER #endif #endif #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace bg = ::boost::geometry; namespace ba = ::boost::assign; namespace services = bg::strategy::distance::services; typedef boost::tuple tuple_point_type; typedef std::vector tuple_multi_point_type; BOOST_GEOMETRY_REGISTER_BOOST_TUPLE_CS(cs::cartesian) BOOST_GEOMETRY_REGISTER_MULTI_POINT(tuple_multi_point_type) BOOST_GEOMETRY_REGISTER_MULTI_POINT_TEMPLATED(std::vector) typedef bg::strategy::distance::projected_point<> distance_strategy_type; typedef bg::strategy::distance::projected_point < void, bg::strategy::distance::comparable::pythagoras<> > comparable_distance_strategy_type; template struct default_simplify_strategy { typedef bg::model::point point_type; typedef typename bg::strategy::distance::services::default_strategy < bg::point_tag, bg::segment_tag, point_type >::type default_distance_strategy_type; typedef bg::strategy::simplify::douglas_peucker < point_type, default_distance_strategy_type > type; }; template struct simplify_regular_distance_strategy { typedef bg::model::point point_type; typedef bg::strategy::simplify::douglas_peucker < point_type, distance_strategy_type > type; }; template struct simplify_comparable_distance_strategy { typedef bg::model::point point_type; typedef bg::strategy::simplify::douglas_peucker < point_type, comparable_distance_strategy_type > type; }; template inline Geometry from_wkt(std::string const& wkt) { Geometry geometry; boost::geometry::read_wkt(wkt, geometry); return geometry; } template inline std::ostream& print_point_range(std::ostream& os, Iterator first, Iterator beyond, std::string const& header) { os << header << "("; for (Iterator it = first; it != beyond; ++it) { os << " " << bg::dsv(*it); } os << " )"; return os; } struct equals { template static inline bool apply(Iterator1 begin1, Iterator1 end1, Iterator2 begin2, Iterator2 end2) { std::size_t num_points1 = std::distance(begin1, end1); std::size_t num_points2 = std::distance(begin2, end2); if ( num_points1 != num_points2 ) { return false; } Iterator1 it1 = begin1; Iterator2 it2 = begin2; for (; it1 != end1; ++it1, ++it2) { if ( !bg::equals(*it1, *it2) ) { return false; } } return true; } template static inline bool apply(Range1 const& range1, Range2 const& range2) { return apply(boost::begin(range1), boost::end(range1), boost::begin(range2), boost::end(range2)); } }; template struct test_one_case { template static inline void apply(std::string const& case_id, std::string const& wkt, double max_distance, Strategy const& strategy, Range const& expected_result) { typedef typename bg::point_type::type point_type; std::vector result; Geometry geometry = from_wkt(wkt); std::string typeid_name = typeid(typename bg::coordinate_type::type).name(); #ifdef BOOST_GEOMETRY_TEST_DEBUG std::cout << case_id << " - " << typeid_name << std::endl; std::cout << wkt << std::endl; #endif strategy.apply(geometry, std::back_inserter(result), max_distance); boost::ignore_unused(strategy); #ifdef BOOST_GEOMETRY_TEST_DEBUG print_point_range(std::cout, boost::begin(result), boost::end(result), "output: "); std::cout << std::endl << std::endl; #endif std::stringstream stream_expected; print_point_range(stream_expected, boost::begin(expected_result), boost::end(expected_result), ""); std::stringstream stream_detected; print_point_range(stream_detected, boost::begin(result), boost::end(result), ""); BOOST_CHECK_MESSAGE(equals::apply(result, expected_result), "case id: " << case_id << " - " << typeid_name << ", geometry: " << wkt << ", Expected: " << stream_expected.str() << " - Detected: " << stream_detected.str()); #ifdef BOOST_GEOMETRY_TEST_DEBUG std::cout << "---------------" << std::endl; std::cout << "---------------" << std::endl; std::cout << std::endl << std::endl; #endif } }; template inline void test_with_strategy(std::string label) { std::cout.precision(20); Strategy strategy; typedef bg::model::point point_type; typedef bg::model::linestring linestring_type; typedef bg::model::segment segment_type; typedef test_one_case tester; label = " (" + label + ")"; { point_type const p1(-6,-13), p2(0,-15); segment_type const s(point_type(12,-3), point_type(-12,5)); if (bg::comparable_distance(p1, s) >= bg::comparable_distance(p2, s)) { tester::apply("l01c1" + label, "LINESTRING(12 -3, 4 8,-6 -13,-9 4,0 -15,-12 5)", 10, strategy, ba::tuple_list_of(12,-3)(4,8)(-6,-13)(-12,5) ); } else { tester::apply("l01c2" + label, "LINESTRING(12 -3, 4 8,-6 -13,-9 4,0 -15,-12 5)", 10, strategy, ba::tuple_list_of(12,-3)(4,8)(-6,-13)(-9,4)(0,-15)(-12,5) ); } } tester::apply("l02" + label, "LINESTRING(-6 -13,-9 4,0 -15,-12 5)", 10, strategy, ba::tuple_list_of(-6,-13)(-12,5) ); tester::apply("l03" + label, "LINESTRING(12 -3, 4 8,-6 -13,-9 4,0 -14,-12 5)", 10, strategy, ba::tuple_list_of(12,-3)(4,8)(-6,-13)(-12,5) ); tester::apply("l04" + label, "LINESTRING(12 -3, 4 8,-6 -13,-9 4,0 -14,-12 5)", 14, strategy, ba::tuple_list_of(12,-3)(-6,-13)(-12,5) ); { segment_type const s(point_type(0,-1), point_type(5,-4)); point_type const p1(5,-1), p2(0,-4); #ifdef BOOST_GEOMETRY_TEST_DEBUG bool d_larger_first = (bg::distance(p1, s) > bg::distance(p2, s)); bool d_larger_second = (bg::distance(p1, s) < bg::distance(p2, s)); bool cd_larger_first = (bg::comparable_distance(p1, s) > bg::comparable_distance(p2, s)); bool cd_larger_second = (bg::comparable_distance(p1, s) < bg::comparable_distance(p2, s)); std::cout << "segment: " << bg::dsv(s) << std::endl; std::cout << "distance from " << bg::dsv(p1) << ": " << bg::distance(p1, s) << std::endl; std::cout << "comp. distance from " << bg::dsv(p1) << ": " << bg::comparable_distance(p1, s) << std::endl; std::cout << "distance from " << bg::dsv(p2) << ": " << bg::distance(p2, s) << std::endl; std::cout << "comp. distance from " << bg::dsv(p2) << ": " << bg::comparable_distance(p2, s) << std::endl; std::cout << "larger distance from " << (d_larger_first ? "first" : (d_larger_second ? "second" : "equal")) << std::endl; std::cout << "larger comp. distance from " << (cd_larger_first ? "first" : (cd_larger_second ? "second" : "equal")) << std::endl; std::cout << "difference of distances: " << (bg::distance(p1, s) - bg::distance(p2, s)) << std::endl; std::cout << "difference of comp. distances: " << (bg::comparable_distance(p1, s) - bg::comparable_distance(p2, s)) << std::endl; #endif std::string wkt = "LINESTRING(0 0,5 0,0 -1,5 -1,0 -2,5 -2,0 -3,5 -3,0 -4,5 -4,0 0)"; if (bg::comparable_distance(p1, s) >= bg::comparable_distance(p2, s)) { tester::apply("l05c1" + label, wkt, 1, strategy, ba::tuple_list_of(0,0)(5,0)(0,-1)(5,-1)(0,-2)(5,-2)(0,-3)(5,-4)(0,0) ); tester::apply("l05c1a" + label, wkt, 2, strategy, ba::tuple_list_of(0,0)(5,0)(0,-1)(5,-1)(0,-2)(5,-4)(0,0) ); } else { tester::apply("l05c2" + label, wkt, 1, strategy, ba::tuple_list_of(0,0)(5,0)(0,-1)(5,-1)(0,-2)(5,-2)(0,-4)(5,-4)(0,0) ); tester::apply("l05c2a" + label, wkt, 2, strategy, ba::tuple_list_of(0,0)(5,0)(0,-1)(5,-1)(0,-4)(5,-4)(0,0) ); } } #ifdef BOOST_GEOMETRY_TEST_DEBUG std::cout << std::endl; std::cout << std::endl; std::cout << "*************************************************"; std::cout << std::endl; std::cout << std::endl; #endif } BOOST_AUTO_TEST_CASE( test_default_strategy ) { test_with_strategy::type>("i"); test_with_strategy::type>("f"); test_with_strategy::type>("d"); test_with_strategy < long double, default_simplify_strategy::type >("ld"); } BOOST_AUTO_TEST_CASE( test_with_regular_distance_strategy ) { test_with_strategy < int, simplify_regular_distance_strategy::type >("i"); test_with_strategy < float, simplify_regular_distance_strategy::type >("f"); test_with_strategy < double, simplify_regular_distance_strategy::type >("d"); test_with_strategy < long double, simplify_regular_distance_strategy::type >("ld"); } BOOST_AUTO_TEST_CASE( test_with_comparable_distance_strategy ) { test_with_strategy < int, simplify_comparable_distance_strategy::type >("i"); test_with_strategy < float, simplify_comparable_distance_strategy::type >("f"); test_with_strategy < double, simplify_comparable_distance_strategy::type >("d"); test_with_strategy < long double, simplify_comparable_distance_strategy::type >("ld"); }