From 7033337149ea250b146cc0b464c23d181e357a76 Mon Sep 17 00:00:00 2001 From: Adam Wulkiewicz Date: Mon, 24 Feb 2014 15:16:37 +0100 Subject: [PATCH 1/2] IP coordinates rounded to the nearest value instead of a cast in segments_intersection_points if coordinate_type is integer --- .../policies/relate/intersection_points.hpp | 35 +++++++++++++++++-- 1 file changed, 32 insertions(+), 3 deletions(-) diff --git a/include/boost/geometry/policies/relate/intersection_points.hpp b/include/boost/geometry/policies/relate/intersection_points.hpp index ff8ec1949..8a315ef57 100644 --- a/include/boost/geometry/policies/relate/intersection_points.hpp +++ b/include/boost/geometry/policies/relate/intersection_points.hpp @@ -22,13 +22,42 @@ #include #include - namespace boost { namespace geometry { namespace policies { namespace relate { +template ::is_integer> +struct round_dispatch +{ + template + static inline Result apply(T const& v) + { + return v < 0 ? + boost::numeric_cast(ceil(v - 0.5f)) : + boost::numeric_cast(floor(v + 0.5f)); + } +}; + +template +struct round_dispatch +{ + template + static inline Result apply(T const& v) + { + return boost::numeric_cast(v); + } +}; + +template +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::is_integer); + return round_dispatch::apply(v); +} template 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(R(s1x) + r * R(dx1))); + round(R(s1x) + r * R(dx1))); set<1>(result.intersections[0], - boost::numeric_cast(R(s1y) + r * R(dy1))); + round(R(s1y) + r * R(dy1))); return result; } From 00941b7d5098256c5ff4fab2399f848f99b67155 Mon Sep 17 00:00:00 2001 From: Adam Wulkiewicz Date: Mon, 24 Feb 2014 17:47:29 +0100 Subject: [PATCH 2/2] Implemented relate(MultiPoint, MultiPoint), added detail::relate::less comparing Point types with different coordinate_type, added some TODO notes regarding possible optimizations --- .../algorithms/detail/relate/point_point.hpp | 211 ++++++++++++++---- .../algorithms/detail/relate/relate.hpp | 8 +- test/algorithms/relate.cpp | 13 ++ 3 files changed, 179 insertions(+), 53 deletions(-) diff --git a/include/boost/geometry/algorithms/detail/relate/point_point.hpp b/include/boost/geometry/algorithms/detail/relate/point_point.hpp index aeec654c9..671a4ae84 100644 --- a/include/boost/geometry/algorithms/detail/relate/point_point.hpp +++ b/include/boost/geometry/algorithms/detail/relate/point_point.hpp @@ -83,12 +83,23 @@ struct point_multipoint template static inline void apply(Point const& point, MultiPoint const& multi_point, Result & result) { + if ( boost::empty(multi_point) ) + { + // TODO: throw on empty input? + set(result); + return; + } + std::pair rel = point_multipoint_check(point, multi_point); if ( rel.first ) // some point of MP is equal to P { set(result); - + + if ( rel.second ) // a point of MP was found outside P + { + set(result); + } } else { @@ -96,11 +107,6 @@ struct point_multipoint set(result); } - if ( rel.second ) // a point of MP was found outside P - { - set(result); - } - set::value, Transpose>(result); } }; @@ -117,49 +123,156 @@ struct multipoint_point } }; -//template -//struct multipoint_multipoint -//{ -// static const bool interruption_enabled = false; -// -// template -// static inline void apply(MultiPoint1 const& multi_point1, MultiPoint2 const& multi_point2, Result & result) -// { -// if ( boost::size(multi_point1) < boost::size(multi_point2) ) -// { -// apply(multi_point1, multi_point2, result); -// } -// else -// { -// apply(multi_point2, multi_point1, result); -// } -// } -// -// template -// void apply(SortedMultiPoint const& sorted_mpt, -// IteratedMultiPoint const& iterated_mpt, -// Result & result) -// { -// // sort points from the 1 MPt -// typedef typename geometry::point_type::type point_type; -// std::vector points; -// std::sort(points.begin(), point.end(), geometry::less()); -// -// // for each point in the second MPt -// typedef typename boost::range_iterator::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 ::value> +struct less_dispatch +{ + static inline bool apply(Point1 const& l, Point2 const& r) + { + typename geometry::coordinate_type::type + cl = geometry::get(l); + typename geometry::coordinate_type::type + cr = geometry::get(r); + + if ( geometry::math::equals(cl, cr) ) + { + return less_dispatch::apply(l, r); + } + else + { + return cl < cr; + } + } +}; + +template +struct less_dispatch +{ + static inline bool apply(Point1 const&, Point2 const&) + { + return false; + } +}; + +struct less +{ + template + inline bool operator()(Point1 const& point1, Point2 const& point2) + { + return less_dispatch::apply(point1, point2); + } +}; + +template +struct multipoint_multipoint +{ + static const bool interruption_enabled = true; + + template + 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(result); + return; + } + else if ( empty2 ) + { + set(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(multi_point1, multi_point2, result); + + if ( all_handled || result.interrupt ) + return; + + // MlogM + NlogM + search(multi_point2, multi_point1, result); + } + + template + 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::type point_type; + std::vector 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::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(result); + + if ( found_outside ) // some point of MP2 was found outside of MP1 + { + set(result); + } + } + else + { + set(result); + set(result); + + // if no point is intersecting the other MPt then we musn't analyse the reversed case + all_handled = true; + } + + set::value, Transpose>(result); + + return all_handled; + } +}; }} // namespace detail::relate #endif // DOXYGEN_NO_DETAIL diff --git a/include/boost/geometry/algorithms/detail/relate/relate.hpp b/include/boost/geometry/algorithms/detail/relate/relate.hpp index 77c68c3d8..f3352e00d 100644 --- a/include/boost/geometry/algorithms/detail/relate/relate.hpp +++ b/include/boost/geometry/algorithms/detail/relate/relate.hpp @@ -75,10 +75,10 @@ struct relate : detail::relate::multipoint_point {}; -//template -//struct relate -// : detail::relate::multipoint_multipoint -//{}; +template +struct relate + : detail::relate::multipoint_multipoint +{}; //template //struct relate diff --git a/test/algorithms/relate.cpp b/test/algorithms/relate.cpp index 7856cd594..3339e23bb 100644 --- a/test/algorithms/relate.cpp +++ b/test/algorithms/relate.cpp @@ -158,6 +158,18 @@ void test_point_multipoint() test_geometry("POINT(0 0)", "MULTIPOINT(0 0, 1 0)", "0FFFFF0F2"); } +template +void test_multipoint_multipoint() +{ + typedef bg::model::multi_point

mpt; + + test_geometry("MULTIPOINT(0 0)", "MULTIPOINT(0 0)", "0FFFFFFF2"); + test_geometry("MULTIPOINT(1 0)", "MULTIPOINT(0 0)", "FF0FFF0F2"); + test_geometry("MULTIPOINT(0 0)", "MULTIPOINT(0 0, 1 0)", "0FFFFF0F2"); + test_geometry("MULTIPOINT(0 0, 1 0)", "MULTIPOINT(0 0)", "0F0FFFFF2"); + test_geometry("MULTIPOINT(0 0, 1 1)", "MULTIPOINT(0 0, 1 0)", "0F0FFF0F2"); +} + template void test_point_linestring() { @@ -333,6 +345,7 @@ void test_all() { test_point_point

(); test_point_multipoint

(); + test_multipoint_multipoint

(); test_point_linestring

(); test_point_multilinestring

(); test_linestring_linestring

();