mirror of
https://github.com/boostorg/geometry.git
synced 2026-02-11 11:52:11 +00:00
Merge branch 'feature/relate' of https://github.com/boostorg/geometry into feature/setops
This commit is contained in:
@@ -492,7 +492,8 @@ struct get_turn_info_linear_linear
|
||||
|
||||
result_ignore_ip0 = !opposite ? // <=> ip_count == 1 || ip_count == 2 && !opposite
|
||||
append0_last :
|
||||
(append0_last && p0j);
|
||||
(append0_last && (p0j || q0_last && q1i));
|
||||
// NOTE: based on how collinear is calculated for opposite segments
|
||||
|
||||
if ( append0_first || append0_last )
|
||||
{
|
||||
@@ -533,7 +534,9 @@ struct get_turn_info_linear_linear
|
||||
|
||||
result_ignore_ip1 = !opposite ? // <=> ip_count == 2 && !opposite
|
||||
append1_last :
|
||||
(append1_last && q1j);
|
||||
(append1_last && (q1j || p1_last && p0i));
|
||||
// NOTE: based on how collinear is calculated for opposite segments
|
||||
// this condition is symmetric to the one above
|
||||
|
||||
if ( append1_first || append1_last )
|
||||
{
|
||||
|
||||
@@ -0,0 +1,184 @@
|
||||
// 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/algorithms/detail/disjoint/point_point.hpp>
|
||||
#include <boost/geometry/algorithms/detail/range_helpers.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_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)) );
|
||||
return has_boundary;
|
||||
}
|
||||
|
||||
template <boundary_query BoundaryQuery>
|
||||
bool is_boundary(point_type const& pt, segment_identifier const& sid) const
|
||||
{
|
||||
if ( !has_boundary )
|
||||
return false;
|
||||
|
||||
if ( BoundaryQuery == boundary_front )
|
||||
{
|
||||
return sid.segment_index == 0
|
||||
&& detail::equals::equals_point_point(pt, range::front(geometry));
|
||||
}
|
||||
else if ( BoundaryQuery == boundary_back )
|
||||
{
|
||||
return sid.segment_index + 2 == geometry::num_points(geometry)
|
||||
&& detail::equals::equals_point_point(pt, range::back(geometry));
|
||||
}
|
||||
else if ( BoundaryQuery == boundary_any )
|
||||
{
|
||||
return sid.segment_index == 0
|
||||
&& detail::equals::equals_point_point(pt, range::front(geometry))
|
||||
|| sid.segment_index + 2 == geometry::num_points(geometry)
|
||||
&& detail::equals::equals_point_point(pt, range::back(geometry));
|
||||
}
|
||||
|
||||
BOOST_ASSERT(false);
|
||||
return false;
|
||||
}
|
||||
|
||||
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)
|
||||
{}
|
||||
|
||||
template <boundary_query BoundaryQuery>
|
||||
bool is_endpoint_boundary(point_type const& pt)
|
||||
{
|
||||
return is_boundary_point(pt);
|
||||
}
|
||||
|
||||
template <boundary_query BoundaryQuery>
|
||||
bool is_boundary(point_type const& pt, segment_identifier const& sid)
|
||||
{
|
||||
if ( BoundaryQuery == boundary_front )
|
||||
{
|
||||
if ( sid.segment_index != 0 )
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( BoundaryQuery == boundary_back )
|
||||
{
|
||||
if ( sid.segment_index + 2 != geometry::num_points(sub_geometry::get(geometry, sid)) )
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( BoundaryQuery == boundary_any )
|
||||
{
|
||||
if ( sid.segment_index != 0
|
||||
&& sid.segment_index + 2 != geometry::num_points(sub_geometry::get(geometry, sid)) )
|
||||
return false;
|
||||
}
|
||||
|
||||
return is_boundary_point(pt);
|
||||
}
|
||||
|
||||
private:
|
||||
// First call O(NlogN)
|
||||
// Each next call O(logN)
|
||||
bool is_boundary_point(point_type const& pt)
|
||||
{
|
||||
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
|
||||
}
|
||||
|
||||
bool is_filled;
|
||||
// TODO: store references/pointers instead of points?
|
||||
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
|
||||
@@ -9,15 +9,18 @@
|
||||
// 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_LINEAR_LINEAR_HPP
|
||||
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_RELATE_LINEAR_LINEAR_HPP
|
||||
|
||||
#include <boost/geometry/algorithms/detail/sub_geometry.hpp>
|
||||
#include <boost/geometry/algorithms/detail/range_helpers.hpp>
|
||||
|
||||
#include <boost/geometry/algorithms/detail/relate/result.hpp>
|
||||
#include <boost/geometry/algorithms/detail/relate/point_geometry.hpp>
|
||||
#include <boost/geometry/algorithms/detail/relate/turns.hpp>
|
||||
#include <boost/geometry/algorithms/detail/sub_geometry.hpp>
|
||||
|
||||
#include <boost/geometry/algorithms/detail/range_helpers.hpp>
|
||||
#include <boost/geometry/algorithms/detail/relate/boundary_checker.hpp>
|
||||
|
||||
namespace boost { namespace geometry
|
||||
{
|
||||
@@ -25,170 +28,188 @@ namespace boost { namespace geometry
|
||||
#ifndef DOXYGEN_NO_DETAIL
|
||||
namespace detail { namespace relate {
|
||||
|
||||
// update_result
|
||||
enum linestring_kind { linestring_exterior, linestring_point, linestring_closed, linestring_open };
|
||||
|
||||
template <field F1, field F2, char D, bool Reverse>
|
||||
struct update_result_dispatch
|
||||
template <typename Linestring>
|
||||
linestring_kind check_linestring_kind(Linestring const& ls)
|
||||
{
|
||||
static inline void apply(result & res)
|
||||
std::size_t count = boost::size(ls);
|
||||
if ( count == 0 )
|
||||
return linestring_exterior;
|
||||
else if ( count == 1 )
|
||||
return linestring_point;
|
||||
else
|
||||
{
|
||||
res.template update<F1, F2, D>();
|
||||
}
|
||||
};
|
||||
|
||||
template <field F1, field F2, char D>
|
||||
struct update_result_dispatch<F1, F2, D, true>
|
||||
{
|
||||
static inline void apply(result & res)
|
||||
{
|
||||
res.template update<F2, F1, D>();
|
||||
}
|
||||
};
|
||||
|
||||
template <field F1, field F2, char D, bool Reverse>
|
||||
inline void update_result(result & res)
|
||||
{
|
||||
update_result_dispatch<F1, F2, D, Reverse>::apply(res);
|
||||
}
|
||||
|
||||
// boundary_checker
|
||||
|
||||
enum boundary_query { boundary_front, boundary_back, boundary_front_explicit, boundary_back_explicit, 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(! detail::equals::equals_point_point(range::front(g), range::back(g)))
|
||||
, geometry(g)
|
||||
{}
|
||||
|
||||
template <boundary_query BoundaryQuery>
|
||||
bool is_boundary(point_type const& pt, segment_identifier const& sid) const
|
||||
{
|
||||
// TODO: replace with assert?
|
||||
if ( boost::size(geometry) < 2 )
|
||||
return false;
|
||||
|
||||
// TODO: handle also linestrings with points_num == 2 and equals(front, back) - treat like point?
|
||||
|
||||
if ( !has_boundary )
|
||||
return false;
|
||||
|
||||
if ( BoundaryQuery == boundary_front_explicit || BoundaryQuery == boundary_back_explicit )
|
||||
return true;
|
||||
|
||||
if ( BoundaryQuery == boundary_front )
|
||||
return sid.segment_index == 0
|
||||
&& detail::equals::equals_point_point(pt, range::front(geometry));
|
||||
|
||||
if ( BoundaryQuery == boundary_back )
|
||||
return sid.segment_index + 2 == geometry::num_points(geometry)
|
||||
&& detail::equals::equals_point_point(pt, range::back(geometry));
|
||||
|
||||
if ( BoundaryQuery == boundary_any )
|
||||
return sid.segment_index == 0
|
||||
&& detail::equals::equals_point_point(pt, range::front(geometry))
|
||||
|| sid.segment_index + 2 == geometry::num_points(geometry)
|
||||
&& detail::equals::equals_point_point(pt, range::back(geometry));
|
||||
|
||||
BOOST_ASSERT(false);
|
||||
return false;
|
||||
}
|
||||
|
||||
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)
|
||||
{}
|
||||
|
||||
template <boundary_query BoundaryQuery>
|
||||
bool is_boundary(point_type const& pt, segment_identifier const& sid)
|
||||
{
|
||||
typedef typename boost::range_size<Geometry>::type size_type;
|
||||
size_type multi_count = boost::size(geometry);
|
||||
|
||||
// TODO: replace with assert?
|
||||
if ( multi_count < 1 )
|
||||
return false;
|
||||
|
||||
// TODO: for explicit parameters ASSERT could be used
|
||||
|
||||
if ( BoundaryQuery == boundary_front || BoundaryQuery == boundary_front_explicit )
|
||||
bool equal_fb = equals::equals_point_point(range::front(ls), range::back(ls));
|
||||
if ( equal_fb )
|
||||
{
|
||||
if ( sid.segment_index != 0 )
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( BoundaryQuery == boundary_back || BoundaryQuery == boundary_back_explicit )
|
||||
{
|
||||
if ( sid.segment_index + 2 != geometry::num_points(geometry) )
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( BoundaryQuery == boundary_any )
|
||||
{
|
||||
if ( sid.segment_index != 0 && sid.segment_index + 2 != geometry::num_points(geometry) )
|
||||
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 )
|
||||
typedef typename boost::range_iterator<Linestring const>::type iterator;
|
||||
iterator first = boost::begin(ls);
|
||||
++first;
|
||||
iterator last = boost::end(ls);
|
||||
--last;
|
||||
for ( iterator it = first ; it != last ; ++it )
|
||||
{
|
||||
// point - no boundary
|
||||
if ( boost::size(*it) < 2 )
|
||||
continue;
|
||||
|
||||
// TODO: handle also linestrings with points_num == 2 and equals(front, back) - treat like point?
|
||||
|
||||
boundary_points.push_back(range::front(*it));
|
||||
boundary_points.push_back(range::back(*it));
|
||||
if ( !equals::equals_point_point(range::front(ls), *it) )
|
||||
return linestring_closed;
|
||||
}
|
||||
|
||||
std::sort(boundary_points.begin(), boundary_points.end(), geometry::less<point_type>());
|
||||
return linestring_point;
|
||||
}
|
||||
else
|
||||
return linestring_open;
|
||||
}
|
||||
}
|
||||
|
||||
is_filled = true;
|
||||
// TODO:
|
||||
// For 1-point linestrings or with all equal points turns won't be generated!
|
||||
// Check for those degenerated cases may be connected with this one!
|
||||
|
||||
template <std::size_t OpId,
|
||||
typename Geometry,
|
||||
typename Tag = typename geometry::tag<Geometry>::type>
|
||||
struct for_each_disjoint_linestring_if {};
|
||||
|
||||
template <std::size_t OpId, typename Geometry>
|
||||
struct for_each_disjoint_linestring_if<OpId, Geometry, linestring_tag>
|
||||
{
|
||||
template <typename TurnIt, typename Pred>
|
||||
static inline bool apply(TurnIt first, TurnIt last,
|
||||
Geometry const& geometry,
|
||||
Pred & pred)
|
||||
{
|
||||
if ( first != last )
|
||||
return false;
|
||||
pred(geometry);
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
template <std::size_t OpId, typename Geometry>
|
||||
struct for_each_disjoint_linestring_if<OpId, Geometry, multi_linestring_tag>
|
||||
{
|
||||
template <typename TurnIt, typename Pred>
|
||||
static inline bool apply(TurnIt first, TurnIt last,
|
||||
Geometry const& geometry,
|
||||
Pred & pred)
|
||||
{
|
||||
BOOST_ASSERT(first != last);
|
||||
|
||||
std::size_t count = boost::size(geometry);
|
||||
std::vector<bool> detected_intersections(count, false);
|
||||
for ( TurnIt it = first ; it != last ; ++it )
|
||||
{
|
||||
int multi_index = it->operations[OpId].seg_id.multi_index;
|
||||
BOOST_ASSERT(multi_index >= 0);
|
||||
std::size_t index = static_cast<std::size_t>(multi_index);
|
||||
BOOST_ASSERT(index < count);
|
||||
detected_intersections[index] = true;
|
||||
}
|
||||
|
||||
std::size_t equal_points_count
|
||||
= boost::size(
|
||||
std::equal_range(boundary_points.begin(),
|
||||
boundary_points.end(),
|
||||
pt,
|
||||
geometry::less<point_type>())
|
||||
);
|
||||
bool found = false;
|
||||
|
||||
return equal_points_count % 2 != 0 && equal_points_count > 0; // the number is odd and > 0
|
||||
|
||||
for ( std::vector<bool>::iterator it = detected_intersections.begin() ;
|
||||
it != detected_intersections.end() ; ++it )
|
||||
{
|
||||
// if there were no intersections for this multi_index
|
||||
if ( *it == false )
|
||||
{
|
||||
found = true;
|
||||
bool cont = pred(
|
||||
*(boost::begin(geometry)
|
||||
+ std::distance(detected_intersections.begin(), it)));
|
||||
if ( !cont )
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return found;
|
||||
}
|
||||
};
|
||||
|
||||
// Called in a loop for:
|
||||
// Ls/Ls - worst O(N) - 1x point_in_geometry(MLs)
|
||||
// Ls/MLs - worst O(N) - 1x point_in_geometry(MLs)
|
||||
// MLs/Ls - worst O(N^2) - Bx point_in_geometry(Ls)
|
||||
// MLs/MLs - worst O(N^2) - Bx point_in_geometry(Ls)
|
||||
// TODO: later use spatial index
|
||||
template <std::size_t OpId, typename BoundaryChecker, typename OtherGeometry>
|
||||
class disjoint_linestring_pred
|
||||
{
|
||||
static const bool transpose_result = OpId != 0;
|
||||
|
||||
public:
|
||||
disjoint_linestring_pred(result & res, BoundaryChecker & boundary_checker, OtherGeometry const& other_geometry)
|
||||
: m_result_ptr(boost::addressof(res))
|
||||
, m_boundary_checker_ptr(boost::addressof(boundary_checker))
|
||||
, m_other_geometry(boost::addressof(other_geometry))
|
||||
, m_detected_mask_point(0)
|
||||
, m_detected_open_boundary(false)
|
||||
{}
|
||||
|
||||
template <typename Linestring>
|
||||
bool operator()(Linestring const& linestring)
|
||||
{
|
||||
linestring_kind lk = check_linestring_kind(linestring);
|
||||
|
||||
if ( lk == linestring_point ) // just an optimization
|
||||
{
|
||||
if ( m_detected_mask_point != 7 )
|
||||
{
|
||||
// check the relation
|
||||
int pig = within::point_in_geometry(range::front(linestring), *m_other_geometry);
|
||||
|
||||
// point inside
|
||||
if ( pig > 0 )
|
||||
{
|
||||
update<interior, interior, '0', transpose_result>(*m_result_ptr);
|
||||
m_detected_mask_point |= 1;
|
||||
}
|
||||
// point on boundary
|
||||
else if ( pig == 0 )
|
||||
{
|
||||
update<interior, boundary, '0', transpose_result>(*m_result_ptr);
|
||||
m_detected_mask_point |= 2;
|
||||
}
|
||||
// point outside
|
||||
else
|
||||
{
|
||||
update<interior, exterior, '0', transpose_result>(*m_result_ptr);
|
||||
m_detected_mask_point |= 4;
|
||||
}
|
||||
}
|
||||
}
|
||||
// NOTE: For closed Linestrings I/I=1 could be set automatically
|
||||
// but for MultiLinestrings endpoints of closed Linestrings must also be checked for boundary
|
||||
else if ( lk == linestring_open || lk == linestring_closed )
|
||||
{
|
||||
if ( !m_detected_open_boundary ) // just an optimization
|
||||
{
|
||||
update<interior, exterior, '1', transpose_result>(*m_result_ptr);
|
||||
|
||||
// check if there is a boundary
|
||||
if ( m_boundary_checker_ptr->template
|
||||
is_endpoint_boundary<boundary_front>(range::front(linestring))
|
||||
|| m_boundary_checker_ptr->template
|
||||
is_endpoint_boundary<boundary_back>(range::back(linestring)) )
|
||||
{
|
||||
update<boundary, exterior, '0', transpose_result>(*m_result_ptr);
|
||||
|
||||
m_detected_open_boundary = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool all_detected = m_detected_mask_point == 7 && m_detected_open_boundary;
|
||||
return !all_detected && !m_result_ptr->interrupt;
|
||||
}
|
||||
|
||||
private:
|
||||
bool is_filled;
|
||||
// TODO: store references/pointers instead of points?
|
||||
std::vector<point_type> boundary_points;
|
||||
Geometry const& geometry;
|
||||
result * m_result_ptr;
|
||||
BoundaryChecker * m_boundary_checker_ptr;
|
||||
const OtherGeometry * m_other_geometry;
|
||||
char m_detected_mask_point;
|
||||
bool m_detected_open_boundary;
|
||||
};
|
||||
|
||||
// currently works only for linestrings
|
||||
@@ -200,44 +221,8 @@ struct linear_linear
|
||||
|
||||
static inline result apply(Geometry1 const& geometry1, Geometry2 const& geometry2)
|
||||
{
|
||||
// TODO: currently this only works for linestrings
|
||||
std::size_t s1 = boost::size(geometry1);
|
||||
std::size_t s2 = boost::size(geometry2);
|
||||
if ( s1 == 0 || s2 == 0 )
|
||||
{
|
||||
// throw on empty output?
|
||||
return result("FFFFFFFFF");
|
||||
}
|
||||
else if ( s1 == 1 && s2 == 1 )
|
||||
{
|
||||
// TODO : not working for MultiLinestrings
|
||||
// return point_point<point1_type, point2_type>::apply(range::front(geometry1), range::front(geometry2));
|
||||
BOOST_ASSERT(false);
|
||||
}
|
||||
else if ( s1 == 1 /*&& s2 > 1*/ )
|
||||
{
|
||||
// TODO : not working for MultiLinestrings
|
||||
// return point_geometry<point1_type, Geometry2>::apply(range::front(geometry1), geometry2);
|
||||
BOOST_ASSERT(false);
|
||||
}
|
||||
else if ( s2 == 1 /*&& s1 > 1*/ )
|
||||
{
|
||||
// TODO : not working for MultiLinestrings
|
||||
// return geometry_point<Geometry2, point2_type>::apply(geometry1, range::front(geometry2));
|
||||
BOOST_ASSERT(false);
|
||||
}
|
||||
|
||||
// TODO: handle also linestrings with points_num == 2 and equals(front, back) - treat like point?
|
||||
|
||||
result res("FFFFFFFFT");
|
||||
static const std::size_t dimension = geometry::dimension<Geometry1>::value;
|
||||
if ( dimension < 10 )
|
||||
res.template set<exterior, exterior, '0' + dimension>();
|
||||
|
||||
// TEMP
|
||||
//bool has_boundary1 = ! detail::equals::equals_point_point(range::front(geometry1), range::back(geometry1));
|
||||
//bool has_boundary2 = ! detail::equals::equals_point_point(range::front(geometry2), range::back(geometry2));
|
||||
//handle_boundaries(res, geometry1, geometry2, has_boundary1, has_boundary2);
|
||||
result res; // FFFFFFFFF
|
||||
set<exterior, exterior, result_dimension<Geometry1>::value>(res);// FFFFFFFFd, d in [1,9] or T
|
||||
|
||||
// get and analyse turns
|
||||
typedef typename turns::get_turns<Geometry1, Geometry2>::turn_info turn_type;
|
||||
@@ -246,13 +231,20 @@ struct linear_linear
|
||||
|
||||
turns::get_turns<Geometry1, Geometry2>::apply(turns, geometry1, geometry2);
|
||||
|
||||
if ( turns.empty() )
|
||||
{
|
||||
return res;
|
||||
}
|
||||
|
||||
boundary_checker<Geometry1> boundary_checker1(geometry1);
|
||||
disjoint_linestring_pred<0, boundary_checker<Geometry1>, Geometry2> pred1(res, boundary_checker1, geometry2);
|
||||
for_each_disjoint_linestring_if<0, Geometry1>::apply(turns.begin(), turns.end(), geometry1, pred1);
|
||||
if ( res.interrupt )
|
||||
return res;
|
||||
|
||||
boundary_checker<Geometry2> boundary_checker2(geometry2);
|
||||
disjoint_linestring_pred<1, boundary_checker<Geometry2>, Geometry1> pred2(res, boundary_checker2, geometry1);
|
||||
for_each_disjoint_linestring_if<1, Geometry2>::apply(turns.begin(), turns.end(), geometry2, pred2);
|
||||
if ( res.interrupt )
|
||||
return res;
|
||||
|
||||
if ( turns.empty() )
|
||||
return res;
|
||||
|
||||
// TODO: turns must be sorted and followed only if it's possible to go out and in on the same point
|
||||
// for linear geometries union operation must be detected which I guess would be quite often
|
||||
@@ -266,6 +258,9 @@ struct linear_linear
|
||||
geometry1, geometry2,
|
||||
boundary_checker1, boundary_checker2);
|
||||
}
|
||||
|
||||
if ( res.interrupt )
|
||||
return res;
|
||||
|
||||
{
|
||||
std::sort(turns.begin(), turns.end(), turns::less_seg_dist_op<0,2,3,1,4,0,1>());
|
||||
@@ -428,7 +423,7 @@ struct linear_linear
|
||||
{
|
||||
static const std::size_t op_id = OpId;
|
||||
static const std::size_t other_op_id = (OpId + 1) % 2;
|
||||
static const bool reverse_result = OpId != 0;
|
||||
static const bool transpose_result = OpId != 0;
|
||||
|
||||
public:
|
||||
turns_analyser()
|
||||
@@ -474,7 +469,7 @@ struct linear_linear
|
||||
m_exit_watcher.reset_detected_exit();
|
||||
|
||||
// not the last IP
|
||||
update_result<interior, exterior, '1', reverse_result>(res);
|
||||
update<interior, exterior, '1', transpose_result>(res);
|
||||
}
|
||||
// fake exit point, reset state
|
||||
// in reality this will be op == overlay::operation_intersection
|
||||
@@ -495,11 +490,10 @@ struct linear_linear
|
||||
segment_identifier const& prev_seg_id = prev->operations[op_id].seg_id;
|
||||
|
||||
// if there is a boundary on the last point
|
||||
if ( boost::size(sub_geometry::get(geometry, prev_seg_id)) > 1
|
||||
&& boundary_checker.template is_boundary<boundary_back_explicit>
|
||||
(range::back(sub_geometry::get(geometry, prev_seg_id)), prev_seg_id) )
|
||||
if ( boundary_checker.template is_endpoint_boundary<boundary_back>
|
||||
(range::back(sub_geometry::get(geometry, prev_seg_id))) )
|
||||
{
|
||||
update_result<boundary, exterior, '0', reverse_result>(res);
|
||||
update<boundary, exterior, '0', transpose_result>(res);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -512,23 +506,23 @@ struct linear_linear
|
||||
bool was_outside = m_exit_watcher.enter(it->point, other_id);
|
||||
|
||||
// interiors overlaps
|
||||
update_result<interior, interior, '1', reverse_result>(res);
|
||||
update<interior, interior, '1', transpose_result>(res);
|
||||
|
||||
// going inside on boundary point
|
||||
if ( boundary_checker.template is_boundary<boundary_front>(it->point, seg_id) )
|
||||
{
|
||||
bool other_b =
|
||||
it->operations[other_op_id].operation == overlay::operation_blocked ?
|
||||
other_boundary_checker.template is_boundary<boundary_back_explicit>(it->point, other_id) :
|
||||
other_boundary_checker.template is_endpoint_boundary<boundary_back>(it->point) :
|
||||
other_boundary_checker.template is_boundary<boundary_any>(it->point, other_id);
|
||||
// it's also the boundary of the other geometry
|
||||
if ( other_b )
|
||||
{
|
||||
update_result<boundary, boundary, '0', reverse_result>(res);
|
||||
update<boundary, boundary, '0', transpose_result>(res);
|
||||
}
|
||||
else
|
||||
{
|
||||
update_result<boundary, interior, '0', reverse_result>(res);
|
||||
update<boundary, interior, '0', transpose_result>(res);
|
||||
}
|
||||
}
|
||||
// going inside on non-boundary point
|
||||
@@ -537,16 +531,16 @@ struct linear_linear
|
||||
// if we didn't enter in the past, we were outside
|
||||
if ( was_outside && !fake_enter_detected )
|
||||
{
|
||||
update_result<interior, exterior, '1', reverse_result>(res);
|
||||
update<interior, exterior, '1', transpose_result>(res);
|
||||
|
||||
// if it's the first IP then the first point is outside
|
||||
if ( first_in_range )
|
||||
{
|
||||
// if there is a boundary on the first point
|
||||
if ( boundary_checker.template is_boundary<boundary_front_explicit>
|
||||
(range::front(sub_geometry::get(geometry, seg_id)), seg_id) )
|
||||
if ( boundary_checker.template is_endpoint_boundary<boundary_front>
|
||||
(range::front(sub_geometry::get(geometry, seg_id))) )
|
||||
{
|
||||
update_result<boundary, exterior, '0', reverse_result>(res);
|
||||
update<boundary, exterior, '0', transpose_result>(res);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -564,20 +558,20 @@ struct linear_linear
|
||||
if ( op_blocked )
|
||||
{
|
||||
// check if this is indeed the boundary point
|
||||
if ( boundary_checker.template is_boundary<boundary_back_explicit>(it->point, seg_id) )
|
||||
if ( boundary_checker.template is_endpoint_boundary<boundary_back>(it->point) )
|
||||
{
|
||||
bool other_b =
|
||||
it->operations[other_op_id].operation == overlay::operation_blocked ?
|
||||
other_boundary_checker.template is_boundary<boundary_back_explicit>(it->point, other_id) :
|
||||
other_boundary_checker.template is_endpoint_boundary<boundary_back>(it->point) :
|
||||
other_boundary_checker.template is_boundary<boundary_any>(it->point, other_id);
|
||||
// it's also the boundary of the other geometry
|
||||
if ( other_b )
|
||||
{
|
||||
update_result<boundary, boundary, '0', reverse_result>(res);
|
||||
update<boundary, boundary, '0', transpose_result>(res);
|
||||
}
|
||||
else
|
||||
{
|
||||
update_result<boundary, interior, '0', reverse_result>(res);
|
||||
update<boundary, interior, '0', transpose_result>(res);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -585,21 +579,21 @@ struct linear_linear
|
||||
// we're outside
|
||||
else
|
||||
{
|
||||
update_result<interior, exterior, '1', reverse_result>(res);
|
||||
update<interior, exterior, '1', transpose_result>(res);
|
||||
|
||||
// boundaries don't overlap - just an optimization
|
||||
if ( it->method == overlay::method_crosses )
|
||||
{
|
||||
update_result<interior, interior, '0', reverse_result>(res);
|
||||
update<interior, interior, '0', transpose_result>(res);
|
||||
|
||||
// it's the first point in range
|
||||
if ( first_in_range )
|
||||
{
|
||||
// if there is a boundary on the first point
|
||||
if ( boundary_checker.template is_boundary<boundary_front_explicit>
|
||||
(range::front(sub_geometry::get(geometry, seg_id)), seg_id) )
|
||||
if ( boundary_checker.template is_endpoint_boundary<boundary_front>
|
||||
(range::front(sub_geometry::get(geometry, seg_id))) )
|
||||
{
|
||||
update_result<boundary, exterior, '0', reverse_result>(res);
|
||||
update<boundary, exterior, '0', transpose_result>(res);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -608,7 +602,7 @@ struct linear_linear
|
||||
{
|
||||
bool this_b =
|
||||
op_blocked ?
|
||||
boundary_checker.template is_boundary<boundary_back_explicit>(it->point, seg_id) :
|
||||
boundary_checker.template is_endpoint_boundary<boundary_back>(it->point) :
|
||||
boundary_checker.template is_boundary<boundary_front>(it->point, seg_id);
|
||||
|
||||
// if current IP is on boundary of the geometry
|
||||
@@ -616,41 +610,41 @@ struct linear_linear
|
||||
{
|
||||
bool other_b =
|
||||
it->operations[other_op_id].operation == overlay::operation_blocked ?
|
||||
other_boundary_checker.template is_boundary<boundary_back_explicit>(it->point, other_id) :
|
||||
other_boundary_checker.template is_endpoint_boundary<boundary_back>(it->point) :
|
||||
other_boundary_checker.template is_boundary<boundary_any>(it->point, other_id);
|
||||
// it's also the boundary of the other geometry
|
||||
if ( other_b )
|
||||
{
|
||||
update_result<boundary, boundary, '0', reverse_result>(res);
|
||||
update<boundary, boundary, '0', transpose_result>(res);
|
||||
}
|
||||
else
|
||||
{
|
||||
update_result<boundary, interior, '0', reverse_result>(res);
|
||||
update<boundary, interior, '0', transpose_result>(res);
|
||||
}
|
||||
|
||||
// first IP on the last segment point - this means that the first point is outside
|
||||
if ( first_in_range && op_blocked )
|
||||
{
|
||||
// if there is a boundary on the first point
|
||||
if ( boundary_checker.template is_boundary<boundary_front_explicit>
|
||||
(range::front(sub_geometry::get(geometry, seg_id)), seg_id) )
|
||||
if ( boundary_checker.template is_endpoint_boundary<boundary_front>
|
||||
(range::front(sub_geometry::get(geometry, seg_id))) )
|
||||
{
|
||||
update_result<boundary, exterior, '0', reverse_result>(res);
|
||||
update<boundary, exterior, '0', transpose_result>(res);
|
||||
}
|
||||
}
|
||||
}
|
||||
// boundaries don't overlap
|
||||
else
|
||||
{
|
||||
update_result<interior, interior, '0', reverse_result>(res);
|
||||
update<interior, interior, '0', transpose_result>(res);
|
||||
|
||||
if ( first_in_range )
|
||||
{
|
||||
// if there is a boundary on the first point
|
||||
if ( boundary_checker.template is_boundary<boundary_front_explicit>
|
||||
(range::front(sub_geometry::get(geometry, seg_id)), seg_id) )
|
||||
if ( boundary_checker.template is_endpoint_boundary<boundary_front>
|
||||
(range::front(sub_geometry::get(geometry, seg_id))) )
|
||||
{
|
||||
update_result<boundary, exterior, '0', reverse_result>(res);
|
||||
update<boundary, exterior, '0', transpose_result>(res);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -667,7 +661,7 @@ struct linear_linear
|
||||
|| m_last_union )
|
||||
{
|
||||
// for sure
|
||||
update_result<interior, exterior, '1', reverse_result>(res);
|
||||
update<interior, exterior, '1', transpose_result>(res);
|
||||
|
||||
BOOST_ASSERT(first != last);
|
||||
// TODO: ERROR!
|
||||
@@ -675,13 +669,12 @@ struct linear_linear
|
||||
TurnIt prev = last;
|
||||
--prev;
|
||||
segment_identifier const& prev_seg_id = prev->operations[OpId].seg_id;
|
||||
|
||||
|
||||
// if there is a boundary on the last point
|
||||
if ( boost::size(sub_geometry::get(geometry, prev_seg_id)) > 1
|
||||
&& boundary_checker.template is_boundary<boundary_back_explicit>
|
||||
(range::back(sub_geometry::get(geometry, prev_seg_id)), prev_seg_id) )
|
||||
if ( boundary_checker.template is_endpoint_boundary<boundary_back>
|
||||
(range::back(sub_geometry::get(geometry, prev_seg_id))) )
|
||||
{
|
||||
update_result<boundary, exterior, '0', reverse_result>(res);
|
||||
update<boundary, exterior, '0', transpose_result>(res);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -715,6 +708,9 @@ struct linear_linear
|
||||
analyser.apply(res, first, it, last,
|
||||
geometry, other_geometry,
|
||||
boundary_checker, other_boundary_checker);
|
||||
|
||||
if ( res.interrupt )
|
||||
return;
|
||||
}
|
||||
|
||||
analyser.apply(res, first, last, last,
|
||||
|
||||
@@ -14,8 +14,8 @@
|
||||
|
||||
#include <boost/geometry/algorithms/detail/disjoint/point_point.hpp> // later change to equal/point_point.hpp
|
||||
#include <boost/geometry/algorithms/detail/within/point_in_geometry.hpp>
|
||||
#include <boost/geometry/algorithms/within.hpp>
|
||||
#include <boost/geometry/algorithms/covered_by.hpp>
|
||||
//#include <boost/geometry/algorithms/within.hpp>
|
||||
//#include <boost/geometry/algorithms/covered_by.hpp>
|
||||
|
||||
#include <boost/geometry/algorithms/detail/relate/result.hpp>
|
||||
|
||||
@@ -30,104 +30,22 @@ struct point_point
|
||||
{
|
||||
static inline result apply(Point1 const& point1, Point2 const& point2)
|
||||
{
|
||||
result res;
|
||||
|
||||
bool equal = detail::equals::equals_point_point(point1, point2);
|
||||
|
||||
if ( equal )
|
||||
return result("0FFFFFFFT");
|
||||
{
|
||||
set<interior, interior, '0'>(res);
|
||||
set<exterior, exterior, result_dimension<Point1>::value>(res);
|
||||
}
|
||||
else
|
||||
return result("FF0FFF0FT");
|
||||
}
|
||||
};
|
||||
|
||||
// NOTE: Those tests should be consistent with within(Point, Box) and covered_by(Point, Box)
|
||||
// There is no EPS used in those functions, values are compared using < or <=
|
||||
// so comparing MIN and MAX in the same way should be fine
|
||||
|
||||
template <typename Box, std::size_t I = 0, std::size_t D = geometry::dimension<Box>::value>
|
||||
struct box_has_interior
|
||||
{
|
||||
static inline bool apply(Box const& box)
|
||||
{
|
||||
return geometry::get<min_corner, I>(box) < geometry::get<max_corner, I>(box)
|
||||
&& box_has_interior<Box, I + 1, D>::apply(box);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename Box, std::size_t D>
|
||||
struct box_has_interior<Box, D, D>
|
||||
{
|
||||
static inline bool apply(Box const&) { return true; }
|
||||
};
|
||||
|
||||
// NOTE: especially important here (see the NOTE above).
|
||||
|
||||
template <typename Box, std::size_t I = 0, std::size_t D = geometry::dimension<Box>::value>
|
||||
struct box_has_equal_min_max
|
||||
{
|
||||
static inline bool apply(Box const& box)
|
||||
{
|
||||
return geometry::get<min_corner, I>(box) == geometry::get<max_corner, I>(box)
|
||||
&& box_has_equal_min_max<Box, I + 1, D>::apply(box);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename Box, std::size_t D>
|
||||
struct box_has_equal_min_max<Box, D, D>
|
||||
{
|
||||
static inline bool apply(Box const&) { return true; }
|
||||
};
|
||||
|
||||
template <typename Point, typename Box>
|
||||
struct point_box
|
||||
{
|
||||
static inline result apply(Point const& point, Box const& box)
|
||||
{
|
||||
if ( geometry::within(point, box) ) // this also means that the box has interior
|
||||
{
|
||||
return result("0FFFFFTTT");
|
||||
set<interior, exterior, '0'>(res);
|
||||
set<exterior, interior, '0'>(res);
|
||||
set<exterior, exterior, result_dimension<Point1>::value>(res);
|
||||
}
|
||||
else if ( geometry::covered_by(point, box) ) // point is on the boundary
|
||||
{
|
||||
//if ( box_has_interior<Box>::apply(box) )
|
||||
//{
|
||||
// return result("F0FFFFTTT");
|
||||
//}
|
||||
//else if ( box_has_equal_min_max<Box>::apply(box) ) // no boundary outside point
|
||||
//{
|
||||
// return result("F0FFFFFFT");
|
||||
//}
|
||||
//else // no interior outside point
|
||||
//{
|
||||
// return result("F0FFFFFTT");
|
||||
//}
|
||||
return result("F0FFFF**T");
|
||||
}
|
||||
else
|
||||
{
|
||||
/*if ( box_has_interior<Box>::apply(box) )
|
||||
{
|
||||
return result("FF0FFFTTT");
|
||||
}
|
||||
else
|
||||
{
|
||||
return result("FF0FFFFTT");
|
||||
}*/
|
||||
return result("FF0FFF*TT");
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
template <typename Box, typename Point>
|
||||
struct box_point
|
||||
{
|
||||
static inline result apply(Box const& box, Point const& point)
|
||||
{
|
||||
if ( geometry::within(point, box) )
|
||||
return result("0FTFFTFFT");
|
||||
else if ( geometry::covered_by(point, box) )
|
||||
return result("FF*0F*FFT");
|
||||
else
|
||||
return result("FF*FFT0FT");
|
||||
return res;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -137,17 +55,31 @@ struct point_geometry
|
||||
{
|
||||
static inline result apply(Point const& point, Geometry const& geometry)
|
||||
{
|
||||
result res;
|
||||
|
||||
int pig = detail::within::point_in_geometry(point, geometry);
|
||||
|
||||
// TODO: * - if geometry has interior and/or boundary
|
||||
// e.g. isn't 1-point linestring or linear ring or 0-area polygon
|
||||
|
||||
if ( pig < 0 ) // not within
|
||||
return result("FF0FFF**T");
|
||||
if ( pig > 0 ) // within
|
||||
{
|
||||
set<interior, interior, '0'>(res);
|
||||
}
|
||||
else if ( pig == 0 )
|
||||
return result("F0FFFF**T");
|
||||
else // pig > 0 - within
|
||||
return result("0FFFFF**T");
|
||||
{
|
||||
set<interior, boundary, '0'>(res);
|
||||
}
|
||||
else // pig < 0 - not within
|
||||
{
|
||||
set<interior, exterior, '0'>(res);
|
||||
}
|
||||
|
||||
set<exterior, interior, '*'>(res); // TODO
|
||||
set<exterior, boundary, '*'>(res); // TODO
|
||||
set<exterior, exterior, result_dimension<Point>::value>(res);
|
||||
|
||||
return res;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -157,20 +89,132 @@ struct geometry_point
|
||||
{
|
||||
static inline result apply(Geometry const& geometry, Point const& point)
|
||||
{
|
||||
result res;
|
||||
|
||||
int pig = detail::within::point_in_geometry(point, geometry);
|
||||
|
||||
// TODO: * - if geometry has interior and/or boundary
|
||||
// e.g. isn't 1-point linestring or linear ring or 0-area polygon
|
||||
|
||||
if ( pig < 0 ) // not within
|
||||
return result("FF*FF*0FT");
|
||||
if ( pig > 0 ) // within
|
||||
{
|
||||
set<interior, interior, '0'>(res);
|
||||
}
|
||||
else if ( pig == 0 )
|
||||
return result("FF*0F*FFT");
|
||||
else // pig > 0 - within
|
||||
return result("0F*FF*FFT");
|
||||
{
|
||||
set<boundary, interior, '0'>(res);
|
||||
}
|
||||
else // pig < 0 - not within
|
||||
{
|
||||
set<exterior, interior, '0'>(res);
|
||||
}
|
||||
|
||||
set<interior, exterior, '*'>(res); // TODO
|
||||
set<boundary, exterior, '*'>(res); // TODO
|
||||
set<exterior, exterior, result_dimension<Point>::value>(res);
|
||||
|
||||
return res;
|
||||
}
|
||||
};
|
||||
|
||||
// TODO: rewrite the folowing:
|
||||
|
||||
//// NOTE: Those tests should be consistent with within(Point, Box) and covered_by(Point, Box)
|
||||
//// There is no EPS used in those functions, values are compared using < or <=
|
||||
//// so comparing MIN and MAX in the same way should be fine
|
||||
//
|
||||
//template <typename Box, std::size_t I = 0, std::size_t D = geometry::dimension<Box>::value>
|
||||
//struct box_has_interior
|
||||
//{
|
||||
// static inline bool apply(Box const& box)
|
||||
// {
|
||||
// return geometry::get<min_corner, I>(box) < geometry::get<max_corner, I>(box)
|
||||
// && box_has_interior<Box, I + 1, D>::apply(box);
|
||||
// }
|
||||
//};
|
||||
//
|
||||
//template <typename Box, std::size_t D>
|
||||
//struct box_has_interior<Box, D, D>
|
||||
//{
|
||||
// static inline bool apply(Box const&) { return true; }
|
||||
//};
|
||||
//
|
||||
//// NOTE: especially important here (see the NOTE above).
|
||||
//
|
||||
//template <typename Box, std::size_t I = 0, std::size_t D = geometry::dimension<Box>::value>
|
||||
//struct box_has_equal_min_max
|
||||
//{
|
||||
// static inline bool apply(Box const& box)
|
||||
// {
|
||||
// return geometry::get<min_corner, I>(box) == geometry::get<max_corner, I>(box)
|
||||
// && box_has_equal_min_max<Box, I + 1, D>::apply(box);
|
||||
// }
|
||||
//};
|
||||
//
|
||||
//template <typename Box, std::size_t D>
|
||||
//struct box_has_equal_min_max<Box, D, D>
|
||||
//{
|
||||
// static inline bool apply(Box const&) { return true; }
|
||||
//};
|
||||
//
|
||||
//template <typename Point, typename Box>
|
||||
//struct point_box
|
||||
//{
|
||||
// static inline result apply(Point const& point, Box const& box)
|
||||
// {
|
||||
// result res;
|
||||
//
|
||||
// if ( geometry::within(point, box) ) // this also means that the box has interior
|
||||
// {
|
||||
// return result("0FFFFFTTT");
|
||||
// }
|
||||
// else if ( geometry::covered_by(point, box) ) // point is on the boundary
|
||||
// {
|
||||
// //if ( box_has_interior<Box>::apply(box) )
|
||||
// //{
|
||||
// // return result("F0FFFFTTT");
|
||||
// //}
|
||||
// //else if ( box_has_equal_min_max<Box>::apply(box) ) // no boundary outside point
|
||||
// //{
|
||||
// // return result("F0FFFFFFT");
|
||||
// //}
|
||||
// //else // no interior outside point
|
||||
// //{
|
||||
// // return result("F0FFFFFTT");
|
||||
// //}
|
||||
// return result("F0FFFF**T");
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// /*if ( box_has_interior<Box>::apply(box) )
|
||||
// {
|
||||
// return result("FF0FFFTTT");
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// return result("FF0FFFFTT");
|
||||
// }*/
|
||||
// return result("FF0FFF*TT");
|
||||
// }
|
||||
//
|
||||
// return res;
|
||||
// }
|
||||
//};
|
||||
//
|
||||
//template <typename Box, typename Point>
|
||||
//struct box_point
|
||||
//{
|
||||
// static inline result apply(Box const& box, Point const& point)
|
||||
// {
|
||||
// if ( geometry::within(point, box) )
|
||||
// return result("0FTFFTFFT");
|
||||
// else if ( geometry::covered_by(point, box) )
|
||||
// return result("FF*0F*FFT");
|
||||
// else
|
||||
// return result("FF*FFT0FT");
|
||||
// }
|
||||
//};
|
||||
|
||||
}} // namespace detail::relate
|
||||
#endif // DOXYGEN_NO_DETAIL
|
||||
|
||||
|
||||
@@ -62,15 +62,15 @@ struct relate<Point1, Point2, point_tag, point_tag>
|
||||
: detail::relate::point_point<Point1, Point2>
|
||||
{};
|
||||
|
||||
template <typename Point, typename Box>
|
||||
struct relate<Point, Box, point_tag, box_tag>
|
||||
: detail::relate::point_box<Point, Box>
|
||||
{};
|
||||
|
||||
template <typename Box, typename Point>
|
||||
struct relate<Box, Point, box_tag, point_tag>
|
||||
: detail::relate::box_point<Box, Point>
|
||||
{};
|
||||
//template <typename Point, typename Box>
|
||||
//struct relate<Point, Box, point_tag, box_tag>
|
||||
// : detail::relate::point_box<Point, Box>
|
||||
//{};
|
||||
//
|
||||
//template <typename Box, typename Point>
|
||||
//struct relate<Box, Point, box_tag, point_tag>
|
||||
// : detail::relate::box_point<Box, Point>
|
||||
//{};
|
||||
|
||||
template <typename Point, typename Geometry, typename Tag2>
|
||||
struct relate<Point, Geometry, point_tag, Tag2>
|
||||
@@ -92,6 +92,16 @@ struct relate<Linestring, MultiLinestring, linestring_tag, multi_linestring_tag>
|
||||
: detail::relate::linear_linear<Linestring, MultiLinestring>
|
||||
{};
|
||||
|
||||
template <typename MultiLinestring, typename Linestring>
|
||||
struct relate<MultiLinestring, Linestring, multi_linestring_tag, linestring_tag>
|
||||
: detail::relate::linear_linear<MultiLinestring, Linestring>
|
||||
{};
|
||||
|
||||
template <typename MultiLinestring1, typename MultiLinestring2>
|
||||
struct relate<MultiLinestring1, MultiLinestring2, multi_linestring_tag, multi_linestring_tag>
|
||||
: detail::relate::linear_linear<MultiLinestring1, MultiLinestring2>
|
||||
{};
|
||||
|
||||
}} // namespace detail_dispatch::relate
|
||||
|
||||
namespace detail { namespace relate {
|
||||
|
||||
@@ -23,58 +23,122 @@ enum field { interior = 0, boundary = 1, exterior = 2 };
|
||||
class result
|
||||
{
|
||||
public:
|
||||
result()
|
||||
{
|
||||
set('F');
|
||||
}
|
||||
|
||||
result(const char * str)
|
||||
static const bool interrupt = false;
|
||||
|
||||
inline result()
|
||||
{
|
||||
::memcpy(array, str, 9);
|
||||
::memset(array, 'F', 9);
|
||||
}
|
||||
|
||||
template <field F1, field F2>
|
||||
char get() const
|
||||
inline char get() const
|
||||
{
|
||||
return array[F1 * 3 + F2];
|
||||
}
|
||||
|
||||
template <field F1, field F2, char V>
|
||||
void set()
|
||||
inline void set()
|
||||
{
|
||||
array[F1 * 3 + F2] = V;
|
||||
}
|
||||
|
||||
template <field F1, field F2, char D>
|
||||
void update()
|
||||
{
|
||||
BOOST_STATIC_ASSERT('0' <= D && D <= '9');
|
||||
char * c = array + F1 * 3 + F2;
|
||||
if ( D > *c || *c > '9')
|
||||
*c = D;
|
||||
}
|
||||
|
||||
void set(char v)
|
||||
{
|
||||
::memset(array, v, 9);
|
||||
}
|
||||
|
||||
std::pair<const char*, const char*> get_code() const
|
||||
inline std::pair<const char*, const char*> get_code() const
|
||||
{
|
||||
return std::make_pair(array, array+9);
|
||||
}
|
||||
|
||||
void transpose()
|
||||
{
|
||||
std::swap(array[1], array[3]);
|
||||
std::swap(array[2], array[6]);
|
||||
std::swap(array[5], array[7]);
|
||||
}
|
||||
|
||||
private:
|
||||
char array[9];
|
||||
};
|
||||
|
||||
template <field F1, field F2, char V, typename Result>
|
||||
inline void set(Result & res)
|
||||
{
|
||||
res.template set<F1, F2, V>();
|
||||
}
|
||||
|
||||
template <char V, typename Result>
|
||||
inline void set(Result & res)
|
||||
{
|
||||
res.template set<interior, interior, V>();
|
||||
res.template set<interior, boundary, V>();
|
||||
res.template set<interior, exterior, V>();
|
||||
res.template set<boundary, interior, V>();
|
||||
res.template set<boundary, boundary, V>();
|
||||
res.template set<boundary, exterior, V>();
|
||||
res.template set<exterior, interior, V>();
|
||||
res.template set<exterior, boundary, V>();
|
||||
res.template set<exterior, exterior, V>();
|
||||
}
|
||||
|
||||
template <char II, char IB, char IE, char BI, char BB, char BE, char EI, char EB, char EE, typename Result>
|
||||
inline void set(Result & res)
|
||||
{
|
||||
res.template set<interior, interior, II>();
|
||||
res.template set<interior, boundary, IB>();
|
||||
res.template set<interior, exterior, IE>();
|
||||
res.template set<boundary, interior, BI>();
|
||||
res.template set<boundary, boundary, BB>();
|
||||
res.template set<boundary, exterior, BE>();
|
||||
res.template set<exterior, interior, EI>();
|
||||
res.template set<exterior, boundary, EB>();
|
||||
res.template set<exterior, exterior, EE>();
|
||||
}
|
||||
|
||||
template <field F1, field F2, char D, typename Result>
|
||||
inline void update(Result & res)
|
||||
{
|
||||
BOOST_STATIC_ASSERT('0' <= D && D <= '9');
|
||||
char c = res.template get<F1, F2>();
|
||||
if ( D > c || c > '9')
|
||||
res.template set<F1, F2, D>();
|
||||
}
|
||||
|
||||
template <field F1, field F2, char D, bool Transpose>
|
||||
struct update_result_dispatch
|
||||
{
|
||||
template <typename Result>
|
||||
static inline void apply(Result & res)
|
||||
{
|
||||
update<F1, F2, D>(res);
|
||||
}
|
||||
};
|
||||
|
||||
template <field F1, field F2, char D>
|
||||
struct update_result_dispatch<F1, F2, D, true>
|
||||
{
|
||||
template <typename Result>
|
||||
static inline void apply(Result & res)
|
||||
{
|
||||
update<F2, F1, D>(res);
|
||||
}
|
||||
};
|
||||
|
||||
template <field F1, field F2, char D, bool Transpose, typename Result>
|
||||
inline void update(Result & res)
|
||||
{
|
||||
update_result_dispatch<F1, F2, D, Transpose>::apply(res);
|
||||
}
|
||||
|
||||
template <typename Result, char II, char IB, char IE, char BI, char BB, char BE, char EI, char EB, char EE>
|
||||
inline Result return_result()
|
||||
{
|
||||
Result res;
|
||||
set<II, IB, IE, BI, BB, BE, EI, EB, EE>(res);
|
||||
return res;
|
||||
}
|
||||
|
||||
template <typename Geometry>
|
||||
struct result_dimension
|
||||
{
|
||||
BOOST_STATIC_ASSERT(geometry::dimension<Geometry>::value >= 0);
|
||||
static const char value
|
||||
= ( geometry::dimension<Geometry>::value <= 9 ) ?
|
||||
( '0' + geometry::dimension<Geometry>::value ) :
|
||||
'T';
|
||||
};
|
||||
|
||||
}} // namespace detail::relate
|
||||
#endif // DOXYGEN_NO_DETAIL
|
||||
|
||||
|
||||
@@ -83,6 +83,17 @@ template <typename Geometry,
|
||||
struct point_in_geometry : not_implemented<Tag>
|
||||
{};
|
||||
|
||||
template <typename Point2>
|
||||
struct point_in_geometry<Point2, point_tag>
|
||||
{
|
||||
template <typename Point1, typename Strategy> static inline
|
||||
int apply(Point1 const& point1, Point2 const& point2, Strategy const& strategy)
|
||||
{
|
||||
boost::ignore_unused_variable_warning(strategy);
|
||||
return strategy.apply(point1, point2) ? 1 : -1;
|
||||
}
|
||||
};
|
||||
|
||||
template <typename Linestring>
|
||||
struct point_in_geometry<Linestring, linestring_tag>
|
||||
{
|
||||
@@ -105,9 +116,11 @@ struct point_in_geometry<Linestring, linestring_tag>
|
||||
else
|
||||
return 1;
|
||||
}
|
||||
// else if ( count == 1
|
||||
// && detail::equals::equals_point_point(point, *boost::begin(linestring)) )
|
||||
// return 0;
|
||||
else if ( count == 1 )
|
||||
{
|
||||
if ( detail::equals::equals_point_point(point, *boost::begin(linestring)) )
|
||||
return 1;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -5,8 +5,8 @@
|
||||
// Copyright (c) 2009-2012 Mateusz Loskot, London, UK.
|
||||
// Copyright (c) 2013 Adam Wulkiewicz, Lodz, Poland.
|
||||
|
||||
// This file was modified by Oracle on 2013.
|
||||
// Modifications copyright (c) 2013, Oracle and/or its affiliates.
|
||||
// This file was modified by Oracle on 2013, 2014.
|
||||
// Modifications copyright (c) 2013, 2014 Oracle and/or its affiliates.
|
||||
|
||||
// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
|
||||
// (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
|
||||
@@ -113,6 +113,26 @@ struct point_in_geometry<Geometry, multi_linestring_tag>
|
||||
}
|
||||
};
|
||||
|
||||
template <typename Geometry>
|
||||
struct point_in_geometry<Geometry, multi_point_tag>
|
||||
{
|
||||
template <typename Point, typename Strategy> static inline
|
||||
int apply(Point const& point, Geometry const& geometry, Strategy const& strategy)
|
||||
{
|
||||
typedef typename boost::range_value<Geometry>::type point_type;
|
||||
typedef typename boost::range_const_iterator<Geometry>::type iterator;
|
||||
for ( iterator it = boost::begin(geometry) ; it != boost::end(geometry) ; ++it )
|
||||
{
|
||||
int pip = point_in_geometry<point_type>::apply(point, *it, strategy);
|
||||
|
||||
if ( pip > 0 ) // inside
|
||||
return 1;
|
||||
}
|
||||
|
||||
return -1; // outside
|
||||
}
|
||||
};
|
||||
|
||||
}} // namespace detail_dispatch::within
|
||||
#endif // DOXYGEN_NO_DETAIL
|
||||
|
||||
|
||||
@@ -0,0 +1,88 @@
|
||||
// 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_STRATEGY_AGNOSTIC_POINT_IN_POINT_HPP
|
||||
#define BOOST_GEOMETRY_STRATEGY_AGNOSTIC_POINT_IN_POINT_HPP
|
||||
|
||||
#include <boost/geometry/algorithms/detail/disjoint/point_point.hpp>
|
||||
|
||||
#include <boost/geometry/strategies/covered_by.hpp>
|
||||
#include <boost/geometry/strategies/within.hpp>
|
||||
|
||||
|
||||
namespace boost { namespace geometry
|
||||
{
|
||||
|
||||
namespace strategy { namespace within
|
||||
{
|
||||
|
||||
template
|
||||
<
|
||||
typename Point1, typename Point2
|
||||
>
|
||||
struct point_in_point
|
||||
{
|
||||
static inline bool apply(Point1 const& point1, Point2 const& point2)
|
||||
{
|
||||
return detail::equals::equals_point_point(point1, point2);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
#ifndef DOXYGEN_NO_STRATEGY_SPECIALIZATIONS
|
||||
|
||||
namespace services
|
||||
{
|
||||
|
||||
template <typename Point1, typename Point2, typename AnyCS1, typename AnyCS2>
|
||||
struct default_strategy<point_tag, point_tag, point_tag, point_tag, AnyCS1, AnyCS2, Point1, Point2>
|
||||
{
|
||||
typedef strategy::within::point_in_point<Point1, Point2> type;
|
||||
};
|
||||
|
||||
template <typename Point, typename MultiPoint, typename AnyCS1, typename AnyCS2>
|
||||
struct default_strategy<point_tag, multi_point_tag, point_tag, multi_point_tag, AnyCS1, AnyCS2, Point, MultiPoint>
|
||||
{
|
||||
typedef strategy::within::point_in_point<Point, typename point_type<MultiPoint>::type> type;
|
||||
};
|
||||
|
||||
} // namespace services
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
}} // namespace strategy::within
|
||||
|
||||
|
||||
|
||||
#ifndef DOXYGEN_NO_STRATEGY_SPECIALIZATIONS
|
||||
namespace strategy { namespace covered_by { namespace services
|
||||
{
|
||||
|
||||
template <typename Point1, typename Point2, typename AnyCS1, typename AnyCS2>
|
||||
struct default_strategy<point_tag, point_tag, point_tag, point_tag, AnyCS1, AnyCS2, Point1, Point2>
|
||||
{
|
||||
typedef strategy::within::point_in_point<Point1, Point2> type;
|
||||
};
|
||||
|
||||
template <typename Point, typename MultiPoint, typename AnyCS1, typename AnyCS2>
|
||||
struct default_strategy<point_tag, multi_point_tag, point_tag, multi_point_tag, AnyCS1, AnyCS2, Point, MultiPoint>
|
||||
{
|
||||
typedef strategy::within::point_in_point<Point, typename point_type<MultiPoint>::type> type;
|
||||
};
|
||||
|
||||
}}} // namespace strategy::covered_by::services
|
||||
#endif
|
||||
|
||||
|
||||
}} // namespace boost::geometry
|
||||
|
||||
|
||||
#endif // BOOST_GEOMETRY_STRATEGY_AGNOSTIC_POINT_IN_POINT_HPP
|
||||
@@ -4,6 +4,9 @@
|
||||
// Copyright (c) 2008-2012 Bruno Lalande, Paris, France.
|
||||
// Copyright (c) 2009-2012 Mateusz Loskot, London, UK.
|
||||
|
||||
// This file was modified by Oracle on 2014.
|
||||
// Modifications copyright (c) 2014 Oracle and/or its affiliates.
|
||||
|
||||
// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
|
||||
// (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
|
||||
|
||||
@@ -11,6 +14,8 @@
|
||||
// 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_STRATEGIES_STRATEGIES_HPP
|
||||
#define BOOST_GEOMETRY_STRATEGIES_STRATEGIES_HPP
|
||||
|
||||
@@ -46,6 +51,7 @@
|
||||
|
||||
#include <boost/geometry/strategies/agnostic/hull_graham_andrew.hpp>
|
||||
#include <boost/geometry/strategies/agnostic/point_in_box_by_side.hpp>
|
||||
#include <boost/geometry/strategies/agnostic/point_in_point.hpp>
|
||||
#include <boost/geometry/strategies/agnostic/point_in_poly_winding.hpp>
|
||||
#include <boost/geometry/strategies/agnostic/simplify_douglas_peucker.hpp>
|
||||
|
||||
|
||||
@@ -207,6 +207,8 @@ void test_all()
|
||||
|
||||
test_geometry<ls, ls>("LINESTRING(0 0,10 0)", "LINESTRING(-1 -1,1 0,10 0,20 -1)", "mii", "txu");
|
||||
test_geometry<ls, ls>("LINESTRING(0 0,10 0)", "LINESTRING(20 -1,10 0,1 0,-1 -1)", "miu", "txi");
|
||||
test_geometry<ls, ls>("LINESTRING(-1 -1,1 0,10 0,20 -1)", "LINESTRING(0 0,10 0)", "mii", "tux");
|
||||
test_geometry<ls, ls>("LINESTRING(20 -1,10 0,1 0,-1 -1)", "LINESTRING(0 0,10 0)", "mui", "tix");
|
||||
|
||||
test_geometry<ls, ls>("LINESTRING(-1 1,0 0,1 0,4 0,5 5,10 5,15 0,31 0)",
|
||||
"LINESTRING(-1 -1,0 0,1 0,2 0,2.5 1,3 0,30 0)",
|
||||
@@ -221,6 +223,20 @@ void test_all()
|
||||
"LINESTRING(30 0,3 0,2.5 1,2 0,1 0,0 0,-1 -1)",
|
||||
expected("tuu")("ecc")("mii")("muu")("mii")("muu")("mii").vec);
|
||||
|
||||
test_geometry<ls, ls>("LINESTRING(-1 0,1 0,2 1,3 2)", "LINESTRING(4 5,3 2,1 0,0 0)", "mix", "txi", "ecc");
|
||||
test_geometry<ls, ls>("LINESTRING(4 5,3 2,1 0,0 0)", "LINESTRING(-1 0,1 0,2 1,3 2)", "mxi", "tix", "ecc");
|
||||
|
||||
test_geometry<ls, ls>("LINESTRING(30 1,20 1,10 0,0 0)", "LINESTRING(1 1,2 0,3 1,20 1,25 1)", "mix", "tui", "muu");
|
||||
test_geometry<ls, ls>("LINESTRING(1 1,2 0,3 1,20 1,25 1)", "LINESTRING(30 1,20 1,10 0,0 0)", "mxi", "tiu", "muu");
|
||||
|
||||
test_geometry<ls, ls>("LINESTRING(0 0,30 0)", "LINESTRING(4 0,4 1,20 1,5 0,1 0)", "muu", "mui", "mix");
|
||||
test_geometry<ls, ls>("LINESTRING(4 0,4 1,20 1,5 0,1 0)", "LINESTRING(0 0,30 0)", "muu", "miu", "mxi");
|
||||
|
||||
test_geometry<ls, ls>("LINESTRING(30 0,0 0)", "LINESTRING(1 0,5 0,20 1,4 1,4 0,5 0)",
|
||||
expected("mui")("miu")("mui")("mix").vec);
|
||||
test_geometry<ls, ls>("LINESTRING(1 0,5 0,20 1,4 1,4 0,5 0)", "LINESTRING(30 0,0 0)",
|
||||
expected("miu")("mui")("miu")("mxi").vec);
|
||||
|
||||
//if ( boost::is_same<T, double>::value )
|
||||
//{
|
||||
// to_svg<ls, ls>("LINESTRING(0 0,1 0,2 0,2.5 0,3 1)", "LINESTRING(0 0,2 0,2.5 0,3 1)", "test11.svg");
|
||||
|
||||
@@ -176,6 +176,14 @@ void test_linestring_linestring()
|
||||
test_geometry<ls, ls>("LINESTRING(0 0,5 0)", "LINESTRING(5 0,10 0,5 5,5 0)", "FF00F01F2");
|
||||
|
||||
//to_svg<ls, ls>("LINESTRING(0 0,5 0)", "LINESTRING(5 0,10 0,5 5,0 0,5 0)", "test_relate_00.svg");
|
||||
|
||||
// 1-point LS (a Point) NOT disjoint
|
||||
test_geometry<ls, ls>("LINESTRING(1 0)", "LINESTRING(0 0,5 0)", "0FFFFF102");
|
||||
test_geometry<ls, ls>("LINESTRING(0 0,5 0)", "LINESTRING(1 0)", "0F1FF0FF2");
|
||||
test_geometry<ls, ls>("LINESTRING(0 0,5 0)", "LINESTRING(1 0,1 0)", "0F1FF0FF2");
|
||||
test_geometry<ls, ls>("LINESTRING(0 0,5 0)", "LINESTRING(1 0,1 0,1 0)", "0F1FF0FF2");
|
||||
// Point/Point
|
||||
test_geometry<ls, ls>("LINESTRING(0 0)", "LINESTRING(0 0)", "0FFFFFFF2");
|
||||
}
|
||||
|
||||
template <typename P>
|
||||
@@ -184,7 +192,20 @@ void test_linestring_multi_linestring()
|
||||
typedef bg::model::linestring<P> ls;
|
||||
typedef bg::model::multi_linestring<ls> mls;
|
||||
|
||||
// LS disjoint
|
||||
test_geometry<ls, mls>("LINESTRING(0 0,10 0)", "MULTILINESTRING((1 0,2 0),(1 1,2 1))", "101FF0102");
|
||||
// linear ring disjoint
|
||||
test_geometry<ls, mls>("LINESTRING(0 0,10 0)", "MULTILINESTRING((1 0,2 0),(1 1,2 1,2 2,1 1))", "101FF01F2");
|
||||
// 2xLS forming non-simple linear ring disjoint
|
||||
test_geometry<ls, mls>("LINESTRING(0 0,10 0)", "MULTILINESTRING((1 0,2 0),(1 1,2 1,2 2),(1 1,2 2))", "101FF01F2");
|
||||
// 1-point LS (a Point) disjoint
|
||||
test_geometry<ls, mls>("LINESTRING(0 0,10 0)", "MULTILINESTRING((1 0,2 0),(1 1))", "101FF00F2");
|
||||
test_geometry<ls, mls>("LINESTRING(0 0,10 0)", "MULTILINESTRING((1 0,2 0),(1 1,1 1))", "101FF00F2");
|
||||
test_geometry<ls, mls>("LINESTRING(0 0,10 0)", "MULTILINESTRING((1 0,2 0),(1 1,1 1,1 1))", "101FF00F2");
|
||||
// 1-point LS (a Point) NOT disjoint
|
||||
test_geometry<ls, mls>("LINESTRING(0 0,10 0)", "MULTILINESTRING((1 0,9 0),(2 0))", "101FF0FF2");
|
||||
test_geometry<ls, mls>("LINESTRING(0 0,10 0)", "MULTILINESTRING((1 0,9 0),(2 0,2 0))", "101FF0FF2");
|
||||
test_geometry<ls, mls>("LINESTRING(0 0,10 0)", "MULTILINESTRING((1 0,9 0),(2 0,2 0,2 0))", "101FF0FF2");
|
||||
}
|
||||
|
||||
template <typename P>
|
||||
|
||||
Reference in New Issue
Block a user