mirror of
https://github.com/boostorg/geometry.git
synced 2026-01-31 20:22:09 +00:00
[relate] Add MutliPoint/SingleLorA implementation.
This commit is contained in:
@@ -23,6 +23,7 @@
|
||||
#include <boost/geometry/algorithms/detail/relate/point_geometry.hpp>
|
||||
#include <boost/geometry/algorithms/detail/relate/linear_linear.hpp>
|
||||
#include <boost/geometry/algorithms/detail/relate/linear_areal.hpp>
|
||||
#include <boost/geometry/algorithms/detail/relate/multi_point_geometry.hpp>
|
||||
#include <boost/geometry/algorithms/detail/relate/areal_areal.hpp>
|
||||
|
||||
#include <boost/geometry/strategies/intersection.hpp>
|
||||
@@ -81,6 +82,16 @@ struct relate<Geometry, Point, Tag1, point_tag, TopDim1, 0, true>
|
||||
: detail::relate::geometry_point<Geometry, Point>
|
||||
{};
|
||||
|
||||
template <typename MultiPoint, typename Geometry, typename Tag2, int TopDim2>
|
||||
struct relate<MultiPoint, Geometry, multi_point_tag, Tag2, 0, TopDim2, false>
|
||||
: detail::relate::multi_point_single_geometry<MultiPoint, Geometry>
|
||||
{};
|
||||
|
||||
template <typename Geometry, typename MultiPoint, typename Tag1, int TopDim1>
|
||||
struct relate<Geometry, MultiPoint, Tag1, multi_point_tag, TopDim1, 0, false>
|
||||
: detail::relate::single_geometry_multi_point<Geometry, MultiPoint>
|
||||
{};
|
||||
|
||||
|
||||
template <typename Linear1, typename Linear2, typename Tag1, typename Tag2>
|
||||
struct relate<Linear1, Linear2, Tag1, Tag2, 1, 1, true>
|
||||
|
||||
@@ -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 <boost/range.hpp>
|
||||
|
||||
#include <boost/geometry/algorithms/detail/disjoint/point_box.hpp>
|
||||
#include <boost/geometry/algorithms/detail/expand_by_epsilon.hpp>
|
||||
#include <boost/geometry/algorithms/detail/relate/result.hpp>
|
||||
#include <boost/geometry/algorithms/detail/relate/topology_check.hpp>
|
||||
#include <boost/geometry/algorithms/detail/within/point_in_geometry.hpp>
|
||||
#include <boost/geometry/algorithms/envelope.hpp>
|
||||
|
||||
#include <boost/geometry/core/is_areal.hpp>
|
||||
#include <boost/geometry/core/point_type.hpp>
|
||||
|
||||
#include <boost/geometry/geometries/box.hpp>
|
||||
|
||||
|
||||
namespace boost { namespace geometry
|
||||
{
|
||||
|
||||
#ifndef DOXYGEN_NO_DETAIL
|
||||
namespace detail { namespace relate {
|
||||
|
||||
|
||||
/*
|
||||
template <bool IsLinear>
|
||||
struct multi_point_linear_exterior_boundary_check
|
||||
{
|
||||
template <typename MultiPoint>
|
||||
struct exterior_boundary_visitor
|
||||
{
|
||||
typedef typename boost::range_value<MultiPoint>::type point_type;
|
||||
std::vector<point_type> 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<point_type>());
|
||||
}
|
||||
|
||||
template <typename BoundaryPoint>
|
||||
bool apply(BoundaryPoint const& boundary_point)
|
||||
{
|
||||
if (! std::binary_search(points.begin(), points.end(), boundary_point, geometry::less<point_type>()))
|
||||
{
|
||||
found_exterior_boundary = true;
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
template <typename MultiPoint, typename TopologyCheck>
|
||||
static bool apply(MultiPoint const& multi_point, TopologyCheck const& topology_check)
|
||||
{
|
||||
exterior_boundary_visitor<MultiPoint> visitor(multi_point);
|
||||
topology_check.for_each_boundary_point(visitor);
|
||||
return visitor.found_exterior_boundary;
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct multi_point_linear_exterior_boundary_check<false>
|
||||
{
|
||||
template <typename MultiPoint, typename TopologyCheck>
|
||||
static bool apply(MultiPoint const& , TopologyCheck const& )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
};
|
||||
*/
|
||||
|
||||
// SingleGeometry - Linear or Areal
|
||||
template <typename MultiPoint, typename SingleGeometry, bool Transpose = false>
|
||||
class multi_point_single_geometry
|
||||
{
|
||||
public:
|
||||
|
||||
static const bool interruption_enabled = true;
|
||||
|
||||
template <typename Result, typename Strategy>
|
||||
static inline void apply(MultiPoint const& multi_point,
|
||||
SingleGeometry const& single_geometry,
|
||||
Result & result,
|
||||
Strategy const& strategy)
|
||||
{
|
||||
typedef typename point_type<MultiPoint>::type point1_type;
|
||||
typedef typename point_type<SingleGeometry>::type point2_type;
|
||||
typedef model::box<point2_type> box2_type;
|
||||
|
||||
box2_type box2;
|
||||
geometry::envelope(single_geometry, box2, strategy.get_envelope_strategy());
|
||||
geometry::detail::expand_by_epsilon(box2);
|
||||
|
||||
relate::set<exterior, exterior, result_dimension<MultiPoint>::value, Transpose>(result);
|
||||
|
||||
typedef typename boost::range_const_iterator<MultiPoint>::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<interior, exterior, '0', Transpose>(result);
|
||||
}
|
||||
else
|
||||
{
|
||||
int in_val = detail::within::point_in_geometry(*it, single_geometry, strategy);
|
||||
|
||||
if ( in_val > 0 ) // within
|
||||
{
|
||||
relate::set<interior, interior, '0', Transpose>(result);
|
||||
}
|
||||
else if ( in_val == 0 )
|
||||
{
|
||||
relate::set<interior, boundary, '0', Transpose>(result);
|
||||
}
|
||||
else // in_val < 0 - not within
|
||||
{
|
||||
relate::set<interior, exterior, '0', Transpose>(result);
|
||||
}
|
||||
}
|
||||
|
||||
if ( BOOST_GEOMETRY_CONDITION(result.interrupt) )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (! (relate::may_update<interior, interior, '0', Transpose>(result)
|
||||
|| relate::may_update<interior, boundary, '0', Transpose>(result)
|
||||
|| relate::may_update<interior, exterior, '0', Transpose>(result) ) )
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
typedef detail::relate::topology_check<SingleGeometry> tc_t;
|
||||
if ( relate::may_update<exterior, interior, tc_t::interior, Transpose>(result)
|
||||
|| relate::may_update<exterior, boundary, tc_t::boundary, Transpose>(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<exterior, interior, tc_t::interior, Transpose>(result);
|
||||
if ( tc.has_boundary )
|
||||
relate::set<exterior, boundary, tc_t::boundary, Transpose>(result);
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
||||
// transposed result of point_geometry
|
||||
template <typename Geometry, typename MultiPoint>
|
||||
struct single_geometry_multi_point
|
||||
{
|
||||
static const bool interruption_enabled = true;
|
||||
|
||||
template <typename Result, typename Strategy>
|
||||
static inline void apply(Geometry const& geometry, MultiPoint const& multi_point,
|
||||
Result & result, Strategy const& strategy)
|
||||
{
|
||||
multi_point_single_geometry<MultiPoint, Geometry, true>::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
|
||||
@@ -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<Geometry> tc_t;
|
||||
if ( relate::may_update<exterior, interior, tc_t::interior, Transpose>(result)
|
||||
|| relate::may_update<exterior, boundary, tc_t::boundary, Transpose>(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<Geometry> 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<exterior, interior, tc_t::interior, Transpose>(result);
|
||||
//if ( tc.has_boundary )
|
||||
relate::set<exterior, boundary, tc_t::boundary, Transpose>(result);
|
||||
}
|
||||
else
|
||||
{
|
||||
// check if there is a boundary in Geometry
|
||||
typedef detail::relate::topology_check<Geometry> tc_t;
|
||||
tc_t tc(geometry);
|
||||
if ( tc.has_interior )
|
||||
relate::set<exterior, interior, tc_t::interior, Transpose>(result);
|
||||
if ( tc.has_boundary )
|
||||
relate::set<exterior, boundary, tc_t::boundary, Transpose>(result);
|
||||
}
|
||||
else
|
||||
{
|
||||
// check if there is a boundary in Geometry
|
||||
tc_t tc(geometry);
|
||||
if ( tc.has_interior )
|
||||
relate::set<exterior, interior, tc_t::interior, Transpose>(result);
|
||||
if ( tc.has_boundary )
|
||||
relate::set<exterior, boundary, tc_t::boundary, Transpose>(result);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -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<Linestring, linestring_tag>
|
||||
bool has_boundary;
|
||||
|
||||
topology_check(Linestring const& ls)
|
||||
{
|
||||
init(ls, 0); /*dummy param*/
|
||||
}
|
||||
|
||||
template <typename IgnoreBoundaryPoint>
|
||||
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 <typename IgnoreBoundaryPoint>
|
||||
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<Linestring, linestring_tag>
|
||||
has_boundary = count > 1
|
||||
&& ! detail::equals::equals_point_point(range::front(ls), range::back(ls));
|
||||
}
|
||||
|
||||
/*template <typename Visitor>
|
||||
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 <typename MultiLinestring>
|
||||
@@ -87,22 +86,11 @@ struct topology_check<MultiLinestring, multi_linestring_tag>
|
||||
bool has_interior;
|
||||
bool has_boundary;
|
||||
|
||||
typedef typename geometry::point_type<MultiLinestring>::type point_type;
|
||||
std::vector<point_type> endpoints;
|
||||
|
||||
topology_check(MultiLinestring const& mls)
|
||||
{
|
||||
init(mls, not_ignoring_counter());
|
||||
}
|
||||
|
||||
template <typename IgnoreBoundaryPoint>
|
||||
topology_check(MultiLinestring const& mls, IgnoreBoundaryPoint const& ibp)
|
||||
{
|
||||
init(mls, ignoring_counter<IgnoreBoundaryPoint>(ibp));
|
||||
}
|
||||
|
||||
template <typename OddCounter>
|
||||
void init(MultiLinestring const& mls, OddCounter const& odd_counter)
|
||||
{
|
||||
typedef typename geometry::point_type<MultiLinestring>::type point_type;
|
||||
std::vector<point_type> endpoints;
|
||||
endpoints.reserve(boost::size(mls) * 2);
|
||||
|
||||
typedef typename boost::range_iterator<MultiLinestring const>::type ls_iterator;
|
||||
@@ -153,47 +141,41 @@ struct topology_check<MultiLinestring, multi_linestring_tag>
|
||||
if ( !endpoints.empty() )
|
||||
{
|
||||
std::sort(endpoints.begin(), endpoints.end(), geometry::less<point_type>());
|
||||
has_boundary = odd_counter(endpoints.begin(), endpoints.end());
|
||||
has_boundary = find_odd_count(endpoints.begin(), endpoints.end());
|
||||
}
|
||||
}
|
||||
|
||||
struct not_ignoring_counter
|
||||
{
|
||||
template <typename It>
|
||||
bool operator()(It first, It last) const
|
||||
{
|
||||
return find_odd_count(first, last);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename Point>
|
||||
struct ignoring_counter
|
||||
{
|
||||
ignoring_counter(Point const& pt) : m_pt(pt) {}
|
||||
|
||||
template <typename It>
|
||||
bool operator()(It first, It last) const
|
||||
{
|
||||
typedef typename std::iterator_traits<It>::value_type point_type;
|
||||
|
||||
std::pair<It, It> ignore_range
|
||||
= std::equal_range(first, last, m_pt,
|
||||
geometry::less<point_type>());
|
||||
|
||||
if ( find_odd_count(first, ignore_range.first) )
|
||||
return true;
|
||||
|
||||
return find_odd_count(ignore_range.second, last);
|
||||
}
|
||||
|
||||
Point const& m_pt;
|
||||
};
|
||||
|
||||
template <typename It>
|
||||
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 <typename Point>
|
||||
bool apply(Point const&)
|
||||
{
|
||||
found = true;
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
template <typename Visitor>
|
||||
void for_each_boundary_point(Visitor& visitor) const
|
||||
{
|
||||
for_each_boundary_point(endpoints.begin(), endpoints.end(), visitor);
|
||||
}
|
||||
|
||||
template <typename It, typename Visitor>
|
||||
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<MultiLinestring, multi_linestring_tag>
|
||||
// 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<MultiLinestring, multi_linestring_tag>
|
||||
}
|
||||
}
|
||||
|
||||
return count % 2 != 0;
|
||||
// odd count -> boundary
|
||||
if ( count % 2 != 0 )
|
||||
{
|
||||
visitor.apply(*prev);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -227,8 +219,6 @@ struct topology_check<Ring, ring_tag>
|
||||
static const bool has_boundary = true;
|
||||
|
||||
topology_check(Ring const&) {}
|
||||
template <typename P>
|
||||
topology_check(Ring const&, P const&) {}
|
||||
};
|
||||
|
||||
template <typename Polygon>
|
||||
@@ -240,8 +230,6 @@ struct topology_check<Polygon, polygon_tag>
|
||||
static const bool has_boundary = true;
|
||||
|
||||
topology_check(Polygon const&) {}
|
||||
template <typename P>
|
||||
topology_check(Polygon const&, P const&) {}
|
||||
};
|
||||
|
||||
template <typename MultiPolygon>
|
||||
@@ -253,8 +241,6 @@ struct topology_check<MultiPolygon, multi_polygon_tag>
|
||||
static const bool has_boundary = true;
|
||||
|
||||
topology_check(MultiPolygon const&) {}
|
||||
template <typename P>
|
||||
topology_check(MultiPolygon const&, P const&) {}
|
||||
};
|
||||
|
||||
}} // namespace detail::relate
|
||||
|
||||
Reference in New Issue
Block a user