blob: f98c3e9b8264b6e986b8c897fc7997516198fd00 [file] [log] [blame]
// 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_BOUNDARY_CHECKER_HPP
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_RELATE_BOUNDARY_CHECKER_HPP
#include <boost/geometry/util/range.hpp>
#include <boost/geometry/algorithms/num_points.hpp>
#include <boost/geometry/algorithms/detail/sub_range.hpp>
#include <boost/geometry/algorithms/detail/equals/point_point.hpp>
namespace boost { namespace geometry
{
#ifndef DOXYGEN_NO_DETAIL
namespace detail { namespace relate {
enum boundary_query { boundary_front, boundary_back, boundary_any };
template <typename Geometry,
typename Tag = typename geometry::tag<Geometry>::type>
class boundary_checker {};
template <typename Geometry>
class boundary_checker<Geometry, linestring_tag>
{
typedef typename point_type<Geometry>::type point_type;
public:
boundary_checker(Geometry const& g)
: has_boundary( boost::size(g) >= 2
&& !detail::equals::equals_point_point(range::front(g), range::back(g)) )
, geometry(g)
{}
template <boundary_query BoundaryQuery>
bool is_endpoint_boundary(point_type const& pt) const
{
boost::ignore_unused_variable_warning(pt);
#ifdef BOOST_GEOMETRY_DEBUG_RELATE_BOUNDARY_CHECKER
// may give false positives for INT
BOOST_ASSERT( (BoundaryQuery == boundary_front || BoundaryQuery == boundary_any)
&& detail::equals::equals_point_point(pt, range::front(geometry))
|| (BoundaryQuery == boundary_back || BoundaryQuery == boundary_any)
&& detail::equals::equals_point_point(pt, range::back(geometry)) );
#endif
return has_boundary;
}
private:
bool has_boundary;
Geometry const& geometry;
};
template <typename Geometry>
class boundary_checker<Geometry, multi_linestring_tag>
{
typedef typename point_type<Geometry>::type point_type;
public:
boundary_checker(Geometry const& g)
: is_filled(false), geometry(g)
{}
// First call O(NlogN)
// Each next call O(logN)
template <boundary_query BoundaryQuery>
bool is_endpoint_boundary(point_type const& pt) const
{
typedef typename boost::range_size<Geometry>::type size_type;
size_type multi_count = boost::size(geometry);
if ( multi_count < 1 )
return false;
if ( ! is_filled )
{
//boundary_points.clear();
boundary_points.reserve(multi_count * 2);
typedef typename boost::range_iterator<Geometry const>::type multi_iterator;
for ( multi_iterator it = boost::begin(geometry) ;
it != boost::end(geometry) ; ++ it )
{
// empty or point - no boundary
if ( boost::size(*it) < 2 )
continue;
// linear ring or point - no boundary
if ( equals::equals_point_point(range::front(*it), range::back(*it)) )
continue;
boundary_points.push_back(range::front(*it));
boundary_points.push_back(range::back(*it));
}
std::sort(boundary_points.begin(), boundary_points.end(), geometry::less<point_type>());
is_filled = true;
}
std::size_t equal_points_count
= boost::size(
std::equal_range(boundary_points.begin(),
boundary_points.end(),
pt,
geometry::less<point_type>())
);
return equal_points_count % 2 != 0;// && equal_points_count > 0; // the number is odd and > 0
}
private:
mutable bool is_filled;
// TODO: store references/pointers instead of points?
mutable std::vector<point_type> boundary_points;
Geometry const& geometry;
};
}} // namespace detail::relate
#endif // DOXYGEN_NO_DETAIL
}} // namespace boost::geometry
#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_RELATE_BOUNDARY_CHECKER_HPP