File indexing completed on 2025-09-18 08:44:42
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