Merge branch 'develop' of https://github.com/boostorg/geometry into develop

This commit is contained in:
Barend Gehrels
2017-11-19 16:01:09 +01:00
6 changed files with 99 additions and 36 deletions

View File

@@ -1471,7 +1471,8 @@ struct buffered_piece_collection
// negative rings (negative child with negative parent)
detail::overlay::assign_parents(offsetted_rings, traversed_rings,
selected, m_intersection_strategy, true, false);
return detail::overlay::add_rings<GeometryOutput>(selected, offsetted_rings, traversed_rings, out);
return detail::overlay::add_rings<GeometryOutput>(selected, offsetted_rings, traversed_rings, out,
m_area_strategy);
}
};

View File

@@ -62,6 +62,13 @@ inline void convert_and_add(GeometryOut& result,
}
}
enum add_rings_error_handling
{
add_rings_ignore_unordered,
add_rings_add_unordered,
add_rings_throw_if_reversed
};
template
<
typename GeometryOut,
@@ -69,17 +76,18 @@ template
typename Geometry1,
typename Geometry2,
typename RingCollection,
typename OutputIterator
typename OutputIterator,
typename AreaStrategy
>
inline OutputIterator add_rings(SelectionMap const& map,
Geometry1 const& geometry1, Geometry2 const& geometry2,
RingCollection const& collection,
OutputIterator out,
bool require_positive_area = true)
AreaStrategy const& area_strategy,
add_rings_error_handling error_handling = add_rings_ignore_unordered)
{
typedef typename SelectionMap::const_iterator iterator;
typedef typename SelectionMap::mapped_type property_type;
typedef typename property_type::area_type area_type;
typedef typename AreaStrategy::return_type area_type;
area_type const zero = 0;
std::size_t const min_num_points = core_detail::closure::minimum_ring_size
@@ -123,11 +131,22 @@ inline OutputIterator add_rings(SelectionMap const& map,
// Only add rings if they satisfy minimal requirements.
// This cannot be done earlier (during traversal), not
// everything is figured out yet (sum of positive/negative rings)
if (geometry::num_points(result) >= min_num_points
&& (! require_positive_area
|| math::larger(geometry::area(result), zero)))
if (geometry::num_points(result) >= min_num_points)
{
*out++ = result;
area_type const area = geometry::area(result, area_strategy);
// Ignore if area is 0
if (! math::equals(area, zero))
{
if (error_handling == add_rings_add_unordered
|| area > zero)
{
*out++ = result;
}
else if (error_handling == add_rings_throw_if_reversed)
{
BOOST_THROW_EXCEPTION(invalid_output_exception());
}
}
}
}
}
@@ -141,15 +160,17 @@ template
typename SelectionMap,
typename Geometry,
typename RingCollection,
typename OutputIterator
typename OutputIterator,
typename AreaStrategy
>
inline OutputIterator add_rings(SelectionMap const& map,
Geometry const& geometry,
RingCollection const& collection,
OutputIterator out)
OutputIterator out,
AreaStrategy const& area_strategy)
{
Geometry empty;
return add_rings<GeometryOut>(map, geometry, empty, collection, out);
return add_rings<GeometryOut>(map, geometry, empty, collection, out, area_strategy);
}

View File

@@ -234,7 +234,8 @@ inline OutputIterator return_if_one_input_is_empty(Geometry1 const& geometry1,
select_rings<OverlayType>(geometry1, geometry2, empty, all_of_one_of_them, strategy);
ring_container_type rings;
assign_parents(geometry1, geometry2, rings, all_of_one_of_them, strategy);
return add_rings<GeometryOut>(all_of_one_of_them, geometry1, geometry2, rings, out);
return add_rings<GeometryOut>(all_of_one_of_them, geometry1, geometry2, rings, out,
strategy.template get_area_strategy<point_type1>());
}
@@ -370,9 +371,8 @@ std::cout << "traverse" << std::endl;
selected_ring_properties, strategy);
// Add rings created during traversal
area_strategy_type const area_strategy = strategy.template get_area_strategy<point_type>();
{
area_strategy_type const area_strategy = strategy.template get_area_strategy<point_type>();
ring_identifier id(2, 0, -1);
for (typename boost::range_iterator<ring_container_type>::type
it = boost::begin(rings);
@@ -390,10 +390,18 @@ std::cout << "traverse" << std::endl;
// NOTE: There is no need to check result area for union because
// as long as the polygons in the input are valid the resulting
// polygons should be valid as well.
// This also solves the issue with non-cartesian CSes, the result may
// be too big so the area is negative but it's returned anyway.
// This also solves the issue with non-cartesian CSes. The result may
// be too big, so the area is negative. In this case either it's returned
// anyway (default) or an exception is thrown (based on #define).
return add_rings<GeometryOut>(selected_ring_properties, geometry1, geometry2, rings, out,
OverlayType != overlay_union);
area_strategy,
OverlayType == overlay_union ?
#ifdef BOOST_GEOMETRY_UNION_THROW_INVALID_OUTPUT_EXCEPTION
add_rings_throw_if_reversed
#else
add_rings_add_unordered
#endif
: add_rings_ignore_unordered);
}
template <typename RobustPolicy, typename OutputIterator, typename Strategy>

View File

@@ -4,8 +4,8 @@
// Copyright (c) 2008-2015 Bruno Lalande, Paris, France.
// Copyright (c) 2009-2015 Mateusz Loskot, London, UK.
// This file was modified by Oracle on 2015.
// Modifications copyright (c) 2015 Oracle and/or its affiliates.
// This file was modified by Oracle on 2015, 2017.
// Modifications copyright (c) 2015-2017 Oracle and/or its affiliates.
// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
@@ -83,6 +83,25 @@ public:
}
};
/*!
\brief Invalid Output Exception
\ingroup core
\details The invalid_output_exception is thrown if valid output cannot be
generated by a function even if arguments are valid, e.g. union of
geographic polygons covering more than half of the area of the globe.
*/
class invalid_output_exception : public geometry::exception
{
public:
inline invalid_output_exception() {}
virtual char const* what() const throw()
{
return "Boost.Geometry Invalid-Output exception";
}
};
}} // namespace boost::geometry

View File

@@ -246,9 +246,8 @@ struct dissolve_ring_or_polygon
detail::overlay::select_rings<overlay_dissolve_union>(geometry, turn_info_per_ring, selected, strategy);
// Add intersected rings
area_strategy_type const area_strategy = strategy.template get_area_strategy<point_type>();
{
area_strategy_type const area_strategy = strategy.template get_area_strategy<point_type>();
ring_identifier id(2, 0, -1);
for (typename boost::range_iterator<std::vector<ring_type> const>::type
it = boost::begin(rings);
@@ -264,7 +263,7 @@ struct dissolve_ring_or_polygon
// children with negative parents
detail::overlay::assign_parents(geometry, rings, selected,
strategy, true, true);
return detail::overlay::add_rings<GeometryOut>(selected, geometry, rings, out);
return detail::overlay::add_rings<GeometryOut>(selected, geometry, rings, out, area_strategy);
}
};

View File

@@ -58,21 +58,36 @@ void test_geographic_one(std::string const& wkt1, std::string const& wkt2,
boost::geometry::read_wkt(wkt2, p2);
multipolygon result;
boost::geometry::union_(p1, p2, result, is);
double result_area = bg::area(result, as);
#ifdef BOOST_GEOMETRY_UNION_THROW_INVALID_OUTPUT_EXCEPTION
if (expected_area >= 0)
{
#else
{
#endif
boost::geometry::union_(p1, p2, result, is);
std::size_t result_count = boost::size(result);
std::size_t result_exterior_points = std::for_each(boost::begin(result),
boost::end(result),
exterior_points_counter()).count;
std::size_t result_interiors = std::for_each(boost::begin(result),
boost::end(result),
interiors_counter()).count;
BOOST_CHECK_EQUAL(result_count, count);
BOOST_CHECK_EQUAL(result_exterior_points, exterior_points_count);
BOOST_CHECK_EQUAL(result_interiors, interiors_count);
BOOST_CHECK_CLOSE(result_area, expected_area, 0.001);
double result_area = bg::area(result, as);
std::size_t result_count = boost::size(result);
std::size_t result_exterior_points = std::for_each(boost::begin(result),
boost::end(result),
exterior_points_counter()).count;
std::size_t result_interiors = std::for_each(boost::begin(result),
boost::end(result),
interiors_counter()).count;
BOOST_CHECK_EQUAL(result_count, count);
BOOST_CHECK_EQUAL(result_exterior_points, exterior_points_count);
BOOST_CHECK_EQUAL(result_interiors, interiors_count);
BOOST_CHECK_CLOSE(result_area, expected_area, 0.001);
}
#ifdef BOOST_GEOMETRY_UNION_THROW_INVALID_OUTPUT_EXCEPTION
else
{
BOOST_CHECK_THROW(boost::geometry::union_(p1, p2, result, is),
bg::invalid_output_exception);
}
#endif
}