123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351 |
- // Boost.Geometry (aka GGL, Generic Geometry Library)
- // 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_TOPOLOGY_CHECK_HPP
- #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_RELATE_TOPOLOGY_CHECK_HPP
- #include <boost/range/size.hpp>
- #include <boost/geometry/algorithms/detail/equals/point_point.hpp>
- #include <boost/geometry/algorithms/not_implemented.hpp>
- #include <boost/geometry/policies/compare.hpp>
- #include <boost/geometry/util/has_nan_coordinate.hpp>
- #include <boost/geometry/util/range.hpp>
- 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
- <
- typename Geometry,
- typename Strategy,
- typename Tag = typename geometry::tag<Geometry>::type
- >
- struct topology_check
- : not_implemented<Tag>
- {};
- //template <typename Point, typename Strategy>
- //struct topology_check<Point, Strategy, point_tag>
- //{
- // 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 <typename IgnoreBoundaryPoint>
- // topology_check(Point const&, IgnoreBoundaryPoint const&) {}
- //};
- template <typename Linestring, typename Strategy>
- struct topology_check<Linestring, Strategy, linestring_tag>
- {
- static const char interior = '1';
- static const char boundary = '0';
- topology_check(Linestring const& ls, Strategy const& strategy)
- : m_ls(ls)
- , m_strategy(strategy)
- , m_is_initialized(false)
- {}
- bool has_interior() const
- {
- init();
- return m_has_interior;
- }
- bool has_boundary() const
- {
- init();
- return m_has_boundary;
- }
- /*template <typename Point>
- bool check_boundary_point(Point const& point) const
- {
- init();
- return m_has_boundary
- && ( equals::equals_point_point(point, range::front(m_ls))
- || equals::equals_point_point(point, range::back(m_ls)) );
- }*/
- template <typename Visitor>
- void for_each_boundary_point(Visitor & visitor) const
- {
- init();
- if (m_has_boundary)
- {
- if (visitor.apply(range::front(m_ls), m_strategy))
- visitor.apply(range::back(m_ls), m_strategy);
- }
- }
- private:
- void init() const
- {
- if (m_is_initialized)
- return;
- std::size_t count = boost::size(m_ls);
- m_has_interior = count > 0;
- // NOTE: Linestring with all points equal is treated as 1d linear ring
- m_has_boundary = count > 1
- && ! detail::equals::equals_point_point(range::front(m_ls),
- range::back(m_ls),
- m_strategy);
- m_is_initialized = true;
- }
- Linestring const& m_ls;
- Strategy const& m_strategy;
- mutable bool m_is_initialized;
- mutable bool m_has_interior;
- mutable bool m_has_boundary;
- };
- template <typename MultiLinestring, typename Strategy>
- struct topology_check<MultiLinestring, Strategy, multi_linestring_tag>
- {
- static const char interior = '1';
- static const char boundary = '0';
- topology_check(MultiLinestring const& mls, Strategy const& strategy)
- : m_mls(mls)
- , m_strategy(strategy)
- , m_is_initialized(false)
- {}
- bool has_interior() const
- {
- init();
- return m_has_interior;
- }
- bool has_boundary() const
- {
- init();
- return m_has_boundary;
- }
- template <typename Point>
- bool check_boundary_point(Point const& point) const
- {
- init();
- if (! m_has_boundary)
- return false;
- std::size_t count = count_equal(m_endpoints.begin(), m_endpoints.end(), point);
- return count % 2 != 0; // odd count -> boundary
- }
- template <typename Visitor>
- void for_each_boundary_point(Visitor & visitor) const
- {
- init();
- if (m_has_boundary)
- {
- for_each_boundary_point(m_endpoints.begin(), m_endpoints.end(), visitor);
- }
- }
- private:
- typedef geometry::less<void, -1, Strategy> less_type;
- void init() const
- {
- if (m_is_initialized)
- {
- return;
- }
- m_endpoints.reserve(boost::size(m_mls) * 2);
- m_has_interior = false;
- for (auto it = boost::begin(m_mls); it != boost::end(m_mls); ++it)
- {
- auto const& ls = *it;
- std::size_t count = boost::size(ls);
- if (count > 0)
- {
- m_has_interior = true;
- }
- if (count > 1)
- {
- auto const& front_pt = range::front(ls);
- auto const& back_pt = range::back(ls);
- // don't store boundaries of linear rings, this doesn't change anything
- if (! equals::equals_point_point(front_pt, back_pt, m_strategy))
- {
- // do not add points containing NaN coordinates
- // because they cannot be reasonably compared, e.g. with MSVC
- // an assertion failure is reported in std::equal_range()
- // NOTE: currently ignoring_counter calling std::equal_range()
- // is not used anywhere in the code, still it's safer this way
- if (! geometry::has_nan_coordinate(front_pt))
- {
- m_endpoints.push_back(front_pt);
- }
- if (! geometry::has_nan_coordinate(back_pt))
- {
- m_endpoints.push_back(back_pt);
- }
- }
- }
- }
- m_has_boundary = false;
- if (! m_endpoints.empty())
- {
- std::sort(m_endpoints.begin(), m_endpoints.end(), less_type());
- m_has_boundary = find_odd_count(m_endpoints.begin(), m_endpoints.end());
- }
- m_is_initialized = true;
- }
- template <typename It, typename Point>
- static inline std::size_t count_equal(It first, It last, Point const& point)
- {
- std::pair<It, It> rng = std::equal_range(first, last, point, less_type());
- return (std::size_t)std::distance(rng.first, rng.second);
- }
- template <typename It>
- inline bool find_odd_count(It first, It last) const
- {
- interrupting_visitor visitor;
- for_each_boundary_point(first, last, visitor);
- return visitor.found;
- }
- struct interrupting_visitor
- {
- bool found;
- interrupting_visitor() : found(false) {}
- template <typename Point>
- bool apply(Point const&, Strategy const&)
- {
- found = true;
- return false;
- }
- };
- template <typename It, typename Visitor>
- void for_each_boundary_point(It first, It last, Visitor& visitor) const
- {
- if ( first == last )
- return;
- 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, m_strategy) )
- {
- // odd count -> boundary
- if ( count % 2 != 0 )
- {
- if (! visitor.apply(*prev, m_strategy))
- {
- return;
- }
- }
- count = 1;
- }
- else
- {
- ++count;
- }
- }
- // odd count -> boundary
- if ( count % 2 != 0 )
- {
- visitor.apply(*prev, m_strategy);
- }
- }
- private:
- MultiLinestring const& m_mls;
- Strategy const& m_strategy;
- mutable bool m_is_initialized;
- mutable bool m_has_interior;
- mutable bool m_has_boundary;
- typedef typename geometry::point_type<MultiLinestring>::type point_type;
- mutable std::vector<point_type> m_endpoints;
- };
- struct topology_check_areal
- {
- static const char interior = '2';
- static const char boundary = '1';
- static bool has_interior() { return true; }
- static bool has_boundary() { return true; }
- };
- template <typename Ring, typename Strategy>
- struct topology_check<Ring, Strategy, ring_tag>
- : topology_check_areal
- {
- topology_check(Ring const&, Strategy const&) {}
- };
- template <typename Polygon, typename Strategy>
- struct topology_check<Polygon, Strategy, polygon_tag>
- : topology_check_areal
- {
- topology_check(Polygon const&, Strategy const&) {}
- };
- template <typename MultiPolygon, typename Strategy>
- struct topology_check<MultiPolygon, Strategy, multi_polygon_tag>
- : topology_check_areal
- {
- topology_check(MultiPolygon const&, Strategy const&) {}
- template <typename Point>
- static bool check_boundary_point(Point const& ) { return true; }
- };
- }} // namespace detail::relate
- #endif // DOXYGEN_NO_DETAIL
- }} // namespace boost::geometry
- #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_RELATE_TOPOLOGY_CHECK_HPP
|