Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-08-26 08:45:54

0001 // Boost.Geometry
0002 
0003 // Copyright (c) 2025 Barend Gehrels, Amsterdam, the Netherlands.
0004 
0005 // Use, modification and distribution is subject to the Boost Software License,
0006 // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
0007 // http://www.boost.org/LICENSE_1_0.txt)
0008 
0009 #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_GET_PROPERTIES_AHEAD_HPP
0010 #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_GET_PROPERTIES_AHEAD_HPP
0011 
0012 #include <boost/geometry/algorithms/detail/overlay/get_ring.hpp>
0013 #include <boost/geometry/algorithms/detail/overlay/overlay_type.hpp>
0014 #include <boost/geometry/algorithms/detail/overlay/copy_segment_point.hpp>
0015 #include <boost/geometry/algorithms/detail/overlay/segment_identifier.hpp>
0016 
0017 #if defined(BOOST_GEOMETRY_DEBUG_GET_PROPERTIES_AHEAD)
0018 #include <boost/geometry/io/wkt/wkt.hpp>
0019 #endif
0020 
0021 namespace boost { namespace geometry
0022 {
0023 
0024 #ifndef DOXYGEN_NO_DETAIL
0025 namespace detail { namespace overlay
0026 {
0027 
0028 // Get properties ahead of a turn. This is important for turns marked as cc (continue-continue).
0029 // It walks over the ring (of each operation) into the direction of the next turn,
0030 // as long as the points are collinear.
0031 // It then reports both the collinear (comparable) distance, of the turn to the point where it bend,
0032 // and the side of the next point. So where it bends to.
0033 template
0034 <
0035     bool Reverse1, bool Reverse2,
0036     typename Turns, typename Clusters,
0037     typename Geometry1, typename Geometry2,
0038     typename IntersectionStrategy
0039 >
0040 void get_properties_ahead(Turns& turns, Clusters const& clusters,
0041         Geometry1 const& geometry1, Geometry2 const& geometry2,
0042         IntersectionStrategy const& intersection_strategy)
0043 {
0044     using point_type = typename Turns::value_type::point_type;
0045     auto const side_strategy = intersection_strategy.side();
0046     auto const comparable_distance_strategy
0047         = intersection_strategy.comparable_distance(point_type(), point_type());
0048 
0049     auto walk_ahead = [&](auto const& turn, auto& op)
0050     {
0051         auto current_ring_id = ring_id_by_seg_id(op.seg_id);
0052         auto const& next_turn = turns[op.enriched.travels_to_ip_index];
0053         auto const next_ring_id0 = ring_id_by_seg_id(next_turn.operations[0].seg_id);
0054         auto const next_op_index = next_ring_id0 == current_ring_id ? 0 : 1;
0055         auto const& next_op = next_turn.operations[next_op_index];
0056         signed_size_type const point_count_to_next_turn = current_ring_id.source_index == 0
0057                         ? segment_distance(geometry1, op.seg_id, next_op.seg_id)
0058                         : segment_distance(geometry2, op.seg_id, next_op.seg_id);
0059 
0060         int offset = 0;
0061         point_type point_of_segment0;
0062         geometry::copy_segment_point<Reverse1, Reverse2>(geometry1, geometry2, op.seg_id,
0063             offset++, point_of_segment0);
0064 
0065 #if defined(BOOST_GEOMETRY_DEBUG_GET_PROPERTIES_AHEAD)
0066         std::cout << " EXAMINE AHEAD: ring " <<  current_ring_id
0067             << " segment: " << op.seg_id.segment_index
0068             << "  [ until turn: " << op.enriched.travels_to_ip_index
0069             << " at: " << next_op.seg_id.segment_index
0070             << " count: " << point_count_to_next_turn
0071             << " " << geometry::wkt(next_turn.point)
0072             << " ]"
0073             << std::endl;
0074 #endif
0075 
0076         // It starts with the distance from the turn to the next point on the segment.
0077 
0078         point_type point_of_segment1;
0079         point_type side_changing_point_ahead = turn.point;
0080         bool found = false;
0081         int final_side = 0;
0082         for (auto i = 0; i <= point_count_to_next_turn; i++, offset++)
0083         {
0084             point_type current_point;
0085             if (i == point_count_to_next_turn)
0086             {
0087                 current_point = next_turn.point;
0088             }
0089             else
0090             {
0091                 geometry::copy_segment_point<Reverse1, Reverse2>(geometry1, geometry2,
0092                     op.seg_id, offset, current_point);
0093             }
0094             if (i == 0)
0095             {
0096                 point_of_segment1 = current_point;
0097             }
0098             int const side = side_strategy.apply(point_of_segment0, point_of_segment1,
0099                 current_point);
0100 #if defined(BOOST_GEOMETRY_DEBUG_GET_PROPERTIES_AHEAD)
0101             std::cout << "  " << i << " " << geometry::wkt(current_point)
0102                 << " side: " << side
0103                 << std::endl;
0104 #endif
0105             if (side != 0)
0106             {
0107                 found = true;
0108                 final_side = side;
0109                 break;
0110             }
0111             if (! found)
0112             {
0113                 side_changing_point_ahead = current_point;
0114             }
0115         }
0116 
0117         op.enriched.ahead_distance_of_side_change
0118             = comparable_distance_strategy.apply(point_of_segment0, side_changing_point_ahead);
0119         op.enriched.ahead_side = final_side;
0120 #if defined(BOOST_GEOMETRY_DEBUG_GET_PROPERTIES_AHEAD)
0121         std::cout << "  result: " << op.enriched.ahead_distance_of_side_change
0122             << " side: " << op.enriched.ahead_side
0123             << std::endl;
0124 #endif
0125     };
0126 
0127     // First examine all clusters (this includes cc turns)
0128     for (const auto& key_value : clusters)
0129     {
0130         auto const& cluster = key_value.second;
0131         for (auto const& index : cluster.turn_indices)
0132         {
0133             auto& turn = turns[index];
0134             for (auto& op : turn.operations)
0135             {
0136                 if (op.enriched.travels_to_ip_index == -1)
0137                 {
0138                     continue;
0139                 }
0140 #ifdef BOOST_GEOMETRY_DEBUG_GET_PROPERTIES_AHEAD
0141                 std::cout << "Cluster " << turn.cluster_id
0142                     << " turn " << index
0143                     << " " << operation_char(op.operation)
0144                     << " travels to " << op.enriched.travels_to_ip_index
0145                     << std::endl;
0146 #endif
0147                 walk_ahead(turn, op);
0148             }
0149         }
0150     }
0151 
0152     // Then do the remaining cc turns
0153     for (auto& turn : turns)
0154     {
0155         if (turn.discarded || turn.is_clustered() || ! turn.both(operation_continue))
0156         {
0157             continue;
0158         }
0159 
0160         auto& op0 = turn.operations[0];
0161         auto& op1 = turn.operations[1];
0162 
0163         // IMPLEMENTATION NOTE:
0164         // This means: it should be called AFTER enrichment.
0165         // Which is called after assigning counts.
0166         if (op0.enriched.travels_to_ip_index == -1 || op1.enriched.travels_to_ip_index == -1)
0167         {
0168             continue;
0169         }
0170 
0171         walk_ahead(turn, op0);
0172         walk_ahead(turn, op1);
0173     }
0174 }
0175 
0176 
0177 }} // namespace detail::overlay
0178 #endif //DOXYGEN_NO_DETAIL
0179 
0180 
0181 }} // namespace boost::geometry
0182 
0183 #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_GET_PROPERTIES_AHEAD_HPP