diff --git a/doc/release_notes.qbk b/doc/release_notes.qbk index 6b732cefd..224cff1a8 100644 --- a/doc/release_notes.qbk +++ b/doc/release_notes.qbk @@ -40,7 +40,7 @@ * [@https://svn.boost.org/trac/boost/ticket/10467 10467] Template parameter name coliding with B0 macro name defined in termios.h * [@https://svn.boost.org/trac/boost/ticket/10666 10666] MSVC compiler warning C4127: conditional expression is constant * [@https://svn.boost.org/trac/boost/ticket/10747 10747] Error in rescaling causing errors in areal/areal set operations -* [@https://svn.boost.org/trac/boost/ticket/10770 10770] Buffer fails for large distances, or rough round joints, where concavities where not intersected properly +* [@https://svn.boost.org/trac/boost/ticket/10770 10770] Buffer fails for large distances, or rough round joins, where concavities where not intersected properly * [@https://svn.boost.org/trac/boost/ticket/10861 10861] Rtree failing to compile for Value being a pair or a tuple containing pointer to Geometry and the default equal_to<> used * [@https://svn.boost.org/trac/boost/ticket/10863 10863] Template parameter name coliding with B0 macro name defined in termios.h (duplicate of 10467) * [@https://svn.boost.org/trac/boost/ticket/10887 10887] Invalid result of within() and relate() for Linear/MultiPolygon @@ -60,6 +60,7 @@ * Bug in Cartesian segment-segment intersection strategy when one segment degenerates to a point and is collinear to the other non-degenerate segment * Bug in centroid(), non-deterministic result if calculated for e.g. a Polygon with zero-area. * Bug in buffers for joins with a limited number of points +* Bug in buffers for round joins with limited number of points around sharp corners * Bug in buffers for joins with large buffer distances * Bug in buffers for round ends with an odd number of points * Bug in buffers for flat ends with large buffer distances diff --git a/include/boost/geometry/strategies/cartesian/buffer_join_round.hpp b/include/boost/geometry/strategies/cartesian/buffer_join_round.hpp index 2472c5385..0a37983fa 100644 --- a/include/boost/geometry/strategies/cartesian/buffer_join_round.hpp +++ b/include/boost/geometry/strategies/cartesian/buffer_join_round.hpp @@ -89,11 +89,20 @@ private : // Divide the angle into an integer amount of steps to make it // visually correct also for a low number of points / circle - int const n - = static_cast(m_points_per_circle * angle_diff / two_pi); + + // If a full circle is divided into 3 parts (e.g. angle is 125), + // the one point in between must still be generated + // The calculation below: + // - generates 1 point in between for an angle of 125 based on 3 points + // - generates 0 points in between for an angle of 90 based on 4 points + + int const n = 1 + std::max(static_cast( + ceil(-1.0 + m_points_per_circle * angle_diff / two_pi)), 0); PromotedType const diff = angle_diff / static_cast(n); PromotedType a = angle1 - diff; + + // Walk to n - 1 to avoid generating the last point for (int i = 0; i < n - 1; i++, a -= diff) { Point p; diff --git a/test/algorithms/buffer/linestring_buffer.cpp b/test/algorithms/buffer/linestring_buffer.cpp index 63f6d8567..337ea2824 100644 --- a/test/algorithms/buffer/linestring_buffer.cpp +++ b/test/algorithms/buffer/linestring_buffer.cpp @@ -183,24 +183,24 @@ void test_all() test_one("mysql_report_2015_03_02a_3", mysql_report_2015_03_02a, join_round(3), end_round(3), 38.000, d10); test_one("mysql_report_2015_03_02a_4", mysql_report_2015_03_02a, join_round(4), end_round(4), 38.000, d10); - test_one("mysql_report_2015_03_02a_5", mysql_report_2015_03_02a, join_round(5), end_round(5), 38.169, d10); - test_one("mysql_report_2015_03_02a_6", mysql_report_2015_03_02a, join_round(6), end_round(6), 38.196, d10); - test_one("mysql_report_2015_03_02a_7", mysql_report_2015_03_02a, join_round(7), end_round(7), 38.230, d10); + test_one("mysql_report_2015_03_02a_5", mysql_report_2015_03_02a, join_round(5), end_round(5), 38.790, d10); + test_one("mysql_report_2015_03_02a_6", mysql_report_2015_03_02a, join_round(6), end_round(6), 38.817, d10); + test_one("mysql_report_2015_03_02a_7", mysql_report_2015_03_02a, join_round(7), end_round(7), 38.851, d10); test_one("mysql_report_2015_03_02b_3", mysql_report_2015_03_02b, join_round(3), end_round(3), 36.500, d10); test_one("mysql_report_2015_03_02b_4", mysql_report_2015_03_02b, join_round(4), end_round(4), 36.500, d10); - test_one("mysql_report_2015_03_02b_5", mysql_report_2015_03_02b, join_round(5), end_round(5), 36.724, d10); - test_one("mysql_report_2015_03_02b_6", mysql_report_2015_03_02b, join_round(6), end_round(6), 36.781, d10); - test_one("mysql_report_2015_03_02b_7", mysql_report_2015_03_02b, join_round(7), end_round(7), 36.884, d10); + test_one("mysql_report_2015_03_02b_5", mysql_report_2015_03_02b, join_round(5), end_round(5), 37.346, d10); + test_one("mysql_report_2015_03_02b_6", mysql_report_2015_03_02b, join_round(6), end_round(6), 37.402, d10); + test_one("mysql_report_2015_03_02b_7", mysql_report_2015_03_02b, join_round(7), end_round(7), 37.506, d10); test_one("mysql_report_2015_03_02c_3", mysql_report_2015_03_02c, join_round(2), end_round(3), 32.500, d10); test_one("mysql_report_2015_03_02c_4", mysql_report_2015_03_02c, join_round(4), end_round(4), 32.500, d10); - test_one("mysql_report_2015_03_02c_5", mysql_report_2015_03_02c, join_round(5), end_round(5), 32.990, d10); - test_one("mysql_report_2015_03_02c_6", mysql_report_2015_03_02c, join_round(6), end_round(6), 33.098, d10); - test_one("mysql_report_2015_03_02c_7", mysql_report_2015_03_02c, join_round(7), end_round(7), 33.279, d10); + test_one("mysql_report_2015_03_02c_5", mysql_report_2015_03_02c, join_round(5), end_round(5), 33.611, d10); + test_one("mysql_report_2015_03_02c_6", mysql_report_2015_03_02c, join_round(6), end_round(6), 33.719, d10); + test_one("mysql_report_2015_03_02c_7", mysql_report_2015_03_02c, join_round(7), end_round(7), 33.901, d10); // Testing the asymmetric end caps with odd number of points double const d15 = 1.5; - test_one("mysql_report_2015_03_02c_asym1", mysql_report_2015_03_02c, join_round(7), end_round(7), 39.093, d10, d15); - test_one("mysql_report_2015_03_02c_asym2", mysql_report_2015_03_02c, join_round(7), end_round(7), 44.718, d15, d10); + test_one("mysql_report_2015_03_02c_asym1", mysql_report_2015_03_02c, join_round(7), end_round(7), 39.714, d10, d15); + test_one("mysql_report_2015_03_02c_asym2", mysql_report_2015_03_02c, join_round(7), end_round(7), 46.116, d15, d10); } diff --git a/test/algorithms/buffer/multi_linestring_buffer.cpp b/test/algorithms/buffer/multi_linestring_buffer.cpp index b4ed68b63..24aca1a67 100644 --- a/test/algorithms/buffer/multi_linestring_buffer.cpp +++ b/test/algorithms/buffer/multi_linestring_buffer.cpp @@ -59,7 +59,7 @@ void test_all() test_one("two_bends", two_bends, join_round, end_flat, 64.6217, 1.5, 1.5); test_one("bend_near_start1", bend_near_start1, join_round, end_flat, 202.5910, 9.0, 9.0); - test_one("bend_near_start2", bend_near_start2, join_round, end_flat, 231.4882, 9.0, 9.0); + test_one("bend_near_start2", bend_near_start2, join_round, end_flat, 231.4988, 9.0, 9.0); // TODO this should be fixed test_one("turn_inside", turn_inside, join_round, end_flat, 99, 1.5, 1.5); test_one("two_bends_asym", two_bends, join_round, end_flat, 52.3793, 1.5, 0.75); @@ -85,20 +85,20 @@ void test_all() // (The expected area for large distances is about R*R*PI where R is distance) // Note that for large distances the flat ends (not tested here) still give weird effects test_one("mikado1_large", mikado1, join_round32, end_round32, 5455052109.518, 41751.0); - test_one("mikado1_small", mikado1, join_round32, end_round32, 1057.12, 10.0); - test_one("mikado1_small", mikado1, join_round32, end_flat, 874.337, 10.0); + test_one("mikado1_small", mikado1, join_round32, end_round32, 1057.37, 10.0); + test_one("mikado1_small", mikado1, join_round32, end_flat, 874.590, 10.0); test_one("mikado2_large", mikado2, join_round32, end_round32, 19878812278.387, 79610.0); - test_one("mikado2_small", mikado2, join_round32, end_round32, 1082.344, 10.0); - test_one("mikado2_small", mikado2, join_round32, end_flat, 711.552, 10.0); + test_one("mikado2_small", mikado2, join_round32, end_round32, 1082.470, 10.0); + test_one("mikado2_small", mikado2, join_round32, end_flat, 711.678, 10.0); test_one("mikado3_large", mikado3, join_round32, end_round32, 29151950703.779, 96375.0); - test_one("mikado3_small", mikado3, join_round32, end_round32, 2532.945, 10.0); - test_one("mikado3_small", mikado3, join_round32, end_flat, 2135.627, 10.0); + test_one("mikado3_small", mikado3, join_round32, end_round32, 2533.285, 10.0); + test_one("mikado3_small", mikado3, join_round32, end_flat, 2136.236, 10.0); test_one("mikado4_large", mikado4, join_round32, end_round32, 11212832197.267, 59772.0); - test_one("mikado4_small", mikado4, join_round32, end_round32, 2103.113, 10.0); - test_one("mikado4_small", mikado4, join_round32, end_flat, 1930.327, 10.0); + test_one("mikado4_small", mikado4, join_round32, end_round32, 2103.686, 10.0); + test_one("mikado4_small", mikado4, join_round32, end_flat, 1930.785, 10.0); } diff --git a/test/algorithms/buffer/multi_polygon_buffer.cpp b/test/algorithms/buffer/multi_polygon_buffer.cpp index 81da5bcba..4b526a8e6 100644 --- a/test/algorithms/buffer/multi_polygon_buffer.cpp +++ b/test/algorithms/buffer/multi_polygon_buffer.cpp @@ -438,7 +438,7 @@ void test_all() // (the change was irrelevant to this, so they succeeded earlier by luck). // TODO: get_occupation/left_turns in combination with a u/u turn test_one("rt_u7", rt_u7, join_round, end_flat, 35.6233, 1.0); - test_one("rt_u7_rough", rt_u7, join_round_rough, end_flat, 35.0483, 1.0); + test_one("rt_u7_rough", rt_u7, join_round_rough, end_flat, 35.1675, 1.0); } test_one("rt_u8", rt_u8, join_miter, end_flat, 70.9142, 1.0); diff --git a/test/algorithms/buffer/polygon_buffer.cpp b/test/algorithms/buffer/polygon_buffer.cpp index d0eeedb09..2403c61a3 100644 --- a/test/algorithms/buffer/polygon_buffer.cpp +++ b/test/algorithms/buffer/polygon_buffer.cpp @@ -71,6 +71,9 @@ static std::string const triangle static std::string const sharp_triangle = "POLYGON((2 0,3 8,4 0,2 0))"; +static std::string const right_triangle + = "POLYGON((0 1,20 0,0 0,0 1))"; + static std::string const degenerate0 = "POLYGON(())"; @@ -225,17 +228,17 @@ void test_all() test_one("concave_b75", concave_b, join_miter, end_flat, 36318.1642, 75.0); test_one("concave_b100", concave_b, join_miter, end_flat, 63879.5140, 100.0); - test_one("concave_b10", concave_b, join_round, end_flat, 532.2763, 10.0); - test_one("concave_b25", concave_b, join_round, end_flat, 2482.7577, 25.0); - test_one("concave_b50", concave_b, join_round, end_flat, 8872.6784, 50.0); - test_one("concave_b75", concave_b, join_round, end_flat, 19186.8841, 75.0); - test_one("concave_b100", concave_b, join_round, end_flat, 33425.4379, 100.0); + test_one("concave_b10", concave_b, join_round, end_flat, 532.2875, 10.0); + test_one("concave_b25", concave_b, join_round, end_flat, 2482.8329, 25.0); + test_one("concave_b50", concave_b, join_round, end_flat, 8872.9719, 50.0); + test_one("concave_b75", concave_b, join_round, end_flat, 19187.5490, 75.0); + test_one("concave_b100", concave_b, join_round, end_flat, 33426.6139, 100.0); - test_one("concave_b_rough_10", concave_b, join_round_rough, end_flat, 512.8457, 10.0); - test_one("concave_b_rough_25", concave_b, join_round_rough, end_flat, 2364.5658, 25.0); - test_one("concave_b_rough_50", concave_b, join_round_rough, end_flat, 8410.399996, 50.0); - test_one("concave_b_rough_75", concave_b, join_round_rough, end_flat, 18153.9268, 75.0); - test_one("concave_b_rough_100", concave_b, join_round_rough, end_flat, 31595.1463, 100.0); + test_one("concave_b_rough_10", concave_b, join_round_rough, end_flat, 520.312, 10.0); + test_one("concave_b_rough_25", concave_b, join_round_rough, end_flat, 2409.384, 25.0); + test_one("concave_b_rough_50", concave_b, join_round_rough, end_flat, 8586.812, 50.0); + test_one("concave_b_rough_75", concave_b, join_round_rough, end_flat, 18549.018, 75.0); + test_one("concave_b_rough_100", concave_b, join_round_rough, end_flat, 32295.917, 100.0); test_one("spike_simplex15", spike_simplex, join_round, end_round, 50.3633, 1.5); test_one("spike_simplex15", spike_simplex, join_miter, end_flat, 51.5509, 1.5); @@ -244,7 +247,7 @@ void test_all() test_one("spike_simplex30", spike_simplex, join_round, end_round, 100.9199, 3.0); test_one("spike_simplex30", spike_simplex, join_miter, end_flat, 120.9859, 3.0); #endif - test_one("spike_simplex150", spike_simplex, join_round, end_round, 998.9530, 15.0); + test_one("spike_simplex150", spike_simplex, join_round, end_round, 998.9821, 15.0); #if defined(BOOST_GEOMETRY_BUFFER_INCLUDE_FAILING_TESTS) test_one("spike_simplex150", spike_simplex, join_miter, end_flat, 1532.6543, 15.0); #endif @@ -430,33 +433,33 @@ void test_all() test_one("county1", county1, join_round, end_flat, 0.00114092, -0.01); test_one("county1", county1, join_miter, end_flat, 0.00132859, -0.01); - test_one("parcel1_10", parcel1, join_round, end_flat, 7571.39121246337891, 10.0); + test_one("parcel1_10", parcel1, join_round, end_flat, 7571.405, 10.0); test_one("parcel1_10", parcel1, join_miter, end_flat, 8207.45314788818359, 10.0); - test_one("parcel1_20", parcel1, join_round, end_flat, 11648.0537185668945, 20.0); + test_one("parcel1_20", parcel1, join_round, end_flat, 11648.111, 20.0); test_one("parcel1_20", parcel1, join_miter, end_flat, 14184.0223083496094, 20.0); - test_one("parcel1_30", parcel1, join_round, end_flat, 16350.3611068725586, 30.0); - test_one("parcel1_30", parcel1, join_miter, end_flat, 22417.8007659912109, 30.0); + test_one("parcel1_30", parcel1, join_round, end_flat, 16350.488, 30.0); + test_one("parcel1_30", parcel1, join_miter, end_flat, 22417.799, 30.0); - test_one("parcel2_10", parcel2, join_round, end_flat, 5000.85063171386719, 10.0); + test_one("parcel2_10", parcel2, join_round, end_flat, 5000.867, 10.0); test_one("parcel2_10", parcel2, join_miter, end_flat, 5091.12226867675781, 10.0); - test_one("parcel2_20", parcel2, join_round, end_flat, 9049.60844421386719, 20.0); + test_one("parcel2_20", parcel2, join_round, end_flat, 9049.673, 20.0); test_one("parcel2_20", parcel2, join_miter, end_flat, 9410.69154357910156, 20.0); - test_one("parcel2_30", parcel2, join_round, end_flat, 13726.3790588378906, 30.0); + test_one("parcel2_30", parcel2, join_round, end_flat, 13726.528, 30.0); test_one("parcel2_30", parcel2, join_miter, end_flat, 14535.2319564819336, 30.0); - test_one("parcel3_10", parcel3, join_round, end_flat, 19992.6824035644531, 10.0); + test_one("parcel3_10", parcel3, join_round, end_flat, 19993.007, 10.0); test_one("parcel3_10", parcel3, join_miter, end_flat, 20024.5579376220703, 10.0, 10.0, true, 0.05); // MSVC 14 reports 20024.51456, so we increase the tolerance - test_one("parcel3_20", parcel3, join_round, end_flat, 34505.0746192932129, 20.0); + test_one("parcel3_20", parcel3, join_round, end_flat, 34505.837, 20.0); test_one("parcel3_20", parcel3, join_miter, end_flat, 34633.2606201171875, 20.0); - test_one("parcel3_30", parcel3, join_round, end_flat, 45261.4196014404297, 30.0); + test_one("parcel3_30", parcel3, join_round, end_flat, 45262.452, 30.0); test_one("parcel3_30", parcel3, join_miter, end_flat, 45567.3875694274902, 30.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_5", parcel3_bend, join_round, end_flat, 155.634, 5.0); + test_one("parcel3_bend_10", parcel3_bend, join_round, end_flat, 458.454, 10.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); + // These cases differ a bit based on point order, because piece generation is different in one corner. Tolerance is increased + test_one("parcel3_bend_15", parcel3_bend, join_round, end_flat, 918.06, 15.0, 15.0, true, 0.25); + test_one("parcel3_bend_20", parcel3_bend, join_round, end_flat, 1534.64, 20.0, 20.0, true, 0.25); // Parcel - deflated test_one("parcel1_10", parcel1, join_round, end_flat, 1571.9024, -10.0); @@ -464,12 +467,12 @@ void test_all() test_one("parcel1_20", parcel1, join_round, end_flat, 209.3579, -20.0); test_one("parcel1_20", parcel1, join_miter, end_flat, 188.4224, -20.0); - test_one("nl_part1_2", nl_part1, join_round, end_flat, 1848737386.1343, -0.2 * 1000.0); - test_one("nl_part1_5", nl_part1, join_round, end_flat, 1775954035.2947, -0.5 * 1000.0); + test_one("nl_part1_2", nl_part1, join_round, end_flat, 1848737355.633, -0.2 * 1000.0); + test_one("nl_part1_5", nl_part1, join_round, end_flat, 1775953844.678, -0.5 * 1000.0); - test_one("italy_part1_30", italy_part1, join_round, end_flat, 5015307172.18164, 30.0 * 1000.0); - test_one("italy_part1_50", italy_part1, join_round, end_flat, 11362317400.63281, 50.0 * 1000.0); - test_one("italy_part1_60", italy_part1, join_round, end_flat, 15478123348.53125, 60.0 * 1000.0); + test_one("italy_part1_30", italy_part1, join_round, end_flat, 5015638830.339, 30.0 * 1000.0); + test_one("italy_part1_50", italy_part1, join_round, end_flat, 11363180030.278, 50.0 * 1000.0); + test_one("italy_part1_60", italy_part1, join_round, end_flat, 15479097108.720, 60.0 * 1000.0); // Tickets test_one("ticket_10398_1_5", ticket_10398_1, join_miter, end_flat, 494.7192, 0.5, -999, false); @@ -544,7 +547,7 @@ void test_all() test_with_custom_strategies("sharp_triangle_j12", sharp_triangle, join_round(12), end_flat, distance(1.0), side_strategy, point_strategy, - 29.0980); + 29.1604); // Test very various number of points (min is 3) test_with_custom_strategies("sharp_triangle_j2", sharp_triangle, @@ -553,7 +556,7 @@ void test_all() test_with_custom_strategies("sharp_triangle_j5", sharp_triangle, join_round(5), end_flat, distance(1.0), side_strategy, point_strategy, - 28.1091); + 28.8563); test_with_custom_strategies("sharp_triangle_j36", sharp_triangle, @@ -586,6 +589,25 @@ void test_all() join_miter(25), end_flat, distance(4.0), side_strategy, point_strategy, 244.7471); + // Right triangles, testing both points around sharp corner as well as points + // around right corners in join_round strategy + test_with_custom_strategies("right_triangle_j3", + right_triangle, + join_round(3), end_flat, distance(1.0), side_strategy, point_strategy, + 53.0240); + test_with_custom_strategies("right_triangle_j4", + right_triangle, + join_round(4), end_flat, distance(1.0), side_strategy, point_strategy, + 53.2492); + test_with_custom_strategies("right_triangle_j5", + right_triangle, + join_round(5), end_flat, distance(1.0), side_strategy, point_strategy, + 53.7430); + test_with_custom_strategies("right_triangle_j6", + right_triangle, + join_round(6), end_flat, distance(1.0), side_strategy, point_strategy, + 53.7430); + buffer_custom_side_strategy custom_side_strategy; test_with_custom_strategies("sharp_triangle_custom_side", sharp_triangle,