123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329 |
- // 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_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/iterators/closing_iterator.hpp>
- #include <boost/geometry/algorithms/detail/get_left_turns.hpp>
- namespace boost { namespace geometry
- {
- #ifndef DOXYGEN_NO_DETAIL
- 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 Point point_type;
- segment_identifier seg_id;
- int turn_index;
- int operation_index;
- Point intersection_point;
- Point direction_point;
- T angle;
- bool incoming;
- };
- 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)
- {}
- template <typename PointC, typename Point1, typename Point2>
- inline void add(PointC const& map_point, Point1 const& direction_point, Point2 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;
- }
- 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;
- if (comparator.equals(intersection_point, *it))
- {
- // It should be equal only once. But otherwise we skip it (in "add")
- it = advance_circular(it, ring, seg_id, false);
- }
- 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++)
- {
- it = advance_circular(it, ring, real_seg_id);
- }
- info.add(map_point, *it, intersection_point, turn_index, operation_index, real_seg_id, false);
- }
- // 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
- {
- public :
- typedef std::map<Point, OccupationInfo, relaxed_less<Point> > map_type;
- map_type map;
- std::set<int> turn_indices;
- inline OccupationInfo& find_or_insert(Point const& point, Point& mapped_point)
- {
- typename map_type::iterator it = map.find(point);
- if (it == boost::end(map))
- {
- std::pair<typename map_type::iterator, bool> pair
- = map.insert(std::make_pair(point, OccupationInfo()));
- it = pair.first;
- }
- mapped_point = it->first;
- return it->second;
- }
- inline bool contains(Point const& point) const
- {
- typename map_type::const_iterator it = map.find(point);
- return it != boost::end(map);
- }
- inline bool contains_turn_index(int index) const
- {
- return turn_indices.count(index) > 0;
- }
- inline void insert_turn_index(int index)
- {
- turn_indices.insert(index);
- }
- };
- } // namespace detail
- #endif // DOXYGEN_NO_DETAIL
- }} // namespace boost::geometry
- #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_OCCUPATION_INFO_HPP
|