mirror of
https://github.com/boostorg/geometry.git
synced 2025-05-11 21:44:04 +00:00
Merge branch 'feature/intvalid' into develop
# Conflicts: # include/boost/geometry/algorithms/intersects.hpp # include/boost/geometry/algorithms/touches.hpp
This commit is contained in:
commit
60c9b096b1
@ -81,7 +81,7 @@ inline bool has_self_intersections(Geometry const& geometry,
|
||||
std::deque<turn_info> turns;
|
||||
detail::disjoint::disjoint_interrupt_policy policy;
|
||||
|
||||
geometry::self_turns<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);
|
||||
|
||||
#ifdef BOOST_GEOMETRY_DEBUG_HAS_SELF_INTERSECTIONS
|
||||
bool first = true;
|
||||
|
@ -74,7 +74,7 @@ struct self_intersects
|
||||
detail::disjoint::disjoint_interrupt_policy policy;
|
||||
detail::self_get_turn_points::get_turns
|
||||
<
|
||||
turn_policy
|
||||
false, turn_policy
|
||||
>::apply(geometry, strategy, robust_policy, turns, policy, 0);
|
||||
return policy.has_intersections;
|
||||
}
|
||||
|
@ -219,7 +219,7 @@ inline bool has_self_intersections(Linear const& linear, Strategy const& strateg
|
||||
|
||||
detail::self_get_turn_points::get_turns
|
||||
<
|
||||
turn_policy
|
||||
false, turn_policy
|
||||
>::apply(linear,
|
||||
strategy,
|
||||
detail::no_rescale_policy(),
|
||||
|
@ -86,7 +86,7 @@ public:
|
||||
IsAcceptableTurn
|
||||
> interrupt_policy;
|
||||
|
||||
geometry::self_turns<turn_policy>(geometry,
|
||||
detail::self_get_turn_points::self_turns<false, turn_policy>(geometry,
|
||||
strategy,
|
||||
robust_policy,
|
||||
turns,
|
||||
|
@ -125,6 +125,34 @@ private:
|
||||
typedef typename boost::range_value<MultiPolygon>::type polygon;
|
||||
typedef is_acceptable_turn<polygon> base;
|
||||
|
||||
template <typename Operation>
|
||||
static inline
|
||||
bool check_int_ext(Operation const& op1,
|
||||
detail::overlay::operation_type optype1,
|
||||
Operation const& op2,
|
||||
detail::overlay::operation_type optype2)
|
||||
{
|
||||
// u/i is acceptable for touch of interior ring with another exterior ring
|
||||
// (but only if there is a colocated uu-turn of its exterior, TODO)
|
||||
return op1.seg_id.ring_index == -1
|
||||
&& op2.seg_id.ring_index >= 0
|
||||
&& op1.operation == optype1
|
||||
&& op2.operation == optype2;
|
||||
}
|
||||
|
||||
template <typename Operation>
|
||||
static inline
|
||||
bool check_int_int(Operation const& op1,
|
||||
Operation const& op2,
|
||||
detail::overlay::operation_type optype)
|
||||
{
|
||||
// i/i is acceptable for touching interior/interior rings
|
||||
return op1.seg_id.ring_index >= 0
|
||||
&& op2.seg_id.ring_index >= 0
|
||||
&& op1.operation == optype
|
||||
&& op2.operation == optype;
|
||||
}
|
||||
|
||||
public:
|
||||
template <typename Turn>
|
||||
static inline bool apply(Turn const& turn)
|
||||
@ -138,10 +166,32 @@ public:
|
||||
}
|
||||
|
||||
operation_type const op = acceptable_operation<MultiPolygon>::value;
|
||||
if ( base::check_turn(turn, method_touch_interior, op)
|
||||
|| base::check_turn(turn, method_touch, op))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return base::check_turn(turn, method_touch_interior, op)
|
||||
|| base::check_turn(turn, method_touch, op)
|
||||
;
|
||||
if (turn.method != method_touch)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
operation_type const reverse_op
|
||||
= op == operation_union
|
||||
? operation_intersection
|
||||
: operation_union;
|
||||
|
||||
if ( check_int_int(turn.operations[0], turn.operations[1], reverse_op)
|
||||
|| check_int_ext(turn.operations[0], reverse_op,
|
||||
turn.operations[1], op)
|
||||
|| check_int_ext(turn.operations[1], reverse_op,
|
||||
turn.operations[0], op))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -27,6 +27,9 @@ struct ring_with_direction
|
||||
|
||||
std::size_t turn_index;
|
||||
int operation_index;
|
||||
operation_type operation;
|
||||
signed_size_type region_id;
|
||||
bool isolated;
|
||||
|
||||
inline bool operator<(ring_with_direction const& other) const
|
||||
{
|
||||
@ -39,6 +42,9 @@ struct ring_with_direction
|
||||
: direction(dir_unknown)
|
||||
, turn_index(-1)
|
||||
, operation_index(0)
|
||||
, operation(operation_none)
|
||||
, region_id(-1)
|
||||
, isolated(false)
|
||||
{}
|
||||
};
|
||||
|
||||
@ -75,6 +81,89 @@ struct rank_with_rings
|
||||
return all_equal(sort_by_side::dir_from);
|
||||
}
|
||||
|
||||
inline bool has_only(operation_type op) const
|
||||
{
|
||||
for (std::set<ring_with_direction>::const_iterator it = rings.begin();
|
||||
it != rings.end(); ++it)
|
||||
{
|
||||
const ring_with_direction& rwd = *it;
|
||||
if (rwd.operation != op)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
//! Check if set has both op1 and op2, but no others
|
||||
inline bool has_only_both(operation_type op1, operation_type op2) const
|
||||
{
|
||||
bool has1 = false;
|
||||
bool has2 = false;
|
||||
for (std::set<ring_with_direction>::const_iterator it = rings.begin();
|
||||
it != rings.end(); ++it)
|
||||
{
|
||||
const ring_with_direction& rwd = *it;
|
||||
|
||||
if (rwd.operation == op1) { has1 = true; }
|
||||
else if (rwd.operation == op2) { has2 = true; }
|
||||
else { return false; }
|
||||
}
|
||||
return has1 && has2;
|
||||
}
|
||||
|
||||
inline bool is_isolated() const
|
||||
{
|
||||
for (std::set<ring_with_direction>::const_iterator it = rings.begin();
|
||||
it != rings.end(); ++it)
|
||||
{
|
||||
const ring_with_direction& rwd = *it;
|
||||
if (! rwd.isolated)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
inline bool has_unique_region_id() const
|
||||
{
|
||||
int region_id = -1;
|
||||
for (std::set<ring_with_direction>::const_iterator it = rings.begin();
|
||||
it != rings.end(); ++it)
|
||||
{
|
||||
const ring_with_direction& rwd = *it;
|
||||
if (region_id == -1)
|
||||
{
|
||||
region_id = rwd.region_id;
|
||||
}
|
||||
else if (rwd.region_id != region_id)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
inline int region_id() const
|
||||
{
|
||||
int region_id = -1;
|
||||
for (std::set<ring_with_direction>::const_iterator it = rings.begin();
|
||||
it != rings.end(); ++it)
|
||||
{
|
||||
const ring_with_direction& rwd = *it;
|
||||
if (region_id == -1)
|
||||
{
|
||||
region_id = rwd.region_id;
|
||||
}
|
||||
else if (rwd.region_id != region_id)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
return region_id;
|
||||
}
|
||||
|
||||
template <typename Turns>
|
||||
inline bool traversable(Turns const& turns) const
|
||||
{
|
||||
@ -87,7 +176,13 @@ struct rank_with_rings
|
||||
const ring_with_direction& rwd = *it;
|
||||
turn_type const& turn = turns[rwd.turn_index];
|
||||
turn_operation_type const& op = turn.operations[rwd.operation_index];
|
||||
if (op.visited.finalized())
|
||||
|
||||
// TODO: this is still necessary, but makes it order-dependent
|
||||
// which should not be done.
|
||||
|
||||
// This would obsolete the whole function and should be solved
|
||||
// in a different way
|
||||
if (op.visited.finalized() || op.visited.visited())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
@ -99,7 +194,8 @@ struct rank_with_rings
|
||||
|
||||
template <typename Sbs, typename Turns>
|
||||
inline void aggregate_operations(Sbs const& sbs, std::vector<rank_with_rings>& aggregation,
|
||||
Turns const& turns)
|
||||
Turns const& turns,
|
||||
operation_type target_operation)
|
||||
{
|
||||
typedef typename boost::range_value<Turns>::type turn_type;
|
||||
typedef typename turn_type::turn_operation_type turn_operation_type;
|
||||
@ -113,9 +209,14 @@ inline void aggregate_operations(Sbs const& sbs, std::vector<rank_with_rings>& a
|
||||
|
||||
turn_operation_type const& op = turn.operations[ranked_point.operation_index];
|
||||
|
||||
if (! (op.operation == operation_intersection || op.operation == operation_continue))
|
||||
if (! ((target_operation == operation_union && ranked_point.rank == 0)
|
||||
|| op.operation == target_operation
|
||||
|| op.operation == operation_continue
|
||||
|| (op.operation == operation_blocked && ranked_point.direction == dir_from)))
|
||||
{
|
||||
// Always take rank 0 (because self-turns are blocked)
|
||||
// Don't consider union/blocked (aggregate is only used for intersections)
|
||||
// Blocked is allowed for from
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -133,6 +234,9 @@ inline void aggregate_operations(Sbs const& sbs, std::vector<rank_with_rings>& a
|
||||
rwd.direction = ranked_point.direction;
|
||||
rwd.turn_index = ranked_point.turn_index;
|
||||
rwd.operation_index = ranked_point.operation_index;
|
||||
rwd.operation = op.operation;
|
||||
rwd.region_id = op.enriched.region_id;
|
||||
rwd.isolated = op.enriched.isolated;
|
||||
|
||||
aggregation.back().rings.insert(rwd);
|
||||
}
|
||||
|
@ -26,15 +26,14 @@
|
||||
|
||||
#include <boost/range.hpp>
|
||||
|
||||
#include <boost/geometry/iterators/ever_circling_iterator.hpp>
|
||||
#include <boost/geometry/algorithms/detail/ring_identifier.hpp>
|
||||
#include <boost/geometry/algorithms/detail/overlay/copy_segment_point.hpp>
|
||||
#include <boost/geometry/algorithms/detail/overlay/handle_colocations.hpp>
|
||||
#include <boost/geometry/algorithms/detail/overlay/handle_self_turns.hpp>
|
||||
#include <boost/geometry/algorithms/detail/overlay/is_self_turn.hpp>
|
||||
#include <boost/geometry/algorithms/detail/overlay/less_by_segment_ratio.hpp>
|
||||
#include <boost/geometry/algorithms/detail/overlay/overlay_type.hpp>
|
||||
#include <boost/geometry/algorithms/detail/overlay/sort_by_side.hpp>
|
||||
#include <boost/geometry/policies/robustness/robust_type.hpp>
|
||||
#include <boost/geometry/strategies/side.hpp>
|
||||
|
||||
#ifdef BOOST_GEOMETRY_DEBUG_ENRICH
|
||||
# include <boost/geometry/algorithms/detail/overlay/check_enrich.hpp>
|
||||
#endif
|
||||
@ -173,9 +172,7 @@ inline void enrich_assign(Operations& operations, Turns& turns)
|
||||
|
||||
|
||||
template <typename Turns, typename MappedVector>
|
||||
inline void create_map(Turns const& turns,
|
||||
detail::overlay::operation_type for_operation,
|
||||
MappedVector& mapped_vector)
|
||||
inline void create_map(Turns const& turns, MappedVector& mapped_vector)
|
||||
{
|
||||
typedef typename boost::range_value<Turns>::type turn_type;
|
||||
typedef typename turn_type::container_type container_type;
|
||||
@ -268,6 +265,7 @@ inline void calculate_remaining_distance(Turns& turns)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}} // namespace detail::overlay
|
||||
#endif //DOXYGEN_NO_DETAIL
|
||||
|
||||
@ -305,8 +303,13 @@ inline void enrich_intersection_points(Turns& turns,
|
||||
RobustPolicy const& robust_policy,
|
||||
Strategy const& strategy)
|
||||
{
|
||||
static const detail::overlay::operation_type for_operation
|
||||
static const detail::overlay::operation_type target_operation
|
||||
= detail::overlay::operation_from_overlay<OverlayType>::value;
|
||||
static const detail::overlay::operation_type opposite_operation
|
||||
= target_operation == detail::overlay::operation_union
|
||||
? detail::overlay::operation_intersection
|
||||
: detail::overlay::operation_union;
|
||||
|
||||
typedef typename boost::range_value<Turns>::type turn_type;
|
||||
typedef typename turn_type::turn_operation_type op_type;
|
||||
typedef detail::overlay::indexed_turn_operation
|
||||
@ -332,34 +335,31 @@ inline void enrich_intersection_points(Turns& turns,
|
||||
++it)
|
||||
{
|
||||
turn_type& turn = *it;
|
||||
|
||||
if (turn.both(detail::overlay::operation_none))
|
||||
{
|
||||
turn.discarded = true;
|
||||
continue;
|
||||
}
|
||||
if (for_operation == detail::overlay::operation_intersection
|
||||
&& turn.both(detail::overlay::operation_union))
|
||||
|
||||
if (turn.both(opposite_operation))
|
||||
{
|
||||
// For intersections, remove uu to avoid the need to travel
|
||||
// a union (during intersection) in uu/cc clusters (e.g. #31,#32,#33)
|
||||
turn.discarded = true;
|
||||
turn.cluster_id = -1;
|
||||
}
|
||||
|
||||
if (for_operation == detail::overlay::operation_union
|
||||
&& turn.both(detail::overlay::operation_intersection))
|
||||
{
|
||||
// Also, for union, discard ii
|
||||
turn.discarded = true;
|
||||
turn.cluster_id = -1;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (OverlayType != overlay_buffer
|
||||
&& turn.cluster_id >= 0
|
||||
&& turn.self_turn())
|
||||
if (detail::overlay::is_self_turn<OverlayType>(turn)
|
||||
&& turn.cluster_id < 0
|
||||
&& ! turn.both(target_operation))
|
||||
{
|
||||
// Avoid interfering self-turn if there are already clustered turns
|
||||
// TODO: avoid discarding if there are ONLY self-turns
|
||||
// Only keep self-uu-turns or self-ii-turns
|
||||
turn.discarded = true;
|
||||
turn.cluster_id = -1;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (! turn.discarded
|
||||
@ -369,11 +369,22 @@ inline void enrich_intersection_points(Turns& turns,
|
||||
}
|
||||
}
|
||||
|
||||
detail::overlay::discard_closed_turns
|
||||
<
|
||||
OverlayType,
|
||||
target_operation
|
||||
>::apply(turns, geometry1, geometry2);
|
||||
detail::overlay::discard_open_turns
|
||||
<
|
||||
OverlayType,
|
||||
target_operation
|
||||
>::apply(turns, geometry1, geometry2);
|
||||
|
||||
// Create a map of vectors of indexed operation-types to be able
|
||||
// to sort intersection points PER RING
|
||||
mapped_vector_type mapped_vector;
|
||||
|
||||
detail::overlay::create_map(turns, for_operation, mapped_vector);
|
||||
detail::overlay::create_map(turns, mapped_vector);
|
||||
|
||||
// No const-iterator; contents of mapped copy is temporary,
|
||||
// and changed by enrich
|
||||
@ -387,7 +398,7 @@ inline void enrich_intersection_points(Turns& turns,
|
||||
<< mit->first << std::endl;
|
||||
#endif
|
||||
detail::overlay::enrich_sort<Reverse1, Reverse2>(
|
||||
mit->second, turns, for_operation,
|
||||
mit->second, turns, target_operation,
|
||||
geometry1, geometry2,
|
||||
robust_policy, strategy);
|
||||
}
|
||||
@ -406,12 +417,16 @@ inline void enrich_intersection_points(Turns& turns,
|
||||
|
||||
if (has_colocations)
|
||||
{
|
||||
// First gather cluster properties (using even clusters with
|
||||
// discarded turns - for open turns), then clean up clusters
|
||||
detail::overlay::gather_cluster_properties
|
||||
<
|
||||
Reverse1,
|
||||
Reverse2,
|
||||
OverlayType
|
||||
>(clusters, turns, for_operation, geometry1, geometry2);
|
||||
>(clusters, turns, target_operation, geometry1, geometry2);
|
||||
|
||||
detail::overlay::cleanup_clusters(turns, clusters);
|
||||
}
|
||||
|
||||
if (has_cc)
|
||||
|
@ -262,15 +262,6 @@ inline void handle_colocation_cluster(Turns& turns,
|
||||
add_cluster_id(other_op, cluster_per_segment, ref_id);
|
||||
id = ref_id;
|
||||
}
|
||||
|
||||
// In case of colocated xx turns, all other turns may NOT be
|
||||
// followed at all. xx cannot be discarded (otherwise colocated
|
||||
// turns are followed).
|
||||
if (ref_turn.both(operation_blocked))
|
||||
{
|
||||
turn.discarded = true;
|
||||
// We can either set or not set colocated because it is not effective on blocked turns
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -331,11 +322,7 @@ inline void assign_cluster_to_turns(Turns& turns,
|
||||
}
|
||||
}
|
||||
|
||||
template
|
||||
<
|
||||
typename Turns,
|
||||
typename Clusters
|
||||
>
|
||||
template <typename Turns, typename Clusters>
|
||||
inline void remove_clusters(Turns& turns, Clusters& clusters)
|
||||
{
|
||||
typename Clusters::iterator it = clusters.begin();
|
||||
@ -350,13 +337,39 @@ inline void remove_clusters(Turns& turns, Clusters& clusters)
|
||||
= current_it->second.turn_indices;
|
||||
if (turn_indices.size() == 1)
|
||||
{
|
||||
signed_size_type turn_index = *turn_indices.begin();
|
||||
signed_size_type const turn_index = *turn_indices.begin();
|
||||
turns[turn_index].cluster_id = -1;
|
||||
clusters.erase(current_it);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <typename Turns, typename Clusters>
|
||||
inline void cleanup_clusters(Turns& turns, Clusters& clusters)
|
||||
{
|
||||
// Removes discarded turns from clusters
|
||||
for (typename Clusters::iterator mit = clusters.begin();
|
||||
mit != clusters.end(); ++mit)
|
||||
{
|
||||
cluster_info& cinfo = mit->second;
|
||||
std::set<signed_size_type>& ids = cinfo.turn_indices;
|
||||
for (std::set<signed_size_type>::iterator sit = ids.begin();
|
||||
sit != ids.end(); /* no increment */)
|
||||
{
|
||||
std::set<signed_size_type>::iterator current_it = sit;
|
||||
++sit;
|
||||
|
||||
signed_size_type const turn_index = *current_it;
|
||||
if (turns[turn_index].discarded)
|
||||
{
|
||||
ids.erase(current_it);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
remove_clusters(turns, clusters);
|
||||
}
|
||||
|
||||
template <typename Turn, typename IdSet>
|
||||
inline void discard_ie_turn(Turn& turn, IdSet& ids, signed_size_type id)
|
||||
{
|
||||
@ -508,7 +521,7 @@ inline void set_colocation(Turns& turns, Clusters const& clusters)
|
||||
{
|
||||
has_ii = true;
|
||||
}
|
||||
if (turn.both(operation_union))
|
||||
if (turn.both(operation_union) || turn.combination(operation_union, operation_blocked))
|
||||
{
|
||||
has_uu = true;
|
||||
}
|
||||
@ -629,7 +642,6 @@ inline bool handle_colocations(Turns& turns, Clusters& clusters,
|
||||
do_reverse<geometry::point_order<Geometry2>::value>::value != Reverse2,
|
||||
OverlayType
|
||||
>(turns, clusters);
|
||||
remove_clusters(turns, clusters);
|
||||
|
||||
#if defined(BOOST_GEOMETRY_DEBUG_HANDLE_COLOCATIONS)
|
||||
std::cout << "*** Colocations " << map.size() << std::endl;
|
||||
@ -716,7 +728,7 @@ inline void gather_cluster_properties(Clusters& clusters, Turns& turns,
|
||||
point_type turn_point; // should be all the same for all turns in cluster
|
||||
|
||||
bool first = true;
|
||||
for (typename std::set<signed_size_type>::const_iterator sit = ids.begin();
|
||||
for (std::set<signed_size_type>::const_iterator sit = ids.begin();
|
||||
sit != ids.end(); ++sit)
|
||||
{
|
||||
signed_size_type turn_index = *sit;
|
||||
@ -737,6 +749,8 @@ inline void gather_cluster_properties(Clusters& clusters, Turns& turns,
|
||||
sbs.find_open();
|
||||
sbs.assign_zones(for_operation);
|
||||
|
||||
cinfo.open_count = sbs.open_count(for_operation);
|
||||
|
||||
// Unset the startable flag for all 'closed' zones
|
||||
for (std::size_t i = 0; i < sbs.m_ranked_points.size(); i++)
|
||||
{
|
||||
@ -744,6 +758,11 @@ inline void gather_cluster_properties(Clusters& clusters, Turns& turns,
|
||||
turn_type& turn = turns[ranked.turn_index];
|
||||
turn_operation_type& op = turn.operations[ranked.operation_index];
|
||||
|
||||
if (for_operation == operation_union && cinfo.open_count == 0)
|
||||
{
|
||||
op.enriched.startable = false;
|
||||
}
|
||||
|
||||
if (ranked.direction != sort_by_side::dir_to)
|
||||
{
|
||||
continue;
|
||||
@ -763,7 +782,6 @@ inline void gather_cluster_properties(Clusters& clusters, Turns& turns,
|
||||
}
|
||||
}
|
||||
|
||||
cinfo.open_count = sbs.open_count(for_operation);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,143 @@
|
||||
// Boost.Geometry (aka GGL, Generic Geometry Library)
|
||||
|
||||
// Copyright (c) 2017 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)
|
||||
|
||||
#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_HANDLE_SELF_TURNS_HPP
|
||||
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_HANDLE_SELF_TURNS_HPP
|
||||
|
||||
#include <boost/range.hpp>
|
||||
|
||||
#include <boost/geometry/algorithms/detail/overlay/is_self_turn.hpp>
|
||||
#include <boost/geometry/algorithms/detail/overlay/overlay_type.hpp>
|
||||
#include <boost/geometry/algorithms/within.hpp>
|
||||
|
||||
namespace boost { namespace geometry
|
||||
{
|
||||
|
||||
#ifndef DOXYGEN_NO_DETAIL
|
||||
namespace detail { namespace overlay
|
||||
{
|
||||
|
||||
struct discard_turns
|
||||
{
|
||||
template <typename Turns, typename Geometry0, typename Geometry1>
|
||||
static inline
|
||||
void apply(Turns& , Geometry0 const& , Geometry1 const& )
|
||||
{}
|
||||
};
|
||||
|
||||
template <overlay_type OverlayType, operation_type OperationType>
|
||||
struct discard_closed_turns : discard_turns {};
|
||||
|
||||
// It is only implemented for operation_union, not in buffer
|
||||
template <>
|
||||
struct discard_closed_turns<overlay_union, operation_union>
|
||||
{
|
||||
|
||||
template <typename Turns, typename Geometry0, typename Geometry1>
|
||||
static inline
|
||||
void apply(Turns& turns,
|
||||
Geometry0 const& geometry0, Geometry1 const& geometry1)
|
||||
{
|
||||
typedef typename boost::range_value<Turns>::type turn_type;
|
||||
|
||||
for (typename boost::range_iterator<Turns>::type
|
||||
it = boost::begin(turns);
|
||||
it != boost::end(turns);
|
||||
++it)
|
||||
{
|
||||
turn_type& turn = *it;
|
||||
|
||||
if (turn.cluster_id >= 0
|
||||
|| turn.discarded
|
||||
|| ! is_self_turn<overlay_union>(turn))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
bool const within =
|
||||
turn.operations[0].seg_id.source_index == 0
|
||||
? geometry::within(turn.point, geometry1)
|
||||
: geometry::within(turn.point, geometry0);
|
||||
|
||||
if (within)
|
||||
{
|
||||
// It is in the interior of the other geometry
|
||||
turn.discarded = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
struct discard_self_intersection_turns
|
||||
{
|
||||
template <typename Turns, typename Geometry0, typename Geometry1>
|
||||
static inline
|
||||
void apply(Turns& turns,
|
||||
Geometry0 const& geometry0, Geometry1 const& geometry1)
|
||||
{
|
||||
typedef typename boost::range_value<Turns>::type turn_type;
|
||||
|
||||
for (typename boost::range_iterator<Turns>::type
|
||||
it = boost::begin(turns);
|
||||
it != boost::end(turns);
|
||||
++it)
|
||||
{
|
||||
turn_type& turn = *it;
|
||||
|
||||
if (turn.cluster_id >= 0
|
||||
|| turn.discarded
|
||||
|| ! is_self_turn<overlay_intersection>(turn))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
segment_identifier const& id0 = turn.operations[0].seg_id;
|
||||
segment_identifier const& id1 = turn.operations[1].seg_id;
|
||||
if (id0.multi_index != id1.multi_index
|
||||
|| (id0.ring_index == -1 && id1.ring_index == -1)
|
||||
|| (id0.ring_index >= 0 && id1.ring_index >= 0))
|
||||
{
|
||||
// Not an ii ring (int/ext) on same ring
|
||||
continue;
|
||||
}
|
||||
|
||||
// It is a non co-located ii self-turn
|
||||
// Check if it is within the other geometry
|
||||
// If not, it can be ignored
|
||||
|
||||
bool const within =
|
||||
turn.operations[0].seg_id.source_index == 0
|
||||
? geometry::within(turn.point, geometry1)
|
||||
: geometry::within(turn.point, geometry0);
|
||||
|
||||
if (! within)
|
||||
{
|
||||
// It is not within another geometry, discard the turn
|
||||
turn.discarded = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
template <overlay_type OverlayType, operation_type OperationType>
|
||||
struct discard_open_turns : discard_turns {};
|
||||
|
||||
// Handler it for intersection
|
||||
template <>
|
||||
struct discard_open_turns<overlay_intersection, operation_intersection>
|
||||
: discard_self_intersection_turns {};
|
||||
|
||||
// For difference, it should be done in a different way (TODO)
|
||||
|
||||
}} // namespace detail::overlay
|
||||
#endif //DOXYGEN_NO_DETAIL
|
||||
|
||||
|
||||
}} // namespace boost::geometry
|
||||
|
||||
#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_HANDLE_SELF_TURNS_HPP
|
@ -0,0 +1,68 @@
|
||||
// Boost.Geometry (aka GGL, Generic Geometry Library)
|
||||
|
||||
// Copyright (c) 2017-2017 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)
|
||||
|
||||
#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_IS_SELF_TURN_HPP
|
||||
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_IS_SELF_TURN_HPP
|
||||
|
||||
#include <boost/geometry/algorithms/detail/overlay/overlay_type.hpp>
|
||||
|
||||
namespace boost { namespace geometry
|
||||
{
|
||||
|
||||
|
||||
#ifndef DOXYGEN_NO_DETAIL
|
||||
namespace detail { namespace overlay
|
||||
{
|
||||
|
||||
template <overlay_type OverlayType>
|
||||
struct is_self_turn_check
|
||||
{
|
||||
template <typename Turn>
|
||||
static inline bool apply(Turn const& turn)
|
||||
{
|
||||
return turn.operations[0].seg_id.source_index
|
||||
== turn.operations[1].seg_id.source_index;
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct is_self_turn_check<overlay_buffer>
|
||||
{
|
||||
template <typename Turn>
|
||||
static inline bool apply(Turn const& turn)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct is_self_turn_check<overlay_dissolve>
|
||||
{
|
||||
template <typename Turn>
|
||||
static inline bool apply(Turn const& turn)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
template <overlay_type OverlayType, typename Turn>
|
||||
bool is_self_turn(Turn const& turn)
|
||||
{
|
||||
return is_self_turn_check<OverlayType>::apply(turn);
|
||||
}
|
||||
|
||||
|
||||
}} // namespace detail::overlay
|
||||
#endif // DOXYGEN_NO_DETAIL
|
||||
|
||||
|
||||
}} // namespace boost::geometry
|
||||
|
||||
|
||||
#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_IS_SELF_TURN_HPP
|
@ -28,6 +28,7 @@
|
||||
#include <boost/geometry/algorithms/detail/overlay/enrich_intersection_points.hpp>
|
||||
#include <boost/geometry/algorithms/detail/overlay/enrichment_info.hpp>
|
||||
#include <boost/geometry/algorithms/detail/overlay/get_turns.hpp>
|
||||
#include <boost/geometry/algorithms/detail/overlay/is_self_turn.hpp>
|
||||
#include <boost/geometry/algorithms/detail/overlay/overlay_type.hpp>
|
||||
#include <boost/geometry/algorithms/detail/overlay/traverse.hpp>
|
||||
#include <boost/geometry/algorithms/detail/overlay/traversal_info.hpp>
|
||||
@ -117,6 +118,7 @@ inline void get_ring_turn_info(TurnInfoMap& turn_info_map, Turns const& turns, C
|
||||
? turn.colocated_uu : turn.colocated_ii;
|
||||
bool const colocated_opp = target_operation == operation_union
|
||||
? turn.colocated_ii : turn.colocated_uu;
|
||||
bool const both_opposite = turn.both(opposite_operation);
|
||||
|
||||
bool const traversed
|
||||
= turn.operations[0].visited.finalized()
|
||||
@ -126,6 +128,16 @@ inline void get_ring_turn_info(TurnInfoMap& turn_info_map, Turns const& turns, C
|
||||
|| turn.both(operation_blocked)
|
||||
|| turn.combination(opposite_operation, operation_blocked);
|
||||
|
||||
bool is_closed = false;
|
||||
if (turn.cluster_id >= 0 && target_operation == operation_union)
|
||||
{
|
||||
typename Clusters::const_iterator mit = clusters.find(turn.cluster_id);
|
||||
BOOST_ASSERT(mit != clusters.end());
|
||||
|
||||
cluster_info const& cinfo = mit->second;
|
||||
is_closed = cinfo.open_count == 0;
|
||||
}
|
||||
|
||||
for (typename boost::range_iterator<container_type const>::type
|
||||
op_it = boost::begin(turn.operations);
|
||||
op_it != boost::end(turn.operations);
|
||||
@ -138,54 +150,32 @@ inline void get_ring_turn_info(TurnInfoMap& turn_info_map, Turns const& turns, C
|
||||
op_it->seg_id.ring_index
|
||||
);
|
||||
|
||||
if (traversed)
|
||||
if (traversed || is_closed || ! op_it->enriched.startable)
|
||||
{
|
||||
turn_info_map[ring_id].has_traversed_turn = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (turn.both(opposite_operation) && colocated_target)
|
||||
else if (both_opposite && colocated_target)
|
||||
{
|
||||
// For union: ii, colocated with a uu
|
||||
// For example, two interior rings touch where two exterior rings also touch.
|
||||
// The interior rings are not yet traversed, and should be taken from the input
|
||||
|
||||
// For intersection: uu, colocated with an ii
|
||||
continue;
|
||||
}
|
||||
// unless it is two interior inner rings colocated with a uu
|
||||
|
||||
// unless it is two interior inner rings colocated with a uu
|
||||
if (turn.both(opposite_operation))
|
||||
// So don't set has_traversed_turn here
|
||||
}
|
||||
else if (both_opposite && ! is_self_turn<OverlayType>(turn))
|
||||
{
|
||||
// For union, mark any ring with a ii turn as traversed
|
||||
// For intersection, any uu
|
||||
// For intersection, any uu - but not if it is a self-turn
|
||||
turn_info_map[ring_id].has_traversed_turn = true;
|
||||
continue;
|
||||
}
|
||||
else if (colocated_opp && ! colocated_target)
|
||||
{
|
||||
// For union, a turn colocated with ii and NOT with uu
|
||||
// For union, a turn colocated with ii and NOT with uu/ux
|
||||
// For intersection v.v.
|
||||
turn_info_map[ring_id].has_traversed_turn = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (turn.cluster_id >= 0)
|
||||
{
|
||||
// Check other turns in same cluster
|
||||
|
||||
typename Clusters::const_iterator mit = clusters.find(turn.cluster_id);
|
||||
BOOST_ASSERT(mit != clusters.end());
|
||||
|
||||
cluster_info const& cinfo = mit->second;
|
||||
|
||||
if (target_operation == operation_union && cinfo.open_count == 0)
|
||||
{
|
||||
// It is not traversed, and there is no way out for a union,
|
||||
// so register it as traversed to avoid including the ring
|
||||
turn_info_map[ring_id].has_traversed_turn = true;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -308,10 +298,10 @@ std::cout << "get turns" << std::endl;
|
||||
|
||||
#ifdef BOOST_GEOMETRY_INCLUDE_SELF_TURNS
|
||||
{
|
||||
geometry::self_turns<assign_null_policy>(geometry1, strategy, robust_policy,
|
||||
turns, policy, 0);
|
||||
geometry::self_turns<assign_null_policy>(geometry2, strategy, robust_policy,
|
||||
turns, policy, 1);
|
||||
self_get_turn_points::self_turns<Reverse1, assign_null_policy>(geometry1,
|
||||
strategy, robust_policy, turns, policy, 0);
|
||||
self_get_turn_points::self_turns<Reverse2, assign_null_policy>(geometry2,
|
||||
strategy, robust_policy, turns, policy, 1);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -23,12 +23,14 @@
|
||||
|
||||
#include <boost/geometry/core/access.hpp>
|
||||
#include <boost/geometry/core/coordinate_dimension.hpp>
|
||||
#include <boost/geometry/core/point_order.hpp>
|
||||
#include <boost/geometry/core/tags.hpp>
|
||||
|
||||
#include <boost/geometry/geometries/concepts/check.hpp>
|
||||
|
||||
#include <boost/geometry/algorithms/detail/disjoint/box_box.hpp>
|
||||
#include <boost/geometry/algorithms/detail/partition.hpp>
|
||||
#include <boost/geometry/algorithms/detail/overlay/do_reverse.hpp>
|
||||
#include <boost/geometry/algorithms/detail/overlay/get_turns.hpp>
|
||||
#include <boost/geometry/algorithms/detail/sections/section_box_policies.hpp>
|
||||
|
||||
@ -60,6 +62,7 @@ struct no_interrupt_policy
|
||||
|
||||
template
|
||||
<
|
||||
bool Reverse,
|
||||
typename Geometry,
|
||||
typename Turns,
|
||||
typename TurnPolicy,
|
||||
@ -101,7 +104,7 @@ struct self_section_visitor
|
||||
return detail::get_turns::get_turns_in_sections
|
||||
<
|
||||
Geometry, Geometry,
|
||||
false, false,
|
||||
Reverse, Reverse,
|
||||
Section, Section,
|
||||
TurnPolicy
|
||||
>::apply(m_source_index, m_geometry, sec1,
|
||||
@ -119,7 +122,7 @@ struct self_section_visitor
|
||||
|
||||
|
||||
|
||||
template<typename TurnPolicy>
|
||||
template <bool Reverse, typename TurnPolicy>
|
||||
struct get_turns
|
||||
{
|
||||
template <typename Geometry, typename IntersectionStrategy, typename RobustPolicy, typename Turns, typename InterruptPolicy>
|
||||
@ -145,12 +148,12 @@ struct get_turns
|
||||
typedef boost::mpl::vector_c<std::size_t, 0> dimensions;
|
||||
|
||||
sections_type sec;
|
||||
geometry::sectionalize<false, dimensions>(geometry, robust_policy, sec,
|
||||
geometry::sectionalize<Reverse, dimensions>(geometry, robust_policy, sec,
|
||||
intersection_strategy.get_envelope_strategy());
|
||||
|
||||
self_section_visitor
|
||||
<
|
||||
Geometry,
|
||||
Reverse, Geometry,
|
||||
Turns, TurnPolicy, IntersectionStrategy, RobustPolicy, InterruptPolicy
|
||||
> visitor(geometry, intersection_strategy, robust_policy, turns, interrupt_policy, source_index);
|
||||
|
||||
@ -177,6 +180,7 @@ namespace dispatch
|
||||
|
||||
template
|
||||
<
|
||||
bool Reverse,
|
||||
typename GeometryTag,
|
||||
typename Geometry,
|
||||
typename TurnPolicy
|
||||
@ -188,26 +192,28 @@ struct self_get_turn_points
|
||||
|
||||
template
|
||||
<
|
||||
bool Reverse,
|
||||
typename Ring,
|
||||
typename TurnPolicy
|
||||
>
|
||||
struct self_get_turn_points
|
||||
<
|
||||
ring_tag, Ring,
|
||||
Reverse, ring_tag, Ring,
|
||||
TurnPolicy
|
||||
>
|
||||
: detail::self_get_turn_points::get_turns<TurnPolicy>
|
||||
: detail::self_get_turn_points::get_turns<Reverse, TurnPolicy>
|
||||
{};
|
||||
|
||||
|
||||
template
|
||||
<
|
||||
bool Reverse,
|
||||
typename Box,
|
||||
typename TurnPolicy
|
||||
>
|
||||
struct self_get_turn_points
|
||||
<
|
||||
box_tag, Box,
|
||||
Reverse, box_tag, Box,
|
||||
TurnPolicy
|
||||
>
|
||||
{
|
||||
@ -227,29 +233,31 @@ struct self_get_turn_points
|
||||
|
||||
template
|
||||
<
|
||||
bool Reverse,
|
||||
typename Polygon,
|
||||
typename TurnPolicy
|
||||
>
|
||||
struct self_get_turn_points
|
||||
<
|
||||
polygon_tag, Polygon,
|
||||
Reverse, polygon_tag, Polygon,
|
||||
TurnPolicy
|
||||
>
|
||||
: detail::self_get_turn_points::get_turns<TurnPolicy>
|
||||
: detail::self_get_turn_points::get_turns<Reverse, TurnPolicy>
|
||||
{};
|
||||
|
||||
|
||||
template
|
||||
<
|
||||
bool Reverse,
|
||||
typename MultiPolygon,
|
||||
typename TurnPolicy
|
||||
>
|
||||
struct self_get_turn_points
|
||||
<
|
||||
multi_polygon_tag, MultiPolygon,
|
||||
Reverse, multi_polygon_tag, MultiPolygon,
|
||||
TurnPolicy
|
||||
>
|
||||
: detail::self_get_turn_points::get_turns<TurnPolicy>
|
||||
: detail::self_get_turn_points::get_turns<Reverse, TurnPolicy>
|
||||
{};
|
||||
|
||||
|
||||
@ -257,6 +265,45 @@ struct self_get_turn_points
|
||||
#endif // DOXYGEN_NO_DISPATCH
|
||||
|
||||
|
||||
#ifndef DOXYGEN_NO_DETAIL
|
||||
namespace detail { namespace self_get_turn_points
|
||||
{
|
||||
|
||||
// Version where Reverse can be specified manually. TODO:
|
||||
// can most probably be merged with self_get_turn_points::get_turn
|
||||
template
|
||||
<
|
||||
bool Reverse,
|
||||
typename AssignPolicy,
|
||||
typename Geometry,
|
||||
typename IntersectionStrategy,
|
||||
typename RobustPolicy,
|
||||
typename Turns,
|
||||
typename InterruptPolicy
|
||||
>
|
||||
inline void self_turns(Geometry const& geometry,
|
||||
IntersectionStrategy const& strategy,
|
||||
RobustPolicy const& robust_policy,
|
||||
Turns& turns,
|
||||
InterruptPolicy& interrupt_policy,
|
||||
std::size_t source_index = 0)
|
||||
{
|
||||
concepts::check<Geometry const>();
|
||||
|
||||
typedef detail::overlay::get_turn_info<detail::overlay::assign_null_policy> turn_policy;
|
||||
|
||||
dispatch::self_get_turn_points
|
||||
<
|
||||
Reverse,
|
||||
typename tag<Geometry>::type,
|
||||
Geometry,
|
||||
turn_policy
|
||||
>::apply(geometry, strategy, robust_policy, turns, interrupt_policy, source_index);
|
||||
}
|
||||
|
||||
}} // namespace detail::self_get_turn_points
|
||||
#endif // DOXYGEN_NO_DETAIL
|
||||
|
||||
/*!
|
||||
\brief Calculate self intersections of a geometry
|
||||
\ingroup overlay
|
||||
@ -288,14 +335,16 @@ inline void self_turns(Geometry const& geometry,
|
||||
{
|
||||
concepts::check<Geometry const>();
|
||||
|
||||
typedef detail::overlay::get_turn_info<detail::overlay::assign_null_policy> turn_policy;
|
||||
static bool const reverse = detail::overlay::do_reverse
|
||||
<
|
||||
geometry::point_order<Geometry>::value
|
||||
>::value;
|
||||
|
||||
dispatch::self_get_turn_points
|
||||
detail::self_get_turn_points::self_turns
|
||||
<
|
||||
typename tag<Geometry>::type,
|
||||
Geometry,
|
||||
turn_policy
|
||||
>::apply(geometry, strategy, robust_policy, turns, interrupt_policy, source_index);
|
||||
reverse,
|
||||
AssignPolicy
|
||||
>(geometry, strategy, robust_policy, turns, interrupt_policy, source_index);
|
||||
}
|
||||
|
||||
|
||||
|
@ -14,7 +14,9 @@
|
||||
#include <boost/range.hpp>
|
||||
|
||||
#include <boost/geometry/algorithms/detail/overlay/aggregate_operations.hpp>
|
||||
#include <boost/geometry/algorithms/detail/overlay/is_self_turn.hpp>
|
||||
#include <boost/geometry/algorithms/detail/overlay/sort_by_side.hpp>
|
||||
#include <boost/geometry/algorithms/detail/overlay/traversal_intersection_patterns.hpp>
|
||||
#include <boost/geometry/algorithms/detail/overlay/turn_info.hpp>
|
||||
#include <boost/geometry/core/access.hpp>
|
||||
#include <boost/geometry/core/assert.hpp>
|
||||
@ -195,8 +197,8 @@ struct traversal
|
||||
}
|
||||
|
||||
inline bool select_source(signed_size_type turn_index,
|
||||
segment_identifier const& seg_id1,
|
||||
segment_identifier const& seg_id2) const
|
||||
segment_identifier const& candidate_seg_id,
|
||||
segment_identifier const& previous_seg_id) const
|
||||
{
|
||||
// For uu/ii, only switch sources if indicated
|
||||
turn_type const& turn = m_turns[turn_index];
|
||||
@ -205,14 +207,16 @@ struct traversal
|
||||
{
|
||||
// Buffer does not use source_index (always 0)
|
||||
return turn.switch_source
|
||||
? seg_id1.multi_index != seg_id2.multi_index
|
||||
: seg_id1.multi_index == seg_id2.multi_index;
|
||||
? candidate_seg_id.multi_index != previous_seg_id.multi_index
|
||||
: candidate_seg_id.multi_index == previous_seg_id.multi_index;
|
||||
}
|
||||
|
||||
// If it is a self-turn, always switch source
|
||||
if (turn.self_turn())
|
||||
if (is_self_turn<OverlayType>(turn))
|
||||
{
|
||||
return true;
|
||||
// Also, if it is a self-turn, stay on same ring (multi/ring)
|
||||
return turn.switch_source
|
||||
? candidate_seg_id.multi_index != previous_seg_id.multi_index
|
||||
: candidate_seg_id.multi_index == previous_seg_id.multi_index;
|
||||
}
|
||||
|
||||
#if defined(BOOST_GEOMETRY_DEBUG_TRAVERSAL_SWITCH_DETECTOR)
|
||||
@ -226,8 +230,8 @@ struct traversal
|
||||
}
|
||||
#endif
|
||||
return turn.switch_source
|
||||
? seg_id1.source_index != seg_id2.source_index
|
||||
: seg_id1.source_index == seg_id2.source_index;
|
||||
? candidate_seg_id.source_index != previous_seg_id.source_index
|
||||
: candidate_seg_id.source_index == previous_seg_id.source_index;
|
||||
}
|
||||
|
||||
inline bool traverse_possible(signed_size_type turn_index) const
|
||||
@ -295,7 +299,7 @@ struct traversal
|
||||
inline
|
||||
bool select_noncc_operation(turn_type const& turn,
|
||||
signed_size_type turn_index,
|
||||
segment_identifier const& seg_id,
|
||||
segment_identifier const& previous_seg_id,
|
||||
int& selected_op_index) const
|
||||
{
|
||||
bool result = false;
|
||||
@ -306,7 +310,7 @@ struct traversal
|
||||
|
||||
if (op.operation == target_operation
|
||||
&& ! op.visited.finished()
|
||||
&& (! result || select_source(turn_index, op.seg_id, seg_id)))
|
||||
&& (! result || select_source(turn_index, op.seg_id, previous_seg_id)))
|
||||
{
|
||||
selected_op_index = i;
|
||||
debug_traverse(turn, op, "Candidate");
|
||||
@ -369,65 +373,56 @@ struct traversal
|
||||
}
|
||||
|
||||
inline bool select_from_cluster_union(signed_size_type& turn_index,
|
||||
int& op_index, signed_size_type start_turn_index,
|
||||
sbs_type const& sbs, bool is_touching) const
|
||||
int& op_index, sbs_type& sbs) const
|
||||
{
|
||||
std::vector<sort_by_side::rank_with_rings> aggregation;
|
||||
sort_by_side::aggregate_operations(sbs, aggregation, m_turns, operation_union);
|
||||
|
||||
|
||||
sort_by_side::rank_with_rings const& incoming = aggregation.front();
|
||||
|
||||
// Take the first one outgoing for the incoming region
|
||||
std::size_t selected_rank = 0;
|
||||
std::size_t min_rank = 0;
|
||||
bool result = false;
|
||||
for (std::size_t i = 0; i < sbs.m_ranked_points.size(); i++)
|
||||
for (std::size_t i = 1; i < aggregation.size(); i++)
|
||||
{
|
||||
sort_by_side::rank_with_rings const& rwr = aggregation[i];
|
||||
if (rwr.all_to()
|
||||
&& rwr.region_id() == incoming.region_id())
|
||||
{
|
||||
selected_rank = rwr.rank;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
for (std::size_t i = 1; i < sbs.m_ranked_points.size(); i++)
|
||||
{
|
||||
typename sbs_type::rp const& ranked_point = sbs.m_ranked_points[i];
|
||||
if (result && ranked_point.rank > selected_rank)
|
||||
if (ranked_point.rank == selected_rank
|
||||
&& ranked_point.direction == sort_by_side::dir_to)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
turn_index = ranked_point.turn_index;
|
||||
op_index = ranked_point.operation_index;
|
||||
|
||||
turn_type const& ranked_turn = m_turns[ranked_point.turn_index];
|
||||
turn_operation_type const& ranked_op = ranked_turn.operations[ranked_point.operation_index];
|
||||
turn_type const& turn = m_turns[turn_index];
|
||||
turn_operation_type const& op = turn.operations[op_index];
|
||||
|
||||
if (result && ranked_op.visited.finalized())
|
||||
{
|
||||
// One of the arcs in the same direction as the selected result
|
||||
// is already traversed.
|
||||
return false;
|
||||
}
|
||||
|
||||
if (! is_touching && ranked_op.visited.finalized())
|
||||
{
|
||||
// Skip this one, go to next
|
||||
min_rank = ranked_point.rank;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (ranked_point.direction == sort_by_side::dir_to
|
||||
&& (ranked_point.rank > min_rank
|
||||
|| ranked_turn.both(operation_continue)))
|
||||
{
|
||||
if (ranked_op.enriched.count_left == 0
|
||||
&& ranked_op.enriched.count_right > 0)
|
||||
if (op.enriched.count_left == 0
|
||||
&& op.enriched.count_right > 0
|
||||
&& ! op.visited.finalized())
|
||||
{
|
||||
if (result && ranked_point.turn_index != start_turn_index)
|
||||
{
|
||||
// Don't override - only override if arrive at start
|
||||
continue;
|
||||
}
|
||||
// In some cases interior rings might be generated with polygons
|
||||
// on both sides
|
||||
|
||||
turn_index = ranked_point.turn_index;
|
||||
op_index = ranked_point.operation_index;
|
||||
|
||||
result = true;
|
||||
selected_rank = ranked_point.rank;
|
||||
}
|
||||
else if (! is_touching)
|
||||
{
|
||||
return result;
|
||||
// TODO: this should be finetuned such that checking
|
||||
// finalized is not necessary
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
inline bool all_operations_of_type(sort_by_side::rank_with_rings const& rwr,
|
||||
operation_type op_type,
|
||||
sort_by_side::direction_type dir) const
|
||||
@ -461,65 +456,78 @@ struct traversal
|
||||
int& op_index, sbs_type const& sbs) const
|
||||
{
|
||||
std::vector<sort_by_side::rank_with_rings> aggregation;
|
||||
sort_by_side::aggregate_operations(sbs, aggregation, m_turns);
|
||||
sort_by_side::aggregate_operations(sbs, aggregation, m_turns, operation_intersection);
|
||||
|
||||
std::size_t selected_rank = 0;
|
||||
|
||||
int incoming_region_id = 0;
|
||||
std::set<int> outgoing_region_ids;
|
||||
|
||||
for (std::size_t i = 0; i < aggregation.size(); i++)
|
||||
// Detect specific pattern(s)
|
||||
bool const detected
|
||||
= intersection_pattern_common_interior1(selected_rank, aggregation)
|
||||
|| intersection_pattern_common_interior2(selected_rank, aggregation)
|
||||
|| intersection_pattern_common_interior3(selected_rank, aggregation)
|
||||
|| intersection_pattern_common_interior4(selected_rank, aggregation)
|
||||
;
|
||||
|
||||
if (! detected)
|
||||
{
|
||||
sort_by_side::rank_with_rings const& rwr = aggregation[i];
|
||||
int incoming_region_id = 0;
|
||||
std::set<int> outgoing_region_ids;
|
||||
|
||||
if (rwr.all_to()
|
||||
&& rwr.traversable(m_turns)
|
||||
&& selected_rank == 0)
|
||||
for (std::size_t i = 0; i < aggregation.size(); i++)
|
||||
{
|
||||
// Take the first (= right) where segments leave,
|
||||
// having the polygon on the right side
|
||||
selected_rank = rwr.rank;
|
||||
}
|
||||
if (rwr.all_from()
|
||||
&& selected_rank > 0
|
||||
&& outgoing_region_ids.empty())
|
||||
{
|
||||
// Incoming
|
||||
break;
|
||||
}
|
||||
sort_by_side::rank_with_rings const& rwr = aggregation[i];
|
||||
|
||||
if (incoming_region_id == 0)
|
||||
{
|
||||
sort_by_side::ring_with_direction const& rwd = *rwr.rings.begin();
|
||||
turn_type const& turn = m_turns[rwd.turn_index];
|
||||
incoming_region_id = turn.operations[rwd.operation_index].enriched.region_id;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (rwr.rings.size() == 1)
|
||||
if (rwr.all_to()
|
||||
&& rwr.traversable(m_turns)
|
||||
&& selected_rank == 0)
|
||||
{
|
||||
// Take the first (= right) where segments leave,
|
||||
// having the polygon on the right side
|
||||
selected_rank = rwr.rank;
|
||||
}
|
||||
|
||||
if (rwr.all_from()
|
||||
&& selected_rank > 0
|
||||
&& outgoing_region_ids.empty())
|
||||
{
|
||||
// Incoming
|
||||
break;
|
||||
}
|
||||
|
||||
if (incoming_region_id == 0)
|
||||
{
|
||||
sort_by_side::ring_with_direction const& rwd = *rwr.rings.begin();
|
||||
turn_type const& turn = m_turns[rwd.turn_index];
|
||||
if (rwd.direction == sort_by_side::dir_to
|
||||
&& turn.both(operation_intersection))
|
||||
incoming_region_id = turn.operations[rwd.operation_index].enriched.region_id;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (rwr.rings.size() == 1)
|
||||
{
|
||||
sort_by_side::ring_with_direction const& rwd = *rwr.rings.begin();
|
||||
turn_type const& turn = m_turns[rwd.turn_index];
|
||||
if (rwd.direction == sort_by_side::dir_to
|
||||
&& turn.both(operation_intersection))
|
||||
{
|
||||
|
||||
turn_operation_type const& op = turn.operations[rwd.operation_index];
|
||||
if (op.enriched.region_id != incoming_region_id
|
||||
&& op.enriched.isolated)
|
||||
{
|
||||
outgoing_region_ids.insert(op.enriched.region_id);
|
||||
}
|
||||
}
|
||||
else if (! outgoing_region_ids.empty())
|
||||
{
|
||||
for (int i = 0; i < 2; i++)
|
||||
{
|
||||
int const region_id = turn.operations[i].enriched.region_id;
|
||||
if (outgoing_region_ids.count(region_id) == 1)
|
||||
turn_operation_type const& op = turn.operations[rwd.operation_index];
|
||||
if (op.enriched.region_id != incoming_region_id
|
||||
&& op.enriched.isolated)
|
||||
{
|
||||
selected_rank = 0;
|
||||
outgoing_region_ids.erase(region_id);
|
||||
outgoing_region_ids.insert(op.enriched.region_id);
|
||||
}
|
||||
}
|
||||
else if (! outgoing_region_ids.empty())
|
||||
{
|
||||
for (int i = 0; i < 2; i++)
|
||||
{
|
||||
int const region_id = turn.operations[i].enriched.region_id;
|
||||
if (outgoing_region_ids.count(region_id) == 1)
|
||||
{
|
||||
selected_rank = 0;
|
||||
outgoing_region_ids.erase(region_id);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -564,7 +572,7 @@ struct traversal
|
||||
}
|
||||
|
||||
inline bool select_turn_from_cluster(signed_size_type& turn_index,
|
||||
int& op_index, bool& is_touching,
|
||||
int& op_index,
|
||||
signed_size_type start_turn_index,
|
||||
segment_identifier const& previous_seg_id) const
|
||||
{
|
||||
@ -612,31 +620,7 @@ struct traversal
|
||||
|
||||
if (is_union)
|
||||
{
|
||||
#if defined(BOOST_GEOMETRY_DEBUG_TRAVERSAL_SWITCH_DETECTOR)
|
||||
is_touching = cinfo.open_count > 1;
|
||||
if (is_touching)
|
||||
{
|
||||
if (cinfo.switch_source)
|
||||
{
|
||||
is_touching = false;
|
||||
std::cout << "CLUSTER: SWITCH SOURCES at " << turn_index << std::endl;
|
||||
}
|
||||
else
|
||||
{
|
||||
std::cout << "CLUSTER: CONTINUE at " << turn_index << std::endl;
|
||||
}
|
||||
}
|
||||
#else
|
||||
is_touching = cinfo.open_count > 1 && ! cinfo.switch_source;
|
||||
#endif
|
||||
|
||||
if (is_touching)
|
||||
{
|
||||
sbs.reverse();
|
||||
}
|
||||
|
||||
result = select_from_cluster_union(turn_index, op_index, start_turn_index, sbs,
|
||||
is_touching);
|
||||
result = select_from_cluster_union(turn_index, op_index, sbs);
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -768,7 +752,6 @@ struct traversal
|
||||
bool select_turn(signed_size_type start_turn_index, int start_op_index,
|
||||
signed_size_type& turn_index,
|
||||
int& op_index,
|
||||
bool& is_touching,
|
||||
int previous_op_index,
|
||||
signed_size_type previous_turn_index,
|
||||
segment_identifier const& previous_seg_id,
|
||||
@ -803,7 +786,7 @@ struct traversal
|
||||
|
||||
if (current_turn.cluster_id >= 0)
|
||||
{
|
||||
if (! select_turn_from_cluster(turn_index, op_index, is_touching,
|
||||
if (! select_turn_from_cluster(turn_index, op_index,
|
||||
start_turn_index, previous_seg_id))
|
||||
{
|
||||
return false;
|
||||
|
@ -0,0 +1,306 @@
|
||||
// Boost.Geometry (aka GGL, Generic Geometry Library)
|
||||
|
||||
// Copyright (c) 2007-2017 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)
|
||||
|
||||
#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_TRAVERSAL_INTERSECTION_PATTERNS_HPP
|
||||
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_TRAVERSAL_INTERSECTION_PATTERNS_HPP
|
||||
|
||||
#include <cstddef>
|
||||
#include <vector>
|
||||
|
||||
#include <boost/geometry/algorithms/detail/overlay/aggregate_operations.hpp>
|
||||
#include <boost/geometry/algorithms/detail/overlay/sort_by_side.hpp>
|
||||
|
||||
namespace boost { namespace geometry
|
||||
{
|
||||
|
||||
#ifndef DOXYGEN_NO_DETAIL
|
||||
namespace detail { namespace overlay
|
||||
{
|
||||
|
||||
inline bool check_pairs(std::vector<sort_by_side::rank_with_rings> const& aggregation,
|
||||
signed_size_type incoming_region_id,
|
||||
std::size_t first, std::size_t last)
|
||||
{
|
||||
// Check if pairs 1,2 (and possibly 3,4 and 5,6 etc) satisfy
|
||||
|
||||
for (std::size_t i = first; i <= last; i += 2)
|
||||
{
|
||||
sort_by_side::rank_with_rings const& curr = aggregation[i];
|
||||
sort_by_side::rank_with_rings const& next = aggregation[i + 1];
|
||||
int const curr_id = curr.region_id();
|
||||
int const next_id = next.region_id();
|
||||
|
||||
bool const possible =
|
||||
curr.rings.size() == 2
|
||||
&& curr.is_isolated()
|
||||
&& curr.has_unique_region_id()
|
||||
&& next.rings.size() == 2
|
||||
&& next.is_isolated()
|
||||
&& next.has_unique_region_id()
|
||||
&& curr_id == next_id
|
||||
&& curr_id != incoming_region_id;
|
||||
|
||||
if (! possible)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
inline bool intersection_pattern_common_interior1(std::size_t& selected_rank,
|
||||
std::vector<sort_by_side::rank_with_rings> const& aggregation)
|
||||
{
|
||||
// Pattern: coming from exterior ring, encountering an isolated
|
||||
// parallel interior ring, which should be skipped, and the first
|
||||
// left (normally intersection takes first right) should be taken.
|
||||
// Solves cases #case_133_multi
|
||||
// and #case_recursive_boxes_49
|
||||
|
||||
std::size_t const n = aggregation.size();
|
||||
if (n < 4)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
sort_by_side::rank_with_rings const& incoming = aggregation.front();
|
||||
sort_by_side::rank_with_rings const& outgoing = aggregation.back();
|
||||
|
||||
bool const incoming_ok =
|
||||
incoming.all_from()
|
||||
&& incoming.rings.size() == 1
|
||||
&& incoming.has_only(operation_intersection);
|
||||
|
||||
if (! incoming_ok)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool const outgoing_ok =
|
||||
outgoing.all_to()
|
||||
&& outgoing.rings.size() == 1
|
||||
&& outgoing.has_only(operation_intersection)
|
||||
&& outgoing.region_id() == incoming.region_id();
|
||||
|
||||
if (! outgoing_ok)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (check_pairs(aggregation, incoming.region_id(), 1, n - 2))
|
||||
{
|
||||
selected_rank = n - 1;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
inline bool intersection_pattern_common_interior2(std::size_t& selected_rank,
|
||||
std::vector<sort_by_side::rank_with_rings> const& aggregation)
|
||||
{
|
||||
// Pattern: coming from two exterior rings, encountering two isolated
|
||||
// equal interior rings
|
||||
|
||||
// See (for example, for ii) #case_recursive_boxes_53:
|
||||
|
||||
// INCOMING:
|
||||
// Rank 0 {11[0] (s:0, m:0) i F rgn: 1 ISO} {13[1] (s:1, m:0) i F rgn: 1 ISO}
|
||||
|
||||
// PAIR:
|
||||
// Rank 1 {13[0] (s:0, r:1, m:0) i T rgn: 3 ISO ->16} {11[1] (s:1, r:5, m:0) i T rgn: 3 ISO ->16}
|
||||
// Rank 2 {13[0] (s:0, r:1, m:0) i F rgn: 3 ISO} {11[1] (s:1, r:5, m:0) i F rgn: 3 ISO}
|
||||
|
||||
// LEAVING (in the same direction, take last one)
|
||||
// Rank 3 {11[0] (s:0, m:0) i T rgn: 1 ISO ->10} {13[1] (s:1, m:0) i T rgn: 1 ISO ->10}
|
||||
|
||||
|
||||
std::size_t const n = aggregation.size();
|
||||
if (n < 4)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
sort_by_side::rank_with_rings const& incoming = aggregation.front();
|
||||
sort_by_side::rank_with_rings const& outgoing = aggregation.back();
|
||||
|
||||
bool const incoming_ok =
|
||||
incoming.all_from()
|
||||
&& incoming.rings.size() == 2
|
||||
&& incoming.has_unique_region_id();
|
||||
|
||||
if (! incoming_ok)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool const outgoing_ok =
|
||||
outgoing.all_to()
|
||||
&& outgoing.rings.size() == 2
|
||||
&& outgoing.has_unique_region_id()
|
||||
&& outgoing.region_id() == incoming.region_id();
|
||||
|
||||
if (! outgoing_ok)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool const operation_ok =
|
||||
(incoming.has_only(operation_continue) && outgoing.has_only(operation_continue))
|
||||
|| (incoming.has_only(operation_intersection) && outgoing.has_only(operation_intersection));
|
||||
|
||||
if (! operation_ok)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check if pairs 1,2 (and possibly 3,4 and 5,6 etc) satisfy
|
||||
if (check_pairs(aggregation, incoming.region_id(), 1, n - 2))
|
||||
{
|
||||
selected_rank = n - 1;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
inline bool intersection_pattern_common_interior3(std::size_t& selected_rank,
|
||||
std::vector<sort_by_side::rank_with_rings> const& aggregation)
|
||||
{
|
||||
// Pattern: approaches colocated turn (exterior+interior) from two
|
||||
// different directions, and both leaves in the same direction
|
||||
|
||||
// See #case_136_multi:
|
||||
// INCOMING:
|
||||
//Rank 0 {10[0] (s:0, m:0) c F rgn: 1 ISO}
|
||||
|
||||
// PAIR:
|
||||
//Rank 1 {14[0] (s:0, r:0, m:0) i T rgn: 2 ISO ->16} {11[1] (s:1, r:1, m:0) i T rgn: 2 ISO ->16}
|
||||
//Rank 2 {14[0] (s:0, r:0, m:0) i F rgn: 2 ISO} {11[1] (s:1, r:1, m:0) i F rgn: 2 ISO}
|
||||
|
||||
// LEAVING (select this one):
|
||||
//Rank 3 {10[0] (s:0, m:0) c T rgn: 1 ISO ->12} {10[1] (s:1, m:0) c T rgn: 1 ISO ->12}
|
||||
|
||||
// ADDITIONALLY: (other polygon coming in)
|
||||
//Rank 4 {10[1] (s:1, m:0) c F rgn: 1 ISO}
|
||||
|
||||
std::size_t const n = aggregation.size();
|
||||
if (n < 4)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
sort_by_side::rank_with_rings const& incoming = aggregation.front();
|
||||
sort_by_side::rank_with_rings const& outgoing = aggregation[n - 2];
|
||||
sort_by_side::rank_with_rings const& last = aggregation.back();
|
||||
|
||||
bool const incoming_ok =
|
||||
incoming.all_from()
|
||||
&& incoming.rings.size() == 1
|
||||
&& incoming.has_only(operation_continue);
|
||||
|
||||
if (! incoming_ok)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool const outgoing_ok =
|
||||
outgoing.all_to()
|
||||
&& outgoing.rings.size() == 2
|
||||
&& outgoing.has_only(operation_continue)
|
||||
&& outgoing.has_unique_region_id()
|
||||
&& outgoing.region_id() == incoming.region_id()
|
||||
&& last.all_from()
|
||||
&& last.rings.size() == 1
|
||||
&& last.region_id() == incoming.region_id()
|
||||
&& last.all_from();
|
||||
|
||||
if (! outgoing_ok)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check if pairs 1,2 (and possibly 3,4 and 5,6 etc) satisfy
|
||||
if (check_pairs(aggregation, incoming.region_id(), 1, n - 3))
|
||||
{
|
||||
selected_rank = n - 2;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
inline bool intersection_pattern_common_interior4(std::size_t& selected_rank,
|
||||
std::vector<sort_by_side::rank_with_rings> const& aggregation)
|
||||
{
|
||||
// Pattern: approaches colocated turn (exterior+interior) from same
|
||||
// direction, but leaves in two different directions
|
||||
|
||||
// See #case_137_multi:
|
||||
|
||||
// INCOMING:
|
||||
//Rank 0 {11[0] (s:0, m:0) i F rgn: 1 ISO} {10[1] (s:1, m:0) i F rgn: 1 ISO}
|
||||
|
||||
// PAIR:
|
||||
//Rank 1 {13[0] (s:0, r:0, m:0) i T rgn: 2 ISO ->15} {11[1] (s:1, r:1, m:0) i T rgn: 2 ISO ->15}
|
||||
//Rank 2 {13[0] (s:0, r:0, m:0) i F rgn: 2 ISO} {11[1] (s:1, r:1, m:0) i F rgn: 2 ISO}
|
||||
|
||||
// LEAVING (in two different directions, take last one)
|
||||
//Rank 3 {10[1] (s:1, m:0) i T rgn: 1 ISO ->0}
|
||||
//Rank 4 {11[0] (s:0, m:0) i T rgn: 1 ISO ->12}
|
||||
|
||||
std::size_t const n = aggregation.size();
|
||||
if (n < 4)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
sort_by_side::rank_with_rings const& incoming = aggregation.front();
|
||||
sort_by_side::rank_with_rings const& extra = aggregation[n - 2];
|
||||
sort_by_side::rank_with_rings const& outgoing = aggregation.back();
|
||||
|
||||
bool const incoming_ok =
|
||||
incoming.all_from()
|
||||
&& incoming.rings.size() == 2
|
||||
&& incoming.has_unique_region_id()
|
||||
&& incoming.has_only(operation_intersection);
|
||||
|
||||
if (! incoming_ok)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool const outgoing_ok =
|
||||
outgoing.all_to()
|
||||
&& outgoing.rings.size() == 1
|
||||
&& outgoing.has_only(operation_intersection)
|
||||
&& outgoing.region_id() == incoming.region_id()
|
||||
&& extra.all_to()
|
||||
&& extra.rings.size() == 1
|
||||
&& extra.has_only(operation_intersection)
|
||||
&& extra.region_id() == incoming.region_id();
|
||||
|
||||
if (! outgoing_ok)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check if pairs 1,2 (and possibly 3,4 and 5,6 etc) satisfy
|
||||
if (check_pairs(aggregation, incoming.region_id(), 1, n - 3))
|
||||
{
|
||||
selected_rank = n - 1;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
}} // namespace detail::overlay
|
||||
#endif // DOXYGEN_NO_DETAIL
|
||||
|
||||
}} // namespace boost::geometry
|
||||
|
||||
#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_TRAVERSAL_INTERSECTION_PATTERNS_HPP
|
@ -127,10 +127,8 @@ struct traversal_ring_creator
|
||||
m_visitor.visit_traverse(m_turns, previous_turn, previous_op, "Start");
|
||||
}
|
||||
|
||||
bool is_touching = false;
|
||||
if (! m_trav.select_turn(start_turn_index, start_op_index,
|
||||
turn_index, op_index,
|
||||
is_touching,
|
||||
previous_op_index, previous_turn_index, previous_seg_id,
|
||||
is_start))
|
||||
{
|
||||
|
@ -16,6 +16,7 @@
|
||||
#include <boost/geometry/algorithms/detail/ring_identifier.hpp>
|
||||
#include <boost/geometry/algorithms/detail/overlay/copy_segments.hpp>
|
||||
#include <boost/geometry/algorithms/detail/overlay/cluster_info.hpp>
|
||||
#include <boost/geometry/algorithms/detail/overlay/is_self_turn.hpp>
|
||||
#include <boost/geometry/algorithms/detail/overlay/turn_info.hpp>
|
||||
#include <boost/geometry/core/access.hpp>
|
||||
#include <boost/geometry/core/assert.hpp>
|
||||
@ -52,7 +53,8 @@ struct traversal_switch_detector
|
||||
typedef typename boost::range_value<Turns>::type turn_type;
|
||||
typedef typename turn_type::turn_operation_type turn_operation_type;
|
||||
|
||||
// For convenience
|
||||
// Per ring, first turns are collected (in turn_indices), and later
|
||||
// a region_id is assigned
|
||||
struct merged_ring_properties
|
||||
{
|
||||
signed_size_type region_id;
|
||||
@ -63,11 +65,26 @@ struct traversal_switch_detector
|
||||
{}
|
||||
};
|
||||
|
||||
struct connection_properties
|
||||
{
|
||||
std::size_t count;
|
||||
std::set<signed_size_type> cluster_indices;
|
||||
connection_properties()
|
||||
: count(0)
|
||||
{}
|
||||
};
|
||||
|
||||
typedef std::map<signed_size_type, connection_properties> connection_map;
|
||||
|
||||
// Per region, a set of properties is maintained, including its connections
|
||||
// to other regions
|
||||
struct region_properties
|
||||
{
|
||||
signed_size_type region_id;
|
||||
isolation_type isolated;
|
||||
std::map<signed_size_type, std::size_t> connected_region_counts;
|
||||
|
||||
// Maps from connected region_id to their properties
|
||||
connection_map connected_region_counts;
|
||||
|
||||
region_properties()
|
||||
: region_id(-1)
|
||||
@ -75,8 +92,10 @@ struct traversal_switch_detector
|
||||
{}
|
||||
};
|
||||
|
||||
// Keeps turn indices per ring
|
||||
typedef std::map<ring_identifier, merged_ring_properties > merge_map;
|
||||
typedef std::map<signed_size_type, region_properties> region_connection_map;
|
||||
|
||||
typedef std::set<signed_size_type>::const_iterator set_iterator;
|
||||
|
||||
inline traversal_switch_detector(Geometry1 const& geometry1, Geometry2 const& geometry2,
|
||||
@ -100,15 +119,47 @@ struct traversal_switch_detector
|
||||
return properties.isolated;
|
||||
}
|
||||
|
||||
bool all_colocated = true;
|
||||
int unique_cluster_id = -1;
|
||||
for (typename connection_map::const_iterator it = properties.connected_region_counts.begin();
|
||||
all_colocated && it != properties.connected_region_counts.end(); ++it)
|
||||
{
|
||||
connection_properties const& cprop = it->second;
|
||||
if (cprop.cluster_indices.size() != 1)
|
||||
{
|
||||
// Either no cluster (non colocated point), or more clusters
|
||||
all_colocated = false;
|
||||
}
|
||||
int const cluster_id = *cprop.cluster_indices.begin();
|
||||
if (cluster_id == -1)
|
||||
{
|
||||
all_colocated = false;
|
||||
}
|
||||
else if (unique_cluster_id == -1)
|
||||
{
|
||||
unique_cluster_id = cluster_id;
|
||||
}
|
||||
else if (unique_cluster_id != cluster_id)
|
||||
{
|
||||
all_colocated = false;
|
||||
}
|
||||
}
|
||||
if (all_colocated)
|
||||
{
|
||||
return isolation_yes;
|
||||
}
|
||||
|
||||
|
||||
// It is isolated if there is only one connection, or if there are more connections but all
|
||||
// of them are isolated themselves
|
||||
// of them are isolated themselves, or if there are more connections
|
||||
// but they are all colocated
|
||||
std::size_t non_isolation_count = 0;
|
||||
bool child_not_isolated = false;
|
||||
for (std::map<signed_size_type, std::size_t>::const_iterator it = properties.connected_region_counts.begin();
|
||||
for (typename connection_map::const_iterator it = properties.connected_region_counts.begin();
|
||||
it != properties.connected_region_counts.end(); ++it)
|
||||
{
|
||||
signed_size_type const region_id = it->first;
|
||||
std::size_t const count = it->second;
|
||||
connection_properties const& cprop = it->second;
|
||||
|
||||
if (region_id == parent_region_id)
|
||||
{
|
||||
@ -120,7 +171,7 @@ struct traversal_switch_detector
|
||||
// Find one of its ancestors again, this is a ring. Not isolated.
|
||||
return isolation_no;
|
||||
}
|
||||
if (count > 1)
|
||||
if (cprop.count > 1)
|
||||
{
|
||||
return isolation_no;
|
||||
}
|
||||
@ -215,9 +266,32 @@ struct traversal_switch_detector
|
||||
// Force insertion
|
||||
m_connected_regions[id0].region_id = id0;
|
||||
m_connected_regions[id1].region_id = id1;
|
||||
// Add reference to connection
|
||||
m_connected_regions[id0].connected_region_counts[id1]++;
|
||||
m_connected_regions[id1].connected_region_counts[id0]++;
|
||||
|
||||
connection_properties& prop0 = m_connected_regions[id0].connected_region_counts[id1];
|
||||
connection_properties& prop1 = m_connected_regions[id1].connected_region_counts[id0];
|
||||
|
||||
if (turn.cluster_id < 0)
|
||||
{
|
||||
// Turn is not colocated, add reference to connection
|
||||
prop0.count++;
|
||||
prop1.count++;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Turn is colocated, only add region reference if it was not yet registered
|
||||
if (prop0.cluster_indices.count(turn.cluster_id) == 0)
|
||||
{
|
||||
prop0.count++;
|
||||
}
|
||||
if (prop1.cluster_indices.count(turn.cluster_id) == 0)
|
||||
{
|
||||
prop1.count++;
|
||||
}
|
||||
}
|
||||
// Insert cluster-id (also -1 is inserted - reinsertion of
|
||||
// same cluster id is OK)
|
||||
prop0.cluster_indices.insert(turn.cluster_id);
|
||||
prop1.cluster_indices.insert(turn.cluster_id);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -225,6 +299,13 @@ struct traversal_switch_detector
|
||||
|
||||
inline bool connects_same_region(turn_type const& turn) const
|
||||
{
|
||||
if (turn.discarded)
|
||||
{
|
||||
// Discarded turns don't connect same region (otherwise discarded colocated uu turn
|
||||
// could make a connection)
|
||||
return false;
|
||||
}
|
||||
|
||||
if (turn.cluster_id == -1)
|
||||
{
|
||||
// If it is a uu/ii-turn (non clustered), it is never same region
|
||||
@ -248,7 +329,7 @@ struct traversal_switch_detector
|
||||
}
|
||||
|
||||
cluster_info const& cinfo = it->second;
|
||||
for (std::set<signed_size_type>::const_iterator sit = cinfo.turn_indices.begin();
|
||||
for (set_iterator sit = cinfo.turn_indices.begin();
|
||||
sit != cinfo.turn_indices.end(); ++sit)
|
||||
{
|
||||
turn_type const& cluster_turn = m_turns[*sit];
|
||||
@ -343,6 +424,13 @@ struct traversal_switch_detector
|
||||
{
|
||||
turn_type const& turn = m_turns[turn_index];
|
||||
|
||||
if (turn.discarded
|
||||
&& operation_from_overlay<OverlayType>::value == operation_intersection)
|
||||
{
|
||||
// Discarded turn (union currently still needs it to determine regions)
|
||||
continue;
|
||||
}
|
||||
|
||||
for (int op_index = 0; op_index < 2; op_index++)
|
||||
{
|
||||
turn_operation_type const& op = turn.operations[op_index];
|
||||
@ -388,6 +476,10 @@ struct traversal_switch_detector
|
||||
{
|
||||
signed_size_type turn_index = *sit;
|
||||
turn_type const& turn = m_turns[turn_index];
|
||||
if (turn.colocated_ii && ! turn.colocated_uu)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
for (int oi = 0; oi < 2; oi++)
|
||||
{
|
||||
int const region = get_region_id(turn.operations[oi]);
|
||||
@ -395,7 +487,7 @@ struct traversal_switch_detector
|
||||
}
|
||||
}
|
||||
// Switch source if this cluster connects the same region
|
||||
cinfo.switch_source = regions.size() == 1;
|
||||
cinfo.switch_source = regions.size() <= 1;
|
||||
}
|
||||
|
||||
// Iterate through all uu/ii turns (non-clustered)
|
||||
|
@ -91,8 +91,10 @@ struct turn_info
|
||||
method_type method;
|
||||
signed_size_type cluster_id; // For multiple turns on same location, >= 0. Else -1
|
||||
bool discarded;
|
||||
bool colocated_ii;
|
||||
bool colocated_uu;
|
||||
|
||||
// TODO: move this to enriched
|
||||
bool colocated_ii; // Colocated with a ii turn (TODO: or a ix turn)
|
||||
bool colocated_uu; // Colocated with a uu turn or a ux turn
|
||||
bool switch_source; // For u/u turns which can either switch or not
|
||||
|
||||
Container operations;
|
||||
@ -134,12 +136,6 @@ struct turn_info
|
||||
{
|
||||
return has(operation_blocked);
|
||||
}
|
||||
inline bool self_turn() const
|
||||
{
|
||||
return this->operations[0].seg_id.source_index
|
||||
== this->operations[1].seg_id.source_index;
|
||||
}
|
||||
|
||||
|
||||
private :
|
||||
inline bool has12(operation_type type1, operation_type type2) const
|
||||
|
@ -445,7 +445,7 @@ struct self_touches
|
||||
rescale_policy_type robust_policy;
|
||||
detail::self_get_turn_points::get_turns
|
||||
<
|
||||
policy_type
|
||||
false, policy_type
|
||||
>::apply(geometry, strategy, robust_policy, turns, policy, 0);
|
||||
|
||||
return policy.result();
|
||||
|
@ -811,6 +811,8 @@ BOOST_AUTO_TEST_CASE( test_is_valid_polygon )
|
||||
template <typename Point, bool AllowDuplicates>
|
||||
inline void test_open_multipolygons()
|
||||
{
|
||||
// WKT of multipolygons should be defined as ccw, open
|
||||
|
||||
#ifdef BOOST_GEOMETRY_TEST_DEBUG
|
||||
std::cout << std::endl << std::endl;
|
||||
std::cout << "************************************" << std::endl;
|
||||
@ -949,6 +951,18 @@ inline void test_open_multipolygons()
|
||||
test::apply("mpg20", open_mpgn, false);
|
||||
}
|
||||
|
||||
// Interior ring touches exterior ring, which at that same point touches another exterior ring in (1 2)
|
||||
test::apply
|
||||
("mpg21",
|
||||
"MULTIPOLYGON(((2 3,1 2,1 0,2 0,2 1,4 3),(2 2,1.5 1.5,1 2)),((0 3,0 2,1 2)))",
|
||||
true);
|
||||
|
||||
// Two interior rings touch each other in (10 5)
|
||||
test::apply
|
||||
("mpg22",
|
||||
"MULTIPOLYGON(((10 5,5 10,0 5,5 0),(10 5,5 4,4 6)),((10 5,10 0,20 0,20 10,10 10),(10 5,18 8,15 3)))",
|
||||
true);
|
||||
|
||||
// MySQL report 12.06.2015
|
||||
{
|
||||
std::string wkt = "MULTIPOLYGON("
|
||||
|
@ -558,6 +558,77 @@ static std::string case_130_multi[2] =
|
||||
"MULTIPOLYGON(((0 0,0 7,7 7,7 0,0 0),(4 3,5 4,4 5,3 4,4 3),(1 2,2 1,3 2,2 3,1 2)))"
|
||||
};
|
||||
|
||||
static std::string case_131_multi[2] =
|
||||
{
|
||||
// For validity, interior ring connections
|
||||
"MULTIPOLYGON(((1 2,1 3,2 3,2 2,1 2)),((2 1,2 2,3 2,3 1,2 1)))",
|
||||
"MULTIPOLYGON(((0 0,0 4,4 4,4 0,0 0),(3 3,1 3,1 1,3 1,3 3)))"
|
||||
};
|
||||
|
||||
static std::string case_132_multi[2] =
|
||||
{
|
||||
// For validity, interior ring connections including cluster
|
||||
"MULTIPOLYGON(((2 4,2 6,4 6,4 4,2 4)),((4 2,4 4,6 4,6 2,4 2)))",
|
||||
"MULTIPOLYGON(((0 0,0 8,8 8,8 0,0 0),(6 6,2 6,2 2,6 2,6 6)),((2 2,2.5 3.5,4 4,3.5 2.5,2 2)),((4 4,4.5 5.5,6 6,5.5 4.5,4 4)))"
|
||||
};
|
||||
|
||||
static std::string case_133_multi[2] =
|
||||
{
|
||||
// Zoomed in version of case_recursive_boxes_49 with in both interiors an extra polygon (same for both)
|
||||
"MULTIPOLYGON(((0 0,0 4,2 4,2 6,4 6,4 8,10 8,10 4,8 4,8 0,0 0),(4 4,4 6,6 6,6 4,4 4)),((5 4.5,4 6,5.5 5, 5 4.5)))",
|
||||
"MULTIPOLYGON(((2 0,2 8,8 8,8 6,10 6,10 2,6 2,6 0,2 0),(6 6,6 4,4 4,4 6,6 6)),((5 4.5,4 6,5.5 5, 5 4.5)))"
|
||||
};
|
||||
|
||||
static std::string case_134_multi[2] =
|
||||
{
|
||||
// Zoomed in version of case_recursive_boxes_49 with two interior rings
|
||||
"MULTIPOLYGON(((0 0,0 4,2 4,2 6,4 6,4 8,10 8,10 4,8 4,8 0,0 0),(3 4,4 6,4 4,3 4),(6 6,4 6,6 7,6 6)))",
|
||||
"MULTIPOLYGON(((2 0,2 8,8 8,8 6,10 6,10 2,6 2,6 0,2 0),(3 4,4 6,4 4,3 4),(6 6,4 6,6 7,6 6)))"
|
||||
};
|
||||
|
||||
static std::string case_135_multi[2] =
|
||||
{
|
||||
// Contains two equal interior rings, both touching to their exterior rings
|
||||
// Needs detection of isolated interior ring pattern
|
||||
"MULTIPOLYGON(((5 8,4 8,4 7,3 7,3 6,2 6,2 7,1 7,1 10,3 10,3 9,5 9,5 8),(3 8,3 9,2 9,2 8,3 8)))",
|
||||
"MULTIPOLYGON(((5 4,4 4,3 4,3 7,1 7,1 8,0 8,0 9,1 9,1 10,3 10,3 9,4 9,4 8,6 8,6 9,7 9,7 5,6 5,6 4,5 4),(5 5,5 6,6 6,6 7,4 7,4 5,5 5),(3 8,3 9,2 9,2 8,3 8)))"
|
||||
};
|
||||
|
||||
static std::string case_136_multi[2] =
|
||||
{
|
||||
// Variant of 135, but approaching cluster is non equal
|
||||
"MULTIPOLYGON(((5 8,4 8,4 7,3 7,3 6,2 6,2 7,1 7,1 10,2 10,3 9,5 9,5 8),(3 8,3 9,2 9,2 8,3 8)))",
|
||||
"MULTIPOLYGON(((5 4,4 4,3 4,3 7,1 7,1 8,0 8,0 9,1 9,1 10,3 10,3 9,4 9,4 8,6 8,6 9,7 9,7 5,6 5,6 4,5 4),(5 5,5 6,6 6,6 7,4 7,4 5,5 5),(3 8,3 9,2 9,2 8,3 8)))"
|
||||
};
|
||||
|
||||
static std::string case_137_multi[2] =
|
||||
{
|
||||
// Variant of 135, but leaving cluster is non equal
|
||||
"MULTIPOLYGON(((5 8,4 8,4 7,3 7,3 6,2 6,2 7,1 7,1 10,3 10,3 9,5 9,5 8),(3 8,3 9,2 9,2 8,3 8)))",
|
||||
"MULTIPOLYGON(((5 4,4 4,3 4,3 7,1 7,1 8,0 8,0 9,1 9,1 10,3 10,3 9,4 8,6 8,6 9,7 9,7 5,6 5,6 4,5 4),(5 5,5 6,6 6,6 7,4 7,4 5,5 5),(3 8,3 9,2 9,2 8,3 8)))"
|
||||
};
|
||||
|
||||
static std::string case_138_multi[2] =
|
||||
{
|
||||
// Zoomed in version of case_recursive_boxes_49 with in both interiors an extra polygon (different for both)
|
||||
"MULTIPOLYGON(((0 0,0 4,2 4,2 6,4 6,4 8,10 8,10 4,8 4,8 0,0 0),(4 4,4 6,6 6,6 4,4 4)),((4.5 4.5,4 6,5.5 5.5,4.5 4.5)))",
|
||||
"MULTIPOLYGON(((2 0,2 8,8 8,8 6,10 6,10 2,6 2,6 0,2 0),(6 6,6 4,4 4,4 6,6 6)),((5 4.5,4 6,5.5 5, 5 4.5)))"
|
||||
};
|
||||
|
||||
static std::string case_139_multi[2] =
|
||||
{
|
||||
// Another zoomed in version of case_recursive_boxes_49 with different interior polygons
|
||||
"MULTIPOLYGON(((0 0,0 4,2 4,2 6,4 6,4 8,10 8,10 4,8 4,8 0,0 0),(4 4,4 6,6 6,6 4,4 4)),((4.5 4.5,4 6,5.5 5,4.5 4.5)))",
|
||||
"MULTIPOLYGON(((2 0,2 8,8 8,8 6,10 6,10 2,6 2,6 0,2 0),(6 6,6 4,4 4,4 6,6 6)),((5 4.5,4 6,5.5 5, 5 4.5)))"
|
||||
};
|
||||
|
||||
static std::string case_140_multi[2] =
|
||||
{
|
||||
// Another zoomed in version of case_recursive_boxes_49 with different interior polygons
|
||||
"MULTIPOLYGON(((0 0,0 4,2 4,2 6,4 6,4 8,10 8,10 4,8 4,8 0,0 0),(4 4,4 6,6 6,6 4,4 4)),((5 4.5,4 6,5.5 5.5,5 4.5)))",
|
||||
"MULTIPOLYGON(((2 0,2 8,8 8,8 6,10 6,10 2,6 2,6 0,2 0),(6 6,6 4,4 4,4 6,6 6)),((5 4.5,4 6,5.5 5, 5 4.5)))"
|
||||
};
|
||||
|
||||
static std::string case_recursive_boxes_1[2] =
|
||||
{
|
||||
"MULTIPOLYGON(((1 0,0 0,0 1,1 1,1 2,0 2,0 4,2 4,2 5,3 5,3 6,1 6,1 5,0 5,0 10,9 10,9 9,7 9,7 8,6 8,6 7,8 7,8 6,9 6,9 4,8 4,8 3,10 3,10 0,6 0,6 1,5 1,5 0,1 0),(8 4,8 5,7 5,7 6,6 6,6 5,5 5,5 4,4 4,4 3,5 3,5 2,7 2,7 3,6 3,6 4,8 4),(8 1,9 1,9 2,8 2,8 1),(4 7,4 9,3 9,3 7,4 7)),((9 9,10 9,10 7,10 6,9 6,9 7,8 7,8 8,9 8,9 9)))",
|
||||
@ -918,6 +989,97 @@ static std::string case_recursive_boxes_47[2] =
|
||||
"MULTIPOLYGON(((4 5,4 4,1 4,1 5,4 5)),((5 6,5 7,6 7,6 6,5 6)),((5 6,5 5,4 5,4 6,5 6)),((5 3,5 5,6 5,6 3,5 3)),((5 3,5 2,4 2,4 3,5 3)),((6 5,6 6,7 6,7 5,6 5)),((3 7,2 7,2 9,3 9,3 8,4 8,4 7,3 7)))"
|
||||
};
|
||||
|
||||
static std::string case_recursive_boxes_48[2] =
|
||||
{
|
||||
// Needs discarding self-ii turns not located within the other geometry
|
||||
"MULTIPOLYGON(((6 7,6 8,7 8,7 7,6 7)))",
|
||||
"MULTIPOLYGON(((9 9,10 9,10 7,9 7,9 5,8 5,8 6,7 6,7 7,6 7,6 8,7 8,7 9,8 9,8 10,9 10,9 9),(9 8,8 8,8 7,9 7,9 8)))"
|
||||
};
|
||||
|
||||
static std::string case_recursive_boxes_49[2] =
|
||||
{
|
||||
// Needs specific handling for cc interior rings touching one exterior ring
|
||||
"MULTIPOLYGON(((5 2,5 3,4 3,4 4,5 4,5 5,6 5,6 2,7 2,7 1,0 1,0 3,1 3,1 2,5 2)),((5 7,5 8,6 8,6 9,7 9,7 10,10 10,10 8,9 8,9 6,10 6,10 4,9 4,9 3,8 3,8 4,7 4,7 6,5 6,5 7),(7 6,8 6,8 7,7 7,7 6),(8 9,7 9,7 8,8 8,8 9)),((2 6,4 6,4 5,3 5,3 4,1 4,1 5,2 5,2 6)),((3 10,4 10,4 7,2 7,2 10,3 10)))",
|
||||
"MULTIPOLYGON(((5 1,4 1,4 3,3 3,3 6,2 6,2 9,5 9,5 7,4 7,4 4,5 4,5 3,6 3,6 2,8 2,8 1,9 1,9 0,5 0,5 1),(4 7,4 8,3 8,3 7,4 7)),((8 2,8 3,9 3,9 2,8 2)),((9 5,9 6,10 6,10 5,9 5)),((9 5,9 4,8 4,8 5,9 5)),((7 5,7 4,6 4,6 5,7 5)),((7 10,9 10,9 9,10 9,10 7,8 7,8 6,6 6,6 10,7 10),(7 9,7 8,8 8,8 9,7 9)))"
|
||||
};
|
||||
|
||||
static std::string case_recursive_boxes_50[2] =
|
||||
{
|
||||
// Same as 49 but needs the second variant
|
||||
"MULTIPOLYGON(((6 9,6 10,7 10,7 9,6 9)),((5 6,6 6,6 5,4 5,4 7,3 7,3 8,4 8,4 9,2 9,2 10,5 10,5 8,6 8,6 7,5 7,5 6)),((4 0,1 0,1 1,2 1,2 2,3 2,3 3,5 3,5 0,4 0)),((3 5,3 3,1 3,1 4,0 4,0 6,1 6,1 7,0 7,0 8,2 8,2 6,3 6,3 5),(2 5,1 5,1 4,2 4,2 5)),((1 1,0 1,0 2,1 2,1 1)),((6 5,7 5,7 4,6 4,6 5)),((10 5,8 5,8 6,9 6,9 7,10 7,10 5)),((6 0,6 1,8 1,8 2,10 2,10 0,6 0)),((9 7,7 7,7 8,8 8,8 9,9 9,9 7)),((8 2,6 2,6 3,8 3,8 2)),((9 9,9 10,10 10,10 9,9 9)))",
|
||||
"MULTIPOLYGON(((5 3,5 4,6 4,6 3,5 3)),((5 7,6 7,6 5,4 5,4 6,3 6,3 7,4 7,4 8,5 8,5 7)),((3 6,3 4,4 4,4 3,1 3,1 2,0 2,0 9,1 9,1 10,3 10,3 9,2 9,2 8,3 8,3 7,1 7,1 6,3 6),(1 5,1 4,2 4,2 5,1 5)),((4 0,0 0,0 1,1 1,1 2,3 2,3 1,5 1,5 0,4 0)),((7 6,7 7,8 7,8 8,9 8,9 6,8 6,8 5,7 5,7 6)),((9 0,7 0,7 1,9 1,9 2,10 2,10 0,9 0)),((7 9,5 9,5 10,7 10,7 9)),((7 9,8 9,8 8,7 8,7 9)),((8 3,8 2,7 2,7 3,8 3)),((8 3,8 4,9 4,9 3,8 3)),((8 9,8 10,9 10,9 9,8 9)),((9 8,9 9,10 9,10 8,9 8)))"
|
||||
};
|
||||
|
||||
static std::string case_recursive_boxes_51[2] =
|
||||
{
|
||||
// Needs keeping colocated turns with a xx turn to properly generate interior rings. It also needs self-turns for validity
|
||||
"MULTIPOLYGON(((0 4,0 5,1 5,1 4,0 4)),((2 1,3 1,3 0,2 0,2 1)),((3 3,4 3,4 2,3 2,3 3)),((5 4,6 4,6 3,5 3,5 4)),((2 3,2 4,3 4,3 3,2 3)),((5 6,4 6,4 5,3 5,3 10,4 10,4 9,5 9,5 8,4 8,4 7,6 7,6 9,7 9,7 10,8 10,8 8,7 8,7 7,8 7,8 4,7 4,7 5,6 5,6 6,5 6)),((5 0,4 0,4 1,5 1,5 2,6 2,6 3,7 3,7 1,8 1,8 0,5 0)),((0 2,1 2,1 1,0 1,0 2)),((1 2,1 3,2 3,2 2,1 2)),((1 10,2 10,2 8,1 8,1 9,0 9,0 10,1 10)),((1 8,1 7,0 7,0 8,1 8)),((10 1,10 0,9 0,9 1,8 1,8 4,9 4,9 6,10 6,10 1)))",
|
||||
"MULTIPOLYGON(((3 1,4 1,4 0,2 0,2 1,3 1)),((1 9,0 9,0 10,1 10,1 9)),((8 2,9 2,9 1,10 1,10 0,8 0,8 2)),((5 8,4 8,4 9,5 9,5 10,7 10,7 8,8 8,8 7,7 7,7 6,8 6,8 7,10 7,10 6,9 6,9 3,8 3,8 2,6 2,6 1,5 1,5 3,7 3,7 4,4 4,4 5,5 5,5 6,6 6,6 8,5 8),(7 5,7 4,8 4,8 5,7 5)),((4 4,4 3,2 3,2 4,1 4,1 5,0 5,0 7,1 7,1 9,2 9,2 8,4 8,4 6,3 6,3 4,4 4),(1 5,2 5,2 6,1 6,1 5)),((0 3,1 3,1 1,0 1,0 3)),((4 9,3 9,3 10,4 10,4 9)),((9 10,10 10,10 9,9 9,9 8,8 8,8 10,9 10)))"
|
||||
};
|
||||
|
||||
static std::string case_recursive_boxes_52[2] =
|
||||
{
|
||||
// Needs checking for isolated in handling of cc_ii clusters for intersection
|
||||
"MULTIPOLYGON(((0 0,0 1,1 1,1 0,0 0)),((5 1,2 1,2 3,1 3,1 4,0 4,0 8,1 8,1 9,2 9,2 8,5 8,5 5,6 5,6 7,7 7,7 9,9 9,9 10,10 10,10 7,9 7,9 6,10 6,10 5,9 5,9 1,8 1,8 2,7 2,7 3,6 3,6 4,5 4,5 2,6 2,6 0,5 0,5 1),(4 4,4 5,3 5,3 6,4 6,4 7,1 7,1 6,2 6,2 5,3 5,3 4,4 4),(7 5,7 4,8 4,8 6,7 6,7 5),(2 5,1 5,1 4,2 4,2 5)),((5 8,5 9,6 9,6 8,5 8)),((8 1,8 0,7 0,7 1,8 1)))",
|
||||
"MULTIPOLYGON(((1 1,2 1,2 0,1 0,1 1)),((9 10,10 10,10 9,9 9,9 10)),((3 9,3 10,4 10,4 9,3 9)),((1 10,2 10,2 9,0 9,0 10,1 10)),((5 4,4 4,4 3,3 3,3 2,1 2,1 1,0 1,0 3,2 3,2 4,1 4,1 5,5 5,5 7,6 7,6 6,7 6,7 8,9 8,9 7,8 7,8 6,9 6,9 4,8 4,8 3,10 3,10 2,8 2,8 1,7 1,7 0,6 0,6 2,7 2,7 3,6 3,6 4,5 4),(8 5,7 5,7 4,8 4,8 5)),((5 9,5 10,8 10,8 9,6 9,6 8,5 8,5 9)),((4 0,3 0,3 1,4 1,4 2,5 2,5 0,4 0)),((3 8,4 8,4 6,2 6,2 8,3 8)),((9 1,9 0,8 0,8 1,9 1)),((9 7,10 7,10 6,9 6,9 7)))"
|
||||
};
|
||||
|
||||
static std::string case_recursive_boxes_53[2] =
|
||||
{
|
||||
// Needs checking for intersection patterns intersection_pattern_common_interior2 with ii
|
||||
"MULTIPOLYGON(((2 0,0 0,0 5,5 5,4 4,5 4,5 0,2 0),(2.5 4.5,3 4,3 5,2.5 4.5),(3 1,4 0,4 1,3 1),(3 3,4 2,4 3,3 3)))",
|
||||
"MULTIPOLYGON(((2 0,0 0,0 5,1 5,0.5 4.5,1 4,2 5,5 5,5 0,2 0),(2 3,2 4,1 4,2 3),(3 1,3 2,2 2,2 1,3 1),(1 3,0 2,1 2,1 3),(1 0,1 1,0.5 0.5,1 0),(5 3,4 3,4 2,5 3),(4 1,3.5 0.5,4 0,4 1)))"
|
||||
};
|
||||
|
||||
static std::string case_recursive_boxes_54[2] =
|
||||
{
|
||||
// Needs including blocked from-ranks/operations in aggregations
|
||||
"MULTIPOLYGON(((2 2,2 3,1 3,1 5,2 4,2 5,5 5,5 4,4 3,5 3,5 2,4 2,4 1,5 0,2 0,2 1,1 1,1 2,2 2),(3 2,2.5 1.5,3 1,4 2,3 2),(3 2,3 3,2.5 2.5,3 2),(3 4,3 3,4 4,3 4)),((1 1,1 0,0 0,0 1,1 1)),((1 3,1 2,0 1,0 3,1 3)))",
|
||||
"MULTIPOLYGON(((2 2,3 3,2 3,2 5,5 5,5 3,4 3,3 2,5 2,5 1,4 1,3 0,1 0,1 1,0 1,0 2,2 2)),((0 4,0 5,1 5,1 4,0 3,0 4)))"
|
||||
};
|
||||
|
||||
static std::string case_recursive_boxes_55[2] =
|
||||
{
|
||||
// Needs correct handling for union clusters with 3 open spaces
|
||||
"MULTIPOLYGON(((3 4,3 5,4 5,3 4)),((0 4,1 4,1 3,0 3,0 4)),((2 1,1.5 0.5,2 0,1 0,1 1,0 1,0 2,2 2,2 1)),((3 2,3 3,4 2,4 3,5 2,4 1,2 1,3 2)),((2 2,2 3,3 3,2 2)))",
|
||||
"MULTIPOLYGON(((2 1,2 0,1 0,2 1)),((2 1,2 2,3 2,3 1,2 1)),((1 3,1 4,2 5,2 2,1 2,0 1,0 4,1 3)),((5 4,4 3,3 3,4 4,3 4,3 5,5 5,5 4)),((1 0,0 0,1 1,1 0)),((0 4,0 5,1 5,0 4)))"
|
||||
};
|
||||
|
||||
static std::string case_recursive_boxes_56[2] =
|
||||
{
|
||||
// Needs not discarding clustered self-turns if the cluster does not contain anything else
|
||||
"MULTIPOLYGON(((3 4,3 5,4 5,3 4)),((3 3,4 3,2 1,2 3,3 3)),((2 1,2 0,1 0,1 1,2 1)),((1 4,1 3,0 3,0 4,1 5,1 4)))",
|
||||
"MULTIPOLYGON(((2 4,2 5,3 4,2 4)),((1 5,1 4,0 4,0 5,1 5)),((1 2,0 2,0 3,1 2)),((2 2,1 2,2 3,2 2)),((2 2,2 1,1 1,1 2,1.5 1.5,2 2)))"
|
||||
};
|
||||
|
||||
static std::string case_recursive_boxes_57[2] =
|
||||
{
|
||||
// Needs handling of 3 open spaces in union to form interior ring
|
||||
"MULTIPOLYGON(((2 0,0 0,0 1,0.5 0.5,1 1,1 2,2 1,4 1,4 4,5 3,5 0,2 0)),((2 5,2 4,1 4,1 5,2 5)),((1 2,0 2,0 3,1 2)),((1 2,1 3,2 3,2 2,1 2)),((0 1,0 2,1 1,0 1)),((4 3,3 3,3 4,4 3)),((3 4,3 5,5 5,5 4,3 4)))",
|
||||
"MULTIPOLYGON(((3 3,2 3,2 5,3 4,3 5,5 5,5 4,4 4,4 3,3 3)),((3 3,4 2,2 2,3 3)),((0 0,0 4,1 4,1 3,2 3,2 2,1 2,1 0,0 0)),((3 1,2 1,2 2,3 1)),((1 5,0 4,0 5,1 5)),((1 5,2 5,1 4,1 5)),((5 2,5 1,4 1,4 3,5 4,5 2)),((4 1,4 0,3 0,3 1,4 1)),((2 1,2 0,1 0,2 1)))",
|
||||
};
|
||||
|
||||
static std::string case_recursive_boxes_58[2] =
|
||||
{
|
||||
// Needs correct handling for union clusters with 3 open spaces
|
||||
"MULTIPOLYGON(((0 0,1 1,2 1,1 0,0 0)),((1 1,1 2,2 2,1 1)),((3 1,4 2,4 1,3 1)),((3 2,3 3,4 3,3 2)))",
|
||||
"MULTIPOLYGON(((0 1,0 2,1 1,0 1)),((1 1,1 2,2 1,1 1)),((1 2,1 3,2 2,1 2)),((2 2,2 3,3 2,2 2)),((4 2,4 3,5 3,4 2)),((1 0,2 1,2 2,3 1,2 0,1 0)))",
|
||||
};
|
||||
|
||||
static std::string case_recursive_boxes_59[2] =
|
||||
{
|
||||
// Needs correct handling for union clusters with 3 open spaces
|
||||
"MULTIPOLYGON(((2 3,2 2,3 2,3 1,2 1,1.5 0.5,2 0,0 0,0 1,1 1,1 4,2 4,3 5,5 5,5 4,3 4,3 3,2 3)),((3 2,3 3,4 3,4 2,3 2)),((2 0,3 1,5 1,5 0,2 0)),((0 3,0 5,1 5,1 4,0 3)),((0 3,1 3,0 2,0 3)))",
|
||||
"MULTIPOLYGON(((3 5,3 4,4 4,4 3,5 3,5 2,4 2,4 1,3.5 0.5,4 0,1 0,1 1,2 2,1 2,1 4,0 4,1 5,3 5),(2 3,2 4,1 3,2 3),(2 2,3 2,3 3,2 2)),((1 1,0 1,0 3,1 2,1 1)))",
|
||||
};
|
||||
|
||||
static std::string case_recursive_boxes_60[2] =
|
||||
{
|
||||
// Needs checking left_count in union clusters
|
||||
"MULTIPOLYGON(((0 4,0 5,1 5,0 4)),((1 2,1 4,2 4,2 5,3 4,4 5,5 5,5 4,4 4,3.5 3.5,4 3,4 2,3 2,2 1,2 2,1 2)),((1 2,2 1,1 1,1 2)),((2 1,3 1,4 2,5 1,4 1,4 0,2 0,2 1)),((0 0,0 2,2 0,0 0)),((0 2,0 3,1 3,0 2)),((5 4,5 3,4 3,5 4)))",
|
||||
"MULTIPOLYGON(((2 3,1 2,1 4,0 4,0 5,3 5,3 3,2 3)),((1 2,3 2,3 3,4 4,5 4,5 3,4 3,3.5 2.5,4 2,4 0,0 0,0 1,1 1,1 2)),((4 2,5 3,5 2,4 2)))",
|
||||
};
|
||||
|
||||
static std::string pie_21_7_21_0_3[2] =
|
||||
{
|
||||
"MULTIPOLYGON(((2500 2500,2500 3875,2855 3828,3187 3690,3472 3472,3690 3187,3828 2855,3875 2500,3828 2144,3690 1812,3472 1527,3187 1309,2855 1171,2499 1125,2144 1171,1812 1309,1527 1527,1309 1812,1171 2144,1125 2499,1171 2855,1309 3187,2500 2500)))",
|
||||
|
@ -347,10 +347,21 @@ void test_overlay(std::string const& caseid,
|
||||
bg::correct(g2);
|
||||
|
||||
#if defined(TEST_WITH_SVG)
|
||||
bool const ccw = bg::point_order<Geometry>::value == bg::counterclockwise;
|
||||
bool const open = bg::closure<Geometry>::value == bg::open;
|
||||
|
||||
std::ostringstream filename;
|
||||
filename << "overlay"
|
||||
<< "_" << caseid
|
||||
<< "_" << string_from_type<typename bg::coordinate_type<Geometry>::type>::name()
|
||||
<< (ccw ? "_ccw" : "")
|
||||
<< (open ? "_open" : "")
|
||||
#ifdef BOOST_GEOMETRY_INCLUDE_SELF_TURNS
|
||||
<< "_self"
|
||||
#endif
|
||||
#if defined(BOOST_GEOMETRY_NO_ROBUSTNESS)
|
||||
<< "_no_rob"
|
||||
#endif
|
||||
<< ".svg";
|
||||
|
||||
std::ofstream svg(filename.str().c_str());
|
||||
@ -372,8 +383,13 @@ void test_overlay(std::string const& caseid,
|
||||
typedef typename boost::range_value<Geometry>::type geometry_out;
|
||||
typedef bg::detail::overlay::overlay
|
||||
<
|
||||
Geometry, Geometry, false, OverlayType == bg::overlay_difference,
|
||||
false, geometry_out,
|
||||
Geometry, Geometry,
|
||||
bg::detail::overlay::do_reverse<bg::point_order<Geometry>::value>::value,
|
||||
OverlayType == bg::overlay_difference
|
||||
? ! bg::detail::overlay::do_reverse<bg::point_order<Geometry>::value>::value
|
||||
: bg::detail::overlay::do_reverse<bg::point_order<Geometry>::value>::value,
|
||||
bg::detail::overlay::do_reverse<bg::point_order<Geometry>::value>::value,
|
||||
geometry_out,
|
||||
OverlayType
|
||||
> overlay;
|
||||
|
||||
@ -434,11 +450,11 @@ void test_overlay(std::string const& caseid,
|
||||
#define TEST_UNION_WITH(caseid, index1, index2, area, clips, holes) (test_overlay<multi_polygon, bg::overlay_union>) \
|
||||
( #caseid "_union" #index1 "_" #index2, caseid[index1], caseid[index2], area, clips, holes)
|
||||
|
||||
template <typename T>
|
||||
template <typename T, bool Clockwise>
|
||||
void test_all()
|
||||
{
|
||||
typedef bg::model::point<T, 2, bg::cs::cartesian> point_type;
|
||||
typedef bg::model::polygon<point_type> polygon;
|
||||
typedef bg::model::polygon<point_type, Clockwise> polygon;
|
||||
typedef bg::model::multi_polygon<polygon> multi_polygon;
|
||||
|
||||
TEST_UNION(case_multi_simplex, 14.58, 1, 0);
|
||||
@ -482,6 +498,7 @@ void test_all()
|
||||
|
||||
int test_main(int, char* [])
|
||||
{
|
||||
test_all<double>();
|
||||
test_all<double, true>();
|
||||
// test_all<double, false>();
|
||||
return 0;
|
||||
}
|
||||
|
@ -35,9 +35,16 @@
|
||||
#endif
|
||||
|
||||
|
||||
#define TEST_DIFFERENCE(caseid, clips1, points1, area1, clips2, points2, area2) \
|
||||
// Convenience macros (points are not checked)
|
||||
#define TEST_DIFFERENCE(caseid, clips1, area1, clips2, area2, clips3) \
|
||||
(test_one<polygon, polygon, polygon>) \
|
||||
( #caseid, caseid[0], caseid[1], clips1, points1, area1, clips2, points2, area2)
|
||||
( #caseid, caseid[0], caseid[1], clips1, -1, area1, clips2, -1, area2, \
|
||||
clips3, -1, area1 + area2)
|
||||
|
||||
#define TEST_DIFFERENCE_IGNORE(caseid, clips1, area1, clips2, area2, clips3) \
|
||||
(test_one<polygon, polygon, polygon>) \
|
||||
( #caseid, caseid[0], caseid[1], clips1, -1, area1, clips2, -1, area2, \
|
||||
clips3, -1, area1 + area2, ignore_validity)
|
||||
|
||||
template <typename P>
|
||||
void test_all()
|
||||
@ -232,9 +239,9 @@ void test_all()
|
||||
4, 18, 1.5,
|
||||
3, 15, 4.0625);
|
||||
|
||||
TEST_DIFFERENCE(case_105, 4, 20, 8.0, 1, 9, 16.0);
|
||||
TEST_DIFFERENCE(case_106, 1, 12, 17.5, 2, 9, 32.5);
|
||||
TEST_DIFFERENCE(case_107, 2, 16, 18.0, 2, 16, 29.0);
|
||||
TEST_DIFFERENCE(case_105, 4, 8.0, 1, 16.0, 5);
|
||||
TEST_DIFFERENCE(case_106, 1, 17.5, 2, 32.5, 3);
|
||||
TEST_DIFFERENCE(case_107, 2, 18.0, 2, 29.0, 4);
|
||||
|
||||
test_one<polygon, polygon, polygon>("winded",
|
||||
winded[0], winded[1],
|
||||
@ -523,57 +530,36 @@ void test_all()
|
||||
***/
|
||||
|
||||
// Should have 2 outputs
|
||||
int const correction_for_invalidity = 1; // should be 0
|
||||
test_one<polygon, polygon, polygon>("mysql_21977775",
|
||||
mysql_21977775[0], mysql_21977775[1],
|
||||
2 - correction_for_invalidity, -1, 160.856568913,
|
||||
2, -1, 92.3565689126,
|
||||
ignore_validity);
|
||||
|
||||
// also mysql_23023665
|
||||
test_one<polygon, polygon, polygon>("mysql_21965285",
|
||||
mysql_21965285[0], mysql_21965285[1],
|
||||
1, 2, -1, 92.0,
|
||||
1, 1, -1, 14.0,
|
||||
1, 2, -1, 92.0 + 14.0);
|
||||
|
||||
test_one<polygon, polygon, polygon>("mysql_23023665_1",
|
||||
mysql_23023665_1[0], mysql_23023665_1[1],
|
||||
1, 2, -1, 92.0,
|
||||
1, 1, -1, 142.5,
|
||||
ignore_validity);
|
||||
|
||||
test_one<polygon, polygon, polygon>("mysql_23023665_2",
|
||||
mysql_23023665_2[0], mysql_23023665_2[1],
|
||||
1, 2, -1, 96.0,
|
||||
1, 1, -1, 16.0,
|
||||
ignore_validity);
|
||||
|
||||
test_one<polygon, polygon, polygon>("mysql_23023665_3",
|
||||
mysql_23023665_3[0], mysql_23023665_3[1],
|
||||
1, 2, -1, 225.0,
|
||||
1, 1, -1, 66.0,
|
||||
ignore_validity);
|
||||
|
||||
test_one<polygon, polygon, polygon>("mysql_23023665_5",
|
||||
mysql_23023665_5[0], mysql_23023665_5[1],
|
||||
2 - correction_for_invalidity, 2 - correction_for_invalidity, -1, 165.23735,
|
||||
2, 2, -1, 105.73735,
|
||||
ignore_validity);
|
||||
|
||||
test_one<polygon, polygon, polygon>("mysql_23023665_6",
|
||||
mysql_23023665_6[0], mysql_23023665_6[1],
|
||||
2, 2, -1, 105.68756,
|
||||
3, 3, -1, 10.18756
|
||||
#if defined(BOOST_GEOMETRY_NO_ROBUSTNESS)
|
||||
, ignore_validity
|
||||
#ifdef BOOST_GEOMETRY_INCLUDE_SELF_TURNS
|
||||
TEST_DIFFERENCE(mysql_21977775,
|
||||
2, 160.856568913, 2, 92.3565689126, 4);
|
||||
#else
|
||||
TEST_DIFFERENCE_IGNORE(mysql_21977775,
|
||||
1, 160.856568913, 2, 92.3565689126, 3);
|
||||
#endif
|
||||
|
||||
TEST_DIFFERENCE(mysql_21965285, 1, 92.0, 1, 14.0, 1);
|
||||
|
||||
TEST_DIFFERENCE_IGNORE(mysql_23023665_1, 1, 92.0, 1, 142.5, 2);
|
||||
TEST_DIFFERENCE_IGNORE(mysql_23023665_2, 1, 96.0, 1, 16.0, 2);
|
||||
TEST_DIFFERENCE_IGNORE(mysql_23023665_3, 1, 225.0, 1, 66.0, 2);
|
||||
#ifdef BOOST_GEOMETRY_INCLUDE_SELF_TURNS
|
||||
TEST_DIFFERENCE(mysql_23023665_5, 2, 165.23735, 2, 105.73735, 4);
|
||||
#else
|
||||
TEST_DIFFERENCE_IGNORE(mysql_23023665_5, 1, 165.23735, 2, 105.73735, 3);
|
||||
#endif
|
||||
|
||||
#if defined(BOOST_GEOMETRY_NO_ROBUSTNESS)
|
||||
TEST_DIFFERENCE(mysql_23023665_6, 2, 105.68756, 3, 10.18756, 5);
|
||||
#else
|
||||
TEST_DIFFERENCE_IGNORE(mysql_23023665_6, 2, 105.68756, 3, 10.18756, 5);
|
||||
#endif
|
||||
|
||||
#ifdef BOOST_GEOMETRY_INCLUDE_SELF_TURNS
|
||||
TEST_DIFFERENCE(mysql_23023665_13, 3, 99.74526, 3, 37.74526, 6);
|
||||
#else
|
||||
TEST_DIFFERENCE_IGNORE(mysql_23023665_13, 2, 99.74526, 3, 37.74526, 5);
|
||||
#endif
|
||||
);
|
||||
test_one<polygon, polygon, polygon>("mysql_23023665_13",
|
||||
mysql_23023665_13[0], mysql_23023665_13[1],
|
||||
3 - correction_for_invalidity, 3 - correction_for_invalidity, -1, 99.74526,
|
||||
3, 3, -1, 37.74526,
|
||||
ignore_validity);
|
||||
}
|
||||
|
||||
|
||||
@ -599,21 +585,17 @@ void test_specific()
|
||||
2, 8, 489763.5,
|
||||
1, 4, 6731652.0);
|
||||
|
||||
{
|
||||
ut_settings settings;
|
||||
settings.test_validity = false;
|
||||
#ifdef BOOST_GEOMETRY_TEST_INCLUDE_FAILING_TESTS
|
||||
settings.test_validity = true;
|
||||
#endif
|
||||
|
||||
// Generates spikes, both a-b and b-a
|
||||
test_one<polygon, polygon, polygon>("ticket_11676",
|
||||
ticket_11676[0], ticket_11676[1],
|
||||
1, 18, 2537992.5,
|
||||
2, 11, 294963.5,
|
||||
2, -1, 2537992.5 + 294963.5,
|
||||
settings);
|
||||
}
|
||||
// Generates spikes, both a-b and b-a
|
||||
#ifdef BOOST_GEOMETRY_INCLUDE_SELF_TURNS
|
||||
TEST_DIFFERENCE(ticket_11676, 2, 2537992.5, 2, 294963.5, 3);
|
||||
#else
|
||||
|
||||
ut_settings ignore_validity;
|
||||
ignore_validity.test_validity = false;
|
||||
|
||||
TEST_DIFFERENCE_IGNORE(ticket_11676, 1, 2537992.5, 2, 294963.5, 2);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
@ -23,13 +23,24 @@
|
||||
|
||||
#include <boost/geometry/io/wkt/read.hpp>
|
||||
|
||||
#define TEST_DIFFERENCE(caseid, clips1, points1, area1, clips2, points2, area2) \
|
||||
// Convenience macros (points are not checked)
|
||||
#define TEST_DIFFERENCE(caseid, clips1, area1, clips2, area2, clips3) \
|
||||
(test_one<Polygon, MultiPolygon, MultiPolygon>) \
|
||||
( #caseid, caseid[0], caseid[1], clips1, points1, area1, clips2, points2, area2)
|
||||
( #caseid, caseid[0], caseid[1], clips1, -1, area1, clips2, -1, area2, \
|
||||
clips3, -1, area1 + area2)
|
||||
|
||||
#define TEST_DIFFERENCE_IGNORE(caseid, clips1, points1, area1, clips2, points2, area2) \
|
||||
#define TEST_DIFFERENCE_IGNORE(caseid, clips1, area1, clips2, area2, clips3) \
|
||||
(test_one<Polygon, MultiPolygon, MultiPolygon>) \
|
||||
( #caseid, caseid[0], caseid[1], clips1, points1, area1, clips2, points2, area2, ignore_validity)
|
||||
( #caseid, caseid[0], caseid[1], clips1, -1, area1, clips2, -1, area2, \
|
||||
clips3, -1, area1 + area2, ignore_validity)
|
||||
|
||||
#define TEST_DIFFERENCE_WITH(index1, index2, caseid, clips1, area1, \
|
||||
clips2, area2, clips3) \
|
||||
(test_one<Polygon, MultiPolygon, MultiPolygon>) \
|
||||
( #caseid "_" #index1 "_" #index2, caseid[index1], caseid[index2], \
|
||||
clips1, -1, area1, \
|
||||
clips2, -1, area2, \
|
||||
clips3, -1, area1 + area2, settings)
|
||||
|
||||
|
||||
template <typename Ring, typename Polygon, typename MultiPolygon>
|
||||
@ -95,10 +106,16 @@ void test_areal()
|
||||
case_78_multi[0], case_78_multi[1],
|
||||
1, 5, 1.0, 1, 5, 1.0);
|
||||
|
||||
TEST_DIFFERENCE(case_123_multi, 1, 4, 0.25, 2, 9, 0.625);
|
||||
TEST_DIFFERENCE(case_124_multi, 1, 4, 0.25, 2, 9, 0.4375);
|
||||
TEST_DIFFERENCE_IGNORE(case_125_multi, 1, 4, 0.25, 2, 12, 0.400);
|
||||
TEST_DIFFERENCE_IGNORE(case_126_multi, 3, 22, 16.0, 4, 27, 27.0); // A should have 3 clips, B should have 5 clips
|
||||
TEST_DIFFERENCE(case_123_multi, 1, 0.25, 2, 0.625, 3);
|
||||
TEST_DIFFERENCE(case_124_multi, 1, 0.25, 2, 0.4375, 3);
|
||||
TEST_DIFFERENCE_IGNORE(case_125_multi, 1, 0.25, 2, 0.400, 3);
|
||||
|
||||
// A should have 3 clips, B should have 5 clips
|
||||
#ifdef BOOST_GEOMETRY_INCLUDE_SELF_TURNS
|
||||
TEST_DIFFERENCE(case_126_multi, 4, 16.0, 5, 27.0, 9);
|
||||
#else
|
||||
TEST_DIFFERENCE_IGNORE(case_126_multi, 3, 16.0, 4, 27.0, 7);
|
||||
#endif
|
||||
|
||||
{
|
||||
ut_settings settings;
|
||||
@ -144,12 +161,13 @@ void test_areal()
|
||||
{
|
||||
ut_settings settings;
|
||||
settings.percentage = 0.001;
|
||||
settings.test_validity = false;
|
||||
|
||||
test_one<Polygon, MultiPolygon, MultiPolygon>("ggl_list_20120221_volker",
|
||||
ggl_list_20120221_volker[0], ggl_list_20120221_volker[1],
|
||||
2, 12, 7962.66, 1, 18, 2775258.93,
|
||||
settings);
|
||||
#ifdef BOOST_GEOMETRY_INCLUDE_SELF_TURNS
|
||||
TEST_DIFFERENCE_WITH(0, 1, ggl_list_20120221_volker, 2, 7962.66, 2, 2775258.93, 4);
|
||||
#else
|
||||
settings.test_validity = false;
|
||||
TEST_DIFFERENCE_WITH(0, 1, ggl_list_20120221_volker, 2, 7962.66, 1, 2775258.93, 3);
|
||||
#endif
|
||||
}
|
||||
|
||||
#if ! defined(BOOST_GEOMETRY_NO_ROBUSTNESS)
|
||||
@ -188,14 +206,19 @@ void test_areal()
|
||||
3, 14, 3.0,
|
||||
4, 21, 5.25);
|
||||
|
||||
TEST_DIFFERENCE(case_133_multi, 3, 16.0, 2, 8.0, 5);
|
||||
TEST_DIFFERENCE(case_134_multi, 3, 16.0, 2, 8.0, 5);
|
||||
TEST_DIFFERENCE(case_135_multi, 2, 2.0, 2, 13.0, 2);
|
||||
TEST_DIFFERENCE(case_136_multi, 2, 2.0, 3, 13.5, 3);
|
||||
TEST_DIFFERENCE(case_137_multi, 2, 2.5, 2, 13.0, 2);
|
||||
|
||||
// Areas correspond with POSTGIS,
|
||||
// #clips in PostGIS is 11,11,5 but should most probably be be 12,12,6
|
||||
test_one<Polygon, MultiPolygon, MultiPolygon>("case_recursive_boxes_1",
|
||||
case_recursive_boxes_1[0], case_recursive_boxes_1[1],
|
||||
11, 75, 26.0,
|
||||
12, 77, 24.0,
|
||||
5, 98, 50.0,
|
||||
ignore_validity);
|
||||
#ifdef BOOST_GEOMETRY_INCLUDE_SELF_TURNS
|
||||
TEST_DIFFERENCE(case_recursive_boxes_1, 12, 26.0, 12, 24.0, 6);
|
||||
#else
|
||||
TEST_DIFFERENCE_IGNORE(case_recursive_boxes_1, 11, 26.0, 12, 24.0, 5);
|
||||
#endif
|
||||
|
||||
// Areas and #clips correspond with POSTGIS
|
||||
test_one<Polygon, MultiPolygon, MultiPolygon>("case_recursive_boxes_2",
|
||||
@ -213,19 +236,18 @@ void test_areal()
|
||||
|
||||
// 4, input is not valid
|
||||
|
||||
test_one<Polygon, MultiPolygon, MultiPolygon>("case_recursive_boxes_5",
|
||||
case_recursive_boxes_5[0], case_recursive_boxes_5[1],
|
||||
15, -1, 22.0, // #clips should be 16
|
||||
11, -1, 27.0, // #clips should be 12
|
||||
8, -1, 49.0,
|
||||
ignore_validity);
|
||||
// Should have 16,12 clips in a,b
|
||||
#ifdef BOOST_GEOMETRY_INCLUDE_SELF_TURNS
|
||||
TEST_DIFFERENCE(case_recursive_boxes_5, 16, 22.0, 12, 27.0, 10);
|
||||
#else
|
||||
TEST_DIFFERENCE_IGNORE(case_recursive_boxes_5, 15, 22.0, 11, 27.0, 8);
|
||||
#endif
|
||||
|
||||
test_one<Polygon, MultiPolygon, MultiPolygon>("case_recursive_boxes_6",
|
||||
case_recursive_boxes_6[0], case_recursive_boxes_6[1],
|
||||
6, -1, 3.5,
|
||||
3, -1, 1.5,
|
||||
8, -1, 5.0,
|
||||
ignore_validity);
|
||||
#ifdef BOOST_GEOMETRY_INCLUDE_SELF_TURNS
|
||||
TEST_DIFFERENCE(case_recursive_boxes_6, 7, 3.5, 3, 1.5, 9);
|
||||
#else
|
||||
TEST_DIFFERENCE_IGNORE(case_recursive_boxes_6, 6, 3.5, 3, 1.5, 8);
|
||||
#endif
|
||||
|
||||
test_one<Polygon, MultiPolygon, MultiPolygon>("case_recursive_boxes_7",
|
||||
case_recursive_boxes_7[0], case_recursive_boxes_7[1],
|
||||
@ -257,6 +279,89 @@ void test_areal()
|
||||
3, -1, 4.5,
|
||||
3, -1, 7.0);
|
||||
|
||||
TEST_DIFFERENCE(case_recursive_boxes_12, 4, 2.75, 3, 2.75, 6);
|
||||
TEST_DIFFERENCE(case_recursive_boxes_13, 4, 4.75, 3, 5.5, 3);
|
||||
TEST_DIFFERENCE(case_recursive_boxes_14, 3, 2.0, 4, 2.5, 5);
|
||||
TEST_DIFFERENCE(case_recursive_boxes_15, 3, 3.0, 2, 2.5, 3);
|
||||
#ifdef BOOST_GEOMETRY_INCLUDE_SELF_TURNS
|
||||
TEST_DIFFERENCE(case_recursive_boxes_16, 8, 6.5, 3, 5.5, 9);
|
||||
TEST_DIFFERENCE(case_recursive_boxes_17, 10, 7.75, 7, 5.5, 13);
|
||||
#else
|
||||
TEST_DIFFERENCE_IGNORE(case_recursive_boxes_16, 7, 6.5, 3, 5.5, 8);
|
||||
TEST_DIFFERENCE_IGNORE(case_recursive_boxes_17, 9, 7.75, 6, 5.5, 11);
|
||||
#endif
|
||||
TEST_DIFFERENCE(case_recursive_boxes_18, 2, 1.0, 1, 1.5, 3);
|
||||
TEST_DIFFERENCE(case_recursive_boxes_19, 2, 1.0, 2, 1.5, 3);
|
||||
TEST_DIFFERENCE(case_recursive_boxes_20, 2, 1.0, 0, 0.0, 2);
|
||||
|
||||
TEST_DIFFERENCE(case_recursive_boxes_21, 2, 1.0, 1, 1.0, 1);
|
||||
TEST_DIFFERENCE(case_recursive_boxes_22, 2, 1.25, 2, 2.0, 2);
|
||||
TEST_DIFFERENCE(case_recursive_boxes_23, 2, 0.75, 1, 0.5, 3);
|
||||
TEST_DIFFERENCE(case_recursive_boxes_24, 3, 2.5, 2, 2.0, 5);
|
||||
TEST_DIFFERENCE(case_recursive_boxes_25, 2, 2.5, 3, 2.5, 2);
|
||||
TEST_DIFFERENCE(case_recursive_boxes_26, 2, 1.5, 3, 2.0, 4);
|
||||
TEST_DIFFERENCE(case_recursive_boxes_27, 1, 1.5, 3, 2.5, 3);
|
||||
TEST_DIFFERENCE(case_recursive_boxes_28, 3, 2.5, 2, 3.0, 4);
|
||||
TEST_DIFFERENCE(case_recursive_boxes_29, 5, 7.25, 5, 4.5, 5);
|
||||
TEST_DIFFERENCE(case_recursive_boxes_30, 6, 4.25, 3, 7.25, 7);
|
||||
|
||||
TEST_DIFFERENCE(case_recursive_boxes_31, 2, 2.0, 1, 0.5, 2);
|
||||
TEST_DIFFERENCE(case_recursive_boxes_32, 2, 2.75, 2, 1.25, 2);
|
||||
TEST_DIFFERENCE(case_recursive_boxes_33, 4, 3.0, 3, 6.0, 4);
|
||||
#ifdef BOOST_GEOMETRY_INCLUDE_SELF_TURNS
|
||||
TEST_DIFFERENCE(case_recursive_boxes_34, 7, 7.25, 1, 0.5, 8);
|
||||
#else
|
||||
TEST_DIFFERENCE_IGNORE(case_recursive_boxes_34, 5, 7.25, 1, 0.5, 6);
|
||||
#endif
|
||||
TEST_DIFFERENCE(case_recursive_boxes_35, 5, 1.75, 5, 2.75, 10);
|
||||
TEST_DIFFERENCE(case_recursive_boxes_36, 2, 1.0, 2, 1.5, 3);
|
||||
TEST_DIFFERENCE_IGNORE(case_recursive_boxes_37, 3, 2.5, 2, 4.25, 2);
|
||||
TEST_DIFFERENCE(case_recursive_boxes_38, 5, 7.75, 4, 3.5, 3);
|
||||
TEST_DIFFERENCE(case_recursive_boxes_39, 3, 6.0, 3, 3.0, 4);
|
||||
TEST_DIFFERENCE(case_recursive_boxes_40, 11, 14.0, 9, 13.0, 11);
|
||||
|
||||
TEST_DIFFERENCE(case_recursive_boxes_41, 1, 0.5, 1, 0.5, 2);
|
||||
#ifndef BOOST_GEOMETRY_INCLUDE_SELF_TURNS
|
||||
// 42.a Fails with self-turns
|
||||
TEST_DIFFERENCE(case_recursive_boxes_42, 1, 1.0, 4, 4.0, 5);
|
||||
#endif
|
||||
TEST_DIFFERENCE(case_recursive_boxes_43, 1, 0.5, 3, 2.0, 4);
|
||||
TEST_DIFFERENCE(case_recursive_boxes_44, 3, 5.0, 0, 0.0, 3);
|
||||
TEST_DIFFERENCE(case_recursive_boxes_45, 6, 20.0, 7, 20.0, 3);
|
||||
TEST_DIFFERENCE(case_recursive_boxes_46, 4, 14.0, 5, 12.0, 5);
|
||||
TEST_DIFFERENCE(case_recursive_boxes_47, 4, 10.0, 7, 11.0, 1);
|
||||
TEST_DIFFERENCE(case_recursive_boxes_48, 0, 0.0, 1, 9.0, 1);
|
||||
#ifdef BOOST_GEOMETRY_INCLUDE_SELF_TURNS
|
||||
TEST_DIFFERENCE(case_recursive_boxes_49, 10, 22.0, 10, 17.0, 11);
|
||||
#else
|
||||
TEST_DIFFERENCE_IGNORE(case_recursive_boxes_49, 9, 22.0, 10, 17.0, 10);
|
||||
#endif
|
||||
TEST_DIFFERENCE(case_recursive_boxes_50, 14, 21.0, 16, 21.0, 14);
|
||||
TEST_DIFFERENCE(case_recursive_boxes_51, 14, 25.0, 12, 31.0, 7);
|
||||
|
||||
#ifdef BOOST_GEOMETRY_INCLUDE_SELF_TURNS
|
||||
TEST_DIFFERENCE(case_recursive_boxes_52, 13, 30.0, 15, 25.0, 8);
|
||||
#else
|
||||
TEST_DIFFERENCE_IGNORE(case_recursive_boxes_52, 13, 30.0, 15, 25.0, 8);
|
||||
#endif
|
||||
TEST_DIFFERENCE(case_recursive_boxes_53, 6, 3.5, 4, 1.5, 9);
|
||||
TEST_DIFFERENCE(case_recursive_boxes_54, 6, 6.5, 8, 6.0, 7);
|
||||
TEST_DIFFERENCE(case_recursive_boxes_55, 4, 5.5, 6, 7.75, 4);
|
||||
TEST_DIFFERENCE_IGNORE(case_recursive_boxes_56, 4, 4.5, 5, 2.75, 6);
|
||||
TEST_DIFFERENCE(case_recursive_boxes_57, 5, 3.75, 9, 6.5, 10);
|
||||
TEST_DIFFERENCE(case_recursive_boxes_58, 4, 2.25, 6, 3.75, 7);
|
||||
#ifdef BOOST_GEOMETRY_INCLUDE_SELF_TURNS
|
||||
TEST_DIFFERENCE(case_recursive_boxes_59, 8, 6.5, 7, 7.0, 12);
|
||||
#else
|
||||
TEST_DIFFERENCE_IGNORE(case_recursive_boxes_59, 8, 6.5, 6, 7.0, 11);
|
||||
#endif
|
||||
|
||||
#ifdef BOOST_GEOMETRY_INCLUDE_SELF_TURNS
|
||||
TEST_DIFFERENCE(case_recursive_boxes_60, 6, 5.25, 7, 5.25, 11);
|
||||
#else
|
||||
TEST_DIFFERENCE_IGNORE(case_recursive_boxes_60, 5, 5.25, 5, 5.25, 8);
|
||||
#endif
|
||||
|
||||
test_one<Polygon, MultiPolygon, MultiPolygon>("mysql_21965285_b",
|
||||
mysql_21965285_b[0],
|
||||
mysql_21965285_b[1],
|
||||
@ -277,12 +382,9 @@ void test_all()
|
||||
|
||||
|
||||
// Test cases for integer coordinates / ccw / open
|
||||
template <typename Point, bool ClockWise, bool Closed>
|
||||
void test_specific()
|
||||
template <typename Polygon, typename MultiPolygon>
|
||||
void test_specific_areal()
|
||||
{
|
||||
typedef bg::model::polygon<Point, ClockWise, Closed> polygon;
|
||||
typedef bg::model::multi_polygon<polygon> multi_polygon;
|
||||
|
||||
{
|
||||
// Spikes in a-b and b-a, failure in symmetric difference
|
||||
|
||||
@ -294,12 +396,7 @@ void test_specific()
|
||||
settings.sym_difference = true;
|
||||
#endif
|
||||
|
||||
test_one<polygon, multi_polygon, multi_polygon>("ticket_11674",
|
||||
ticket_11674[0], ticket_11674[1],
|
||||
3, 27, 9105781.5,
|
||||
5, 22, 119059.5,
|
||||
2, -1, -1,
|
||||
settings);
|
||||
TEST_DIFFERENCE_WITH(0, 1, ticket_11674, 3, 9105781.5, 5, 119059.5, -1);
|
||||
}
|
||||
|
||||
{
|
||||
@ -307,25 +404,25 @@ void test_specific()
|
||||
// Spikes in a-b and b-a, failure in symmetric difference
|
||||
|
||||
ut_settings settings;
|
||||
settings.remove_spikes = true;
|
||||
#if ! defined(BOOST_GEOMETRY_INCLUDE_SELF_TURNS)
|
||||
settings.sym_difference = false;
|
||||
settings.test_validity = false;
|
||||
settings.remove_spikes = true;
|
||||
#endif
|
||||
|
||||
std::string a_min_b =
|
||||
test_one<polygon, multi_polygon, multi_polygon>("ticket_12751_1",
|
||||
ticket_12751[0], ticket_12751[1],
|
||||
1, 14, 2781965.0,
|
||||
1, 4, 597.0,
|
||||
settings);
|
||||
TEST_DIFFERENCE_WITH(0, 1, ticket_12751, 1, 2781965.0, 1, 597.0, 2);
|
||||
|
||||
#ifdef BOOST_GEOMETRY_INCLUDE_SELF_TURNS
|
||||
TEST_DIFFERENCE_WITH(2, 3, ticket_12751, 2, 2537992.5, 2, 294963.5, 3);
|
||||
#else
|
||||
|
||||
// Testing consistency of testcase itself
|
||||
BOOST_CHECK_EQUAL(a_min_b, ticket_12751[2]);
|
||||
|
||||
test_one<polygon, multi_polygon, multi_polygon>("ticket_12751_2",
|
||||
ticket_12751[2], ticket_12751[3],
|
||||
1, 18, 2537992.5,
|
||||
2, 11, 294963.5,
|
||||
settings);
|
||||
TEST_DIFFERENCE_WITH(2, 3, ticket_12751, 1, 2537992.5, 2, 294963.5, 3);
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
{
|
||||
@ -336,36 +433,29 @@ void test_specific()
|
||||
settings.sym_difference = false;
|
||||
settings.test_validity = false;
|
||||
|
||||
test_one<polygon, multi_polygon, multi_polygon>("ticket_12752",
|
||||
ticket_12752[0], ticket_12752[1],
|
||||
3, 22, 2776692.0,
|
||||
3, 11, 7893.0,
|
||||
settings);
|
||||
TEST_DIFFERENCE_WITH(0, 1, ticket_12752, 3, 2776692.0, 3, 7893.0, 6);
|
||||
}
|
||||
|
||||
{
|
||||
ut_settings settings;
|
||||
settings.test_validity = true;
|
||||
|
||||
std::string a_min_b =
|
||||
test_one<polygon, multi_polygon, multi_polygon>("ticket_10661_1",
|
||||
ticket_10661[0], ticket_10661[1],
|
||||
2, 11, 1441632.5,
|
||||
2, 7, 13167454,
|
||||
settings);
|
||||
TEST_DIFFERENCE(ticket_10661, 2, 1441632.5, 2, 13167454, 4);
|
||||
|
||||
settings.test_validity = false;
|
||||
#ifdef BOOST_GEOMETRY_TEST_INCLUDE_FAILING_TESTS
|
||||
settings.test_validity = true;
|
||||
#endif
|
||||
test_one<polygon, multi_polygon, multi_polygon>("ticket_10661_2",
|
||||
test_one<Polygon, MultiPolygon, MultiPolygon>("ticket_10661_2",
|
||||
a_min_b, ticket_10661[2],
|
||||
1, 8, 825192.0,
|
||||
1, 10, 27226370.5,
|
||||
1, -1, 825192.0 + 27226370.5,
|
||||
settings);
|
||||
1, -1, 825192.0 + 27226370.5);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename Point, bool ClockWise, bool Closed>
|
||||
void test_specific()
|
||||
{
|
||||
typedef bg::model::polygon<Point, ClockWise, Closed> polygon;
|
||||
typedef bg::model::multi_polygon<polygon> multi_polygon;
|
||||
test_specific_areal<polygon, multi_polygon>();
|
||||
}
|
||||
|
||||
|
||||
int test_main(int, char* [])
|
||||
{
|
||||
|
@ -91,10 +91,22 @@ void difference_output(std::string const& caseid, G1 const& g1, G2 const& g2, Ou
|
||||
typedef typename bg::coordinate_type<G1>::type coordinate_type;
|
||||
typedef typename bg::point_type<G1>::type point_type;
|
||||
|
||||
bool const ccw =
|
||||
bg::point_order<G1>::value == bg::counterclockwise
|
||||
|| bg::point_order<G2>::value == bg::counterclockwise;
|
||||
bool const open =
|
||||
bg::closure<G1>::value == bg::open
|
||||
|| bg::closure<G2>::value == bg::open;
|
||||
|
||||
std::ostringstream filename;
|
||||
filename << "difference_"
|
||||
<< caseid << "_"
|
||||
<< string_from_type<coordinate_type>::name()
|
||||
<< (ccw ? "_ccw" : "")
|
||||
<< (open ? "_open" : "")
|
||||
#if defined(BOOST_GEOMETRY_INCLUDE_SELF_TURNS)
|
||||
<< "_self"
|
||||
#endif
|
||||
#if defined(BOOST_GEOMETRY_NO_ROBUSTNESS)
|
||||
<< "_no_rob"
|
||||
#endif
|
||||
@ -187,7 +199,8 @@ std::string test_difference(std::string const& caseid, G1 const& g1, G2 const& g
|
||||
std::string message;
|
||||
bool const valid = bg::is_valid(result, message);
|
||||
BOOST_CHECK_MESSAGE(valid,
|
||||
"difference: " << caseid << " not valid " << message);
|
||||
"difference: " << caseid << " not valid " << message
|
||||
<< " type: " << (type_for_assert_message<G1, G2>()));
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -154,6 +154,16 @@ void test_areal()
|
||||
TEST_INTERSECTION(case_129_multi, 1, 20, 20.5);
|
||||
TEST_INTERSECTION(case_130_multi, 2, 30, 39.0);
|
||||
|
||||
TEST_INTERSECTION(case_133_multi, 2, 23, 40.625);
|
||||
TEST_INTERSECTION(case_134_multi, 1, 23, 42.0);
|
||||
TEST_INTERSECTION(case_135_multi, 1, 17, 7.0);
|
||||
TEST_INTERSECTION(case_136_multi, 1, 17, 6.5);
|
||||
TEST_INTERSECTION(case_137_multi, 1, 17, 6.5);
|
||||
|
||||
TEST_INTERSECTION(case_138_multi, 2, 23, 40.4);
|
||||
TEST_INTERSECTION(case_139_multi, 2, 23, 40.546875);
|
||||
TEST_INTERSECTION(case_140_multi, 2, 23, 40.546875);
|
||||
|
||||
#ifdef BOOST_GEOMETRY_INCLUDE_SELF_TURNS
|
||||
TEST_INTERSECTION(case_recursive_boxes_1, 10, 97, 47.0);
|
||||
#else
|
||||
@ -282,6 +292,21 @@ void test_areal()
|
||||
TEST_INTERSECTION(case_recursive_boxes_43, 2, 0, 22.5);
|
||||
TEST_INTERSECTION(case_recursive_boxes_44, 2, 0, 3.0);
|
||||
TEST_INTERSECTION(case_recursive_boxes_45, 7, 0, 12.0);
|
||||
TEST_INTERSECTION(case_recursive_boxes_46, 6, -1, 7.0);
|
||||
TEST_INTERSECTION(case_recursive_boxes_47, 1, 5, 1.0);
|
||||
TEST_INTERSECTION(case_recursive_boxes_48, 1, 5, 1.0);
|
||||
TEST_INTERSECTION(case_recursive_boxes_49, 7, 57, 20.0);
|
||||
TEST_INTERSECTION(case_recursive_boxes_50, 9, 71, 26.0);
|
||||
TEST_INTERSECTION(case_recursive_boxes_51, 14, 79, 19.0);
|
||||
TEST_INTERSECTION(case_recursive_boxes_52, 8, -1, 22.0);
|
||||
TEST_INTERSECTION(case_recursive_boxes_53, 1, -1, 19.75);
|
||||
TEST_INTERSECTION(case_recursive_boxes_54, 3, -1, 10.0);
|
||||
TEST_INTERSECTION(case_recursive_boxes_55, 5, -1, 2.25);
|
||||
TEST_INTERSECTION(case_recursive_boxes_56, 1, -1, 0.5);
|
||||
TEST_INTERSECTION(case_recursive_boxes_57, 10, -1, 9.5);
|
||||
TEST_INTERSECTION(case_recursive_boxes_58, 1, -1, 0.25);
|
||||
TEST_INTERSECTION(case_recursive_boxes_59, 8, -1, 8.25);
|
||||
TEST_INTERSECTION(case_recursive_boxes_60, 8, -1, 10.0);
|
||||
|
||||
test_one<Polygon, MultiPolygon, MultiPolygon>("ggl_list_20120915_h2_a",
|
||||
ggl_list_20120915_h2[0], ggl_list_20120915_h2[1],
|
||||
|
@ -102,7 +102,8 @@ check_result(
|
||||
std::string message;
|
||||
bool const valid = bg::is_valid(*it, message);
|
||||
BOOST_CHECK_MESSAGE(valid,
|
||||
"intersection: " << caseid << " not valid " << message);
|
||||
"intersection: " << caseid << " not valid: " << message
|
||||
<< " type: " << (type_for_assert_message<G1, G2>()));
|
||||
}
|
||||
}
|
||||
|
||||
@ -240,6 +241,9 @@ typename bg::default_area_result<G1>::type test_intersection(std::string const&
|
||||
<< string_from_type<CalculationType>::name()
|
||||
<< (ccw ? "_ccw" : "")
|
||||
<< (open ? "_open" : "")
|
||||
#if defined(BOOST_GEOMETRY_INCLUDE_SELF_TURNS)
|
||||
<< "_self"
|
||||
#endif
|
||||
#if defined(BOOST_GEOMETRY_NO_ROBUSTNESS)
|
||||
<< "_no_rob"
|
||||
#endif
|
||||
|
@ -21,6 +21,7 @@
|
||||
#include "../setop_output_type.hpp"
|
||||
|
||||
#include <boost/core/ignore_unused.hpp>
|
||||
#include <boost/foreach.hpp>
|
||||
#include <boost/range/algorithm/copy.hpp>
|
||||
|
||||
#include <boost/geometry/algorithms/union.hpp>
|
||||
@ -70,6 +71,44 @@ inline void check_input_validity(std::string const& caseid, int case_index,
|
||||
}
|
||||
#endif
|
||||
|
||||
template
|
||||
<
|
||||
typename Geometry,
|
||||
typename Tag = typename bg::tag<Geometry>::type
|
||||
>
|
||||
struct check_validity
|
||||
{
|
||||
static inline
|
||||
bool apply(Geometry const& geometry, std::string& message)
|
||||
{
|
||||
if (! bg::is_valid(geometry, message))
|
||||
{
|
||||
std::cout << bg::wkt(geometry) << std::endl;
|
||||
}
|
||||
return bg::is_valid(geometry, message);
|
||||
}
|
||||
};
|
||||
|
||||
// Specialization for vector of <geometry> (e.g. rings)
|
||||
template <typename Geometry>
|
||||
struct check_validity<Geometry, void>
|
||||
{
|
||||
static inline
|
||||
bool apply(Geometry const& geometry, std::string& message)
|
||||
{
|
||||
typedef typename boost::range_value<Geometry>::type single_type;
|
||||
BOOST_FOREACH(single_type const& element, geometry)
|
||||
{
|
||||
if (! bg::is_valid(element, message))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
template <typename Range>
|
||||
inline std::size_t num_points(Range const& rng, bool add_for_open = false)
|
||||
{
|
||||
@ -121,6 +160,16 @@ void test_union(std::string const& caseid, G1 const& g1, G2 const& g2,
|
||||
}
|
||||
#endif
|
||||
|
||||
if (settings.test_validity)
|
||||
{
|
||||
std::string message;
|
||||
bool const valid = check_validity<result_type>::apply(clip, message);
|
||||
BOOST_CHECK_MESSAGE(valid,
|
||||
"union: " << caseid << " not valid: " << message
|
||||
<< " type: " << (type_for_assert_message<G1, G2>()));
|
||||
}
|
||||
|
||||
|
||||
typename bg::default_area_result<OutputType>::type area = 0;
|
||||
std::size_t n = 0;
|
||||
std::size_t holes = 0;
|
||||
@ -130,16 +179,6 @@ void test_union(std::string const& caseid, G1 const& g1, G2 const& g2,
|
||||
area += bg::area(*it);
|
||||
holes += bg::num_interior_rings(*it);
|
||||
n += bg::num_points(*it, true);
|
||||
|
||||
if (settings.test_validity)
|
||||
{
|
||||
// Check validity (currently on separate clips only)
|
||||
// std::cout << bg::dsv(*it) << std::endl;
|
||||
std::string message;
|
||||
bool const valid = bg::is_valid(*it, message);
|
||||
BOOST_CHECK_MESSAGE(valid,
|
||||
"union: " << caseid << " not valid " << message);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -219,6 +258,9 @@ void test_union(std::string const& caseid, G1 const& g1, G2 const& g2,
|
||||
<< string_from_type<coordinate_type>::name()
|
||||
<< (ccw ? "_ccw" : "")
|
||||
<< (open ? "_open" : "")
|
||||
#if defined(BOOST_GEOMETRY_INCLUDE_SELF_TURNS)
|
||||
<< "_self"
|
||||
#endif
|
||||
#if defined(BOOST_GEOMETRY_NO_ROBUSTNESS)
|
||||
<< "_no_rob"
|
||||
#endif
|
||||
|
@ -32,9 +32,6 @@ void test_areal()
|
||||
{
|
||||
typedef typename bg::coordinate_type<Polygon>::type ct;
|
||||
|
||||
ut_settings ignore_validity;
|
||||
ignore_validity.test_validity = false;
|
||||
|
||||
test_one<Polygon, Polygon, Polygon>("simplex_normal",
|
||||
simplex_normal[0], simplex_normal[1],
|
||||
1, 0, 13, 11.526367);
|
||||
@ -381,9 +378,13 @@ void test_areal()
|
||||
test_one<Polygon, Polygon, Polygon>("ticket_11725", ticket_11725[0], ticket_11725[1],
|
||||
1, 1, 10, 7.5);
|
||||
|
||||
test_one<Polygon, Polygon, Polygon>("geos_1", geos_1[0], geos_1[1],
|
||||
1, 0, -1, 3461.3203125,
|
||||
ignore_validity);
|
||||
{
|
||||
ut_settings ignore_validity;
|
||||
ignore_validity.test_validity = false;
|
||||
test_one<Polygon, Polygon, Polygon>("geos_1", geos_1[0], geos_1[1],
|
||||
1, 0, -1, 3461.3203125,
|
||||
ignore_validity);
|
||||
}
|
||||
test_one<Polygon, Polygon, Polygon>("geos_2", geos_2[0], geos_2[1],
|
||||
1, 0, -1, 350.55102539);
|
||||
test_one<Polygon, Polygon, Polygon>("geos_3", geos_3[0], geos_3[1],
|
||||
@ -397,24 +398,18 @@ void test_areal()
|
||||
// Robustness issues, followed out buffer-robustness-tests, test them also reverse
|
||||
#if ! defined(BOOST_GEOMETRY_NO_ROBUSTNESS)
|
||||
test_one<Polygon, Polygon, Polygon>("buffer_rt_f", buffer_rt_f[0], buffer_rt_f[1],
|
||||
1, 0, if_typed<ct, double>(18, 23), 4.60853,
|
||||
ignore_validity);
|
||||
1, 0, if_typed<ct, double>(18, 23), 4.60853);
|
||||
test_one<Polygon, Polygon, Polygon>("buffer_rt_f_rev", buffer_rt_f[1], buffer_rt_f[0],
|
||||
1, 0, if_typed<ct, double>(18, 23), 4.60853,
|
||||
ignore_validity);
|
||||
#endif
|
||||
|
||||
1, 0, if_typed<ct, double>(18, 23), 4.60853);
|
||||
test_one<Polygon, Polygon, Polygon>("buffer_rt_g", buffer_rt_g[0], buffer_rt_g[1],
|
||||
1, 0, if_typed<ct, float>(18, 17), 16.571);
|
||||
test_one<Polygon, Polygon, Polygon>("buffer_rt_g_rev", buffer_rt_g[1], buffer_rt_g[0],
|
||||
1, 0, if_typed<ct, float>(18, 17), 16.571);
|
||||
|
||||
#if ! defined(BOOST_GEOMETRY_NO_ROBUSTNESS)
|
||||
test_one<Polygon, Polygon, Polygon>("buffer_rt_i", buffer_rt_i[0], buffer_rt_i[1],
|
||||
1, 0, if_typed<ct, float>(14, 13), 13.6569);
|
||||
#endif
|
||||
test_one<Polygon, Polygon, Polygon>("buffer_rt_i_rev", buffer_rt_i[1], buffer_rt_i[0],
|
||||
1, 0, 13, 13.6569);
|
||||
#endif
|
||||
|
||||
test_one<Polygon, Polygon, Polygon>("buffer_rt_j", buffer_rt_j[0], buffer_rt_j[1],
|
||||
1, 0, -1, 16.5711);
|
||||
@ -438,12 +433,11 @@ void test_areal()
|
||||
test_one<Polygon, Polygon, Polygon>("buffer_rt_m2_rev", buffer_rt_m2[1], buffer_rt_m2[0],
|
||||
1, 0, if_typed_tt<ct>(20, 19), 21.4853);
|
||||
|
||||
#if ! defined(BOOST_GEOMETRY_NO_ROBUSTNESS)
|
||||
test_one<Polygon, Polygon, Polygon>("buffer_rt_q", buffer_rt_q[0], buffer_rt_q[1],
|
||||
1, 0, 18, 18.5710);
|
||||
test_one<Polygon, Polygon, Polygon>("buffer_rt_q_rev", buffer_rt_q[1], buffer_rt_q[0],
|
||||
1, 0, 18, 18.5710);
|
||||
|
||||
#if ! defined(BOOST_GEOMETRY_NO_ROBUSTNESS)
|
||||
test_one<Polygon, Polygon, Polygon>("buffer_rt_r", buffer_rt_r[0], buffer_rt_r[1],
|
||||
1, 0, 19, 21.07612);
|
||||
test_one<Polygon, Polygon, Polygon>("buffer_rt_r_rev", buffer_rt_r[1], buffer_rt_r[0],
|
||||
@ -462,7 +456,7 @@ void test_areal()
|
||||
|
||||
test_one<Polygon, Polygon, Polygon>("buffer_mp2", buffer_mp2[0], buffer_mp2[1],
|
||||
#if defined(BOOST_GEOMETRY_NO_ROBUSTNESS)
|
||||
1, 0, 217, 36.752837, ignore_validity);
|
||||
1, 0, 217, 36.752837);
|
||||
#else
|
||||
1, 1, 217, 36.752837);
|
||||
#endif
|
||||
|
@ -33,15 +33,16 @@
|
||||
(test_one<Polygon, MultiPolygon, MultiPolygon>) \
|
||||
( #caseid, caseid[0], caseid[1], clips, holes, points, area)
|
||||
|
||||
#define TEST_UNION_IGNORE(caseid, clips, holes, points, area) \
|
||||
{ ut_settings ignore_validity; ignore_validity.test_validity = false; \
|
||||
test_one<Polygon, MultiPolygon, MultiPolygon> \
|
||||
(#caseid, caseid[0], caseid[1], \
|
||||
clips, holes, points, area, ignore_validity); }
|
||||
|
||||
|
||||
template <typename Ring, typename Polygon, typename MultiPolygon>
|
||||
void test_areal()
|
||||
{
|
||||
ut_settings ignore_validity;
|
||||
ignore_validity.test_validity = false;
|
||||
|
||||
// Some output is only invalid for CCW
|
||||
bool const ccw = bg::point_order<Polygon>::value == bg::counterclockwise;
|
||||
|
||||
test_one<Polygon, MultiPolygon, MultiPolygon>("simplex_multi",
|
||||
case_multi_simplex[0], case_multi_simplex[1],
|
||||
1, 0, 20, 14.58);
|
||||
@ -72,12 +73,9 @@ void test_areal()
|
||||
test_one<Polygon, MultiPolygon, MultiPolygon>("case_58_multi_a",
|
||||
case_58_multi[0], case_58_multi[3],
|
||||
2, 0, 21, 19.83333333);
|
||||
|
||||
// Was valid before but is invalid now that ii turns are discarded
|
||||
// It should be validated in another way
|
||||
test_one<Polygon, MultiPolygon, MultiPolygon>("case_58_multi_b",
|
||||
case_58_multi[1], case_58_multi[2],
|
||||
1, 1, 17, 48.333333, ignore_validity);
|
||||
1, 3, 17, 48.333333);
|
||||
|
||||
// Constructed cases for multi/touch/equal/etc
|
||||
test_one<Polygon, MultiPolygon, MultiPolygon>("case_61_multi",
|
||||
@ -132,14 +130,12 @@ void test_areal()
|
||||
case_108_multi[0], case_108_multi[1],
|
||||
1, 1, 20, 22.75);
|
||||
|
||||
// Should have 2 holes
|
||||
// To make it valid, it is necessary to calculate and use self turns
|
||||
// for each input. Now the two holes are connected because a turn is missing
|
||||
// there.
|
||||
test_one<Polygon, MultiPolygon, MultiPolygon>("case_109_multi",
|
||||
case_109_multi[0], case_109_multi[1],
|
||||
1, 1, 14, 1400,
|
||||
ignore_validity);
|
||||
// Should have 2 holes. Needs self turns
|
||||
#ifdef BOOST_GEOMETRY_INCLUDE_SELF_TURNS
|
||||
TEST_UNION(case_109_multi, 1, 2, 14, 1400);
|
||||
#else
|
||||
TEST_UNION_IGNORE(case_109_multi, 1, 1, 14, 1400);
|
||||
#endif
|
||||
|
||||
// Should have 9 holes, they are all separate and touching
|
||||
test_one<Polygon, MultiPolygon, MultiPolygon>("case_110_multi",
|
||||
@ -188,6 +184,27 @@ void test_areal()
|
||||
TEST_UNION(case_125_multi, 1, 0, 9, 2.75);
|
||||
TEST_UNION(case_126_multi, 1, 2, 27, 52.0);
|
||||
|
||||
// Should have 2 holes. Needs self turns
|
||||
#ifdef BOOST_GEOMETRY_INCLUDE_SELF_TURNS
|
||||
TEST_UNION(case_131_multi, 1, 2, 15, 14.0);
|
||||
#else
|
||||
TEST_UNION_IGNORE(case_131_multi, 1, 1, 15, 14.0);
|
||||
#endif
|
||||
|
||||
// SQL Server returns: MULTIPOLYGON (((4 4, 5.5 4.5, 6 6, 4.5 5.5, 4 4)), ((2 2, 3.5 2.5, 4 4, 2.5 3.5, 2 2)), ((0 0, 8 0, 8 8, 0 8, 0 0), (2 2, 2 4, 4 4, 4 6, 6 6, 6 4, 4 4, 4 2, 2 2)))
|
||||
// Which is one self-connected hole with two island polygons in both parts, basically identical to what Boost.Geometry delivers
|
||||
|
||||
// PostGIS returns: MULTIPOLYGON(((0 0,0 8,8 8,8 0,0 0),(4 6,4 4,6 4,6 6,4 6)),((2 2,2.5 3.5,4 4,3.5 2.5,2 2),(4 4,2 4,2 2,4 2,4 4)),((4 4,4.5 5.5,6 6,5.5 4.5,4 4)))
|
||||
// Which seems wrong because the second hole is part of a smaller polygon (?)
|
||||
// ("POSTGIS="2.1.7 r13414" GEOS="3.5.0dev-CAPI-1.9.0 r4057")
|
||||
TEST_UNION(case_132_multi, 3, 2, 26, 60.0);
|
||||
|
||||
TEST_UNION(case_133_multi, 2, 1, -1, 64.625);
|
||||
TEST_UNION(case_134_multi, 1, 2, -1, 66.0);
|
||||
TEST_UNION(case_135_multi, 1, 2, -1, 22.0);
|
||||
TEST_UNION(case_136_multi, 1, 2, -1, 22.0);
|
||||
TEST_UNION(case_137_multi, 1, 2, -1, 22.0);
|
||||
|
||||
test_one<Polygon, MultiPolygon, MultiPolygon>("case_recursive_boxes_1",
|
||||
case_recursive_boxes_1[0], case_recursive_boxes_1[1],
|
||||
1, 1, 36, 97.0);
|
||||
@ -202,14 +219,12 @@ void test_areal()
|
||||
case_recursive_boxes_4[0], case_recursive_boxes_4[1],
|
||||
1, 2, 42, 96.75);
|
||||
|
||||
// Should have 10 holes.
|
||||
// For making #5 valid, it is necessary to calculate and use self turns
|
||||
// for each input. Now one hole is connected to another hole because a turn
|
||||
// missing there.
|
||||
test_one<Polygon, MultiPolygon, MultiPolygon>("case_recursive_boxes_5",
|
||||
case_recursive_boxes_5[0], case_recursive_boxes_5[1],
|
||||
3, 9, 115, 70.0,
|
||||
ignore_validity);
|
||||
// Should have 10 holes. Needs self turns
|
||||
#ifdef BOOST_GEOMETRY_INCLUDE_SELF_TURNS
|
||||
TEST_UNION(case_recursive_boxes_5, 3, 10, 118, 70.0);
|
||||
#else
|
||||
TEST_UNION_IGNORE(case_recursive_boxes_5, 3, 9, 115, 70.0);
|
||||
#endif
|
||||
|
||||
test_one<Polygon, MultiPolygon, MultiPolygon>("case_recursive_boxes_6",
|
||||
case_recursive_boxes_6[0], case_recursive_boxes_6[1],
|
||||
@ -244,30 +259,15 @@ void test_areal()
|
||||
case_recursive_boxes_14[0], case_recursive_boxes_14[1],
|
||||
5, 0, -1, 4.5);
|
||||
|
||||
// Invalid versions of 12/13/14
|
||||
test_one<Polygon, MultiPolygon, MultiPolygon>("case_recursive_boxes_12_invalid",
|
||||
case_recursive_boxes_12_invalid[0], case_recursive_boxes_12_invalid[1],
|
||||
6, 0, -1, 6.0);
|
||||
|
||||
if (! ccw)
|
||||
{
|
||||
// Handling this invalid input delivers invalid results for CCW
|
||||
test_one<Polygon, MultiPolygon, MultiPolygon>("case_recursive_boxes_13_invalid",
|
||||
case_recursive_boxes_13_invalid[0], case_recursive_boxes_13_invalid[1],
|
||||
3, 0, -1, 10.25);
|
||||
}
|
||||
else
|
||||
{
|
||||
test_one<Polygon, MultiPolygon, MultiPolygon>("case_recursive_boxes_13_invalid",
|
||||
case_recursive_boxes_13_invalid[0], case_recursive_boxes_13_invalid[1],
|
||||
2, 0, -1, 10.25,
|
||||
ignore_validity);
|
||||
}
|
||||
|
||||
test_one<Polygon, MultiPolygon, MultiPolygon>("case_recursive_boxes_14_invalid",
|
||||
case_recursive_boxes_14_invalid[0], case_recursive_boxes_14_invalid[1],
|
||||
5, 0, -1, 4.5);
|
||||
// 12, 13, 14 with invalid input. To make then valid it is necessary
|
||||
// to break regions at self-intersection points (postponed)
|
||||
|
||||
TEST_UNION_IGNORE(case_recursive_boxes_12_invalid, 5, 0, -1, 6.0);
|
||||
#ifdef BOOST_GEOMETRY_INCLUDE_SELF_TURNS
|
||||
// Without self-turns, a whole part is missed
|
||||
TEST_UNION_IGNORE(case_recursive_boxes_13_invalid, 2, 0, -1, 10.25);
|
||||
#endif
|
||||
TEST_UNION_IGNORE(case_recursive_boxes_14_invalid, 4, 0, -1, 4.5);
|
||||
|
||||
test_one<Polygon, MultiPolygon, MultiPolygon>("case_recursive_boxes_15",
|
||||
case_recursive_boxes_15[0], case_recursive_boxes_15[1],
|
||||
@ -344,6 +344,44 @@ void test_areal()
|
||||
|
||||
TEST_UNION(case_recursive_boxes_46, 1, 4, 51, 33.0);
|
||||
TEST_UNION(case_recursive_boxes_47, 1, 0, -1, 22.0);
|
||||
TEST_UNION(case_recursive_boxes_48, 1, 1, -1, 10.0);
|
||||
#ifdef BOOST_GEOMETRY_INCLUDE_SELF_TURNS
|
||||
TEST_UNION(case_recursive_boxes_49, 1, 3, -1, 59.0);
|
||||
#else
|
||||
TEST_UNION_IGNORE(case_recursive_boxes_49, 1, 2, -1, 59.0);
|
||||
#endif
|
||||
|
||||
TEST_UNION(case_recursive_boxes_50, 7, 4, -1, 68.0);
|
||||
|
||||
#ifdef BOOST_GEOMETRY_INCLUDE_SELF_TURNS
|
||||
TEST_UNION(case_recursive_boxes_51, 2, 6, -1, 75.0);
|
||||
#else
|
||||
TEST_UNION_IGNORE(case_recursive_boxes_51, 2, 5, -1, 75.0);
|
||||
#endif
|
||||
|
||||
TEST_UNION(case_recursive_boxes_52, 2, 6, -1, 77.0);
|
||||
TEST_UNION(case_recursive_boxes_53, 1, 1, -1, 24.75);
|
||||
#ifdef BOOST_GEOMETRY_INCLUDE_SELF_TURNS
|
||||
TEST_UNION(case_recursive_boxes_54, 1, 2, -1, 22.5);
|
||||
#else
|
||||
TEST_UNION_IGNORE(case_recursive_boxes_54, 1, 1, -1, 22.5);
|
||||
#endif
|
||||
|
||||
TEST_UNION(case_recursive_boxes_55, 3, 1, -1, 15.5);
|
||||
#ifdef BOOST_GEOMETRY_INCLUDE_SELF_TURNS
|
||||
TEST_UNION(case_recursive_boxes_56, 5, 1, -1, 7.75);
|
||||
#else
|
||||
TEST_UNION_IGNORE(case_recursive_boxes_56, 5, 0, -1, 7.75);
|
||||
#endif
|
||||
TEST_UNION(case_recursive_boxes_57, 3, 4, -1, 19.75);
|
||||
TEST_UNION(case_recursive_boxes_58, 6, 1, -1, 6.25);
|
||||
|
||||
#ifdef BOOST_GEOMETRY_INCLUDE_SELF_TURNS
|
||||
// If there are no self-turns, an interior ring is missed
|
||||
TEST_UNION(case_recursive_boxes_59, 1, 3, -1, 21.75);
|
||||
#endif
|
||||
|
||||
TEST_UNION(case_recursive_boxes_60, 3, 0, -1, 20.5);
|
||||
|
||||
test_one<Polygon, MultiPolygon, MultiPolygon>("ggl_list_20120915_h2_a",
|
||||
ggl_list_20120915_h2[0], ggl_list_20120915_h2[1],
|
||||
@ -383,17 +421,19 @@ void test_areal()
|
||||
1, 0, -1, 575.831180350007);
|
||||
#endif
|
||||
|
||||
// TODO: solve validity, it needs calculating self-turns
|
||||
// Should have 1 hole
|
||||
test_one<Polygon, MultiPolygon, MultiPolygon>("mysql_23023665_7",
|
||||
mysql_23023665_7[0], mysql_23023665_7[1],
|
||||
1, 0, -1, 99.19494,
|
||||
ignore_validity);
|
||||
// Should have 2 holes
|
||||
test_one<Polygon, MultiPolygon, MultiPolygon>("mysql_23023665_8",
|
||||
mysql_23023665_8[0], mysql_23023665_8[1],
|
||||
1, 1, -1, 1400.0,
|
||||
ignore_validity);
|
||||
// Should have 1 hole. Needs self turns.
|
||||
#ifdef BOOST_GEOMETRY_INCLUDE_SELF_TURNS
|
||||
TEST_UNION(mysql_23023665_7, 1, 1, -1, 99.19494);
|
||||
#else
|
||||
TEST_UNION_IGNORE(mysql_23023665_7, 1, 0, -1, 99.19494);
|
||||
#endif
|
||||
|
||||
// Should have 2 holes. Needs self turns.
|
||||
#ifdef BOOST_GEOMETRY_INCLUDE_SELF_TURNS
|
||||
TEST_UNION(mysql_23023665_8, 1, 2, -1, 1400.0);
|
||||
#else
|
||||
TEST_UNION_IGNORE(mysql_23023665_8, 1, 1, -1, 1400.0);
|
||||
#endif
|
||||
|
||||
test_one<Polygon, MultiPolygon, MultiPolygon>("mysql_23023665_9",
|
||||
mysql_23023665_9[0], mysql_23023665_9[1],
|
||||
|
@ -7,6 +7,8 @@
|
||||
// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
|
||||
// http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#define BOOST_GEOMETRY_INCLUDE_SELF_TURNS
|
||||
|
||||
#define BOOST_GEOMETRY_REPORT_OVERLAY_ERROR
|
||||
#define BOOST_GEOMETRY_NO_BOOST_TEST
|
||||
|
||||
@ -160,6 +162,7 @@ int main(int argc, char** argv)
|
||||
("seed", po::value<int>(&seed), "Initialization seed for random generator")
|
||||
("count", po::value<int>(&count)->default_value(1), "Number of tests")
|
||||
("diff", po::value<bool>(&settings.also_difference)->default_value(false), "Include testing on difference")
|
||||
("validity", po::value<bool>(&settings.validity)->default_value(true), "Include testing on validity")
|
||||
("level", po::value<int>(&level)->default_value(3), "Level to reach (higher->slower)")
|
||||
("size", po::value<int>(&field_size)->default_value(10), "Size of the field")
|
||||
("form", po::value<std::string>(&form)->default_value("box"), "Form of the polygons (box, triangle)")
|
||||
|
@ -34,18 +34,21 @@
|
||||
|
||||
#include <boost/geometry/algorithms/detail/overlay/debug_turn_info.hpp>
|
||||
#include <boost/geometry/algorithms/intersects.hpp>
|
||||
#include <boost/geometry/algorithms/is_valid.hpp>
|
||||
#include <boost/geometry/algorithms/touches.hpp>
|
||||
|
||||
struct p_q_settings
|
||||
{
|
||||
bool svg;
|
||||
bool also_difference;
|
||||
bool validity;
|
||||
bool wkt;
|
||||
double tolerance;
|
||||
|
||||
p_q_settings()
|
||||
: svg(false)
|
||||
, also_difference(false)
|
||||
, validity(false)
|
||||
, wkt(false)
|
||||
, tolerance(1.0e-3) // since rescaling to integer the tolerance should be less. Was originally 1.0e-6
|
||||
{}
|
||||
@ -74,7 +77,7 @@ static bool test_overlay_p_q(std::string const& caseid,
|
||||
typedef typename bg::coordinate_type<G1>::type coordinate_type;
|
||||
typedef typename bg::point_type<G1>::type point_type;
|
||||
|
||||
bg::model::multi_polygon<OutputType> out_i, out_u, out_d, out_d2;
|
||||
bg::model::multi_polygon<OutputType> out_i, out_u, out_d1, out_d2;
|
||||
|
||||
CalculationType area_p = p_q_area(p);
|
||||
CalculationType area_q = p_q_area(q);
|
||||
@ -92,9 +95,9 @@ static bool test_overlay_p_q(std::string const& caseid,
|
||||
|
||||
if (settings.also_difference)
|
||||
{
|
||||
bg::difference(p, q, out_d);
|
||||
bg::difference(p, q, out_d1);
|
||||
bg::difference(q, p, out_d2);
|
||||
area_d1 = p_q_area(out_d);
|
||||
area_d1 = p_q_area(out_d1);
|
||||
area_d2 = p_q_area(out_d2);
|
||||
double sum_d1 = (area_u - area_q) - area_d1;
|
||||
double sum_d2 = (area_u - area_p) - area_d2;
|
||||
@ -107,6 +110,34 @@ static bool test_overlay_p_q(std::string const& caseid,
|
||||
}
|
||||
}
|
||||
|
||||
if (settings.validity)
|
||||
{
|
||||
std::string message;
|
||||
if (! bg::is_valid(out_u, message))
|
||||
{
|
||||
std::cout << "Union is not valid: " << message << std::endl;
|
||||
wrong = true;
|
||||
}
|
||||
if (! bg::is_valid(out_i, message))
|
||||
{
|
||||
std::cout << "Intersection is not valid: " << message << std::endl;
|
||||
wrong = true;
|
||||
}
|
||||
if (settings.also_difference)
|
||||
{
|
||||
if (! bg::is_valid(out_d1, message))
|
||||
{
|
||||
std::cout << "Difference (p-q) is not valid: " << message << std::endl;
|
||||
wrong = true;
|
||||
}
|
||||
if (! bg::is_valid(out_d2, message))
|
||||
{
|
||||
std::cout << "Difference (q-p) is not valid: " << message << std::endl;
|
||||
wrong = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (true)
|
||||
{
|
||||
if ((area_i > 0 && bg::touches(p, q))
|
||||
@ -181,7 +212,7 @@ static bool test_overlay_p_q(std::string const& caseid,
|
||||
|
||||
if (settings.also_difference)
|
||||
{
|
||||
for (BOOST_AUTO(it, out_d.begin()); it != out_d.end(); ++it)
|
||||
for (BOOST_AUTO(it, out_d1.begin()); it != out_d1.end(); ++it)
|
||||
{
|
||||
mapper.map(*it,
|
||||
"opacity:0.8;fill:none;stroke:rgb(255,128,0);stroke-width:4;stroke-dasharray:1,7;stroke-linecap:round");
|
||||
@ -194,16 +225,10 @@ static bool test_overlay_p_q(std::string const& caseid,
|
||||
}
|
||||
else
|
||||
{
|
||||
for (BOOST_AUTO(it, out_i.begin()); it != out_i.end(); ++it)
|
||||
{
|
||||
mapper.map(*it, "fill-opacity:0.1;stroke-opacity:0.4;fill:rgb(255,0,0);"
|
||||
"stroke:rgb(255,0,0);stroke-width:4");
|
||||
}
|
||||
for (BOOST_AUTO(it, out_u.begin()); it != out_u.end(); ++it)
|
||||
{
|
||||
mapper.map(*it, "fill-opacity:0.1;stroke-opacity:0.4;fill:rgb(255,0,0);"
|
||||
"stroke:rgb(255,0,255);stroke-width:4");
|
||||
}
|
||||
mapper.map(out_i, "fill-opacity:0.1;stroke-opacity:0.4;fill:rgb(255,0,128);"
|
||||
"stroke:rgb(255,0,0);stroke-width:4");
|
||||
mapper.map(out_u, "fill-opacity:0.1;stroke-opacity:0.4;fill:rgb(255,0,0);"
|
||||
"stroke:rgb(255,0,255);stroke-width:4");
|
||||
}
|
||||
}
|
||||
return result;
|
||||
|
@ -299,7 +299,7 @@ inline void to_svg(G const& g, std::string const& filename, bool /*sort*/ = true
|
||||
|
||||
bg::detail::self_get_turn_points::get_turns
|
||||
<
|
||||
TurnPolicy
|
||||
false, TurnPolicy
|
||||
>::apply(g, bg::detail::no_rescale_policy(), turns, interrupt_policy);
|
||||
|
||||
turns_to_svg<G>(turns, mapper);
|
||||
|
Loading…
x
Reference in New Issue
Block a user