File indexing completed on 2025-10-31 08:41:01
0001 
0002 
0003 
0004 
0005 
0006 
0007 
0008 
0009 
0010 
0011 
0012 
0013 
0014 #ifndef BOOST_GEOMETRY_STRATEGIES_CARTESIAN_TURN_IN_RING_WINDING_HPP
0015 #define BOOST_GEOMETRY_STRATEGIES_CARTESIAN_TURN_IN_RING_WINDING_HPP
0016 
0017 #include <boost/geometry/arithmetic/infinite_line_functions.hpp>
0018 #include <boost/geometry/core/access.hpp>
0019 #include <boost/geometry/core/config.hpp>
0020 #include <boost/geometry/algorithms/detail/make/make.hpp>
0021 #include <boost/geometry/util/math.hpp>
0022 
0023 #include <boost/geometry/strategies/cartesian/side_rounded_input.hpp>
0024 
0025 namespace boost { namespace geometry
0026 {
0027 
0028 namespace strategy { namespace buffer
0029 {
0030 
0031 #ifndef DOXYGEN_NO_DETAIL
0032 
0033 enum place_on_ring_type
0034 {
0035     
0036     
0037     
0038     
0039     
0040     
0041     
0042     place_on_ring_offsetted,
0043     place_on_ring_original,
0044     place_on_ring_to_offsetted,
0045     place_on_ring_from_offsetted,
0046 };
0047 
0048 template <typename CalculationType>
0049 class turn_in_ring_winding
0050 {
0051 
0052     
0053     
0054     
0055     
0056     
0057     
0058     
0059     
0060     
0061     
0062     
0063     
0064     
0065 
0066 
0067 public:
0068 
0069     struct counter
0070     {
0071         
0072         
0073         int count{0};
0074 
0075         int count_on_offsetted{0};
0076         int count_on_origin{0};
0077         int count_on_edge{0};
0078 
0079         CalculationType edge_min_fraction{(std::numeric_limits<CalculationType>::max)()};
0080 
0081         inline bool is_inside() const
0082         {
0083             return count < 0 || count_on_origin > 0;
0084         }
0085 
0086         inline bool is_on_boundary() const
0087         {
0088             return count_on_origin == 0
0089                 && (count_on_offsetted > 0
0090                 || (count_on_edge > 0 && edge_min_fraction < 1.0e-3)
0091                 );
0092         }
0093 
0094     };
0095 
0096     using state_type = counter;
0097 
0098     template <typename Point, typename PointOfSegment>
0099     static inline bool is_in_vertical_range(Point const& point,
0100                              PointOfSegment const& s1,
0101                              PointOfSegment const& s2)
0102     {
0103         CalculationType const py = get<1>(point);
0104         CalculationType const s1y = get<1>(s1);
0105         CalculationType const s2y = get<1>(s2);
0106 
0107         return s1y < s2y ? (py >= s1y && py <= s2y) : (py >= s2y && py <= s1y);
0108     }
0109 
0110     template <typename Point, typename PointOfSegment>
0111     static inline void apply_on_boundary(Point const& point,
0112                              PointOfSegment const& s1,
0113                              PointOfSegment const& s2,
0114                              place_on_ring_type place_on_ring,
0115                              counter& the_state)
0116     {
0117         if (place_on_ring == place_on_ring_offsetted)
0118         {
0119             the_state.count_on_offsetted++;
0120         }
0121         else if (place_on_ring == place_on_ring_to_offsetted
0122             || place_on_ring == place_on_ring_from_offsetted)
0123         {
0124             the_state.count_on_edge++;
0125 
0126             auto const line1 = detail::make::make_perpendicular_line<CalculationType>(s1, s2, s1);
0127             auto const line2 = detail::make::make_perpendicular_line<CalculationType>(s2, s1, s2);
0128 
0129             auto const value1 = arithmetic::side_value(line1, point);
0130             auto const value2 = arithmetic::side_value(line2, point);
0131             if (value1 >= 0 && value2 >= 0)
0132             {
0133                 auto const length_value = value1 + value2;
0134                 if (length_value > 0)
0135                 {
0136                     
0137                     auto const fraction = (place_on_ring == place_on_ring_to_offsetted ? value2 : value1) / length_value;
0138                     if (fraction < the_state.edge_min_fraction)
0139                     {
0140                         the_state.edge_min_fraction = fraction;
0141                     }
0142                 }
0143             }
0144         }
0145         else
0146         {
0147             the_state.count_on_origin++;
0148         }
0149     }
0150 
0151     template <typename Point, typename PointOfSegment>
0152     static inline bool apply(Point const& point,
0153                              PointOfSegment const& s1,
0154                              PointOfSegment const& s2,
0155                              place_on_ring_type place_on_ring,
0156                              bool is_convex,
0157                              counter& the_state)
0158     {
0159         int const side = strategy::side::side_rounded_input<CalculationType>::apply(s1, s2, point);
0160 
0161         if (is_convex && side > 0)
0162         {
0163             
0164             
0165             the_state.count = 1;
0166             return false;
0167         }
0168 
0169         CalculationType const px = get<0>(point);
0170         CalculationType const s1x = get<0>(s1);
0171         CalculationType const s2x = get<0>(s2);
0172 
0173         bool const in_horizontal_range = s1x < s2x ? (px >= s1x && px <= s2x) : (px >= s2x && px <= s1x);
0174 
0175         bool const vertical = s1x == s2x;
0176 
0177         if (in_horizontal_range || (vertical && is_in_vertical_range(point, s1, s2)))
0178         {
0179             if (side == 0)
0180             {
0181                 apply_on_boundary(point, s1, s2, place_on_ring, the_state);
0182             }
0183         }
0184 
0185         if (in_horizontal_range)
0186         {
0187             auto const on_boundary = the_state.count_on_offsetted + the_state.count_on_edge + the_state.count_on_origin;
0188             if (on_boundary == 0)
0189             {
0190                 
0191                 
0192                 
0193                 bool const eq1 = s1x == px;
0194                 bool const eq2 = s2x == px;
0195 
0196                 
0197                 
0198                 int const multiplier = eq1 || eq2 ? 1 : 2;
0199 
0200                 the_state.count += side * multiplier;
0201             }
0202         }
0203 
0204         return true;
0205     }
0206 };
0207 
0208 #endif 
0209 
0210 }} 
0211 
0212 }} 
0213 
0214 #endif 
0215