diff --git a/include/boost/geometry/algorithms/area.hpp b/include/boost/geometry/algorithms/area.hpp index 435189d94..78e419793 100644 --- a/include/boost/geometry/algorithms/area.hpp +++ b/include/boost/geometry/algorithms/area.hpp @@ -19,7 +19,6 @@ #include #include - #include #include #include @@ -30,6 +29,7 @@ #include #include +#include #include #include @@ -241,6 +241,8 @@ inline typename default_area_result::type area(Geometry const& geometr point_type >::type strategy_type; + detail::throw_on_empty_input(geometry); + return dispatch::area < Geometry @@ -277,6 +279,8 @@ inline typename Strategy::return_type area( { concept::check(); + detail::throw_on_empty_input(geometry); + return dispatch::area < Geometry, diff --git a/include/boost/geometry/algorithms/convex_hull.hpp b/include/boost/geometry/algorithms/convex_hull.hpp index 36d7a7466..56b87c8c1 100644 --- a/include/boost/geometry/algorithms/convex_hull.hpp +++ b/include/boost/geometry/algorithms/convex_hull.hpp @@ -35,33 +35,6 @@ namespace boost { namespace geometry { -#if ! defined(BOOST_GEOMETRY_CONVEX_HULL_NO_THROW) - -/*! -\brief Convex Hull Exception -\ingroup convex_hull -\details The convex_hull_exception is thrown if the free convex hull function is called with - geometries for which the hull cannot be calculated. For example: a linestring - without points, a polygon without points, an empty multi-geometry. -\qbk{ -[heading See also] -\* [link geometry.reference.algorithms.convex_hull the convex_hull function] -} - - */ -class convex_hull_exception : public geometry::exception -{ -public: - - inline convex_hull_exception() {} - - virtual char const* what() const throw() - { - return "Boost.Geometry Convex Hull calculation exception"; - } -}; - -#endif #ifndef DOXYGEN_NO_DETAIL namespace detail { namespace convex_hull @@ -204,9 +177,7 @@ inline void convex_hull(Geometry const& geometry, if (geometry::num_points(geometry) == 0) { -#if ! defined(BOOST_GEOMETRY_CONVEX_HULL_NO_THROW) - throw convex_hull_exception(); -#endif + // Leave output empty return; } diff --git a/include/boost/geometry/algorithms/detail/throw_on_empty_input.hpp b/include/boost/geometry/algorithms/detail/throw_on_empty_input.hpp new file mode 100644 index 000000000..56bf2ab62 --- /dev/null +++ b/include/boost/geometry/algorithms/detail/throw_on_empty_input.hpp @@ -0,0 +1,43 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2008-2012 Bruno Lalande, Paris, France. +// Copyright (c) 2009-2012 Mateusz Loskot, London, UK. + +// 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_ALGORITHMS_DETAIL_THROW_ON_EMPTY_INPUT_HPP +#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_THROW_ON_EMPTY_INPUT_HPP + +#include +#include + +namespace boost { namespace geometry +{ + +#ifndef DOXYGEN_NO_DETAIL +namespace detail +{ + +template +inline void throw_on_empty_input(Geometry const& geometry) +{ +#if ! defined(BOOST_GEOMETRY_EMPTY_INPUT_NO_THROW) + if (geometry::num_points(geometry) == 0) + { + throw empty_input_exception(); + } +#endif +} + +} // namespace detail +#endif // DOXYGEN_NO_DETAIL + + +}} // namespace boost::geometry + + +#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_THROW_ON_EMPTY_INPUT_HPP + diff --git a/include/boost/geometry/algorithms/distance.hpp b/include/boost/geometry/algorithms/distance.hpp index 8027cc87c..9b4a6476b 100644 --- a/include/boost/geometry/algorithms/distance.hpp +++ b/include/boost/geometry/algorithms/distance.hpp @@ -25,6 +25,7 @@ #include #include +#include #include #include @@ -549,6 +550,9 @@ inline typename strategy::distance::services::return_type::type distan { concept::check(); concept::check(); + + detail::throw_on_empty_input(geometry1); + detail::throw_on_empty_input(geometry2); return dispatch::distance < diff --git a/include/boost/geometry/algorithms/length.hpp b/include/boost/geometry/algorithms/length.hpp index 0d4249c08..77a24ccd9 100644 --- a/include/boost/geometry/algorithms/length.hpp +++ b/include/boost/geometry/algorithms/length.hpp @@ -28,6 +28,7 @@ #include #include +#include #include #include #include @@ -151,6 +152,8 @@ inline typename default_length_result::type length( { concept::check(); + detail::throw_on_empty_input(geometry); + typedef typename strategy::distance::services::default_strategy < point_tag, typename point_type::type @@ -185,6 +188,8 @@ inline typename default_length_result::type length( { concept::check(); + detail::throw_on_empty_input(geometry); + return dispatch::length < typename tag::type, diff --git a/include/boost/geometry/algorithms/perimeter.hpp b/include/boost/geometry/algorithms/perimeter.hpp index 7862900cf..90df707ef 100644 --- a/include/boost/geometry/algorithms/perimeter.hpp +++ b/include/boost/geometry/algorithms/perimeter.hpp @@ -22,6 +22,7 @@ #include #include #include +#include namespace boost { namespace geometry @@ -97,6 +98,8 @@ inline typename default_length_result::type perimeter( point_tag, point_type >::type strategy_type; + detail::throw_on_empty_input(geometry); + return dispatch::perimeter < typename tag::type, @@ -125,6 +128,8 @@ inline typename default_length_result::type perimeter( { concept::check(); + detail::throw_on_empty_input(geometry); + return dispatch::perimeter < typename tag::type, diff --git a/include/boost/geometry/core/exception.hpp b/include/boost/geometry/core/exception.hpp index 3073bfdf8..97d249e93 100644 --- a/include/boost/geometry/core/exception.hpp +++ b/include/boost/geometry/core/exception.hpp @@ -29,6 +29,32 @@ class exception : public std::exception {}; +/*! +\brief Empty Input Exception +\ingroup core +\details The empty_input_exception is thrown if free functions, e.g. distance, + are called with empty geometries, e.g. a linestring + without points, a polygon without points, an empty multi-geometry. +\qbk{ +[heading See also] +\* [link geometry.reference.algorithms.area the area function] +\* [link geometry.reference.algorithms.distance the distance function] +\* [link geometry.reference.algorithms.length the length function] +} + */ +class empty_input_exception : public geometry::exception +{ +public: + + inline empty_input_exception() {} + + virtual char const* what() const throw() + { + return "Boost.Geometry Empty-Input exception"; + } +}; + + }} // namespace boost::geometry #endif // BOOST_GEOMETRY_CORE_EXCEPTION_HPP diff --git a/include/boost/geometry/multi/algorithms/distance.hpp b/include/boost/geometry/multi/algorithms/distance.hpp index c815eb3f4..8acb3f900 100644 --- a/include/boost/geometry/multi/algorithms/distance.hpp +++ b/include/boost/geometry/multi/algorithms/distance.hpp @@ -23,6 +23,7 @@ #include #include +#include #include @@ -49,12 +50,12 @@ struct distance_single_to_multi MultiGeometry const& multi, Strategy const& strategy) { + return_type mindist = return_type(); bool first = true; - return_type mindist; for(typename range_iterator::type it = boost::begin(multi); it != boost::end(multi); - ++it) + ++it, first = false) { return_type dist = dispatch::distance < @@ -67,7 +68,6 @@ struct distance_single_to_multi { mindist = dist; } - first = false; } return mindist; @@ -88,12 +88,12 @@ struct distance_multi_to_multi static inline return_type apply(Multi1 const& multi1, Multi2 const& multi2, Strategy const& strategy) { + return_type mindist = return_type(); bool first = true; - return_type mindist; for(typename range_iterator::type it = boost::begin(multi1); it != boost::end(multi1); - ++it) + ++it, first = false) { return_type dist = distance_single_to_multi < @@ -105,7 +105,6 @@ struct distance_multi_to_multi { mindist = dist; } - first = false; } return mindist; diff --git a/test/algorithms/area.cpp b/test/algorithms/area.cpp index 0872be5a8..0ca9f2682 100644 --- a/test/algorithms/area.cpp +++ b/test/algorithms/area.cpp @@ -194,7 +194,15 @@ void test_open_ccw() // Note the triangular testcase used in CCW is not sensible for open/close } +template +void test_empty_input() +{ + bg::model::polygon

poly_empty; + bg::model::ring

ring_empty; + test_empty_input(poly_empty); + test_empty_input(ring_empty); +} int test_main(int, char* []) { @@ -214,5 +222,7 @@ int test_main(int, char* []) test_spherical > >(); #endif + test_empty_input >(); + return 0; } diff --git a/test/algorithms/convex_hull.cpp b/test/algorithms/convex_hull.cpp index 286048d08..f268aa90e 100644 --- a/test/algorithms/convex_hull.cpp +++ b/test/algorithms/convex_hull.cpp @@ -44,11 +44,11 @@ void test_all() ", 5.3 2.6, 5.4 1.2, 4.9 0.8, 2.9 0.7,2.0 1.3))", 12, 8, 5.245); - // Waits for next cycle test_geometry >("box(0 0,2 2)", 5, 5, 4); - - test_convex_hull_exception >(); - test_convex_hull_exception >(); - test_convex_hull_exception >(); + test_geometry >("box(0 0,2 2)", 4, 5, 4); + + test_empty_input >(); + test_empty_input >(); + test_empty_input >(); } diff --git a/test/algorithms/distance.cpp b/test/algorithms/distance.cpp index 613659043..a6be71478 100644 --- a/test/algorithms/distance.cpp +++ b/test/algorithms/distance.cpp @@ -228,6 +228,20 @@ void test_all() // test_geometry >("POINT(3 1)", "LINESTRING(1 1,4 4)", sqrt(2.0)); test_geometry >("POINT(3 1)", "LINESTRING(1 1,4 4)", sqrt(2.0)); + +} + +template +void test_empty_input() +{ + P p; + bg::model::linestring

line_empty; + bg::model::polygon

poly_empty; + bg::model::ring

ring_empty; + + test_empty_input(p, line_empty); + test_empty_input(p, poly_empty); + test_empty_input(p, ring_empty); } int test_main(int, char* []) @@ -248,5 +262,7 @@ int test_main(int, char* []) test_all >(); #endif + test_empty_input >(); + return 0; } diff --git a/test/algorithms/length.cpp b/test/algorithms/length.cpp index 2d96ee7b8..05efad111 100644 --- a/test/algorithms/length.cpp +++ b/test/algorithms/length.cpp @@ -33,6 +33,12 @@ void test_all() test_geometry >("POLYGON((0 0,0 1,1 1,1 0,0 0))", 0); } +template +void test_empty_input() +{ + test_empty_input(bg::model::linestring

()); +} + int test_main(int, char* []) { test_all >(); @@ -43,5 +49,7 @@ int test_main(int, char* []) test_all >(); #endif + test_empty_input >(); + return 0; } diff --git a/test/algorithms/perimeter.cpp b/test/algorithms/perimeter.cpp index 333f9b644..13d604602 100644 --- a/test/algorithms/perimeter.cpp +++ b/test/algorithms/perimeter.cpp @@ -35,6 +35,15 @@ void test_open() test_geometry("POLYGON((0 0,0 1,1 1,1 0))", 4); } +template +void test_empty_input() +{ + bg::model::polygon

poly_empty; + bg::model::ring

ring_empty; + + test_empty_input(poly_empty); + test_empty_input(ring_empty); +} int test_main(int, char* []) { @@ -48,5 +57,7 @@ int test_main(int, char* []) test_all >(); #endif + test_empty_input >(); + return 0; } diff --git a/test/algorithms/test_area.hpp b/test/algorithms/test_area.hpp index c153f728b..767eb3e93 100644 --- a/test/algorithms/test_area.hpp +++ b/test/algorithms/test_area.hpp @@ -66,5 +66,20 @@ void test_geometry(std::string const& wkt, test_area(geometry, expected_area); } +template +void test_empty_input(Geometry const& geometry) +{ + try + { + typename bg::default_area_result::type area + = bg::area(geometry); + } + catch(bg::empty_input_exception const& ) + { + return; + } + BOOST_CHECK_MESSAGE(false, "A empty_input_exception should have been thrown" ); +} + #endif diff --git a/test/algorithms/test_convex_hull.hpp b/test/algorithms/test_convex_hull.hpp index 7d77b3104..6ad1a4f83 100644 --- a/test/algorithms/test_convex_hull.hpp +++ b/test/algorithms/test_convex_hull.hpp @@ -109,23 +109,16 @@ void test_geometry(std::string const& wkt, } template -void test_convex_hull_exception() +void test_empty_input() { Geometry geometry; - try - { - bg::model::polygon - < - typename bg::point_type::type - > hull; + bg::model::polygon + < + typename bg::point_type::type + > hull; - bg::convex_hull(geometry, hull); - } - catch(bg::convex_hull_exception const& ) - { - return; - } - BOOST_CHECK_MESSAGE(false, "A convex_hull_exception should have been thrown" ); + bg::convex_hull(geometry, hull); + BOOST_CHECK_MESSAGE(bg::num_points(hull) == 0, "Output convex hull should be empty" ); } diff --git a/test/algorithms/test_distance.hpp b/test/algorithms/test_distance.hpp index ddf8015a1..a66572323 100644 --- a/test/algorithms/test_distance.hpp +++ b/test/algorithms/test_distance.hpp @@ -140,5 +140,20 @@ void test_geometry(std::string const& wkt1, std::string const& wkt2, double expe test_distance(geometry1, geometry2, expected_distance); } +template +void test_empty_input(Geometry1 const& geometry1, Geometry2 const& geometry2) +{ + try + { + typename bg::default_distance_result::type distance + = bg::distance(geometry1, geometry2); + } + catch(bg::empty_input_exception const& ) + { + return; + } + BOOST_CHECK_MESSAGE(false, "A empty_input_exception should have been thrown" ); +} + #endif diff --git a/test/algorithms/test_length.hpp b/test/algorithms/test_length.hpp index 591649a1b..947cbddb2 100644 --- a/test/algorithms/test_length.hpp +++ b/test/algorithms/test_length.hpp @@ -44,5 +44,19 @@ void test_geometry(std::string const& wkt, double expected_length) test_length(geometry, expected_length); } +template +void test_empty_input(Geometry const& geometry) +{ + try + { + typename bg::default_length_result::type length + = bg::length(geometry); + } + catch(bg::empty_input_exception const& ) + { + return; + } + BOOST_CHECK_MESSAGE(false, "A empty_input_exception should have been thrown" ); +} #endif diff --git a/test/algorithms/test_perimeter.hpp b/test/algorithms/test_perimeter.hpp index 0518938d7..061662c7b 100644 --- a/test/algorithms/test_perimeter.hpp +++ b/test/algorithms/test_perimeter.hpp @@ -47,5 +47,19 @@ void test_geometry(std::string const& wkt, double expected_perimeter) test_perimeter(geometry, expected_perimeter); } +template +void test_empty_input(Geometry const& geometry) +{ + try + { + typename bg::default_distance_result::type peri + = bg::perimeter(geometry); + } + catch(bg::empty_input_exception const& ) + { + return; + } + BOOST_CHECK_MESSAGE(false, "A empty_input_exception should have been thrown" ); +} #endif diff --git a/test/multi/algorithms/multi_convex_hull.cpp b/test/multi/algorithms/multi_convex_hull.cpp index 55d7da6f2..19d9c1ff6 100644 --- a/test/multi/algorithms/multi_convex_hull.cpp +++ b/test/multi/algorithms/multi_convex_hull.cpp @@ -53,9 +53,9 @@ void test_all() test_geometry("multilinestring((2 4, 3 4, 3 5), (4 3,4 4,5 4))", 6, 5, 3.0); test_geometry("multipolygon(((1 4,1 6,2 5,3 5,4 6,4 4,1 4)), ((4 2,4 3,6 3,6 2,4 2)))", 12, 7, 14.0); - test_convex_hull_exception(); - test_convex_hull_exception(); - test_convex_hull_exception(); + test_empty_input(); + test_empty_input(); + test_empty_input(); } diff --git a/test/multi/algorithms/multi_distance.cpp b/test/multi/algorithms/multi_distance.cpp index 1294d5dad..249598c91 100644 --- a/test/multi/algorithms/multi_distance.cpp +++ b/test/multi/algorithms/multi_distance.cpp @@ -10,6 +10,8 @@ #include +#include + #include #include @@ -128,6 +130,23 @@ void test_mixed() test_distance(pythagoras(), "MULTIPOINT((1 1),(1 0),(0 2))", "POINT(0 0)", 1.0); } +template +void test_empty_input() +{ + P p; + bg::model::multi_point

mp_empty; + bg::model::multi_linestring > ml_empty; + + test_empty_input(p, mp_empty); + test_empty_input(p, ml_empty); + test_empty_input(mp_empty, mp_empty); + + // Test behaviour if one of the inputs is empty + bg::model::multi_point

mp; + mp.push_back(p); + test_empty_input(mp_empty, mp); + test_empty_input(mp, mp_empty); +} int test_main( int , char* [] ) @@ -146,5 +165,7 @@ int test_main( int , char* [] ) test_mixed, bg::model::d2::point_xy >(); #endif + test_empty_input >(); + return 0; }