// Boost.Geometry // Copyright (c) 2014-2023, Oracle and/or its affiliates. // Contributed and/or modified by Vissarion Fysikopoulos, on behalf of Oracle // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle // Use, modification and distribution is subject to the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_RELATE_MULTI_POINT_GEOMETRY_HPP #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_RELATE_MULTI_POINT_GEOMETRY_HPP #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include // TEMP #include #include #include #include namespace boost { namespace geometry { #ifndef DOXYGEN_NO_DETAIL namespace detail { namespace relate { template < typename Geometry, typename Tag = typename tag::type > struct multi_point_geometry_eb { template static inline bool apply(MultiPoint const& , detail::relate::topology_check const& ) { return true; } }; template struct multi_point_geometry_eb { template struct boundary_visitor { boundary_visitor(Points const& points) : m_points(points) , m_boundary_found(false) {} template struct find_pred { find_pred(Point const& point, Strategy const& strategy) : m_point(point) , m_strategy(strategy) {} template bool operator()(Pt const& pt) const { return detail::equals::equals_point_point(pt, m_point, m_strategy); } Point const& m_point; Strategy const& m_strategy; }; template bool apply(Point const& boundary_point, Strategy const& strategy) { if ( std::none_of(m_points.begin(), m_points.end(), find_pred(boundary_point, strategy))) { m_boundary_found = true; return false; } return true; } bool result() const { return m_boundary_found; } private: Points const& m_points; bool m_boundary_found; }; template static inline bool apply(MultiPoint const& multi_point, detail::relate::topology_check const& tc) { boundary_visitor visitor(multi_point); tc.for_each_boundary_point(visitor); return visitor.result(); } }; template struct multi_point_geometry_eb { template struct boundary_visitor { boundary_visitor(Points const& points) : m_points(points) , m_boundary_found(false) {} template bool apply(Point const& boundary_point, Strategy const&) { typedef geometry::less less_type; if (! std::binary_search(m_points.begin(), m_points.end(), boundary_point, less_type()) ) { m_boundary_found = true; return false; } return true; } bool result() const { return m_boundary_found; } private: Points const& m_points; bool m_boundary_found; }; template static inline bool apply(MultiPoint const& multi_point, detail::relate::topology_check const& tc) { typedef typename boost::range_value::type point_type; typedef std::vector points_type; typedef geometry::less less_type; points_type points(boost::begin(multi_point), boost::end(multi_point)); std::sort(points.begin(), points.end(), less_type()); boundary_visitor visitor(points); tc.for_each_boundary_point(visitor); return visitor.result(); } }; // SingleGeometry - Linear or Areal template struct multi_point_single_geometry { static const bool interruption_enabled = true; template static inline void apply(MultiPoint const& multi_point, SingleGeometry const& single_geometry, Result & result, Strategy const& strategy) { typedef typename point_type::type point2_type; typedef model::box box2_type; box2_type box2; geometry::envelope(single_geometry, box2, strategy); geometry::detail::expand_by_epsilon(box2); for (auto it = boost::begin(multi_point); it != boost::end(multi_point); ++it) { if (! (relate::may_update(result) || relate::may_update(result) || relate::may_update(result) ) ) { break; } // The default strategy is enough for Point/Box if (detail::disjoint::disjoint_point_box(*it, box2, strategy)) { update(result); } else { int in_val = detail::within::point_in_geometry(*it, single_geometry, strategy); if (in_val > 0) // within { update(result); } else if (in_val == 0) { update(result); } else // in_val < 0 - not within { update(result); } } if ( BOOST_GEOMETRY_CONDITION(result.interrupt) ) { return; } } typedef detail::relate::topology_check tc_t; if ( relate::may_update(result) || relate::may_update(result) ) { tc_t tc(single_geometry, strategy); if ( relate::may_update(result) && tc.has_interior() ) { // TODO: this is not true if a linestring is degenerated to a point // then the interior has topological dimension = 0, not 1 update(result); } if ( relate::may_update(result) && tc.has_boundary() ) { if (multi_point_geometry_eb::apply(multi_point, tc)) { update(result); } } } update::value, Transpose>(result); } }; // MultiGeometry - Linear or Areal // part of the algorithm calculating II and IB when no IE has to be calculated // using partition() template class multi_point_multi_geometry_ii_ib { template struct expand_box_point { expand_box_point(Strategy const& strategy) : m_strategy(strategy) {} template inline void apply(Box& total, Point const& point) const { geometry::expand(total, point, m_strategy); } private: Strategy const& m_strategy; }; template struct expand_box_box_pair { expand_box_box_pair(Strategy const& strategy) : m_strategy(strategy) {} template inline void apply(Box& total, BoxPair const& box_pair) const { geometry::expand(total, box_pair.first, m_strategy); } private: Strategy const& m_strategy; }; template struct overlaps_box_point { overlaps_box_point(Strategy const& strategy) : m_strategy(strategy) {} template inline bool apply(Box const& box, Point const& point) const { // The default strategy is enough for Point/Box return ! detail::disjoint::disjoint_point_box(point, box, m_strategy); } private: Strategy const& m_strategy; }; template struct overlaps_box_box_pair { overlaps_box_box_pair(Strategy const& strategy) : m_strategy(strategy) {} template inline bool apply(Box const& box, BoxPair const& box_pair) const { // The default strategy is enough for Box/Box return ! detail::disjoint::disjoint_box_box(box_pair.first, box, m_strategy); } private: Strategy const& m_strategy; }; template class item_visitor_type { typedef detail::relate::topology_check topology_check_type; public: item_visitor_type(MultiGeometry const& multi_geometry, topology_check_type const& tc, Result & result, Strategy const& strategy) : m_multi_geometry(multi_geometry) , m_tc(tc) , m_result(result) , m_strategy(strategy) {} template inline bool apply(Point const& point, BoxPair const& box_pair) { // The default strategy is enough for Point/Box if (! detail::disjoint::disjoint_point_box(point, box_pair.first, m_strategy) ) { typename boost::range_value::type const& single = range::at(m_multi_geometry, box_pair.second); int in_val = detail::within::point_in_geometry(point, single, m_strategy); if (in_val > 0) // within { update(m_result); } else if (in_val == 0) { if (m_tc.check_boundary_point(point)) { update(m_result); } else { update(m_result); } } } if ( BOOST_GEOMETRY_CONDITION(m_result.interrupt) ) { return false; } if (! (relate::may_update(m_result) || relate::may_update(m_result) ) ) { return false; } return true; } private: MultiGeometry const& m_multi_geometry; topology_check_type const& m_tc; Result & m_result; Strategy const& m_strategy; }; public: typedef typename point_type::type point1_type; typedef typename point_type::type point2_type; typedef model::box box1_type; typedef model::box box2_type; typedef std::pair box_pair_type; template static inline void apply(MultiPoint const& multi_point, MultiGeometry const& multi_geometry, std::vector const& boxes, detail::relate::topology_check < MultiGeometry, Strategy > const& tc, Result & result, Strategy const& strategy) { item_visitor_type visitor(multi_geometry, tc, result, strategy); geometry::partition < box1_type >::apply(multi_point, boxes, visitor, expand_box_point(strategy), overlaps_box_point(strategy), expand_box_box_pair(strategy), overlaps_box_box_pair(strategy)); } }; // MultiGeometry - Linear or Areal // part of the algorithm calculating II, IB and IE // using rtree template struct multi_point_multi_geometry_ii_ib_ie { typedef typename point_type::type point1_type; typedef typename point_type::type point2_type; typedef model::box box1_type; typedef model::box box2_type; typedef std::pair box_pair_type; typedef std::vector boxes_type; template static inline void apply(MultiPoint const& multi_point, MultiGeometry const& multi_geometry, std::vector const& boxes, detail::relate::topology_check < MultiGeometry, Strategy > const& tc, Result & result, Strategy const& strategy) { typedef index::parameters < index::rstar<4>, Strategy > index_parameters_type; index::rtree rtree(boxes.begin(), boxes.end(), index_parameters_type(index::rstar<4>(), strategy)); for (auto it = boost::begin(multi_point); it != boost::end(multi_point); ++it) { if (! (relate::may_update(result) || relate::may_update(result) || relate::may_update(result) ) ) { return; } typename boost::range_value::type const& point = *it; boxes_type boxes_found; rtree.query(index::intersects(point), std::back_inserter(boxes_found)); bool found_ii_or_ib = false; for (auto const& box_found : boxes_found) { typename boost::range_value::type const& single = range::at(multi_geometry, box_found.second); int in_val = detail::within::point_in_geometry(point, single, strategy); if (in_val > 0) // within { update(result); found_ii_or_ib = true; } else if (in_val == 0) // on boundary of single { if (tc.check_boundary_point(point)) { update(result); } else { update(result); } found_ii_or_ib = true; } } // neither interior nor boundary found -> exterior if (found_ii_or_ib == false) { update(result); } if ( BOOST_GEOMETRY_CONDITION(result.interrupt) ) { return; } } } }; // MultiGeometry - Linear or Areal template struct multi_point_multi_geometry { static const bool interruption_enabled = true; template static inline void apply(MultiPoint const& multi_point, MultiGeometry const& multi_geometry, Result & result, Strategy const& strategy) { typedef typename point_type::type point2_type; typedef model::box box2_type; typedef std::pair box_pair_type; std::size_t count2 = boost::size(multi_geometry); std::vector boxes(count2); for (std::size_t i = 0 ; i < count2 ; ++i) { geometry::envelope(range::at(multi_geometry, i), boxes[i].first, strategy); geometry::detail::expand_by_epsilon(boxes[i].first); boxes[i].second = i; } typedef detail::relate::topology_check tc_t; tc_t tc(multi_geometry, strategy); if ( relate::may_update(result) || relate::may_update(result) || relate::may_update(result) ) { // If there is no need to calculate IE, use partition if (! relate::may_update(result) ) { multi_point_multi_geometry_ii_ib ::apply(multi_point, multi_geometry, boxes, tc, result, strategy); } else // otherwise use rtree { multi_point_multi_geometry_ii_ib_ie ::apply(multi_point, multi_geometry, boxes, tc, result, strategy); } } if ( BOOST_GEOMETRY_CONDITION(result.interrupt) ) { return; } if ( relate::may_update(result) || relate::may_update(result) ) { if ( relate::may_update(result) && tc.has_interior() ) { // TODO: this is not true if a linestring is degenerated to a point // then the interior has topological dimension = 0, not 1 update(result); } if ( relate::may_update(result) && tc.has_boundary() ) { if (multi_point_geometry_eb::apply(multi_point, tc)) { update(result); } } } update::value, Transpose>(result); } }; template < typename MultiPoint, typename Geometry, bool Transpose = false, bool isMulti = util::is_multi::value > struct multi_point_geometry : multi_point_single_geometry {}; template struct multi_point_geometry : multi_point_multi_geometry {}; // transposed result of multi_point_geometry template struct geometry_multi_point { static const bool interruption_enabled = true; template static inline void apply(Geometry const& geometry, MultiPoint const& multi_point, Result & result, Strategy const& strategy) { multi_point_geometry::apply(multi_point, geometry, result, strategy); } }; }} // namespace detail::relate #endif // DOXYGEN_NO_DETAIL }} // namespace boost::geometry #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_RELATE_MULTI_POINT_GEOMETRY_HPP