// Boost.Geometry (aka GGL, Generic Geometry Library) test file // // Copyright Barend Gehrels 2007-2009, Geodan, Amsterdam, the Netherlands // Copyright Bruno Lalande 2008, 2009 // Use, modification and distribution is subject to the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) #define TEST_ARRAY #include #include #include #include #include #ifndef TEST_ARRAY #include #endif #include #include #include #include #include namespace bg = boost::geometry; // Define a custom distance strategy // For this one, the "taxicab" distance, // see http://en.wikipedia.org/wiki/Taxicab_geometry // For a point-point-distance operation, one typename Point is enough. // For a point-segment-distance operation, there is some magic inside // using another point type and casting if necessary. Therefore, // two point-types are necessary. template struct taxicab_distance { static inline typename boost::geometry::coordinate_type::type apply( P1 const& p1, P2 const& p2) { using boost::geometry::get; using boost::geometry::math::abs; return abs(get<0>(p1) - get<1>(p2)) + abs(get<1>(p1) - get<1>(p2)); } }; namespace boost { namespace geometry { namespace strategy { namespace distance { namespace services { template struct tag > { typedef strategy_tag_distance_point_point type; }; template struct return_type > { typedef typename coordinate_type::type type; }; template struct similar_type, PN1, PN2> { typedef taxicab_distance type; }; template struct get_similar, PN1, PN2> { static inline typename similar_type < taxicab_distance, PN1, PN2 >::type apply(taxicab_distance const& ) { return taxicab_distance(); } }; template struct comparable_type > { typedef taxicab_distance type; }; template struct get_comparable > { static inline taxicab_distance apply(taxicab_distance const& input) { return input; } }; template struct result_from_distance > { template static inline typename coordinate_type::type apply(taxicab_distance const& , T const& value) { return value; } }; }}}}} // namespace boost::geometry::strategy::distance::services template void test_distance_point() { namespace services = bg::strategy::distance::services; typedef typename bg::distance_result

::type return_type; { // Basic, trivial test P p1; bg::set<0>(p1, 1); bg::set<1>(p1, 1); P p2; bg::set<0>(p2, 2); bg::set<1>(p2, 2); return_type d = bg::distance(p1, p2); BOOST_CHECK_CLOSE(d, return_type(1.4142135), 0.001); // Test specifying strategy manually typename services::default_strategy::type strategy; d = bg::distance(p1, p2, strategy); BOOST_CHECK_CLOSE(d, return_type(1.4142135), 0.001); { // Test custom strategy BOOST_CONCEPT_ASSERT( (bg::concept::PointDistanceStrategy >) ); typedef typename services::return_type >::type cab_return_type; BOOST_MPL_ASSERT((boost::is_same::type>)); taxicab_distance

tcd; cab_return_type d = bg::distance(p1, p2, tcd); BOOST_CHECK( bg::math::abs(d - cab_return_type(2)) <= cab_return_type(0.01) ); } } { // 3-4-5 angle P p1, p2, p3; bg::set<0>(p1, 0); bg::set<1>(p1, 0); bg::set<0>(p2, 3); bg::set<1>(p2, 0); bg::set<0>(p3, 0); bg::set<1>(p3, 4); return_type dr12 = bg::distance(p1, p2); return_type dr13 = bg::distance(p1, p3); return_type dr23 = bg::distance(p2, p3); BOOST_CHECK_CLOSE(dr12, return_type(3), 0.001); BOOST_CHECK_CLOSE(dr13, return_type(4), 0.001); BOOST_CHECK_CLOSE(dr23, return_type(5), 0.001); } { // test comparability typedef typename services::default_strategy::type strategy_type; typedef typename services::comparable_type::type comparable_strategy_type; strategy_type strategy; comparable_strategy_type comparable_strategy = services::get_comparable::apply(strategy); return_type comparable = services::result_from_distance::apply(comparable_strategy, 3); BOOST_CHECK_CLOSE(comparable, return_type(9), 0.001); } } template void test_distance_segment() { typedef typename bg::distance_result

::type return_type; typedef typename bg::coordinate_type

::type coordinate_type; P s1; bg::set<0>(s1, 1); bg::set<1>(s1, 1); P s2; bg::set<0>(s2, 4); bg::set<1>(s2, 4); // Check points left, right, projected-left, projected-right, on segment P p1; bg::set<0>(p1, 0); bg::set<1>(p1, 1); P p2; bg::set<0>(p2, 1); bg::set<1>(p2, 0); P p3; bg::set<0>(p3, 3); bg::set<1>(p3, 1); P p4; bg::set<0>(p4, 1); bg::set<1>(p4, 3); P p5; bg::set<0>(p5, 3); bg::set<1>(p5, 3); bg::segment

const seg(s1, s2); return_type d1 = bg::distance(p1, seg); return_type d2 = bg::distance(p2, seg); return_type d3 = bg::distance(p3, seg); return_type d4 = bg::distance(p4, seg); return_type d5 = bg::distance(p5, seg); BOOST_CHECK_CLOSE(d1, return_type(1), 0.001); BOOST_CHECK_CLOSE(d2, return_type(1), 0.001); BOOST_CHECK_CLOSE(d3, return_type(1.4142135), 0.001); BOOST_CHECK_CLOSE(d4, return_type(1.4142135), 0.001); BOOST_CHECK_CLOSE(d5, return_type(0), 0.001); // Reverse case: segment/point instead of point/segment return_type dr1 = bg::distance(seg, p1); return_type dr2 = bg::distance(seg, p2); BOOST_CHECK_CLOSE(dr1, d1, 0.001); BOOST_CHECK_CLOSE(dr2, d2, 0.001); // Test specifying strategy manually: // 1) point-point-distance typename bg::strategy::distance::services::default_strategy::type pp_strategy; d1 = bg::distance(p1, seg, pp_strategy); BOOST_CHECK_CLOSE(d1, return_type(1), 0.001); // 2) point-segment-distance typename bg::strategy::distance::services::default_strategy::type ps_strategy; d1 = bg::distance(p1, seg, ps_strategy); BOOST_CHECK_CLOSE(d1, return_type(1), 0.001); // 3) custom point strategy taxicab_distance

tcd; return_type d = bg::distance(p1, seg, tcd); BOOST_CHECK_CLOSE(d1, return_type(1), 0.001); } template void test_distance_linestring() { typedef typename bg::distance_result

::type return_type; boost::array points; bg::set<0>(points[0], 1); bg::set<1>(points[0], 1); bg::set<0>(points[1], 3); bg::set<1>(points[1], 3); P p; bg::set<0>(p, 2); bg::set<1>(p, 1); return_type d = bg::distance(p, points); BOOST_CHECK_CLOSE(d, return_type(0.70710678), 0.001); bg::set<0>(p, 5); bg::set<1>(p, 5); d = bg::distance(p, points); BOOST_CHECK_CLOSE(d, return_type(2.828427), 0.001); bg::linestring

line; { P lp; bg::set<0>(lp, 1); bg::set<1>(lp, 1); line.push_back(lp); bg::set<0>(lp, 2); bg::set<1>(lp, 2); line.push_back(lp); bg::set<0>(lp, 3); bg::set<1>(lp, 3); line.push_back(lp); } bg::set<0>(p, 5); bg::set<1>(p, 5); d = bg::distance(p, line); BOOST_CHECK_CLOSE(d, return_type(2.828427), 0.001); // Reverse case: line/point instead of point/line d = bg::distance(line, p); BOOST_CHECK_CLOSE(d, return_type(2.828427), 0.001); } template void test_distance_ring() { typedef typename bg::distance_result

::type return_type; bg::linear_ring

ring; { P lp; bg::set<0>(lp, 1); bg::set<1>(lp, 1); line.push_back(lp); bg::set<0>(lp, 2); bg::set<1>(lp, 2); line.push_back(lp); bg::set<0>(lp, 3); bg::set<1>(lp, 3); line.push_back(lp); } bg::set<0>(p, 5); bg::set<1>(p, 5); d = bg::distance(p, line); BOOST_CHECK_CLOSE(d, return_type(2.828427), 0.001); // Reverse case: line/point instead of point/line d = bg::distance(line, p); BOOST_CHECK_CLOSE(d, return_type(2.828427), 0.001); } template void test_all() { test_distance_point

(); test_distance_segment

(); test_distance_linestring

(); } int test_main(int, char* []) { #ifdef TEST_ARRAY //test_all(); //test_all(); //test_all(); //test_all(); // located here because of 3D #endif test_all >(); test_all >(); test_all >(); test_all >(); return 0; }