From 7ab31cd832769c2d4617c9ce5b00453fb952d56a Mon Sep 17 00:00:00 2001 From: Barend Gehrels Date: Fri, 24 Nov 2017 22:32:33 +0100 Subject: [PATCH 1/9] [buffer][test] remove default argument - change order --- test/algorithms/buffer/buffer_multi_point.cpp | 2 +- test/algorithms/buffer/test_buffer.hpp | 10 ++++------ 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/test/algorithms/buffer/buffer_multi_point.cpp b/test/algorithms/buffer/buffer_multi_point.cpp index 1380151f3..1a38dd874 100644 --- a/test/algorithms/buffer/buffer_multi_point.cpp +++ b/test/algorithms/buffer/buffer_multi_point.cpp @@ -91,7 +91,7 @@ void test_all() distance_strategy(1), side_strategy, bg::strategy::buffer::point_circle(36), - 1, 0, 3.12566719800474635, ut_settings(1.0)); + 1, 0, 3.12566719800474635, ut_settings(1.0), NULL); } } diff --git a/test/algorithms/buffer/test_buffer.hpp b/test/algorithms/buffer/test_buffer.hpp index ba2b1b959..627294946 100644 --- a/test/algorithms/buffer/test_buffer.hpp +++ b/test/algorithms/buffer/test_buffer.hpp @@ -98,13 +98,13 @@ template<> struct EndTestProperties struct ut_settings { double tolerance; - bool check_self_intersections; bool test_validity; + bool check_self_intersections; explicit ut_settings(double tol = 0.01, bool val = true, bool self = true) : tolerance(tol) - , check_self_intersections(self) , test_validity(val) + , check_self_intersections(self) {} static inline ut_settings ignore_validity() @@ -158,8 +158,8 @@ void test_buffer(std::string const& caseid, Geometry const& geometry, int expected_count, int expected_holes_count, double expected_area, - ut_settings const& settings = ut_settings(), - std::size_t* self_ip_count = NULL) + ut_settings const& settings, + std::size_t* self_ip_count) { namespace bg = boost::geometry; @@ -590,6 +590,4 @@ void test_with_custom_strategies(std::string const& caseid, expected_area, settings, NULL); } - - #endif From 900219f408f871b542328575a2e09d4fc656d282 Mon Sep 17 00:00:00 2001 From: Barend Gehrels Date: Sat, 25 Nov 2017 13:19:26 +0100 Subject: [PATCH 2/9] [buffer][test] add test_area to ut_settings, and avoid checking the tests with huge coordinate differences on area, because they are meant for assertion-checks and they might be invalid, self-intersecting or empty depending on machine and numerical properties. --- test/algorithms/buffer/buffer_countries.cpp | 2 +- test/algorithms/buffer/buffer_linestring.cpp | 8 +- .../buffer/buffer_multi_linestring.cpp | 45 +++++------ .../buffer/buffer_multi_polygon.cpp | 9 ++- test/algorithms/buffer/buffer_polygon.cpp | 60 +++++++++++--- test/algorithms/buffer/test_buffer.hpp | 81 +++++++++++-------- 6 files changed, 126 insertions(+), 79 deletions(-) diff --git a/test/algorithms/buffer/buffer_countries.cpp b/test/algorithms/buffer/buffer_countries.cpp index 579081bf3..8c7c18aea 100644 --- a/test/algorithms/buffer/buffer_countries.cpp +++ b/test/algorithms/buffer/buffer_countries.cpp @@ -133,7 +133,7 @@ void test_one(std::string const& caseid, std::string const& wkt, double expected // Test with a high tolerance, even a difference of 1000 is only ~1.0e-6% settings.tolerance = 10000.0; - settings.check_self_intersections = false; + settings.test_self_intersections = false; #if defined(BOOST_GEOMETRY_NO_ROBUSTNESS) // in case robustness policies are changed, areas should be adapted diff --git a/test/algorithms/buffer/buffer_linestring.cpp b/test/algorithms/buffer/buffer_linestring.cpp index f2ff35890..4d5141e6a 100644 --- a/test/algorithms/buffer/buffer_linestring.cpp +++ b/test/algorithms/buffer/buffer_linestring.cpp @@ -253,12 +253,10 @@ void test_all() { - ut_settings settings(1.0e-10); + // Check on validity (not on self-intersections) with high precision because areas are all very small + ut_settings settings(1.0e-10, true, false); - ut_settings settings_wo_self = settings; - settings_wo_self.check_self_intersections = false; - - test_one("aimes120", aimes120, join_miter, end_flat, 1.62669948622351512e-08, 0.000018, settings_wo_self); + test_one("aimes120", aimes120, join_miter, end_flat, 1.62669948622351512e-08, 0.000018, settings); test_one("aimes120", aimes120, join_round, end_round, 1.72842078427493107e-08, 0.000018, settings); test_one("aimes167", aimes167, join_miter, end_flat, 1.88900628472765675e-09, 0.000018, settings); diff --git a/test/algorithms/buffer/buffer_multi_linestring.cpp b/test/algorithms/buffer/buffer_multi_linestring.cpp index dcc7166c4..6bd85766f 100644 --- a/test/algorithms/buffer/buffer_multi_linestring.cpp +++ b/test/algorithms/buffer/buffer_multi_linestring.cpp @@ -125,36 +125,31 @@ void test_all() test_one("mikado4_small", mikado4, join_round32, end_flat, 1930.785, 10.0); } + { #if ! defined(BOOST_GEOMETRY_NO_ROBUSTNESS) - // Coordinates in one linestring vary so much that - // length = geometry::math::sqrt(dx * dx + dy * dy); returns a value of inf for length - // That geometry is skipped for the buffer - // SQL Server reports area 2117753600 (for b) - // PostGIS reports 2087335072 (for b) - // BG (2) reports 794569660 (for a/b) which apparently misses parts - // old value was 927681870 (for a/b) which also misses parts - // (2: since selecting other IP at end points or when segment b is smaller than a) - test_one("mysql_2015_04_10a", mysql_2015_04_10a, join_round32, end_round32, 1063005187.214, 0.98); - test_one("mysql_2015_04_10b", mysql_2015_04_10b, join_round32, end_round32, 1063005187.214, 0.98); + // Coordinates in one linestring vary so much that + // length = geometry::math::sqrt(dx * dx + dy * dy); returns a value of inf for length + // That geometry is skipped for the buffer + // SQL Server reports area 2117753600 (for b) + // PostGIS reports 2087335072 (for b) + // BG (2017) reports 1063005187 (for a/b) which apparently misses parts + // BG (2015) reported 794569660 (for a/b) + // BG (earlier) reported 927681870 (for a/b) + test_one("mysql_2015_04_10a", + mysql_2015_04_10a, join_round32, end_round32, + ut_settings::ignore_area(), 0.98, ut_settings::assertions_only()); + test_one("mysql_2015_04_10b", + mysql_2015_04_10b, join_round32, end_round32, + ut_settings::ignore_area(), 0.98, ut_settings::assertions_only()); #endif - { - // Two other cases with inf for length calculation (tolerance quite high - // because the output area is quite high and varies between gcc/clang) - - // On MinGW this still causes invalid output, for case a: - // multiline_mysql_2015_09_08a_d_round_round output is self-intersecting. - // multiline_mysql_2015_09_08a_d_round_round is not valid - // On PowerPC also case b is reported as invalid - - ut_settings settings(1.0e12, false, false); - + // Two other cases with for length calculation test_one("mysql_2015_09_08a", - mysql_2015_09_08a, join_round32, end_round32, - 5.12436196736438764e+19, 4051744443.0, settings); + mysql_2015_09_08a, join_round32, end_round32, + ut_settings::ignore_area(), 4051744443.0, ut_settings::assertions_only()); test_one("mysql_2015_09_08b", - mysql_2015_09_08b, join_round32, end_round32, - 1.32832149026508268e+19, 2061380362.0, settings); + mysql_2015_09_08b, join_round32, end_round32, + ut_settings::ignore_area(), 2061380362.0, ut_settings::assertions_only()); } // Generates first no interior, then one touching point (no interior), diff --git a/test/algorithms/buffer/buffer_multi_polygon.cpp b/test/algorithms/buffer/buffer_multi_polygon.cpp index 9ae1d9705..961415941 100644 --- a/test/algorithms/buffer/buffer_multi_polygon.cpp +++ b/test/algorithms/buffer/buffer_multi_polygon.cpp @@ -503,15 +503,16 @@ void test_all() neighbouring_with_holes, join_round32, end_round32, 0.0, -10.0); - // On MinGW the output is invalid + // Check cases with extreme coordinates on assertions test_one("mysql_report_2015_07_05_1", mysql_report_2015_07_05_1, - join_round32, end_round32, 6.04454566324708726e+23, 5526.0, - ut_settings(1e+020, false, false)); + join_round32, end_round32, ut_settings::ignore_area(), 5526.0, + ut_settings::assertions_only()); test_one("mysql_report_2015_07_05_2", mysql_report_2015_07_05_2, - join_round32, end_round32, 0.0, 948189399.0); + join_round32, end_round32, ut_settings::ignore_area(), 948189399.0, + ut_settings::assertions_only()); } int test_main(int, char* []) diff --git a/test/algorithms/buffer/buffer_polygon.cpp b/test/algorithms/buffer/buffer_polygon.cpp index 699c9c804..5eba7e6d1 100644 --- a/test/algorithms/buffer/buffer_polygon.cpp +++ b/test/algorithms/buffer/buffer_polygon.cpp @@ -168,6 +168,20 @@ static std::string const mysql_report_2015_07_05_4 static std::string const mysql_report_2015_07_05_5 = "POLYGON((9 3,-8193 8.38861e+06,-2 -4,9 3),(-10 -2,32268 -2557,1.72036e+308 5.67867e+307,4.91634e+307 1.41031e+308,-2.68435e+08 -19,-10 -2),(-5 4,9.50167e+307 1.05883e+308,-422 -25737,-5 4))"; +// Versions without interiors +static std::string const mysql_report_2015_07_05_0_wi + = "POLYGON((0 0,0 30000,30000 20000,25000 0,0 0))"; +static std::string const mysql_report_2015_07_05_1_wi + = "POLYGON((9192 27876,128 4.5036e+15,-1 5,3 9,9192 27876))"; +static std::string const mysql_report_2015_07_05_2_wi + = "POLYGON((-15 -15,1.31128e+308 2.47964e+307,-20 -9,-15 -15))"; +static std::string const mysql_report_2015_07_05_3_wi + = "POLYGON((-2.68435e+08 -12,27090 -14130,5.76461e+17 5.49756e+11,-2.68435e+08 -12))"; +static std::string const mysql_report_2015_07_05_4_wi + = "POLYGON((2.19902e+12 524287,1.13649e+308 1.36464e+308,-10 -19,2.19902e+12 524287))"; +static std::string const mysql_report_2015_07_05_5_wi + = "POLYGON((9 3,-8193 8.38861e+06,-2 -4,9 3))"; + class buffer_custom_side_strategy { public : @@ -509,7 +523,7 @@ void test_all() { ut_settings settings; - settings.check_self_intersections = false; + settings.test_self_intersections = false; settings.test_validity = false; // Tickets @@ -582,27 +596,51 @@ void test_all() join_round32, end_round32, 64.0, -1.0); { + // These extreme testcases, containing huge coordinate differences + // and huge buffer distances, are to verify assertions. + // No assertions should be raised. + + // The buffers themselves are most often wrong. Versions + // without interior rings might be smaller (or have no output) + // then their versions with interior rings. + + // Therefore all checks on area, validity, self-intersections + // or having output at all are omitted. + + // Details (for versions with interior rings) // Case 3 is reported as invalid // On MinGW, also case 2 and 4 are reported as invalid // On PowerPC, also case 1 is reported as invalid - ut_settings settings(1.0e+20, false, false); + ut_settings settings = ut_settings::assertions_only(); + const double no_area = ut_settings::ignore_area(); test_one("mysql_report_2015_07_05_0", mysql_report_2015_07_05_0, - join_round32, end_round32, 700643542.242915988, 6.0); + join_round32, end_round32, no_area, 6.0, settings); test_one("mysql_report_2015_07_05_1", mysql_report_2015_07_05_1, - join_round32, end_round32, 2.07548405999982264e+19, 6.0, settings); - + join_round32, end_round32, no_area, 6.0, settings); test_one("mysql_report_2015_07_05_2", mysql_report_2015_07_05_2, - join_round32, end_round32, 9.48681585720922691e+23, 549755813889.0, settings); + join_round32, end_round32, no_area, 549755813889.0, settings); test_one("mysql_report_2015_07_05_3", mysql_report_2015_07_05_3, - join_round32, end_round32, 6.10005339242509925e+22, 49316.0, settings); + join_round32, end_round32, no_area, 49316.0, settings); test_one("mysql_report_2015_07_05_4", mysql_report_2015_07_05_4, - join_round32, end_round32, 4.25405937213774089e+23, 1479986.0, settings); - + join_round32, end_round32, no_area, 1479986.0, settings); test_one("mysql_report_2015_07_05_5", mysql_report_2015_07_05_5, - join_round32, end_round32, 644489321051.62439, 38141.0, - ut_settings(100000.0, true, false)); + join_round32, end_round32, no_area, 38141.0, settings); + + // Versions without interior rings (area should be smaller but still no checks) + test_one("mysql_report_2015_07_05_0_wi", mysql_report_2015_07_05_0_wi, + join_round32, end_round32, no_area, 6.0, settings); + test_one("mysql_report_2015_07_05_1_wi", mysql_report_2015_07_05_1_wi, + join_round32, end_round32, no_area, 6.0, settings); + test_one("mysql_report_2015_07_05_2_wi", mysql_report_2015_07_05_2_wi, + join_round32, end_round32, no_area, 549755813889.0, settings); + test_one("mysql_report_2015_07_05_3_wi", mysql_report_2015_07_05_3_wi, + join_round32, end_round32, no_area, 49316.0, settings); + test_one("mysql_report_2015_07_05_4_wi", mysql_report_2015_07_05_4_wi, + join_round32, end_round32, no_area, 1479986.0, settings); + test_one("mysql_report_2015_07_05_5_wi", mysql_report_2015_07_05_5_wi, + join_round32, end_round32, no_area, 38141.0, settings); } } diff --git a/test/algorithms/buffer/test_buffer.hpp b/test/algorithms/buffer/test_buffer.hpp index 627294946..3a361b3a2 100644 --- a/test/algorithms/buffer/test_buffer.hpp +++ b/test/algorithms/buffer/test_buffer.hpp @@ -99,12 +99,14 @@ struct ut_settings { double tolerance; bool test_validity; - bool check_self_intersections; + bool test_self_intersections; + bool test_area; explicit ut_settings(double tol = 0.01, bool val = true, bool self = true) : tolerance(tol) , test_validity(val) - , check_self_intersections(self) + , test_self_intersections(self) + , test_area(true) {} static inline ut_settings ignore_validity() @@ -114,6 +116,16 @@ struct ut_settings return result; } + static inline ut_settings assertions_only() + { + ut_settings result; + result.test_validity = false; + result.test_self_intersections = false; + result.test_area = false; + return result; + } + + static inline double ignore_area() { return 9999.9; } }; template @@ -266,9 +278,6 @@ void test_buffer(std::string const& caseid, Geometry const& geometry, buffer_mapper.map_input_output(mapper, geometry, buffered, distance_strategy.negative()); #endif - - typename bg::default_area_result::type area = bg::area(buffered); - //Uncomment to create simple CSV to compare/use in tests - adapt precision if necessary //std::cout << complete.str() << "," << std::fixed << std::setprecision(0) << area << std::endl; //return; @@ -279,11 +288,14 @@ void test_buffer(std::string const& caseid, Geometry const& geometry, return; } - BOOST_CHECK_MESSAGE - ( - ! bg::is_empty(buffered), - complete.str() << " output is empty (unexpected)." - ); + if (settings.test_area) + { + BOOST_CHECK_MESSAGE + ( + ! bg::is_empty(buffered), + complete.str() << " output is empty (unexpected)." + ); + } bg::model::box envelope_output; bg::assign_values(envelope_output, 0, 0, 1, 1); @@ -321,8 +333,9 @@ void test_buffer(std::string const& caseid, Geometry const& geometry, ); } - if (expected_area > -0.1) + if (settings.test_area) { + typename bg::default_area_result::type area = bg::area(buffered); double const difference = area - expected_area; BOOST_CHECK_MESSAGE ( @@ -336,30 +349,31 @@ void test_buffer(std::string const& caseid, Geometry const& geometry, << std::setprecision(3) << " , " << 100.0 * (difference / expected_area) << "%" ); + } - if (settings.check_self_intersections) + if (settings.test_self_intersections) + { + // This test is basically replaced by check on validity, + // and might therefore be removed completely. + try { - - try - { - bool has_self_ips = bg::detail::overlay::has_self_intersections( - buffered, strategy, rescale_policy_output, false); - // Be sure resulting polygon does not contain - // self-intersections - BOOST_CHECK_MESSAGE - ( - ! has_self_ips, - complete.str() << " output is self-intersecting. " - ); - } - catch(...) - { - BOOST_CHECK_MESSAGE - ( - false, - "Exception in checking self-intersections" - ); - } + bool has_self_ips + = bg::detail::overlay::has_self_intersections(buffered, + strategy, rescale_policy_output, false); + // Be sure resulting polygon does not contain self-intersections + BOOST_CHECK_MESSAGE + ( + ! has_self_ips, + complete.str() << " output is self-intersecting. " + ); + } + catch(...) + { + BOOST_CHECK_MESSAGE + ( + false, + "Exception in checking self-intersections" + ); } } @@ -389,6 +403,7 @@ void test_buffer(std::string const& caseid, Geometry const& geometry, #endif // Check for self-intersections + // See above for test_self_intersections, also this might be removed later. if (self_ip_count != NULL) { std::size_t count = 0; From 99da88ac26a9f2afa8b738482ed8a6dc45a46487 Mon Sep 17 00:00:00 2001 From: Barend Gehrels Date: Wed, 29 Nov 2017 10:24:00 +0100 Subject: [PATCH 3/9] [test][buffer] remove checks for self-intersections which is replaced by validity --- test/algorithms/buffer/buffer_countries.cpp | 1 - test/algorithms/buffer/buffer_linestring.cpp | 5 +- .../buffer/buffer_linestring_aimes.cpp | 18 +-- test/algorithms/buffer/buffer_multi_point.cpp | 2 +- test/algorithms/buffer/buffer_polygon.cpp | 1 - test/algorithms/buffer/test_buffer.hpp | 124 ++---------------- 6 files changed, 17 insertions(+), 134 deletions(-) diff --git a/test/algorithms/buffer/buffer_countries.cpp b/test/algorithms/buffer/buffer_countries.cpp index 8c7c18aea..56bdfb8bb 100644 --- a/test/algorithms/buffer/buffer_countries.cpp +++ b/test/algorithms/buffer/buffer_countries.cpp @@ -133,7 +133,6 @@ void test_one(std::string const& caseid, std::string const& wkt, double expected // Test with a high tolerance, even a difference of 1000 is only ~1.0e-6% settings.tolerance = 10000.0; - settings.test_self_intersections = false; #if defined(BOOST_GEOMETRY_NO_ROBUSTNESS) // in case robustness policies are changed, areas should be adapted diff --git a/test/algorithms/buffer/buffer_linestring.cpp b/test/algorithms/buffer/buffer_linestring.cpp index 4d5141e6a..efb3776cc 100644 --- a/test/algorithms/buffer/buffer_linestring.cpp +++ b/test/algorithms/buffer/buffer_linestring.cpp @@ -251,10 +251,9 @@ void test_all() #endif } - { - // Check on validity (not on self-intersections) with high precision because areas are all very small - ut_settings settings(1.0e-10, true, false); + // Check on validity, with high precision because areas are all very small + ut_settings settings(1.0e-10, true); test_one("aimes120", aimes120, join_miter, end_flat, 1.62669948622351512e-08, 0.000018, settings); test_one("aimes120", aimes120, join_round, end_round, 1.72842078427493107e-08, 0.000018, settings); diff --git a/test/algorithms/buffer/buffer_linestring_aimes.cpp b/test/algorithms/buffer/buffer_linestring_aimes.cpp index 7e76c6407..51dec91ad 100644 --- a/test/algorithms/buffer/buffer_linestring_aimes.cpp +++ b/test/algorithms/buffer/buffer_linestring_aimes.cpp @@ -468,10 +468,8 @@ void test_aimes() bg::strategy::buffer::end_flat end_flat; bg::strategy::buffer::end_round end_round(100); - ut_settings settings(1.0e-10, true, false); - // Aimes tested originally with 0.000018 degrees (around 2 m) - std::size_t self_ip_count = 0; + ut_settings settings(1.0e-10); int expectation_index = 0; for (int width = 18; width <= 36; width += 18, expectation_index += 2) @@ -483,17 +481,17 @@ void test_aimes() try { name << "aimes_" << i << "_" << width; - test_one_and_count_ips + test_one ( name.str(), testcases[i], join_miter, end_flat, expectations[i][expectation_index], - aimes_width, self_ip_count, settings + aimes_width, settings ); - test_one_and_count_ips + test_one ( name.str(), testcases[i], join_round, end_round, expectations[i][expectation_index + 1], - aimes_width, self_ip_count, settings + aimes_width, settings ); } catch(std::exception const& e) @@ -502,12 +500,6 @@ void test_aimes() } } } - - BOOST_CHECK_MESSAGE - ( - self_ip_count == 0, - "There are self-intersections: " << self_ip_count - ); } diff --git a/test/algorithms/buffer/buffer_multi_point.cpp b/test/algorithms/buffer/buffer_multi_point.cpp index 1a38dd874..1380151f3 100644 --- a/test/algorithms/buffer/buffer_multi_point.cpp +++ b/test/algorithms/buffer/buffer_multi_point.cpp @@ -91,7 +91,7 @@ void test_all() distance_strategy(1), side_strategy, bg::strategy::buffer::point_circle(36), - 1, 0, 3.12566719800474635, ut_settings(1.0), NULL); + 1, 0, 3.12566719800474635, ut_settings(1.0)); } } diff --git a/test/algorithms/buffer/buffer_polygon.cpp b/test/algorithms/buffer/buffer_polygon.cpp index 5eba7e6d1..544159d60 100644 --- a/test/algorithms/buffer/buffer_polygon.cpp +++ b/test/algorithms/buffer/buffer_polygon.cpp @@ -523,7 +523,6 @@ void test_all() { ut_settings settings; - settings.test_self_intersections = false; settings.test_validity = false; // Tickets diff --git a/test/algorithms/buffer/test_buffer.hpp b/test/algorithms/buffer/test_buffer.hpp index 3a361b3a2..0fd93545d 100644 --- a/test/algorithms/buffer/test_buffer.hpp +++ b/test/algorithms/buffer/test_buffer.hpp @@ -99,13 +99,11 @@ struct ut_settings { double tolerance; bool test_validity; - bool test_self_intersections; bool test_area; - explicit ut_settings(double tol = 0.01, bool val = true, bool self = true) + explicit ut_settings(double tol = 0.01, bool val = true) : tolerance(tol) , test_validity(val) - , test_self_intersections(self) , test_area(true) {} @@ -120,7 +118,6 @@ struct ut_settings { ut_settings result; result.test_validity = false; - result.test_self_intersections = false; result.test_area = false; return result; } @@ -128,29 +125,6 @@ struct ut_settings static inline double ignore_area() { return 9999.9; } }; -template -inline std::size_t count_self_ips(Geometry const& geometry, - Strategy const& strategy, - RescalePolicy const& rescale_policy) -{ - typedef typename bg::point_type::type point_type; - typedef bg::detail::overlay::turn_info - < - point_type, - typename bg::segment_ratio_type::type - > turn_info; - - std::vector turns; - - bg::detail::self_get_turn_points::no_interrupt_policy policy; - bg::self_turns - < - bg::detail::overlay::assign_null_policy - >(geometry, strategy, rescale_policy, turns, policy); - - return turns.size(); -} - template < typename GeometryOut, @@ -170,8 +144,7 @@ void test_buffer(std::string const& caseid, Geometry const& geometry, int expected_count, int expected_holes_count, double expected_area, - ut_settings const& settings, - std::size_t* self_ip_count) + ut_settings const& settings) { namespace bg = boost::geometry; @@ -301,9 +274,6 @@ void test_buffer(std::string const& caseid, Geometry const& geometry, bg::assign_values(envelope_output, 0, 0, 1, 1); bg::envelope(buffered, envelope_output); - rescale_policy_type rescale_policy_output - = bg::get_rescale_policy(envelope_output); - // std::cout << caseid << std::endl; // std::cout << "INPUT: " << bg::wkt(geometry) << std::endl; // std::cout << "OUTPUT: " << area << std::endl; @@ -351,32 +321,6 @@ void test_buffer(std::string const& caseid, Geometry const& geometry, ); } - if (settings.test_self_intersections) - { - // This test is basically replaced by check on validity, - // and might therefore be removed completely. - try - { - bool has_self_ips - = bg::detail::overlay::has_self_intersections(buffered, - strategy, rescale_policy_output, false); - // Be sure resulting polygon does not contain self-intersections - BOOST_CHECK_MESSAGE - ( - ! has_self_ips, - complete.str() << " output is self-intersecting. " - ); - } - catch(...) - { - BOOST_CHECK_MESSAGE - ( - false, - "Exception in checking self-intersections" - ); - } - } - if (settings.test_validity && ! bg::is_valid(buffered)) { BOOST_CHECK_MESSAGE(bg::is_valid(buffered), complete.str() << " is not valid"); @@ -399,26 +343,11 @@ void test_buffer(std::string const& caseid, Geometry const& geometry, // self_ips NYI here } #elif defined(TEST_WITH_SVG) + rescale_policy_type rescale_policy_output + = bg::get_rescale_policy(envelope_output); buffer_mapper.map_self_ips(mapper, buffered, strategy, rescale_policy_output); #endif - // Check for self-intersections - // See above for test_self_intersections, also this might be removed later. - if (self_ip_count != NULL) - { - std::size_t count = 0; - if (bg::detail::overlay::has_self_intersections(buffered, - strategy, rescale_policy_output, false)) - { - count = count_self_ips(buffered, strategy, rescale_policy_output); - } - - *self_ip_count += count; - if (count > 0) - { - std::cout << complete.str() << " " << count << std::endl; - } - } } template @@ -438,12 +367,11 @@ void test_buffer(std::string const& caseid, Geometry const& geometry, SideStrategy const& side_strategy, PointStrategy const& point_strategy, double expected_area, - ut_settings const& settings = ut_settings(), - std::size_t* self_ip_count = NULL) + ut_settings const& settings = ut_settings()) { test_buffer(caseid, geometry, join_strategy, end_strategy, distance_strategy, side_strategy, point_strategy, - -1, -1, expected_area, settings, self_ip_count); + -1, -1, expected_area, settings); } #ifdef BOOST_GEOMETRY_CHECK_WITH_POSTGIS @@ -497,7 +425,7 @@ void test_one(std::string const& caseid, std::string const& wkt, join_strategy, end_strategy, distance_strategy, side_strategy, circle_strategy, expected_count, expected_holes_count, expected_area, - settings, NULL); + settings); #if !defined(BOOST_GEOMETRY_COMPILER_MODE_DEBUG) && defined(BOOST_GEOMETRY_COMPILER_MODE_RELEASE) @@ -515,7 +443,7 @@ void test_one(std::string const& caseid, std::string const& wkt, join_strategy, end_strategy, sym_distance_strategy, side_strategy, circle_strategy, expected_count, expected_holes_count, expected_area, - settings, NULL); + settings); } #endif @@ -539,40 +467,6 @@ void test_one(std::string const& caseid, std::string const& wkt, distance_left, settings, distance_right); } -// Version (currently for the Aimes test) counting self-ip's instead of checking -template -< - typename Geometry, - typename GeometryOut, - typename JoinStrategy, - typename EndStrategy -> -void test_one_and_count_ips(std::string const& caseid, std::string const& wkt, - JoinStrategy const& join_strategy, EndStrategy const& end_strategy, - double expected_area, - double distance_left, - std::size_t& self_ip_count, - ut_settings const& settings) -{ - namespace bg = boost::geometry; - Geometry g; - bg::read_wkt(wkt, g); - bg::correct(g); - - bg::strategy::buffer::distance_asymmetric - < - typename bg::coordinate_type::type - > distance_strategy(distance_left, distance_left); - - bg::strategy::buffer::point_circle circle_strategy(88); - bg::strategy::buffer::side_straight side_strategy; - test_buffer(caseid, g, - join_strategy, end_strategy, - distance_strategy, side_strategy, circle_strategy, - expected_area, - settings, &self_ip_count); -} - template < typename Geometry, @@ -602,7 +496,7 @@ void test_with_custom_strategies(std::string const& caseid, (caseid, g, join_strategy, end_strategy, distance_strategy, side_strategy, point_strategy, - expected_area, settings, NULL); + expected_area, settings); } #endif From c9ea4b50ed5e2384dcfa28c8d7b239fae7dfbfd0 Mon Sep 17 00:00:00 2001 From: Barend Gehrels Date: Wed, 29 Nov 2017 14:39:20 +0100 Subject: [PATCH 4/9] [test] Add validity check to robustness test of buffer --- .../overlay/buffer/recursive_polygons_buffer.cpp | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/test/robustness/overlay/buffer/recursive_polygons_buffer.cpp b/test/robustness/overlay/buffer/recursive_polygons_buffer.cpp index 8816e2b59..6a6d431a9 100644 --- a/test/robustness/overlay/buffer/recursive_polygons_buffer.cpp +++ b/test/robustness/overlay/buffer/recursive_polygons_buffer.cpp @@ -87,8 +87,8 @@ bool verify(std::string const& caseid, MultiPolygon const& mp, MultiPolygon cons bool result = true; // Area of buffer must be larger than of original polygon - BOOST_AUTO(area_mp, bg::area(mp)); - BOOST_AUTO(area_buf, bg::area(buffer)); + double area_mp = bg::area(mp); + double area_buf = bg::area(buffer); if (area_buf < area_mp) { @@ -109,6 +109,16 @@ bool verify(std::string const& caseid, MultiPolygon const& mp, MultiPolygon cons } } + if (result) + { + std::string message; + if (! bg::is_valid(buffer, message)) + { + std::cout << "Buffer is not valid: " << message << std::endl; + result = false; + } + } + bool svg = settings.svg; bool wkt = settings.wkt; if (! result) @@ -204,7 +214,7 @@ bool test_buffer(MultiPolygon& result, int& index, bg::strategy::buffer::end_round end_strategy; bg::strategy::buffer::point_circle point_strategy; bg::strategy::buffer::side_straight side_strategy; - bg::strategy::buffer::join_round join_round_strategy(100); // Compatible with unit tests + bg::strategy::buffer::join_round join_round_strategy(32); // Compatible with MySQL bg::strategy::buffer::join_miter join_miter_strategy; try From 0e9e6caded22be05d63be9adaa7ac8510df79510 Mon Sep 17 00:00:00 2001 From: Barend Gehrels Date: Wed, 29 Nov 2017 16:27:01 +0100 Subject: [PATCH 5/9] [buffer][fix] in deflated buffers it could occur that a turn was missed (so: not within original) and traveled to itself. This is fixed by checking for deflated buffers (or inflated interior rings) if the minimum number of turns is 3. --- .../detail/buffer/buffer_inserter.hpp | 16 ++- .../buffer/buffered_piece_collection.hpp | 108 +++++++++++++++++- .../agnostic/buffer_distance_symmetric.hpp | 2 +- 3 files changed, 118 insertions(+), 8 deletions(-) diff --git a/include/boost/geometry/algorithms/detail/buffer/buffer_inserter.hpp b/include/boost/geometry/algorithms/detail/buffer/buffer_inserter.hpp index 06570cf87..990081a86 100644 --- a/include/boost/geometry/algorithms/detail/buffer/buffer_inserter.hpp +++ b/include/boost/geometry/algorithms/detail/buffer/buffer_inserter.hpp @@ -412,7 +412,7 @@ inline void buffer_point(Point const& point, Collection& collection, DistanceStrategy const& distance_strategy, PointStrategy const& point_strategy) { - collection.start_new_ring(); + collection.start_new_ring(false); std::vector range_out; point_strategy.apply(point, distance_strategy, range_out); collection.add_piece(geometry::strategy::buffer::buffered_point, range_out, false); @@ -627,7 +627,7 @@ struct buffer_inserter RobustPolicy const& robust_policy, Strategy const& strategy) // side strategy { - collection.start_new_ring(); + collection.start_new_ring(distance.negative()); geometry::strategy::buffer::result_code const code = buffer_inserter_ring::apply(ring, collection, distance, @@ -745,7 +745,7 @@ struct buffer_inserter std::size_t n = boost::size(simplified); if (n > 1) { - collection.start_new_ring(); + collection.start_new_ring(false); output_point_type first_p1; code = iterate(collection, boost::begin(simplified), boost::end(simplified), @@ -819,7 +819,13 @@ private: { for (Iterator it = begin; it != end; ++it) { - collection.start_new_ring(); + // For exterior rings, it deflates if distance is negative. + // For interior rings, it is vice versa + bool const deflate = is_interior + ? ! distance.negative() + : distance.negative(); + + collection.start_new_ring(deflate); geometry::strategy::buffer::result_code const code = policy::apply(*it, collection, distance, side_strategy, join_strategy, end_strategy, point_strategy, @@ -881,7 +887,7 @@ public: Strategy const& strategy) // side strategy { { - collection.start_new_ring(); + collection.start_new_ring(distance.negative()); geometry::strategy::buffer::result_code const code = policy::apply(exterior_ring(polygon), collection, 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 a9160b683..bc9c1ca7f 100644 --- a/include/boost/geometry/algorithms/detail/buffer/buffered_piece_collection.hpp +++ b/include/boost/geometry/algorithms/detail/buffer/buffered_piece_collection.hpp @@ -220,6 +220,7 @@ struct buffered_piece_collection bool is_flat_start; bool is_flat_end; + bool is_deflated; bool is_convex; bool is_monotonic_increasing[2]; // 0=x, 1=y bool is_monotonic_decreasing[2]; // 0=x, 1=y @@ -249,6 +250,7 @@ struct buffered_piece_collection , offsetted_count(-1) , is_flat_start(false) , is_flat_end(false) + , is_deflated(false) , is_convex(false) , robust_min_comparable_radius(0) , robust_max_comparable_radius(0) @@ -300,6 +302,8 @@ struct buffered_piece_collection piece_vector_type m_pieces; turn_vector_type m_turns; signed_size_type m_first_piece_index; + bool m_deflate; + bool m_has_deflated; buffered_ring_collection > offsetted_rings; // indexed by multi_index std::vector robust_originals; // robust representation of the original(s) @@ -338,6 +342,8 @@ struct buffered_piece_collection buffered_piece_collection(IntersectionStrategy const& intersection_strategy, RobustPolicy const& robust_policy) : m_first_piece_index(-1) + , m_deflate(false) + , m_has_deflated(false) , m_intersection_strategy(intersection_strategy) , m_side_strategy(intersection_strategy.get_side_strategy()) , m_area_strategy(intersection_strategy.template get_area_strategy()) @@ -529,6 +535,90 @@ struct buffered_piece_collection } } + struct deflate_properties + { + bool has_inflated; + std::size_t count; + + inline deflate_properties() + : has_inflated(false) + , count(0u) + {} + }; + + inline void discard_turns_for_deflate() + { + // Deflate cases should have at least 3 points PER deflated original + // to form a correct triangle + + // But if there are intersections between a deflated ring and another + // ring, it is all accepted + + // In deflate most turns are i/u by nature, but u/u is also possible + + std::map properties; + + for (typename boost::range_iterator::type it = + boost::begin(m_turns); it != boost::end(m_turns); ++it) + { + const buffer_turn_info_type& turn = *it; + if (turn.location == location_ok) + { + const buffer_turn_operation_type& op0 = turn.operations[0]; + const buffer_turn_operation_type& op1 = turn.operations[1]; + + if (! m_pieces[op0.seg_id.piece_index].is_deflated + || ! m_pieces[op1.seg_id.piece_index].is_deflated) + { + properties[op0.seg_id.multi_index].has_inflated = true; + properties[op1.seg_id.multi_index].has_inflated = true; + continue; + } + + // It is deflated, update counts + for (int i = 0; i < 2; i++) + { + const buffer_turn_operation_type& op = turn.operations[i]; + if (op.operation == detail::overlay::operation_union + || op.operation == detail::overlay::operation_continue) + { + properties[op.seg_id.multi_index].count++; + } + } + } + } + + for (typename boost::range_iterator::type it = + boost::begin(m_turns); it != boost::end(m_turns); ++it) + { + buffer_turn_info_type& turn = *it; + + if (turn.location == location_ok) + { + const buffer_turn_operation_type& op0 = turn.operations[0]; + const buffer_turn_operation_type& op1 = turn.operations[1]; + signed_size_type const multi0 = op0.seg_id.multi_index; + signed_size_type const multi1 = op1.seg_id.multi_index; + + if (multi0 == multi1) + { + const deflate_properties& prop = properties[multi0]; + if (! prop.has_inflated && prop.count < 3) + { + // Property is not inflated + // Not enough points, this might be caused by where + // detection turn-in-original failed because of numeric errors + turn.location = location_discard; + } + } + else + { + // Two different (possibly deflated) rings + } + } + } + } + template inline void check_remaining_points(DistanceStrategy const& distance_strategy) { @@ -554,7 +644,7 @@ struct buffered_piece_collection { if (deflate && turn.count_in_original <= 0) { - // For deflate: it is not in original, discard + // For deflate/negative buffers: it is not in original, discard turn.location = location_discard; } else if (! deflate && turn.count_in_original > 0) @@ -564,6 +654,12 @@ struct buffered_piece_collection } } } + + if (m_has_deflated) + { + // Either strategy was negative, or there were interior rings + discard_turns_for_deflate(); + } } inline bool assert_indices_in_robust_rings() const @@ -832,7 +928,7 @@ struct buffered_piece_collection } } - inline void start_new_ring() + inline void start_new_ring(bool deflate) { signed_size_type const n = static_cast(offsetted_rings.size()); current_segment_id.source_index = 0; @@ -844,6 +940,13 @@ struct buffered_piece_collection current_robust_ring.clear(); m_first_piece_index = static_cast(boost::size(m_pieces)); + m_deflate = deflate; + if (deflate) + { + // Pieces contain either deflated exterior rings, or inflated + // interior rings which are effectively deflated too + m_has_deflated = true; + } } inline void abort_ring() @@ -978,6 +1081,7 @@ struct buffered_piece_collection piece pc; pc.type = type; pc.index = static_cast(boost::size(m_pieces)); + pc.is_deflated = m_deflate; current_segment_id.piece_index = pc.index; diff --git a/include/boost/geometry/strategies/agnostic/buffer_distance_symmetric.hpp b/include/boost/geometry/strategies/agnostic/buffer_distance_symmetric.hpp index 73bd21ac7..fe973e3f3 100644 --- a/include/boost/geometry/strategies/agnostic/buffer_distance_symmetric.hpp +++ b/include/boost/geometry/strategies/agnostic/buffer_distance_symmetric.hpp @@ -68,7 +68,7 @@ public : return negative() ? -1 : 1; } - //! Returns true if distance is negative + //! Returns true if distance is negative (aka deflate) inline bool negative() const { return m_distance < 0; From 00a8dac0196a3229181e2fa88e1b692f6e05821b Mon Sep 17 00:00:00 2001 From: Barend Gehrels Date: Wed, 29 Nov 2017 17:06:56 +0100 Subject: [PATCH 6/9] [buffer][test] add test cases for fixed behaviour of deflated holes should have minimal 3 points --- test/algorithms/buffer/buffer_polygon.cpp | 43 +++++++++++++++++++++++ 1 file changed, 43 insertions(+) diff --git a/test/algorithms/buffer/buffer_polygon.cpp b/test/algorithms/buffer/buffer_polygon.cpp index 544159d60..0a4e0ecb8 100644 --- a/test/algorithms/buffer/buffer_polygon.cpp +++ b/test/algorithms/buffer/buffer_polygon.cpp @@ -114,6 +114,10 @@ static std::string const italy_part1 static std::string const nl_part1 = "POLYGON ((471871.966884626832325 6683515.683521211147308,470695.876464393688366 6681756.129975977353752,469211.542374156008009 6679924.978601523675025,464542.357652322971262 6674631.078279769048095,463243.59315323777264 6673494.345109832473099,459502.033748187706806 6670774.304660517722368,452204.484529234410729 6666030.372161027044058,439990.287360413349234 6659313.515823394991457,434547.988775020290632 6657783.034025833010674,433867.715366783668287 6657685.311832630075514,433063.65468478546245 6657783.034025833010674,423725.285241116478574 6659758.338574352674186,422581.143514745577704 6660350.880751021206379,422333.791606202081311 6660844.461689073592424,421993.599242338153999 6662622.453031159006059,421993.599242338153999 6663363.130126810632646,422612.090333183819894 6667314.244697011075914,422241.062470370030496 6667759.324870104901493,421096.80942450783914 6668303.522556710988283,408449.802075482031796 6673245.655735924839973,401646.845354124438018 6675273.665065255947411,400842.895991614612285 6675372.844085373915732,400255.351719210040756 6675224.699206517077982,392370.258227849320974 6672455.311684883199632,391968.283546594379004 6672009.975794731639326,391875.554410762328189 6671219.573235900141299,391937.336728153284639 6670527.121663697995245,392122.906319305824582 6669933.841785561293364,392339.311409408226609 6667957.501854715868831,392308.475910458364524 6665733.178529324010015,391937.336728153284639 6665289.631341196596622,387793.802641845482867 6664449.731981083750725,385814.7647345236619 6664202.740090588107705,384268.648326894966885 6664300.5401631873101,382846.319193030707538 6664646.406163938343525,382289.610419573145919 6664943.560305980034173,377186.502322628628463 6668957.888622742146254,376352.608017096004914 6669834.728738470934331,376197.985244384559337 6670428.001423852518201,375548.658654586179182 6676313.056885857135057,375243.086652359867003 6687692.866469252854586,379228.324422756850254 6689778.692146780900657,391782.713955441897269 6694388.125634397380054,393885.427817036863416 6694487.537080916576087,395215.139134563156404 6694091.147844122722745,405171.999669074953999 6689084.665672835893929,414263.128523688821588 6684478.40333267301321,415778.298112876422238 6683439.398042757064104,416396.677884233708028 6683192.009851422160864,419025.042381353967357 6682597.809754087589681,429909.63955213711597 6681508.792763692326844,430497.183824544539675 6681656.873437026515603,440979.806314075656701 6686955.330480101518333,467325.344922157470137 6687797.546342735178769,468129.294284664443694 6687698.216345063410699,468747.785375512961764 6687450.699095219373703,469211.542374156008009 6687054.651439971290529,469489.952420631831046 6686707.835750493220985,471871.966884626832325 6683515.683521211147308))"; +static std::string const erode_triangle ="POLYGON((-262.6446228027343700 -261.9999389648437500, -261.0000000000000000 -262.0000000000000000, -261.0000915527343700 -262.5285644531250000, -262.6446228027343700 -261.9999389648437500))"; + +static std::string const forming_uu_a ="POLYGON((0 0,0 10,5 6,10 10,10 0,5 4,0 0))"; +static std::string const forming_uu_b ="POLYGON((0 0,0 10,5 6,10 10,10 0,5 4,0 0),(1.25 2.5, 4.25 5,1.25 7.5,1.25 5.5,2.25 5.0,1.25 4.5,1.25 2.5))"; // Ticket 10398, fails at next distances ( /10.0 ): // #1: 5,25,84 @@ -724,7 +728,42 @@ void test_all() join_round(49), end_flat, distance(1.0), custom_side_strategy, point_strategy, 31.1087); } +} +template +void test_deflate_special_cases() +{ + typedef bg::model::polygon polygon_type; + + bg::strategy::buffer::join_miter join_miter(5); + bg::strategy::buffer::join_round join_round(8); + bg::strategy::buffer::end_flat end_flat; + + // This case fails for because there is an IP formed at the border of the original + test_one("erode_50", erode_triangle, join_miter, end_flat, 0, 0, 0.0, -0.50); + test_one("erode_40", erode_triangle, join_miter, end_flat, 0, 0, 0.0, -0.40); + test_one("erode_60", erode_triangle, join_miter, end_flat, 0, 0, 0.0, -0.60); + + // This case generates a uu-turn in deflate, at 1.0 + test_one("forming_uu_a_95", forming_uu_a, join_round, end_flat, 1, 0, 23.0516, -0.95); + test_one("forming_uu_a_10", forming_uu_a, join_round, end_flat, 2, 0, 21.4606, -1.0); + test_one("forming_uu_a_15", forming_uu_a, join_round, end_flat, 2, 0, 8.8272, -1.5); + test_one("forming_uu_a_20", forming_uu_a, join_round, end_flat, 2, 0, 1.7588, -2.0); + test_one("forming_uu_a_21", forming_uu_a, join_round, end_flat, 2, 0, 0.9944, -2.1); + + test_one("forming_uu_b_25", forming_uu_b, join_round, end_flat, 1, 1, 38.4064, -0.25); + test_one("forming_uu_b_50", forming_uu_b, join_round, end_flat, 1, 1, 24.4551, -0.50); + test_one("forming_uu_b_95", forming_uu_b, join_round, end_flat, 1, 0, 11.5009, -0.95); + test_one("forming_uu_b_10", forming_uu_b, join_round, end_flat, 1, 0, 10.7152, -1.0); + test_one("forming_uu_b_15", forming_uu_b, join_round, end_flat, 1, 0, 4.4136, -1.5); + + test_one("forming_uu_b_25", forming_uu_b, join_round, end_flat, 1, 1, 67.7139, 0.25); + test_one("forming_uu_b_50", forming_uu_b, join_round, end_flat, 1, 1, 82.0260, 0.50); + test_one("forming_uu_b_70", forming_uu_b, join_round, end_flat, 1, 3, 93.0760, 0.70); + + // From here on a/b have the same result + test_one("forming_uu_a_10", forming_uu_a, join_round, end_flat, 1, 0, 108.0959, 1.0); + test_one("forming_uu_b_10", forming_uu_b, join_round, end_flat, 1, 0, 108.0959, 1.0); } template @@ -764,6 +803,10 @@ int test_main(int, char* []) test_all(); test_all(); + typedef bg::model::point fpoint; + test_deflate_special_cases(); + test_deflate_special_cases(); + #if ! defined(BOOST_GEOMETRY_TEST_ONLY_ONE_TYPE) test_mixed(); From d1e02961717888e4e1e1ca69fb5e207527902fdf Mon Sep 17 00:00:00 2001 From: Barend Gehrels Date: Wed, 29 Nov 2017 17:07:29 +0100 Subject: [PATCH 7/9] [buffer][test] remove ignore_validity for two cases which are now always fine --- test/algorithms/buffer/buffer_multi_polygon.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/algorithms/buffer/buffer_multi_polygon.cpp b/test/algorithms/buffer/buffer_multi_polygon.cpp index 961415941..ec9b276d1 100644 --- a/test/algorithms/buffer/buffer_multi_polygon.cpp +++ b/test/algorithms/buffer/buffer_multi_polygon.cpp @@ -464,8 +464,8 @@ void test_all() test_one("rt_u2", rt_u2, join_round, end_flat, 138.8001, 1.0); 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, ut_settings::ignore_validity()); - test_one("rt_u6", rt_u6, join_round, end_flat, 115.4461, 1.0, ut_settings::ignore_validity()); + 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); test_one("rt_u7", rt_u7, join_miter, end_flat, 42.6421, 1.0); test_one("rt_u7", rt_u7, join_round, end_flat, 35.6233, 1.0); From 775b0e6199d31c53683d5994bb5bea7d7990c54a Mon Sep 17 00:00:00 2001 From: Adam Wulkiewicz Date: Thu, 30 Nov 2017 14:33:16 +0100 Subject: [PATCH 8/9] [doc] Update 1.66 release notes. --- doc/release_notes.qbk | 3 +++ 1 file changed, 3 insertions(+) diff --git a/doc/release_notes.qbk b/doc/release_notes.qbk index c93dd7265..a144628c8 100644 --- a/doc/release_notes.qbk +++ b/doc/release_notes.qbk @@ -24,6 +24,8 @@ [*Improvements] +* Add distance for geographic PointLike/AnyGeometry. + [*Solved issues] * [@https://svn.boost.org/trac10/ticket/12503 12503] Validity of complex polygon @@ -33,6 +35,7 @@ * Fixes in validity of union/intersection/difference which were sometimes invalid. In most cases, results are valid now. * Fixes in validity of buffer which were sometimes invalid. In most cases, results are valid now. * Fixes in results of union/intersection/difference which could be incorrect in very complex cases +* Fixes in set and relational operations for non-cartesian coordinate systems. [/=================] [heading Boost 1.65] From 9e882889f4cdad4c6c1d1c2c2b24a30af90f7e69 Mon Sep 17 00:00:00 2001 From: Adam Wulkiewicz Date: Mon, 4 Dec 2017 22:31:26 +0100 Subject: [PATCH 9/9] [formulas] Fix thomas direct formula for meridian segments (azi=0, lat1<0). --- include/boost/geometry/formulas/thomas_direct.hpp | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/include/boost/geometry/formulas/thomas_direct.hpp b/include/boost/geometry/formulas/thomas_direct.hpp index ef8f119b2..748960b01 100644 --- a/include/boost/geometry/formulas/thomas_direct.hpp +++ b/include/boost/geometry/formulas/thomas_direct.hpp @@ -169,9 +169,8 @@ public: { CT const sigma2 = S_sigma - sigma1; //theta2 = asin(cos(sigma2)) <=> sin_theta0 = 1 - // calculate absolute value because the geodesic is reversed - // if azimuth is pi and the result is altered below - CT const tan_theta2 = math::abs(cos(sigma2) / sin(sigma2)); + // NOTE: cos(sigma2) defines the sign of tan_theta2 + CT const tan_theta2 = cos(sigma2) / math::abs(sin(sigma2)); result.lat2 = atan(tan_theta2 / one_minus_f); } @@ -179,7 +178,7 @@ public: { result.lat2 = -result.lat2; } - } + } if (BOOST_GEOMETRY_CONDITION(CalcQuantities)) {