1 // Boost.Geometry (aka GGL, Generic Geometry Library) 2 3 // Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. 4 // Copyright (c) 2013 Adam Wulkiewicz, Lodz, Poland. 5 6 // This file was modified by Oracle on 2013, 2014, 2016, 2017, 2018, 2019. 7 // Modifications copyright (c) 2013-2019 Oracle and/or its affiliates. 8 // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle 9 10 // Parts of Boost.Geometry are redesigned from Geodan's Geographic Library 11 // (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands. 12 13 // Use, modification and distribution is subject to the Boost Software License, 14 // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at 15 // http://www.boost.org/LICENSE_1_0.txt) 16 17 #ifndef BOOST_GEOMETRY_STRATEGY_CARTESIAN_POINT_IN_POLY_WINDING_HPP 18 #define BOOST_GEOMETRY_STRATEGY_CARTESIAN_POINT_IN_POLY_WINDING_HPP 19 20 21 #include <boost/geometry/core/tags.hpp> 22 23 #include <boost/geometry/util/math.hpp> 24 #include <boost/geometry/util/select_calculation_type.hpp> 25 26 #include <boost/geometry/strategies/cartesian/point_in_box.hpp> 27 #include <boost/geometry/strategies/cartesian/disjoint_box_box.hpp> 28 #include <boost/geometry/strategies/cartesian/side_by_triangle.hpp> 29 #include <boost/geometry/strategies/covered_by.hpp> 30 #include <boost/geometry/strategies/within.hpp> 31 32 33 namespace boost { namespace geometry 34 { 35 36 namespace strategy { namespace within 37 { 38 39 40 /*! 41 \brief Within detection using winding rule in cartesian coordinate system. 42 \ingroup strategies 43 \tparam Point_ \tparam_point 44 \tparam PointOfSegment_ \tparam_segment_point 45 \tparam CalculationType \tparam_calculation 46 \author Barend Gehrels 47 48 \qbk{ 49 [heading See also] 50 [link geometry.reference.algorithms.within.within_3_with_strategy within (with strategy)] 51 } 52 */ 53 template 54 < 55 typename Point_ = void, // for backward compatibility 56 typename PointOfSegment_ = Point_, // for backward compatibility 57 typename CalculationType = void 58 > 59 class cartesian_winding 60 { 61 template <typename Point, typename PointOfSegment> 62 struct calculation_type 63 : select_calculation_type 64 < 65 Point, 66 PointOfSegment, 67 CalculationType 68 > 69 {}; 70 71 /*! subclass to keep state */ 72 class counter 73 { 74 int m_count; 75 bool m_touches; 76 code() const77 inline int code() const 78 { 79 return m_touches ? 0 : m_count == 0 ? -1 : 1; 80 } 81 82 public : 83 friend class cartesian_winding; 84 counter()85 inline counter() 86 : m_count(0) 87 , m_touches(false) 88 {} 89 90 }; 91 92 public: 93 typedef cartesian_tag cs_tag; 94 95 typedef side::side_by_triangle<CalculationType> side_strategy_type; 96 get_side_strategy()97 static inline side_strategy_type get_side_strategy() 98 { 99 return side_strategy_type(); 100 } 101 102 typedef expand::cartesian_point expand_point_strategy_type; 103 104 typedef typename side_strategy_type::envelope_strategy_type envelope_strategy_type; 105 get_envelope_strategy()106 static inline envelope_strategy_type get_envelope_strategy() 107 { 108 return side_strategy_type::get_envelope_strategy(); 109 } 110 111 typedef typename side_strategy_type::disjoint_strategy_type disjoint_strategy_type; 112 get_disjoint_strategy()113 static inline disjoint_strategy_type get_disjoint_strategy() 114 { 115 return side_strategy_type::get_disjoint_strategy(); 116 } 117 118 typedef typename side_strategy_type::equals_point_point_strategy_type equals_point_point_strategy_type; get_equals_point_point_strategy()119 static inline equals_point_point_strategy_type get_equals_point_point_strategy() 120 { 121 return side_strategy_type::get_equals_point_point_strategy(); 122 } 123 124 typedef disjoint::cartesian_box_box disjoint_box_box_strategy_type; get_disjoint_box_box_strategy()125 static inline disjoint_box_box_strategy_type get_disjoint_box_box_strategy() 126 { 127 return disjoint_box_box_strategy_type(); 128 } 129 130 typedef covered_by::cartesian_point_box disjoint_point_box_strategy_type; 131 132 // Typedefs and static methods to fulfill the concept 133 typedef counter state_type; 134 135 template <typename Point, typename PointOfSegment> apply(Point const & point,PointOfSegment const & s1,PointOfSegment const & s2,counter & state)136 static inline bool apply(Point const& point, 137 PointOfSegment const& s1, PointOfSegment const& s2, 138 counter& state) 139 { 140 bool eq1 = false; 141 bool eq2 = false; 142 143 int count = check_segment(point, s1, s2, state, eq1, eq2); 144 if (count != 0) 145 { 146 int side = 0; 147 if (count == 1 || count == -1) 148 { 149 side = side_equal(point, eq1 ? s1 : s2, count); 150 } 151 else // count == 2 || count == -2 152 { 153 // 1 left, -1 right 154 side = side_strategy_type::apply(s1, s2, point); 155 } 156 157 if (side == 0) 158 { 159 // Point is lying on segment 160 state.m_touches = true; 161 state.m_count = 0; 162 return false; 163 } 164 165 // Side is NEG for right, POS for left. 166 // The count is -2 for left, 2 for right (or -1/1) 167 // Side positive thus means RIGHT and LEFTSIDE or LEFT and RIGHTSIDE 168 // See accompagnying figure (TODO) 169 if (side * count > 0) 170 { 171 state.m_count += count; 172 } 173 } 174 return ! state.m_touches; 175 } 176 result(counter const & state)177 static inline int result(counter const& state) 178 { 179 return state.code(); 180 } 181 182 private: 183 template <typename Point, typename PointOfSegment> check_segment(Point const & point,PointOfSegment const & seg1,PointOfSegment const & seg2,counter & state,bool & eq1,bool & eq2)184 static inline int check_segment(Point const& point, 185 PointOfSegment const& seg1, 186 PointOfSegment const& seg2, 187 counter& state, 188 bool& eq1, bool& eq2) 189 { 190 if (check_touch(point, seg1, seg2, state, eq1, eq2)) 191 { 192 return 0; 193 } 194 195 return calculate_count(point, seg1, seg2, eq1, eq2); 196 } 197 198 template <typename Point, typename PointOfSegment> check_touch(Point const & point,PointOfSegment const & seg1,PointOfSegment const & seg2,counter & state,bool & eq1,bool & eq2)199 static inline bool check_touch(Point const& point, 200 PointOfSegment const& seg1, 201 PointOfSegment const& seg2, 202 counter& state, 203 bool& eq1, bool& eq2) 204 { 205 typedef typename calculation_type<Point, PointOfSegment>::type calc_t; 206 207 calc_t const px = get<0>(point); 208 calc_t const s1x = get<0>(seg1); 209 calc_t const s2x = get<0>(seg2); 210 211 eq1 = math::equals(s1x, px); 212 eq2 = math::equals(s2x, px); 213 214 // Both equal p -> segment vertical 215 // The only thing which has to be done is check if point is ON segment 216 if (eq1 && eq2) 217 { 218 calc_t const py = get<1>(point); 219 calc_t const s1y = get<1>(seg1); 220 calc_t const s2y = get<1>(seg2); 221 if ((s1y <= py && s2y >= py) || (s2y <= py && s1y >= py)) 222 { 223 state.m_touches = true; 224 } 225 return true; 226 } 227 return false; 228 } 229 230 template <typename Point, typename PointOfSegment> calculate_count(Point const & point,PointOfSegment const & seg1,PointOfSegment const & seg2,bool eq1,bool eq2)231 static inline int calculate_count(Point const& point, 232 PointOfSegment const& seg1, 233 PointOfSegment const& seg2, 234 bool eq1, bool eq2) 235 { 236 typedef typename calculation_type<Point, PointOfSegment>::type calc_t; 237 238 calc_t const p = get<0>(point); 239 calc_t const s1 = get<0>(seg1); 240 calc_t const s2 = get<0>(seg2); 241 242 return eq1 ? (s2 > p ? 1 : -1) // Point on level s1, E/W depending on s2 243 : eq2 ? (s1 > p ? -1 : 1) // idem 244 : s1 < p && s2 > p ? 2 // Point between s1 -> s2 --> E 245 : s2 < p && s1 > p ? -2 // Point between s2 -> s1 --> W 246 : 0; 247 } 248 249 template <typename Point, typename PointOfSegment> side_equal(Point const & point,PointOfSegment const & se,int count)250 static inline int side_equal(Point const& point, 251 PointOfSegment const& se, 252 int count) 253 { 254 // NOTE: for D=0 the signs would be reversed 255 return math::equals(get<1>(point), get<1>(se)) ? 256 0 : 257 get<1>(point) < get<1>(se) ? 258 // assuming count is equal to 1 or -1 259 -count : // ( count > 0 ? -1 : 1) : 260 count; // ( count > 0 ? 1 : -1) ; 261 } 262 }; 263 264 265 #ifndef DOXYGEN_NO_STRATEGY_SPECIALIZATIONS 266 267 namespace services 268 { 269 270 template <typename PointLike, typename Geometry, typename AnyTag1, typename AnyTag2> 271 struct default_strategy<PointLike, Geometry, AnyTag1, AnyTag2, pointlike_tag, polygonal_tag, cartesian_tag, cartesian_tag> 272 { 273 typedef cartesian_winding<> type; 274 }; 275 276 template <typename PointLike, typename Geometry, typename AnyTag1, typename AnyTag2> 277 struct default_strategy<PointLike, Geometry, AnyTag1, AnyTag2, pointlike_tag, linear_tag, cartesian_tag, cartesian_tag> 278 { 279 typedef cartesian_winding<> type; 280 }; 281 282 } // namespace services 283 284 #endif 285 286 287 }} // namespace strategy::within 288 289 290 #ifndef DOXYGEN_NO_STRATEGY_SPECIALIZATIONS 291 namespace strategy { namespace covered_by { namespace services 292 { 293 294 template <typename PointLike, typename Geometry, typename AnyTag1, typename AnyTag2> 295 struct default_strategy<PointLike, Geometry, AnyTag1, AnyTag2, pointlike_tag, polygonal_tag, cartesian_tag, cartesian_tag> 296 { 297 typedef within::cartesian_winding<> type; 298 }; 299 300 template <typename PointLike, typename Geometry, typename AnyTag1, typename AnyTag2> 301 struct default_strategy<PointLike, Geometry, AnyTag1, AnyTag2, pointlike_tag, linear_tag, cartesian_tag, cartesian_tag> 302 { 303 typedef within::cartesian_winding<> type; 304 }; 305 306 }}} // namespace strategy::covered_by::services 307 #endif 308 309 310 }} // namespace boost::geometry 311 312 313 #endif // BOOST_GEOMETRY_STRATEGY_CARTESIAN_POINT_IN_POLY_WINDING_HPP 314