File indexing completed on 2025-01-18 09:36:44
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 #if defined(BOOST_GEOMETRY_USE_RESCALING)
0081 CalculationType inside_min_measure{(std::numeric_limits<CalculationType>::max)()};
0082 #endif
0083
0084 inline bool is_inside() const
0085 {
0086 return count < 0 || count_on_origin > 0;
0087 }
0088
0089 inline bool is_on_boundary() const
0090 {
0091 return count_on_origin == 0
0092 && (count_on_offsetted > 0
0093 || (count_on_edge > 0 && edge_min_fraction < 1.0e-3)
0094 #if defined(BOOST_GEOMETRY_USE_RESCALING)
0095 || (count < 0 && inside_min_measure < 1.0e-5)
0096 #endif
0097 );
0098 }
0099
0100 };
0101
0102 using state_type = counter;
0103
0104 template <typename Point, typename PointOfSegment>
0105 static inline bool is_in_vertical_range(Point const& point,
0106 PointOfSegment const& s1,
0107 PointOfSegment const& s2)
0108 {
0109 CalculationType const py = get<1>(point);
0110 CalculationType const s1y = get<1>(s1);
0111 CalculationType const s2y = get<1>(s2);
0112
0113 return s1y < s2y ? (py >= s1y && py <= s2y) : (py >= s2y && py <= s1y);
0114 }
0115
0116 template <typename Point, typename PointOfSegment>
0117 static inline void apply_on_boundary(Point const& point,
0118 PointOfSegment const& s1,
0119 PointOfSegment const& s2,
0120 place_on_ring_type place_on_ring,
0121 counter& the_state)
0122 {
0123 if (place_on_ring == place_on_ring_offsetted)
0124 {
0125 the_state.count_on_offsetted++;
0126 }
0127 else if (place_on_ring == place_on_ring_to_offsetted
0128 || place_on_ring == place_on_ring_from_offsetted)
0129 {
0130 the_state.count_on_edge++;
0131
0132 auto const line1 = detail::make::make_perpendicular_line<CalculationType>(s1, s2, s1);
0133 auto const line2 = detail::make::make_perpendicular_line<CalculationType>(s2, s1, s2);
0134
0135 auto const value1 = arithmetic::side_value(line1, point);
0136 auto const value2 = arithmetic::side_value(line2, point);
0137 if (value1 >= 0 && value2 >= 0)
0138 {
0139 auto const length_value = value1 + value2;
0140 if (length_value > 0)
0141 {
0142
0143 auto const fraction = (place_on_ring == place_on_ring_to_offsetted ? value2 : value1) / length_value;
0144 if (fraction < the_state.edge_min_fraction)
0145 {
0146 the_state.edge_min_fraction = fraction;
0147 }
0148 }
0149 }
0150 }
0151 else
0152 {
0153 the_state.count_on_origin++;
0154 }
0155 }
0156
0157 template <typename Point, typename PointOfSegment>
0158 static inline bool apply(Point const& point,
0159 PointOfSegment const& s1,
0160 PointOfSegment const& s2,
0161 place_on_ring_type place_on_ring,
0162 bool is_convex,
0163 counter& the_state)
0164 {
0165 int const side = strategy::side::side_rounded_input<CalculationType>::apply(s1, s2, point);
0166
0167 if (is_convex && side > 0)
0168 {
0169
0170
0171 the_state.count = 1;
0172 return false;
0173 }
0174
0175 CalculationType const px = get<0>(point);
0176 CalculationType const s1x = get<0>(s1);
0177 CalculationType const s2x = get<0>(s2);
0178
0179 bool const in_horizontal_range = s1x < s2x ? (px >= s1x && px <= s2x) : (px >= s2x && px <= s1x);
0180
0181 bool const vertical = s1x == s2x;
0182
0183 if (in_horizontal_range || (vertical && is_in_vertical_range(point, s1, s2)))
0184 {
0185 if (side == 0)
0186 {
0187 apply_on_boundary(point, s1, s2, place_on_ring, the_state);
0188 }
0189 #if defined(BOOST_GEOMETRY_USE_RESCALING)
0190 else if (side == -1)
0191 {
0192 auto const line = detail::make::make_infinite_line<CalculationType>(s1, s2);
0193 auto const value = -arithmetic::side_value(line, point);
0194 if (value > 0 && value < the_state.inside_min_measure) { the_state.inside_min_measure = value; }
0195
0196 }
0197 #endif
0198 }
0199
0200 if (in_horizontal_range)
0201 {
0202 auto const on_boundary = the_state.count_on_offsetted + the_state.count_on_edge + the_state.count_on_origin;
0203 if (on_boundary == 0)
0204 {
0205
0206
0207
0208 bool const eq1 = s1x == px;
0209 bool const eq2 = s2x == px;
0210
0211
0212
0213 int const multiplier = eq1 || eq2 ? 1 : 2;
0214
0215 the_state.count += side * multiplier;
0216 }
0217 }
0218
0219 return true;
0220 }
0221 };
0222
0223 #endif
0224
0225 }}
0226
0227 }}
0228
0229 #endif
0230