// Boost.Geometry (aka GGL, Generic Geometry Library) // Copyright (c) 2014, Oracle and/or its affiliates. // 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 #include #include #include namespace boost { namespace geometry { #ifndef DOXYGEN_NO_DETAIL namespace detail { namespace relate { // TODO: change the name for e.g. something with the word "exterior" template ::type> struct topology_check : not_implemented {}; //template //struct topology_check //{ // static const char interior = '0'; // static const char boundary = 'F'; // // static const bool has_interior = true; // static const bool has_boundary = false; // // topology_check(Point const&) {} // template // topology_check(Point const&, IgnoreBoundaryPoint const&) {} //}; template struct topology_check { static const char interior = '1'; static const char boundary = '0'; bool has_interior; 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&) { std::size_t count = boost::size(ls); has_interior = count > 0; // NOTE: Linestring with all points equal is treated as 1d linear ring has_boundary = count > 1 && ! detail::equals::equals_point_point(range::front(ls), range::back(ls)); } }; template struct topology_check { static const char interior = '1'; static const char boundary = '0'; bool has_interior; bool has_boundary; 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; for ( ls_iterator it = boost::begin(mls) ; it != boost::end(mls) ; ++it ) { std::size_t count = boost::size(*it); if ( count > 0 ) { has_interior = true; } if ( count > 1 ) { // don't store boundaries of linear rings, this doesn't change anything if ( ! equals::equals_point_point(range::front(*it), range::back(*it)) ) { endpoints.push_back(range::front(*it)); endpoints.push_back(range::back(*it)); } } } has_boundary = false; if ( !endpoints.empty() ) { std::sort(endpoints.begin(), endpoints.end(), geometry::less()); has_boundary = odd_counter(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 ) return false; std::size_t count = 1; It prev = first; ++first; for ( ; first != last ; ++first, ++prev ) { // the end of the equal points subrange if ( ! equals::equals_point_point(*first, *prev) ) { if ( count % 2 != 0 ) return true; count = 1; } else { ++count; } } return count % 2 != 0; } }; template struct topology_check { static const char interior = '2'; static const char boundary = '1'; static const bool has_interior = true; static const bool has_boundary = true; topology_check(Ring const&) {} template topology_check(Ring const&, P const&) {} }; template struct topology_check { static const char interior = '2'; static const char boundary = '1'; static const bool has_interior = true; static const bool has_boundary = true; topology_check(Polygon const&) {} template topology_check(Polygon const&, P const&) {} }; template struct topology_check { static const char interior = '2'; static const char boundary = '1'; static const bool has_interior = true; static const bool has_boundary = true; topology_check(MultiPolygon const&) {} template topology_check(MultiPolygon const&, P const&) {} }; }} // namespace detail::relate #endif // DOXYGEN_NO_DETAIL }} // namespace boost::geometry #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_RELATE_TOPOLOGY_CHECK_HPP