diff --git a/doc/release_notes.qbk b/doc/release_notes.qbk index 423d3df14..22b1a9642 100644 --- a/doc/release_notes.qbk +++ b/doc/release_notes.qbk @@ -22,6 +22,8 @@ [*Improvements] * The support of parameters convertible to value_type in rtree insert(), remove() and count() functions +* Support for counterclockwise input/output in algorithm buffer +* Support for degenerate input in algorithm buffer [*Solved tickets] diff --git a/include/boost/geometry/algorithms/detail/buffer/buffer_inserter.hpp b/include/boost/geometry/algorithms/detail/buffer/buffer_inserter.hpp index 7a901c869..2021a0481 100644 --- a/include/boost/geometry/algorithms/detail/buffer/buffer_inserter.hpp +++ b/include/boost/geometry/algorithms/detail/buffer/buffer_inserter.hpp @@ -29,6 +29,8 @@ #include +#include + #if defined(BOOST_GEOMETRY_BUFFER_SIMPLIFY_WITH_AX) #include #endif @@ -87,6 +89,13 @@ inline void simplify_input(Range const& range, geometry::simplify(range, simplified, max_distance, strategy); #endif + + if (boost::size(simplified) == 2 + && geometry::equals(geometry::range::front(simplified), + geometry::range::back(simplified))) + { + traits::resize::apply(simplified, 1); + } } @@ -202,7 +211,7 @@ struct buffer_range typename EndStrategy, typename RobustPolicy > - static inline void iterate(Collection& collection, + static inline bool iterate(Collection& collection, Iterator begin, Iterator end, strategy::buffer::buffer_side_selector side, DistanceStrategy const& distance_strategy, @@ -246,6 +255,7 @@ struct buffer_range * pup: penultimate_point */ + bool result = false; bool first = true; Iterator it = begin; @@ -259,14 +269,21 @@ struct buffer_range { robust_point_type robust_input; geometry::recalculate(robust_input, *it, robust_policy); - // Check on equality - however, if input is simplified, this is highly - // unlikely (though possible by rescaling) + // Check on equality - however, if input is simplified, this is + // unlikely (though possible by rescaling or for degenerated pointlike polygons) if (! detail::equals::equals_point_point(previous_robust_input, robust_input)) { generated_side.clear(); side_strategy.apply(*prev, *it, side, distance_strategy, generated_side); + if (generated_side.empty()) + { + break; + } + + result = true; + if (! first) { add_join(collection, @@ -295,6 +312,7 @@ struct buffer_range } previous_robust_input = robust_input; } + return result; } }; @@ -345,6 +363,26 @@ struct visit_pieces_default_policy {} }; +template +< + typename OutputPointType, + typename Point, + typename Collection, + typename DistanceStrategy, + typename PointStrategy +> +inline void buffer_point(Point const& point, Collection& collection, + DistanceStrategy const& distance_strategy, + PointStrategy const& point_strategy) +{ + collection.start_new_ring(); + std::vector range_out; + point_strategy.apply(point, distance_strategy, range_out); + collection.add_piece(strategy::buffer::buffered_point, range_out, false); + collection.finish_ring(); +} + + }} // namespace detail::buffer #endif // DOXYGEN_NO_DETAIL @@ -389,13 +427,10 @@ struct buffer_inserter PointStrategy const& point_strategy, RobustPolicy const& ) { - typedef typename point_type::type output_point_type; - - collection.start_new_ring(); - std::vector range_out; - point_strategy.apply(point, distance_strategy, range_out); - collection.add_piece(strategy::buffer::buffered_point, range_out, false); - collection.finish_ring(); + detail::buffer::buffer_point + < + typename point_type::type + >(point, collection, distance_strategy, point_strategy); } }; @@ -419,7 +454,7 @@ struct buffer_inserter typename EndStrategy, typename RobustPolicy > - static inline void iterate(Collection& collection, + static inline bool iterate(Collection& collection, Iterator begin, Iterator end, strategy::buffer::buffer_side_selector side, DistanceStrategy const& distance_strategy, @@ -432,21 +467,25 @@ struct buffer_inserter typedef detail::buffer::buffer_range buffer_range; - buffer_range::iterate(collection, begin, end, + bool result = buffer_range::iterate(collection, begin, end, side, distance_strategy, side_strategy, join_strategy, end_strategy, robust_policy, first_p1, first_p2, last_p1, last_p2); // Generate closing join - buffer_range::add_join(collection, - *(end - 2), - *(end - 1), last_p1, last_p2, - *(begin + 1), first_p1, first_p2, - side, - distance_strategy, join_strategy, end_strategy, - robust_policy); + if (result) + { + buffer_range::add_join(collection, + *(end - 2), + *(end - 1), last_p1, last_p2, + *(begin + 1), first_p1, first_p2, + side, + distance_strategy, join_strategy, end_strategy, + robust_policy); + } // Buffer is closed automatically by last closing corner + return result; } template @@ -465,30 +504,43 @@ struct buffer_inserter SideStrategy const& side_strategy, JoinStrategy const& join_strategy, EndStrategy const& end_strategy, - PointStrategy const& , + PointStrategy const& point_strategy, RobustPolicy const& robust_policy) { - if (boost::size(ring) > 3) - { - RingOutput simplified; - detail::buffer::simplify_input(ring, distance, simplified); + RingInput simplified; + detail::buffer::simplify_input(ring, distance, simplified); + bool has_output = false; + + std::size_t n = boost::size(simplified); + if (n > 3) + { + detail::normalized_view view(simplified); if (distance.negative()) { // Walk backwards (rings will be reversed afterwards) // It might be that this will be changed later. // TODO: decide this. - iterate(collection, boost::rbegin(simplified), boost::rend(simplified), + has_output = iterate(collection, boost::rbegin(view), boost::rend(view), strategy::buffer::buffer_side_right, distance, side_strategy, join_strategy, end_strategy, robust_policy); } else { - iterate(collection, boost::begin(simplified), boost::end(simplified), + has_output = iterate(collection, boost::begin(view), boost::end(view), strategy::buffer::buffer_side_left, distance, side_strategy, join_strategy, end_strategy, robust_policy); } + } + if (! has_output && n >= 1) + { + // Use point_strategy to buffer degenerated ring + detail::buffer::buffer_point + ( + geometry::range::front(simplified), + collection, distance, point_strategy + ); } } }; @@ -505,19 +557,6 @@ struct buffer_inserter typedef typename point_type::type output_point_type; typedef typename point_type::type input_point_type; - template - static inline output_point_type first_perpendicular_point( - input_point_type const& p1, input_point_type const& p2, - DistanceStrategy const& distance_strategy, - SideStrategy const& side_strategy) - { - std::vector generated_side; - side_strategy.apply(p1, p2, - strategy::buffer::buffer_side_right, - distance_strategy, generated_side); - return generated_side.front(); - } - template < typename Collection, @@ -528,7 +567,7 @@ struct buffer_inserter typename EndStrategy, typename RobustPolicy > - static inline void iterate(Collection& collection, + static inline bool iterate(Collection& collection, Iterator begin, Iterator end, strategy::buffer::buffer_side_selector side, DistanceStrategy const& distance_strategy, @@ -545,10 +584,23 @@ struct buffer_inserter // other side of the linestring. If it is the second pass (right), // we have it already from the first phase (left). // But for the first pass, we have to generate it - output_point_type reverse_p1 - = side == strategy::buffer::buffer_side_right - ? first_p1 - : first_perpendicular_point(ultimate_point, penultimate_point, distance_strategy, side_strategy); + output_point_type reverse_p1; + if (side == strategy::buffer::buffer_side_right) + { + reverse_p1 = first_p1; + } + else + { + std::vector generated_side; + side_strategy.apply(ultimate_point, penultimate_point, + strategy::buffer::buffer_side_right, + distance_strategy, generated_side); + if (generated_side.empty()) + { + return false; + } + reverse_p1 = generated_side.front(); + } output_point_type first_p2, last_p1, last_p2; @@ -560,6 +612,7 @@ struct buffer_inserter std::vector range_out; end_strategy.apply(penultimate_point, last_p2, ultimate_point, reverse_p1, side, distance_strategy, range_out); collection.add_endcap(end_strategy, range_out, ultimate_point); + return true; } template @@ -577,30 +630,41 @@ struct buffer_inserter SideStrategy const& side_strategy, JoinStrategy const& join_strategy, EndStrategy const& end_strategy, - PointStrategy const& , + PointStrategy const& point_strategy, RobustPolicy const& robust_policy) { - if (boost::size(linestring) > 1) - { - Linestring simplified; - detail::buffer::simplify_input(linestring, distance, simplified); + Linestring simplified; + detail::buffer::simplify_input(linestring, distance, simplified); + bool has_output = false; + std::size_t n = boost::size(simplified); + if (n > 1) + { collection.start_new_ring(); output_point_type first_p1; - iterate(collection, boost::begin(simplified), boost::end(simplified), + has_output = iterate(collection, + boost::begin(simplified), boost::end(simplified), strategy::buffer::buffer_side_left, distance, side_strategy, join_strategy, end_strategy, robust_policy, first_p1); - iterate(collection, boost::rbegin(simplified), boost::rend(simplified), - strategy::buffer::buffer_side_right, - distance, side_strategy, join_strategy, end_strategy, robust_policy, - first_p1); + if (has_output) + { + iterate(collection, boost::rbegin(simplified), boost::rend(simplified), + strategy::buffer::buffer_side_right, + distance, side_strategy, join_strategy, end_strategy, robust_policy, + first_p1); + } collection.finish_ring(); } - else + if (! has_output && n >= 1) { // Use point_strategy to buffer degenerated linestring + detail::buffer::buffer_point + ( + geometry::range::front(simplified), + collection, distance, point_strategy + ); } } }; @@ -814,7 +878,16 @@ inline void buffer_inserter(GeometryInput const& geometry_input, OutputIterator collection.enrich(); collection.traverse(); - if (distance_strategy.negative() && areal) + // Reverse all offsetted rings / traversed rings if: + // - they were generated on the negative side (deflate) of polygons + // - the output is counter clockwise + // and avoid reversing twice + bool reverse = distance_strategy.negative() && areal; + if (geometry::point_order::value == counterclockwise) + { + reverse = ! reverse; + } + if (reverse) { collection.reverse(); } diff --git a/include/boost/geometry/algorithms/detail/buffer/buffered_piece_collection.hpp b/include/boost/geometry/algorithms/detail/buffer/buffered_piece_collection.hpp index 3a002601c..558a61fcb 100644 --- a/include/boost/geometry/algorithms/detail/buffer/buffered_piece_collection.hpp +++ b/include/boost/geometry/algorithms/detail/buffer/buffered_piece_collection.hpp @@ -117,6 +117,8 @@ struct buffered_piece_collection point_type, RobustPolicy >::type robust_point_type; + + // Robust ring/polygon type, always clockwise typedef geometry::model::ring robust_ring_type; typedef geometry::model::polygon robust_polygon_type; @@ -571,7 +573,11 @@ struct buffered_piece_collection inline void finish_ring(bool is_interior = false) { - BOOST_ASSERT(m_first_piece_index != -1); + if (m_first_piece_index == -1) + { + return; + } + if (m_first_piece_index < static_cast(boost::size(m_pieces))) { // If piece was added diff --git a/include/boost/geometry/strategies/cartesian/buffer_side_straight.hpp b/include/boost/geometry/strategies/cartesian/buffer_side_straight.hpp index b5d28e257..24655ab3d 100644 --- a/include/boost/geometry/strategies/cartesian/buffer_side_straight.hpp +++ b/include/boost/geometry/strategies/cartesian/buffer_side_straight.hpp @@ -9,8 +9,6 @@ #include -#include - #include #include #include @@ -69,14 +67,19 @@ public : // Generate a block along (left or right of) the segment // Simulate a vector d (dx,dy) - coordinate_type dx = get<0>(input_p2) - get<0>(input_p1); - coordinate_type dy = get<1>(input_p2) - get<1>(input_p1); + coordinate_type const dx = get<0>(input_p2) - get<0>(input_p1); + coordinate_type const dy = get<1>(input_p2) - get<1>(input_p1); // For normalization [0,1] (=dot product d.d, sqrt) promoted_type const length = geometry::math::sqrt(dx * dx + dy * dy); - // Because coordinates are not equal, length should not be zero - BOOST_ASSERT((! geometry::math::equals(length, 0))); + if (geometry::math::equals(length, 0)) + { + // Coordinates are simplified and therefore most often not equal. + // But if simplify is skipped, or for lines with two + // equal points, length is 0 and we cannot generate output. + return; + } // Generate the normalized perpendicular p, to the left (ccw) promoted_type const px = -dy / length; diff --git a/test/algorithms/buffer/linestring_buffer.cpp b/test/algorithms/buffer/linestring_buffer.cpp index bdca6e3d0..078ca3f21 100644 --- a/test/algorithms/buffer/linestring_buffer.cpp +++ b/test/algorithms/buffer/linestring_buffer.cpp @@ -27,6 +27,12 @@ static std::string const overlapping = "LINESTRING(0 0,4 5,7 4,10 6, 10 2,2 2)"; static std::string const curve = "LINESTRING(2 7,3 5,5 4,7 5,8 7)"; static std::string const tripod = "LINESTRING(5 0,5 5,1 8,5 5,9 8)"; // with spike +static std::string const degenerate0 = "LINESTRING()"; +static std::string const degenerate1 = "LINESTRING(5 5)"; +static std::string const degenerate2 = "LINESTRING(5 5,5 5)"; +static std::string const degenerate3 = "LINESTRING(5 5,5 5,5 5)"; +static std::string const degenerate4 = "LINESTRING(5 5,5 5,4 4,5 5,5 5)"; + static std::string const for_collinear = "LINESTRING(2 0,0 0,0 4,6 4,6 0,4 0)"; static std::string const for_collinear2 = "LINESTRING(2 1,2 0,0 0,0 4,6 4,6 0,4 0,4 1)"; @@ -42,11 +48,11 @@ static std::string const aimes171 = "LINESTRING(-2.393161 52.265087,-2.393002 52 static std::string const aimes181 = "LINESTRING(-2.320686 52.43505,-2.320678 52.435016,-2.320697 52.434978,-2.3207 52.434977,-2.320741 52.434964,-2.320807 52.434964,-2.320847 52.434986,-2.320903 52.435022)"; -template +template void test_all() { typedef bg::model::linestring

linestring; - typedef bg::model::polygon

polygon; + typedef bg::model::polygon polygon; bg::strategy::buffer::join_miter join_miter; bg::strategy::buffer::join_round join_round(100); @@ -133,6 +139,13 @@ void test_all() test_one("field_sprayer1", field_sprayer1, join_round, end_round, 718.761877, 16.5, 6.5); test_one("field_sprayer1", field_sprayer1, join_miter, end_round, 718.939628, 16.5, 6.5); + test_one("degenerate0", degenerate0, join_round, end_round, 0.0, 3.0); + test_one("degenerate1", degenerate1, join_round, end_round, 28.25, 3.0); + test_one("degenerate2", degenerate2, join_round, end_round, 28.2503, 3.0); + test_one("degenerate3", degenerate3, join_round, end_round, 28.2503, 3.0); + test_one("degenerate4", degenerate4, join_round, end_round, 36.7410, 3.0); + test_one("degenerate4", degenerate4, join_round, end_flat, 8.4853, 3.0); + double tolerance = 1.0e-10; test_one("aimes120", aimes120, join_miter, end_flat, 1.62669948622351512e-08, 0.000018, 0.000018, false, tolerance); @@ -165,7 +178,8 @@ void test_all() int test_main(int, char* []) { - test_all >(); + test_all >(); + test_all >(); //test_all >(); return 0; } diff --git a/test/algorithms/buffer/multi_linestring_buffer.cpp b/test/algorithms/buffer/multi_linestring_buffer.cpp index 6174e3c8e..c36a3a2e4 100644 --- a/test/algorithms/buffer/multi_linestring_buffer.cpp +++ b/test/algorithms/buffer/multi_linestring_buffer.cpp @@ -15,13 +15,19 @@ static std::string const simplex = "MULTILINESTRING((0 0,4 5),(5 4,10 0))"; static std::string const two_bends = "MULTILINESTRING((0 0,4 5,7 4,10 6),(1 5,5 9,8 6))"; static std::string const turn_inside = "MULTILINESTRING((0 0,4 5,7 4,10 6),(1 5,5 9,8 6),(0 4,-2 6))"; +static std::string const degenerate0 = "MULTILINESTRING()"; +static std::string const degenerate1 = "MULTILINESTRING((5 5))"; +static std::string const degenerate2 = "MULTILINESTRING((5 5),(9 9))"; +static std::string const degenerate3 = "MULTILINESTRING((5 5),(9 9),(4 10))"; +static std::string const degenerate4 = "MULTILINESTRING((5 5,5 5),(9 9,9 9,10 10,9 9,9 9,9 9),(4 10,4 10,3 11,4 12,3 11,4 10,4 10))"; -template + +template void test_all() { typedef bg::model::linestring

linestring; typedef bg::model::multi_linestring multi_linestring_type; - typedef bg::model::polygon

polygon; + typedef bg::model::polygon polygon; bg::strategy::buffer::join_miter join_miter; bg::strategy::buffer::join_round join_round(100); @@ -49,13 +55,20 @@ void test_all() test_one("two_bends", two_bends, join_round_by_divide, end_flat, 64.6217, 1.5, 1.5); test_one("two_bends", two_bends, join_miter, end_flat, 65.1834, 1.5, 1.5); test_one("two_bends", two_bends, join_miter, end_round, 75.2917, 1.5, 1.5); + + test_one("degenerate0", degenerate0, join_round, end_round, 0.0, 3.0, 3.0); + test_one("degenerate1", degenerate1, join_round, end_round, 28.2503, 3.0, 3.0); + test_one("degenerate2", degenerate2, join_round, end_round, 56.0457, 3.0, 3.0); + test_one("degenerate3", degenerate3, join_round, end_round, 80.4531, 3.0, 3.0); + test_one("degenerate4", degenerate4, join_round, end_round, 104.3142, 3.0, 3.0); } int test_main(int, char* []) { - test_all >(); + test_all >(); + test_all >(); return 0; } diff --git a/test/algorithms/buffer/multi_point_buffer.cpp b/test/algorithms/buffer/multi_point_buffer.cpp index 148292ef4..da0efc3a7 100644 --- a/test/algorithms/buffer/multi_point_buffer.cpp +++ b/test/algorithms/buffer/multi_point_buffer.cpp @@ -21,12 +21,10 @@ static std::string const multipoint_a = "MULTIPOINT((39 44),(38 37),(41 29),(15 static std::string const multipoint_b = "MULTIPOINT((5 56),(98 67),(20 7),(58 60),(10 4),(75 68),(61 68),(75 62),(92 26),(74 6),(67 54),(20 43),(63 30),(45 7))"; -template +template void test_all() { - //std::cout << typeid(bg::coordinate_type

::type).name() << std::endl; - - typedef bg::model::polygon

polygon; + typedef bg::model::polygon polygon; typedef bg::model::multi_point

multi_point_type; bg::strategy::buffer::join_miter join_miter; @@ -185,9 +183,8 @@ void test_growth(int n, int distance_count) int test_main(int, char* []) { - //std::cout << std::setprecision(6); - //test_all >(); - test_all >(); + test_all >(); + test_all >(); #ifdef BOOST_GEOMETRY_BUFFER_TEST_GROWTH diff --git a/test/algorithms/buffer/multi_polygon_buffer.cpp b/test/algorithms/buffer/multi_polygon_buffer.cpp index 9beeff8cc..4cce69a4c 100644 --- a/test/algorithms/buffer/multi_polygon_buffer.cpp +++ b/test/algorithms/buffer/multi_polygon_buffer.cpp @@ -24,6 +24,13 @@ static std::string const wrapped static std::string const triangles = "MULTIPOLYGON(((0 4,3 0,-2.5 -1,0 4)),((3 8,5.5 13,8 8,3 8)),((11 4,13.5 -1,8 0,11 4)))"; +static std::string const degenerate0 + = "MULTIPOLYGON()"; +static std::string const degenerate1 + = "MULTIPOLYGON(((5 5,5 5,5 5,5 5)),((6 6,6 6,6 6,6 6)))"; +static std::string const degenerate2 + = "MULTIPOLYGON(((0 0,0 10,10 10,10 0,0 0),(5 5,5 5,5 5,5 5)),((11 5,11 5,11 5,11 5)))"; + // From robustness tests (rt) // Case with duplicate points (due to chained boxes) (round) @@ -260,10 +267,10 @@ static std::string const rt_u12 static std::string const rt_u13 = "MULTIPOLYGON(((6 4,6 5,7 5,6 4)),((3 2,3 3,4 3,3 2)),((7 8,7 9,8 9,8 8,7 8)),((4 9,4 10,5 10,4 9)),((7 7,7 8,8 7,7 7)),((2 6,2 7,3 7,2 6)),((0 1,1 2,1 1,0 1)),((3 1,4 2,4 1,3 1)),((2 5,2 6,3 6,2 5)),((3 5,4 4,3 4,2 4,3 5)),((4 1,5 2,5 1,4 1)),((2 0,2 1,3 1,2 0)),((5 7,5 8,6 7,5 7)),((0 2,0 3,1 3,0 2)),((9 8,9 9,10 9,10 8,9 8)),((7 5,7 6,8 5,7 5)),((5 6,5 7,6 6,5 6)),((0 6,0 7,1 7,1 6,0 6)),((5 0,5 1,6 1,5 0)),((8 7,8 8,9 8,8 7)),((4.5 4.5,5 4,4 4,4 5,5 5,4.5 4.5)),((6 2,5 2,5 3,6 3,7 3,8 2,7 2,6 2)),((8 6,8 7,9 7,9 6,9 5,8 5,8 6)),((8 1,9 0,8 0,7 0,8 1)))"; -template +template void test_all() { - typedef bg::model::polygon

polygon_type; + typedef bg::model::polygon polygon_type; typedef bg::model::multi_polygon multi_polygon_type; bg::strategy::buffer::join_miter join_miter; @@ -298,6 +305,10 @@ void test_all() test_one("wrapped_15", wrapped, join_round, end_flat, 167.066, 1.5); test_one("wrapped_15", wrapped, join_miter, end_flat, 169.000, 1.5); + test_one("degenerate0", degenerate0, join_round, end_flat, 0.0, 1.0); + test_one("degenerate1", degenerate1, join_round, end_flat, 5.708, 1.0); + test_one("degenerate2", degenerate2, join_round, end_flat, 133.0166, 0.75); + test_one("rt_a", rt_a, join_round, end_flat, 34.5381, 1.0); test_one("rt_a", rt_a, join_miter, end_flat, 36, 1.0); test_one("rt_b", rt_b, join_round, end_flat, 31.4186, 1.0); @@ -394,7 +405,8 @@ void test_all() int test_main(int, char* []) { - test_all >(); + test_all >(); + test_all >(); //test_all >(); return 0; diff --git a/test/algorithms/buffer/point_buffer.cpp b/test/algorithms/buffer/point_buffer.cpp index ff68b9c52..a5f1b979b 100644 --- a/test/algorithms/buffer/point_buffer.cpp +++ b/test/algorithms/buffer/point_buffer.cpp @@ -7,29 +7,15 @@ // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) -//#define BOOST_GEOMETRY_DEBUG_WITH_MAPPER -//#define BOOST_GEOMETRY_DEBUG_ASSEMBLE -//#define BOOST_GEOMETRY_DEBUG_IDENTIFIER - -#include - -#include -#include - -#include - -#include -#include - #include static std::string const simplex = "POINT(5 5)"; -template +template void test_all() { - typedef bg::model::polygon

polygon; + typedef bg::model::polygon polygon; bg::strategy::buffer::join_miter join_miter; bg::strategy::buffer::end_flat end_flat; @@ -44,8 +30,7 @@ void test_all() int test_main(int, char* []) { - //std::cout << std::setprecision(6); - //test_all >(); - test_all >(); + test_all >(); + test_all >(); return 0; } diff --git a/test/algorithms/buffer/polygon_buffer.cpp b/test/algorithms/buffer/polygon_buffer.cpp index e19b4f500..fe3e48bf5 100644 --- a/test/algorithms/buffer/polygon_buffer.cpp +++ b/test/algorithms/buffer/polygon_buffer.cpp @@ -63,6 +63,16 @@ static std::string const bowl static std::string const triangle = "POLYGON((4 5,5 4,4 4,3 4,3 5,3 6,4 5))"; +static std::string const degenerate0 + = "POLYGON(())"; +static std::string const degenerate1 + = "POLYGON((5 5))"; +static std::string const degenerate2 + = "POLYGON((5 5,5 5,5 5,5 5))"; +static std::string const degenerate3 + = "POLYGON((0 0,0 10,10 10,10 0,0 0),(5 5,5 5,5 5,5 5))"; + + // Real-life examples static std::string const county1 = "POLYGON((-111.700 41.200 ,-111.681388 41.181739 ,-111.682453 41.181506 ,-111.684052 41.180804 ,-111.685295 41.180538 ,-111.686318 41.180776 ,-111.687517 41.181416 ,-111.688982 41.181520 ,-111.690670 41.181523 ,-111.692135 41.181460 ,-111.693646 41.182034 ,-111.695156 41.182204 ,-111.696489 41.182274 ,-111.697775 41.182075 ,-111.698974 41.181539 ,-111.700485 41.182348 ,-111.701374 41.182955 ,-111.700 41.200))"; @@ -98,11 +108,15 @@ static std::string const ticket_10398_4 static std::string const ticket_10412 = "POLYGON((897747.8 6270564.3,897764.3 6270569.7,897776.5 6270529.5,897768.1 6270527.1,897767.6 6270529.4,897756.3 6270525.8,897745.8 6270522.3,897752 6270502.9,897749.7 6270502,897750.7 6270499.1,897751.8 6270498.6,897752.3 6270499.3,897754.6 6270497.9,897755.8 6270500.2,897766.8 6270494.1,897765.6 6270491.5,897768.3 6270490.5,897770.9 6270491.5,897770.2 6270494.6,897780.1 6270497.5,897781 6270494.6,897786.8 6270496.6,897790.8 6270482.5,897785.3 6270480.7,897785.9 6270478.2,897768.9 6270473.2,897768.1 6270475.8,897766.1 6270475.2,897758.7 6270479.2,897753.2 6270481.8,897751.9 6270479,897746.5 6270481.9,897748 6270484.6,897745.2 6270486.1,897743.9 6270483.3,897741.4 6270484.7,897742.6 6270487.3,897739.4 6270488.9,897738.3 6270486.3,897735.6 6270487.8,897733.1 6270496.8,897731.2 6270502.7,897732.4 6270503.2,897731.5 6270506.1,897730.3 6270505.7,897725.8 6270520.2,897726.8 6270520.7,897726 6270523,897728 6270523.7,897726.3 6270529.6,897742.8 6270534.5,897741.2 6270539.9,897751.4 6270543.4,897750.7 6270546.4,897753.2 6270547.2,897747.8 6270564.3))"; +static std::string const mysql_report_2014_10_24 + = "POLYGON((0 0, 0 8, 8 8, 8 10, -10 10, -10 0, 0 0))"; -template + + +template void test_all() { - typedef bg::model::polygon

polygon_type; + typedef bg::model::polygon polygon_type; bg::strategy::buffer::join_miter join_miter(10.0); bg::strategy::buffer::join_round join_round(100); @@ -210,6 +224,11 @@ void test_all() test_one("fork_c1", fork_c, join_miter, end_flat, 152, 1); test_one("triangle", triangle, join_miter, end_flat, 14.6569, 1.0); + test_one("degenerate0", degenerate0, join_round, end_round, 0.0, 1.0); + test_one("degenerate1", degenerate1, join_round, end_round, 3.1389, 1.0); + test_one("degenerate2", degenerate2, join_round, end_round, 3.1389, 1.0); + test_one("degenerate3", degenerate3, join_round, end_round, 143.1395, 1.0); + test_one("gammagate2", gammagate, join_miter, end_flat, 130, 2); test_one("flower1", flower, join_miter, end_flat, 67.614, 0.1); @@ -310,11 +329,12 @@ void test_all() test_one("parcel3_30", parcel3, join_round, end_flat, 45261.4196014404297, 30.0); test_one("parcel3_30", parcel3, join_miter, end_flat, 45567.3875694274902, 30.0); - test_one("parcel3_bend_10", parcel3_bend, join_round, end_flat, 155.6188, 5.0); + test_one("parcel3_bend_5", parcel3_bend, join_round, end_flat, 155.6188, 5.0); test_one("parcel3_bend_10", parcel3_bend, join_round, end_flat, 458.4187, 10.0); - test_one("parcel3_bend_10", parcel3_bend, join_round, end_flat, 917.9747, 15.0); - test_one("parcel3_bend_10", parcel3_bend, join_round, end_flat, 1534.4795, 20.0); + // These cases differ a bit based on point order (TODO: find out / describe why) + test_one("parcel3_bend_15", parcel3_bend, join_round, end_flat, Clockwise ? 917.9747 : 917.996, 15.0); + test_one("parcel3_bend_20", parcel3_bend, join_round, end_flat, Clockwise ? 1534.4795 : 1534.508, 20.0); // Negative buffers making polygons smaller test_one("simplex", simplex, join_round, end_flat, 7.04043, -0.5); @@ -344,8 +364,34 @@ void test_all() test_one("ticket_10398_4_91", ticket_10398_4, join_miter, end_flat, 819.1406, 9.1, -999, false); test_one("ticket_10412", ticket_10412, join_miter, end_flat, 3109.6616, 1.5, -999, false); + + bg::strategy::buffer::join_round join_round32(32); + bg::strategy::buffer::end_round end_round32(32); + test_one("mysql_report_2014_10_24", mysql_report_2014_10_24, join_round32, end_round32, 174.902, 1.0, -999, false); } +template +< + typename InputPoint, + typename OutputPoint, + bool InputClockwise, + bool OutputClockwise, + bool InputClosed, + bool OutputClosed +> +void test_mixed() +{ + typedef bg::model::polygon input_polygon_type; + typedef bg::model::polygon output_polygon_type; + + bg::strategy::buffer::join_round join_round(12); + bg::strategy::buffer::end_flat end_flat; + + std::ostringstream name; + name << "mixed_" << std::boolalpha << InputClockwise << "_" << OutputClockwise << "_" << InputClosed << "_" << OutputClosed; + + test_one(name.str(), simplex, join_round, end_flat, 47.4831, 1.5); +} #ifdef HAVE_TTMATH #include @@ -353,8 +399,16 @@ void test_all() int test_main(int, char* []) { - test_all >(); + typedef bg::model::point dpoint; + + test_all(); + test_all(); //test_all >(); - + + test_mixed(); + test_mixed(); + test_mixed(); + test_mixed(); + return 0; } diff --git a/test/algorithms/buffer/test_buffer.hpp b/test/algorithms/buffer/test_buffer.hpp index c6467fdeb..248519c58 100644 --- a/test/algorithms/buffer/test_buffer.hpp +++ b/test/algorithms/buffer/test_buffer.hpp @@ -412,6 +412,7 @@ void test_buffer(std::string const& caseid, Geometry const& geometry, << "_" << join_name << (end_name.empty() ? "" : "_") << end_name << (distance_left < 0 && distance_right < 0 ? "_deflate" : "") + << (bg::point_order::value == bg::counterclockwise ? "_ccw" : "") // << "_" << point_buffer_count ; diff --git a/test/strategies/Jamfile.v2 b/test/strategies/Jamfile.v2 index 474378a27..d32c10737 100644 --- a/test/strategies/Jamfile.v2 +++ b/test/strategies/Jamfile.v2 @@ -8,6 +8,7 @@ # Modifications copyright (c) 2014, 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 # # Use, modification and distribution is subject to the Boost Software License, # Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at @@ -16,8 +17,11 @@ test-suite boost-geometry-strategies : [ run cross_track.cpp ] + [ run crossings_multiply.cpp ] [ run distance_default_result.cpp ] + [ run franklin.cpp ] [ run haversine.cpp ] + [ run point_in_box.cpp ] [ run projected_point.cpp ] [ run projected_point_ax.cpp ] [ run pythagoras.cpp ] @@ -26,5 +30,5 @@ test-suite boost-geometry-strategies [ run segment_intersection_collinear.cpp ] [ run transform_cs.cpp ] [ run transformer.cpp ] - [ run winding_franklin_crossmult.cpp ] + [ run winding.cpp ] ; diff --git a/test/strategies/crossings_multiply.cpp b/test/strategies/crossings_multiply.cpp new file mode 100644 index 000000000..f57d383f1 --- /dev/null +++ b/test/strategies/crossings_multiply.cpp @@ -0,0 +1,87 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) +// Unit Test + +// Copyright (c) 2010-2012 Barend Gehrels, Amsterdam, the Netherlands. + +// This file was modified by Oracle on 2014. +// Modifications copyright (c) 2014 Oracle and/or its affiliates. + +// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle + +// 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) + + +#include + + +template +void test_all() +{ + typedef bg::model::polygon polygon; + + std::string const box = "POLYGON((0 0,0 2,2 2,2 0,0 0))"; + std::string const triangle = "POLYGON((0 0,0 4,6 0,0 0))"; + std::string const with_hole = "POLYGON((0 0,0 3,3 3,3 0,0 0),(1 1,2 1,2 2,1 2,1 1))"; + + bg::strategy::within::crossings_multiply s; + + + test_geometry("b1", "POINT(1 1)", box, s, true); + test_geometry("b2", "POINT(3 3)", box, s, false); + + // Test ALL corners (officialy false but some strategies might answer true) + test_geometry("b3a", "POINT(0 0)", box, s, false); + test_geometry("b3b", "POINT(0 2)", box, s, false); + test_geometry("b3c", "POINT(2 2)", box, s, false); + test_geometry("b3d", "POINT(2 0)", box, s, false); + + // Test ALL sides (officialy false but some strategies might answer true) + test_geometry("b4a", "POINT(0 1)", box, s, false); + test_geometry("b4b", "POINT(1 2)", box, s, true); // different + test_geometry("b4c", "POINT(2 1)", box, s, false); + test_geometry("b4d", "POINT(1 0)", box, s, false); + + + test_geometry("t1", "POINT(1 1)", triangle, s, true); + test_geometry("t2", "POINT(3 3)", triangle, s, false); + + test_geometry("t3a", "POINT(0 0)", triangle, s, false); + test_geometry("t3b", "POINT(0 4)", triangle, s, true); // diff + test_geometry("t3c", "POINT(5 0)", triangle, s, false); + + test_geometry("t4a", "POINT(0 2)", triangle, s, false); + test_geometry("t4b", "POINT(3 2)", triangle, s, false); + test_geometry("t4c", "POINT(2 0)", triangle, s, false); + + + test_geometry("h1", "POINT(0.5 0.5)", with_hole, s, true); + test_geometry("h2a", "POINT(1.5 1.5)", with_hole, s, false); + test_geometry("h2b", "POINT(5 5)", with_hole, s, false); + + test_geometry("h3a", "POINT(1 1)", with_hole, s, true); // diff + test_geometry("h3b", "POINT(2 2)", with_hole, s, false); + test_geometry("h3c", "POINT(0 0)", with_hole, s, false); + + test_geometry("h4a", "POINT(1 1.5)", with_hole, s, false); + test_geometry("h4b", "POINT(1.5 2)", with_hole, s, false); + + // Lying ON (one of the sides of) interior ring + test_geometry("#77-1", "POINT(6 3.5)", + "POLYGON((5 3,5 4,4 4,4 5,3 5,3 6,5 6,5 5,7 5,7 6,8 6,8 5,9 5,9 2,8 2,8 1,7 1,7 2,5 2,5 3),(6 3,8 3,8 4,6 4,6 3))", + s, false); +} + + +int test_main(int, char* []) +{ + test_all >(); + test_all >(); + +#if defined(HAVE_TTMATH) + test_all >(); +#endif + + return 0; +} diff --git a/test/strategies/franklin.cpp b/test/strategies/franklin.cpp new file mode 100644 index 000000000..6a6c5fe17 --- /dev/null +++ b/test/strategies/franklin.cpp @@ -0,0 +1,86 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) +// Unit Test + +// Copyright (c) 2010-2012 Barend Gehrels, Amsterdam, the Netherlands. + +// This file was modified by Oracle on 2014. +// Modifications copyright (c) 2014 Oracle and/or its affiliates. + +// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle + +// 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) + + +#include + + +template +void test_all() +{ + typedef bg::model::polygon polygon; + + std::string const box = "POLYGON((0 0,0 2,2 2,2 0,0 0))"; + std::string const triangle = "POLYGON((0 0,0 4,6 0,0 0))"; + std::string const with_hole = "POLYGON((0 0,0 3,3 3,3 0,0 0),(1 1,2 1,2 2,1 2,1 1))"; + + bg::strategy::within::franklin s; + + test_geometry("b1", "POINT(1 1)", box, s, true); + test_geometry("b2", "POINT(3 3)", box, s, false); + + // Test ALL corners (officialy false but some strategies might answer true) + test_geometry("b3a", "POINT(0 0)", box, s, true); // different + test_geometry("b3b", "POINT(0 2)", box, s, false); + test_geometry("b3c", "POINT(2 2)", box, s, false); + test_geometry("b3d", "POINT(2 0)", box, s, false); + + // Test ALL sides (officialy false but some strategies might answer true) + test_geometry("b4a", "POINT(0 1)", box, s, true); // different + test_geometry("b4b", "POINT(1 2)", box, s, false); + test_geometry("b4c", "POINT(2 1)", box, s, false); + test_geometry("b4d", "POINT(1 0)", box, s, true); // different + + + test_geometry("t1", "POINT(1 1)", triangle, s, true); + test_geometry("t2", "POINT(3 3)", triangle, s, false); + + test_geometry("t3a", "POINT(0 0)", triangle, s, true); // diff + test_geometry("t3b", "POINT(0 4)", triangle, s, false); + test_geometry("t3c", "POINT(5 0)", triangle, s, true); // diff + + test_geometry("t4a", "POINT(0 2)", triangle, s, true); // diff + test_geometry("t4b", "POINT(3 2)", triangle, s, false); + test_geometry("t4c", "POINT(2 0)", triangle, s, true); // diff + + + test_geometry("h1", "POINT(0.5 0.5)", with_hole, s, true); + test_geometry("h2a", "POINT(1.5 1.5)", with_hole, s, false); + test_geometry("h2b", "POINT(5 5)", with_hole, s, false); + + test_geometry("h3a", "POINT(1 1)", with_hole, s, false); + test_geometry("h3b", "POINT(2 2)", with_hole, s, true); // diff + test_geometry("h3c", "POINT(0 0)", with_hole, s, true); // diff + + test_geometry("h4a", "POINT(1 1.5)", with_hole, s, false); + test_geometry("h4b", "POINT(1.5 2)", with_hole, s, true); // diff + + // Lying ON (one of the sides of) interior ring + test_geometry("#77-1", "POINT(6 3.5)", + "POLYGON((5 3,5 4,4 4,4 5,3 5,3 6,5 6,5 5,7 5,7 6,8 6,8 5,9 5,9 2,8 2,8 1,7 1,7 2,5 2,5 3),(6 3,8 3,8 4,6 4,6 3))", + s, false); +} + + +int test_main(int, char* []) +{ + test_all >(); + test_all >(); + +#if defined(HAVE_TTMATH) + test_all >(); +#endif + + return 0; +} diff --git a/test/strategies/point_in_box.cpp b/test/strategies/point_in_box.cpp new file mode 100644 index 000000000..1c5e04879 --- /dev/null +++ b/test/strategies/point_in_box.cpp @@ -0,0 +1,81 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) +// Unit Test + +// Copyright (c) 2010-2012 Barend Gehrels, Amsterdam, the Netherlands. + +// This file was modified by Oracle on 2014. +// Modifications copyright (c) 2014 Oracle and/or its affiliates. + +// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle + +// 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) + + +#include + + +template +void test_box_of(std::string const& wkt_point, std::string const& wkt_box, + bool expected_within, bool expected_covered_by) +{ + typedef bg::model::box box_type; + + Point point; + box_type box; + bg::read_wkt(wkt_point, point); + bg::read_wkt(wkt_box, box); + + bool detected_within = bg::within(point, box); + bool detected_covered_by = bg::covered_by(point, box); + BOOST_CHECK_EQUAL(detected_within, expected_within); + BOOST_CHECK_EQUAL(detected_covered_by, expected_covered_by); + + // Also test with the non-default agnostic side version + namespace wi = bg::strategy::within; + wi::point_in_box_by_side within_strategy; + wi::point_in_box_by_side covered_by_strategy; + + detected_within = bg::within(point, box, within_strategy); + detected_covered_by = bg::covered_by(point, box, covered_by_strategy); + BOOST_CHECK_EQUAL(detected_within, expected_within); + BOOST_CHECK_EQUAL(detected_covered_by, expected_covered_by); + + // We might exchange strategies between within/covered by. + // So the lines below might seem confusing, but are as intended + detected_within = bg::covered_by(point, box, within_strategy); + detected_covered_by = bg::within(point, box, covered_by_strategy); + BOOST_CHECK_EQUAL(detected_within, expected_within); + BOOST_CHECK_EQUAL(detected_covered_by, expected_covered_by); + + // Finally we call the strategies directly + detected_within = within_strategy.apply(point, box); + detected_covered_by = covered_by_strategy.apply(point, box); + BOOST_CHECK_EQUAL(detected_within, expected_within); + BOOST_CHECK_EQUAL(detected_covered_by, expected_covered_by); +} + +template +void test_box() +{ + test_box_of("POINT(1 1)", "BOX(0 0,2 2)", true, true); + test_box_of("POINT(0 0)", "BOX(0 0,2 2)", false, true); + test_box_of("POINT(2 2)", "BOX(0 0,2 2)", false, true); + test_box_of("POINT(0 1)", "BOX(0 0,2 2)", false, true); + test_box_of("POINT(1 0)", "BOX(0 0,2 2)", false, true); + test_box_of("POINT(3 3)", "BOX(0 0,2 2)", false, false); +} + + +int test_main(int, char* []) +{ + test_box >(); + test_box >(); + +#if defined(HAVE_TTMATH) + test_box >(); +#endif + + return 0; +} diff --git a/test/strategies/test_within.hpp b/test/strategies/test_within.hpp new file mode 100644 index 000000000..4ceb2608e --- /dev/null +++ b/test/strategies/test_within.hpp @@ -0,0 +1,106 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) +// Unit Test + +// Copyright (c) 2010-2012 Barend Gehrels, Amsterdam, the Netherlands. + +// This file was modified by Oracle on 2014. +// Modifications copyright (c) 2014 Oracle and/or its affiliates. + +// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle + +// 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) + +#ifndef BOOST_GEOMETRY_TEST_STRATEGIES_TEST_WITHIN_HPP +#define BOOST_GEOMETRY_TEST_STRATEGIES_TEST_WITHIN_HPP + + +#include + +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include + + +#include +#include +#include + +#include + + +template +inline const char * strategy_name(Strategy const&) +{ + return typeid(Strategy).name(); +} + +template +inline const char * strategy_name(bg::strategy::within::crossings_multiply const&) +{ + return "crossings_multiply"; +} + +template +inline const char * strategy_name(bg::strategy::within::franklin const&) +{ + return "franklin"; +} + +template +inline const char * strategy_name(bg::strategy::within::winding const&) +{ + return "winding"; +} + + +template +void test_point_in_polygon(std::string const& case_id, + Point const& point, + Polygon const& polygon, + Strategy const& strategy, + bool expected, + bool use_within = true) +{ + BOOST_CONCEPT_ASSERT( (bg::concept::WithinStrategyPolygonal) ); + bool detected = use_within ? + bg::within(point, polygon, strategy) : + bg::covered_by(point, polygon, strategy); + + BOOST_CHECK_MESSAGE(detected == expected, + (use_within ? "within: " : "covered_by: ") << case_id + << " strategy: " << strategy_name(strategy) + << " output expected: " << int(expected) + << " detected: " << int(detected) + ); +} + + +template +void test_geometry(std::string const& case_id, + std::string const& wkt_point, + std::string const& wkt_polygon, + Strategy const& strategy, + bool expected, + bool use_within = true) +{ + Point point; + Polygon polygon; + bg::read_wkt(wkt_point, point); + bg::read_wkt(wkt_polygon, polygon); + + test_point_in_polygon(case_id, point, polygon, strategy, expected, use_within); +} + + +#endif // BOOST_GEOMETRY_TEST_STRATEGIES_TEST_WITHIN_HPP diff --git a/test/strategies/winding.cpp b/test/strategies/winding.cpp new file mode 100644 index 000000000..ff0f3605a --- /dev/null +++ b/test/strategies/winding.cpp @@ -0,0 +1,227 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) +// Unit Test + +// Copyright (c) 2010-2012 Barend Gehrels, Amsterdam, the Netherlands. + +// This file was modified by Oracle on 2014. +// Modifications copyright (c) 2014 Oracle and/or its affiliates. + +// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle + +// 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) + + +#include + + +template +void test_cartesian() +{ + typedef bg::model::polygon polygon; + + std::string const box = "POLYGON((0 0,0 2,2 2,2 0,0 0))"; + std::string const triangle = "POLYGON((0 0,0 4,6 0,0 0))"; + std::string const with_hole = "POLYGON((0 0,0 3,3 3,3 0,0 0),(1 1,2 1,2 2,1 2,1 1))"; + + bg::strategy::within::winding s; + + + test_geometry("b1", "POINT(1 1)", box, s, true); + test_geometry("b2", "POINT(3 3)", box, s, false); + + // Test ALL corners (officialy false but some strategies might answer true) + test_geometry("b3a", "POINT(0 0)", box, s, false); + test_geometry("b3b", "POINT(0 2)", box, s, false); + test_geometry("b3c", "POINT(2 2)", box, s, false); + test_geometry("b3d", "POINT(2 0)", box, s, false); + + // Test ALL sides (officialy false but some strategies might answer true) + test_geometry("b4a", "POINT(0 1)", box, s, false); + test_geometry("b4b", "POINT(1 2)", box, s, false); + test_geometry("b4c", "POINT(2 1)", box, s, false); + test_geometry("b4d", "POINT(1 0)", box, s, false); + + + test_geometry("t1", "POINT(1 1)", triangle, s, true); + test_geometry("t2", "POINT(3 3)", triangle, s, false); + + test_geometry("t3a", "POINT(0 0)", triangle, s, false); + test_geometry("t3b", "POINT(0 4)", triangle, s, false); + test_geometry("t3c", "POINT(5 0)", triangle, s, false); + + test_geometry("t4a", "POINT(0 2)", triangle, s, false); + test_geometry("t4b", "POINT(3 2)", triangle, s, false); + test_geometry("t4c", "POINT(2 0)", triangle, s, false); + + + test_geometry("h1", "POINT(0.5 0.5)", with_hole, s, true); + test_geometry("h2a", "POINT(1.5 1.5)", with_hole, s, false); + test_geometry("h2b", "POINT(5 5)", with_hole, s, false); + + test_geometry("h3a", "POINT(1 1)", with_hole, s, false); + test_geometry("h3b", "POINT(2 2)", with_hole, s, false); + test_geometry("h3c", "POINT(0 0)", with_hole, s, false); + + test_geometry("h4a", "POINT(1 1.5)", with_hole, s, false); + test_geometry("h4b", "POINT(1.5 2)", with_hole, s, false); + + // Lying ON (one of the sides of) interior ring + test_geometry("#77-1", "POINT(6 3.5)", + "POLYGON((5 3,5 4,4 4,4 5,3 5,3 6,5 6,5 5,7 5,7 6,8 6,8 5,9 5,9 2,8 2,8 1,7 1,7 2,5 2,5 3),(6 3,8 3,8 4,6 4,6 3))", + s, false); +} + +template +void test_spherical() +{ + typedef bg::model::point > point; + typedef bg::model::polygon polygon; + + bg::strategy::within::winding s; + + + // Ticket #9354 + test_geometry( + "#9354", + "POINT(-78.1239 25.9556)", + "POLYGON((-97.08466667 25.95683333, -97.13683333 25.954, -97.1 26, -97.08466667 25.95683333))", + s, + false); + +#ifdef BOOST_GEOMETRY_TEST_STRATEGIES_WINDING_ENABLE_FAILING_TESTS + + test_geometry( + "sph1N", + "POINT(0 10.001)", + "POLYGON((-10 10, 10 10, 10 -10, -10 -10, -10 10))", + s, + bg::strategy::side::spherical_side_formula<>::apply( + point(-10, 10), + point(10, 10), + point(0, (T)10.001)) == -1 // right side + /*true*/); + test_geometry( + "sph1S", + "POINT(0 -10.001)", + "POLYGON((-10 10, 10 10, 10 -10, -10 -10, -10 10))", + s, + bg::strategy::side::spherical_side_formula<>::apply( + point(10, -10), + point(-10, -10), + point(0, (T)-10.001)) == -1 // right side + /*true*/); + + test_geometry( + "sph2S", + "POINT(0 10.001)", + "POLYGON((-10 20, 10 20, 10 10, -10 10, -10 20))", + s, + bg::strategy::side::spherical_side_formula<>::apply( + point(10, 10), + point(-10, 10), + point(0, (T)10.001)) == -1 // right side + /*false*/); + + test_geometry( + "sph3N", + "POINT(0 10)", + "POLYGON((-10 10, 10 10, 10 -10, -10 -10, -10 10))", + s, + bg::strategy::side::spherical_side_formula<>::apply( + point(-10, 10), + point(10, 10), + point(0, (T)10.001)) == -1 // right side + /*true*/); + test_geometry( + "sph3S", + "POINT(0 -10)", + "POLYGON((-10 10, 10 10, 10 -10, -10 -10, -10 10))", + s, + bg::strategy::side::spherical_side_formula<>::apply( + point(10, -10), + point(-10, -10), + point(0, (T)-10.001)) == -1 // right side + /*true*/); + +#endif // BOOST_GEOMETRY_TEST_STRATEGIES_WINDING_ENABLE_FAILING_TESTS + + test_geometry( + "sphEq1", + "POINT(179 10)", + "POLYGON((170 10, -170 10, -170 0, 170 0, 170 10))", + s, + true, + false); + test_geometry( + "sphEq2", + "POINT(179 10)", + "POLYGON((170 20, -170 20, -170 10, 170 10, 170 20))", + s, + true, + false); + test_geometry( + "sphEq3", + "POINT(-179 10)", + "POLYGON((170 10, -170 10, -170 0, 170 0, 170 10))", + s, + true, + false); + test_geometry( + "sphEq4", + "POINT(-179 10)", + "POLYGON((170 20, -170 20, -170 10, 170 10, 170 20))", + s, + true, + false); + +#ifdef BOOST_GEOMETRY_TEST_STRATEGIES_WINDING_ENABLE_FAILING_TESTS + + test_geometry( + "sphEq5", + "POINT(169 10)", + "POLYGON((170 20, -170 20, -170 10, 170 10, 170 20))", + s, + false, + false); + test_geometry( + "sphEq6", + "POINT(-169 10)", + "POLYGON((170 20, -170 20, -170 10, 170 10, 170 20))", + s, + false, + false); + test_geometry( + "sphEq7", + "POINT(169 10)", + "POLYGON((170 10, -170 10, -170 0, 170 0, 170 10))", + s, + false, + false); + test_geometry( + "sphEq8", + "POINT(-169 10)", + "POLYGON((170 10, -170 10, -170 0, 170 0, 170 10))", + s, + false, + false); + +#endif // BOOST_GEOMETRY_TEST_STRATEGIES_WINDING_ENABLE_FAILING_TESTS +} + +int test_main(int, char* []) +{ + test_cartesian >(); + test_cartesian >(); + + test_spherical(); + test_spherical(); + +#if defined(HAVE_TTMATH) + test_cartesian >(); + test_spherical(); +#endif + + return 0; +} diff --git a/test/strategies/winding_franklin_crossmult.cpp b/test/strategies/winding_franklin_crossmult.cpp deleted file mode 100644 index 427e82c87..000000000 --- a/test/strategies/winding_franklin_crossmult.cpp +++ /dev/null @@ -1,326 +0,0 @@ -// Boost.Geometry (aka GGL, Generic Geometry Library) -// Unit Test - -// Copyright (c) 2010-2012 Barend Gehrels, Amsterdam, the Netherlands. - -// 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) - -// Tests with-strategies, especially point-in-polygon - -#include - -#include -#include - -#include -#include -#include -#include -#include -#include - -#include -#include - - -#include -#include -#include - -#include - - - - - - -template -void test_point_in_polygon(std::string const& case_id, - Point const& point, Polygon const& polygon, - Strategy const& strategy, std::string const& strategy_id, - bool expected, bool use_within = true) -{ - BOOST_CONCEPT_ASSERT( (bg::concept::WithinStrategyPolygonal) ); - bool detected = use_within ? - bg::within(point, polygon, strategy) : - bg::covered_by(point, polygon, strategy); - - BOOST_CHECK_MESSAGE(detected == expected, - (use_within ? "within: " : "covered_by: ") << case_id - << " strategy: " << strategy_id // typeid(strategy).name() is too long - << " output expected: " << int(expected) - << " detected: " << int(detected) - ); -} - -template -void test_geometry(std::string const& case_id, std::string const& wkt_point - , std::string const& wkt_polygon - , bool expected - , std::string const& deviations = "" - , bool use_within = true) -{ - Point point; - Polygon polygon; - bg::read_wkt(wkt_point, point); - bg::read_wkt(wkt_polygon, polygon); - - namespace sw = bg::strategy::within; - test_point_in_polygon(case_id, point, polygon, sw::winding(), - "winding", expected, use_within); - test_point_in_polygon(case_id, point, polygon, sw::franklin(), - "franklin", boost::contains(deviations, "f") ? !expected : expected, use_within); - test_point_in_polygon(case_id, point, polygon, sw::crossings_multiply(), - "cross.mult", boost::contains(deviations, "c") ? !expected : expected, use_within); -} - -template -void test_geometry_default(std::string const& case_id, std::string const& wkt_point - , std::string const& wkt_polygon - , bool expected - , bool use_within = true) -{ - Point point; - Polygon polygon; - bg::read_wkt(wkt_point, point); - bg::read_wkt(wkt_polygon, polygon); - - namespace sw = bg::strategy::within; - test_point_in_polygon(case_id, point, polygon, sw::winding(), - "winding", expected, use_within); -} - -template -void test_box_of(std::string const& wkt_point, std::string const& wkt_box, - bool expected_within, bool expected_covered_by) -{ - typedef bg::model::box box_type; - - Point point; - box_type box; - bg::read_wkt(wkt_point, point); - bg::read_wkt(wkt_box, box); - - bool detected_within = bg::within(point, box); - bool detected_covered_by = bg::covered_by(point, box); - BOOST_CHECK_EQUAL(detected_within, expected_within); - BOOST_CHECK_EQUAL(detected_covered_by, expected_covered_by); - - // Also test with the non-default agnostic side version - namespace wi = bg::strategy::within; - wi::point_in_box_by_side within_strategy; - wi::point_in_box_by_side covered_by_strategy; - - detected_within = bg::within(point, box, within_strategy); - detected_covered_by = bg::covered_by(point, box, covered_by_strategy); - BOOST_CHECK_EQUAL(detected_within, expected_within); - BOOST_CHECK_EQUAL(detected_covered_by, expected_covered_by); - - // We might exchange strategies between within/covered by. - // So the lines below might seem confusing, but are as intended - detected_within = bg::covered_by(point, box, within_strategy); - detected_covered_by = bg::within(point, box, covered_by_strategy); - BOOST_CHECK_EQUAL(detected_within, expected_within); - BOOST_CHECK_EQUAL(detected_covered_by, expected_covered_by); - - // Finally we call the strategies directly - detected_within = within_strategy.apply(point, box); - detected_covered_by = covered_by_strategy.apply(point, box); - BOOST_CHECK_EQUAL(detected_within, expected_within); - BOOST_CHECK_EQUAL(detected_covered_by, expected_covered_by); -} - -template -void test_box() -{ - test_box_of("POINT(1 1)", "BOX(0 0,2 2)", true, true); - test_box_of("POINT(0 0)", "BOX(0 0,2 2)", false, true); - test_box_of("POINT(2 2)", "BOX(0 0,2 2)", false, true); - test_box_of("POINT(0 1)", "BOX(0 0,2 2)", false, true); - test_box_of("POINT(1 0)", "BOX(0 0,2 2)", false, true); - test_box_of("POINT(3 3)", "BOX(0 0,2 2)", false, false); -} - - -template -void test_all() -{ - test_box(); - - typedef bg::model::polygon polygon; - - std::string const box = "POLYGON((0 0,0 2,2 2,2 0,0 0))"; - std::string const triangle = "POLYGON((0 0,0 4,6 0,0 0))"; - std::string const with_hole = "POLYGON((0 0,0 3,3 3,3 0,0 0),(1 1,2 1,2 2,1 2,1 1))"; - - - test_geometry("b1", "POINT(1 1)", box, true); - test_geometry("b2", "POINT(3 3)", box, false); - - // Test ALL corners (officialy false but some strategies might answer true) - test_geometry("b3a", "POINT(0 0)", box, false, "f"); - test_geometry("b3b", "POINT(0 2)", box, false); - test_geometry("b3c", "POINT(2 2)", box, false); - test_geometry("b3d", "POINT(2 0)", box, false); - - // Test ALL sides (officialy false but some strategies might answer true) - test_geometry("b4a", "POINT(0 1)", box, false, "f"); - test_geometry("b4b", "POINT(1 2)", box, false, "c"); - test_geometry("b4c", "POINT(2 1)", box, false); - test_geometry("b4d", "POINT(1 0)", box, false, "f"); - - - test_geometry("t1", "POINT(1 1)", triangle, true); - test_geometry("t2", "POINT(3 3)", triangle, false); - - test_geometry("t3a", "POINT(0 0)", triangle, false, "f"); - test_geometry("t3b", "POINT(0 4)", triangle, false, "c"); - test_geometry("t3c", "POINT(5 0)", triangle, false, "f"); - - test_geometry("t4a", "POINT(0 2)", triangle, false, "f"); - test_geometry("t4b", "POINT(3 2)", triangle, false); - test_geometry("t4c", "POINT(2 0)", triangle, false, "f"); - - - test_geometry("h1", "POINT(0.5 0.5)", with_hole, true); - test_geometry("h2a", "POINT(1.5 1.5)", with_hole, false); - test_geometry("h2b", "POINT(5 5)", with_hole, false); - - test_geometry("h3a", "POINT(1 1)", with_hole, false, "c"); - test_geometry("h3b", "POINT(2 2)", with_hole, false, "f"); - test_geometry("h3c", "POINT(0 0)", with_hole, false, "f"); - - test_geometry("h4a", "POINT(1 1.5)", with_hole, false); - test_geometry("h4b", "POINT(1.5 2)", with_hole, false, "f"); - - // Lying ON (one of the sides of) interior ring - test_geometry("#77-1", "POINT(6 3.5)", "POLYGON((5 3,5 4,4 4,4 5,3 5,3 6,5 6,5 5,7 5,7 6,8 6,8 5,9 5,9 2,8 2,8 1,7 1,7 2,5 2,5 3),(6 3,8 3,8 4,6 4,6 3))", false); -} - - -void test_spherical() -{ - typedef bg::model::point > point; - typedef bg::model::polygon polygon; - - // Ticket #9354 - test_geometry_default( - "#9354", - "POINT(-78.1239 25.9556)", - "POLYGON((-97.08466667 25.95683333, -97.13683333 25.954, -97.1 26, -97.08466667 25.95683333))", - false); - - test_geometry_default( - "sph1N", - "POINT(0 10.001)", - "POLYGON((-10 10, 10 10, 10 -10, -10 -10, -10 10))", - bg::strategy::side::spherical_side_formula<>::apply( - point(-10, 10), - point(10, 10), - point(0, 10.001)) == -1 // right side - /*true*/); - test_geometry_default( - "sph1S", - "POINT(0 -10.001)", - "POLYGON((-10 10, 10 10, 10 -10, -10 -10, -10 10))", - bg::strategy::side::spherical_side_formula<>::apply( - point(10, -10), - point(-10, -10), - point(0, -10.001)) == -1 // right side - /*true*/); - - test_geometry_default( - "sph2S", - "POINT(0 10.001)", - "POLYGON((-10 20, 10 20, 10 10, -10 10, -10 20))", - bg::strategy::side::spherical_side_formula<>::apply( - point(10, 10), - point(-10, 10), - point(0, 10.001)) == -1 // right side - /*false*/); - - test_geometry_default( - "sph3N", - "POINT(0 10)", - "POLYGON((-10 10, 10 10, 10 -10, -10 -10, -10 10))", - bg::strategy::side::spherical_side_formula<>::apply( - point(-10, 10), - point(10, 10), - point(0, 10.001)) == -1 // right side - /*true*/); - test_geometry_default( - "sph3S", - "POINT(0 -10)", - "POLYGON((-10 10, 10 10, 10 -10, -10 -10, -10 10))", - bg::strategy::side::spherical_side_formula<>::apply( - point(10, -10), - point(-10, -10), - point(0, -10.001)) == -1 // right side - /*true*/); - - test_geometry_default( - "sphEq1", - "POINT(179 10)", - "POLYGON((170 10, -170 10, -170 0, 170 0, 170 10))", - true, - false); - test_geometry_default( - "sphEq2", - "POINT(179 10)", - "POLYGON((170 20, -170 20, -170 10, 170 10, 170 20))", - true, - false); - test_geometry_default( - "sphEq3", - "POINT(-179 10)", - "POLYGON((170 10, -170 10, -170 0, 170 0, 170 10))", - true, - false); - test_geometry_default( - "sphEq4", - "POINT(-179 10)", - "POLYGON((170 20, -170 20, -170 10, 170 10, 170 20))", - true, - false); - - test_geometry_default( - "sphEq5", - "POINT(169 10)", - "POLYGON((170 20, -170 20, -170 10, 170 10, 170 20))", - false, - false); - test_geometry_default( - "sphEq6", - "POINT(-169 10)", - "POLYGON((170 20, -170 20, -170 10, 170 10, 170 20))", - false, - false); - test_geometry_default( - "sphEq7", - "POINT(169 10)", - "POLYGON((170 10, -170 10, -170 0, 170 0, 170 10))", - false, - false); - test_geometry_default( - "sphEq8", - "POINT(-169 10)", - "POLYGON((170 10, -170 10, -170 0, 170 0, 170 10))", - false, - false); -} - -int test_main(int, char* []) -{ - test_all >(); - test_all >(); - - test_spherical(); - -#if defined(HAVE_TTMATH) - test_all >(); -#endif - - return 0; -}