1 // Boost.Geometry (aka GGL, Generic Geometry Library)
2 
3 // Copyright (c) 2007-2015 Barend Gehrels, Amsterdam, the Netherlands.
4 // Copyright (c) 2008-2015 Bruno Lalande, Paris, France.
5 // Copyright (c) 2009-2015 Mateusz Loskot, London, UK.
6 
7 // This file was modified by Oracle on 2015-2017.
8 // Modifications copyright (c) 2015-2017, Oracle and/or its affiliates.
9 
10 // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
11 
12 // Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
13 // (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
14 
15 // Use, modification and distribution is subject to the Boost Software License,
16 // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
17 // http://www.boost.org/LICENSE_1_0.txt)
18 
19 #ifndef BOOST_GEOMETRY_STRATEGIES_CARTESIAN_POINT_IN_BOX_HPP
20 #define BOOST_GEOMETRY_STRATEGIES_CARTESIAN_POINT_IN_BOX_HPP
21 
22 
23 #include <boost/geometry/core/access.hpp>
24 #include <boost/geometry/core/coordinate_dimension.hpp>
25 #include <boost/geometry/strategies/covered_by.hpp>
26 #include <boost/geometry/strategies/within.hpp>
27 #include <boost/geometry/util/normalize_spheroidal_coordinates.hpp>
28 
29 
30 namespace boost { namespace geometry { namespace strategy
31 {
32 
33 namespace within
34 {
35 
36 struct within_coord
37 {
38     template <typename Value1, typename Value2>
applyboost::geometry::strategy::within::within_coord39     static inline bool apply(Value1 const& value, Value2 const& min_value, Value2 const& max_value)
40     {
41         return value > min_value && value < max_value;
42     }
43 };
44 
45 struct covered_by_coord
46 {
47     template <typename Value1, typename Value2>
applyboost::geometry::strategy::within::covered_by_coord48     static inline bool apply(Value1 const& value, Value2 const& min_value, Value2 const& max_value)
49     {
50         return value >= min_value && value <= max_value;
51     }
52 };
53 
54 template <typename Geometry, std::size_t Dimension, typename CSTag>
55 struct within_range
56     : within_coord
57 {};
58 
59 
60 template <typename Geometry, std::size_t Dimension, typename CSTag>
61 struct covered_by_range
62     : covered_by_coord
63 {};
64 
65 
66 // NOTE: the result would be the same if instead of structs defined below
67 // the above xxx_range were used with the following arguments:
68 // (min_value + diff_min, min_value, max_value)
69 struct within_longitude_diff
70 {
71     template <typename CalcT>
applyboost::geometry::strategy::within::within_longitude_diff72     static inline bool apply(CalcT const& diff_min, CalcT const& min_value, CalcT const& max_value)
73     {
74         CalcT const c0 = 0;
75         return diff_min > c0
76             && (min_value + diff_min < max_value
77              /*|| max_value - diff_min > min_value*/);
78     }
79 };
80 
81 struct covered_by_longitude_diff
82 {
83     template <typename CalcT>
applyboost::geometry::strategy::within::covered_by_longitude_diff84     static inline bool apply(CalcT const& diff_min, CalcT const& min_value, CalcT const& max_value)
85     {
86         return min_value + diff_min <= max_value
87             /*|| max_value - diff_min >= min_value*/;
88     }
89 };
90 
91 
92 template <typename Geometry,
93           typename CoordCheck,
94           typename DiffCheck>
95 struct longitude_range
96 {
97     template <typename Value1, typename Value2>
applyboost::geometry::strategy::within::longitude_range98     static inline bool apply(Value1 const& value, Value2 const& min_value, Value2 const& max_value)
99     {
100         typedef typename select_most_precise
101             <
102                 Value1, Value2
103             >::type calc_t;
104         typedef typename coordinate_system<Geometry>::type::units units_t;
105         typedef math::detail::constants_on_spheroid<calc_t, units_t> constants;
106 
107         if (CoordCheck::apply(value, min_value, max_value))
108         {
109             return true;
110         }
111 
112         // min <= max <=> diff >= 0
113         calc_t const diff_ing = max_value - min_value;
114 
115         // if containing covers the whole globe it contains all
116         if (diff_ing >= constants::period())
117         {
118             return true;
119         }
120 
121         // calculate positive longitude translation with min_value as origin
122         calc_t const diff_min = math::longitude_distance_unsigned<units_t, calc_t>(min_value, value);
123 
124         return DiffCheck::template apply<calc_t>(diff_min, min_value, max_value);
125     }
126 };
127 
128 
129 // spherical_equatorial_tag, spherical_polar_tag and geographic_cat are casted to spherical_tag
130 template <typename Geometry>
131 struct within_range<Geometry, 0, spherical_tag>
132     : longitude_range<Geometry, within_coord, within_longitude_diff>
133 {};
134 
135 
136 template <typename Geometry>
137 struct covered_by_range<Geometry, 0, spherical_tag>
138     : longitude_range<Geometry, covered_by_coord, covered_by_longitude_diff>
139 {};
140 
141 
142 template
143 <
144     template <typename, std::size_t, typename> class SubStrategy,
145     typename Point,
146     typename Box,
147     std::size_t Dimension,
148     std::size_t DimensionCount
149 >
150 struct relate_point_box_loop
151 {
applyboost::geometry::strategy::within::relate_point_box_loop152     static inline bool apply(Point const& point, Box const& box)
153     {
154         typedef typename tag_cast<typename cs_tag<Point>::type, spherical_tag>::type cs_tag_t;
155 
156         if (! SubStrategy<Point, Dimension, cs_tag_t>::apply(get<Dimension>(point),
157                     get<min_corner, Dimension>(box),
158                     get<max_corner, Dimension>(box))
159             )
160         {
161             return false;
162         }
163 
164         return relate_point_box_loop
165             <
166                 SubStrategy,
167                 Point, Box,
168                 Dimension + 1, DimensionCount
169             >::apply(point, box);
170     }
171 };
172 
173 
174 template
175 <
176     template <typename, std::size_t, typename> class SubStrategy,
177     typename Point,
178     typename Box,
179     std::size_t DimensionCount
180 >
181 struct relate_point_box_loop<SubStrategy, Point, Box, DimensionCount, DimensionCount>
182 {
applyboost::geometry::strategy::within::relate_point_box_loop183     static inline bool apply(Point const& , Box const& )
184     {
185         return true;
186     }
187 };
188 
189 
190 template
191 <
192     typename Point,
193     typename Box,
194     template <typename, std::size_t, typename> class SubStrategy = within_range
195 >
196 struct point_in_box
197 {
applyboost::geometry::strategy::within::point_in_box198     static inline bool apply(Point const& point, Box const& box)
199     {
200         return relate_point_box_loop
201             <
202                 SubStrategy,
203                 Point, Box,
204                 0, dimension<Point>::type::value
205             >::apply(point, box);
206     }
207 };
208 
209 
210 } // namespace within
211 
212 
213 #ifndef DOXYGEN_NO_STRATEGY_SPECIALIZATIONS
214 
215 
216 namespace within { namespace services
217 {
218 
219 template <typename Point, typename Box>
220 struct default_strategy
221     <
222         Point, Box,
223         point_tag, box_tag,
224         pointlike_tag, areal_tag,
225         cartesian_tag, cartesian_tag
226     >
227 {
228     typedef within::point_in_box<Point, Box> type;
229 };
230 
231 // spherical_equatorial_tag, spherical_polar_tag and geographic_cat are casted to spherical_tag
232 template <typename Point, typename Box>
233 struct default_strategy
234     <
235         Point, Box,
236         point_tag, box_tag,
237         pointlike_tag, areal_tag,
238         spherical_tag, spherical_tag
239     >
240 {
241     typedef within::point_in_box<Point, Box> type;
242 };
243 
244 
245 }} // namespace within::services
246 
247 
248 namespace covered_by { namespace services
249 {
250 
251 
252 template <typename Point, typename Box>
253 struct default_strategy
254     <
255         Point, Box,
256         point_tag, box_tag,
257         pointlike_tag, areal_tag,
258         cartesian_tag, cartesian_tag
259     >
260 {
261     typedef within::point_in_box
262                 <
263                     Point, Box,
264                     within::covered_by_range
265                 > type;
266 };
267 
268 // spherical_equatorial_tag, spherical_polar_tag and geographic_cat are casted to spherical_tag
269 template <typename Point, typename Box>
270 struct default_strategy
271     <
272         Point, Box,
273         point_tag, box_tag,
274         pointlike_tag, areal_tag,
275         spherical_tag, spherical_tag
276     >
277 {
278     typedef within::point_in_box
279                 <
280                     Point, Box,
281                     within::covered_by_range
282                 > type;
283 };
284 
285 
286 }} // namespace covered_by::services
287 
288 
289 #endif // DOXYGEN_NO_STRATEGY_SPECIALIZATIONS
290 
291 
292 }}} // namespace boost::geometry::strategy
293 
294 
295 #endif // BOOST_GEOMETRY_STRATEGIES_CARTESIAN_POINT_IN_BOX_HPP
296