[dissolve] fix cases where turns were missed because 1) they were on adjacent

segments and 2) vertical segments were not sectionalized properly for this purpose.
This commit is contained in:
Barend Gehrels 2017-10-20 12:48:13 +02:00
parent aa6778e83c
commit 13a8d13cb6
8 changed files with 63 additions and 41 deletions

View File

@ -533,8 +533,7 @@ void test_all()
TEST_DISSOLVE(dissolve_mail_2017_09_24_b, 16.0, 1, 0, 6);
TEST_DISSOLVE(dissolve_mail_2017_09_24_c, 0.5, 2, 0, 8);
TEST_DISSOLVE_IGNORE(dissolve_mail_2017_09_24_d, 0.5, 1, 0, 5);
TEST_DISSOLVE(dissolve_mail_2017_09_24_d, 0.5, 1, 0, 5);
TEST_DISSOLVE(dissolve_mail_2017_09_24_e, 0.001801138128, 5, 0, 69);
TEST_DISSOLVE(dissolve_mail_2017_09_24_f, 0.000361308800, 5, 0, 69);

View File

@ -81,7 +81,11 @@ inline bool has_self_intersections(Geometry const& geometry,
std::deque<turn_info> turns;
detail::disjoint::disjoint_interrupt_policy policy;
detail::self_get_turn_points::self_turns<false, detail::overlay::assign_null_policy>(geometry, strategy, robust_policy, turns, policy);
detail::self_get_turn_points::self_turns
<
false,
detail::overlay::assign_null_policy
>(geometry, strategy, robust_policy, turns, policy, 0, false);
#ifdef BOOST_GEOMETRY_DEBUG_HAS_SELF_INTERSECTIONS
bool first = true;

View File

@ -72,10 +72,11 @@ struct self_intersects
rescale_policy_type robust_policy;
detail::disjoint::disjoint_interrupt_policy policy;
// TODO: skip_adjacent should be set to false
detail::self_get_turn_points::get_turns
<
false, turn_policy
>::apply(geometry, strategy, robust_policy, turns, policy, 0);
>::apply(geometry, strategy, robust_policy, turns, policy, 0, true);
return policy.has_intersections;
}
};

View File

@ -217,6 +217,7 @@ inline bool has_self_intersections(Linear const& linear, Strategy const& strateg
is_acceptable_turn<Linear>
> interrupt_policy(predicate);
// TODO: skip_adjacent should be set to false
detail::self_get_turn_points::get_turns
<
false, turn_policy
@ -224,7 +225,7 @@ inline bool has_self_intersections(Linear const& linear, Strategy const& strateg
strategy,
detail::no_rescale_policy(),
turns,
interrupt_policy, 0);
interrupt_policy, 0, true);
detail::is_valid::debug_print_turns(turns.begin(), turns.end());
debug_print_boundary_points(linear);

View File

@ -144,7 +144,7 @@ class get_turns_in_sections
template <typename Geometry, typename Section>
static inline bool neighbouring(Section const& section,
static inline bool adjacent(Section const& section,
signed_size_type index1, signed_size_type index2)
{
// About n-2:
@ -152,7 +152,7 @@ class get_turns_in_sections
// -> 0-3 are adjacent, don't check on intersections)
// Also tested for open polygons, and/or duplicates
// About first condition: will be optimized by compiler (static)
// It checks if it is areal (box,ring,(multi)polygon
// It checks if it is areal (box, ring, (multi)polygon)
signed_size_type const n = static_cast<signed_size_type>(section.range_count);
boost::ignore_unused_variable_warning(n);
@ -180,7 +180,7 @@ public :
static inline bool apply(
int source_id1, Geometry1 const& geometry1, Section1 const& sec1,
int source_id2, Geometry2 const& geometry2, Section2 const& sec2,
bool skip_larger,
bool skip_larger, bool skip_adjacent,
IntersectionStrategy const& intersection_strategy,
RobustPolicy const& robust_policy,
Turns& turns,
@ -214,11 +214,6 @@ public :
signed_size_type index1 = sec1.begin_index;
signed_size_type ndi1 = sec1.non_duplicate_index;
bool const same_source =
source_id1 == source_id2
&& sec1.ring_id.multi_index == sec2.ring_id.multi_index
&& sec1.ring_id.ring_index == sec2.ring_id.ring_index;
range1_iterator prev1, it1, end1;
get_start_point_iterator(sec1, view1, prev1, it1, end1,
@ -254,22 +249,32 @@ public :
it2 != end2 && ! detail::section::exceeding<0>(dir2, *prev2, sec2.bounding_box, sec1.bounding_box, robust_policy);
++prev2, ++it2, ++index2, ++next2, ++ndi2)
{
bool skip = same_source;
if (skip)
bool skip = false;
if (source_id1 == source_id2
&& sec1.ring_id.multi_index == sec2.ring_id.multi_index
&& sec1.ring_id.ring_index == sec2.ring_id.ring_index)
{
// If sources are the same (possibly self-intersecting):
// skip if it is a neighbouring segment.
// (including first-last segment
// and two segments with one or more degenerate/duplicate
// (zero-length) segments in between)
// Sources and rings are the same
// Also skip if index1 < index2 to avoid getting all
// intersections twice (only do this on same source!)
if (skip_larger && index1 >= index2)
{
// Skip to avoid getting all intersections twice
skip = true;
}
else if (skip_adjacent)
{
// In some cases (dissolve, has_self_intersections)
// neighbouring segments should be checked
// (for example to detect spikes properly)
skip = (skip_larger && index1 >= index2)
|| ndi2 == ndi1 + 1
|| neighbouring<Geometry1>(sec1, index1, index2)
;
// skip if it is a neighbouring segment.
// (including, for areas, first-last segment
// and two segments with one or more degenerate/duplicate
// (zero-length) segments in between)
skip = ndi2 == ndi1 + 1
|| adjacent<Geometry1>(sec1, index1, index2);
}
}
if (! skip)
@ -431,7 +436,7 @@ struct section_visitor
TurnPolicy
>::apply(m_source_id1, m_geometry1, sec1,
m_source_id2, m_geometry2, sec2,
false,
false, false,
m_intersection_strategy,
m_rescale_policy,
m_turns, m_interrupt_policy);

View File

@ -78,19 +78,22 @@ struct self_section_visitor
Turns& m_turns;
InterruptPolicy& m_interrupt_policy;
std::size_t m_source_index;
bool m_skip_adjacent;
inline self_section_visitor(Geometry const& g,
IntersectionStrategy const& is,
RobustPolicy const& rp,
Turns& turns,
InterruptPolicy& ip,
std::size_t source_index)
std::size_t source_index,
bool skip_adjacent)
: m_geometry(g)
, m_intersection_strategy(is)
, m_rescale_policy(rp)
, m_turns(turns)
, m_interrupt_policy(ip)
, m_source_index(source_index)
, m_skip_adjacent(skip_adjacent)
{}
template <typename Section>
@ -109,7 +112,7 @@ struct self_section_visitor
TurnPolicy
>::apply(m_source_index, m_geometry, sec1,
m_source_index, m_geometry, sec2,
false,
false, m_skip_adjacent,
m_intersection_strategy,
m_rescale_policy,
m_turns, m_interrupt_policy);
@ -132,7 +135,7 @@ struct get_turns
RobustPolicy const& robust_policy,
Turns& turns,
InterruptPolicy& interrupt_policy,
std::size_t source_index)
std::size_t source_index, bool skip_adjacent)
{
typedef model::box
<
@ -143,9 +146,11 @@ struct get_turns
>::type
> box_type;
typedef geometry::sections<box_type, 1> sections_type;
// sectionalize in two dimensions to detect
// all potential spikes correctly
typedef geometry::sections<box_type, 2> sections_type;
typedef boost::mpl::vector_c<std::size_t, 0> dimensions;
typedef boost::mpl::vector_c<std::size_t, 0, 1> dimensions;
sections_type sec;
geometry::sectionalize<Reverse, dimensions>(geometry, robust_policy, sec,
@ -155,7 +160,7 @@ struct get_turns
<
Reverse, Geometry,
Turns, TurnPolicy, IntersectionStrategy, RobustPolicy, InterruptPolicy
> visitor(geometry, intersection_strategy, robust_policy, turns, interrupt_policy, source_index);
> visitor(geometry, intersection_strategy, robust_policy, turns, interrupt_policy, source_index, skip_adjacent);
// false if interrupted
geometry::partition
@ -224,7 +229,8 @@ struct self_get_turn_points
RobustPolicy const& ,
Turns& ,
InterruptPolicy& ,
std::size_t)
std::size_t /*source_index*/,
bool /*skip_adjacent*/)
{
return true;
}
@ -286,7 +292,8 @@ inline void self_turns(Geometry const& geometry,
RobustPolicy const& robust_policy,
Turns& turns,
InterruptPolicy& interrupt_policy,
std::size_t source_index = 0)
std::size_t source_index = 0,
bool skip_adjacent = false)
{
concepts::check<Geometry const>();
@ -298,7 +305,8 @@ inline void self_turns(Geometry const& geometry,
typename tag<Geometry>::type,
Geometry,
turn_policy
>::apply(geometry, strategy, robust_policy, turns, interrupt_policy, source_index);
>::apply(geometry, strategy, robust_policy, turns, interrupt_policy,
source_index, skip_adjacent);
}
}} // namespace detail::self_get_turn_points
@ -331,7 +339,8 @@ inline void self_turns(Geometry const& geometry,
RobustPolicy const& robust_policy,
Turns& turns,
InterruptPolicy& interrupt_policy,
std::size_t source_index = 0)
std::size_t source_index = 0,
bool skip_adjacent = false)
{
concepts::check<Geometry const>();
@ -344,7 +353,8 @@ inline void self_turns(Geometry const& geometry,
<
reverse,
AssignPolicy
>(geometry, strategy, robust_policy, turns, interrupt_policy, source_index);
>(geometry, strategy, robust_policy, turns, interrupt_policy,
source_index, skip_adjacent);
}

View File

@ -413,7 +413,8 @@ struct touches<Areal1, Areal2, ring_tag, ring_tag, areal_tag, areal_tag, false>
#endif // DOXYGEN_NO_DISPATCH
namespace resolve_variant {
namespace resolve_variant
{
template <typename Geometry>
struct self_touches
@ -443,10 +444,11 @@ struct self_touches
detail::touches::areal_interrupt_policy policy;
strategy_type strategy;
rescale_policy_type robust_policy;
// TODO: skip_adjacent should be set to false
detail::self_get_turn_points::get_turns
<
false, policy_type
>::apply(geometry, strategy, robust_policy, turns, policy, 0);
>::apply(geometry, strategy, robust_policy, turns, policy, 0, true);
return policy.result();
}

View File

@ -160,7 +160,7 @@ struct dissolve_ring_or_polygon
geometry::self_turns
<
detail::overlay::assign_null_policy
>(geometry, strategy, rescale_policy, turns, policy);
>(geometry, strategy, rescale_policy, turns, policy, 0, false);
visitor.visit_turns(1, turns);