summaryrefslogtreecommitdiff
path: root/boost/geometry/algorithms/detail/occupation_info.hpp
diff options
context:
space:
mode:
Diffstat (limited to 'boost/geometry/algorithms/detail/occupation_info.hpp')
-rw-r--r--boost/geometry/algorithms/detail/occupation_info.hpp356
1 files changed, 110 insertions, 246 deletions
diff --git a/boost/geometry/algorithms/detail/occupation_info.hpp b/boost/geometry/algorithms/detail/occupation_info.hpp
index e147ba12d8..d90f3cf7cf 100644
--- a/boost/geometry/algorithms/detail/occupation_info.hpp
+++ b/boost/geometry/algorithms/detail/occupation_info.hpp
@@ -1,6 +1,6 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
-// Copyright (c) 2012 Barend Gehrels, Amsterdam, the Netherlands.
+// Copyright (c) 2012-2014 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
@@ -9,17 +9,13 @@
#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_OCCUPATION_INFO_HPP
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OCCUPATION_INFO_HPP
-#if ! defined(NDEBUG)
- #define BOOST_GEOMETRY_DEBUG_BUFFER_OCCUPATION
-#endif
-
#include <algorithm>
#include <boost/range.hpp>
#include <boost/geometry/core/coordinate_type.hpp>
#include <boost/geometry/core/point_type.hpp>
-#include <boost/geometry/algorithms/equals.hpp>
+#include <boost/geometry/policies/compare.hpp>
#include <boost/geometry/iterators/closing_iterator.hpp>
#include <boost/geometry/algorithms/detail/get_left_turns.hpp>
@@ -33,291 +29,159 @@ namespace boost { namespace geometry
namespace detail
{
-template <typename P>
-class relaxed_less
-{
- typedef typename geometry::coordinate_type<P>::type coordinate_type;
-
- coordinate_type epsilon;
-
-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.
- epsilon = std::numeric_limits<double>::epsilon() * 100.0;
- }
-
- inline bool operator()(P const& a, P const& b) const
- {
- coordinate_type const dx = math::abs(geometry::get<0>(a) - geometry::get<0>(b));
- coordinate_type const dy = math::abs(geometry::get<1>(a) - geometry::get<1>(b));
-
-
- if (dx < epsilon && dy < epsilon)
- {
- return false;
- }
- if (dx < epsilon)
- {
- return geometry::get<1>(a) < geometry::get<1>(b);
- }
-
- return geometry::get<0>(a) < geometry::get<0>(b);
- }
-
- inline bool equals(P const& a, P const& b) const
- {
- typedef typename geometry::coordinate_type<P>::type coordinate_type;
-
- coordinate_type const dx = math::abs(geometry::get<0>(a) - geometry::get<0>(b));
- coordinate_type const dy = math::abs(geometry::get<1>(a) - geometry::get<1>(b));
-
- return dx < epsilon && dy < epsilon;
- };
-};
-
-
-template <typename T, typename P1, typename P2>
-inline T calculate_angle(P1 const& from_point, P2 const& to_point)
-{
- typedef P1 vector_type;
- vector_type v = from_point;
- geometry::subtract_point(v, to_point);
- return atan2(geometry::get<1>(v), geometry::get<0>(v));
-}
-
-template <typename Iterator, typename Vector>
-inline Iterator advance_circular(Iterator it, Vector const& vector, segment_identifier& seg_id, bool forward = true)
-{
- int const increment = forward ? 1 : -1;
- if (it == boost::begin(vector) && increment < 0)
- {
- it = boost::end(vector);
- seg_id.segment_index = boost::size(vector);
- }
- it += increment;
- seg_id.segment_index += increment;
- if (it == boost::end(vector))
- {
- seg_id.segment_index = 0;
- it = boost::begin(vector);
- }
- return it;
-}
-
template <typename Point, typename T>
struct angle_info
{
- typedef T angle_type;
+ typedef T angle_type;
typedef Point point_type;
segment_identifier seg_id;
int turn_index;
int operation_index;
+ std::size_t cluster_index;
Point intersection_point;
- Point direction_point;
- T angle;
+ Point point; // either incoming or outgoing point
bool incoming;
+ bool blocked;
+ bool included;
+
+ inline angle_info()
+ : blocked(false)
+ , included(false)
+ {}
};
template <typename AngleInfo>
class occupation_info
{
- typedef std::vector<AngleInfo> collection_type;
-
- struct angle_sort
- {
- inline bool operator()(AngleInfo const& left, AngleInfo const& right) const
- {
- // In this case we can compare even double using equals
- // return geometry::math::equals(left.angle, right.angle)
- return left.angle == right.angle
- ? int(left.incoming) < int(right.incoming)
- : left.angle < right.angle
- ;
- }
- };
-
-public :
- collection_type angles;
-private :
- bool m_occupied;
- bool m_calculated;
-
- inline bool is_occupied()
- {
- if (boost::size(angles) <= 1)
- {
- return false;
- }
-
- std::sort(angles.begin(), angles.end(), angle_sort());
-
- typedef geometry::closing_iterator<collection_type const> closing_iterator;
- closing_iterator vit(angles);
- closing_iterator end(angles, true);
-
- closing_iterator prev = vit++;
- for( ; vit != end; prev = vit++)
- {
- if (! geometry::math::equals(prev->angle, vit->angle)
- && ! prev->incoming
- && vit->incoming)
- {
- return false;
- }
- }
- return true;
- }
-
public :
- inline occupation_info()
- : m_occupied(false)
- , m_calculated(false)
- {}
+ typedef std::vector<AngleInfo> collection_type;
- template <typename PointC, typename Point1, typename Point2>
- inline void add(PointC const& map_point, Point1 const& direction_point, Point2 const& intersection_point,
+ template <typename RobustPoint>
+ inline void add(RobustPoint const& incoming_point,
+ RobustPoint const& outgoing_point,
+ RobustPoint const& intersection_point,
int turn_index, int operation_index,
- segment_identifier const& seg_id, bool incoming)
- {
- //std::cout << "-> adding angle " << geometry::wkt(direction_point) << " .. " << geometry::wkt(intersection_point) << " " << int(incoming) << std::endl;
- if (geometry::equals(direction_point, intersection_point))
- {
- //std::cout << "EQUAL! Skipping" << std::endl;
- return;
- }
+ segment_identifier const& seg_id)
+ {
+ geometry::equal_to<RobustPoint> comparator;
+ if (comparator(incoming_point, intersection_point))
+ {
+ return;
+ }
+ if (comparator(outgoing_point, intersection_point))
+ {
+ return;
+ }
AngleInfo info;
- info.incoming = incoming;
- info.angle = calculate_angle<typename AngleInfo::angle_type>(direction_point, map_point);
info.seg_id = seg_id;
info.turn_index = turn_index;
info.operation_index = operation_index;
info.intersection_point = intersection_point;
- info.direction_point = direction_point;
- angles.push_back(info);
-
- m_calculated = false;
- }
-
- inline bool occupied()
- {
- if (! m_calculated)
- {
- m_occupied = is_occupied();
- m_calculated = true;
- }
- return m_occupied;
- }
-
- template <typename Turns, typename TurnSegmentIndices>
- inline void get_left_turns(
- Turns& turns, TurnSegmentIndices const& turn_segment_indices,
- std::set<int>& keep_indices)
- {
- std::sort(angles.begin(), angles.end(), angle_sort());
- calculate_left_turns<AngleInfo>(angles, turns, turn_segment_indices, keep_indices);
- }
-};
-
-
-template <typename Point, typename Ring, typename Info>
-inline void add_incoming_and_outgoing_angles(Point const& map_point, Point const& intersection_point,
- Ring const& ring,
- int turn_index,
- int operation_index,
- segment_identifier seg_id,
- Info& info)
-{
- typedef typename boost::range_iterator
- <
- Ring const
- >::type iterator_type;
-
- int const n = boost::size(ring);
- if (seg_id.segment_index >= n || seg_id.segment_index < 0)
- {
- return;
- }
-
- segment_identifier real_seg_id = seg_id;
- iterator_type it = boost::begin(ring) + seg_id.segment_index;
- // TODO: if we use turn-info ("to", "middle"), we know if to advance without resorting to equals
- relaxed_less<Point> comparator;
+ {
+ info.point = incoming_point;
+ info.incoming = true;
+ m_angles.push_back(info);
+ }
+ {
+ info.point = outgoing_point;
+ info.incoming = false;
+ m_angles.push_back(info);
+ }
+ }
- if (comparator.equals(intersection_point, *it))
+ template <typename RobustPoint, typename Turns>
+ inline void get_left_turns(RobustPoint const& origin, Turns& turns)
{
- // It should be equal only once. But otherwise we skip it (in "add")
- it = advance_circular(it, ring, seg_id, false);
+ // Sort on angle
+ std::sort(m_angles.begin(), m_angles.end(),
+ detail::left_turns::angle_less<typename AngleInfo::point_type>(origin));
+
+ // Group same-angled elements
+ std::size_t cluster_size = detail::left_turns::assign_cluster_indices(m_angles, origin);
+ // Block all turns on the right side of any turn
+ detail::left_turns::block_turns(m_angles, cluster_size);
+ detail::left_turns::get_left_turns(m_angles, turns);
}
- info.add(map_point, *it, intersection_point, turn_index, operation_index, real_seg_id, true);
-
- if (comparator.equals(intersection_point, *it))
- {
- it = advance_circular(it, ring, real_seg_id);
- }
- else
- {
- // Don't upgrade the ID
- it = advance_circular(it, ring, seg_id);
- }
- for (int defensive_check = 0;
- comparator.equals(intersection_point, *it) && defensive_check < n;
- defensive_check++)
+#if defined(BOOST_GEOMETRY_BUFFER_ENLARGED_CLUSTERS)
+ template <typename RobustPoint>
+ inline bool has_rounding_issues(RobustPoint const& origin) const
{
- it = advance_circular(it, ring, real_seg_id);
+ return detail::left_turns::has_rounding_issues(angles, origin);
}
+#endif
- info.add(map_point, *it, intersection_point, turn_index, operation_index, real_seg_id, false);
-}
-
+private :
+ collection_type m_angles; // each turn splitted in incoming/outgoing vectors
+};
-// Map in two senses of the word: it is a std::map where the key is a point.
-// Per point an "occupation_info" record is kept
-// Used for the buffer (but will also be used for intersections/unions having complex self-tangencies)
-template <typename Point, typename OccupationInfo>
-class occupation_map
+template<typename Pieces>
+inline void move_index(Pieces const& pieces, int& index, int& piece_index, int direction)
{
-public :
- typedef std::map<Point, OccupationInfo, relaxed_less<Point> > map_type;
+ BOOST_ASSERT(direction == 1 || direction == -1);
+ BOOST_ASSERT(piece_index >= 0 && piece_index < static_cast<int>(boost::size(pieces)) );
+ BOOST_ASSERT(index >= 0 && index < static_cast<int>(boost::size(pieces[piece_index].robust_ring)));
- map_type map;
- std::set<int> turn_indices;
-
- inline OccupationInfo& find_or_insert(Point const& point, Point& mapped_point)
+ index += direction;
+ if (direction == -1 && index < 0)
{
- typename map_type::iterator it = map.find(point);
- if (it == boost::end(map))
+ piece_index--;
+ if (piece_index < 0)
{
- std::pair<typename map_type::iterator, bool> pair
- = map.insert(std::make_pair(point, OccupationInfo()));
- it = pair.first;
+ piece_index = boost::size(pieces) - 1;
}
- mapped_point = it->first;
- return it->second;
+ index = boost::size(pieces[piece_index].robust_ring) - 1;
}
-
- inline bool contains(Point const& point) const
+ if (direction == 1
+ && index >= static_cast<int>(boost::size(pieces[piece_index].robust_ring)))
{
- typename map_type::const_iterator it = map.find(point);
- return it != boost::end(map);
+ piece_index++;
+ if (piece_index >= static_cast<int>(boost::size(pieces)))
+ {
+ piece_index = 0;
+ }
+ index = 0;
}
+}
- inline bool contains_turn_index(int index) const
- {
- return turn_indices.count(index) > 0;
- }
- inline void insert_turn_index(int index)
+template
+<
+ typename RobustPoint,
+ typename Turn,
+ typename Pieces,
+ typename Info
+>
+inline void add_incoming_and_outgoing_angles(
+ RobustPoint const& intersection_point, // rescaled
+ Turn const& turn,
+ Pieces const& pieces, // using rescaled offsets of it
+ int operation_index,
+ segment_identifier seg_id,
+ Info& info)
+{
+ segment_identifier real_seg_id = seg_id;
+ geometry::equal_to<RobustPoint> comparator;
+
+ // Move backward and forward
+ RobustPoint direction_points[2];
+ for (int i = 0; i < 2; i++)
{
- turn_indices.insert(index);
+ int index = turn.operations[operation_index].index_in_robust_ring;
+ int piece_index = turn.operations[operation_index].piece_index;
+ while(comparator(pieces[piece_index].robust_ring[index], intersection_point))
+ {
+ move_index(pieces, index, piece_index, i == 0 ? -1 : 1);
+ }
+ direction_points[i] = pieces[piece_index].robust_ring[index];
}
-};
+
+ info.add(direction_points[0], direction_points[1], intersection_point,
+ turn.turn_index, operation_index, real_seg_id);
+}
} // namespace detail