From a7764c1b9ea9455a77b55b49f9ae024adbbfda1a Mon Sep 17 00:00:00 2001 From: Barend Gehrels Date: Sun, 10 Aug 2014 15:32:07 +0200 Subject: [PATCH] [buffer][fix] use taxicab distance instead of comparable distance This is faster and avoids overflows. This fixes rt_u6 --- .../detail/buffer/turn_in_piece_visitor.hpp | 40 +++++++++++++------ .../buffer/multi_polygon_buffer.cpp | 5 +++ 2 files changed, 32 insertions(+), 13 deletions(-) diff --git a/include/boost/geometry/algorithms/detail/buffer/turn_in_piece_visitor.hpp b/include/boost/geometry/algorithms/detail/buffer/turn_in_piece_visitor.hpp index d43a01dcf..fa08c9cd2 100644 --- a/include/boost/geometry/algorithms/detail/buffer/turn_in_piece_visitor.hpp +++ b/include/boost/geometry/algorithms/detail/buffer/turn_in_piece_visitor.hpp @@ -56,6 +56,8 @@ class turn_in_piece_visitor Turns& m_turns; // because partition is currently operating on const input only Pieces const& m_pieces; // to check for piece-type + typedef boost::long_long_type calculation_type; + template static inline bool projection_on_segment(Point const& subject, Point const& p, Point const& q) { @@ -83,9 +85,17 @@ class turn_in_piece_visitor return true; } + template + static inline calculation_type taxicab_distance(Point const& p, Point const& q) + { + return math::abs(geometry::get<0>(p) - geometry::get<0>(q)) + + math::abs(geometry::get<1>(p) - geometry::get<1>(q)); + } + + // TODO: see comment below, this adaption of distance_projected_point can be removed template - static inline boost::long_long_type distance_from_segment(Point const& subject, Point const& p, Point const& q) + static inline calculation_type taxicab_distance_from_segment(Point const& subject, Point const& p, Point const& q) { typedef Point vector_type; typedef typename geometry::coordinate_type::type coordinate_type; @@ -98,15 +108,14 @@ class turn_in_piece_visitor coordinate_type const zero = coordinate_type(); coordinate_type const c1 = dot_product(w, v); - if (c1 < zero) + if (c1 <= zero) { - // Any value above 2 is fine in this case - return 99999; + return taxicab_distance(subject, p); } coordinate_type const c2 = dot_product(v, v); - if (c2 < c1 || c2 <= zero) + if (c2 <= c1) { - return 99999; + return taxicab_distance(subject, q); } multiply_value(v, c1); @@ -118,7 +127,9 @@ class turn_in_piece_visitor add_point(projected, v); - return dot_product(subject, projected); + // The dot-product still overflows for boost::long_long_type with + // these values (should not occur, TODO: fix this) + return taxicab_distance(subject, projected); } @@ -148,17 +159,18 @@ class turn_in_piece_visitor } template - inline boost::long_long_type - comparable_distance_from_offsetted(Point const& point, Piece const& piece) const + inline calculation_type + taxicab_distance_from_offsetted(Point const& point, Piece const& piece) const { // TODO: replace this by the code below if that is fixed for boost::long_long_type // with these contents of values - boost::long_long_type result = 0; + calculation_type result = 0; for (int i = 1; i < piece.offsetted_count; i++) { Point const& previous = piece.robust_ring[i - 1]; Point const& current = piece.robust_ring[i]; - boost::long_long_type dist = distance_from_segment(point, previous, current); + calculation_type const dist + = taxicab_distance_from_segment(point, previous, current); if (i == 1 || dist < result) { result = dist; @@ -258,9 +270,11 @@ public: if (geometry_code == 1) { - if (comparable_distance_from_offsetted(turn.robust_point, piece) >= 2) + calculation_type const distance + = taxicab_distance_from_offsetted(turn.robust_point, piece); + if (distance >= 2) { - // This is too far from the border, it counts as really inside + // This is too far from the border, it counts as "really within" mutable_turn.count_within++; } else diff --git a/test/algorithms/buffer/multi_polygon_buffer.cpp b/test/algorithms/buffer/multi_polygon_buffer.cpp index 4e1a73cfb..e6293b62f 100644 --- a/test/algorithms/buffer/multi_polygon_buffer.cpp +++ b/test/algorithms/buffer/multi_polygon_buffer.cpp @@ -233,6 +233,10 @@ static std::string const rt_u4 static std::string const rt_u5 = "MULTIPOLYGON(((4 3,4 4,5 4,5 3,4 3)),((6 5,6 6,7 6,6 5)),((5 4,6 5,6 4,5 4)),((4 0,4 1,5 1,5 0,4 0)),((7 8,8 9,8 8,7 8)),((8 2,8 3,9 3,8 2)),((2 1,2 2,3 1,2 1)),((5 7,5 8,6 8,5 7)),((4 5,4 6,5 5,4 5)),((7 0,8 1,8 0,7 0)),((7 2,8 1,7 1,6 1,7 2)),((3 3,4 3,4 2,3 2,3 3)),((3 9,3 10,4 9,3 9)),((1 2,2 3,2 2,1 2)),((2 4,2 5,3 4,2 3,2 4)),((3 7,4 7,3 6,2 6,3 7)))"; +static std::string const rt_u6 + = "MULTIPOLYGON(((2 2,3 3,3 2,2 2)),((9 8,9 9,10 9,10 8,9 8)),((5 3,6 4,6 3,5 3)),((5 5,5 6,6 6,5 5)),((5 1,6 2,6 1,5 1)),((6 5,7 6,7 5,6 5)),((3 0,4 1,4 0,3 0)),((6 6,6 7,7 6,6 6)),((9 2,10 2,10 1,9 1,9 2)),((6 8,6 9,7 9,7 8,6 8)),((7 0,7 1,8 0,7 0)),((4 4,4 5,5 5,4 4)),((0 7,0 8,1 8,0 7)),((5 9,6 10,6 9,5 9)),((4 9,4 10,5 10,5 9,4 9)),((3 7,4 7,3 6,2 6,3 7)),((9 7,10 6,9 6,8 6,9 7)),((5 3,5 2,4 2,4 3,4 4,5 4,5 3)),((1 1,2 0,1 0,0 0,1 1)),((2 10,3 10,3 9,2 9,1 9,1 10,2 10)),((8.5 4.5,9 4,8 4,7 4,8 5,9 5,8.5 4.5)),((8 3,9 3,9 2,8 2,8 3)))"; + + template void test_all() @@ -348,6 +352,7 @@ void test_all() test_one("rt_u3", rt_u3, join_round, end_flat, 133.4526, 1.0); test_one("rt_u4", rt_u4, join_round, end_flat, 126.9268, 1.0); test_one("rt_u5", rt_u5, join_round, end_flat, 78.4906, 1.0); + test_one("rt_u6", rt_u6, join_round, end_flat, 115.4461, 1.0); } int test_main(int, char* [])