From e054e25bfdfef99e9f0eb1266011fd24cd88920f Mon Sep 17 00:00:00 2001 From: Adam Wulkiewicz Date: Thu, 23 Oct 2014 21:32:20 +0200 Subject: [PATCH 01/14] [test][strategies] Divide different within/covered_by strategies tests into separate files. --- test/strategies/Jamfile.v2 | 6 +- test/strategies/crossings_multiply.cpp | 87 +++++ test/strategies/franklin.cpp | 86 +++++ test/strategies/point_in_box.cpp | 81 +++++ test/strategies/test_within.hpp | 106 ++++++ test/strategies/winding.cpp | 219 ++++++++++++ .../strategies/winding_franklin_crossmult.cpp | 326 ------------------ 7 files changed, 584 insertions(+), 327 deletions(-) create mode 100644 test/strategies/crossings_multiply.cpp create mode 100644 test/strategies/franklin.cpp create mode 100644 test/strategies/point_in_box.cpp create mode 100644 test/strategies/test_within.hpp create mode 100644 test/strategies/winding.cpp delete mode 100644 test/strategies/winding_franklin_crossmult.cpp 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..fc6d7bb55 --- /dev/null +++ b/test/strategies/winding.cpp @@ -0,0 +1,219 @@ +// 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); + + 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*/); + + 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); + + 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); +} + +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; -} From 4d7210da99b0a27a2167f1f097e8e2fc17439a36 Mon Sep 17 00:00:00 2001 From: Adam Wulkiewicz Date: Fri, 24 Oct 2014 00:03:27 +0200 Subject: [PATCH 02/14] [test][strategies] Disable failing winding tests for spherical CS (enabled with #define). --- test/strategies/winding.cpp | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/test/strategies/winding.cpp b/test/strategies/winding.cpp index fc6d7bb55..f22058cd6 100644 --- a/test/strategies/winding.cpp +++ b/test/strategies/winding.cpp @@ -207,12 +207,19 @@ int test_main(int, char* []) test_cartesian >(); test_cartesian >(); +#if defined(HAVE_TTMATH) + test_cartesian >(); +#endif + +#ifdef BOOST_GEOMETRY_TEST_STRATEGIES_WINDING_ENABLE_FAILING_TESTS + test_spherical(); test_spherical(); #if defined(HAVE_TTMATH) - test_cartesian >(); test_spherical(); +#endif + #endif return 0; From f5ce90c9a65365251532768b4858af0ae7af1186 Mon Sep 17 00:00:00 2001 From: Adam Wulkiewicz Date: Fri, 24 Oct 2014 00:15:25 +0200 Subject: [PATCH 03/14] [test][strategies] Enable some of the winding tests for spherical CS. --- test/strategies/winding.cpp | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/test/strategies/winding.cpp b/test/strategies/winding.cpp index f22058cd6..ff0f3605a 100644 --- a/test/strategies/winding.cpp +++ b/test/strategies/winding.cpp @@ -90,6 +90,8 @@ void test_spherical() s, false); +#ifdef BOOST_GEOMETRY_TEST_STRATEGIES_WINDING_ENABLE_FAILING_TESTS + test_geometry( "sph1N", "POINT(0 10.001)", @@ -143,6 +145,8 @@ void test_spherical() point(0, (T)-10.001)) == -1 // right side /*true*/); +#endif // BOOST_GEOMETRY_TEST_STRATEGIES_WINDING_ENABLE_FAILING_TESTS + test_geometry( "sphEq1", "POINT(179 10)", @@ -172,6 +176,8 @@ void test_spherical() true, false); +#ifdef BOOST_GEOMETRY_TEST_STRATEGIES_WINDING_ENABLE_FAILING_TESTS + test_geometry( "sphEq5", "POINT(169 10)", @@ -200,6 +206,8 @@ void test_spherical() s, false, false); + +#endif // BOOST_GEOMETRY_TEST_STRATEGIES_WINDING_ENABLE_FAILING_TESTS } int test_main(int, char* []) @@ -207,19 +215,12 @@ int test_main(int, char* []) test_cartesian >(); test_cartesian >(); -#if defined(HAVE_TTMATH) - test_cartesian >(); -#endif - -#ifdef BOOST_GEOMETRY_TEST_STRATEGIES_WINDING_ENABLE_FAILING_TESTS - test_spherical(); test_spherical(); #if defined(HAVE_TTMATH) + test_cartesian >(); test_spherical(); -#endif - #endif return 0; From e4cd46ac5d5d4e55b3046a20fe7cfcea29b0bf0d Mon Sep 17 00:00:00 2001 From: Barend Gehrels Date: Fri, 24 Oct 2014 11:21:32 +0200 Subject: [PATCH 04/14] [buffer] support degenerate linestrings containing one point. In that case point-buffer is applied. Including updated unit tests --- .../detail/buffer/buffer_inserter.hpp | 43 ++++++++++++++----- test/algorithms/buffer/linestring_buffer.cpp | 14 ++++++ .../buffer/multi_linestring_buffer.cpp | 10 +++++ 3 files changed, 57 insertions(+), 10 deletions(-) diff --git a/include/boost/geometry/algorithms/detail/buffer/buffer_inserter.hpp b/include/boost/geometry/algorithms/detail/buffer/buffer_inserter.hpp index 7a901c869..1e2e6e33c 100644 --- a/include/boost/geometry/algorithms/detail/buffer/buffer_inserter.hpp +++ b/include/boost/geometry/algorithms/detail/buffer/buffer_inserter.hpp @@ -345,6 +345,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 +409,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); } }; @@ -577,10 +594,11 @@ 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) + std::size_t n = boost::size(linestring); + if (n > 1) { Linestring simplified; detail::buffer::simplify_input(linestring, distance, simplified); @@ -598,9 +616,14 @@ struct buffer_inserter first_p1); collection.finish_ring(); } - else + else if (n == 1) { // Use point_strategy to buffer degenerated linestring + detail::buffer::buffer_point + ( + geometry::range::front(linestring), + collection, distance, point_strategy + ); } } }; diff --git a/test/algorithms/buffer/linestring_buffer.cpp b/test/algorithms/buffer/linestring_buffer.cpp index bdca6e3d0..8329d961f 100644 --- a/test/algorithms/buffer/linestring_buffer.cpp +++ b/test/algorithms/buffer/linestring_buffer.cpp @@ -27,6 +27,10 @@ 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 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 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)"; @@ -133,6 +137,16 @@ 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("degenerate1", degenerate1, join_round, end_round, 28.25, 3.0); +#if defined(BOOST_GEOMETRY_BUFFER_INCLUDE_FAILING_TESTS) + test_one("degenerate2", degenerate2, join_miter, end_flat, 99.99, 3.0); + test_one("degenerate2", degenerate2, join_round, end_round, 99.99, 3.0); + test_one("degenerate3", degenerate3, join_miter, end_flat, 99.99, 3.0); + test_one("degenerate3", degenerate3, join_round, end_round, 99.99, 3.0); +#endif + + + double tolerance = 1.0e-10; test_one("aimes120", aimes120, join_miter, end_flat, 1.62669948622351512e-08, 0.000018, 0.000018, false, tolerance); diff --git a/test/algorithms/buffer/multi_linestring_buffer.cpp b/test/algorithms/buffer/multi_linestring_buffer.cpp index 6174e3c8e..8d1481c47 100644 --- a/test/algorithms/buffer/multi_linestring_buffer.cpp +++ b/test/algorithms/buffer/multi_linestring_buffer.cpp @@ -15,6 +15,11 @@ 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))"; + template void test_all() @@ -49,6 +54,11 @@ 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); } From fd75d83fd1132d556a64b27ed443b1c54aaaff57 Mon Sep 17 00:00:00 2001 From: Barend Gehrels Date: Fri, 24 Oct 2014 12:36:22 +0200 Subject: [PATCH 05/14] [buffer][fix] fix output for generated linestrings with two equal points only It now simplifies first and removes second point if necessary. Also it is defensive such that generation is stopped if length is 0. Including unit tests. --- .../detail/buffer/buffer_inserter.hpp | 72 +++++++++++-------- .../cartesian/buffer_side_straight.hpp | 11 +-- test/algorithms/buffer/linestring_buffer.cpp | 15 ++-- .../buffer/multi_linestring_buffer.cpp | 2 + 4 files changed, 58 insertions(+), 42 deletions(-) diff --git a/include/boost/geometry/algorithms/detail/buffer/buffer_inserter.hpp b/include/boost/geometry/algorithms/detail/buffer/buffer_inserter.hpp index 1e2e6e33c..d51840c3f 100644 --- a/include/boost/geometry/algorithms/detail/buffer/buffer_inserter.hpp +++ b/include/boost/geometry/algorithms/detail/buffer/buffer_inserter.hpp @@ -87,6 +87,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); + } } @@ -505,7 +512,6 @@ struct buffer_inserter strategy::buffer::buffer_side_left, distance, side_strategy, join_strategy, end_strategy, robust_policy); } - } } }; @@ -522,19 +528,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, @@ -545,7 +538,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, @@ -562,10 +555,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; @@ -577,6 +583,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 @@ -597,31 +604,36 @@ struct buffer_inserter PointStrategy const& point_strategy, RobustPolicy const& robust_policy) { - std::size_t n = boost::size(linestring); + Linestring simplified; + detail::buffer::simplify_input(linestring, distance, simplified); + + bool has_output = false; + std::size_t n = boost::size(simplified); if (n > 1) { - Linestring simplified; - detail::buffer::simplify_input(linestring, distance, simplified); - 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 (n == 1) + if (! has_output && n >= 1) { // Use point_strategy to buffer degenerated linestring detail::buffer::buffer_point ( - geometry::range::front(linestring), + geometry::range::front(simplified), collection, distance, point_strategy ); } diff --git a/include/boost/geometry/strategies/cartesian/buffer_side_straight.hpp b/include/boost/geometry/strategies/cartesian/buffer_side_straight.hpp index b5d28e257..7e979d242 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 @@ -75,8 +73,13 @@ public : // 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 8329d961f..173a5746c 100644 --- a/test/algorithms/buffer/linestring_buffer.cpp +++ b/test/algorithms/buffer/linestring_buffer.cpp @@ -27,9 +27,11 @@ 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)"; @@ -137,15 +139,12 @@ 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); -#if defined(BOOST_GEOMETRY_BUFFER_INCLUDE_FAILING_TESTS) - test_one("degenerate2", degenerate2, join_miter, end_flat, 99.99, 3.0); - test_one("degenerate2", degenerate2, join_round, end_round, 99.99, 3.0); - test_one("degenerate3", degenerate3, join_miter, end_flat, 99.99, 3.0); - test_one("degenerate3", degenerate3, join_round, end_round, 99.99, 3.0); -#endif - - + 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; diff --git a/test/algorithms/buffer/multi_linestring_buffer.cpp b/test/algorithms/buffer/multi_linestring_buffer.cpp index 8d1481c47..3aadf713d 100644 --- a/test/algorithms/buffer/multi_linestring_buffer.cpp +++ b/test/algorithms/buffer/multi_linestring_buffer.cpp @@ -19,6 +19,7 @@ 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 @@ -59,6 +60,7 @@ void test_all() 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); } From a57e8ffe7f4f2e1e16933967e8df8504f4b587d8 Mon Sep 17 00:00:00 2001 From: Barend Gehrels Date: Fri, 24 Oct 2014 12:36:44 +0200 Subject: [PATCH 06/14] [buffer] make constant local variables const --- .../geometry/strategies/cartesian/buffer_side_straight.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/include/boost/geometry/strategies/cartesian/buffer_side_straight.hpp b/include/boost/geometry/strategies/cartesian/buffer_side_straight.hpp index 7e979d242..24655ab3d 100644 --- a/include/boost/geometry/strategies/cartesian/buffer_side_straight.hpp +++ b/include/boost/geometry/strategies/cartesian/buffer_side_straight.hpp @@ -67,8 +67,8 @@ 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); From 6280a2b67e54242d567159505a38fa6afdeff81a Mon Sep 17 00:00:00 2001 From: Barend Gehrels Date: Fri, 24 Oct 2014 13:12:10 +0200 Subject: [PATCH 07/14] [buffer] support buffer for degenerate polygons (pointlike, not enough points) --- .../detail/buffer/buffer_inserter.hpp | 64 +++++++++++++------ .../buffer/buffered_piece_collection.hpp | 6 +- .../buffer/multi_polygon_buffer.cpp | 11 ++++ test/algorithms/buffer/polygon_buffer.cpp | 15 +++++ 4 files changed, 76 insertions(+), 20 deletions(-) diff --git a/include/boost/geometry/algorithms/detail/buffer/buffer_inserter.hpp b/include/boost/geometry/algorithms/detail/buffer/buffer_inserter.hpp index d51840c3f..49f4b25d3 100644 --- a/include/boost/geometry/algorithms/detail/buffer/buffer_inserter.hpp +++ b/include/boost/geometry/algorithms/detail/buffer/buffer_inserter.hpp @@ -209,7 +209,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, @@ -253,6 +253,7 @@ struct buffer_range * pup: penultimate_point */ + bool result = false; bool first = true; Iterator it = begin; @@ -266,14 +267,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, @@ -302,6 +310,7 @@ struct buffer_range } previous_robust_input = robust_input; } + return result; } }; @@ -443,7 +452,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, @@ -456,21 +465,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 @@ -489,30 +502,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); + RingOutput simplified; + detail::buffer::simplify_input(ring, distance, simplified); + bool has_output = false; + + std::size_t n = boost::size(simplified); + if (n > 3) + { 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(simplified), boost::rend(simplified), 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(simplified), boost::end(simplified), 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 + ); + } } }; 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..fa9cab286 100644 --- a/include/boost/geometry/algorithms/detail/buffer/buffered_piece_collection.hpp +++ b/include/boost/geometry/algorithms/detail/buffer/buffered_piece_collection.hpp @@ -571,7 +571,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/test/algorithms/buffer/multi_polygon_buffer.cpp b/test/algorithms/buffer/multi_polygon_buffer.cpp index 9beeff8cc..9ffa39c10 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) @@ -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); diff --git a/test/algorithms/buffer/polygon_buffer.cpp b/test/algorithms/buffer/polygon_buffer.cpp index e19b4f500..68d750f6c 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))"; @@ -210,6 +220,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); From d7625436768ac9081b704995f77eb325260d972a Mon Sep 17 00:00:00 2001 From: Barend Gehrels Date: Fri, 24 Oct 2014 13:33:17 +0200 Subject: [PATCH 08/14] [buffer][test] add reported testcase which succeeds --- test/algorithms/buffer/polygon_buffer.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/test/algorithms/buffer/polygon_buffer.cpp b/test/algorithms/buffer/polygon_buffer.cpp index 68d750f6c..ec7cf85c7 100644 --- a/test/algorithms/buffer/polygon_buffer.cpp +++ b/test/algorithms/buffer/polygon_buffer.cpp @@ -108,6 +108,10 @@ 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 void test_all() @@ -359,6 +363,10 @@ 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); } From b40c1096a457a57617d071cde989cf096ec8fb67 Mon Sep 17 00:00:00 2001 From: Barend Gehrels Date: Fri, 24 Oct 2014 14:20:15 +0200 Subject: [PATCH 09/14] [buffer][test] fix 3 testcase names --- test/algorithms/buffer/polygon_buffer.cpp | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/test/algorithms/buffer/polygon_buffer.cpp b/test/algorithms/buffer/polygon_buffer.cpp index ec7cf85c7..7b4830ad4 100644 --- a/test/algorithms/buffer/polygon_buffer.cpp +++ b/test/algorithms/buffer/polygon_buffer.cpp @@ -329,11 +329,10 @@ 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); - + test_one("parcel3_bend_15", parcel3_bend, join_round, end_flat, 917.9747, 15.0); + test_one("parcel3_bend_20", parcel3_bend, join_round, end_flat, 1534.4795, 20.0); // Negative buffers making polygons smaller test_one("simplex", simplex, join_round, end_flat, 7.04043, -0.5); From bd4de457d8e9000d9a7c7c617c4fc7b424f38c39 Mon Sep 17 00:00:00 2001 From: Barend Gehrels Date: Fri, 24 Oct 2014 15:02:55 +0200 Subject: [PATCH 10/14] [buffer][fix] fixes counter clockwise polygons --- .../detail/buffer/buffer_inserter.hpp | 18 +++++++++++++++--- .../buffer/buffered_piece_collection.hpp | 2 ++ .../algorithms/buffer/multi_polygon_buffer.cpp | 7 ++++--- test/algorithms/buffer/polygon_buffer.cpp | 13 ++++++++----- test/algorithms/buffer/test_buffer.hpp | 1 + 5 files changed, 30 insertions(+), 11 deletions(-) diff --git a/include/boost/geometry/algorithms/detail/buffer/buffer_inserter.hpp b/include/boost/geometry/algorithms/detail/buffer/buffer_inserter.hpp index 49f4b25d3..2d13c0cc9 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 @@ -513,18 +515,19 @@ struct buffer_inserter 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. - has_output = 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 { - has_output = 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); } @@ -875,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 fa9cab286..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; diff --git a/test/algorithms/buffer/multi_polygon_buffer.cpp b/test/algorithms/buffer/multi_polygon_buffer.cpp index 9ffa39c10..4cce69a4c 100644 --- a/test/algorithms/buffer/multi_polygon_buffer.cpp +++ b/test/algorithms/buffer/multi_polygon_buffer.cpp @@ -267,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; @@ -405,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/polygon_buffer.cpp b/test/algorithms/buffer/polygon_buffer.cpp index 7b4830ad4..2c4f5926f 100644 --- a/test/algorithms/buffer/polygon_buffer.cpp +++ b/test/algorithms/buffer/polygon_buffer.cpp @@ -113,10 +113,10 @@ static std::string const mysql_report_2014_10_24 -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); @@ -331,8 +331,10 @@ void test_all() 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_15", parcel3_bend, join_round, end_flat, 917.9747, 15.0); - test_one("parcel3_bend_20", 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); @@ -375,7 +377,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/test_buffer.hpp b/test/algorithms/buffer/test_buffer.hpp index c6467fdeb..9373e0bfa 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 ; From 6f09c5fd980fb97f7905630feb6a17a369e8afa2 Mon Sep 17 00:00:00 2001 From: Barend Gehrels Date: Fri, 24 Oct 2014 15:17:05 +0200 Subject: [PATCH 11/14] [buffer][test] test counter clockwise output for (multi)linestrings / points --- test/algorithms/buffer/linestring_buffer.cpp | 7 +++--- .../buffer/multi_linestring_buffer.cpp | 7 +++--- test/algorithms/buffer/multi_point_buffer.cpp | 11 ++++----- test/algorithms/buffer/point_buffer.cpp | 23 ++++--------------- 4 files changed, 16 insertions(+), 32 deletions(-) diff --git a/test/algorithms/buffer/linestring_buffer.cpp b/test/algorithms/buffer/linestring_buffer.cpp index 173a5746c..078ca3f21 100644 --- a/test/algorithms/buffer/linestring_buffer.cpp +++ b/test/algorithms/buffer/linestring_buffer.cpp @@ -48,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); @@ -178,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 3aadf713d..c36a3a2e4 100644 --- a/test/algorithms/buffer/multi_linestring_buffer.cpp +++ b/test/algorithms/buffer/multi_linestring_buffer.cpp @@ -22,12 +22,12 @@ 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); @@ -67,7 +67,8 @@ void test_all() 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/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; } From 745e5a94e7f5e4fc8918e3cbc1003433eff1d00f Mon Sep 17 00:00:00 2001 From: Barend Gehrels Date: Fri, 24 Oct 2014 15:19:12 +0200 Subject: [PATCH 12/14] [buffer][doc] add support for ccw / degenerated input to release notes --- doc/release_notes.qbk | 2 ++ 1 file changed, 2 insertions(+) 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] From ffd3cd1e3d9a1ab172bf92812ab3794ff923d006 Mon Sep 17 00:00:00 2001 From: Barend Gehrels Date: Fri, 24 Oct 2014 15:33:03 +0200 Subject: [PATCH 13/14] [buffer][test] fix ccw suffix which should use output geometry --- test/algorithms/buffer/test_buffer.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/algorithms/buffer/test_buffer.hpp b/test/algorithms/buffer/test_buffer.hpp index 9373e0bfa..248519c58 100644 --- a/test/algorithms/buffer/test_buffer.hpp +++ b/test/algorithms/buffer/test_buffer.hpp @@ -412,7 +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" : "") + << (bg::point_order::value == bg::counterclockwise ? "_ccw" : "") // << "_" << point_buffer_count ; From 0f72af95f0ac94f94022c6e4b7831895c2291dde Mon Sep 17 00:00:00 2001 From: Barend Gehrels Date: Fri, 24 Oct 2014 15:52:05 +0200 Subject: [PATCH 14/14] [buffer] fix simplify which should work on input ringtype and added unit test which tests different input/output types w.r.t. point order (different point types are not yet supported) --- .../detail/buffer/buffer_inserter.hpp | 4 +-- test/algorithms/buffer/polygon_buffer.cpp | 35 +++++++++++++++++-- 2 files changed, 34 insertions(+), 5 deletions(-) diff --git a/include/boost/geometry/algorithms/detail/buffer/buffer_inserter.hpp b/include/boost/geometry/algorithms/detail/buffer/buffer_inserter.hpp index 2d13c0cc9..2021a0481 100644 --- a/include/boost/geometry/algorithms/detail/buffer/buffer_inserter.hpp +++ b/include/boost/geometry/algorithms/detail/buffer/buffer_inserter.hpp @@ -507,7 +507,7 @@ struct buffer_inserter PointStrategy const& point_strategy, RobustPolicy const& robust_policy) { - RingOutput simplified; + RingInput simplified; detail::buffer::simplify_input(ring, distance, simplified); bool has_output = false; @@ -515,7 +515,7 @@ struct buffer_inserter std::size_t n = boost::size(simplified); if (n > 3) { - detail::normalized_view view(simplified); + detail::normalized_view view(simplified); if (distance.negative()) { // Walk backwards (rings will be reversed afterwards) diff --git a/test/algorithms/buffer/polygon_buffer.cpp b/test/algorithms/buffer/polygon_buffer.cpp index 2c4f5926f..fe3e48bf5 100644 --- a/test/algorithms/buffer/polygon_buffer.cpp +++ b/test/algorithms/buffer/polygon_buffer.cpp @@ -370,6 +370,28 @@ void test_all() 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 @@ -377,9 +399,16 @@ void test_all() int test_main(int, char* []) { - test_all >(); - test_all >(); + typedef bg::model::point dpoint; + + test_all(); + test_all(); //test_all >(); - + + test_mixed(); + test_mixed(); + test_mixed(); + test_mixed(); + return 0; }