mirror of
https://github.com/boostorg/geometry.git
synced 2025-05-11 13:34:10 +00:00
[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:
parent
aa6778e83c
commit
13a8d13cb6
@ -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);
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
};
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
@ -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();
|
||||
}
|
||||
|
@ -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);
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user