Merge branch 'feature/relate' of https://github.com/boostorg/geometry into feature/setops

This commit is contained in:
Menelaos Karavelas
2014-02-19 09:00:09 +02:00
12 changed files with 851 additions and 386 deletions

View File

@@ -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 )
{

View File

@@ -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

View File

@@ -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,

View File

@@ -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

View File

@@ -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 {

View File

@@ -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

View File

@@ -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;
}

View File

@@ -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

View File

@@ -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

View File

@@ -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>

View File

@@ -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");

View File

@@ -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>