mirror of
https://github.com/boostorg/geometry.git
synced 2026-02-11 11:52:11 +00:00
[buffer] propagate error information from strategy to buffer inserter
This commit is contained in:
@@ -12,9 +12,9 @@
|
||||
#include <cstddef>
|
||||
#include <iterator>
|
||||
|
||||
#include <boost/assert.hpp>
|
||||
#include <boost/core/ignore_unused.hpp>
|
||||
#include <boost/numeric/conversion/cast.hpp>
|
||||
|
||||
#include <boost/range.hpp>
|
||||
|
||||
#include <boost/geometry/core/closure.hpp>
|
||||
@@ -227,7 +227,7 @@ struct buffer_range
|
||||
typename EndStrategy,
|
||||
typename RobustPolicy
|
||||
>
|
||||
static inline bool iterate(Collection& collection,
|
||||
static inline strategy::buffer::result_code iterate(Collection& collection,
|
||||
Iterator begin, Iterator end,
|
||||
strategy::buffer::buffer_side_selector side,
|
||||
DistanceStrategy const& distance_strategy,
|
||||
@@ -266,7 +266,7 @@ struct buffer_range
|
||||
* pup: penultimate_point
|
||||
*/
|
||||
|
||||
bool result = false;
|
||||
strategy::buffer::result_code result = strategy::buffer::result_no_output;
|
||||
bool first = true;
|
||||
|
||||
Iterator it = begin;
|
||||
@@ -277,18 +277,25 @@ struct buffer_range
|
||||
for (Iterator prev = it++; it != end; ++it)
|
||||
{
|
||||
generated_side.clear();
|
||||
side_strategy.apply(*prev, *it, side,
|
||||
strategy::buffer::result_code error_code
|
||||
= side_strategy.apply(*prev, *it, side,
|
||||
distance_strategy, generated_side);
|
||||
|
||||
if (generated_side.empty())
|
||||
if (error_code == strategy::buffer::result_no_output)
|
||||
{
|
||||
// Because input is simplified, this is improbable,
|
||||
// but it can happen for degenerate geometries
|
||||
// Further handling of this side is skipped
|
||||
continue;
|
||||
}
|
||||
else if (error_code == strategy::buffer::result_error_numerical)
|
||||
{
|
||||
return error_code;
|
||||
}
|
||||
|
||||
result = true;
|
||||
BOOST_ASSERT(! generated_side.empty());
|
||||
|
||||
result = strategy::buffer::result_normal;
|
||||
|
||||
if (! first)
|
||||
{
|
||||
@@ -459,7 +466,7 @@ struct buffer_inserter<ring_tag, RingInput, RingOutput>
|
||||
typename EndStrategy,
|
||||
typename RobustPolicy
|
||||
>
|
||||
static inline bool iterate(Collection& collection,
|
||||
static inline strategy::buffer::result_code iterate(Collection& collection,
|
||||
Iterator begin, Iterator end,
|
||||
strategy::buffer::buffer_side_selector side,
|
||||
DistanceStrategy const& distance_strategy,
|
||||
@@ -472,13 +479,14 @@ struct buffer_inserter<ring_tag, RingInput, RingOutput>
|
||||
|
||||
typedef detail::buffer::buffer_range<RingOutput> buffer_range;
|
||||
|
||||
bool result = buffer_range::iterate(collection, begin, end,
|
||||
strategy::buffer::result_code 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
|
||||
if (result)
|
||||
if (result == strategy::buffer::result_normal)
|
||||
{
|
||||
buffer_range::add_join(collection,
|
||||
*(end - 2),
|
||||
@@ -515,7 +523,7 @@ struct buffer_inserter<ring_tag, RingInput, RingOutput>
|
||||
RingInput simplified;
|
||||
detail::buffer::simplify_input(ring, distance, simplified);
|
||||
|
||||
bool has_output = false;
|
||||
strategy::buffer::result_code code = strategy::buffer::result_no_output;
|
||||
|
||||
std::size_t n = boost::size(simplified);
|
||||
std::size_t const min_points = core_detail::closure::minimum_ring_size
|
||||
@@ -529,21 +537,19 @@ struct buffer_inserter<ring_tag, RingInput, RingOutput>
|
||||
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(view), boost::rend(view),
|
||||
code = 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(view), boost::end(view),
|
||||
code = iterate(collection, boost::begin(view), boost::end(view),
|
||||
strategy::buffer::buffer_side_left,
|
||||
distance, side_strategy, join_strategy, end_strategy, robust_policy);
|
||||
}
|
||||
}
|
||||
|
||||
if (! has_output && n >= 1)
|
||||
if (code == strategy::buffer::result_no_output && n >= 1)
|
||||
{
|
||||
// Use point_strategy to buffer degenerated ring
|
||||
detail::buffer::buffer_point<output_point_type>
|
||||
@@ -577,7 +583,7 @@ struct buffer_inserter<linestring_tag, Linestring, Polygon>
|
||||
typename EndStrategy,
|
||||
typename RobustPolicy
|
||||
>
|
||||
static inline bool iterate(Collection& collection,
|
||||
static inline strategy::buffer::result_code iterate(Collection& collection,
|
||||
Iterator begin, Iterator end,
|
||||
strategy::buffer::buffer_side_selector side,
|
||||
DistanceStrategy const& distance_strategy,
|
||||
@@ -602,24 +608,27 @@ struct buffer_inserter<linestring_tag, Linestring, Polygon>
|
||||
else
|
||||
{
|
||||
std::vector<output_point_type> generated_side;
|
||||
side_strategy.apply(ultimate_point, penultimate_point,
|
||||
strategy::buffer::result_code code
|
||||
= side_strategy.apply(ultimate_point, penultimate_point,
|
||||
strategy::buffer::buffer_side_right,
|
||||
distance_strategy, generated_side);
|
||||
if (generated_side.empty())
|
||||
if (code != strategy::buffer::result_normal)
|
||||
{
|
||||
return false;
|
||||
// No output or numerical error
|
||||
return code;
|
||||
}
|
||||
reverse_p1 = generated_side.front();
|
||||
}
|
||||
|
||||
output_point_type first_p2, last_p1, last_p2;
|
||||
|
||||
bool result = detail::buffer::buffer_range<output_ring_type>::iterate(collection,
|
||||
strategy::buffer::result_code result
|
||||
= detail::buffer::buffer_range<output_ring_type>::iterate(collection,
|
||||
begin, end, side,
|
||||
distance_strategy, side_strategy, join_strategy, end_strategy, robust_policy,
|
||||
first_p1, first_p2, last_p1, last_p2);
|
||||
|
||||
if (result)
|
||||
if (result == strategy::buffer::result_normal)
|
||||
{
|
||||
std::vector<output_point_type> range_out;
|
||||
end_strategy.apply(penultimate_point, last_p2, ultimate_point, reverse_p1, side, distance_strategy, range_out);
|
||||
@@ -649,28 +658,29 @@ struct buffer_inserter<linestring_tag, Linestring, Polygon>
|
||||
Linestring simplified;
|
||||
detail::buffer::simplify_input(linestring, distance, simplified);
|
||||
|
||||
bool has_output = false;
|
||||
strategy::buffer::result_code code = strategy::buffer::result_no_output;
|
||||
std::size_t n = boost::size(simplified);
|
||||
if (n > 1)
|
||||
{
|
||||
collection.start_new_ring();
|
||||
output_point_type first_p1;
|
||||
has_output = iterate(collection,
|
||||
code = iterate(collection,
|
||||
boost::begin(simplified), boost::end(simplified),
|
||||
strategy::buffer::buffer_side_left,
|
||||
distance, side_strategy, join_strategy, end_strategy, robust_policy,
|
||||
first_p1);
|
||||
|
||||
if (has_output)
|
||||
if (code == strategy::buffer::result_normal)
|
||||
{
|
||||
iterate(collection, boost::rbegin(simplified), boost::rend(simplified),
|
||||
code = 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();
|
||||
}
|
||||
if (! has_output && n >= 1)
|
||||
if (code == strategy::buffer::result_no_output && n >= 1)
|
||||
{
|
||||
// Use point_strategy to buffer degenerated linestring
|
||||
detail::buffer::buffer_point<output_point_type>
|
||||
|
||||
@@ -83,6 +83,17 @@ enum join_selector
|
||||
join_spike // collinear, with overlap, next segment goes back
|
||||
};
|
||||
|
||||
/*!
|
||||
\brief Enumerates types of result codes from buffer strategies
|
||||
\ingroup enum
|
||||
*/
|
||||
enum result_code
|
||||
{
|
||||
result_normal,
|
||||
result_error_numerical,
|
||||
result_no_output
|
||||
};
|
||||
|
||||
|
||||
}} // namespace strategy::buffer
|
||||
|
||||
|
||||
@@ -9,6 +9,8 @@
|
||||
|
||||
#include <cstddef>
|
||||
|
||||
#include <boost/math/special_functions/fpclassify.hpp>
|
||||
|
||||
#include <boost/geometry/core/coordinate_type.hpp>
|
||||
#include <boost/geometry/core/access.hpp>
|
||||
#include <boost/geometry/util/math.hpp>
|
||||
@@ -51,9 +53,9 @@ public :
|
||||
typename OutputRange,
|
||||
typename DistanceStrategy
|
||||
>
|
||||
static inline void apply(
|
||||
static inline result_code apply(
|
||||
Point const& input_p1, Point const& input_p2,
|
||||
strategy::buffer::buffer_side_selector side,
|
||||
buffer_side_selector side,
|
||||
DistanceStrategy const& distance,
|
||||
OutputRange& output_range)
|
||||
{
|
||||
@@ -78,10 +80,11 @@ public :
|
||||
// In case of coordinates differences of e.g. 1e300, length
|
||||
// will overflow and we should not generate output
|
||||
#ifdef BOOST_GEOMETRY_DEBUG_BUFFER_WARN
|
||||
std::cout << "Length not calculated for points " << geometry::wkt(input_p1)
|
||||
<< " " << geometry::wkt(input_p2) << " " << length << std::endl;
|
||||
std::cout << "Error in length calculation for points "
|
||||
<< geometry::wkt(input_p1) << " " << geometry::wkt(input_p2)
|
||||
<< " length: " << length << std::endl;
|
||||
#endif
|
||||
return;
|
||||
return result_error_numerical;
|
||||
}
|
||||
|
||||
if (geometry::math::equals(length, 0))
|
||||
@@ -89,14 +92,29 @@ public :
|
||||
// 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;
|
||||
return result_no_output;
|
||||
}
|
||||
|
||||
promoted_type const d = distance.apply(input_p1, input_p2, side);
|
||||
|
||||
// Generate the normalized perpendicular p, to the left (ccw)
|
||||
promoted_type const px = -dy / length;
|
||||
promoted_type const py = dx / length;
|
||||
|
||||
promoted_type const d = distance.apply(input_p1, input_p2, side);
|
||||
if (geometry::math::equals(px, 0)
|
||||
&& geometry::math::equals(py, 0))
|
||||
{
|
||||
// This basically should not occur - because of the checks above.
|
||||
// There are no unit tests triggering this condition
|
||||
#ifdef BOOST_GEOMETRY_DEBUG_BUFFER_WARN
|
||||
std::cout << "Error in perpendicular calculation for points "
|
||||
<< geometry::wkt(input_p1) << " " << geometry::wkt(input_p2)
|
||||
<< " length: " << length
|
||||
<< " distance: " << d
|
||||
<< std::endl;
|
||||
#endif
|
||||
return result_no_output;
|
||||
}
|
||||
|
||||
output_range.resize(2);
|
||||
|
||||
@@ -104,6 +122,8 @@ public :
|
||||
set<1>(output_range.front(), get<1>(input_p1) + py * d);
|
||||
set<0>(output_range.back(), get<0>(input_p2) + px * d);
|
||||
set<1>(output_range.back(), get<1>(input_p2) + py * d);
|
||||
|
||||
return result_normal;
|
||||
}
|
||||
#endif // DOXYGEN_SHOULD_SKIP_THIS
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user