diff --git a/include/boost/geometry/algorithms/detail/get_left_turns.hpp b/include/boost/geometry/algorithms/detail/get_left_turns.hpp new file mode 100644 index 000000000..62f0f7f0f --- /dev/null +++ b/include/boost/geometry/algorithms/detail/get_left_turns.hpp @@ -0,0 +1,367 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2012 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_GET_LEFT_TURNS_HPP +#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_GET_LEFT_TURNS_HPP + +#include + +namespace boost { namespace geometry +{ + + +#ifndef DOXYGEN_NO_DETAIL +namespace detail +{ + +// TODO: move this to /util/ +template +static inline std::pair ordered_pair(T const& first, T const& second) +{ + return first < second ? std::make_pair(first, second) : std::make_pair(second, first); +} + +template +inline void debug_left_turn(AngleInfo const& ai, AngleInfo const& previous) +{ +#ifdef BOOST_GEOMETRY_DEBUG_BUFFER_OCCUPATION + std::cout << "Angle: " << (ai.incoming ? "i" : "o") + << " " << si(ai.seg_id) + << " " << (math::r2d * (ai.angle) ) + << " turn: " << ai.turn_index << "[" << ai.operation_index << "]" + ; + + if (ai.turn_index != previous.turn_index + || ai.operation_index != previous.operation_index) + { + std::cout << " diff: " << math::r2d * math::abs(previous.angle - ai.angle); + } + std::cout << std::endl; +#endif +} + +template +inline void debug_left_turn(std::string const& caption, AngleInfo const& ai, AngleInfo const& previous, + int code = -99, int code2 = -99, int code3 = -99, int code4 = -99) +{ +#ifdef BOOST_GEOMETRY_DEBUG_BUFFER_OCCUPATION + std::cout << " " << caption + << " turn: " << ai.turn_index << "[" << ai.operation_index << "]" + << " " << si(ai.seg_id) + << " " << (ai.incoming ? "i" : "o") + << " " << (math::r2d * (ai.angle) ) + << " turn: " << previous.turn_index << "[" << previous.operation_index << "]" + << " " << si(previous.seg_id) + << " " << (previous.incoming ? "i" : "o") + << " " << (math::r2d * (previous.angle) ) + ; + + if (code != -99) + { + std::cout << " code: " << code << " , " << code2 << " , " << code3 << " , " << code4; + } + std::cout << std::endl; +#endif +} + + +template +inline bool include_operation(Operation const& op, + segment_identifier const& outgoing_seg_id, + segment_identifier const& incoming_seg_id) +{ + return op.seg_id == outgoing_seg_id + && op.other_id == incoming_seg_id + && (op.operation == detail::overlay::operation_union + ||op.operation == detail::overlay::operation_continue) + ; +} + +template +inline bool process_include(segment_identifier const& outgoing_seg_id, segment_identifier const& incoming_seg_id, + int turn_index, Turn& turn, + std::set& keep_indices, int priority) +{ + bool result = false; + for (int i = 0; i < 2; i++) + { + if (include_operation(turn.operations[i], outgoing_seg_id, incoming_seg_id)) + { + turn.operations[i].include_in_occupation_map = true; + if (priority > turn.priority) + { + turn.priority = priority; + } + keep_indices.insert(turn_index); + result = true; + } + } + return result; +} + +template +inline bool include_left_turn_of_all( + AngleInfo const& outgoing, AngleInfo const& incoming, + Turns& turns, TurnSegmentIndices const& turn_segment_indices, + std::set& keep_indices, int priority) +{ + segment_identifier const& outgoing_seg_id = turns[outgoing.turn_index].operations[outgoing.operation_index].seg_id; + segment_identifier const& incoming_seg_id = turns[incoming.turn_index].operations[incoming.operation_index].seg_id; + + if (outgoing.turn_index == incoming.turn_index) + { + return process_include(outgoing_seg_id, incoming_seg_id, outgoing.turn_index, turns[outgoing.turn_index], keep_indices, priority); + } + + bool result = false; + std::pair pair = ordered_pair(outgoing_seg_id, incoming_seg_id); + auto it = turn_segment_indices.find(pair); + if (it != turn_segment_indices.end()) + { + for (auto sit = it->second.begin(); sit != it->second.end(); ++sit) + { + if (process_include(outgoing_seg_id, incoming_seg_id, *sit, turns[*sit], keep_indices, priority)) + { + result = true; + } + } + } + return result; +} + +template +inline bool corresponds(Turn const& turn, segment_identifier const& seg_id) +{ + return turn.operations[Index].operation == detail::overlay::operation_union + && turn.operations[Index].seg_id == seg_id; +} + + +template +inline bool prefer_by_other(Turns const& turns, + TurnSegmentIndices const& turn_segment_indices, + std::set& indices) +{ + std::map map; + for (auto sit = indices.begin(); sit != indices.end(); ++sit) + { + map[turns[*sit].operations[0].seg_id]++; + map[turns[*sit].operations[1].seg_id]++; + } + + std::set segment_occuring_once; + for (auto mit = map.begin(); mit != map.end(); ++mit) + { + if (mit->second == 1) + { + segment_occuring_once.insert(mit->first); + } +#ifdef BOOST_GEOMETRY_DEBUG_BUFFER_PREFER + std::cout << si(mit->first) << " " << mit->second << std::endl; +#endif + } + + if (segment_occuring_once.size() == 2) + { + // Try to find within all turns a turn with these two segments + + std::set::const_iterator soo_it = segment_occuring_once.begin(); + segment_identifier front = *soo_it; + soo_it++; + segment_identifier back = *soo_it; + + std::pair pair = ordered_pair(front, back); + auto it = turn_segment_indices.find(pair); + if (it != turn_segment_indices.end()) + { + // debug_turns_by_indices("Found", it->second); + // Check which is the union/continue + segment_identifier good; + for (auto sit = it->second.begin(); sit != it->second.end(); ++sit) + { + if (turns[*sit].operations[0].operation == detail::overlay::operation_union) + { + good = turns[*sit].operations[0].seg_id; + } + else if (turns[*sit].operations[1].operation == detail::overlay::operation_union) + { + good = turns[*sit].operations[1].seg_id; + } + } + +#ifdef BOOST_GEOMETRY_DEBUG_BUFFER_PREFER + std::cout << "Good: " << si(good) << std::endl; +#endif + + // Find in indexes-to-keep this segment with the union. Discard the other one + std::set ok_indices; + for (auto sit = indices.begin(); sit != indices.end(); ++sit) + { + if (corresponds<0>(turns[*sit], good) || corresponds<1>(turns[*sit], good)) + { + ok_indices.insert(*sit); + } + } + if (ok_indices.size() > 0 && ok_indices.size() < indices.size()) + { + indices = ok_indices; + std::cout << "^"; + return true; + } + } + } + return false; +} + +template +inline void prefer_by_priority(Turns const& turns, std::set& indices) +{ + // Find max prio + int min_prio = 1024, max_prio = 0; + for (auto sit = indices.begin(); sit != indices.end(); ++sit) + { + if (turns[*sit].priority > max_prio) + { + max_prio = turns[*sit].priority; + } + if (turns[*sit].priority < min_prio) + { + min_prio = turns[*sit].priority; + } + } + + if (min_prio == max_prio) + { + return; + } + + // Only keep indices with high prio + std::set ok_indices; + for (auto sit = indices.begin(); sit != indices.end(); ++sit) + { + if (turns[*sit].priority >= max_prio) + { + ok_indices.insert(*sit); + } + } + if (ok_indices.size() > 0 && ok_indices.size() < indices.size()) + { + indices = ok_indices; + std::cout << "%"; + } +} + +template +inline void calculate_left_turns(Angles const& angles, + Turns& turns, TurnSegmentIndices const& turn_segment_indices, + std::set& keep_indices) +{ + bool debug_indicate_size = false; + + typedef typename strategy::side::services::default_strategy + < + typename cs_tag::type + >::type side_strategy; + + std::size_t i = 0; + std::size_t n = boost::size(angles); + + typedef geometry::ever_circling_range_iterator circling_iterator; + circling_iterator cit(angles); + + debug_left_turn(*cit, *cit); + for(circling_iterator prev = cit++; i < n; prev = cit++, i++) + { + debug_left_turn(*cit, *prev); + + bool const include = ! geometry::math::equals(prev->angle, cit->angle) + && ! prev->incoming + && cit->incoming; + + if (include) + { + // Go back to possibly include more same left outgoing angles: + // Because we check on side too we can take a large "epsilon" + circling_iterator back = prev - 1; + + typename AngleInfo::angle_type eps = 0.00001; + int b = 1; + for(std::size_t d = 0; + math::abs(prev->angle - back->angle) < eps + && ! back->incoming + && d < n; + d++) + { + --back; + ++b; + } + + // Same but forward to possibly include more incoming angles + int f = 1; + circling_iterator forward = cit + 1; + for(std::size_t d = 0; + math::abs(cit->angle - forward->angle) < eps + && forward->incoming + && d < n; + d++) + { + ++forward; + ++f; + } + +#ifdef BOOST_GEOMETRY_DEBUG_BUFFER_OCCUPATION + std::cout << "HANDLE " << b << "/" << f << " ANGLES" << std::endl; +#endif + for(circling_iterator bit = prev; bit != back; --bit) + { + int code = side_strategy::apply(bit->direction_point, prev->intersection_point, prev->direction_point); + int code2 = side_strategy::apply(prev->direction_point, bit->intersection_point, bit->direction_point); + for(circling_iterator fit = cit; fit != forward; ++fit) + { + int code3 = side_strategy::apply(fit->direction_point, cit->intersection_point, cit->direction_point); + int code4 = side_strategy::apply(cit->direction_point, fit->intersection_point, fit->direction_point); + + int priority = 2; + if (code == -1 && code2 == 1) + { + // This segment is lying right of the other one. + // Cannot ignore it (because of robustness, see a.o. #rt_p21 from unit test). + // But if we find more we can prefer later by priority + // (a.o. necessary for #rt_o2 from unit test) + priority = 1; + } + + bool included = include_left_turn_of_all(*bit, *fit, turns, turn_segment_indices, keep_indices, priority); + debug_left_turn(included ? "KEEP" : "SKIP", *fit, *bit, code, code2, code3, code4); + } + } + } + } + + if (debug_indicate_size) + { + std::cout << " size=" << keep_indices.size(); + } + + if (keep_indices.size() >= 2) + { + prefer_by_other(turns, turn_segment_indices, keep_indices); + } + if (keep_indices.size() >= 2) + { + prefer_by_priority(turns, keep_indices); + } +} + +} // namespace detail +#endif // DOXYGEN_NO_DETAIL + + +}} // namespace boost::geometry + +#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_GET_LEFT_TURNS_HPP diff --git a/include/boost/geometry/algorithms/detail/occupation_info.hpp b/include/boost/geometry/algorithms/detail/occupation_info.hpp index 8bd2cbf3c..e147ba12d 100644 --- a/include/boost/geometry/algorithms/detail/occupation_info.hpp +++ b/include/boost/geometry/algorithms/detail/occupation_info.hpp @@ -9,7 +9,9 @@ #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_OCCUPATION_INFO_HPP #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OCCUPATION_INFO_HPP - #define BOOST_GEOMETRY_DEBUG_BUFFER_OCCUPATION +#if ! defined(NDEBUG) + #define BOOST_GEOMETRY_DEBUG_BUFFER_OCCUPATION +#endif #include #include @@ -19,7 +21,8 @@ #include #include -#include + +#include namespace boost { namespace geometry @@ -42,8 +45,7 @@ public : inline relaxed_less() { // TODO: adapt for ttmath, and maybe build the map in another way - // (e.g. exact constellations of segment-id's, maybe adaptive. - // for the moment take the sqrt (to consider it as comparable distances) + // (e.g. exact constellations of segment-id's), maybe adaptive. epsilon = std::numeric_limits::epsilon() * 100.0; } @@ -211,163 +213,14 @@ public : return m_occupied; } - static inline void debug_left_turn(AngleInfo const& ai, AngleInfo const& previous) + template + inline void get_left_turns( + Turns& turns, TurnSegmentIndices const& turn_segment_indices, + std::set& keep_indices) { -#ifdef BOOST_GEOMETRY_DEBUG_BUFFER_OCCUPATION - std::cout << "Angle: " << (ai.incoming ? "i" : "o") - // << " " << si(ai.seg_id) - << " " << (math::r2d * (ai.angle) ) - << " turn: " << ai.turn_index << "[" << ai.operation_index << "]"; - - if (ai.turn_index != previous.turn_index - || ai.operation_index != previous.operation_index) - { - std::cout << " diff: " << math::r2d * math::abs(previous.angle - ai.angle); - } - std::cout << std::endl; -#endif + std::sort(angles.begin(), angles.end(), angle_sort()); + calculate_left_turns(angles, turns, turn_segment_indices, keep_indices); } - - static inline void debug_left_turn(std::string const& caption, AngleInfo const& ai, AngleInfo const& previous, - int code = -99, int code2 = -99, int code3 = -99, int code4 = -99) - { -#ifdef BOOST_GEOMETRY_DEBUG_BUFFER_OCCUPATION - std::cout << " " << caption << ": " - << (ai.incoming ? "i" : "o") - << " " << (math::r2d * (ai.angle) ) - << " turn: " << ai.turn_index << "[" << ai.operation_index << "]" - << " " << (previous.incoming ? "i" : "o") - << " " << (math::r2d * (previous.angle) ) - << " turn: " << previous.turn_index << "[" << previous.operation_index << "]"; - - if (code != -99) - { - std::cout << " code: " << code << " , " << code2 << " , " << code3 << " , " << code4; - } - std::cout << std::endl; -#endif - } - - template - static inline void include_left_turn(AngleInfo const& outgoing, AngleInfo const& incoming, - Turns const& turns, - std::set const& turn_indices, - std::set >& keep_indices) - { - // Safety check - if (turn_indices.count(outgoing.turn_index) > 0 - && turn_indices.count(incoming.turn_index) > 0) - { - // Check if this is the intended turn (of the two segments making an open angle with each other) - if (turns[outgoing.turn_index].operations[outgoing.operation_index].other_id == - turns[incoming.turn_index].operations[incoming.operation_index].seg_id) - { - //if (turns[outgoing.turn_index].operations[outgoing.operation_index].operation == detail::overlay::operation_union - // || turns[outgoing.turn_index].operations[outgoing.operation_index].operation == detail::overlay::operation_continue) - { - // This is the left turn. Mark it and don't check it for other pieces - keep_indices.insert(std::make_pair(outgoing.turn_index, outgoing.operation_index)); - //std::cout << " INC"; - } - } -#ifdef BOOST_GEOMETRY_DEBUG_BUFFER_OCCUPATION - //else - //{ - // std::cout << " SKIP " << outgoing.turn_index << "[" << outgoing.operation_index << "]" << std::endl; - //} -#endif - } - } - - - template - inline void get_left_turns(Turns const& turns, - std::set const& turn_indices, - std::set >& keep_indices) - { - typedef typename strategy::side::services::default_strategy - < - typename cs_tag::type - >::type side_strategy; - - std::sort(angles.begin(), angles.end(), angle_sort()); -#ifdef BOOST_GEOMETRY_DEBUG_BUFFER_OCCUPATION - std::cout << "get_left_turns()" << std::endl; -#endif - - std::size_t i = 0; - std::size_t n = boost::size(angles); - - typedef geometry::ever_circling_range_iterator circling_iterator; - circling_iterator cit(angles); - - debug_left_turn(*cit, *cit); - for(circling_iterator prev = cit++; i < n; prev = cit++, i++) - { - debug_left_turn(*cit, *prev); - - bool include = ! geometry::math::equals(prev->angle, cit->angle) - && ! prev->incoming - && cit->incoming; - - if (include) - { - // Go back to possibly include more same left outgoing angles: - // Because we check on side too we can take a large "epsilon" - circling_iterator back = prev - 1; - - typename AngleInfo::angle_type eps = 0.00001; - int b = 1; - for(std::size_t d = 0; - math::abs(prev->angle - back->angle) < eps - && ! back->incoming - && d < n; - d++) - { - --back; - ++b; - } - - // Same but forward to possibly include more incoming angles - int f = 1; - circling_iterator forward = cit + 1; - for(std::size_t d = 0; - math::abs(cit->angle - forward->angle) < eps - && forward->incoming - && d < n; - d++) - { - ++forward; - ++f; - } - -#ifdef BOOST_GEOMETRY_DEBUG_BUFFER_OCCUPATION - std::cout << "HANDLE " << b << "/" << f << " ANGLES" << std::endl; -#endif - - for(circling_iterator bit = prev; bit != back; --bit) - { - int code = side_strategy::apply(bit->direction_point, prev->intersection_point, prev->direction_point); - int code2 = side_strategy::apply(prev->direction_point, bit->intersection_point, bit->direction_point); - for(circling_iterator fit = cit; fit != forward; ++fit) - { - int code3 = side_strategy::apply(fit->direction_point, cit->intersection_point, cit->direction_point); - int code4 = side_strategy::apply(cit->direction_point, fit->intersection_point, fit->direction_point); - - if (! (code == -1 && code2 == 1)) - { - include_left_turn(*bit, *fit, turns, turn_indices, keep_indices); - debug_left_turn("ALSO", *fit, *bit, code, code2, code3, code4); - } - } - } - } - } -#ifdef BOOST_GEOMETRY_DEBUG_BUFFER_OCCUPATION - std::cout << "USE " << keep_indices.size() << " OF " << turn_indices.size() << " TURNS" << std::endl; -#endif - } - }; diff --git a/include/boost/geometry/algorithms/detail/overlay/turn_info.hpp b/include/boost/geometry/algorithms/detail/overlay/turn_info.hpp index a8aa754f4..89a60b21a 100644 --- a/include/boost/geometry/algorithms/detail/overlay/turn_info.hpp +++ b/include/boost/geometry/algorithms/detail/overlay/turn_info.hpp @@ -103,6 +103,12 @@ struct turn_info { return has12(type, type); } + + inline bool has(operation_type type) const + { + return this->operations[0].operation == type + || this->operations[1].operation == type; + } inline bool combination(operation_type type1, operation_type type2) const { @@ -121,8 +127,7 @@ struct turn_info } inline bool any_blocked() const { - return this->operations[0].operation == operation_blocked - || this->operations[1].operation == operation_blocked; + return has(operation_blocked); } diff --git a/include/boost/geometry/extensions/algorithms/buffer/buffer_inserter.hpp b/include/boost/geometry/extensions/algorithms/buffer/buffer_inserter.hpp index 19d6de8fb..2b70c3b8c 100644 --- a/include/boost/geometry/extensions/algorithms/buffer/buffer_inserter.hpp +++ b/include/boost/geometry/extensions/algorithms/buffer/buffer_inserter.hpp @@ -368,8 +368,8 @@ inline void buffer_inserter(GeometryInput const& geometry_input, OutputIterator #ifdef BOOST_GEOMETRY_DEBUG_WITH_MAPPER //collection.map_offsetted(mapper); //collection.map_offsetted_points(mapper); - //collection.map_turns(mapper); - collection.map_opposite_locations(mapper); + collection.map_turns(mapper); + //collection.map_opposite_locations(mapper); #endif collection.discard_rings(); diff --git a/include/boost/geometry/extensions/algorithms/buffer/buffer_policies.hpp b/include/boost/geometry/extensions/algorithms/buffer/buffer_policies.hpp index fc2c3b450..f6f7d8d50 100644 --- a/include/boost/geometry/extensions/algorithms/buffer/buffer_policies.hpp +++ b/include/boost/geometry/extensions/algorithms/buffer/buffer_policies.hpp @@ -101,9 +101,11 @@ template struct buffer_turn_operation : public detail::overlay::traversal_turn_operation { int piece_index; + bool include_in_occupation_map; inline buffer_turn_operation() : piece_index(-1) + , include_in_occupation_map(false) {} }; @@ -115,12 +117,14 @@ struct buffer_turn_info : public detail::overlay::turn_info piece_indices_to_skip; #ifdef BOOST_GEOMETRY_DEBUG_WITH_MAPPER @@ -130,6 +134,7 @@ struct buffer_turn_info : public detail::overlay::turn_info #include + #include #include @@ -173,6 +174,9 @@ struct buffered_piece_collection buffered_ring_collection traversed_rings; segment_identifier current_segment_id; + std::map, std::set > m_turn_indices_per_segment_pair; + + typedef std::vector > turn_vector_type; typedef detail::overlay::get_turn_info < @@ -297,6 +301,11 @@ struct buffered_piece_collection iterator next2 = next_point(ring2, it2); + if (piece1.index == 5 && piece2.index == 22) + { + int kkk = 0; + } + turn_policy::apply(*prev1, *it1, *next1, *prev2, *it2, *next2, the_model, std::back_inserter(m_turns)); @@ -429,7 +438,7 @@ struct buffered_piece_collection buffered_ring const& ring = offsetted_rings[seg_id.multi_index]; - int const side_offsetted = side_on_convex_range(turn.point, + int const side_offsetted = side_on_convex_range< /*relaxed_side */ side_strategy >(turn.point, boost::begin(ring) + seg_id.segment_index, boost::begin(ring) + pc.last_segment_index, seg_id, on_segment_seg_id); @@ -473,7 +482,7 @@ struct buffered_piece_collection } } - inline void debug_preference(std::string const& caption, std::set const& indices) const + inline void debug_turns_by_indices(std::string const& caption, std::set const& indices) const { #ifdef BOOST_GEOMETRY_DEBUG_BUFFER_OCCUPATION std::cout << caption << ": " << indices.size() << std::endl; @@ -493,21 +502,14 @@ struct buffered_piece_collection #endif } - template - static inline std::pair ordered_pair(T const& first, T const& second) - { - return first < second ? std::make_pair(first, second) : std::make_pair(second, first); - } - - std::map, std::set > turns_per_segment; inline void fill_segment_map() { - turns_per_segment.clear(); + m_turn_indices_per_segment_pair.clear(); int index = 0; for (typename boost::range_iterator::type it = boost::begin(m_turns); it != boost::end(m_turns); ++it, ++index) { - turns_per_segment + m_turn_indices_per_segment_pair [ ordered_pair ( @@ -518,156 +520,17 @@ struct buffered_piece_collection } } - template - static inline bool corresponds(Turn const& turn, segment_identifier const& seg_id) - { - return turn.operations[Index].operation == detail::overlay::operation_union - && turn.operations[Index].seg_id == seg_id; - } - inline bool prefer_one(std::set& indices) const - { - std::map map; - for (auto sit = indices.begin(); sit != indices.end(); ++sit) - { - int const index = *sit; - map[m_turns[index].operations[0].seg_id]++; - map[m_turns[index].operations[1].seg_id]++; - } - std::set segment_occuring_once; - for (auto mit = map.begin(); mit != map.end(); ++mit) - { - if (mit->second == 1) - { - segment_occuring_once.insert(mit->first); - } -#ifdef BOOST_GEOMETRY_DEBUG_BUFFER_PREFER - std::cout << si(mit->first) << " " << mit->second << std::endl; -#endif - } - - if (segment_occuring_once.size() == 2) - { - // Try to find within all turns a turn with these two segments - - std::set::const_iterator soo_it = segment_occuring_once.begin(); - segment_identifier front = *soo_it; - soo_it++; - segment_identifier back = *soo_it; - - std::pair pair = ordered_pair(front, back); - auto it = turns_per_segment.find(pair); - if (it != turns_per_segment.end()) - { - debug_preference("Found", it->second); - // Check which is the union/continue - segment_identifier good; - for (auto sit = it->second.begin(); sit != it->second.end(); ++sit) - { - if (m_turns[*sit].operations[0].operation == detail::overlay::operation_union) - { - good = m_turns[*sit].operations[0].seg_id; - } - else if (m_turns[*sit].operations[1].operation == detail::overlay::operation_union) - { - good = m_turns[*sit].operations[1].seg_id; - } - } - -#ifdef BOOST_GEOMETRY_DEBUG_BUFFER_PREFER - std::cout << "Good: " << si(good) << std::endl; -#endif - - // Find in indexes-to-keep this segment with the union. Discard the other one - std::set ok_indices; - for (auto sit = indices.begin(); sit != indices.end(); ++sit) - { - if (corresponds<0>(m_turns[*sit], good) || corresponds<1>(m_turns[*sit], good)) - { - ok_indices.insert(*sit); - } - } - if (ok_indices.size() > 0 && ok_indices.size() < indices.size()) - { - indices = ok_indices; - ////std::cout << "^"; - return true; - } - } - } - return false; - } - - inline void get_left_turns(buffer_occupation_info& info) + // Sets "count_on_multi" (if not kept) or "piece_indices_to_skip" (if kept) + // for to avoid within operations for these pieces + inline void process_left_turns(buffer_occupation_info const& info, + std::set const& keep_indices) { - std::set > keep_indices; - info.get_left_turns(m_turns, info.turn_indices, keep_indices); - - if (keep_indices.empty()) - { - return; - } - -#ifdef BOOST_GEOMETRY_DEBUG_BUFFER_OCCUPATION - for (std::set >::const_iterator sit = keep_indices.begin(); - sit != keep_indices.end(); - ++sit) - { - std::cout << " " << sit->first << "[" << sit->second << "]"; - } - std::cout << std::endl; -#endif - - // We have to create a version of the set with only turn_indices, ki - std::set ki; - for (std::set >::const_iterator sit = keep_indices.begin(); - sit != keep_indices.end(); - ++sit) - { - ki.insert(sit->first); - - if (m_turns[sit->first].both(detail::overlay::operation_union)) - { - // Avoid both turns of a u/u turn to be included. - if (keep_indices.count(std::make_pair(sit->first, 1 - sit->second)) == 0) - { - m_turns[sit->first].operations[1 - sit->second].operation = detail::overlay::operation_none; - } -#if defined(BOOST_GEOMETRY_COUNT_DOUBLE_UU) - else if (m_turns[sit->first].both(detail::overlay::operation_union)) - { - m_turns[sit->first].count_on_uu++; - } -#endif - } - -#ifdef BOOST_GEOMETRY_DEBUG_BUFFER_OCCUPATION - std::cout << "Keep " << sit->first << "[" << sit->second << "]" - << " "<< si(m_turns[sit->first].operations[0].seg_id) - << " "<< si(m_turns[sit->first].operations[1].seg_id) - << " " << m_turns[sit->first].operations[0].piece_index - << "/" << m_turns[sit->first].operations[1].piece_index - << " " << method_char(m_turns[sit->first].method) - << " " << operation_char(m_turns[sit->first].operations[0].operation) - << "/" << operation_char(m_turns[sit->first].operations[1].operation) - - << std::endl; -#endif - - } - - if (ki.size() == 2) - { - debug_preference("Keep", ki); - prefer_one(ki); - debug_preference("Kept", ki); - } - for (std::set::const_iterator sit1 = info.turn_indices.begin(); sit1 != info.turn_indices.end(); ++sit1) { - if (ki.count(*sit1) == 0) + if (keep_indices.count(*sit1) == 0) { m_turns[*sit1].count_on_multi++; } @@ -685,6 +548,22 @@ struct buffered_piece_collection } } } + } + + inline void get_left_turns(buffer_occupation_info& info) + { + debug_turns_by_indices("Examine", info.turn_indices); + + std::set keep_indices; + info.get_left_turns(m_turns, m_turn_indices_per_segment_pair, keep_indices); + + if (! keep_indices.empty()) + { +#ifdef BOOST_GEOMETRY_DEBUG_BUFFER_OCCUPATION + std::cout << "USE " << keep_indices.size() << " OF " << info.turn_indices.size() << " TURNS" << std::endl; +#endif + process_left_turns(info, keep_indices); + } } inline int piece_count(buffer_occupation_info const& info) @@ -703,20 +582,18 @@ struct buffered_piece_collection inline void classify_occupied_locations() { - fill_segment_map(); - for (typename boost::range_iterator::type it = boost::begin(m_occupation_map.map); it != boost::end(m_occupation_map.map); ++it) { buffer_occupation_info& info = it->second; - int const pc = piece_count(info); + #ifdef BOOST_GEOMETRY_DEBUG_BUFFER_OCCUPATION - std::cout << std::endl << "left turns: " << pc << " " + std::cout << std::endl << "left turns: " << piece_count(info) << " " //<< std::setprecision(20) << geometry::wkt(it->first) << std::endl; #endif - if (pc > 2) + if (piece_count(info) > 2) { if (info.occupied()) { @@ -724,10 +601,9 @@ struct buffered_piece_collection std::cout << "-> occupied" << std::endl; // std::set turn_indices; - //std::set > keep_indices; //info.get_left_turns(it->first, m_turns, turn_indices, keep_indices); // just for debug-info - #endif + for (std::set::const_iterator sit = info.turn_indices.begin(); sit != info.turn_indices.end(); ++sit) @@ -739,11 +615,62 @@ struct buffered_piece_collection { get_left_turns(info); } - //std::cout << geometry::wkt(it->first) << " " << int(info.occupied()) << std::endl; + //std::cout << geometry::wkt(it->first) << " " << int(info.occupied()) << std::endl; } } } + // The "get_left_turn" process indicates, if it is a u/u turn (both only applicable + // for union, two separate turns), which is indicated in the map. If done so, set + // the other to "none", it is part of an occupied situation and should not be followed. + inline void process_uu() + { + for (typename boost::range_iterator::type it = + boost::begin(m_turns); it != boost::end(m_turns); ++it) + { + if (it->both(detail::overlay::operation_union) + && (it->operations[0].include_in_occupation_map + || it->operations[1].include_in_occupation_map)) + { + bool set_to_none = false; + + // Avoid both turns of a u/u turn to be included. + if (! it->operations[0].include_in_occupation_map) + { + it->operations[0].operation = detail::overlay::operation_none; + set_to_none = true; + } + if (! it->operations[1].include_in_occupation_map) + { + it->operations[1].operation = detail::overlay::operation_none; + set_to_none = true; + } + if (set_to_none) + { + std::cout << "-"; + } +#if defined(BOOST_GEOMETRY_COUNT_DOUBLE_UU) + else + { + it->count_on_uu++; + } +#endif +#ifdef BOOST_GEOMETRY_DEBUG_BUFFER_OCCUPATION + //std::cout << "Keep " << *sit + // << " "<< si(m_turns[*sit].operations[0].seg_id) + // << " "<< si(m_turns[*sit].operations[1].seg_id) + // << " " << m_turns[*sit].operations[0].piece_index + // << "/" << m_turns[*sit].operations[1].piece_index + // << " " << method_char(m_turns[*sit].method) + // << " " << operation_char(m_turns[*sit].operations[0].operation) + // << "/" << operation_char(m_turns[*sit].operations[1].operation) + //<< std::endl; +#endif + + } + } + } + #define BOOST_GEOMETRY_DEBUG_BUFFER_SITUATION_MAP #ifdef BOOST_GEOMETRY_DEBUG_BUFFER_SITUATION_MAP inline int get_side(point_type const& point, Ring const& ring, int segment_index) @@ -833,9 +760,9 @@ struct buffered_piece_collection struct clustered_info { - std::vector intersecting_segments; - std::set intersecting_ids; int piece_index; + std::set intersecting_ids; + std::vector intersecting_segments; }; #ifdef OLD @@ -846,7 +773,7 @@ struct buffered_piece_collection }; #endif - inline bool add_mutual_intersection(clustered_info const& cluster, segment_identifier const& seg_id) + static inline bool add_mutual_intersection(clustered_info const& cluster, segment_identifier const& seg_id) { bool result = false; //if (cluster.intersecting_ids.count(seg_id) > 0) @@ -854,14 +781,52 @@ struct buffered_piece_collection { if (it->operation.seg_id == seg_id) { - //add_angles(it->turn_index); - //add_angles(it->turn_index, it->point, it->operation); result = true; } } return result; } + inline bool mutually_interact(cluster_info const& a, cluster_info const& b, clustered_info const& other) const + { + // Either these two segments intersect, or they are perfectly collinear. + // First check the intersection: + if (add_mutual_intersection(other, b.operation.seg_id)) + { + std::cout << "#"; + return true; + } + + // Then the collinearity + if (get_side(a.operation.seg_id, b.operation.seg_id) == 0) + { + std::cout << "1"; + return true; + + } + + if (get_side(a.operation.seg_id, b.operation.seg_id, 0) == 0) + { + std::cout << "0"; + return true; + } + + if (geometry::equals(a.point, b.point)) + { + std::cout << "="; + return true; + } + + relaxed_less comparator; + if (comparator.equals(a.point, b.point)) + { + std::cout << "*"; + return true; + } + + return false; + } + inline void add_mutual_intersections(clustered_info const& cluster, std::map const& map) { for(auto it1 = cluster.intersecting_segments.begin(); it1 != cluster.intersecting_segments.end(); it1++) @@ -874,41 +839,11 @@ struct buffered_piece_collection if (! m_occupation_map.contains_turn_index(it1->turn_index) || ! m_occupation_map.contains_turn_index(it2->turn_index)) { - // Either these two segments intersect, or they are perfectly collinear. - // First check the intersection: - if (add_mutual_intersection(other_cluster_it->second, it2->operation.seg_id)) - { - ////std::cout << "#"; - add_angles(it1->turn_index); - add_angles(it2->turn_index); - } - else - { - // Then the collinearity - int const code = get_side(it1->operation.seg_id, it2->operation.seg_id); - if (code == 0) - { - ////std::cout << "1"; - add_angles(it1->turn_index); - add_angles(it2->turn_index); - } - else - { - int const code = get_side(it1->operation.seg_id, it2->operation.seg_id, 0); - if (code == 0) - { - ////std::cout << "0"; - add_angles(it1->turn_index); - add_angles(it2->turn_index); - } - else if (geometry::equals(it1->point, it2->point)) - { - ////std::cout << "*"; - add_angles(it1->turn_index); - add_angles(it2->turn_index); - } - } - } + if (mutually_interact(*it1, *it2, other_cluster_it->second)) + { + add_angles(it1->turn_index); + add_angles(it2->turn_index); + } } } } @@ -928,23 +863,19 @@ struct buffered_piece_collection { buffer_turn_info const& turn = *it; - // if (! turn.both(detail::overlay::operation_union)) - { + // Take care with all the indices + map[turn.operations[0].seg_id].piece_index = turn.operations[0].piece_index; + map[turn.operations[0].seg_id].intersecting_segments.push_back(cluster_info(index, turn.point, turn.operations[1])); + map[turn.operations[0].seg_id].intersecting_ids.insert(turn.operations[1].seg_id); - // Take care with all the indices - map[turn.operations[0].seg_id].piece_index = turn.operations[0].piece_index; - map[turn.operations[0].seg_id].intersecting_segments.push_back(cluster_info(index, turn.point, turn.operations[1])); - map[turn.operations[0].seg_id].intersecting_ids.insert(turn.operations[1].seg_id); - - map[turn.operations[1].seg_id].piece_index = turn.operations[1].piece_index; - map[turn.operations[1].seg_id].intersecting_segments.push_back(cluster_info(index, turn.point, turn.operations[0])); - map[turn.operations[1].seg_id].intersecting_ids.insert(turn.operations[0].seg_id); - } + map[turn.operations[1].seg_id].piece_index = turn.operations[1].piece_index; + map[turn.operations[1].seg_id].intersecting_segments.push_back(cluster_info(index, turn.point, turn.operations[0])); + map[turn.operations[1].seg_id].intersecting_ids.insert(turn.operations[0].seg_id); } // Pass 2: // Verify all segments crossing with more than one segment, and if they intersect each other, - // at that pair + // add that pair for (typename map_type::const_iterator mit = map.begin(); mit != map.end(); ++mit) { if (mit->second.intersecting_segments.size() > 1) @@ -1069,6 +1000,53 @@ struct buffered_piece_collection } } + template + static inline void split_uu_turns(Turns& turns) + { + Turns added; + + for (typename boost::range_iterator::type it = boost::begin(turns); + it != boost::end(turns); ++it) + { + if (it->both(detail::overlay::operation_union)) + { + //std::cout << "U"; + + typename boost::range_value::type turn = *it; // copy by value + // std::swap(turn.operations[0], turn.operations[1]); + turn.operations[0].operation = detail::overlay::operation_continue; + turn.operations[1].operation = detail::overlay::operation_continue; + it->operations[1].operation = detail::overlay::operation_continue; + it->operations[0].operation = detail::overlay::operation_continue; + added.push_back(turn); + } + } + + for (typename boost::range_iterator::type it = boost::begin(added); + it != boost::end(added); ++it) + { + turns.push_back(*it); + } + + if (added.size() > 0) + { + for (typename boost::range_iterator::type it = boost::begin(turns); + it != boost::end(turns); ++it) + { + std::cout << "Turn" + << " "<< si(it->operations[0].seg_id) + << " "<< si(it->operations[1].seg_id) + << " " << it->operations[0].piece_index + << "/" << it->operations[1].piece_index + << " " << method_char(it->method) + << " " << operation_char(it->operations[0].operation) + << "/" << operation_char(it->operations[1].operation) + << std::endl; + } + } + + } + template inline void get_turns(Geometry const& input_geometry, int factor) { @@ -1090,8 +1068,30 @@ struct buffered_piece_collection } } + //discard_uu_turns(); + for (typename boost::range_iterator::type it = + boost::begin(m_turns); it != boost::end(m_turns); ++it) + { + //if (it->both(detail::overlay::operation_union)) + //{ + // std::cout << "double UU" << std::endl; + //} + //std::cout << std::setprecision(16) << geometry::wkt(it->point) + // << " " << it->operations[0].piece_index << "/" << it->operations[1].piece_index + // << " " << si(it->operations[0].seg_id) << "/" << si(it->operations[1].seg_id) + // << " " << method_char(it->method) + // << ":" << operation_char(it->operations[0].operation) + // << "/" << operation_char(it->operations[1].operation) + // << std::endl; + } + + //split_uu_turns(m_turns); + + + fill_segment_map(); get_occupation(); classify_occupied_locations(); + process_uu(); classify_turns(); classify_inside(); @@ -1249,6 +1249,17 @@ struct buffered_piece_collection } + // inline void discard_uu_turns() + // { + // m_turns.erase + //( + // std::remove_if(boost::begin(m_turns), boost::end(m_turns), + // uu_turn()), + // boost::end(m_turns) + //); + + // } + inline void traverse() { typedef detail::overlay::traverse