diff --git a/include/boost/geometry/algorithms/detail/relate/implementation.hpp b/include/boost/geometry/algorithms/detail/relate/implementation.hpp index 3bd0f806c..e1689f97e 100644 --- a/include/boost/geometry/algorithms/detail/relate/implementation.hpp +++ b/include/boost/geometry/algorithms/detail/relate/implementation.hpp @@ -23,6 +23,7 @@ #include #include #include +#include #include #include @@ -81,6 +82,16 @@ struct relate : detail::relate::geometry_point {}; +template +struct relate + : detail::relate::multi_point_single_geometry +{}; + +template +struct relate + : detail::relate::single_geometry_multi_point +{}; + template struct relate diff --git a/include/boost/geometry/algorithms/detail/relate/multi_point_geometry.hpp b/include/boost/geometry/algorithms/detail/relate/multi_point_geometry.hpp new file mode 100644 index 000000000..93e8607ef --- /dev/null +++ b/include/boost/geometry/algorithms/detail/relate/multi_point_geometry.hpp @@ -0,0 +1,189 @@ +// Boost.Geometry + +// Copyright (c) 2017 Oracle and/or its affiliates. + +// 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 + + +namespace boost { namespace geometry +{ + +#ifndef DOXYGEN_NO_DETAIL +namespace detail { namespace relate { + + +/* +template +struct multi_point_linear_exterior_boundary_check +{ + template + struct exterior_boundary_visitor + { + typedef typename boost::range_value::type point_type; + std::vector points; + bool found_exterior_boundary; + + exterior_boundary_visitor(MultiPoint const& multi_point) + : points(boost::begin(multi_point), boost::end(multi_point)) + , found_exterior_boundary(false) + { + std::sort(points.begin(), points.end(), geometry::less()); + } + + template + bool apply(BoundaryPoint const& boundary_point) + { + if (! std::binary_search(points.begin(), points.end(), boundary_point, geometry::less())) + { + found_exterior_boundary = true; + return false; + } + return true; + } + }; + + template + static bool apply(MultiPoint const& multi_point, TopologyCheck const& topology_check) + { + exterior_boundary_visitor visitor(multi_point); + topology_check.for_each_boundary_point(visitor); + return visitor.found_exterior_boundary; + } +}; + +template <> +struct multi_point_linear_exterior_boundary_check +{ + template + static bool apply(MultiPoint const& , TopologyCheck const& ) + { + return false; + } +}; +*/ + +// SingleGeometry - Linear or Areal +template +class multi_point_single_geometry +{ +public: + + 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 point1_type; + typedef typename point_type::type point2_type; + typedef model::box box2_type; + + box2_type box2; + geometry::envelope(single_geometry, box2, strategy.get_envelope_strategy()); + geometry::detail::expand_by_epsilon(box2); + + relate::set::value, Transpose>(result); + + typedef typename boost::range_const_iterator::type iterator; + for ( iterator it = boost::begin(multi_point) ; it != boost::end(multi_point) ; ++it ) + { + // The default strategy is enough for Point/Box + if (detail::disjoint::disjoint_point_box(*it, box2)) + { + relate::set(result); + } + else + { + int in_val = detail::within::point_in_geometry(*it, single_geometry, strategy); + + if ( in_val > 0 ) // within + { + relate::set(result); + } + else if ( in_val == 0 ) + { + relate::set(result); + } + else // in_val < 0 - not within + { + relate::set(result); + } + } + + if ( BOOST_GEOMETRY_CONDITION(result.interrupt) ) + { + return; + } + + if (! (relate::may_update(result) + || relate::may_update(result) + || relate::may_update(result) ) ) + { + break; + } + } + + typedef detail::relate::topology_check tc_t; + if ( relate::may_update(result) + || relate::may_update(result) ) + { + // TODO: For Linear geometry check all boundary points and degenerated linestrings? + tc_t tc(single_geometry); + + // TODO: this is not true if a linestring is degenerated to a point + // then the interior has topological dimension = 0, not 1 + if ( tc.has_interior ) + relate::set(result); + if ( tc.has_boundary ) + relate::set(result); + } + } + +}; + + +// transposed result of point_geometry +template +struct single_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_single_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 diff --git a/include/boost/geometry/algorithms/detail/relate/point_geometry.hpp b/include/boost/geometry/algorithms/detail/relate/point_geometry.hpp index a0c6c0d49..0d5b5ef22 100644 --- a/include/boost/geometry/algorithms/detail/relate/point_geometry.hpp +++ b/include/boost/geometry/algorithms/detail/relate/point_geometry.hpp @@ -60,29 +60,27 @@ struct point_geometry if ( BOOST_GEOMETRY_CONDITION(result.interrupt) ) return; - // the point is on the boundary - if ( pig == 0 ) + typedef detail::relate::topology_check tc_t; + if ( relate::may_update(result) + || relate::may_update(result) ) { - // NOTE: even for MLs, if there is at least one boundary point, - // somewhere there must be another one - - // check if there are other boundaries outside - typedef detail::relate::topology_check tc_t; - //tc_t tc(geometry, point); - //if ( tc.has_interior ) + // the point is on the boundary + if ( pig == 0 ) + { + // NOTE: even for MLs, if there is at least one boundary point, + // somewhere there must be another one relate::set(result); - //if ( tc.has_boundary ) - relate::set(result); - } - else - { - // check if there is a boundary in Geometry - typedef detail::relate::topology_check tc_t; - tc_t tc(geometry); - if ( tc.has_interior ) - relate::set(result); - if ( tc.has_boundary ) relate::set(result); + } + else + { + // check if there is a boundary in Geometry + tc_t tc(geometry); + if ( tc.has_interior ) + relate::set(result); + if ( tc.has_boundary ) + relate::set(result); + } } } }; diff --git a/include/boost/geometry/algorithms/detail/relate/topology_check.hpp b/include/boost/geometry/algorithms/detail/relate/topology_check.hpp index caa8a3c22..efbf922e7 100644 --- a/include/boost/geometry/algorithms/detail/relate/topology_check.hpp +++ b/include/boost/geometry/algorithms/detail/relate/topology_check.hpp @@ -1,13 +1,13 @@ // Boost.Geometry (aka GGL, Generic Geometry Library) -// Copyright (c) 2014, Oracle and/or its affiliates. +// Copyright (c) 2014-2017, Oracle and/or its affiliates. + +// 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) -// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle - #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_RELATE_TOPOLOGY_CHECK_HPP #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_RELATE_TOPOLOGY_CHECK_HPP @@ -55,20 +55,7 @@ struct topology_check bool has_boundary; topology_check(Linestring const& ls) - { - init(ls, 0); /*dummy param*/ - } - - template - topology_check(Linestring const& ls, IgnoreBoundaryPoint const& ibp) - { - init(ls, ibp); /*dummy param, won't be used*/ - } - - // Even if some point is on the boundary, if the Linestring has the boundary, - // there will be second boundary point different than IgnoreBoundaryPoint - template - void init(Linestring const& ls, IgnoreBoundaryPoint const&) + : m_ls(ls) { std::size_t count = boost::size(ls); has_interior = count > 0; @@ -76,6 +63,18 @@ struct topology_check has_boundary = count > 1 && ! detail::equals::equals_point_point(range::front(ls), range::back(ls)); } + + /*template + void for_each_boundary_point(Visitor& visitor) const + { + if (has_boundary) + { + visitor.apply(range::front(m_ls)); + visitor.apply(range::back(m_ls)); + } + }*/ + + Linestring const& m_ls; }; template @@ -87,22 +86,11 @@ struct topology_check bool has_interior; bool has_boundary; + typedef typename geometry::point_type::type point_type; + std::vector endpoints; + topology_check(MultiLinestring const& mls) { - init(mls, not_ignoring_counter()); - } - - template - topology_check(MultiLinestring const& mls, IgnoreBoundaryPoint const& ibp) - { - init(mls, ignoring_counter(ibp)); - } - - template - void init(MultiLinestring const& mls, OddCounter const& odd_counter) - { - typedef typename geometry::point_type::type point_type; - std::vector endpoints; endpoints.reserve(boost::size(mls) * 2); typedef typename boost::range_iterator::type ls_iterator; @@ -153,47 +141,41 @@ struct topology_check if ( !endpoints.empty() ) { std::sort(endpoints.begin(), endpoints.end(), geometry::less()); - has_boundary = odd_counter(endpoints.begin(), endpoints.end()); + has_boundary = find_odd_count(endpoints.begin(), endpoints.end()); } } - struct not_ignoring_counter - { - template - bool operator()(It first, It last) const - { - return find_odd_count(first, last); - } - }; - - template - struct ignoring_counter - { - ignoring_counter(Point const& pt) : m_pt(pt) {} - - template - bool operator()(It first, It last) const - { - typedef typename std::iterator_traits::value_type point_type; - - std::pair ignore_range - = std::equal_range(first, last, m_pt, - geometry::less()); - - if ( find_odd_count(first, ignore_range.first) ) - return true; - - return find_odd_count(ignore_range.second, last); - } - - Point const& m_pt; - }; - template static inline bool find_odd_count(It first, It last) { - if ( first == last ) + interrupting_visitor visitor; + for_each_boundary_point(first, last, visitor); + return visitor.found; + } + + struct interrupting_visitor + { + bool found; + interrupting_visitor() : found(false) {} + template + bool apply(Point const&) + { + found = true; return false; + } + }; + + template + void for_each_boundary_point(Visitor& visitor) const + { + for_each_boundary_point(endpoints.begin(), endpoints.end(), visitor); + } + + template + static void for_each_boundary_point(It first, It last, Visitor& visitor) + { + if ( first == last ) + return; std::size_t count = 1; It prev = first; @@ -203,8 +185,14 @@ struct topology_check // the end of the equal points subrange if ( ! equals::equals_point_point(*first, *prev) ) { + // odd count -> boundary if ( count % 2 != 0 ) - return true; + { + if (! visitor.apply(*prev)) + { + return; + } + } count = 1; } @@ -214,7 +202,11 @@ struct topology_check } } - return count % 2 != 0; + // odd count -> boundary + if ( count % 2 != 0 ) + { + visitor.apply(*prev); + } } }; @@ -227,8 +219,6 @@ struct topology_check static const bool has_boundary = true; topology_check(Ring const&) {} - template - topology_check(Ring const&, P const&) {} }; template @@ -240,8 +230,6 @@ struct topology_check static const bool has_boundary = true; topology_check(Polygon const&) {} - template - topology_check(Polygon const&, P const&) {} }; template @@ -253,8 +241,6 @@ struct topology_check static const bool has_boundary = true; topology_check(MultiPolygon const&) {} - template - topology_check(MultiPolygon const&, P const&) {} }; }} // namespace detail::relate