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

This commit is contained in:
Menelaos Karavelas 2014-02-24 22:20:35 +02:00
commit 4030dd7c4b
4 changed files with 211 additions and 56 deletions

View File

@ -83,12 +83,23 @@ struct point_multipoint
template <typename Result>
static inline void apply(Point const& point, MultiPoint const& multi_point, Result & result)
{
if ( boost::empty(multi_point) )
{
// TODO: throw on empty input?
set<interior, exterior, '0', Transpose>(result);
return;
}
std::pair<bool, bool> rel = point_multipoint_check(point, multi_point);
if ( rel.first ) // some point of MP is equal to P
{
set<interior, interior, '0', Transpose>(result);
if ( rel.second ) // a point of MP was found outside P
{
set<exterior, interior, '0', Transpose>(result);
}
}
else
{
@ -96,11 +107,6 @@ struct point_multipoint
set<exterior, interior, '0', Transpose>(result);
}
if ( rel.second ) // a point of MP was found outside P
{
set<exterior, interior, '0', Transpose>(result);
}
set<exterior, exterior, result_dimension<Point>::value, Transpose>(result);
}
};
@ -117,49 +123,156 @@ struct multipoint_point
}
};
//template <typename MultiPoint1, typename MultiPoint2>
//struct multipoint_multipoint
//{
// static const bool interruption_enabled = false;
//
// template <typename Result>
// static inline void apply(MultiPoint1 const& multi_point1, MultiPoint2 const& multi_point2, Result & result)
// {
// if ( boost::size(multi_point1) < boost::size(multi_point2) )
// {
// apply<false>(multi_point1, multi_point2, result);
// }
// else
// {
// apply<true>(multi_point2, multi_point1, result);
// }
// }
//
// template <bool Transpose,
// typename SortedMultiPoint,
// typename IteratedMultiPoint,
// typename Result>
// void apply(SortedMultiPoint const& sorted_mpt,
// IteratedMultiPoint const& iterated_mpt,
// Result & result)
// {
// // sort points from the 1 MPt
// typedef typename geometry::point_type<SortedMultiPoint>::type point_type;
// std::vector<point_type> points;
// std::sort(points.begin(), point.end(), geometry::less<point_type>());
//
// // for each point in the second MPt
// typedef typename boost::range_iterator<IteratedMultiPoint const>::iterator iterator;
// for ( iterator it = boost::begin(iterated_mpt) ;
// it != boost::end(iterated_mpt) ; ++it )
// {
//
//// TODO: FOR THIS TO WORK, WE NEED geometry::less<> WHICH CAN TAKE 2 DIFFERENT POINT TYPES!
////
// bool found = binary_search (points.begin(), point.end(), *it, less);
// }
// }
//};
// TODO: should this be integrated with geometry::less?
template <typename Point1,
typename Point2,
std::size_t I = 0,
std::size_t D = geometry::dimension<Point1>::value>
struct less_dispatch
{
static inline bool apply(Point1 const& l, Point2 const& r)
{
typename geometry::coordinate_type<Point1>::type
cl = geometry::get<I>(l);
typename geometry::coordinate_type<Point2>::type
cr = geometry::get<I>(r);
if ( geometry::math::equals(cl, cr) )
{
return less_dispatch<Point1, Point2, I + 1, D>::apply(l, r);
}
else
{
return cl < cr;
}
}
};
template <typename Point1, typename Point2, std::size_t D>
struct less_dispatch<Point1, Point2, D, D>
{
static inline bool apply(Point1 const&, Point2 const&)
{
return false;
}
};
struct less
{
template <typename Point1, typename Point2>
inline bool operator()(Point1 const& point1, Point2 const& point2)
{
return less_dispatch<Point1, Point2>::apply(point1, point2);
}
};
template <typename MultiPoint1, typename MultiPoint2>
struct multipoint_multipoint
{
static const bool interruption_enabled = true;
template <typename Result>
static inline void apply(MultiPoint1 const& multi_point1, MultiPoint2 const& multi_point2, Result & result)
{
{
// TODO: throw on empty input?
bool empty1 = boost::empty(multi_point1);
bool empty2 = boost::empty(multi_point2);
if ( empty1 && empty2 )
{
return;
}
else if ( empty1 )
{
set<exterior, interior, '0'>(result);
return;
}
else if ( empty2 )
{
set<interior, exterior, '0'>(result);
return;
}
}
// TODO: ADD A CHECK TO THE RESULT INDICATING IF THE FIRST AND/OR SECOND GEOMETRY MUST BE ANALYSED
// TODO: if I/I is set for one MPt, this won't be changed when the other one in analysed
// so if e.g. only I/I must be analysed we musn't check the other MPt
// TODO: Also, the geometry with the smaller number of points may be analysed first
//if ( boost::size(multi_point1) < boost::size(multi_point2) )
// NlogN + MlogN
bool all_handled = search<false>(multi_point1, multi_point2, result);
if ( all_handled || result.interrupt )
return;
// MlogM + NlogM
search<true>(multi_point2, multi_point1, result);
}
template <bool Transpose,
typename SortedMultiPoint,
typename IteratedMultiPoint,
typename Result>
static inline bool search(SortedMultiPoint const& sorted_mpt,
IteratedMultiPoint const& iterated_mpt,
Result & result)
{
// sort points from the 1 MPt
typedef typename geometry::point_type<SortedMultiPoint>::type point_type;
std::vector<point_type> points(boost::begin(sorted_mpt), boost::end(sorted_mpt));
std::sort(points.begin(), points.end(), less());
bool found_inside = false;
bool found_outside = false;
// for each point in the second MPt
typedef typename boost::range_iterator<IteratedMultiPoint const>::type iterator;
for ( iterator it = boost::begin(iterated_mpt) ;
it != boost::end(iterated_mpt) ; ++it )
{
bool ii = binary_search(points.begin(), points.end(), *it, less());
if ( ii )
found_inside = true;
else
found_outside = true;
if ( found_inside && found_outside )
break;
}
// an optimization
bool all_handled = false;
if ( found_inside ) // some point of MP2 is equal to some of MP1
{
// TODO: if I/I is set for one MPt, this won't be changed when the other one in analysed
// so if e.g. only I/I must be analysed we musn't check the other MPt
set<interior, interior, '0', Transpose>(result);
if ( found_outside ) // some point of MP2 was found outside of MP1
{
set<exterior, interior, '0', Transpose>(result);
}
}
else
{
set<interior, exterior, '0', Transpose>(result);
set<exterior, interior, '0', Transpose>(result);
// if no point is intersecting the other MPt then we musn't analyse the reversed case
all_handled = true;
}
set<exterior, exterior, result_dimension<point_type>::value, Transpose>(result);
return all_handled;
}
};
}} // namespace detail::relate
#endif // DOXYGEN_NO_DETAIL

View File

@ -75,10 +75,10 @@ struct relate<MultiPoint, Point, multi_point_tag, point_tag>
: detail::relate::multipoint_point<MultiPoint, Point>
{};
//template <typename MultiPoint1, typename MultiPoint2>
//struct relate<MultiPoint1, MultiPoint2, multi_point_tag, multi_point_tag>
// : detail::relate::multipoint_multipoint<MultiPoint1, MultiPoint2>
//{};
template <typename MultiPoint1, typename MultiPoint2>
struct relate<MultiPoint1, MultiPoint2, multi_point_tag, multi_point_tag>
: detail::relate::multipoint_multipoint<MultiPoint1, MultiPoint2>
{};
//template <typename Point, typename Box>
//struct relate<Point, Box, point_tag, box_tag>

View File

@ -22,13 +22,42 @@
#include <boost/geometry/util/select_calculation_type.hpp>
#include <boost/geometry/util/select_most_precise.hpp>
namespace boost { namespace geometry
{
namespace policies { namespace relate
{
template <typename Result, bool IsInteger = std::numeric_limits<Result>::is_integer>
struct round_dispatch
{
template <typename T>
static inline Result apply(T const& v)
{
return v < 0 ?
boost::numeric_cast<Result>(ceil(v - 0.5f)) :
boost::numeric_cast<Result>(floor(v + 0.5f));
}
};
template <typename Result>
struct round_dispatch<Result, false>
{
template <typename T>
static inline Result apply(T const& v)
{
return boost::numeric_cast<Result>(v);
}
};
template <typename Result, typename T>
inline Result round(T const& v)
{
// NOTE: boost::round() could be used instead but it throws in some situations
//BOOST_STATIC_ASSERT(!std::numeric_limits<T>::is_integer);
return round_dispatch<Result>::apply(v);
}
template <typename S1, typename S2, typename ReturnType, typename CalculationType = void>
struct segments_intersection_points
@ -60,9 +89,9 @@ struct segments_intersection_points
return_type result;
result.count = 1;
set<0>(result.intersections[0],
boost::numeric_cast<return_coordinate_type>(R(s1x) + r * R(dx1)));
round<return_coordinate_type>(R(s1x) + r * R(dx1)));
set<1>(result.intersections[0],
boost::numeric_cast<return_coordinate_type>(R(s1y) + r * R(dy1)));
round<return_coordinate_type>(R(s1y) + r * R(dy1)));
return result;
}

View File

@ -158,6 +158,18 @@ void test_point_multipoint()
test_geometry<P, mpt>("POINT(0 0)", "MULTIPOINT(0 0, 1 0)", "0FFFFF0F2");
}
template <typename P>
void test_multipoint_multipoint()
{
typedef bg::model::multi_point<P> mpt;
test_geometry<mpt, mpt>("MULTIPOINT(0 0)", "MULTIPOINT(0 0)", "0FFFFFFF2");
test_geometry<mpt, mpt>("MULTIPOINT(1 0)", "MULTIPOINT(0 0)", "FF0FFF0F2");
test_geometry<mpt, mpt>("MULTIPOINT(0 0)", "MULTIPOINT(0 0, 1 0)", "0FFFFF0F2");
test_geometry<mpt, mpt>("MULTIPOINT(0 0, 1 0)", "MULTIPOINT(0 0)", "0F0FFFFF2");
test_geometry<mpt, mpt>("MULTIPOINT(0 0, 1 1)", "MULTIPOINT(0 0, 1 0)", "0F0FFF0F2");
}
template <typename P>
void test_point_linestring()
{
@ -333,6 +345,7 @@ void test_all()
{
test_point_point<P>();
test_point_multipoint<P>();
test_multipoint_multipoint<P>();
test_point_linestring<P>();
test_point_multilinestring<P>();
test_linestring_linestring<P>();