]> git.proxmox.com Git - ceph.git/blame - ceph/src/boost/boost/geometry/algorithms/detail/within/point_in_geometry.hpp
import new upstream nautilus stable release 14.2.8
[ceph.git] / ceph / src / boost / boost / geometry / algorithms / detail / within / point_in_geometry.hpp
CommitLineData
7c673cae
FG
1// Boost.Geometry (aka GGL, Generic Geometry Library)
2
3// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
4// Copyright (c) 2008-2012 Bruno Lalande, Paris, France.
5// Copyright (c) 2009-2012 Mateusz Loskot, London, UK.
6// Copyright (c) 2014 Adam Wulkiewicz, Lodz, Poland.
7
92f5a8d4
TL
8// This file was modified by Oracle on 2013, 2014, 2015, 2017, 2018, 2019.
9// Modifications copyright (c) 2013-2019, Oracle and/or its affiliates.
b32b8144
FG
10
11// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
7c673cae
FG
12
13// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
14// (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
15
16// Use, modification and distribution is subject to the Boost Software License,
17// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
18// http://www.boost.org/LICENSE_1_0.txt)
19
7c673cae
FG
20#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_WITHIN_POINT_IN_GEOMETRY_HPP
21#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_WITHIN_POINT_IN_GEOMETRY_HPP
22
23
24#include <boost/core/ignore_unused.hpp>
25#include <boost/mpl/assert.hpp>
26#include <boost/range.hpp>
27#include <boost/type_traits/is_same.hpp>
28#include <boost/type_traits/remove_reference.hpp>
29
30#include <boost/geometry/core/assert.hpp>
31
32#include <boost/geometry/algorithms/detail/equals/point_point.hpp>
33#include <boost/geometry/algorithms/detail/interior_iterator.hpp>
34
35#include <boost/geometry/geometries/concepts/check.hpp>
36#include <boost/geometry/strategies/concepts/within_concept.hpp>
37#include <boost/geometry/strategies/default_strategy.hpp>
b32b8144 38#include <boost/geometry/strategies/relate.hpp>
7c673cae
FG
39
40#include <boost/geometry/util/range.hpp>
41#include <boost/geometry/views/detail/normalized_view.hpp>
42
43namespace boost { namespace geometry {
44
45#ifndef DOXYGEN_NO_DETAIL
46namespace detail { namespace within {
47
92f5a8d4
TL
48template <typename Point1, typename Point2, typename Strategy>
49inline bool equals_point_point(Point1 const& p1, Point2 const& p2, Strategy const& strategy)
50{
51 return equals::equals_point_point(p1, p2, strategy.get_equals_point_point_strategy());
52}
b32b8144 53
7c673cae
FG
54// TODO: is this needed?
55inline int check_result_type(int result)
56{
57 return result;
58}
59
60template <typename T>
61inline T check_result_type(T result)
62{
63 BOOST_GEOMETRY_ASSERT(false);
64 return result;
65}
66
67template <typename Point, typename Range, typename Strategy> inline
68int point_in_range(Point const& point, Range const& range, Strategy const& strategy)
69{
70 boost::ignore_unused(strategy);
71
72 typedef typename boost::range_iterator<Range const>::type iterator_type;
73 typename Strategy::state_type state;
74 iterator_type it = boost::begin(range);
75 iterator_type end = boost::end(range);
76
77 for ( iterator_type previous = it++ ; it != end ; ++previous, ++it )
78 {
79 if ( ! strategy.apply(point, *previous, *it, state) )
80 {
81 break;
82 }
83 }
84
85 return check_result_type(strategy.result(state));
86}
87
88template <typename Geometry, typename Point, typename Range>
89inline int point_in_range(Point const& point, Range const& range)
90{
b32b8144 91 typedef typename strategy::point_in_geometry::services::default_strategy
7c673cae 92 <
b32b8144 93 Point, Geometry
7c673cae
FG
94 >::type strategy_type;
95
7c673cae
FG
96 return point_in_range(point, range, strategy_type());
97}
98
99}} // namespace detail::within
100
101namespace detail_dispatch { namespace within {
102
103// checks the relation between a point P and geometry G
104// returns 1 if P is in the interior of G
105// returns 0 if P is on the boundry of G
106// returns -1 if P is in the exterior of G
107
108template <typename Geometry,
109 typename Tag = typename geometry::tag<Geometry>::type>
110struct point_in_geometry
111 : not_implemented<Tag>
112{};
113
114template <typename Point2>
115struct point_in_geometry<Point2, point_tag>
116{
117 template <typename Point1, typename Strategy> static inline
118 int apply(Point1 const& point1, Point2 const& point2, Strategy const& strategy)
119 {
120 boost::ignore_unused(strategy);
121 return strategy.apply(point1, point2) ? 1 : -1;
122 }
123};
124
125template <typename Segment>
126struct point_in_geometry<Segment, segment_tag>
127{
128 template <typename Point, typename Strategy> static inline
129 int apply(Point const& point, Segment const& segment, Strategy const& strategy)
130 {
131 boost::ignore_unused(strategy);
132
133 typedef typename geometry::point_type<Segment>::type point_type;
134 point_type p0, p1;
135// TODO: don't copy points
136 detail::assign_point_from_index<0>(segment, p0);
137 detail::assign_point_from_index<1>(segment, p1);
138
139 typename Strategy::state_type state;
140 strategy.apply(point, p0, p1, state);
141 int r = detail::within::check_result_type(strategy.result(state));
142
143 if ( r != 0 )
144 return -1; // exterior
145
146 // if the point is equal to the one of the terminal points
92f5a8d4
TL
147 if ( detail::within::equals_point_point(point, p0, strategy)
148 || detail::within::equals_point_point(point, p1, strategy) )
7c673cae
FG
149 return 0; // boundary
150 else
151 return 1; // interior
152 }
153};
154
155
156template <typename Linestring>
157struct point_in_geometry<Linestring, linestring_tag>
158{
159 template <typename Point, typename Strategy> static inline
160 int apply(Point const& point, Linestring const& linestring, Strategy const& strategy)
161 {
162 std::size_t count = boost::size(linestring);
163 if ( count > 1 )
164 {
165 if ( detail::within::point_in_range(point, linestring, strategy) != 0 )
166 return -1; // exterior
167
168 // if the linestring doesn't have a boundary
92f5a8d4 169 if (detail::within::equals_point_point(range::front(linestring), range::back(linestring), strategy))
7c673cae
FG
170 return 1; // interior
171 // else if the point is equal to the one of the terminal points
92f5a8d4
TL
172 else if (detail::within::equals_point_point(point, range::front(linestring), strategy)
173 || detail::within::equals_point_point(point, range::back(linestring), strategy))
7c673cae
FG
174 return 0; // boundary
175 else
176 return 1; // interior
177 }
178// TODO: for now degenerated linestrings are ignored
179// throw an exception here?
180 /*else if ( count == 1 )
181 {
182 if ( detail::equals::equals_point_point(point, range::front(linestring)) )
183 return 1;
184 }*/
185
186 return -1; // exterior
187 }
188};
189
190template <typename Ring>
191struct point_in_geometry<Ring, ring_tag>
192{
193 template <typename Point, typename Strategy> static inline
194 int apply(Point const& point, Ring const& ring, Strategy const& strategy)
195 {
196 if ( boost::size(ring) < core_detail::closure::minimum_ring_size
197 <
198 geometry::closure<Ring>::value
199 >::value )
200 {
201 return -1;
202 }
203
204 detail::normalized_view<Ring const> view(ring);
205 return detail::within::point_in_range(point, view, strategy);
206 }
207};
208
209// Polygon: in exterior ring, and if so, not within interior ring(s)
210template <typename Polygon>
211struct point_in_geometry<Polygon, polygon_tag>
212{
213 template <typename Point, typename Strategy>
214 static inline int apply(Point const& point, Polygon const& polygon,
215 Strategy const& strategy)
216 {
217 int const code = point_in_geometry
218 <
219 typename ring_type<Polygon>::type
220 >::apply(point, exterior_ring(polygon), strategy);
221
222 if (code == 1)
223 {
224 typename interior_return_type<Polygon const>::type
225 rings = interior_rings(polygon);
226
227 for (typename detail::interior_iterator<Polygon const>::type
228 it = boost::begin(rings);
229 it != boost::end(rings);
230 ++it)
231 {
232 int const interior_code = point_in_geometry
233 <
234 typename ring_type<Polygon>::type
235 >::apply(point, *it, strategy);
236
237 if (interior_code != -1)
238 {
239 // If 0, return 0 (touch)
240 // If 1 (inside hole) return -1 (outside polygon)
241 // If -1 (outside hole) check other holes if any
242 return -interior_code;
243 }
244 }
245 }
246 return code;
247 }
248};
249
250template <typename Geometry>
251struct point_in_geometry<Geometry, multi_point_tag>
252{
253 template <typename Point, typename Strategy> static inline
254 int apply(Point const& point, Geometry const& geometry, Strategy const& strategy)
255 {
256 typedef typename boost::range_value<Geometry>::type point_type;
257 typedef typename boost::range_const_iterator<Geometry>::type iterator;
258 for ( iterator it = boost::begin(geometry) ; it != boost::end(geometry) ; ++it )
259 {
260 int pip = point_in_geometry<point_type>::apply(point, *it, strategy);
261
262 //BOOST_GEOMETRY_ASSERT(pip != 0);
263 if ( pip > 0 ) // inside
264 return 1;
265 }
266
267 return -1; // outside
268 }
269};
270
271template <typename Geometry>
272struct point_in_geometry<Geometry, multi_linestring_tag>
273{
274 template <typename Point, typename Strategy> static inline
275 int apply(Point const& point, Geometry const& geometry, Strategy const& strategy)
276 {
277 int pip = -1; // outside
278
279 typedef typename boost::range_value<Geometry>::type linestring_type;
280 typedef typename boost::range_value<linestring_type>::type point_type;
281 typedef typename boost::range_iterator<Geometry const>::type iterator;
282 iterator it = boost::begin(geometry);
283 for ( ; it != boost::end(geometry) ; ++it )
284 {
285 pip = point_in_geometry<linestring_type>::apply(point, *it, strategy);
286
287 // inside or on the boundary
288 if ( pip >= 0 )
289 {
290 ++it;
291 break;
292 }
293 }
294
295 // outside
296 if ( pip < 0 )
297 return -1;
298
299 // TODO: the following isn't needed for covered_by()
300
301 unsigned boundaries = pip == 0 ? 1 : 0;
302
303 for ( ; it != boost::end(geometry) ; ++it )
304 {
305 if ( boost::size(*it) < 2 )
306 continue;
307
308 point_type const& front = range::front(*it);
309 point_type const& back = range::back(*it);
310
311 // is closed_ring - no boundary
92f5a8d4 312 if ( detail::within::equals_point_point(front, back, strategy) )
7c673cae
FG
313 continue;
314
315 // is point on boundary
92f5a8d4
TL
316 if ( detail::within::equals_point_point(point, front, strategy)
317 || detail::within::equals_point_point(point, back, strategy) )
7c673cae
FG
318 {
319 ++boundaries;
320 }
321 }
322
323 // if the number of boundaries is odd, the point is on the boundary
324 return boundaries % 2 ? 0 : 1;
325 }
326};
327
328template <typename Geometry>
329struct point_in_geometry<Geometry, multi_polygon_tag>
330{
331 template <typename Point, typename Strategy> static inline
332 int apply(Point const& point, Geometry const& geometry, Strategy const& strategy)
333 {
334 // For invalid multipolygons
335 //int res = -1; // outside
336
337 typedef typename boost::range_value<Geometry>::type polygon_type;
338 typedef typename boost::range_const_iterator<Geometry>::type iterator;
339 for ( iterator it = boost::begin(geometry) ; it != boost::end(geometry) ; ++it )
340 {
341 int pip = point_in_geometry<polygon_type>::apply(point, *it, strategy);
342
343 // inside or on the boundary
344 if ( pip >= 0 )
345 return pip;
346
347 // For invalid multi-polygons
348 //if ( 1 == pip ) // inside polygon
349 // return 1;
350 //else if ( res < pip ) // point must be inside at least one polygon
351 // res = pip;
352 }
353
354 return -1; // for valid multipolygons
355 //return res; // for invalid multipolygons
356 }
357};
358
359}} // namespace detail_dispatch::within
360
361namespace detail { namespace within {
362
363// 1 - in the interior
364// 0 - in the boundry
365// -1 - in the exterior
366template <typename Point, typename Geometry, typename Strategy>
367inline int point_in_geometry(Point const& point, Geometry const& geometry, Strategy const& strategy)
368{
92f5a8d4 369 concepts::within::check<Point, Geometry, Strategy>();
7c673cae
FG
370
371 return detail_dispatch::within::point_in_geometry<Geometry>::apply(point, geometry, strategy);
372}
373
374template <typename Point, typename Geometry>
375inline int point_in_geometry(Point const& point, Geometry const& geometry)
376{
b32b8144 377 typedef typename strategy::point_in_geometry::services::default_strategy
7c673cae 378 <
b32b8144 379 Point, Geometry
7c673cae
FG
380 >::type strategy_type;
381
7c673cae
FG
382 return point_in_geometry(point, geometry, strategy_type());
383}
384
92f5a8d4
TL
385template <typename Point, typename Geometry, typename Strategy>
386inline bool within_point_geometry(Point const& point, Geometry const& geometry, Strategy const& strategy)
387{
388 return point_in_geometry(point, geometry, strategy) > 0;
389}
390
391template <typename Point, typename Geometry>
392inline bool within_point_geometry(Point const& point, Geometry const& geometry)
393{
394 return point_in_geometry(point, geometry) > 0;
395}
396
397template <typename Point, typename Geometry, typename Strategy>
398inline bool covered_by_point_geometry(Point const& point, Geometry const& geometry, Strategy const& strategy)
399{
400 return point_in_geometry(point, geometry, strategy) >= 0;
401}
402
403template <typename Point, typename Geometry>
404inline bool covered_by_point_geometry(Point const& point, Geometry const& geometry)
405{
406 return point_in_geometry(point, geometry) >= 0;
407}
408
7c673cae
FG
409}} // namespace detail::within
410#endif // DOXYGEN_NO_DETAIL
411
412}} // namespace boost::geometry
413
414#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_WITHIN_POINT_IN_GEOMETRY_HPP