Merge pull request #754 from barendgehrels/fix/buffer-mp

Fix/buffer mp
This commit is contained in:
Barend Gehrels 2020-09-30 10:18:33 +02:00 committed by GitHub
commit a4b2e6195e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 161 additions and 103 deletions

View File

@ -198,6 +198,7 @@ struct piece_get_box
template <typename Box, typename Piece>
static inline void apply(Box& total, Piece const& piece)
{
assert_coordinate_type_equal(total, piece.m_piece_border.m_envelope);
typedef typename strategy::expand::services::default_strategy
<
box_tag, typename cs_tag<Box>::type
@ -212,11 +213,13 @@ struct piece_get_box
};
template <typename DisjointBoxBoxStrategy>
struct piece_ovelaps_box
struct piece_overlaps_box
{
template <typename Box, typename Piece>
static inline bool apply(Box const& box, Piece const& piece)
{
assert_coordinate_type_equal(box, piece.m_piece_border.m_envelope);
if (piece.type == strategy::buffer::buffered_flat_end
|| piece.type == strategy::buffer::buffered_concave)
{
@ -245,16 +248,18 @@ struct turn_get_box
<
point_tag, typename cs_tag<Box>::type
>::type expand_strategy_type;
assert_coordinate_type_equal(total, turn.point);
geometry::expand(total, turn.point, expand_strategy_type());
}
};
template <typename DisjointPointBoxStrategy>
struct turn_ovelaps_box
struct turn_overlaps_box
{
template <typename Box, typename Turn>
static inline bool apply(Box const& box, Turn const& turn)
{
assert_coordinate_type_equal(turn.point, box);
return ! geometry::detail::disjoint::disjoint_point_box(turn.point, box,
DisjointPointBoxStrategy());
}

View File

@ -272,10 +272,15 @@ struct buffered_piece_collection
buffered_ring_collection<Ring> traversed_rings;
segment_identifier current_segment_id;
// Specificly for offsetted rings around points
// but also for large joins with many points
typedef geometry::sections<box_type, 2> sections_type;
sections_type monotonic_sections;
// Monotonic sections (used for offsetted rings around points)
// are still using a robust type, to be comparable with turn calculations,
// which is using rescaling.
typedef geometry::model::box
<
typename geometry::robust_point_type<point_type, RobustPolicy>::type
> robust_box_type;
typedef geometry::sections <robust_box_type, 2> robust_sections_type;
robust_sections_type monotonic_sections;
// Define the clusters, mapping cluster_id -> turns
typedef std::map
@ -459,14 +464,14 @@ struct buffered_piece_collection
// Check if a turn is inside any of the originals
inline void check_turn_in_original()
{
typedef turn_in_original_ovelaps_box
typedef turn_in_original_overlaps_box
<
typename IntersectionStrategy::disjoint_point_box_strategy_type
> turn_in_original_ovelaps_box_type;
typedef original_ovelaps_box
> turn_in_original_overlaps_box_type;
typedef original_overlaps_box
<
typename IntersectionStrategy::disjoint_box_box_strategy_type
> original_ovelaps_box_type;
> original_overlaps_box_type;
turn_in_original_visitor
<
@ -480,8 +485,8 @@ struct buffered_piece_collection
include_turn_policy,
detail::partition::include_all_policy
>::apply(m_turns, original_rings, visitor,
turn_get_box(), turn_in_original_ovelaps_box_type(),
original_get_box(), original_ovelaps_box_type());
turn_get_box(), turn_in_original_overlaps_box_type(),
original_get_box(), original_overlaps_box_type());
bool const deflate = m_distance_strategy.negative();
@ -589,7 +594,7 @@ struct buffered_piece_collection
m_envelope_strategy);
geometry::partition
<
box_type
robust_box_type
>::apply(monotonic_sections, visitor,
get_section_box_type(),
overlaps_section_box_type());
@ -605,21 +610,21 @@ struct buffered_piece_collection
turn_vector_type, piece_vector_type, DistanceStrategy
> visitor(m_turns, m_pieces, m_distance_strategy);
typedef turn_ovelaps_box
typedef turn_overlaps_box
<
typename IntersectionStrategy::disjoint_point_box_strategy_type
> turn_ovelaps_box_type;
typedef piece_ovelaps_box
> turn_overlaps_box_type;
typedef piece_overlaps_box
<
typename IntersectionStrategy::disjoint_box_box_strategy_type
> piece_ovelaps_box_type;
> piece_overlaps_box_type;
geometry::partition
<
box_type
>::apply(m_turns, m_pieces, visitor,
turn_get_box(), turn_ovelaps_box_type(),
piece_get_box(), piece_ovelaps_box_type());
turn_get_box(), turn_overlaps_box_type(),
piece_get_box(), piece_overlaps_box_type());
}
}

View File

@ -149,6 +149,43 @@ class piece_turn_visitor
return ! m_rings[piece1.first_seg_id.multi_index].has_concave;
}
template <std::size_t Dimension, typename Iterator, typename Box>
inline void move_begin_iterator(Iterator& it_begin, Iterator it_beyond,
signed_size_type& index, int dir,
Box const& this_bounding_box,
Box const& other_bounding_box)
{
for(; it_begin != it_beyond
&& it_begin + 1 != it_beyond
&& detail::section::preceding<Dimension>(dir, *(it_begin + 1),
this_bounding_box,
other_bounding_box,
m_robust_policy);
++it_begin, index++)
{}
}
template <std::size_t Dimension, typename Iterator, typename Box>
inline void move_end_iterator(Iterator it_begin, Iterator& it_beyond,
int dir, Box const& this_bounding_box,
Box const& other_bounding_box)
{
while (it_beyond != it_begin
&& it_beyond - 1 != it_begin
&& it_beyond - 2 != it_begin)
{
if (detail::section::exceeding<Dimension>(dir, *(it_beyond - 2),
this_bounding_box, other_bounding_box, m_robust_policy))
{
--it_beyond;
}
else
{
return;
}
}
}
template <typename Piece, typename Section>
inline void calculate_turns(Piece const& piece1, Piece const& piece2,
Section const& section1, Section const& section2)
@ -181,10 +218,31 @@ class piece_turn_visitor
iterator it2_first = boost::begin(ring2) + sec2_first_index;
iterator it2_beyond = boost::begin(ring2) + sec2_last_index + 1;
// Set begin/end of monotonic ranges, in both x/y directions
signed_size_type index1 = sec1_first_index;
move_begin_iterator<0>(it1_first, it1_beyond, index1,
section1.directions[0], section1.bounding_box, section2.bounding_box);
move_end_iterator<0>(it1_first, it1_beyond,
section1.directions[0], section1.bounding_box, section2.bounding_box);
move_begin_iterator<1>(it1_first, it1_beyond, index1,
section1.directions[1], section1.bounding_box, section2.bounding_box);
move_end_iterator<1>(it1_first, it1_beyond,
section1.directions[1], section1.bounding_box, section2.bounding_box);
signed_size_type index2 = sec2_first_index;
move_begin_iterator<0>(it2_first, it2_beyond, index2,
section2.directions[0], section2.bounding_box, section1.bounding_box);
move_end_iterator<0>(it2_first, it2_beyond,
section2.directions[0], section2.bounding_box, section1.bounding_box);
move_begin_iterator<1>(it2_first, it2_beyond, index2,
section2.directions[1], section2.bounding_box, section1.bounding_box);
move_end_iterator<1>(it2_first, it2_beyond,
section2.directions[1], section2.bounding_box, section1.bounding_box);
turn_type the_model;
the_model.operations[0].piece_index = piece1.index;
the_model.operations[0].seg_id = piece1.first_seg_id;
the_model.operations[0].seg_id.segment_index = sec1_first_index; // override
the_model.operations[0].seg_id.segment_index = index1; // override
iterator it1 = it1_first;
for (iterator prev1 = it1++;
@ -193,7 +251,7 @@ class piece_turn_visitor
{
the_model.operations[1].piece_index = piece2.index;
the_model.operations[1].seg_id = piece2.first_seg_id;
the_model.operations[1].seg_id.segment_index = sec2_first_index; // override
the_model.operations[1].seg_id.segment_index = index2; // override
unique_sub_range_from_piece<ring_type> unique_sub_range1(ring1, prev1, it1);

View File

@ -15,6 +15,7 @@
#include <boost/core/ignore_unused.hpp>
#include <boost/geometry/core/coordinate_type.hpp>
#include <boost/geometry/algorithms/detail/buffer/buffer_policies.hpp>
#include <boost/geometry/algorithms/expand.hpp>
@ -35,6 +36,7 @@ struct original_get_box
template <typename Box, typename Original>
static inline void apply(Box& total, Original const& original)
{
assert_coordinate_type_equal(total, original.m_box);
typedef typename strategy::expand::services::default_strategy
<
box_tag, typename cs_tag<Box>::type
@ -45,11 +47,12 @@ struct original_get_box
};
template <typename DisjointBoxBoxStrategy>
struct original_ovelaps_box
struct original_overlaps_box
{
template <typename Box, typename Original>
static inline bool apply(Box const& box, Original const& original)
{
assert_coordinate_type_equal(box, original.m_box);
return ! detail::disjoint::disjoint_box_box(box, original.m_box,
DisjointBoxBoxStrategy());
}
@ -65,7 +68,7 @@ struct include_turn_policy
};
template <typename DisjointPointBoxStrategy>
struct turn_in_original_ovelaps_box
struct turn_in_original_overlaps_box
{
template <typename Box, typename Turn>
static inline bool apply(Box const& box, Turn const& turn)

View File

@ -16,6 +16,7 @@
#include <boost/range.hpp>
#include <boost/geometry/core/coordinate_type.hpp>
#include <boost/geometry/algorithms/envelope.hpp>
#include <boost/geometry/algorithms/expand.hpp>
#include <boost/geometry/algorithms/detail/partition.hpp>
@ -131,16 +132,18 @@ struct ring_info_helper_get_box
template <typename Box, typename InputItem>
static inline void apply(Box& total, InputItem const& item)
{
assert_coordinate_type_equal(total, item.envelope);
geometry::expand(total, item.envelope, BoxExpandStrategy());
}
};
template <typename DisjointBoxBoxStrategy>
struct ring_info_helper_ovelaps_box
struct ring_info_helper_overlaps_box
{
template <typename Box, typename InputItem>
static inline bool apply(Box const& box, InputItem const& item)
{
assert_coordinate_type_equal(box, item.envelope);
return ! geometry::detail::disjoint::disjoint_box_box(
box, item.envelope, DisjointBoxBoxStrategy());
}
@ -336,7 +339,7 @@ inline void assign_parents(Geometry1 const& geometry1,
<
typename Strategy::expand_box_strategy_type
> expand_box_type;
typedef ring_info_helper_ovelaps_box
typedef ring_info_helper_overlaps_box
<
typename Strategy::disjoint_box_box_strategy_type
> overlaps_box_type;

View File

@ -35,51 +35,27 @@ struct distance_measure
: measure(T())
{}
bool is_small() const { return false; }
bool is_zero() const { return false; }
bool is_positive() const { return false; }
bool is_negative() const { return false; }
};
template <typename T>
struct distance_measure_floating
{
T measure;
distance_measure_floating()
: measure(T())
{}
// Returns true if the distance measure is small.
// This is an arbitrary boundary, to enable some behaviour
// (for example include or exclude turns), which are checked later
// with other conditions.
bool is_small() const { return std::abs(measure) < 1.0e-3; }
bool is_small() const { return geometry::math::abs(measure) < 1.0e-3; }
// Returns true if the distance measure is absolutely zero
bool is_zero() const { return measure == 0.0; }
bool is_zero() const
{
return ! is_positive() && ! is_negative();
}
// Returns true if the distance measure is positive. Distance measure
// algorithm returns positive value if it is located on the left side.
bool is_positive() const { return measure > 0.0; }
bool is_positive() const { return measure > T(0); }
// Returns true if the distance measure is negative. Distance measure
// algorithm returns negative value if it is located on the right side.
bool is_negative() const { return measure < 0.0; }
bool is_negative() const { return measure < T(0); }
};
template <>
struct distance_measure<long double>
: public distance_measure_floating<long double> {};
template <>
struct distance_measure<double>
: public distance_measure_floating<double> {};
template <>
struct distance_measure<float>
: public distance_measure_floating<float> {};
} // detail

View File

@ -14,6 +14,7 @@
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_SECTIONS_SECTION_BOX_POLICIES_HPP
#include <boost/geometry/core/coordinate_type.hpp>
#include <boost/geometry/algorithms/detail/disjoint/box_box.hpp>
#include <boost/geometry/algorithms/expand.hpp>
@ -31,6 +32,7 @@ struct get_section_box
template <typename Box, typename Section>
static inline void apply(Box& total, Section const& section)
{
assert_coordinate_type_equal(total, section.bounding_box);
geometry::expand(total, section.bounding_box,
ExpandBoxStrategy());
}
@ -42,6 +44,7 @@ struct overlaps_section_box
template <typename Box, typename Section>
static inline bool apply(Box const& box, Section const& section)
{
assert_coordinate_type_equal(box, section.bounding_box);
return ! detail::disjoint::disjoint_box_box(box, section.bounding_box,
DisjointBoxBoxStrategy());
}

View File

@ -14,9 +14,8 @@
#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_SECTIONS_FUNCTIONS_HPP
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_SECTIONS_FUNCTIONS_HPP
#include <boost/static_assert.hpp>
#include <boost/geometry/core/access.hpp>
#include <boost/geometry/core/coordinate_type.hpp>
#include <boost/geometry/algorithms/detail/recalculate.hpp>
#include <boost/geometry/policies/robustness/robust_point_type.hpp>
@ -123,41 +122,38 @@ template
<
std::size_t Dimension,
typename Point,
typename RobustBox,
typename Box,
typename RobustPolicy
>
static inline bool preceding(int dir,
Point const& point,
RobustBox const& point_robust_box,
RobustBox const& other_robust_box,
Box const& point_box,
Box const& other_box,
RobustPolicy const& robust_policy)
{
typedef typename geometry::robust_point_type<Point, RobustPolicy>::type robust_point_type;
BOOST_STATIC_ASSERT((boost::is_same
<
typename geometry::coordinate_type<robust_point_type>::type,
typename geometry::coordinate_type<RobustBox>::type
>::value));
robust_point_type robust_point;
typename geometry::robust_point_type<Point, RobustPolicy>::type robust_point;
assert_coordinate_type_equal(robust_point, point_box);
geometry::recalculate(robust_point, point, robust_policy);
return preceding_check<Dimension, Point>::apply(dir, robust_point, point_robust_box, other_robust_box);
return preceding_check<Dimension, Box>::apply(dir, robust_point,
point_box,
other_box);
}
template
<
std::size_t Dimension,
typename Point,
typename RobustBox,
typename Box,
typename RobustPolicy
>
static inline bool exceeding(int dir,
Point const& point,
RobustBox const& point_robust_box,
RobustBox const& other_robust_box,
Box const& point_box,
Box const& other_box,
RobustPolicy const& robust_policy)
{
return preceding<Dimension>(-dir, point, point_robust_box, other_robust_box, robust_policy);
return preceding<Dimension>(-dir, point, point_box, other_box, robust_policy);
}

View File

@ -101,6 +101,19 @@ struct fp_coordinate_type
>::type type;
};
/*!
\brief assert_coordinate_type_equal, a compile-time check for equality of two coordinate types
\ingroup utility
*/
template <typename Geometry1, typename Geometry2>
constexpr inline void assert_coordinate_type_equal(Geometry1 const& , Geometry2 const& )
{
static_assert(std::is_same
<
typename coordinate_type<Geometry1>::type,
typename coordinate_type<Geometry2>::type
>::value, "Coordinate types in geometries should be the same");
}
}} // namespace boost::geometry

View File

@ -1,7 +1,7 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// Robustness Test
//
// Copyright (c) 2009-2012 Barend Gehrels, Amsterdam, the Netherlands.
// Copyright (c) 2009-2020 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)
@ -11,22 +11,15 @@
struct common_settings
{
bool svg;
bool wkt;
bool also_difference;
double tolerance;
bool svg{false};
bool wkt{false};
bool also_difference{false};
double tolerance{1.0e-6};
int field_size;
bool triangular;
int field_size{10};
bool triangular{false};
common_settings()
: svg(false)
, wkt(false)
, also_difference(false)
, tolerance(1.0e-6)
, field_size(10)
, triangular(false)
{}
bool check_validity{true};
};
#endif // BOOST_GEOMETRY_COMMON_SETTINGS_HPP

View File

@ -22,13 +22,14 @@
#include <fstream>
#include <sstream>
#include <chrono>
#include <boost/foreach.hpp>
#include <boost/program_options.hpp>
#include <boost/random/linear_congruential.hpp>
#include <boost/random/uniform_int.hpp>
#include <boost/random/uniform_real.hpp>
#include <boost/random/variate_generator.hpp>
#include <boost/timer.hpp>
#include <boost/geometry.hpp>
#include <boost/geometry/geometries/geometries.hpp>
@ -113,7 +114,7 @@ bool verify(std::string const& caseid, MultiPolygon const& mp, MultiPolygon cons
}
}
if (result)
if (result && settings.check_validity)
{
bg::validity_failure_type failure;
if (! bg::is_valid(buffer, failure)
@ -128,18 +129,11 @@ bool verify(std::string const& caseid, MultiPolygon const& mp, MultiPolygon cons
bool wkt = settings.wkt;
if (! result)
{
std::cout << "ERROR " << caseid << std::endl;
//std::cout << bg::wkt(mp) << std::endl;
//std::cout << bg::wkt(buffer) << std::endl;
// The result is wrong, override settings to create a SVG and WKT
svg = true;
wkt = true;
}
if (svg || wkt)
{
//std::cout << caseid << std::endl;
}
if (svg)
{
std::ostringstream filename;
@ -257,7 +251,7 @@ bool test_buffer(MultiPolygon& result, int& index,
template <typename T, bool Clockwise, bool Closed, typename Settings>
void test_all(int seed, int count, int level, Settings const& settings)
{
boost::timer t;
auto const t0 = std::chrono::high_resolution_clock::now();
typedef boost::minstd_rand base_generator_type;
@ -275,15 +269,23 @@ void test_all(int seed, int count, int level, Settings const& settings)
int index = 0;
int errors = 0;
for(int i = 0; i < count; i++)
{
mp p;
test_buffer<mp>(p, index, coordinate_generator, level, settings);
if (! test_buffer<mp>(p, index, coordinate_generator, level, settings))
{
errors++;
}
}
auto const t = std::chrono::high_resolution_clock::now();
auto const elapsed_ms = std::chrono::duration_cast<std::chrono::milliseconds>(t - t0).count();
std::cout
<< "geometries: " << index
<< " errors: " << errors
<< " type: " << typeid(T).name()
<< " time: " << t.elapsed() << std::endl;
<< " time: " << elapsed_ms / 1000.0 << std::endl;
}
int main(int argc, char** argv)
@ -292,7 +294,7 @@ int main(int argc, char** argv)
try
{
namespace po = boost::program_options;
po::options_description description("=== recursive_polygons_linear_areal ===\nAllowed options");
po::options_description description("=== recursive_polygons_buffer ===\nAllowed options");
int count = 1;
int seed = static_cast<unsigned int>(std::time(0));
@ -316,6 +318,7 @@ int main(int argc, char** argv)
("size", po::value<int>(&settings.field_size)->default_value(10), "Size of the field")
("wkt", po::value<bool>(&settings.wkt)->default_value(false), "Create a WKT of the inputs, for all tests")
("svg", po::value<bool>(&settings.svg)->default_value(false), "Create a SVG for all tests")
("check_validity", po::value<bool>(&settings.check_validity)->default_value(true), "Check validity")
;
po::variables_map varmap;