diff --git a/include/boost/geometry/algorithms/detail/distance/segment_to_box.hpp b/include/boost/geometry/algorithms/detail/distance/segment_to_box.hpp index 1f58c6c3b..9955d69d9 100644 --- a/include/boost/geometry/algorithms/detail/distance/segment_to_box.hpp +++ b/include/boost/geometry/algorithms/detail/distance/segment_to_box.hpp @@ -656,8 +656,12 @@ private: { typename other_compare::type less_equal; + bool south = geometry::get<1>(p1) < 0 ? true : false; + // the segment lies below the box if (geometry::get<1>(p1) < geometry::get<1>(bottom_left)) + //if (geometry::get<1>(p1) * geometry::get<1>(bottom_left) > 0 && + // (math::abs(geometry::get<1>(p1)) < math::abs(geometry::get<1>(bottom_left)))) { result = check_below_of_box < @@ -673,6 +677,9 @@ private: // the segment lies above the box if (geometry::get<1>(p0) > geometry::get<1>(top_right)) + //if (geometry::get<1>(p0) * geometry::get<1>(top_right) < 0 || + // (math::abs(geometry::get<1>(p0)) > math::abs(geometry::get<1>(top_right)))) + { result = std::min(above_of_box < @@ -920,6 +927,65 @@ public: } }; +//========================================================================= +template +struct mirror_geometries +{ + template + static void apply(Point& p0, + Point& p1, + Point& bottom_left, + Point& bottom_right, + Point& top_left, + Point& top_right) + {} +}; + +template <> +struct mirror_geometries +{ + template + static void apply(Point& p0, + Point& p1, + Point& bottom_left, + Point& bottom_right, + Point& top_left, + Point& top_right) + { + //if segment's vertex is the southest point then mirror geometries + if (geometry::get<1>(p0) + geometry::get<1>(p1) < 0) + { + Point bl = bottom_left; + Point br = bottom_right; + geometry::set<1>(p0, geometry::get<1>(p0) * -1); + geometry::set<1>(p1, geometry::get<1>(p1) * -1); + geometry::set<1>(bottom_left, geometry::get<1>(top_left) * -1); + geometry::set<1>(top_left, geometry::get<1>(bl) * -1); + geometry::set<1>(bottom_right, geometry::get<1>(top_right) * -1); + geometry::set<1>(top_right, geometry::get<1>(br) * -1); + } + } +}; + +template <> +struct mirror_geometries +{ + template + static void apply(Point& p0, + Point& p1, + Point& bottom_left, + Point& bottom_right, + Point& top_left, + Point& top_right) + { + return mirror_geometries::apply(p0, p1, + bottom_left, + bottom_right, + top_left, + top_right); + } +}; + //========================================================================= @@ -1013,6 +1079,10 @@ public: detail::assign_box_corners(box, bottom_left, bottom_right, top_left, top_right); + mirror_geometries::type>::apply(p[0], p[1], + bottom_left, bottom_right, + top_left, top_right); + if (geometry::less()(p[0], p[1])) { return segment_to_box_2D diff --git a/test/algorithms/distance/distance_geo_linear_box.cpp b/test/algorithms/distance/distance_geo_linear_box.cpp index fcac30d6b..a80b10bf8 100644 --- a/test/algorithms/distance/distance_geo_linear_box.cpp +++ b/test/algorithms/distance/distance_geo_linear_box.cpp @@ -1,7 +1,7 @@ // Boost.Geometry (aka GGL, Generic Geometry Library) // Unit Test -// Copyright (c) 2017, Oracle and/or its affiliates. +// Copyright (c) 2017, 2018 Oracle and/or its affiliates. // Contributed and/or modified by Vissarion Fysikopoulos, on behalf of Oracle @@ -116,182 +116,221 @@ void test_distance_segment_box(Strategy_pp const& strategy_pp, #endif typedef test_distance_of_geometries tester; - std::string const box1 = "BOX(10 10,20 20)"; + std::string const box_north = "BOX(10 10,20 20)"; - tester::apply("sb1-1", "SEGMENT(0 0, 0 20)", box1, + tester::apply("sb1-1a", "SEGMENT(0 0, 0 20)", box_north, pp_distance("POINT(0 20)", "POINT(10 20)", strategy_pp), strategy_ps); - tester::apply("sb1-2", "SEGMENT(0 0, 0 10)", box1, + //segment with slope + tester::apply("sb1-1b", "SEGMENT(10 5, 20 6)", box_north, + pp_distance("POINT(20 6)", "POINT(20 10)", strategy_pp), + strategy_ps); + tester::apply("sb1-2", "SEGMENT(0 0, 0 10)", box_north, ps_distance("POINT(0 10)", "SEGMENT(10 10,10 20)", strategy_ps), strategy_ps); - tester::apply("sb1-3", "SEGMENT(0 0, 0 15)", box1, + tester::apply("sb1-3", "SEGMENT(0 0, 0 15)", box_north, ps_distance("POINT(0 15)", "SEGMENT(10 10,10 20)", strategy_ps), strategy_ps); - tester::apply("sb1-4", "SEGMENT(0 0, 0 25)", box1, + tester::apply("sb1-4", "SEGMENT(0 0, 0 25)", box_north, ps_distance("POINT(10 20)", "SEGMENT(0 0,0 25)", strategy_ps), strategy_ps); - tester::apply("sb1-5", "SEGMENT(0 10, 0 25)", box1, + tester::apply("sb1-5", "SEGMENT(0 10, 0 25)", box_north, ps_distance("POINT(10 20)", "SEGMENT(0 0,0 25)", strategy_ps), strategy_ps); - tester::apply("sb2-2", "SEGMENT(0 5, 15 5)", box1, + tester::apply("sb2-2", "SEGMENT(0 5, 15 5)", box_north, ps_distance("POINT(10 10)", "SEGMENT(0 5,15 5)", strategy_ps), strategy_ps); - tester::apply("sb2-3a", "SEGMENT(0 5, 20 5)", box1, + tester::apply("sb2-3a", "SEGMENT(0 5, 20 5)", box_north, ps_distance("POINT(10 10)", "SEGMENT(0 5,20 5)", strategy_ps), strategy_ps); // Test segments below box - tester::apply("test_b1", "SEGMENT(0 5, 9 5)", box1, + tester::apply("test_b1", "SEGMENT(0 5, 9 5)", box_north, ps_distance("POINT(10 10)", "SEGMENT(0 5, 9 5)", strategy_ps), strategy_ps); - tester::apply("test_b2", "SEGMENT(0 5, 10 5)", box1, + tester::apply("test_b2", "SEGMENT(0 5, 10 5)", box_north, ps_distance("POINT(10 10)", "SEGMENT(0 5, 10 5)", strategy_ps), strategy_ps); - tester::apply("test_b3", "SEGMENT(0 5, 11 5)", box1, + tester::apply("test_b3", "SEGMENT(0 5, 11 5)", box_north, ps_distance("POINT(10 10)", "SEGMENT(0 5, 11 5)", strategy_ps), strategy_ps); - tester::apply("test_b4", "SEGMENT(0 5, 20 5)", box1, + tester::apply("test_b4", "SEGMENT(0 5, 20 5)", box_north, ps_distance("POINT(10 10)", "SEGMENT(0 5,20 5)", strategy_ps), strategy_ps); - tester::apply("test_b5", "SEGMENT(0 5, 22 5)", box1, + tester::apply("test_b5", "SEGMENT(0 5, 22 5)", box_north, ps_distance("POINT(11 10)", "SEGMENT(0 5,22 5)", strategy_ps), strategy_ps); - tester::apply("test_b6", "SEGMENT(10 5, 20 5)", box1, + tester::apply("test_b6", "SEGMENT(10 5, 20 5)", box_north, ps_distance("POINT(15 10)", "SEGMENT(10 5,20 5)", strategy_ps), strategy_ps); - tester::apply("test_b7", "SEGMENT(10 5, 22 5)", box1, + tester::apply("test_b7", "SEGMENT(10 5, 22 5)", box_north, ps_distance("POINT(16 10)", "SEGMENT(10 5,22 5)", strategy_ps), strategy_ps); - tester::apply("test_b8", "SEGMENT(12 5, 22 5)", box1, + tester::apply("test_b8", "SEGMENT(12 5, 22 5)", box_north, ps_distance("POINT(17 10)", "SEGMENT(12 5,22 5)", strategy_ps), strategy_ps); - tester::apply("test_b9", "SEGMENT(18 5, 22 5)", box1, + tester::apply("test_b9", "SEGMENT(18 5, 22 5)", box_north, ps_distance("POINT(20 10)", "SEGMENT(18 5,22 5)", strategy_ps), strategy_ps); - tester::apply("test_b10", "SEGMENT(18 5, 24 5)", box1, + tester::apply("test_b10", "SEGMENT(18 5, 24 5)", box_north, ps_distance("POINT(20 10)", "SEGMENT(18 5,24 5)", strategy_ps), strategy_ps); - tester::apply("test_b11", "SEGMENT(20 5, 24 5)", box1, + tester::apply("test_b11", "SEGMENT(20 5, 24 5)", box_north, ps_distance("POINT(20 10)", "SEGMENT(20 5,24 5)", strategy_ps), strategy_ps); - tester::apply("test_b12", "SEGMENT(22 5, 24 5)", box1, + tester::apply("test_b12", "SEGMENT(22 5, 24 5)", box_north, ps_distance("POINT(20 10)", "SEGMENT(22 5,24 5)", strategy_ps), strategy_ps); // Test segments above box - tester::apply("test_a1", "SEGMENT(0 25, 9 25)", box1, + tester::apply("test_a1", "SEGMENT(0 25, 9 25)", box_north, ps_distance("POINT(10 20)", "SEGMENT(0 25, 9 25)", strategy_ps), strategy_ps); - tester::apply("test_a2", "SEGMENT(0 25, 10 25)", box1, + tester::apply("test_a2", "SEGMENT(0 25, 10 25)", box_north, ps_distance("POINT(10 20)", "SEGMENT(0 25, 10 25)", strategy_ps), strategy_ps); - tester::apply("test_a3", "SEGMENT(0 25, 11 25)", box1, + tester::apply("test_a3", "SEGMENT(0 25, 11 25)", box_north, ps_distance("POINT(11 20)", "SEGMENT(0 25, 11 25)", strategy_ps), strategy_ps); - tester::apply("test_a4", "SEGMENT(0 25, 20 25)", box1, + tester::apply("test_a4", "SEGMENT(0 25, 20 25)", box_north, ps_distance("POINT(20 20)", "SEGMENT(0 25, 20 25)", strategy_ps), strategy_ps); - tester::apply("test_a5", "SEGMENT(0 25, 22 25)", box1, + tester::apply("test_a5", "SEGMENT(0 25, 22 25)", box_north, ps_distance("POINT(20 20)", "SEGMENT(0 25, 22 25)", strategy_ps), strategy_ps); - tester::apply("test_a6", "SEGMENT(10 25, 20 25)", box1, + tester::apply("test_a6", "SEGMENT(10 25, 20 25)", box_north, ps_distance("POINT(20 20)", "SEGMENT(10 25, 20 25)", strategy_ps), strategy_ps); - tester::apply("test_a7", "SEGMENT(10 25, 22 25)", box1, + tester::apply("test_a7", "SEGMENT(10 25, 22 25)", box_north, ps_distance("POINT(10 20)", "SEGMENT(10 25, 22 25)", strategy_ps), strategy_ps); - tester::apply("test_a8", "SEGMENT(12 25, 22 25)", box1, + tester::apply("test_a8", "SEGMENT(12 25, 22 25)", box_north, ps_distance("POINT(12 20)", "SEGMENT(12 25, 22 25)", strategy_ps), strategy_ps); - tester::apply("test_a9", "SEGMENT(18 25, 22 25)", box1, + tester::apply("test_a9", "SEGMENT(18 25, 22 25)", box_north, ps_distance("POINT(18 20)", "SEGMENT(18 25, 22 25)", strategy_ps), strategy_ps); - tester::apply("test_a10", "SEGMENT(18 25, 24 25)", box1, + tester::apply("test_a10", "SEGMENT(18 25, 24 25)", box_north, ps_distance("POINT(18 20)", "SEGMENT(18 25, 24 25)", strategy_ps), strategy_ps); - tester::apply("test_a11", "SEGMENT(20 25, 24 25)", box1, + tester::apply("test_a11", "SEGMENT(20 25, 24 25)", box_north, ps_distance("POINT(20 20)", "SEGMENT(20 25, 24 25)", strategy_ps), strategy_ps); - tester::apply("test_a12", "SEGMENT(22 25, 24 25)", box1, + tester::apply("test_a12", "SEGMENT(22 25, 24 25)", box_north, ps_distance("POINT(20 20)", "SEGMENT(22 25, 24 25)", strategy_ps), strategy_ps); // Segments left-right of box - tester::apply("test_l1", "SEGMENT(0 5, 9 5)", box1, + tester::apply("test_l1", "SEGMENT(0 5, 9 5)", box_north, ps_distance("POINT(10 10)", "SEGMENT(0 5, 9 5)", strategy_ps), strategy_ps); - tester::apply("test_l2", "SEGMENT(0 10, 9 10)", box1, + tester::apply("test_l2", "SEGMENT(0 10, 9 10)", box_north, ps_distance("POINT(9 10)", "SEGMENT(10 10, 10 20)", strategy_ps), strategy_ps); - tester::apply("test_l3", "SEGMENT(0 10, 9 15)", box1, + tester::apply("test_l3", "SEGMENT(0 10, 9 15)", box_north, ps_distance("POINT(9 15)", "SEGMENT(10 10, 10 20)", strategy_ps), strategy_ps); - tester::apply("test_l4", "SEGMENT(0 10, 0 15)", box1, + tester::apply("test_l4", "SEGMENT(0 10, 0 15)", box_north, ps_distance("POINT(0 15)", "SEGMENT(10 10, 10 20)", strategy_ps), strategy_ps); - tester::apply("test_l5", "SEGMENT(1 10, 0 15)", box1, + tester::apply("test_l5", "SEGMENT(1 10, 0 15)", box_north, ps_distance("POINT(1 10)", "SEGMENT(10 10, 10 20)", strategy_ps), strategy_ps); - tester::apply("test_l6", "SEGMENT(0 20, 9 21)", box1, + tester::apply("test_l6", "SEGMENT(0 20, 9 21)", box_north, ps_distance("POINT(9 21)", "SEGMENT(10 10, 10 20)", strategy_ps), strategy_ps); - tester::apply("test_r1", "SEGMENT(21 5, 29 5)", box1, + tester::apply("test_r1", "SEGMENT(21 5, 29 5)", box_north, ps_distance("POINT(20 10)", "SEGMENT(21 5, 29 5)", strategy_ps), strategy_ps); - tester::apply("test_r2", "SEGMENT(21 10, 29 10)", box1, + tester::apply("test_r2", "SEGMENT(21 10, 29 10)", box_north, ps_distance("POINT(21 10)", "SEGMENT(20 10, 20 20)", strategy_ps), strategy_ps); - tester::apply("test_r3", "SEGMENT(21 10, 29 15)", box1, + tester::apply("test_r3", "SEGMENT(21 10, 29 15)", box_north, ps_distance("POINT(21 10)", "SEGMENT(20 10, 20 20)", strategy_ps), strategy_ps); - tester::apply("test_r4", "SEGMENT(21 10, 21 15)", box1, + tester::apply("test_r4", "SEGMENT(21 10, 21 15)", box_north, ps_distance("POINT(21 15)", "SEGMENT(20 10, 20 20)", strategy_ps), strategy_ps); - tester::apply("test_r5", "SEGMENT(21 10, 22 15)", box1, + tester::apply("test_r5", "SEGMENT(21 10, 22 15)", box_north, ps_distance("POINT(21 10)", "SEGMENT(20 10, 20 20)", strategy_ps), strategy_ps); - tester::apply("test_r6", "SEGMENT(29 20, 21 21)", box1, + tester::apply("test_r6", "SEGMENT(29 20, 21 21)", box_north, ps_distance("POINT(21 21)", "SEGMENT(20 10, 20 20)", strategy_ps), strategy_ps); - //segments on corners of box + //Segments on corners of box //left-top corner //generic - tester::apply("test_c1", "SEGMENT(9 19.5, 11 21)", box1, + tester::apply("test_c1", "SEGMENT(9 19.5, 11 21)", box_north, ps_distance("POINT(10 20)", "SEGMENT(9 19.5, 11 21)", strategy_ps), strategy_ps); //degenerate - tester::apply("test_c2", "SEGMENT(9 19, 11 21)", box1, + tester::apply("test_c2", "SEGMENT(9 19, 11 21)", box_north, ps_distance("POINT(10 20)", "SEGMENT(9 19, 11 21)", strategy_ps), strategy_ps); //left-bottom corner //generic - tester::apply("test_c3", "SEGMENT(8.5 11, 11 9)", box1, + tester::apply("test_c3", "SEGMENT(8.5 11, 11 9)", box_north, ps_distance("POINT(10 10)", "SEGMENT(8.5 11, 11 9)", strategy_ps), strategy_ps); //degenerate - tester::apply("test_c4", "SEGMENT(9 11, 11 9)", box1, + tester::apply("test_c4", "SEGMENT(9 11, 11 9)", box_north, 0, strategy_ps); //right-top corner //generic - tester::apply("test_c5", "SEGMENT(19 21, 21 19.5)", box1, + tester::apply("test_c5", "SEGMENT(19 21, 21 19.5)", box_north, ps_distance("POINT(20 20)", "SEGMENT(19 21, 21 19.5)", strategy_ps), strategy_ps); //degenerate - tester::apply("test_c6", "SEGMENT(19 21, 21 19)", box1, + tester::apply("test_c6", "SEGMENT(19 21, 21 19)", box_north, ps_distance("POINT(20 20)", "SEGMENT(19 21, 21 19)", strategy_ps), strategy_ps); //right-bottom corner //generic - tester::apply("test_c7", "SEGMENT(19 9, 21 10.5)", box1, + tester::apply("test_c7", "SEGMENT(19 9, 21 10.5)", box_north, ps_distance("POINT(20 10)", "SEGMENT(19 9, 21 10.5)", strategy_ps), strategy_ps); - tester::apply("test_c7", "SEGMENT(19 9, 21 11)", box1, + tester::apply("test_c7", "SEGMENT(19 9, 21 11)", box_north, 0, strategy_ps); + //Segment and box on different hemispheres + std::string const box_south = "BOX(10 -20,20 -10)"; + + tester::apply("test_ns1", "SEGMENT(10 20, 15 30)", box_south, + ps_distance("POINT(10 -10)", "SEGMENT(10 20, 15 30)", strategy_ps), + strategy_ps); + tester::apply("test_ns2", "SEGMENT(0 10, 12 10)", box_south, + pp_distance("POINT(12 10)", "POINT(12 -10)", strategy_pp), + strategy_ps); + tester::apply("test_ns3", "SEGMENT(10 10, 20 10)", box_south, + pp_distance("POINT(10 10)", "POINT(10 -10)", strategy_pp), + strategy_ps); + tester::apply("test_ns4", "SEGMENT(0 -10, 12 -10)", box_north, + pp_distance("POINT(12 10)", "POINT(12 -10)", strategy_pp), + strategy_ps); + tester::apply("test_ns5", "SEGMENT(10 -10, 20 -10)", box_north, + pp_distance("POINT(10 -10)", "POINT(10 10)", strategy_pp), + strategy_ps); + + //Box crossing equator + std::string const box_crossing = "BOX(10 -10,20 10)"; + + tester::apply("test_cr1", "SEGMENT(10 20, 15 30)", box_crossing, + pp_distance("POINT(10 10)", "POINT(10 20)", strategy_pp), + strategy_ps); + tester::apply("test_cr2", "SEGMENT(10 -20, 15 -30)", box_crossing, + pp_distance("POINT(10 10)", "POINT(10 20)", strategy_pp), + strategy_ps); + + //Geometries in south hemisphere + tester::apply("test_south1", "SEGMENT(10 -30, 15 -30)", box_south, + ps_distance("POINT(10 -20)", "SEGMENT(10 -30, 15 -30)", strategy_ps), + strategy_ps); + + } //=========================================================================== diff --git a/test/algorithms/distance/test_distance_geo_common.hpp b/test/algorithms/distance/test_distance_geo_common.hpp index a81af7ad1..412ac2a5d 100644 --- a/test/algorithms/distance/test_distance_geo_common.hpp +++ b/test/algorithms/distance/test_distance_geo_common.hpp @@ -45,15 +45,22 @@ namespace bg = ::boost::geometry; //=================================================================== -//tag dispatching for swaping arguments in segments template struct dispatch { + //tag dispatching for swaping arguments in segments template static inline T swap(T const& t) { return t; } + + // mirror geometry w.r.t. equator + template + static inline T mirror(T const& t) + { + return t; + } }; // Specialization for segments @@ -71,6 +78,42 @@ template <> struct dispatch return s_swaped; } + + template + static inline Segment mirror(Segment const& s) + { + Segment s_mirror; + + bg::set<0, 0>(s_mirror, bg::get<0, 0>(s)); + bg::set<0, 1>(s_mirror, bg::get<0, 1>(s) * -1); + bg::set<1, 0>(s_mirror, bg::get<1, 0>(s)); + bg::set<1, 1>(s_mirror, bg::get<1, 1>(s) * -1); + + return s_mirror; + } +}; + +// Specialization for boxes +template <> struct dispatch +{ + template + static inline T swap(T const& t) + { + return t; + } + + template + static inline Box mirror(Box const& b) + { + Box b_mirror; + + bg::set<0, 0>(b_mirror, bg::get(b)); + bg::set<0, 1>(b_mirror, bg::get(b) * -1); + bg::set<1, 0>(b_mirror, bg::get(b)); + bg::set<1, 1>(b_mirror, bg::get(b) * -1); + + return b_mirror; + } }; //======================================================================== @@ -133,14 +176,16 @@ struct test_distance_of_geometries DistanceType const& expected_distance, Strategy const& strategy, bool test_reversed = true, - bool swap_geometry_args = false) + bool swap_geometry_args = false, + bool mirror_geometry = true) { Geometry1 geometry1 = from_wkt(wkt1); Geometry2 geometry2 = from_wkt(wkt2); apply(case_id, geometry1, geometry2, expected_distance, - strategy, test_reversed, swap_geometry_args); + strategy, test_reversed, swap_geometry_args, + mirror_geometry); } @@ -156,7 +201,8 @@ struct test_distance_of_geometries DistanceType const& expected_distance, Strategy const& strategy, bool test_reversed = true, - bool swap_geometry_args = false) + bool swap_geometry_args = false, + bool mirror_geometry = true) { #ifdef BOOST_GEOMETRY_TEST_DEBUG std::cout << "case ID: " << case_id << "; " @@ -272,7 +318,35 @@ struct test_distance_of_geometries << std::endl; std::cout << std::endl; #endif - } + } + if (mirror_geometry) + { + Geometry1 g1 = dispatch + < + typename boost::geometry::tag::type + >::mirror(geometry1); + + Geometry2 g2 = dispatch + < + typename boost::geometry::tag::type + >::mirror(geometry2); + + // check distance with given strategy + dist = bg::distance(g1, g2, strategy); + + check_equal + < + default_distance_result + >::apply(case_id, "mirror", g1, g2, + dist, expected_distance); + +#ifdef BOOST_GEOMETRY_TEST_DEBUG + std::cout << "distance[mirror geometries] = " + << dist + << std::endl; + std::cout << std::endl; +#endif + } #ifdef BOOST_GEOMETRY_TEST_DEBUG std::cout << std::endl; #endif