1 // Boost.Geometry Index
3 // Spatial query predicates definition and checks.
5 // Copyright (c) 2011-2015 Adam Wulkiewicz, Lodz, Poland.
7 // This file was modified by Oracle on 2019-2021.
8 // Modifications copyright (c) 2019-2021 Oracle and/or its affiliates.
9 // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
11 // Use, modification and distribution is subject to the Boost Software License,
12 // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
13 // http://www.boost.org/LICENSE_1_0.txt)
15 #ifndef BOOST_GEOMETRY_INDEX_DETAIL_PREDICATES_HPP
16 #define BOOST_GEOMETRY_INDEX_DETAIL_PREDICATES_HPP
19 #include <type_traits>
22 #include <boost/geometry/core/static_assert.hpp>
23 #include <boost/geometry/core/tag.hpp>
24 #include <boost/geometry/core/tags.hpp>
26 #include <boost/geometry/index/detail/tags.hpp>
28 #include <boost/geometry/strategies/default_strategy.hpp>
30 namespace boost { namespace geometry { namespace index { namespace detail {
32 namespace predicates {
34 // ------------------------------------------------------------------ //
36 // ------------------------------------------------------------------ //
38 template <typename Fun, bool IsFunction = std::is_function<Fun>::value>
41 satisfies_impl() : fun(nullptr) {}
42 satisfies_impl(Fun f) : fun(f) {}
46 template <typename Fun>
47 struct satisfies_impl<Fun, false>
49 satisfies_impl() = default;
50 satisfies_impl(Fun const& f) : fun(f) {}
54 template <typename Fun, bool Negated>
55 struct satisfies : satisfies_impl<Fun>
57 using base_t = satisfies_impl<Fun>;
59 satisfies() = default;
60 satisfies(Fun const& f) : base_t(f) {}
61 satisfies(base_t const& b) : base_t(b) {}
64 // ------------------------------------------------------------------ //
66 struct contains_tag {};
67 struct covered_by_tag {};
69 struct disjoint_tag {};
70 struct intersects_tag {};
71 struct overlaps_tag {};
72 struct touches_tag {};
75 template <typename Geometry, typename Tag, bool Negated>
76 struct spatial_predicate
78 spatial_predicate() {}
79 spatial_predicate(Geometry const& g) : geometry(g) {}
83 // ------------------------------------------------------------------ //
85 // CONSIDER: separated nearest<> and path<> may be replaced by
86 // nearest_predicate<Geometry, Tag>
87 // where Tag = point_tag | path_tag
88 // IMPROVEMENT: user-defined nearest predicate allowing to define
89 // all or only geometrical aspects of the search
91 template <typename PointOrRelation>
97 nearest(PointOrRelation const& por, std::size_t k)
98 : point_or_relation(por)
101 PointOrRelation point_or_relation;
105 template <typename SegmentOrLinestring>
111 path(SegmentOrLinestring const& g, std::size_t k)
115 SegmentOrLinestring geometry;
119 } // namespace predicates
121 // ------------------------------------------------------------------ //
123 // ------------------------------------------------------------------ //
125 template <typename Predicate, typename Tag>
126 struct predicate_check
128 BOOST_GEOMETRY_STATIC_ASSERT_FALSE(
129 "Not implemented for this Predicate or Tag.",
133 // ------------------------------------------------------------------ //
135 template <typename Fun>
136 struct predicate_check<predicates::satisfies<Fun, false>, value_tag>
138 template <typename Value, typename Indexable, typename Strategy>
139 static inline bool apply(predicates::satisfies<Fun, false> const& p, Value const& v, Indexable const& , Strategy const&)
145 template <typename Fun>
146 struct predicate_check<predicates::satisfies<Fun, true>, value_tag>
148 template <typename Value, typename Indexable, typename Strategy>
149 static inline bool apply(predicates::satisfies<Fun, true> const& p, Value const& v, Indexable const& , Strategy const&)
155 // ------------------------------------------------------------------ //
157 template <typename Tag>
158 struct spatial_predicate_call
160 BOOST_GEOMETRY_STATIC_ASSERT_FALSE(
161 "Not implemented for this Tag.",
166 struct spatial_predicate_call<predicates::contains_tag>
168 template <typename G1, typename G2, typename S>
169 static inline bool apply(G1 const& g1, G2 const& g2, S const&)
171 return geometry::within(g2, g1);
176 struct spatial_predicate_call<predicates::covered_by_tag>
178 template <typename G1, typename G2, typename S>
179 static inline bool apply(G1 const& g1, G2 const& g2, S const&)
181 return geometry::covered_by(g1, g2);
186 struct spatial_predicate_call<predicates::covers_tag>
188 template <typename G1, typename G2, typename S>
189 static inline bool apply(G1 const& g1, G2 const& g2, S const&)
191 return geometry::covered_by(g2, g1);
196 struct spatial_predicate_call<predicates::disjoint_tag>
198 template <typename G1, typename G2, typename S>
199 static inline bool apply(G1 const& g1, G2 const& g2, S const&)
201 return geometry::disjoint(g1, g2);
205 // TEMP: used to implement CS-specific intersects predicate for certain
206 // combinations of geometries until umbrella strategies are implemented
209 typename G1, typename G2,
210 typename Tag1 = typename tag<G1>::type,
211 typename Tag2 = typename tag<G2>::type
213 struct spatial_predicate_intersects
215 template <typename S>
216 static inline bool apply(G1 const& g1, G2 const& g2, S const&)
218 return geometry::intersects(g1, g2);
221 // TEMP: used in within and relate
222 template <typename G1, typename G2>
223 struct spatial_predicate_intersects<G1, G2, box_tag, point_tag>
225 static inline bool apply(G1 const& g1, G2 const& g2, default_strategy const&)
227 return geometry::intersects(g1, g2);
230 template <typename S>
231 static inline bool apply(G1 const& g1, G2 const& g2, S const& s)
233 return geometry::intersects(g1, g2, s);
238 struct spatial_predicate_call<predicates::intersects_tag>
240 template <typename G1, typename G2, typename S>
241 static inline bool apply(G1 const& g1, G2 const& g2, S const& s)
243 return spatial_predicate_intersects<G1, G2>::apply(g1, g2, s);
248 struct spatial_predicate_call<predicates::overlaps_tag>
250 template <typename G1, typename G2, typename S>
251 static inline bool apply(G1 const& g1, G2 const& g2, S const&)
253 return geometry::overlaps(g1, g2);
258 struct spatial_predicate_call<predicates::touches_tag>
260 template <typename G1, typename G2, typename S>
261 static inline bool apply(G1 const& g1, G2 const& g2, S const&)
263 return geometry::touches(g1, g2);
268 struct spatial_predicate_call<predicates::within_tag>
270 template <typename G1, typename G2, typename S>
271 static inline bool apply(G1 const& g1, G2 const& g2, S const&)
273 return geometry::within(g1, g2);
277 // ------------------------------------------------------------------ //
280 template <typename Geometry, typename Tag>
281 struct predicate_check<predicates::spatial_predicate<Geometry, Tag, false>, value_tag>
283 typedef predicates::spatial_predicate<Geometry, Tag, false> Pred;
285 template <typename Value, typename Indexable, typename Strategy>
286 static inline bool apply(Pred const& p, Value const&, Indexable const& i, Strategy const& s)
288 return spatial_predicate_call<Tag>::apply(i, p.geometry, s);
292 // negated spatial predicate
293 template <typename Geometry, typename Tag>
294 struct predicate_check<predicates::spatial_predicate<Geometry, Tag, true>, value_tag>
296 typedef predicates::spatial_predicate<Geometry, Tag, true> Pred;
298 template <typename Value, typename Indexable, typename Strategy>
299 static inline bool apply(Pred const& p, Value const&, Indexable const& i, Strategy const& s)
301 return !spatial_predicate_call<Tag>::apply(i, p.geometry, s);
305 // ------------------------------------------------------------------ //
307 template <typename DistancePredicates>
308 struct predicate_check<predicates::nearest<DistancePredicates>, value_tag>
310 template <typename Value, typename Box, typename Strategy>
311 static inline bool apply(predicates::nearest<DistancePredicates> const&, Value const&, Box const&, Strategy const&)
317 template <typename Linestring>
318 struct predicate_check<predicates::path<Linestring>, value_tag>
320 template <typename Value, typename Box, typename Strategy>
321 static inline bool apply(predicates::path<Linestring> const&, Value const&, Box const&, Strategy const&)
327 // ------------------------------------------------------------------ //
328 // predicates_check for bounds
329 // ------------------------------------------------------------------ //
331 template <typename Fun, bool Negated>
332 struct predicate_check<predicates::satisfies<Fun, Negated>, bounds_tag>
334 template <typename Value, typename Box, typename Strategy>
335 static bool apply(predicates::satisfies<Fun, Negated> const&, Value const&, Box const&, Strategy const&)
341 // ------------------------------------------------------------------ //
344 // value_tag bounds_tag
345 // ---------------------------
346 // contains(I,G) covers(I,G)
347 // covered_by(I,G) intersects(I,G)
348 // covers(I,G) covers(I,G)
349 // disjoint(I,G) !covered_by(I,G)
350 // intersects(I,G) intersects(I,G)
351 // overlaps(I,G) intersects(I,G) - possibly change to the version without border case, e.g. intersects_without_border(0,0x1,1, 1,1x2,2) should give false
352 // touches(I,G) intersects(I,G)
353 // within(I,G) intersects(I,G) - possibly change to the version without border case, e.g. intersects_without_border(0,0x1,1, 1,1x2,2) should give false
355 // spatial predicate - default
356 template <typename Geometry, typename Tag>
357 struct predicate_check<predicates::spatial_predicate<Geometry, Tag, false>, bounds_tag>
359 typedef predicates::spatial_predicate<Geometry, Tag, false> Pred;
361 template <typename Value, typename Indexable, typename Strategy>
362 static inline bool apply(Pred const& p, Value const&, Indexable const& i, Strategy const& s)
364 return spatial_predicate_call<predicates::intersects_tag>::apply(i, p.geometry, s);
368 // spatial predicate - contains
369 template <typename Geometry>
370 struct predicate_check<predicates::spatial_predicate<Geometry, predicates::contains_tag, false>, bounds_tag>
372 typedef predicates::spatial_predicate<Geometry, predicates::contains_tag, false> Pred;
374 template <typename Value, typename Indexable, typename Strategy>
375 static inline bool apply(Pred const& p, Value const&, Indexable const& i, Strategy const& s)
377 return spatial_predicate_call<predicates::covers_tag>::apply(i, p.geometry, s);
381 // spatial predicate - covers
382 template <typename Geometry>
383 struct predicate_check<predicates::spatial_predicate<Geometry, predicates::covers_tag, false>, bounds_tag>
385 typedef predicates::spatial_predicate<Geometry, predicates::covers_tag, false> Pred;
387 template <typename Value, typename Indexable, typename Strategy>
388 static inline bool apply(Pred const& p, Value const&, Indexable const& i, Strategy const& s)
390 return spatial_predicate_call<predicates::covers_tag>::apply(i, p.geometry, s);
394 // spatial predicate - disjoint
395 template <typename Geometry>
396 struct predicate_check<predicates::spatial_predicate<Geometry, predicates::disjoint_tag, false>, bounds_tag>
398 typedef predicates::spatial_predicate<Geometry, predicates::disjoint_tag, false> Pred;
400 template <typename Value, typename Indexable, typename Strategy>
401 static inline bool apply(Pred const& p, Value const&, Indexable const& i, Strategy const& s)
403 return !spatial_predicate_call<predicates::covered_by_tag>::apply(i, p.geometry, s);
408 // value_tag bounds_tag
409 // ---------------------------
410 // !contains(I,G) TRUE
411 // !covered_by(I,G) !covered_by(I,G)
413 // !disjoint(I,G) !disjoint(I,G)
414 // !intersects(I,G) !covered_by(I,G)
415 // !overlaps(I,G) TRUE
416 // !touches(I,G) !intersects(I,G)
417 // !within(I,G) !within(I,G)
419 // negated spatial predicate - default
420 template <typename Geometry, typename Tag>
421 struct predicate_check<predicates::spatial_predicate<Geometry, Tag, true>, bounds_tag>
423 typedef predicates::spatial_predicate<Geometry, Tag, true> Pred;
425 template <typename Value, typename Indexable, typename Strategy>
426 static inline bool apply(Pred const& p, Value const&, Indexable const& i, Strategy const& s)
428 return !spatial_predicate_call<Tag>::apply(i, p.geometry, s);
432 // negated spatial predicate - contains
433 template <typename Geometry>
434 struct predicate_check<predicates::spatial_predicate<Geometry, predicates::contains_tag, true>, bounds_tag>
436 typedef predicates::spatial_predicate<Geometry, predicates::contains_tag, true> Pred;
438 template <typename Value, typename Indexable, typename Strategy>
439 static inline bool apply(Pred const& , Value const&, Indexable const&, Strategy const&)
445 // negated spatial predicate - covers
446 template <typename Geometry>
447 struct predicate_check<predicates::spatial_predicate<Geometry, predicates::covers_tag, true>, bounds_tag>
449 typedef predicates::spatial_predicate<Geometry, predicates::covers_tag, true> Pred;
451 template <typename Value, typename Indexable, typename Strategy>
452 static inline bool apply(Pred const& , Value const&, Indexable const&, Strategy const&)
458 // negated spatial predicate - intersects
459 template <typename Geometry>
460 struct predicate_check<predicates::spatial_predicate<Geometry, predicates::intersects_tag, true>, bounds_tag>
462 typedef predicates::spatial_predicate<Geometry, predicates::intersects_tag, true> Pred;
464 template <typename Value, typename Indexable, typename Strategy>
465 static inline bool apply(Pred const& p, Value const&, Indexable const& i, Strategy const& s)
467 return !spatial_predicate_call<predicates::covered_by_tag>::apply(i, p.geometry, s);
471 // negated spatial predicate - overlaps
472 template <typename Geometry>
473 struct predicate_check<predicates::spatial_predicate<Geometry, predicates::overlaps_tag, true>, bounds_tag>
475 typedef predicates::spatial_predicate<Geometry, predicates::overlaps_tag, true> Pred;
477 template <typename Value, typename Indexable, typename Strategy>
478 static inline bool apply(Pred const& , Value const&, Indexable const&, Strategy const&)
484 // negated spatial predicate - touches
485 template <typename Geometry>
486 struct predicate_check<predicates::spatial_predicate<Geometry, predicates::touches_tag, true>, bounds_tag>
488 typedef predicates::spatial_predicate<Geometry, predicates::touches_tag, true> Pred;
490 template <typename Value, typename Indexable, typename Strategy>
491 static inline bool apply(Pred const& p, Value const&, Indexable const& i, Strategy const&)
493 return !spatial_predicate_call<predicates::intersects_tag>::apply(i, p.geometry);
497 // ------------------------------------------------------------------ //
499 template <typename DistancePredicates>
500 struct predicate_check<predicates::nearest<DistancePredicates>, bounds_tag>
502 template <typename Value, typename Box, typename Strategy>
503 static inline bool apply(predicates::nearest<DistancePredicates> const&, Value const&, Box const&, Strategy const&)
509 template <typename Linestring>
510 struct predicate_check<predicates::path<Linestring>, bounds_tag>
512 template <typename Value, typename Box, typename Strategy>
513 static inline bool apply(predicates::path<Linestring> const&, Value const&, Box const&, Strategy const&)
519 // ------------------------------------------------------------------ //
521 // ------------------------------------------------------------------ //
523 template <typename T>
524 struct predicates_length
526 static const std::size_t value = 1;
529 template <typename ...Ts>
530 struct predicates_length<std::tuple<Ts...>>
532 static const std::size_t value = std::tuple_size<std::tuple<Ts...>>::value;
535 // ------------------------------------------------------------------ //
536 // predicates_element
537 // ------------------------------------------------------------------ //
539 template <std::size_t I, typename T>
540 struct predicates_element
542 BOOST_GEOMETRY_STATIC_ASSERT((I < 1),
544 std::integral_constant<std::size_t, I>);
547 static type const& get(T const& p) { return p; }
550 template <std::size_t I, typename ...Ts>
551 struct predicates_element<I, std::tuple<Ts...>>
553 typedef std::tuple<Ts...> predicate_type;
555 typedef typename std::tuple_element<I, predicate_type>::type type;
556 static type const& get(predicate_type const& p) { return std::get<I>(p); }
559 // ------------------------------------------------------------------ //
561 // ------------------------------------------------------------------ //
563 template <typename TuplePredicates, typename Tag, std::size_t First, std::size_t Last>
564 struct predicates_check_tuple
566 template <typename Value, typename Indexable, typename Strategy>
567 static inline bool apply(TuplePredicates const& p, Value const& v, Indexable const& i, Strategy const& s)
569 return predicate_check
571 typename std::tuple_element<First, TuplePredicates>::type,
573 >::apply(std::get<First>(p), v, i, s)
574 && predicates_check_tuple<TuplePredicates, Tag, First+1, Last>::apply(p, v, i, s);
578 template <typename TuplePredicates, typename Tag, std::size_t First>
579 struct predicates_check_tuple<TuplePredicates, Tag, First, First>
581 template <typename Value, typename Indexable, typename Strategy>
582 static inline bool apply(TuplePredicates const& , Value const& , Indexable const& , Strategy const& )
588 template <typename Predicate, typename Tag, std::size_t First, std::size_t Last>
589 struct predicates_check_impl
591 static const bool check = First < 1 && Last <= 1 && First <= Last;
592 BOOST_GEOMETRY_STATIC_ASSERT((check),
593 "Invalid First or Last index.",
594 std::integer_sequence<std::size_t, First, Last>);
596 template <typename Value, typename Indexable, typename Strategy>
597 static inline bool apply(Predicate const& p, Value const& v, Indexable const& i, Strategy const& s)
599 return predicate_check<Predicate, Tag>::apply(p, v, i, s);
603 template <typename ...Ts, typename Tag, std::size_t First, std::size_t Last>
604 struct predicates_check_impl<std::tuple<Ts...>, Tag, First, Last>
606 typedef std::tuple<Ts...> predicates_type;
608 static const std::size_t pred_len = std::tuple_size<predicates_type>::value;
609 static const bool check = First < pred_len && Last <= pred_len && First <= Last;
610 BOOST_GEOMETRY_STATIC_ASSERT((check),
611 "Invalid First or Last index.",
612 std::integer_sequence<std::size_t, First, Last>);
614 template <typename Value, typename Indexable, typename Strategy>
615 static inline bool apply(predicates_type const& p, Value const& v, Indexable const& i, Strategy const& s)
617 return predicates_check_tuple
621 >::apply(p, v, i, s);
625 template <typename Tag, typename Predicates, typename Value, typename Indexable, typename Strategy>
626 inline bool predicates_check(Predicates const& p, Value const& v, Indexable const& i, Strategy const& s)
628 return detail::predicates_check_impl
630 Predicates, Tag, 0, predicates_length<Predicates>::value
631 >::apply(p, v, i, s);
634 // ------------------------------------------------------------------ //
635 // nearest predicate helpers
636 // ------------------------------------------------------------------ //
638 // predicates_is_nearest
640 template <typename P>
641 struct predicates_is_distance
643 static const std::size_t value = 0;
646 template <typename DistancePredicates>
647 struct predicates_is_distance< predicates::nearest<DistancePredicates> >
649 static const std::size_t value = 1;
652 template <typename Linestring>
653 struct predicates_is_distance< predicates::path<Linestring> >
655 static const std::size_t value = 1;
658 // predicates_count_nearest
660 template <typename T>
661 struct predicates_count_distance
663 static const std::size_t value = predicates_is_distance<T>::value;
666 template <typename Tuple, std::size_t N>
667 struct predicates_count_distance_tuple
669 static const std::size_t value =
670 predicates_is_distance<typename std::tuple_element<N-1, Tuple>::type>::value
671 + predicates_count_distance_tuple<Tuple, N-1>::value;
674 template <typename Tuple>
675 struct predicates_count_distance_tuple<Tuple, 1>
677 static const std::size_t value =
678 predicates_is_distance<typename std::tuple_element<0, Tuple>::type>::value;
681 template <typename ...Ts>
682 struct predicates_count_distance<std::tuple<Ts...>>
684 static const std::size_t value = predicates_count_distance_tuple<
686 std::tuple_size<std::tuple<Ts...>>::value
690 // predicates_find_nearest
692 template <typename T>
693 struct predicates_find_distance
695 static const std::size_t value = predicates_is_distance<T>::value ? 0 : 1;
698 template <typename Tuple, std::size_t N>
699 struct predicates_find_distance_tuple
701 static const bool is_found = predicates_find_distance_tuple<Tuple, N-1>::is_found
702 || predicates_is_distance<typename std::tuple_element<N-1, Tuple>::type>::value;
704 static const std::size_t value = predicates_find_distance_tuple<Tuple, N-1>::is_found ?
705 predicates_find_distance_tuple<Tuple, N-1>::value :
706 (predicates_is_distance<typename std::tuple_element<N-1, Tuple>::type>::value ?
707 N-1 : std::tuple_size<Tuple>::value);
710 template <typename Tuple>
711 struct predicates_find_distance_tuple<Tuple, 1>
713 static const bool is_found = predicates_is_distance<typename std::tuple_element<0, Tuple>::type>::value;
714 static const std::size_t value = is_found ? 0 : std::tuple_size<Tuple>::value;
717 template <typename ...Ts>
718 struct predicates_find_distance<std::tuple<Ts...>>
720 static const std::size_t value = predicates_find_distance_tuple<
722 std::tuple_size<std::tuple<Ts...>>::value
726 }}}} // namespace boost::geometry::index::detail
728 #endif // BOOST_GEOMETRY_INDEX_DETAIL_PREDICATES_HPP