diff --git a/doc/index/rtree/query.qbk b/doc/index/rtree/query.qbk index 75f40ec29..a2fa49594 100644 --- a/doc/index/rtree/query.qbk +++ b/doc/index/rtree/query.qbk @@ -69,14 +69,19 @@ Examples of some basic queries may be found in the tables below. The query regio ] [table -[[intersects(Ring)] [intersects(Polygon)] [intersects(MultiPolygon)] [intersects(Segment)] [intersects(Linestring)]] -[[[$img/index/rtree/intersects_ring.png]] [[$img/index/rtree/intersects_poly.png]] [[$img/index/rtree/intersects_mpoly.png]] [[$img/index/rtree/intersects_segment.png]] [[$img/index/rtree/intersects_linestring.png]]] +[[intersects(Segment)] [intersects(Box)] [disjoint(Box)] [intersects(Box)] [disjoint(Box)]] +[[[$img/index/rtree/intersects_segment.png]] [[$img/index/rtree/rtree_pt_intersects_box.png]] [[$img/index/rtree/rtree_pt_disjoint_box.png]] [[$img/index/rtree/rtree_seg_intersects_box.png]] [[$img/index/rtree/rtree_seg_disjoint_box.png]]] ] -[table +[/table +[[intersects(Ring)] [intersects(Polygon)] [intersects(MultiPolygon)] [intersects(Segment)] [intersects(Linestring)]] +[[[$img/index/rtree/intersects_ring.png]] [[$img/index/rtree/intersects_poly.png]] [[$img/index/rtree/intersects_mpoly.png]] [[$img/index/rtree/intersects_segment.png]] [[$img/index/rtree/intersects_linestring.png]]] +/] + +[/table [[intersects(Box)] [disjoint(Box)] [intersects(Box)] [disjoint(Box)]] [[[$img/index/rtree/rtree_pt_intersects_box.png]] [[$img/index/rtree/rtree_pt_disjoint_box.png]] [[$img/index/rtree/rtree_seg_intersects_box.png]] [[$img/index/rtree/rtree_seg_disjoint_box.png]]] -] +/] Spatial predicates are generated by functions defined in `boost::geometry::index` namespace. diff --git a/doc/release_notes.qbk b/doc/release_notes.qbk index aca0f84d1..24f1e2377 100644 --- a/doc/release_notes.qbk +++ b/doc/release_notes.qbk @@ -25,6 +25,7 @@ [*Improvements] * Add correct() overload taking area strategy +* Add is_convex() overload taking side strategy * Add missing relational operations (covered_by, crosses, equals, etc.) for MultiPoint/AnyGeometry [*Solved issues] @@ -43,6 +44,7 @@ * Fix propagation of area strategy into the internals of various algorithms from intersection strategy * Fix uninitialized variable in relate and reference to temporary in overlay * Fix error in disjoint for geographic Segment/Box +* Fix handling of non-cartesian geometries in various algorithms [/=================] [heading Boost 1.64] diff --git a/include/boost/geometry/algorithms/detail/buffer/buffer_inserter.hpp b/include/boost/geometry/algorithms/detail/buffer/buffer_inserter.hpp index 029053dda..a149f1dd4 100644 --- a/include/boost/geometry/algorithms/detail/buffer/buffer_inserter.hpp +++ b/include/boost/geometry/algorithms/detail/buffer/buffer_inserter.hpp @@ -122,7 +122,8 @@ struct buffer_range typename DistanceStrategy, typename JoinStrategy, typename EndStrategy, - typename RobustPolicy + typename RobustPolicy, + typename Strategy > static inline void add_join(Collection& collection, @@ -133,18 +134,19 @@ struct buffer_range Point const& input, output_point_type const& perp1, output_point_type const& perp2, - strategy::buffer::buffer_side_selector side, + geometry::strategy::buffer::buffer_side_selector side, DistanceStrategy const& distance, JoinStrategy const& join_strategy, EndStrategy const& end_strategy, - RobustPolicy const& ) + RobustPolicy const& , + Strategy const& strategy) // side strategy { output_point_type intersection_point; geometry::assign_zero(intersection_point); - strategy::buffer::join_selector join - = get_join_type(penultimate_input, previous_input, input); - if (join == strategy::buffer::join_convex) + geometry::strategy::buffer::join_selector join + = get_join_type(penultimate_input, previous_input, input, strategy); + if (join == geometry::strategy::buffer::join_convex) { // Calculate the intersection-point formed by the two sides. // It might be that the two sides are not convex, but continue @@ -157,23 +159,23 @@ struct buffer_range switch(join) { - case strategy::buffer::join_continue : + case geometry::strategy::buffer::join_continue : // No join, we get two consecutive sides break; - case strategy::buffer::join_concave : + case geometry::strategy::buffer::join_concave : { std::vector range_out; range_out.push_back(prev_perp2); range_out.push_back(previous_input); - collection.add_piece(strategy::buffer::buffered_concave, previous_input, range_out); + collection.add_piece(geometry::strategy::buffer::buffered_concave, previous_input, range_out); range_out.clear(); range_out.push_back(previous_input); range_out.push_back(perp1); - collection.add_piece(strategy::buffer::buffered_concave, previous_input, range_out); + collection.add_piece(geometry::strategy::buffer::buffered_concave, previous_input, range_out); } break; - case strategy::buffer::join_spike : + case geometry::strategy::buffer::join_spike : { // For linestrings, only add spike at one side to avoid // duplicates @@ -183,7 +185,7 @@ struct buffer_range collection.set_current_ring_concave(); } break; - case strategy::buffer::join_convex : + case geometry::strategy::buffer::join_convex : { // The corner is convex, we create a join // TODO (future) - avoid a separate vector, add the piece directly @@ -193,7 +195,7 @@ struct buffer_range distance.apply(previous_input, input, side), range_out)) { - collection.add_piece(strategy::buffer::buffered_join, + collection.add_piece(geometry::strategy::buffer::buffered_join, previous_input, range_out); } } @@ -201,27 +203,24 @@ struct buffer_range } } - static inline strategy::buffer::join_selector get_join_type( + template + static inline geometry::strategy::buffer::join_selector get_join_type( output_point_type const& p0, output_point_type const& p1, - output_point_type const& p2) + output_point_type const& p2, + Strategy const& strategy) // side strategy { - typedef typename strategy::side::services::default_strategy - < - typename cs_tag::type - >::type side_strategy; - - int const side = side_strategy::apply(p0, p1, p2); - return side == -1 ? strategy::buffer::join_convex - : side == 1 ? strategy::buffer::join_concave + int const side = strategy.apply(p0, p1, p2); + return side == -1 ? geometry::strategy::buffer::join_convex + : side == 1 ? geometry::strategy::buffer::join_concave : parallel_continue ( get<0>(p2) - get<0>(p1), get<1>(p2) - get<1>(p1), get<0>(p1) - get<0>(p0), get<1>(p1) - get<1>(p0) - ) ? strategy::buffer::join_continue - : strategy::buffer::join_spike; + ) ? geometry::strategy::buffer::join_continue + : geometry::strategy::buffer::join_spike; } template @@ -232,16 +231,18 @@ struct buffer_range typename SideStrategy, typename JoinStrategy, typename EndStrategy, - typename RobustPolicy + typename RobustPolicy, + typename Strategy > - static inline strategy::buffer::result_code iterate(Collection& collection, + static inline geometry::strategy::buffer::result_code iterate(Collection& collection, Iterator begin, Iterator end, - strategy::buffer::buffer_side_selector side, + geometry::strategy::buffer::buffer_side_selector side, DistanceStrategy const& distance_strategy, SideStrategy const& side_strategy, JoinStrategy const& join_strategy, EndStrategy const& end_strategy, RobustPolicy const& robust_policy, + Strategy const& strategy, // side strategy output_point_type& first_p1, output_point_type& first_p2, output_point_type& last_p1, @@ -273,7 +274,7 @@ struct buffer_range * pup: penultimate_point */ - strategy::buffer::result_code result = strategy::buffer::result_no_output; + geometry::strategy::buffer::result_code result = geometry::strategy::buffer::result_no_output; bool first = true; Iterator it = begin; @@ -284,25 +285,25 @@ struct buffer_range for (Iterator prev = it++; it != end; ++it) { generated_side.clear(); - strategy::buffer::result_code error_code + geometry::strategy::buffer::result_code error_code = side_strategy.apply(*prev, *it, side, distance_strategy, generated_side); - if (error_code == strategy::buffer::result_no_output) + if (error_code == geometry::strategy::buffer::result_no_output) { // Because input is simplified, this is improbable, // but it can happen for degenerate geometries // Further handling of this side is skipped continue; } - else if (error_code == strategy::buffer::result_error_numerical) + else if (error_code == geometry::strategy::buffer::result_error_numerical) { return error_code; } BOOST_GEOMETRY_ASSERT(! generated_side.empty()); - result = strategy::buffer::result_normal; + result = geometry::strategy::buffer::result_normal; if (! first) { @@ -312,7 +313,7 @@ struct buffer_range *it, generated_side.front(), generated_side.back(), side, distance_strategy, join_strategy, end_strategy, - robust_policy); + robust_policy, strategy); } collection.add_side_piece(*prev, *it, generated_side, first); @@ -350,7 +351,8 @@ struct buffer_multi typename JoinStrategy, typename EndStrategy, typename PointStrategy, - typename RobustPolicy + typename RobustPolicy, + typename Strategy > static inline void apply(Multi const& multi, Collection& collection, @@ -359,7 +361,8 @@ struct buffer_multi JoinStrategy const& join_strategy, EndStrategy const& end_strategy, PointStrategy const& point_strategy, - RobustPolicy const& robust_policy) + RobustPolicy const& robust_policy, + Strategy const& strategy) // side strategy { for (typename boost::range_iterator::type it = boost::begin(multi); @@ -369,7 +372,7 @@ struct buffer_multi Policy::apply(*it, collection, distance_strategy, side_strategy, join_strategy, end_strategy, point_strategy, - robust_policy); + robust_policy, strategy); } } }; @@ -396,9 +399,9 @@ inline void buffer_point(Point const& point, Collection& collection, collection.start_new_ring(); std::vector range_out; point_strategy.apply(point, distance_strategy, range_out); - collection.add_piece(strategy::buffer::buffered_point, range_out, false); + collection.add_piece(geometry::strategy::buffer::buffered_point, range_out, false); collection.set_piece_center(point); - collection.finish_ring(strategy::buffer::result_normal); + collection.finish_ring(geometry::strategy::buffer::result_normal); } @@ -436,7 +439,8 @@ struct buffer_inserter typename JoinStrategy, typename EndStrategy, typename PointStrategy, - typename RobustPolicy + typename RobustPolicy, + typename Strategy > static inline void apply(Point const& point, Collection& collection, DistanceStrategy const& distance_strategy, @@ -444,7 +448,8 @@ struct buffer_inserter JoinStrategy const& , EndStrategy const& , PointStrategy const& point_strategy, - RobustPolicy const& ) + RobustPolicy const& , + Strategy const& ) // side strategy { detail::buffer::buffer_point < @@ -472,29 +477,32 @@ struct buffer_inserter_ring typename SideStrategy, typename JoinStrategy, typename EndStrategy, - typename RobustPolicy + typename RobustPolicy, + typename Strategy > - static inline strategy::buffer::result_code iterate(Collection& collection, + static inline geometry::strategy::buffer::result_code iterate(Collection& collection, Iterator begin, Iterator end, - strategy::buffer::buffer_side_selector side, + geometry::strategy::buffer::buffer_side_selector side, DistanceStrategy const& distance_strategy, SideStrategy const& side_strategy, JoinStrategy const& join_strategy, EndStrategy const& end_strategy, - RobustPolicy const& robust_policy) + RobustPolicy const& robust_policy, + Strategy const& strategy) // side strategy { output_point_type first_p1, first_p2, last_p1, last_p2; typedef detail::buffer::buffer_range buffer_range; - strategy::buffer::result_code result + geometry::strategy::buffer::result_code result = buffer_range::iterate(collection, begin, end, side, - distance_strategy, side_strategy, join_strategy, end_strategy, robust_policy, + distance_strategy, side_strategy, join_strategy, end_strategy, + robust_policy, strategy, first_p1, first_p2, last_p1, last_p2); // Generate closing join - if (result == strategy::buffer::result_normal) + if (result == geometry::strategy::buffer::result_normal) { buffer_range::add_join(collection, *(end - 2), @@ -502,7 +510,7 @@ struct buffer_inserter_ring *(begin + 1), first_p1, first_p2, side, distance_strategy, join_strategy, end_strategy, - robust_policy); + robust_policy, strategy); } // Buffer is closed automatically by last closing corner @@ -517,21 +525,23 @@ struct buffer_inserter_ring typename JoinStrategy, typename EndStrategy, typename PointStrategy, - typename RobustPolicy + typename RobustPolicy, + typename Strategy > - static inline strategy::buffer::result_code apply(RingInput const& ring, + static inline geometry::strategy::buffer::result_code apply(RingInput const& ring, Collection& collection, DistanceStrategy const& distance, SideStrategy const& side_strategy, JoinStrategy const& join_strategy, EndStrategy const& end_strategy, PointStrategy const& point_strategy, - RobustPolicy const& robust_policy) + RobustPolicy const& robust_policy, + Strategy const& strategy) // side strategy { RingInput simplified; detail::buffer::simplify_input(ring, distance, simplified); - strategy::buffer::result_code code = strategy::buffer::result_no_output; + geometry::strategy::buffer::result_code code = geometry::strategy::buffer::result_no_output; std::size_t n = boost::size(simplified); std::size_t const min_points = core_detail::closure::minimum_ring_size @@ -546,18 +556,20 @@ struct buffer_inserter_ring { // Walk backwards (rings will be reversed afterwards) code = iterate(collection, boost::rbegin(view), boost::rend(view), - strategy::buffer::buffer_side_right, - distance, side_strategy, join_strategy, end_strategy, robust_policy); + geometry::strategy::buffer::buffer_side_right, + distance, side_strategy, join_strategy, end_strategy, + robust_policy, strategy); } else { code = iterate(collection, boost::begin(view), boost::end(view), - strategy::buffer::buffer_side_left, - distance, side_strategy, join_strategy, end_strategy, robust_policy); + geometry::strategy::buffer::buffer_side_left, + distance, side_strategy, join_strategy, end_strategy, + robust_policy, strategy); } } - if (code == strategy::buffer::result_no_output && n >= 1) + if (code == geometry::strategy::buffer::result_no_output && n >= 1) { // Use point_strategy to buffer degenerated ring detail::buffer::buffer_point @@ -586,23 +598,25 @@ struct buffer_inserter typename JoinStrategy, typename EndStrategy, typename PointStrategy, - typename RobustPolicy + typename RobustPolicy, + typename Strategy > - static inline strategy::buffer::result_code apply(RingInput const& ring, + static inline geometry::strategy::buffer::result_code apply(RingInput const& ring, Collection& collection, DistanceStrategy const& distance, SideStrategy const& side_strategy, JoinStrategy const& join_strategy, EndStrategy const& end_strategy, PointStrategy const& point_strategy, - RobustPolicy const& robust_policy) + RobustPolicy const& robust_policy, + Strategy const& strategy) // side strategy { collection.start_new_ring(); - strategy::buffer::result_code const code + geometry::strategy::buffer::result_code const code = buffer_inserter_ring::apply(ring, collection, distance, side_strategy, join_strategy, end_strategy, point_strategy, - robust_policy); + robust_policy, strategy); collection.finish_ring(code); return code; } @@ -627,16 +641,18 @@ struct buffer_inserter typename SideStrategy, typename JoinStrategy, typename EndStrategy, - typename RobustPolicy + typename RobustPolicy, + typename Strategy > - static inline strategy::buffer::result_code iterate(Collection& collection, + static inline geometry::strategy::buffer::result_code iterate(Collection& collection, Iterator begin, Iterator end, - strategy::buffer::buffer_side_selector side, + geometry::strategy::buffer::buffer_side_selector side, DistanceStrategy const& distance_strategy, SideStrategy const& side_strategy, JoinStrategy const& join_strategy, EndStrategy const& end_strategy, RobustPolicy const& robust_policy, + Strategy const& strategy, // side strategy output_point_type& first_p1) { input_point_type const& ultimate_point = *(end - 1); @@ -647,18 +663,18 @@ struct buffer_inserter // we have it already from the first phase (left). // But for the first pass, we have to generate it output_point_type reverse_p1; - if (side == strategy::buffer::buffer_side_right) + if (side == geometry::strategy::buffer::buffer_side_right) { reverse_p1 = first_p1; } else { std::vector generated_side; - strategy::buffer::result_code code + geometry::strategy::buffer::result_code code = side_strategy.apply(ultimate_point, penultimate_point, - strategy::buffer::buffer_side_right, + geometry::strategy::buffer::buffer_side_right, distance_strategy, generated_side); - if (code != strategy::buffer::result_normal) + if (code != geometry::strategy::buffer::result_normal) { // No output or numerical error return code; @@ -668,16 +684,18 @@ struct buffer_inserter output_point_type first_p2, last_p1, last_p2; - strategy::buffer::result_code result + geometry::strategy::buffer::result_code result = detail::buffer::buffer_range::iterate(collection, begin, end, side, - distance_strategy, side_strategy, join_strategy, end_strategy, robust_policy, + distance_strategy, side_strategy, join_strategy, end_strategy, + robust_policy, strategy, first_p1, first_p2, last_p1, last_p2); - if (result == strategy::buffer::result_normal) + if (result == geometry::strategy::buffer::result_normal) { std::vector range_out; - end_strategy.apply(penultimate_point, last_p2, ultimate_point, reverse_p1, side, distance_strategy, range_out); + end_strategy.apply(penultimate_point, last_p2, ultimate_point, reverse_p1, + side, distance_strategy, range_out); collection.add_endcap(end_strategy, range_out, ultimate_point); } return result; @@ -691,20 +709,23 @@ struct buffer_inserter typename JoinStrategy, typename EndStrategy, typename PointStrategy, - typename RobustPolicy + typename RobustPolicy, + typename Strategy > - static inline strategy::buffer::result_code apply(Linestring const& linestring, Collection& collection, + static inline geometry::strategy::buffer::result_code apply(Linestring const& linestring, + Collection& collection, DistanceStrategy const& distance, SideStrategy const& side_strategy, JoinStrategy const& join_strategy, EndStrategy const& end_strategy, PointStrategy const& point_strategy, - RobustPolicy const& robust_policy) + RobustPolicy const& robust_policy, + Strategy const& strategy) // side strategy { Linestring simplified; detail::buffer::simplify_input(linestring, distance, simplified); - strategy::buffer::result_code code = strategy::buffer::result_no_output; + geometry::strategy::buffer::result_code code = geometry::strategy::buffer::result_no_output; std::size_t n = boost::size(simplified); if (n > 1) { @@ -712,21 +733,23 @@ struct buffer_inserter output_point_type first_p1; code = iterate(collection, boost::begin(simplified), boost::end(simplified), - strategy::buffer::buffer_side_left, - distance, side_strategy, join_strategy, end_strategy, robust_policy, + geometry::strategy::buffer::buffer_side_left, + distance, side_strategy, join_strategy, end_strategy, + robust_policy, strategy, first_p1); - if (code == strategy::buffer::result_normal) + if (code == geometry::strategy::buffer::result_normal) { code = iterate(collection, boost::rbegin(simplified), boost::rend(simplified), - strategy::buffer::buffer_side_right, - distance, side_strategy, join_strategy, end_strategy, robust_policy, + geometry::strategy::buffer::buffer_side_right, + distance, side_strategy, join_strategy, end_strategy, + robust_policy, strategy, first_p1); } collection.finish_ring(code); } - if (code == strategy::buffer::result_no_output && n >= 1) + if (code == geometry::strategy::buffer::result_no_output && n >= 1) { // Use point_strategy to buffer degenerated linestring detail::buffer::buffer_point @@ -763,7 +786,8 @@ private: typename JoinStrategy, typename EndStrategy, typename PointStrategy, - typename RobustPolicy + typename RobustPolicy, + typename Strategy > static inline void iterate(Iterator begin, Iterator end, @@ -774,15 +798,16 @@ private: EndStrategy const& end_strategy, PointStrategy const& point_strategy, RobustPolicy const& robust_policy, + Strategy const& strategy, // side strategy bool is_interior) { for (Iterator it = begin; it != end; ++it) { collection.start_new_ring(); - strategy::buffer::result_code const code + geometry::strategy::buffer::result_code const code = policy::apply(*it, collection, distance, side_strategy, join_strategy, end_strategy, point_strategy, - robust_policy); + robust_policy, strategy); collection.finish_ring(code, is_interior); } @@ -797,7 +822,8 @@ private: typename JoinStrategy, typename EndStrategy, typename PointStrategy, - typename RobustPolicy + typename RobustPolicy, + typename Strategy > static inline void apply_interior_rings(InteriorRings const& interior_rings, @@ -807,12 +833,13 @@ private: JoinStrategy const& join_strategy, EndStrategy const& end_strategy, PointStrategy const& point_strategy, - RobustPolicy const& robust_policy) + RobustPolicy const& robust_policy, + Strategy const& strategy) // side strategy { iterate(boost::begin(interior_rings), boost::end(interior_rings), collection, distance, side_strategy, join_strategy, end_strategy, point_strategy, - robust_policy, true); + robust_policy, strategy, true); } public: @@ -824,7 +851,8 @@ public: typename JoinStrategy, typename EndStrategy, typename PointStrategy, - typename RobustPolicy + typename RobustPolicy, + typename Strategy > static inline void apply(PolygonInput const& polygon, Collection& collection, @@ -833,16 +861,17 @@ public: JoinStrategy const& join_strategy, EndStrategy const& end_strategy, PointStrategy const& point_strategy, - RobustPolicy const& robust_policy) + RobustPolicy const& robust_policy, + Strategy const& strategy) // side strategy { { collection.start_new_ring(); - strategy::buffer::result_code const code + geometry::strategy::buffer::result_code const code = policy::apply(exterior_ring(polygon), collection, distance, side_strategy, join_strategy, end_strategy, point_strategy, - robust_policy); + robust_policy, strategy); collection.finish_ring(code, false, geometry::num_interior_rings(polygon) > 0u); @@ -851,7 +880,7 @@ public: apply_interior_rings(interior_rings(polygon), collection, distance, side_strategy, join_strategy, end_strategy, point_strategy, - robust_policy); + robust_policy, strategy); } }; @@ -945,7 +974,7 @@ inline void buffer_inserter(GeometryInput const& geometry_input, OutputIterator >::apply(geometry_input, collection, distance_strategy, side_strategy, join_strategy, end_strategy, point_strategy, - robust_policy); + robust_policy, intersection_strategy.get_side_strategy()); collection.get_turns(); collection.classify_turns(linear); diff --git a/include/boost/geometry/algorithms/detail/buffer/buffered_piece_collection.hpp b/include/boost/geometry/algorithms/detail/buffer/buffered_piece_collection.hpp index 4bb7a281f..c0d906fe6 100644 --- a/include/boost/geometry/algorithms/detail/buffer/buffered_piece_collection.hpp +++ b/include/boost/geometry/algorithms/detail/buffer/buffered_piece_collection.hpp @@ -494,7 +494,7 @@ struct buffered_piece_collection for (typename occupation_map_type::iterator it = occupation_map.begin(); it != occupation_map.end(); ++it) { - it->second.get_left_turns(it->first, m_turns); + it->second.get_left_turns(it->first, m_turns, m_side_strategy); } } diff --git a/include/boost/geometry/algorithms/detail/buffer/get_piece_turns.hpp b/include/boost/geometry/algorithms/detail/buffer/get_piece_turns.hpp index 94dfddd44..5c012e715 100644 --- a/include/boost/geometry/algorithms/detail/buffer/get_piece_turns.hpp +++ b/include/boost/geometry/algorithms/detail/buffer/get_piece_turns.hpp @@ -127,26 +127,31 @@ class piece_turn_visitor template inline void move_begin_iterator(Iterator& it_begin, Iterator it_beyond, - signed_size_type& index, int dir, Box const& other_bounding_box) + signed_size_type& index, int dir, + Box const& this_bounding_box, + Box const& other_bounding_box) { for(; it_begin != it_beyond && it_begin + 1 != it_beyond && detail::section::preceding(dir, *(it_begin + 1), - other_bounding_box, m_robust_policy); + this_bounding_box, + other_bounding_box, + m_robust_policy); ++it_begin, index++) {} } template inline void move_end_iterator(Iterator it_begin, Iterator& it_beyond, - int dir, Box const& other_bounding_box) + int dir, Box const& this_bounding_box, + Box const& other_bounding_box) { while (it_beyond != it_begin && it_beyond - 1 != it_begin && it_beyond - 2 != it_begin) { if (detail::section::exceeding(dir, *(it_beyond - 2), - other_bounding_box, m_robust_policy)) + this_bounding_box, other_bounding_box, m_robust_policy)) { --it_beyond; } @@ -192,23 +197,23 @@ class piece_turn_visitor // Set begin/end of monotonic ranges, in both x/y directions signed_size_type index1 = sec1_first_index; move_begin_iterator<0>(it1_first, it1_beyond, index1, - section1.directions[0], section2.bounding_box); + section1.directions[0], section1.bounding_box, section2.bounding_box); move_end_iterator<0>(it1_first, it1_beyond, - section1.directions[0], section2.bounding_box); + section1.directions[0], section1.bounding_box, section2.bounding_box); move_begin_iterator<1>(it1_first, it1_beyond, index1, - section1.directions[1], section2.bounding_box); + section1.directions[1], section1.bounding_box, section2.bounding_box); move_end_iterator<1>(it1_first, it1_beyond, - section1.directions[1], section2.bounding_box); + section1.directions[1], section1.bounding_box, section2.bounding_box); signed_size_type index2 = sec2_first_index; move_begin_iterator<0>(it2_first, it2_beyond, index2, - section2.directions[0], section1.bounding_box); + section2.directions[0], section2.bounding_box, section1.bounding_box); move_end_iterator<0>(it2_first, it2_beyond, - section2.directions[0], section1.bounding_box); + section2.directions[0], section2.bounding_box, section1.bounding_box); move_begin_iterator<1>(it2_first, it2_beyond, index2, - section2.directions[1], section1.bounding_box); + section2.directions[1], section2.bounding_box, section1.bounding_box); move_end_iterator<1>(it2_first, it2_beyond, - section2.directions[1], section1.bounding_box); + section2.directions[1], section2.bounding_box, section1.bounding_box); turn_type the_model; the_model.operations[0].piece_index = piece1.index; diff --git a/include/boost/geometry/algorithms/detail/direction_code.hpp b/include/boost/geometry/algorithms/detail/direction_code.hpp index 26d53ab4e..3a7d3d878 100644 --- a/include/boost/geometry/algorithms/detail/direction_code.hpp +++ b/include/boost/geometry/algorithms/detail/direction_code.hpp @@ -2,10 +2,11 @@ // Copyright (c) 2015 Barend Gehrels, Amsterdam, the Netherlands. -// This file was modified by Oracle on 2015. -// Modifications copyright (c) 2015 Oracle and/or its affiliates. +// This file was modified by Oracle on 2015, 2017. +// Modifications copyright (c) 2015-2017 Oracle and/or its affiliates. // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle +// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle // Use, modification and distribution is subject to the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at @@ -17,14 +18,22 @@ #include #include +#include +#include + +#include + namespace boost { namespace geometry { + #ifndef DOXYGEN_NO_DETAIL namespace detail { + +// TODO: remove template inline int sign_of_difference(Point1 const& point1, Point2 const& point2) { @@ -37,6 +46,193 @@ inline int sign_of_difference(Point1 const& point1, Point2 const& point2) } +template ::type> +struct direction_code_impl +{ + BOOST_MPL_ASSERT_MSG((false), NOT_IMPLEMENTED_FOR_THIS_CS, (CSTag)); +}; + +template +struct direction_code_impl +{ + template + static inline int apply(Point1 const& segment_a, Point1 const& segment_b, + Point2 const& p) + { + typedef typename geometry::select_coordinate_type + < + Point1, Point2 + >::type calc_t; + + if ( (math::equals(geometry::get<0>(segment_b), geometry::get<0>(segment_a)) + && math::equals(geometry::get<1>(segment_b), geometry::get<1>(segment_a))) + || (math::equals(geometry::get<0>(segment_b), geometry::get<0>(p)) + && math::equals(geometry::get<1>(segment_b), geometry::get<1>(p))) ) + { + return 0; + } + + calc_t x1 = geometry::get<0>(segment_b) - geometry::get<0>(segment_a); + calc_t y1 = geometry::get<1>(segment_b) - geometry::get<1>(segment_a); + calc_t x2 = geometry::get<0>(segment_b) - geometry::get<0>(p); + calc_t y2 = geometry::get<1>(segment_b) - geometry::get<1>(p); + + calc_t ax = (std::min)(math::abs(x1), math::abs(x2)); + calc_t ay = (std::min)(math::abs(y1), math::abs(y2)); + + int s1 = 0, s2 = 0; + if (ax >= ay) + { + s1 = x1 > 0 ? 1 : -1; + s2 = x2 > 0 ? 1 : -1; + } + else + { + s1 = y1 > 0 ? 1 : -1; + s2 = y2 > 0 ? 1 : -1; + } + + return s1 == s2 ? -1 : 1; + } +}; + +template +struct direction_code_impl +{ + template + static inline int apply(Point1 const& segment_a, Point1 const& segment_b, + Point2 const& p) + { + typedef typename coordinate_type::type coord1_t; + typedef typename coordinate_type::type coord2_t; + typedef typename coordinate_system::type::units units_t; + typedef typename coordinate_system::type::units units2_t; + BOOST_MPL_ASSERT_MSG((boost::is_same::value), + NOT_IMPLEMENTED_FOR_DIFFERENT_UNITS, + (units_t, units2_t)); + + typedef typename geometry::select_coordinate_type ::type calc_t; + typedef math::detail::constants_on_spheroid constants1; + typedef math::detail::constants_on_spheroid constants2; + static coord1_t const pi_half1 = constants1::max_latitude(); + static coord2_t const pi_half2 = constants2::max_latitude(); + static calc_t const c0 = 0; + + coord1_t const a0 = geometry::get<0>(segment_a); + coord1_t const a1 = geometry::get<1>(segment_a); + coord1_t const b0 = geometry::get<0>(segment_b); + coord1_t const b1 = geometry::get<1>(segment_b); + coord2_t const p0 = geometry::get<0>(p); + coord2_t const p1 = geometry::get<1>(p); + + if ( (math::equals(b0, a0) && math::equals(b1, a1)) + || (math::equals(b0, p0) && math::equals(b1, p1)) ) + { + return 0; + } + + bool const is_a_pole = math::equals(pi_half1, math::abs(a1)); + bool const is_b_pole = math::equals(pi_half1, math::abs(b1)); + bool const is_p_pole = math::equals(pi_half2, math::abs(p1)); + + if ( is_b_pole && ((is_a_pole && math::sign(b1) == math::sign(a1)) + || (is_p_pole && math::sign(b1) == math::sign(p1))) ) + { + return 0; + } + + // NOTE: as opposed to the implementation for cartesian CS + // here point b is the origin + + calc_t const dlon1 = math::longitude_distance_signed(b0, a0); + calc_t const dlon2 = math::longitude_distance_signed(b0, p0); + + bool is_antilon1 = false, is_antilon2 = false; + calc_t const dlat1 = latitude_distance_signed(b1, a1, dlon1, is_antilon1); + calc_t const dlat2 = latitude_distance_signed(b1, p1, dlon2, is_antilon2); + + calc_t mx = is_a_pole || is_b_pole || is_p_pole ? + c0 : + (std::min)(is_antilon1 ? c0 : math::abs(dlon1), + is_antilon2 ? c0 : math::abs(dlon2)); + calc_t my = (std::min)(math::abs(dlat1), + math::abs(dlat2)); + + int s1 = 0, s2 = 0; + if (mx >= my) + { + s1 = dlon1 > 0 ? 1 : -1; + s2 = dlon2 > 0 ? 1 : -1; + } + else + { + s1 = dlat1 > 0 ? 1 : -1; + s2 = dlat2 > 0 ? 1 : -1; + } + + return s1 == s2 ? -1 : 1; + } + + template + static inline T latitude_distance_signed(T const& lat1, T const& lat2, T const& lon_ds, bool & is_antilon) + { + typedef math::detail::constants_on_spheroid constants; + static T const pi = constants::half_period(); + static T const c0 = 0; + + T res = lat2 - lat1; + + is_antilon = math::equals(math::abs(lon_ds), pi); + if (is_antilon) + { + res = lat2 + lat1; + if (res >= c0) + res = pi - res; + else + res = -pi - res; + } + + return res; + } +}; + +template +struct direction_code_impl +{ + template + static inline int apply(Point1 segment_a, Point1 segment_b, + Point2 p) + { + typedef math::detail::constants_on_spheroid + < + typename coordinate_type::type, + typename coordinate_system::type::units + > constants1; + typedef math::detail::constants_on_spheroid + < + typename coordinate_type::type, + typename coordinate_system::type::units + > constants2; + + geometry::set<1>(segment_a, + constants1::max_latitude() - geometry::get<1>(segment_a)); + geometry::set<1>(segment_b, + constants1::max_latitude() - geometry::get<1>(segment_b)); + geometry::set<1>(p, + constants2::max_latitude() - geometry::get<1>(p)); + + return direction_code_impl + < + Point, spherical_equatorial_tag + >::apply(segment_a, segment_b, p); + } +}; + +template +struct direction_code_impl + : direction_code_impl +{}; + // Gives sense of direction for point p, collinear w.r.t. segment (a,b) // Returns -1 if p goes backward w.r.t (a,b), so goes from b in direction of a // Returns 1 if p goes forward, so extends (a,b) @@ -44,28 +240,9 @@ inline int sign_of_difference(Point1 const& point1, Point2 const& point2) // Note that it does not do any collinearity test, that should be done before template inline int direction_code(Point1 const& segment_a, Point1 const& segment_b, - const Point2& p) + Point2 const& p) { - // Suppose segment = (4 3,4 4) and p =(4 2) - // Then sign_a1 = 1 and sign_p1 = 1 -> goes backward -> return -1 - - int const sign_a0 = sign_of_difference<0>(segment_b, segment_a); - int const sign_a1 = sign_of_difference<1>(segment_b, segment_a); - - if (sign_a0 == 0 && sign_a1 == 0) - { - return 0; - } - - int const sign_p0 = sign_of_difference<0>(segment_b, p); - int const sign_p1 = sign_of_difference<1>(segment_b, p); - - if (sign_p0 == 0 && sign_p1 == 0) - { - return 0; - } - - return sign_a0 == sign_p0 && sign_a1 == sign_p1 ? -1 : 1; + return direction_code_impl::apply(segment_a, segment_b, p); } @@ -73,7 +250,6 @@ inline int direction_code(Point1 const& segment_a, Point1 const& segment_b, #endif //DOXYGEN_NO_DETAIL - }} // namespace boost::geometry #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_DIRECITON_CODE_HPP diff --git a/include/boost/geometry/algorithms/detail/extreme_points.hpp b/include/boost/geometry/algorithms/detail/extreme_points.hpp index 65795cd05..61e984ee3 100644 --- a/include/boost/geometry/algorithms/detail/extreme_points.hpp +++ b/include/boost/geometry/algorithms/detail/extreme_points.hpp @@ -5,6 +5,11 @@ // Copyright (c) 2009-2013 Mateusz Loskot, London, UK. // Copyright (c) 2013-2014 Adam Wulkiewicz, Lodz, Poland. +// This file was modified by Oracle on 2017. +// Modifications copyright (c) 2017 Oracle and/or its affiliates. + +// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle + // Use, modification and distribution is subject to the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) @@ -117,12 +122,6 @@ struct extreme_points_on_ring typedef typename boost::range_iterator::type range_iterator; typedef typename geometry::point_type::type point_type; - typedef typename geometry::strategy::side::services::default_strategy - < - typename geometry::cs_tag::type - >::type side_strategy; - - template static inline bool extend(CirclingIterator& it, std::size_t n, @@ -214,10 +213,11 @@ struct extreme_points_on_ring return true; } - template + template static inline void get_intruders(Ring const& ring, CirclingIterator left, CirclingIterator right, Extremes const& extremes, - Intruders& intruders) + Intruders& intruders, + SideStrategy const& strategy) { if (boost::size(extremes) < 3) { @@ -238,8 +238,8 @@ struct extreme_points_on_ring if (coordinate > min_value && other_coordinate > other_min && other_coordinate < other_max) { int const factor = geometry::point_order::value == geometry::clockwise ? 1 : -1; - int const first_side = side_strategy::apply(*right, extremes.front(), *(extremes.begin() + 1)) * factor; - int const last_side = side_strategy::apply(*right, *(extremes.rbegin() + 1), extremes.back()) * factor; + int const first_side = strategy.apply(*right, extremes.front(), *(extremes.begin() + 1)) * factor; + int const last_side = strategy.apply(*right, *(extremes.rbegin() + 1), extremes.back()) * factor; // If not lying left from any of the extemes side if (first_side != 1 && last_side != 1) @@ -263,10 +263,11 @@ struct extreme_points_on_ring } } - template + template static inline void get_intruders(Ring const& ring, Extremes const& extremes, - Intruders& intruders) + Intruders& intruders, + SideStrategy const& strategy) { std::size_t const n = boost::size(ring); if (n >= 3) @@ -275,12 +276,12 @@ struct extreme_points_on_ring geometry::ever_circling_range_iterator right(ring); ++right; - get_intruders(ring, left, right, extremes, intruders); + get_intruders(ring, left, right, extremes, intruders, strategy); } } - template - static inline bool right_turn(Ring const& ring, Iterator it) + template + static inline bool right_turn(Ring const& ring, Iterator it, SideStrategy const& strategy) { typename std::iterator_traits::difference_type const index = std::distance(boost::begin(ring), it); @@ -295,8 +296,8 @@ struct extreme_points_on_ring } int const factor = geometry::point_order::value == geometry::clockwise ? 1 : -1; - int const first_side = side_strategy::apply(*(right - 1), *right, *left) * factor; - int const last_side = side_strategy::apply(*left, *(left + 1), *right) * factor; + int const first_side = strategy.apply(*(right - 1), *right, *left) * factor; + int const last_side = strategy.apply(*left, *(left + 1), *right) * factor; //std::cout << "Candidate at " << geometry::wkt(*it) << " first=" << first_side << " last=" << last_side << std::endl; @@ -306,8 +307,11 @@ struct extreme_points_on_ring // Gets the extreme segments (top point plus neighbouring points), plus intruders, if any, on the same ring - template - static inline bool apply(Ring const& ring, Extremes& extremes, Intruders& intruders) + template + static inline bool apply(Ring const& ring, + Extremes& extremes, + Intruders& intruders, + SideStrategy const& strategy) { std::size_t const n = boost::size(ring); if (n < 3) @@ -321,7 +325,7 @@ struct extreme_points_on_ring compare smaller; for (range_iterator it = max_it + 1; it != boost::end(ring); ++it) { - if (smaller(*max_it, *it) && right_turn(ring, it)) + if (smaller(*max_it, *it) && right_turn(ring, it, strategy)) { max_it = it; } @@ -365,7 +369,7 @@ struct extreme_points_on_ring std::copy(points.begin(), points.end(), std::back_inserter(extremes)); - get_intruders(ring, left, right, extremes, intruders); + get_intruders(ring, left, right, extremes, intruders, strategy); return true; } @@ -403,8 +407,9 @@ struct extreme_points template struct extreme_points { - template - static inline bool apply(Polygon const& polygon, Extremes& extremes, Intruders& intruders) + template + static inline bool apply(Polygon const& polygon, Extremes& extremes, Intruders& intruders, + SideStrategy const& strategy) { typedef typename geometry::ring_type::type ring_type; typedef detail::extreme_points::extreme_points_on_ring @@ -412,7 +417,8 @@ struct extreme_points ring_type, Dimension > ring_implementation; - if (! ring_implementation::apply(geometry::exterior_ring(polygon), extremes, intruders)) + if (! ring_implementation::apply(geometry::exterior_ring(polygon), + extremes, intruders, strategy)) { return false; } @@ -423,7 +429,7 @@ struct extreme_points for (typename detail::interior_iterator::type it = boost::begin(rings); it != boost::end(rings); ++it) { - ring_implementation::get_intruders(*it, extremes, intruders); + ring_implementation::get_intruders(*it, extremes, intruders, strategy); } return true; @@ -433,8 +439,9 @@ struct extreme_points template struct extreme_points { - template - static inline bool apply(Box const& box, Extremes& extremes, Intruders& ) + template + static inline bool apply(Box const& box, Extremes& extremes, Intruders& , + SideStrategy const& ) { extremes.resize(4); geometry::detail::assign_box_corners_oriented(box, extremes); @@ -446,8 +453,9 @@ struct extreme_points template struct extreme_points { - template - static inline bool apply(Box const& box, Extremes& extremes, Intruders& ) + template + static inline bool apply(Box const& box, Extremes& extremes, Intruders& , + SideStrategy const& ) { extremes.resize(4); geometry::detail::assign_box_corners_oriented(box, extremes); @@ -460,8 +468,9 @@ struct extreme_points template struct extreme_points { - template - static inline bool apply(MultiPolygon const& multi, Extremes& extremes, Intruders& intruders) + template + static inline bool apply(MultiPolygon const& multi, Extremes& extremes, + Intruders& intruders, SideStrategy const& strategy) { // Get one for the very first polygon, that is (for the moment) enough. // It is not guaranteed the "extreme" then, but for the current purpose @@ -473,7 +482,7 @@ struct extreme_points typename boost::range_value::type, Dimension, polygon_tag - >::apply(*boost::begin(multi), extremes, intruders); + >::apply(*boost::begin(multi), extremes, intruders, strategy); } return false; @@ -489,8 +498,18 @@ struct extreme_points for Edge=0 in dimension 0, the right side) \note We could specify a strategy (less/greater) to get bottom/left side too. However, until now we don't need that. */ -template -inline bool extreme_points(Geometry const& geometry, Extremes& extremes, Intruders& intruders) +template +< + std::size_t Edge, + typename Geometry, + typename Extremes, + typename Intruders, + typename SideStrategy +> +inline bool extreme_points(Geometry const& geometry, + Extremes& extremes, + Intruders& intruders, + SideStrategy const& strategy) { concepts::check(); @@ -509,7 +528,11 @@ inline bool extreme_points(Geometry const& geometry, Extremes& extremes, Intrude const >(); - return dispatch::extreme_points::apply(geometry, extremes, intruders); + return dispatch::extreme_points + < + Geometry, + Edge + >::apply(geometry, extremes, intruders, strategy); } diff --git a/include/boost/geometry/algorithms/detail/get_left_turns.hpp b/include/boost/geometry/algorithms/detail/get_left_turns.hpp index 95ab98c23..e9f6a5085 100644 --- a/include/boost/geometry/algorithms/detail/get_left_turns.hpp +++ b/include/boost/geometry/algorithms/detail/get_left_turns.hpp @@ -2,6 +2,11 @@ // Copyright (c) 2012-2014 Barend Gehrels, Amsterdam, the Netherlands. +// This file was modified by Oracle on 2017. +// Modifications copyright (c) 2017, Oracle and/or its affiliates. + +// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle + // Use, modification and distribution is subject to the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) @@ -60,17 +65,14 @@ inline int squared_length(Vector const& vector) } -template +template struct angle_less { typedef Point vector_type; - typedef typename strategy::side::services::default_strategy - < - typename cs_tag::type - >::type side_strategy_type; - angle_less(Point const& origin) + angle_less(Point const& origin, SideStrategy const& strategy) : m_origin(origin) + , m_strategy(strategy) {} template @@ -89,8 +91,7 @@ struct angle_less return quadrant_p < quadrant_q; } // Same quadrant, check if p is located left of q - int const side = side_strategy_type::apply(m_origin, q.point, - p.point); + int const side = m_strategy.apply(m_origin, q.point, p.point); if (side != 0) { return side == 1; @@ -114,19 +115,17 @@ struct angle_less private: Point m_origin; + SideStrategy m_strategy; }; -template +template struct angle_equal_to { typedef Point vector_type; - typedef typename strategy::side::services::default_strategy - < - typename cs_tag::type - >::type side_strategy_type; - - inline angle_equal_to(Point const& origin) + + inline angle_equal_to(Point const& origin, SideStrategy const& strategy) : m_origin(origin) + , m_strategy(strategy) {} template @@ -143,13 +142,13 @@ struct angle_equal_to return false; } // Same quadrant, check if p/q are collinear - int const side = side_strategy_type::apply(m_origin, q.point, - p.point); + int const side = m_strategy.apply(m_origin, q.point, p.point); return side == 0; } private: Point m_origin; + SideStrategy m_strategy; }; template @@ -193,13 +192,14 @@ inline void get_left_turns(AngleCollection const& sorted_angles, //! Returns the number of clusters -template -inline std::size_t assign_cluster_indices(AngleCollection& sorted, Point const& origin) +template +inline std::size_t assign_cluster_indices(AngleCollection& sorted, Point const& origin, + SideStrategy const& strategy) { // Assign same cluster_index for all turns in same direction BOOST_GEOMETRY_ASSERT(boost::size(sorted) >= 4u); - angle_equal_to comparator(origin); + angle_equal_to comparator(origin, strategy); typename boost::range_iterator::type it = sorted.begin(); std::size_t cluster_index = 0; diff --git a/include/boost/geometry/algorithms/detail/is_simple/linear.hpp b/include/boost/geometry/algorithms/detail/is_simple/linear.hpp index 5852ed071..5acf56c5b 100644 --- a/include/boost/geometry/algorithms/detail/is_simple/linear.hpp +++ b/include/boost/geometry/algorithms/detail/is_simple/linear.hpp @@ -236,7 +236,9 @@ inline bool has_self_intersections(Linear const& linear, Strategy const& strateg template struct is_simple_linestring { - static inline bool apply(Linestring const& linestring) + template + static inline bool apply(Linestring const& linestring, + Strategy const& strategy) { simplicity_failure_policy policy; return ! boost::empty(linestring) @@ -247,7 +249,7 @@ struct is_simple_linestring && ! detail::is_valid::has_spikes < Linestring, closed - >::apply(linestring, policy); + >::apply(linestring, policy, strategy.get_side_strategy()); } }; @@ -258,7 +260,10 @@ struct is_simple_linestring static inline bool apply(Linestring const& linestring, Strategy const& strategy) { - return is_simple_linestring::apply(linestring) + return is_simple_linestring + < + Linestring, false + >::apply(linestring, strategy) && ! has_self_intersections(linestring, strategy); } }; @@ -267,23 +272,44 @@ struct is_simple_linestring template struct is_simple_multilinestring { +private: + template + struct per_linestring + { + per_linestring(Strategy const& strategy) + : m_strategy(strategy) + {} + + template + inline bool apply(Linestring const& linestring) const + { + return detail::is_simple::is_simple_linestring + < + Linestring, + false // do not compute self-intersections + >::apply(linestring, m_strategy); + } + + Strategy const& m_strategy; + }; + +public: template static inline bool apply(MultiLinestring const& multilinestring, Strategy const& strategy) { + typedef per_linestring per_ls; + // check each of the linestrings for simplicity // but do not compute self-intersections yet; these will be // computed for the entire multilinestring if ( ! detail::check_iterator_range < - is_simple_linestring - < - typename boost::range_value::type, - false // do not compute self-intersections - >, + per_ls, // do not compute self-intersections true // allow empty multilinestring >::apply(boost::begin(multilinestring), - boost::end(multilinestring)) + boost::end(multilinestring), + per_ls(strategy)) ) { return false; diff --git a/include/boost/geometry/algorithms/detail/is_valid/has_spikes.hpp b/include/boost/geometry/algorithms/detail/is_valid/has_spikes.hpp index aa90e52db..96efec79c 100644 --- a/include/boost/geometry/algorithms/detail/is_valid/has_spikes.hpp +++ b/include/boost/geometry/algorithms/detail/is_valid/has_spikes.hpp @@ -1,8 +1,9 @@ // Boost.Geometry (aka GGL, Generic Geometry Library) -// Copyright (c) 2014-2015, Oracle and/or its affiliates. +// Copyright (c) 2014-2017, Oracle and/or its affiliates. // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle +// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle // Licensed under the Boost Software License version 1.0. // http://www.boost.org/users/license.html @@ -91,8 +92,9 @@ struct has_spikes return std::find_if(second, last, not_equal(*first)); } - template - static inline bool apply(Range const& range, VisitPolicy& visitor) + template + static inline bool apply(Range const& range, VisitPolicy& visitor, + SideStrategy const& strategy) { boost::ignore_unused(visitor); @@ -124,9 +126,8 @@ struct has_spikes while (next != boost::end(view)) { - if ( geometry::detail::point_is_spike_or_equal(*prev, - *next, - *cur) ) + if ( geometry::detail::point_is_spike_or_equal(*prev, *next, *cur, + strategy) ) { return ! visitor.template apply(is_linear, *cur); @@ -146,7 +147,7 @@ struct has_spikes boost::rend(view)); iterator next = find_different_from_first(cur, boost::end(view)); - if (detail::point_is_spike_or_equal(*prev, *next, *cur)) + if (detail::point_is_spike_or_equal(*prev, *next, *cur, strategy)) { return ! visitor.template apply(is_linear, *cur); diff --git a/include/boost/geometry/algorithms/detail/is_valid/linear.hpp b/include/boost/geometry/algorithms/detail/is_valid/linear.hpp index 6bc6b86cf..39cb36ef5 100644 --- a/include/boost/geometry/algorithms/detail/is_valid/linear.hpp +++ b/include/boost/geometry/algorithms/detail/is_valid/linear.hpp @@ -43,9 +43,10 @@ namespace detail { namespace is_valid template struct is_valid_linestring { - template + template static inline bool apply(Linestring const& linestring, - VisitPolicy& visitor) + VisitPolicy& visitor, + Strategy const& strategy) { if (has_invalid_coordinate::apply(linestring, visitor)) { @@ -75,15 +76,12 @@ struct is_valid_linestring { return visitor.template apply(); } - return ! has_spikes::apply(linestring, visitor); - } - template - static inline bool apply(Linestring const& linestring, - VisitPolicy& visitor, - Strategy const&) - { - return apply(linestring, visitor); + return ! has_spikes + < + Linestring, closed + >::apply(linestring, visitor, + strategy.get_side_strategy()); } }; @@ -132,10 +130,13 @@ class is_valid > { private: - template + template struct per_linestring { - per_linestring(VisitPolicy& policy) : m_policy(policy) {} + per_linestring(VisitPolicy& policy, Strategy const& strategy) + : m_policy(policy) + , m_strategy(strategy) + {} template inline bool apply(Linestring const& linestring) const @@ -143,17 +144,18 @@ private: return detail::is_valid::is_valid_linestring < Linestring - >::apply(linestring, m_policy); + >::apply(linestring, m_policy, m_strategy); } VisitPolicy& m_policy; + Strategy const& m_strategy; }; public: template static inline bool apply(MultiLinestring const& multilinestring, VisitPolicy& visitor, - Strategy const&) + Strategy const& strategy) { if (BOOST_GEOMETRY_CONDITION( AllowEmptyMultiGeometries && boost::empty(multilinestring))) @@ -161,13 +163,15 @@ public: return visitor.template apply(); } + typedef per_linestring per_ls; + return detail::check_iterator_range < - per_linestring, + per_ls, false // do not check for empty multilinestring (done above) >::apply(boost::begin(multilinestring), boost::end(multilinestring), - per_linestring(visitor)); + per_ls(visitor, strategy)); } }; diff --git a/include/boost/geometry/algorithms/detail/is_valid/ring.hpp b/include/boost/geometry/algorithms/detail/is_valid/ring.hpp index 996da7d96..0b9595043 100644 --- a/include/boost/geometry/algorithms/detail/is_valid/ring.hpp +++ b/include/boost/geometry/algorithms/detail/is_valid/ring.hpp @@ -198,7 +198,7 @@ struct is_valid_ring return is_topologically_closed::apply(ring, visitor) && ! has_duplicates::apply(ring, visitor) - && ! has_spikes::apply(ring, visitor) + && ! has_spikes::apply(ring, visitor, strategy.get_side_strategy()) && (! CheckSelfIntersections || has_valid_self_turns::apply(ring, visitor, strategy)) && is_properly_oriented::apply(ring, visitor, strategy); diff --git a/include/boost/geometry/algorithms/detail/occupation_info.hpp b/include/boost/geometry/algorithms/detail/occupation_info.hpp index 4048d59d7..fc74f0cc7 100644 --- a/include/boost/geometry/algorithms/detail/occupation_info.hpp +++ b/include/boost/geometry/algorithms/detail/occupation_info.hpp @@ -2,6 +2,11 @@ // Copyright (c) 2012-2014 Barend Gehrels, Amsterdam, the Netherlands. +// This file was modified by Oracle on 2017. +// Modifications copyright (c) 2017, Oracle and/or its affiliates. + +// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle + // Use, modification and distribution is subject to the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) @@ -99,12 +104,18 @@ public : } } - template - inline void get_left_turns(RobustPoint const& origin, Turns& turns) + template + inline void get_left_turns(RobustPoint const& origin, Turns& turns, + SideStrategy const& strategy) { + typedef detail::left_turns::angle_less + < + typename AngleInfo::point_type, + SideStrategy + > angle_less; + // Sort on angle - std::sort(m_angles.begin(), m_angles.end(), - detail::left_turns::angle_less(origin)); + std::sort(m_angles.begin(), m_angles.end(), angle_less(origin, strategy)); // Group same-angled elements std::size_t cluster_size = detail::left_turns::assign_cluster_indices(m_angles, origin); diff --git a/include/boost/geometry/algorithms/detail/overlay/append_no_dups_or_spikes.hpp b/include/boost/geometry/algorithms/detail/overlay/append_no_dups_or_spikes.hpp index 03c06c28d..fb7384079 100644 --- a/include/boost/geometry/algorithms/detail/overlay/append_no_dups_or_spikes.hpp +++ b/include/boost/geometry/algorithms/detail/overlay/append_no_dups_or_spikes.hpp @@ -2,8 +2,8 @@ // Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. -// This file was modified by Oracle on 2014. -// Modifications copyright (c) 2014 Oracle and/or its affiliates. +// This file was modified by Oracle on 2014, 2017. +// Modifications copyright (c) 2014-2017 Oracle and/or its affiliates. // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle @@ -63,8 +63,9 @@ inline bool points_equal_or_close(Point1 const& point1, } -template +template inline void append_no_dups_or_spikes(Range& range, Point const& point, + SideStrategy const& strategy, RobustPolicy const& robust_policy) { #ifdef BOOST_GEOMETRY_DEBUG_INTERSECTION @@ -92,6 +93,7 @@ inline void append_no_dups_or_spikes(Range& range, Point const& point, && point_is_spike_or_equal(point, *(boost::end(range) - 3), *(boost::end(range) - 2), + strategy, robust_policy)) { // Use the Concept/traits, so resize and append again @@ -100,8 +102,9 @@ inline void append_no_dups_or_spikes(Range& range, Point const& point, } } -template +template inline void clean_closing_dups_and_spikes(Range& range, + SideStrategy const& strategy, RobustPolicy const& robust_policy) { std::size_t const minsize @@ -135,7 +138,7 @@ inline void clean_closing_dups_and_spikes(Range& range, // Check if closing point is a spike (this is so if the second point is // considered as a spike w.r.t. the last segment) - if (point_is_spike_or_equal(*second, *ultimate, *first, robust_policy)) + if (point_is_spike_or_equal(*second, *ultimate, *first, strategy, robust_policy)) { range::erase(range, first); if (BOOST_GEOMETRY_CONDITION(closed)) diff --git a/include/boost/geometry/algorithms/detail/overlay/copy_segments.hpp b/include/boost/geometry/algorithms/detail/overlay/copy_segments.hpp index a056d4fa3..c6f540a97 100644 --- a/include/boost/geometry/algorithms/detail/overlay/copy_segments.hpp +++ b/include/boost/geometry/algorithms/detail/overlay/copy_segments.hpp @@ -2,8 +2,8 @@ // Copyright (c) 2007-2014 Barend Gehrels, Amsterdam, the Netherlands. -// This file was modified by Oracle on 2014. -// Modifications copyright (c) 2014 Oracle and/or its affiliates. +// This file was modified by Oracle on 2014, 2017. +// Modifications copyright (c) 2014-2017 Oracle and/or its affiliates. // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle @@ -57,12 +57,14 @@ struct copy_segments_ring < typename Ring, typename SegmentIdentifier, + typename SideStrategy, typename RobustPolicy, typename RangeOut > static inline void apply(Ring const& ring, SegmentIdentifier const& seg_id, signed_size_type to_index, + SideStrategy const& strategy, RobustPolicy const& robust_policy, RangeOut& current_output) { @@ -109,7 +111,7 @@ struct copy_segments_ring for (signed_size_type i = 0; i < count; ++i, ++it) { - detail::overlay::append_no_dups_or_spikes(current_output, *it, robust_policy); + detail::overlay::append_no_dups_or_spikes(current_output, *it, strategy, robust_policy); } } }; @@ -119,20 +121,23 @@ class copy_segments_linestring { private: // remove spikes - template + template static inline void append_to_output(RangeOut& current_output, Point const& point, + SideStrategy const& strategy, RobustPolicy const& robust_policy, boost::true_type const&) { detail::overlay::append_no_dups_or_spikes(current_output, point, + strategy, robust_policy); } // keep spikes - template + template static inline void append_to_output(RangeOut& current_output, Point const& point, + SideStrategy const&, RobustPolicy const&, boost::false_type const&) { @@ -144,12 +149,14 @@ public: < typename LineString, typename SegmentIdentifier, + typename SideStrategy, typename RobustPolicy, typename RangeOut > static inline void apply(LineString const& ls, SegmentIdentifier const& seg_id, signed_size_type to_index, + SideStrategy const& strategy, RobustPolicy const& robust_policy, RangeOut& current_output) { @@ -170,7 +177,7 @@ public: for (signed_size_type i = 0; i < count; ++i, ++it) { - append_to_output(current_output, *it, robust_policy, + append_to_output(current_output, *it, strategy, robust_policy, boost::integral_constant()); } } @@ -183,12 +190,14 @@ struct copy_segments_polygon < typename Polygon, typename SegmentIdentifier, + typename SideStrategy, typename RobustPolicy, typename RangeOut > static inline void apply(Polygon const& polygon, SegmentIdentifier const& seg_id, signed_size_type to_index, + SideStrategy const& strategy, RobustPolicy const& robust_policy, RangeOut& current_output) { @@ -199,6 +208,7 @@ struct copy_segments_polygon ? geometry::exterior_ring(polygon) : range::at(geometry::interior_rings(polygon), seg_id.ring_index), seg_id, to_index, + strategy, robust_policy, current_output ); @@ -213,12 +223,14 @@ struct copy_segments_box < typename Box, typename SegmentIdentifier, + typename SideStrategy, typename RobustPolicy, typename RangeOut > static inline void apply(Box const& box, SegmentIdentifier const& seg_id, signed_size_type to_index, + SideStrategy const& strategy, RobustPolicy const& robust_policy, RangeOut& current_output) { @@ -239,7 +251,7 @@ struct copy_segments_box for (signed_size_type i = 0; i < count; i++, index++) { detail::overlay::append_no_dups_or_spikes(current_output, - bp[index % 5], robust_policy); + bp[index % 5], strategy, robust_policy); } } @@ -253,12 +265,14 @@ struct copy_segments_multi < typename MultiGeometry, typename SegmentIdentifier, + typename SideStrategy, typename RobustPolicy, typename RangeOut > static inline void apply(MultiGeometry const& multi_geometry, SegmentIdentifier const& seg_id, signed_size_type to_index, + SideStrategy const& strategy, RobustPolicy const& robust_policy, RangeOut& current_output) { @@ -272,6 +286,7 @@ struct copy_segments_multi // Call the single-version Policy::apply(range::at(multi_geometry, seg_id.multi_index), seg_id, to_index, + strategy, robust_policy, current_output); } @@ -341,12 +356,14 @@ template bool Reverse, typename Geometry, typename SegmentIdentifier, + typename SideStrategy, typename RobustPolicy, typename RangeOut > inline void copy_segments(Geometry const& geometry, SegmentIdentifier const& seg_id, signed_size_type to_index, + SideStrategy const& strategy, RobustPolicy const& robust_policy, RangeOut& range_out) { @@ -356,7 +373,7 @@ inline void copy_segments(Geometry const& geometry, < typename tag::type, Reverse - >::apply(geometry, seg_id, to_index, robust_policy, range_out); + >::apply(geometry, seg_id, to_index, strategy, robust_policy, range_out); } diff --git a/include/boost/geometry/algorithms/detail/overlay/enrich_intersection_points.hpp b/include/boost/geometry/algorithms/detail/overlay/enrich_intersection_points.hpp index 709382edb..d74e7ae22 100644 --- a/include/boost/geometry/algorithms/detail/overlay/enrich_intersection_points.hpp +++ b/include/boost/geometry/algorithms/detail/overlay/enrich_intersection_points.hpp @@ -2,6 +2,11 @@ // Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. +// This file was modified by Oracle on 2017. +// Modifications copyright (c) 2017 Oracle and/or its affiliates. + +// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle + // Use, modification and distribution is subject to the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) @@ -59,7 +64,7 @@ template typename Turns, typename Geometry1, typename Geometry2, typename RobustPolicy, - typename Strategy + typename SideStrategy > inline void enrich_sort(Operations& operations, Turns const& turns, @@ -67,7 +72,7 @@ inline void enrich_sort(Operations& operations, Geometry1 const& geometry1, Geometry2 const& geometry2, RobustPolicy const& robust_policy, - Strategy const& /*strategy*/) + SideStrategy const& strategy) { std::sort(boost::begin(operations), boost::end(operations), @@ -77,8 +82,9 @@ inline void enrich_sort(Operations& operations, typename boost::range_value::type, Geometry1, Geometry2, RobustPolicy, + SideStrategy, Reverse1, Reverse2 - >(turns, for_operation, geometry1, geometry2, robust_policy)); + >(turns, for_operation, geometry1, geometry2, robust_policy, strategy)); } @@ -275,7 +281,7 @@ inline void calculate_remaining_distance(Turns& turns) \tparam Clusters type of cluster container \tparam Geometry1 \tparam_geometry \tparam Geometry2 \tparam_geometry -\tparam Strategy side strategy type +\tparam SideStrategy side strategy type \param turns container containing intersection points \param clusters container containing clusters \param geometry1 \param_geometry @@ -291,13 +297,13 @@ template typename Clusters, typename Geometry1, typename Geometry2, typename RobustPolicy, - typename Strategy + typename SideStrategy > inline void enrich_intersection_points(Turns& turns, Clusters& clusters, Geometry1 const& geometry1, Geometry2 const& geometry2, RobustPolicy const& robust_policy, - Strategy const& strategy) + SideStrategy const& strategy) { static const detail::overlay::operation_type target_operation = detail::overlay::operation_from_overlay::value; @@ -420,7 +426,8 @@ inline void enrich_intersection_points(Turns& turns, Reverse1, Reverse2, OverlayType - >(clusters, turns, target_operation, geometry1, geometry2); + >(clusters, turns, target_operation, + geometry1, geometry2, strategy); detail::overlay::cleanup_clusters(turns, clusters); } diff --git a/include/boost/geometry/algorithms/detail/overlay/follow.hpp b/include/boost/geometry/algorithms/detail/overlay/follow.hpp index e2de429af..589e12cc2 100644 --- a/include/boost/geometry/algorithms/detail/overlay/follow.hpp +++ b/include/boost/geometry/algorithms/detail/overlay/follow.hpp @@ -157,6 +157,7 @@ struct action_selector typename LineString, typename Point, typename Operation, + typename SideStrategy, typename RobustPolicy > static inline void enter(LineStringOut& current_piece, @@ -164,6 +165,7 @@ struct action_selector segment_identifier& segment_id, signed_size_type , Point const& point, Operation const& operation, + SideStrategy const& , RobustPolicy const& , OutputIterator& ) { @@ -180,6 +182,7 @@ struct action_selector typename LineString, typename Point, typename Operation, + typename SideStrategy, typename RobustPolicy > static inline void leave(LineStringOut& current_piece, @@ -187,6 +190,7 @@ struct action_selector segment_identifier& segment_id, signed_size_type index, Point const& point, Operation const& , + SideStrategy const& strategy, RobustPolicy const& robust_policy, OutputIterator& out) { @@ -195,7 +199,7 @@ struct action_selector detail::copy_segments::copy_segments_linestring < false, RemoveSpikes - >::apply(linestring, segment_id, index, robust_policy, current_piece); + >::apply(linestring, segment_id, index, strategy, robust_policy, current_piece); detail::overlay::append_no_duplicates(current_piece, point); if (::boost::size(current_piece) > 1) { @@ -254,6 +258,7 @@ struct action_selector typename LineString, typename Point, typename Operation, + typename SideStrategy, typename RobustPolicy > static inline void enter(LineStringOut& current_piece, @@ -261,11 +266,12 @@ struct action_selector segment_identifier& segment_id, signed_size_type index, Point const& point, Operation const& operation, + SideStrategy const& strategy, RobustPolicy const& robust_policy, OutputIterator& out) { normal_action::leave(current_piece, linestring, segment_id, index, - point, operation, robust_policy, out); + point, operation, strategy, robust_policy, out); } template @@ -275,6 +281,7 @@ struct action_selector typename LineString, typename Point, typename Operation, + typename SideStrategy, typename RobustPolicy > static inline void leave(LineStringOut& current_piece, @@ -282,11 +289,12 @@ struct action_selector segment_identifier& segment_id, signed_size_type index, Point const& point, Operation const& operation, + SideStrategy const& strategy, RobustPolicy const& robust_policy, OutputIterator& out) { normal_action::enter(current_piece, linestring, segment_id, index, - point, operation, robust_policy, out); + point, operation, strategy, robust_policy, out); } template @@ -456,7 +464,7 @@ public : entered = true; action::enter(current_piece, linestring, current_segment_id, iit->seg_id.segment_index, it->point, *iit, - robust_policy, + strategy, robust_policy, out); } else if (following::is_leaving(*it, *iit, entered, first, linestring, polygon, pt_in_poly_strategy)) @@ -466,7 +474,7 @@ public : entered = false; action::leave(current_piece, linestring, current_segment_id, iit->seg_id.segment_index, it->point, *iit, - robust_policy, + strategy, robust_policy, out); } first = false; @@ -480,7 +488,7 @@ public : >::apply(linestring, current_segment_id, static_cast(boost::size(linestring) - 1), - robust_policy, + strategy, robust_policy, current_piece); } diff --git a/include/boost/geometry/algorithms/detail/overlay/follow_linear_linear.hpp b/include/boost/geometry/algorithms/detail/overlay/follow_linear_linear.hpp index c249ff57f..2a374bf0b 100644 --- a/include/boost/geometry/algorithms/detail/overlay/follow_linear_linear.hpp +++ b/include/boost/geometry/algorithms/detail/overlay/follow_linear_linear.hpp @@ -2,12 +2,14 @@ // Copyright (c) 2017 Adam Wulkiewicz, Lodz, Poland. -// Copyright (c) 2014-2015, Oracle and/or its affiliates. +// Copyright (c) 2014-2017, Oracle and/or its affiliates. + +// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle +// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle // Licensed under the Boost Software License version 1.0. // http://www.boost.org/users/license.html -// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_FOLLOW_LINEAR_LINEAR_HPP #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_FOLLOW_LINEAR_LINEAR_HPP @@ -183,7 +185,8 @@ protected: typename TurnIterator, typename TurnOperationIterator, typename SegmentIdentifier, - typename OutputIterator + typename OutputIterator, + typename SideStrategy > static inline OutputIterator process_turn(TurnIterator it, @@ -193,7 +196,8 @@ protected: Linestring const& linestring, LinestringOut& current_piece, SegmentIdentifier& current_segment_id, - OutputIterator oit) + OutputIterator oit, + SideStrategy const& strategy) { // We don't rescale linear/linear detail::no_rescale_policy robust_policy; @@ -208,7 +212,7 @@ protected: action::enter(current_piece, linestring, current_segment_id, op_it->seg_id.segment_index, - it->point, *op_it, robust_policy, oit); + it->point, *op_it, strategy, robust_policy, oit); } ++enter_count; } @@ -223,7 +227,7 @@ protected: action::leave(current_piece, linestring, current_segment_id, op_it->seg_id.segment_index, - it->point, *op_it, robust_policy, oit); + it->point, *op_it, strategy, robust_policy, oit); } } else if ( FollowIsolatedPoints @@ -249,14 +253,16 @@ protected: template < typename SegmentIdentifier, - typename OutputIterator + typename OutputIterator, + typename SideStrategy > static inline OutputIterator process_end(bool entered, Linestring const& linestring, SegmentIdentifier const& current_segment_id, LinestringOut& current_piece, - OutputIterator oit) + OutputIterator oit, + SideStrategy const& strategy) { if ( action::is_entered(entered) ) { @@ -269,6 +275,7 @@ protected: >::apply(linestring, current_segment_id, static_cast(boost::size(linestring) - 1), + strategy, robust_policy, current_piece); } @@ -283,11 +290,12 @@ protected: } public: - template + template static inline OutputIterator apply(Linestring const& linestring, Linear const&, TurnIterator first, TurnIterator beyond, - OutputIterator oit) + OutputIterator oit, + SideStrategy const& strategy) { // Iterate through all intersection points (they are // ordered along the each line) @@ -304,7 +312,8 @@ public: entered, enter_count, linestring, current_piece, current_segment_id, - oit); + oit, + strategy); } #if ! defined(BOOST_GEOMETRY_OVERLAY_NO_THROW) @@ -318,7 +327,8 @@ public: return process_end(entered, linestring, current_segment_id, current_piece, - oit); + oit, + strategy); } }; @@ -413,11 +423,12 @@ protected: }; public: - template + template static inline OutputIterator apply(MultiLinestring const& multilinestring, Linear const& linear, TurnIterator first, TurnIterator beyond, - OutputIterator oit) + OutputIterator oit, + SideStrategy const& strategy) { BOOST_GEOMETRY_ASSERT( first != beyond ); @@ -447,7 +458,7 @@ public: has_other_multi_id(current_multi_id)); oit = Base::apply(*(ls_first + current_multi_id), - linear, per_ls_current, per_ls_next, oit); + linear, per_ls_current, per_ls_next, oit, strategy); signed_size_type next_multi_id = -1; linestring_iterator ls_next = ls_beyond; diff --git a/include/boost/geometry/algorithms/detail/overlay/get_relative_order.hpp b/include/boost/geometry/algorithms/detail/overlay/get_relative_order.hpp index ea9aa29f1..2eec6af66 100644 --- a/include/boost/geometry/algorithms/detail/overlay/get_relative_order.hpp +++ b/include/boost/geometry/algorithms/detail/overlay/get_relative_order.hpp @@ -2,6 +2,11 @@ // Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. +// This file was modified by Oracle on 2017. +// Modifications copyright (c) 2017 Oracle and/or its affiliates. + +// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle + // Use, modification and distribution is subject to the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) @@ -31,20 +36,15 @@ namespace detail { namespace overlay but we still need to know which comes first. Therefore, it is useful that using sides we are able to discover this. */ -template struct get_relative_order { - typedef typename strategy::side::services::default_strategy - < - typename cs_tag::type - >::type strategy; - - template + template static inline int value_via_product(Point const& ti, Point const& tj, - Point const& ui, Point const& uj, int factor) + Point const& ui, Point const& uj, int factor, + SideStrategy const& strategy) { - int const side_ti_u = strategy::apply(ti, tj, ui); - int const side_tj_u = strategy::apply(ti, tj, uj); + int const side_ti_u = strategy.apply(ti, tj, ui); + int const side_tj_u = strategy.apply(ti, tj, uj); #ifdef BOOST_GEOMETRY_DEBUG_RELATIVE_ORDER std::cout << (factor == 1 ? " r//s " : " s//r ") @@ -57,13 +57,15 @@ struct get_relative_order } + template static inline int apply( Point1 const& pi, Point1 const& pj, Point1 const& ri, Point1 const& rj, - Point1 const& si, Point1 const& sj) + Point1 const& si, Point1 const& sj, + SideStrategy const& strategy) { - int const side_ri_p = strategy::apply(pi, pj, ri); - int const side_si_p = strategy::apply(pi, pj, si); + int const side_ri_p = strategy.apply(pi, pj, ri); + int const side_si_p = strategy.apply(pi, pj, si); #ifdef BOOST_GEOMETRY_DEBUG_RELATIVE_ORDER int const side_rj_p = strategy::apply(pi, pj, rj); @@ -72,10 +74,10 @@ struct get_relative_order std::cout << " s//p: " << side_si_p << " / " << side_sj_p; #endif - int value = value_via_product(si, sj, ri, rj, 1); + int value = value_via_product(si, sj, ri, rj, 1, strategy); if (value == 0) { - value = value_via_product(ri, rj, si, sj, -1); + value = value_via_product(ri, rj, si, sj, -1, strategy); } int const order = side_ri_p * side_ri_p * side_si_p * value; diff --git a/include/boost/geometry/algorithms/detail/overlay/get_turns.hpp b/include/boost/geometry/algorithms/detail/overlay/get_turns.hpp index 6b6458dd7..f88dfe842 100644 --- a/include/boost/geometry/algorithms/detail/overlay/get_turns.hpp +++ b/include/boost/geometry/algorithms/detail/overlay/get_turns.hpp @@ -233,7 +233,7 @@ public : // section 2: [--------------] // section 1: |----|---|---|---|---| for (prev1 = it1++, next1++; - it1 != end1 && ! detail::section::exceeding<0>(dir1, *prev1, sec2.bounding_box, robust_policy); + it1 != end1 && ! detail::section::exceeding<0>(dir1, *prev1, sec1.bounding_box, sec2.bounding_box, robust_policy); ++prev1, ++it1, ++index1, ++next1, ++ndi1) { ever_circling_iterator nd_next1( @@ -251,7 +251,7 @@ public : next2++; for (prev2 = it2++, next2++; - it2 != end2 && ! detail::section::exceeding<0>(dir2, *prev2, sec1.bounding_box, robust_policy); + it2 != end2 && ! detail::section::exceeding<0>(dir2, *prev2, sec2.bounding_box, sec1.bounding_box, robust_policy); ++prev2, ++it2, ++index2, ++next2, ++ndi2) { bool skip = same_source; @@ -359,7 +359,7 @@ private : // skips to the begin-point, we loose the index or have to recalculate it) // So we mimic it here template - static inline void get_start_point_iterator(Section & section, + static inline void get_start_point_iterator(Section const& section, Range const& range, typename boost::range_iterator::type& it, typename boost::range_iterator::type& prev, @@ -373,7 +373,7 @@ private : // Mimic section-iterator: // Skip to point such that section interects other box prev = it++; - for(; it != end && detail::section::preceding<0>(dir, *it, other_bounding_box, robust_policy); + for(; it != end && detail::section::preceding<0>(dir, *it, section.bounding_box, other_bounding_box, robust_policy); prev = it++, index++, ndi++) {} // Go back one step because we want to start completely preceding diff --git a/include/boost/geometry/algorithms/detail/overlay/handle_colocations.hpp b/include/boost/geometry/algorithms/detail/overlay/handle_colocations.hpp index 41d18a4ed..beb42a9e0 100644 --- a/include/boost/geometry/algorithms/detail/overlay/handle_colocations.hpp +++ b/include/boost/geometry/algorithms/detail/overlay/handle_colocations.hpp @@ -2,6 +2,11 @@ // Copyright (c) 2015 Barend Gehrels, Amsterdam, the Netherlands. +// This file was modified by Oracle on 2017. +// Modifications copyright (c) 2017 Oracle and/or its affiliates. + +// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle + // Use, modification and distribution is subject to the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) @@ -728,11 +733,13 @@ template typename Turns, typename Clusters, typename Geometry1, - typename Geometry2 + typename Geometry2, + typename SideStrategy > inline void gather_cluster_properties(Clusters& clusters, Turns& turns, operation_type for_operation, - Geometry1 const& geometry1, Geometry2 const& geometry2) + Geometry1 const& geometry1, Geometry2 const& geometry2, + SideStrategy const& strategy) { typedef typename boost::range_value::type turn_type; typedef typename turn_type::point_type point_type; @@ -742,7 +749,7 @@ inline void gather_cluster_properties(Clusters& clusters, Turns& turns, // right side typedef sort_by_side::side_sorter < - Reverse1, Reverse2, OverlayType, point_type, std::less + Reverse1, Reverse2, OverlayType, point_type, SideStrategy, std::less > sbs_type; for (typename Clusters::iterator mit = clusters.begin(); @@ -755,7 +762,7 @@ inline void gather_cluster_properties(Clusters& clusters, Turns& turns, continue; } - sbs_type sbs; + sbs_type sbs(strategy); point_type turn_point; // should be all the same for all turns in cluster bool first = true; diff --git a/include/boost/geometry/algorithms/detail/overlay/less_by_segment_ratio.hpp b/include/boost/geometry/algorithms/detail/overlay/less_by_segment_ratio.hpp index 21868a293..dd30635ee 100644 --- a/include/boost/geometry/algorithms/detail/overlay/less_by_segment_ratio.hpp +++ b/include/boost/geometry/algorithms/detail/overlay/less_by_segment_ratio.hpp @@ -2,6 +2,11 @@ // Copyright (c) 2007-2015 Barend Gehrels, Amsterdam, the Netherlands. +// This file was modified by Oracle on 2017. +// Modifications copyright (c) 2017 Oracle and/or its affiliates. + +// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle + // Use, modification and distribution is subject to the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) @@ -60,6 +65,7 @@ template typename Indexed, typename Geometry1, typename Geometry2, typename RobustPolicy, + typename SideStrategy, bool Reverse1, bool Reverse2 > struct less_by_segment_ratio @@ -68,12 +74,14 @@ struct less_by_segment_ratio , operation_type for_operation , Geometry1 const& geometry1 , Geometry2 const& geometry2 - , RobustPolicy const& robust_policy) + , RobustPolicy const& robust_policy + , SideStrategy const& strategy) : m_turns(turns) , m_for_operation(for_operation) , m_geometry1(geometry1) , m_geometry2(geometry2) , m_robust_policy(robust_policy) + , m_strategy(strategy) { } @@ -84,6 +92,7 @@ private : Geometry1 const& m_geometry1; Geometry2 const& m_geometry2; RobustPolicy const& m_robust_policy; + SideStrategy const& m_strategy; typedef typename geometry::point_type::type point_type; @@ -108,13 +117,8 @@ private : *right.other_seg_id, si, sj); - typedef typename strategy::side::services::default_strategy - < - typename cs_tag::type - >::type strategy; - - int const side_rj_p = strategy::apply(pi, pj, rj); - int const side_sj_p = strategy::apply(pi, pj, sj); + int const side_rj_p = m_strategy.apply(pi, pj, rj); + int const side_sj_p = m_strategy.apply(pi, pj, sj); // Put the one turning left (1; right == -1) as last if (side_rj_p != side_sj_p) @@ -122,8 +126,8 @@ private : return side_rj_p < side_sj_p; } - int const side_sj_r = strategy::apply(ri, rj, sj); - int const side_rj_s = strategy::apply(si, sj, rj); + int const side_sj_r = m_strategy.apply(ri, rj, sj); + int const side_rj_s = m_strategy.apply(si, sj, rj); // If they both turn left: the most left as last // If they both turn right: this is not relevant, but take also here most left diff --git a/include/boost/geometry/algorithms/detail/overlay/linear_linear.hpp b/include/boost/geometry/algorithms/detail/overlay/linear_linear.hpp index a74bb33ba..21d079d95 100644 --- a/include/boost/geometry/algorithms/detail/overlay/linear_linear.hpp +++ b/include/boost/geometry/algorithms/detail/overlay/linear_linear.hpp @@ -194,13 +194,15 @@ protected: typename Turns, typename LinearGeometry1, typename LinearGeometry2, - typename OutputIterator + typename OutputIterator, + typename IntersectionStrategy > static inline OutputIterator sort_and_follow_turns(Turns& turns, LinearGeometry1 const& linear1, LinearGeometry2 const& linear2, - OutputIterator oit) + OutputIterator oit, + IntersectionStrategy const& strategy) { // remove turns that have no added value turns::filter_continue_turns @@ -228,7 +230,7 @@ protected: FollowIsolatedPoints, !EnableFilterContinueTurns || OverlayType == overlay_intersection >::apply(linear1, linear2, boost::begin(turns), boost::end(turns), - oit); + oit, strategy.get_side_strategy()); } public: @@ -277,7 +279,7 @@ public: OverlayType, EnableFollowIsolatedPoints && OverlayType == overlay_intersection - >(turns, linear1, linear2, oit); + >(turns, linear1, linear2, oit, strategy); } }; diff --git a/include/boost/geometry/algorithms/detail/overlay/sort_by_side.hpp b/include/boost/geometry/algorithms/detail/overlay/sort_by_side.hpp index a2f7691c3..5ad2e41b1 100644 --- a/include/boost/geometry/algorithms/detail/overlay/sort_by_side.hpp +++ b/include/boost/geometry/algorithms/detail/overlay/sort_by_side.hpp @@ -2,6 +2,11 @@ // Copyright (c) 2015 Barend Gehrels, Amsterdam, the Netherlands. +// This file was modified by Oracle on 2017. +// Modifications copyright (c) 2017 Oracle and/or its affiliates. + +// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle + // Use, modification and distribution is subject to the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) @@ -18,7 +23,6 @@ #include #include #include -#include namespace boost { namespace geometry { @@ -106,17 +110,13 @@ struct less_false } }; -template +template struct less_by_side { - typedef typename strategy::side::services::default_strategy - < - typename cs_tag::type - >::type side; - - less_by_side(const Point& p1, const Point& p2) + less_by_side(const Point& p1, const Point& p2, SideStrategy const& strategy) : m_p1(p1) , m_p2(p2) + , m_strategy(strategy) {} template @@ -125,8 +125,8 @@ struct less_by_side LessOnSame on_same; Compare compare; - int const side_first = side::apply(m_p1, m_p2, first.point); - int const side_second = side::apply(m_p1, m_p2, second.point); + int const side_first = m_strategy.apply(m_p1, m_p2, first.point); + int const side_second = m_strategy.apply(m_p1, m_p2, second.point); if (side_first == 0 && side_second == 0) { @@ -166,7 +166,7 @@ struct less_by_side // They are both left, both right, and/or both collinear (with each other and/or with p1,p2) // Check mutual side - int const side_second_wrt_first = side::apply(m_p2, first.point, second.point); + int const side_second_wrt_first = m_strategy.apply(m_p2, first.point, second.point); if (side_second_wrt_first == 0) { @@ -184,6 +184,7 @@ struct less_by_side private : Point m_p1, m_p2; + SideStrategy const& m_strategy; }; // Sorts vectors in counter clockwise order (by default) @@ -193,6 +194,7 @@ template bool Reverse2, overlay_type OverlayType, typename Point, + typename SideStrategy, typename Compare > struct side_sorter @@ -223,9 +225,10 @@ private : }; public : - side_sorter() + side_sorter(SideStrategy const& strategy) : m_origin_count(0) , m_origin_segment_distance(0) + , m_strategy(strategy) {} template @@ -309,8 +312,8 @@ public : // to give colinear points // Sort by side and assign rank - less_by_side less_unique(m_origin, turn_point); - less_by_side less_non_unique(m_origin, turn_point); + less_by_side less_unique(m_origin, turn_point, m_strategy); + less_by_side less_non_unique(m_origin, turn_point, m_strategy); std::sort(m_ranked_points.begin(), m_ranked_points.end(), less_unique); @@ -425,6 +428,7 @@ public : Point m_origin; std::size_t m_origin_count; int m_origin_segment_distance; + SideStrategy m_strategy; private : diff --git a/include/boost/geometry/algorithms/detail/overlay/traversal.hpp b/include/boost/geometry/algorithms/detail/overlay/traversal.hpp index 27727aee1..d6eeda044 100644 --- a/include/boost/geometry/algorithms/detail/overlay/traversal.hpp +++ b/include/boost/geometry/algorithms/detail/overlay/traversal.hpp @@ -2,6 +2,11 @@ // Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. +// This file was modified by Oracle on 2017. +// Modifications copyright (c) 2017 Oracle and/or its affiliates. + +// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle + // Use, modification and distribution is subject to the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) @@ -94,6 +99,7 @@ template typename Turns, typename Clusters, typename RobustPolicy, + typename SideStrategy, typename Visitor > struct traversal @@ -108,17 +114,19 @@ struct traversal typedef sort_by_side::side_sorter < Reverse1, Reverse2, OverlayType, - point_type, side_compare_type + point_type, SideStrategy, side_compare_type > sbs_type; inline traversal(Geometry1 const& geometry1, Geometry2 const& geometry2, Turns& turns, Clusters const& clusters, - RobustPolicy const& robust_policy, Visitor& visitor) + RobustPolicy const& robust_policy, SideStrategy const& strategy, + Visitor& visitor) : m_geometry1(geometry1) , m_geometry2(geometry2) , m_turns(turns) , m_clusters(clusters) , m_robust_policy(robust_policy) + , m_strategy(strategy) , m_visitor(visitor) { } @@ -579,7 +587,7 @@ struct traversal cluster_info const& cinfo = mit->second; std::set const& ids = cinfo.turn_indices; - sbs_type sbs; + sbs_type sbs(m_strategy); for (typename std::set::const_iterator sit = ids.begin(); sit != ids.end(); ++sit) @@ -625,7 +633,7 @@ struct traversal turn_type const& current_turn, segment_identifier const& previous_seg_id) { - sbs_type sbs; + sbs_type sbs(m_strategy); // Add this turn to the sort-by-side sorter for (int i = 0; i < 2; i++) @@ -817,6 +825,7 @@ private : Turns& m_turns; Clusters const& m_clusters; RobustPolicy const& m_robust_policy; + SideStrategy m_strategy; Visitor& m_visitor; }; diff --git a/include/boost/geometry/algorithms/detail/overlay/traversal_ring_creator.hpp b/include/boost/geometry/algorithms/detail/overlay/traversal_ring_creator.hpp index ef50d73be..8096a2269 100644 --- a/include/boost/geometry/algorithms/detail/overlay/traversal_ring_creator.hpp +++ b/include/boost/geometry/algorithms/detail/overlay/traversal_ring_creator.hpp @@ -50,9 +50,13 @@ template > struct traversal_ring_creator { - typedef traversal - traversal_type; + typedef traversal + < + Reverse1, Reverse2, OverlayType, + Geometry1, Geometry2, Turns, Clusters, + RobustPolicy, typename IntersectionStrategy::side_strategy_type, + Visitor + > traversal_type; typedef typename boost::range_value::type turn_type; typedef typename turn_type::turn_operation_type turn_operation_type; @@ -65,7 +69,9 @@ struct traversal_ring_creator Clusters const& clusters, IntersectionStrategy const& intersection_strategy, RobustPolicy const& robust_policy, Visitor& visitor) - : m_trav(geometry1, geometry2, turns, clusters, robust_policy,visitor) + : m_trav(geometry1, geometry2, turns, clusters, + robust_policy, intersection_strategy.get_side_strategy(), + visitor) , m_geometry1(geometry1) , m_geometry2(geometry2) , m_turns(turns) @@ -106,12 +112,14 @@ struct traversal_ring_creator { geometry::copy_segments(m_geometry1, previous_op.seg_id, to_vertex_index, + m_intersection_strategy.get_side_strategy(), m_robust_policy, current_ring); } else { geometry::copy_segments(m_geometry2, previous_op.seg_id, to_vertex_index, + m_intersection_strategy.get_side_strategy(), m_robust_policy, current_ring); } } @@ -155,6 +163,7 @@ struct traversal_ring_creator turn_type& current_turn = m_turns[turn_index]; turn_operation_type& op = current_turn.operations[op_index]; detail::overlay::append_no_dups_or_spikes(current_ring, current_turn.point, + m_intersection_strategy.get_side_strategy(), m_robust_policy); // Register the visit @@ -172,6 +181,7 @@ struct traversal_ring_creator turn_operation_type& start_op = m_turns[start_turn_index].operations[start_op_index]; detail::overlay::append_no_dups_or_spikes(ring, start_turn.point, + m_intersection_strategy.get_side_strategy(), m_robust_policy); signed_size_type current_turn_index = start_turn_index; @@ -274,7 +284,9 @@ struct traversal_ring_creator if (geometry::num_points(ring) >= min_num_points) { - clean_closing_dups_and_spikes(ring, m_robust_policy); + clean_closing_dups_and_spikes(ring, + m_intersection_strategy.get_side_strategy(), + m_robust_policy); rings.push_back(ring); m_trav.finalize_visit_info(m_turn_info_map); diff --git a/include/boost/geometry/algorithms/detail/point_is_spike_or_equal.hpp b/include/boost/geometry/algorithms/detail/point_is_spike_or_equal.hpp index 607ba8153..b8ea5e30e 100644 --- a/include/boost/geometry/algorithms/detail/point_is_spike_or_equal.hpp +++ b/include/boost/geometry/algorithms/detail/point_is_spike_or_equal.hpp @@ -5,10 +5,11 @@ // Copyright (c) 2009-2015 Mateusz Loskot, London, UK. // Copyright (c) 2013-2015 Adam Wulkiewicz, Lodz, Poland. -// This file was modified by Oracle on 2015. -// Modifications copyright (c) 2015 Oracle and/or its affiliates. +// This file was modified by Oracle on 2015, 2017. +// Modifications copyright (c) 2015-2017 Oracle and/or its affiliates. // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle +// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle // Use, modification and distribution is subject to the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at @@ -19,11 +20,13 @@ #include #include +#include #include #include #include #include + namespace boost { namespace geometry { @@ -32,6 +35,26 @@ namespace boost { namespace geometry namespace detail { +template +inline bool collinear_point_is_spike_or_equal(Point1 const& last_point, + Point2 const& segment_a, + Point3 const& segment_b) +{ + // Check if segment is equal + int const sgn_x1 = sign_of_difference<0>(last_point, segment_b); + int const sgn_y1 = sign_of_difference<1>(last_point, segment_b); + if (sgn_x1 == 0 && sgn_y1 == 0) + { + return true; + } + + // Check if segment moves forward + int const sgn_x2 = sign_of_difference<0>(segment_b, segment_a); + int const sgn_y2 = sign_of_difference<1>(segment_b, segment_a); + + return sgn_x1 != sgn_x2 || sgn_y1 != sgn_y2; +} + // Checks if a point ("last_point") causes a spike w.r.t. // the specified two other points (segment_a, segment_b) // @@ -42,33 +65,29 @@ namespace detail // So specify last point first, then (a,b) // The segment's orientation does matter: if lp is to the right of b // no spike is reported -template -static inline bool point_is_spike_or_equal(Point1 const& last_point, - Point2 const& segment_a, - Point3 const& segment_b) +template +< + typename Point1, typename Point2, typename Point3, + typename SideStrategy +> +static inline bool point_is_spike_or_equal(Point1 const& last_point, // prev | back + Point2 const& segment_a, // next | back - 2 + Point3 const& segment_b, // curr | back - 1 | spike's vertex + SideStrategy const& strategy) { - typedef typename strategy::side::services::default_strategy - < - typename cs_tag::type - >::type side_strategy; - - int const side = side_strategy::apply(last_point, segment_a, segment_b); + int const side = strategy.apply(segment_a, segment_b, last_point); if (side == 0) { // Last point is collinear w.r.t previous segment. - // Check if it is equal - int const sgn_x1 = sign_of_difference<0>(last_point, segment_b); - int const sgn_y1 = sign_of_difference<1>(last_point, segment_b); - if (sgn_x1 == 0 && sgn_y1 == 0) - { - return true; - } - - // Check if it moves forward - int const sgn_x2 = sign_of_difference<0>(segment_b, segment_a); - int const sgn_y2 = sign_of_difference<1>(segment_b, segment_a); - - return sgn_x1 != sgn_x2 || sgn_y1 != sgn_y2; +#ifdef BOOST_GEOMETRY_ENABLE_POINT_IS_SPIKE_OR_EQUAL_TEST + bool r1 = collinear_point_is_spike_or_equal(last_point, segment_a, segment_b); + bool r2 = direction_code(segment_a, segment_b, last_point) < 1; + if (r1 != r2) + std::cout << "spike detection failure with: " << r1 << " " << r2 << std::endl; + return r2; +#else + return direction_code(segment_a, segment_b, last_point) < 1; +#endif } return false; } @@ -78,14 +97,16 @@ template typename Point1, typename Point2, typename Point3, + typename SideStrategy, typename RobustPolicy > static inline bool point_is_spike_or_equal(Point1 const& last_point, Point2 const& segment_a, Point3 const& segment_b, + SideStrategy const& strategy, RobustPolicy const& robust_policy) { - if (point_is_spike_or_equal(last_point, segment_a, segment_b)) + if (point_is_spike_or_equal(last_point, segment_a, segment_b, strategy)) { return true; } @@ -111,7 +132,8 @@ static inline bool point_is_spike_or_equal(Point1 const& last_point, ( last_point_rob, segment_a_rob, - segment_b_rob + segment_b_rob, + strategy ); } diff --git a/include/boost/geometry/algorithms/detail/sections/section_functions.hpp b/include/boost/geometry/algorithms/detail/sections/section_functions.hpp index 7bc5c0804..67df3060c 100644 --- a/include/boost/geometry/algorithms/detail/sections/section_functions.hpp +++ b/include/boost/geometry/algorithms/detail/sections/section_functions.hpp @@ -2,8 +2,8 @@ // Copyright (c) 2015 Barend Gehrels, Amsterdam, the Netherlands. -// This file was modified by Oracle on 2015. -// Modifications copyright (c) 2015, Oracle and/or its affiliates. +// This file was modified by Oracle on 2015, 2017. +// Modifications copyright (c) 2015-2017, Oracle and/or its affiliates. // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle @@ -27,6 +27,74 @@ namespace boost { namespace geometry namespace detail { namespace section { +template +< + std::size_t Dimension, + typename Geometry, + typename CastedCSTag = typename tag_cast + < + typename cs_tag::type, + spherical_tag + >::type +> +struct preceding_check +{ + template + static inline bool apply(int dir, Point const& point, Box const& /*point_box*/, Box const& other_box) + { + return (dir == 1 && get(point) < get(other_box)) + || (dir == -1 && get(point) > get(other_box)); + } +}; + +template +struct preceding_check<0, Geometry, spherical_tag> +{ + template + static inline bool apply(int dir, Point const& point, Box const& point_box, Box const& other_box) + { + typedef typename select_coordinate_type + < + Point, Box + >::type calc_t; + typedef typename coordinate_system::type::units units_t; + + calc_t const c0 = 0; + + if (dir == 1) + { + calc_t const diff_min = math::longitude_distance_signed + < + units_t, calc_t + >(get(other_box), get<0>(point)); + + calc_t const diff_min_min = math::longitude_distance_signed + < + units_t, calc_t + >(get(other_box), get(point_box)); + + return diff_min < c0 && diff_min_min <= c0 && diff_min_min <= diff_min; + } + else if (dir == -1) + { + calc_t const diff_max = math::longitude_distance_signed + < + units_t, calc_t + >(get(other_box), get<0>(point)); + + calc_t const diff_max_max = math::longitude_distance_signed + < + units_t, calc_t + >(get(other_box), get(point_box)); + + return diff_max > c0 && diff_max_max >= c0 && diff_max <= diff_max_max; + } + + return false; + } +}; + + template < std::size_t Dimension, @@ -34,14 +102,15 @@ template typename RobustBox, typename RobustPolicy > -static inline bool preceding(int dir, Point const& point, - RobustBox const& robust_box, - RobustPolicy const& robust_policy) +static inline bool preceding(int dir, + Point const& point, + RobustBox const& point_robust_box, + RobustBox const& other_robust_box, + RobustPolicy const& robust_policy) { typename geometry::robust_point_type::type robust_point; geometry::recalculate(robust_point, point, robust_policy); - return (dir == 1 && get(robust_point) < get(robust_box)) - || (dir == -1 && get(robust_point) > get(robust_box)); + return preceding_check::apply(dir, robust_point, point_robust_box, other_robust_box); } template @@ -51,14 +120,13 @@ template typename RobustBox, typename RobustPolicy > -static inline bool exceeding(int dir, Point const& point, - RobustBox const& robust_box, - RobustPolicy const& robust_policy) +static inline bool exceeding(int dir, + Point const& point, + RobustBox const& point_robust_box, + RobustBox const& other_robust_box, + RobustPolicy const& robust_policy) { - typename geometry::robust_point_type::type robust_point; - geometry::recalculate(robust_point, point, robust_policy); - return (dir == 1 && get(robust_point) > get(robust_box)) - || (dir == -1 && get(robust_point) < get(robust_box)); + return preceding(-dir, point, point_robust_box, other_robust_box, robust_policy); } diff --git a/include/boost/geometry/algorithms/detail/sections/sectionalize.hpp b/include/boost/geometry/algorithms/detail/sections/sectionalize.hpp index ff56acec4..f1d8e7d23 100644 --- a/include/boost/geometry/algorithms/detail/sections/sectionalize.hpp +++ b/include/boost/geometry/algorithms/detail/sections/sectionalize.hpp @@ -5,8 +5,8 @@ // Copyright (c) 2009-2015 Mateusz Loskot, London, UK. // Copyright (c) 2014-2015 Adam Wulkiewicz, Lodz, Poland. -// This file was modified by Oracle on 2013, 2014, 2015. -// Modifications copyright (c) 2013-2015 Oracle and/or its affiliates. +// This file was modified by Oracle on 2013, 2014, 2015, 2017. +// Modifications copyright (c) 2013-2017 Oracle and/or its affiliates. // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle @@ -136,11 +136,21 @@ struct sections : std::vector > namespace detail { namespace sectionalize { +// NOTE: This utility will NOT work for latitudes, dimension 1 in spherical +// and geographic coordinate system because in these coordinate systems +// e.g. a segment on northern hemisphere may go towards greater latitude +// and then towards lesser latitude. template < + typename Point, typename DimensionVector, std::size_t Index, - std::size_t Count + std::size_t Count, + typename CastedCSTag = typename tag_cast + < + typename cs_tag::type, + spherical_tag + >::type > struct get_direction_loop { @@ -161,21 +171,67 @@ struct get_direction_loop get_direction_loop < + Point, DimensionVector, Index + 1, - Count + Count, + CastedCSTag >::apply(seg, directions); } }; -template -struct get_direction_loop +template +< + typename Point, + typename DimensionVector, + std::size_t Count +> +struct get_direction_loop +{ + typedef typename boost::mpl::at_c::type dimension; + + template + static inline void apply(Segment const& seg, + int directions[Count]) + { + typedef typename coordinate_type::type coordinate_type; + typedef typename coordinate_system::type::units units_t; + + coordinate_type const diff = math::longitude_distance_signed + < + units_t, coordinate_type + >(geometry::get<0, 0>(seg), + geometry::get<1, 0>(seg)); + + coordinate_type zero = coordinate_type(); + directions[0] = diff > zero ? 1 : diff < zero ? -1 : 0; + + get_direction_loop + < + Point, + DimensionVector, + 1, + Count, + spherical_tag + >::apply(seg, directions); + } +}; + +template +< + typename Point, + typename DimensionVector, + std::size_t Count, + typename CastedCSTag +> +struct get_direction_loop { template static inline void apply(Segment const&, int [Count]) {} }; + //! Copy one static array to another template struct copy_loop @@ -410,7 +466,7 @@ struct sectionalize_part int direction_classes[dimension_count] = {0}; get_direction_loop < - DimensionVector, 0, dimension_count + Point, DimensionVector, 0, dimension_count >::apply(robust_segment, direction_classes); // if "dir" == 0 for all point-dimensions, it is duplicate. @@ -929,9 +985,12 @@ inline void sectionalize(Geometry const& geometry, typename cs_tag::type >::type envelope_strategy_type; - sectionalize(geometry, robust_policy, sections, - envelope_strategy_type(), - source_index, max_count); + boost::geometry::sectionalize + < + Reverse, DimensionVector + >(geometry, robust_policy, sections, + envelope_strategy_type(), + source_index, max_count); } }} // namespace boost::geometry diff --git a/include/boost/geometry/algorithms/is_convex.hpp b/include/boost/geometry/algorithms/is_convex.hpp index 8feb48db6..4a9251b27 100644 --- a/include/boost/geometry/algorithms/is_convex.hpp +++ b/include/boost/geometry/algorithms/is_convex.hpp @@ -2,6 +2,11 @@ // Copyright (c) 2015 Barend Gehrels, Amsterdam, the Netherlands. +// This file was modified by Oracle on 2017. +// Modifications copyright (c) 2017 Oracle and/or its affiliates. + +// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle + // Use, modification and distribution is subject to the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) @@ -10,17 +15,23 @@ #define BOOST_GEOMETRY_ALGORITHMS_IS_CONVEX_HPP +#include +#include +#include + +#include #include #include #include #include #include -#include +#include #include +#include #include -#include #include + namespace boost { namespace geometry { @@ -31,15 +42,9 @@ namespace detail { namespace is_convex struct ring_is_convex { - template - static inline bool apply(Ring const& ring) + template + static inline bool apply(Ring const& ring, SideStrategy const& strategy) { - typedef typename geometry::point_type::type point_type; - typedef typename strategy::side::services::default_strategy - < - typename cs_tag::type - >::type side_strategy_type; - std::size_t n = boost::size(ring); if (boost::size(ring) < core_detail::closure::minimum_ring_size < @@ -86,7 +91,7 @@ struct ring_is_convex // iterator for (std::size_t i = 0; i < n; i++) { - int const side = side_strategy_type::apply(*previous, *current, *next); + int const side = strategy.apply(*previous, *current, *next); if (side == 1) { // Next is on the left side of clockwise ring: @@ -129,7 +134,8 @@ struct is_convex : not_implemented template struct is_convex { - static inline bool apply(Box const& ) + template + static inline bool apply(Box const& , Strategy const& ) { // Any box is convex (TODO: consider spherical boxes) return true; @@ -144,13 +150,71 @@ struct is_convex : detail::is_convex::ring_is_convex } // namespace dispatch #endif // DOXYGEN_NO_DISPATCH -// TODO: variants +namespace resolve_variant { + +template +struct is_convex +{ + template + static bool apply(Geometry const& geometry, Strategy const& strategy) + { + concepts::check(); + return dispatch::is_convex::apply(geometry, strategy); + } + + static bool apply(Geometry const& geometry, geometry::default_strategy const&) + { + typedef typename strategy::side::services::default_strategy + < + typename cs_tag::type + >::type side_strategy; + + return apply(geometry, side_strategy()); + } +}; + +template +struct is_convex > +{ + template + struct visitor: boost::static_visitor + { + Strategy const& m_strategy; + + visitor(Strategy const& strategy) : m_strategy(strategy) {} + + template + bool operator()(Geometry const& geometry) const + { + return is_convex::apply(geometry, m_strategy); + } + }; + + template + static inline bool apply(boost::variant const& geometry, + Strategy const& strategy) + { + return boost::apply_visitor(visitor(strategy), geometry); + } +}; + +} // namespace resolve_variant // TODO: documentation / qbk template inline bool is_convex(Geometry const& geometry) { - return dispatch::is_convex::apply(geometry); + return resolve_variant::is_convex + < + Geometry + >::apply(geometry, geometry::default_strategy()); +} + +// TODO: documentation / qbk +template +inline bool is_convex(Geometry const& geometry, Strategy const& strategy) +{ + return resolve_variant::is_convex::apply(geometry, strategy); } diff --git a/include/boost/geometry/algorithms/point_on_surface.hpp b/include/boost/geometry/algorithms/point_on_surface.hpp index e9041f937..3f4d0f4af 100644 --- a/include/boost/geometry/algorithms/point_on_surface.hpp +++ b/include/boost/geometry/algorithms/point_on_surface.hpp @@ -5,8 +5,8 @@ // Copyright (c) 2009-2013 Mateusz Loskot, London, UK. // Copyright (c) 2013 Adam Wulkiewicz, Lodz, Poland. -// This file was modified by Oracle on 2014. -// Modifications copyright (c) 2014 Oracle and/or its affiliates. +// This file was modified by Oracle on 2014, 2017. +// Modifications copyright (c) 2014-2017 Oracle and/or its affiliates. // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle @@ -33,6 +33,7 @@ #include #include +#include namespace boost { namespace geometry @@ -241,8 +242,9 @@ inline void replace_extremes_for_self_tangencies(Extremes& extremes, Intruders& extremes = triangle; } -template -inline bool calculate_point_on_surface(Geometry const& geometry, Point& point) +template +inline bool calculate_point_on_surface(Geometry const& geometry, Point& point, + SideStrategy const& strategy) { typedef typename geometry::point_type::type point_type; typedef typename geometry::coordinate_type::type coordinate_type; @@ -250,7 +252,7 @@ inline bool calculate_point_on_surface(Geometry const& geometry, Point& point) typedef std::vector > intruders_type; intruders_type intruders; - geometry::extreme_points(geometry, extremes, intruders); + geometry::extreme_points(geometry, extremes, intruders, strategy); if (extremes.size() < 3) { @@ -291,21 +293,57 @@ inline bool calculate_point_on_surface(Geometry const& geometry, Point& point) \tparam Geometry geometry type. This also defines the type of the output point \param geometry Geometry to take point from \param point Point to assign +\param strategy side strategy */ -template -inline void point_on_surface(Geometry const& geometry, Point & point) +template +inline void point_on_surface(Geometry const& geometry, Point & point, + SideStrategy const& strategy) { concepts::check(); concepts::check(); // First try in Y-direction (which should always succeed for valid polygons) - if (! detail::point_on_surface::calculate_point_on_surface<1>(geometry, point)) + if (! detail::point_on_surface::calculate_point_on_surface<1>(geometry, point, strategy)) { // For invalid polygons, we might try X-direction - detail::point_on_surface::calculate_point_on_surface<0>(geometry, point); + detail::point_on_surface::calculate_point_on_surface<0>(geometry, point, strategy); } } +/*! +\brief Assigns a Point guaranteed to lie on the surface of the Geometry +\tparam Geometry geometry type. This also defines the type of the output point +\param geometry Geometry to take point from +\param point Point to assign + */ +template +inline void point_on_surface(Geometry const& geometry, Point & point) +{ + typedef typename strategy::side::services::default_strategy + < + typename cs_tag::type + >::type strategy_type; + + point_on_surface(geometry, point, strategy_type()); +} + + +/*! +\brief Returns point guaranteed to lie on the surface of the Geometry +\tparam Geometry geometry type. This also defines the type of the output point +\param geometry Geometry to take point from +\param strategy side strategy +\return The Point guaranteed to lie on the surface of the Geometry + */ +template +inline typename geometry::point_type::type +return_point_on_surface(Geometry const& geometry, SideStrategy const& strategy) +{ + typename geometry::point_type::type result; + geometry::point_on_surface(geometry, result, strategy); + return result; +} + /*! \brief Returns point guaranteed to lie on the surface of the Geometry \tparam Geometry geometry type. This also defines the type of the output point diff --git a/include/boost/geometry/algorithms/remove_spikes.hpp b/include/boost/geometry/algorithms/remove_spikes.hpp index caa7fed9b..196b20c6a 100644 --- a/include/boost/geometry/algorithms/remove_spikes.hpp +++ b/include/boost/geometry/algorithms/remove_spikes.hpp @@ -5,6 +5,11 @@ // Copyright (c) 2009-2013 Mateusz Loskot, London, UK. // Copyright (c) 2013-2014 Adam Wulkiewicz, Lodz, Poland. +// This file was modified by Oracle on 2017. +// Modifications copyright (c) 2017 Oracle and/or its affiliates. + +// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle + // Use, modification and distribution is subject to the Boost Software License, // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) @@ -34,6 +39,8 @@ #include #include +#include + #include @@ -59,20 +66,13 @@ namespace detail { namespace remove_spikes { -template struct range_remove_spikes { - typedef typename strategy::side::services::default_strategy - < - typename cs_tag::type - >::type side_strategy; - - typedef typename coordinate_type::type coordinate_type; - typedef typename point_type::type point_type; - - - static inline void apply(Range& range) + template + static inline void apply(Range& range, SideStrategy const& strategy) { + typedef typename point_type::type point_type; + std::size_t n = boost::size(range); std::size_t const min_num_points = core_detail::closure::minimum_ring_size < @@ -91,7 +91,10 @@ struct range_remove_spikes cleaned.push_back(*it); while(cleaned.size() >= 3 - && detail::point_is_spike_or_equal(cleaned.back(), *(cleaned.end() - 3), *(cleaned.end() - 2))) + && detail::point_is_spike_or_equal(cleaned.back(), + *(cleaned.end() - 3), + *(cleaned.end() - 2), + strategy)) { // Remove pen-ultimate point causing the spike (or which was equal) cleaned.erase(cleaned.end() - 2); @@ -110,13 +113,21 @@ struct range_remove_spikes found = false; // Check for spike in first point int const penultimate = 2; - while(cleaned.size() >= 3 && detail::point_is_spike_or_equal(cleaned.front(), *(cleaned.end() - penultimate), cleaned.back())) + while(cleaned.size() >= 3 + && detail::point_is_spike_or_equal(cleaned.front(), + *(cleaned.end() - penultimate), + cleaned.back(), + strategy)) { cleaned.pop_back(); found = true; } // Check for spike in second point - while(cleaned.size() >= 3 && detail::point_is_spike_or_equal(*(cleaned.begin() + 1), cleaned.back(), cleaned.front())) + while(cleaned.size() >= 3 + && detail::point_is_spike_or_equal(*(cleaned.begin() + 1), + cleaned.back(), + cleaned.front(), + strategy)) { cleaned.pop_front(); found = true; @@ -144,15 +155,13 @@ struct range_remove_spikes }; -template struct polygon_remove_spikes { - static inline void apply(Polygon& polygon) + template + static inline void apply(Polygon& polygon, SideStrategy const& strategy) { - typedef typename geometry::ring_type::type ring_type; - - typedef range_remove_spikes per_range; - per_range::apply(exterior_ring(polygon)); + typedef range_remove_spikes per_range; + per_range::apply(exterior_ring(polygon), strategy); typename interior_return_type::type rings = interior_rings(polygon); @@ -160,23 +169,24 @@ struct polygon_remove_spikes for (typename detail::interior_iterator::type it = boost::begin(rings); it != boost::end(rings); ++it) { - per_range::apply(*it); + per_range::apply(*it, strategy); } } }; -template +template struct multi_remove_spikes { - static inline void apply(MultiGeometry& multi) + template + static inline void apply(MultiGeometry& multi, SideStrategy const& strategy) { for (typename boost::range_iterator::type it = boost::begin(multi); it != boost::end(multi); ++it) { - SingleVersion::apply(*it); + SingleVersion::apply(*it, strategy); } } }; @@ -199,21 +209,22 @@ template > struct remove_spikes { - static inline void apply(Geometry&) + template + static inline void apply(Geometry&, SideStrategy const&) {} }; template struct remove_spikes - : detail::remove_spikes::range_remove_spikes + : detail::remove_spikes::range_remove_spikes {}; template struct remove_spikes - : detail::remove_spikes::polygon_remove_spikes + : detail::remove_spikes::polygon_remove_spikes {}; @@ -221,11 +232,7 @@ template struct remove_spikes : detail::remove_spikes::multi_remove_spikes < - MultiPolygon, detail::remove_spikes::polygon_remove_spikes - < - typename boost::range_value::type - > > {}; @@ -239,28 +246,46 @@ namespace resolve_variant { template struct remove_spikes { - static void apply(Geometry& geometry) + template + static void apply(Geometry& geometry, Strategy const& strategy) { concepts::check(); - dispatch::remove_spikes::apply(geometry); + dispatch::remove_spikes::apply(geometry, strategy); + } + + static void apply(Geometry& geometry, geometry::default_strategy const&) + { + typedef typename strategy::side::services::default_strategy + < + typename cs_tag::type + >::type side_strategy; + + apply(geometry, side_strategy()); } }; template struct remove_spikes > { + template struct visitor: boost::static_visitor { + Strategy const& m_strategy; + + visitor(Strategy const& strategy) : m_strategy(strategy) {} + template void operator()(Geometry& geometry) const { - remove_spikes::apply(geometry); + remove_spikes::apply(geometry, m_strategy); } }; - static inline void apply(boost::variant& geometry) + template + static inline void apply(boost::variant& geometry, + Strategy const& strategy) { - boost::apply_visitor(visitor(), geometry); + boost::apply_visitor(visitor(strategy), geometry); } }; @@ -275,7 +300,20 @@ struct remove_spikes > template inline void remove_spikes(Geometry& geometry) { - resolve_variant::remove_spikes::apply(geometry); + resolve_variant::remove_spikes::apply(geometry, geometry::default_strategy()); +} + +/*! + \ingroup remove_spikes + \tparam Geometry geometry type + \tparam Strategy side strategy type + \param geometry the geometry to make remove_spikes + \param strategy the side strategy used by the algorithm +*/ +template +inline void remove_spikes(Geometry& geometry, Strategy const& strategy) +{ + resolve_variant::remove_spikes::apply(geometry, strategy); } diff --git a/include/boost/geometry/strategies/geographic/area.hpp b/include/boost/geometry/strategies/geographic/area.hpp index e1d3b09b5..44dc2e694 100644 --- a/include/boost/geometry/strategies/geographic/area.hpp +++ b/include/boost/geometry/strategies/geographic/area.hpp @@ -83,7 +83,7 @@ protected : CT const m_e2; // squared eccentricity CT const m_ep2; // squared second eccentricity CT const m_ep; // second eccentricity - CT const m_c2; // authalic radius + CT const m_c2; // squared authalic radius inline spheroid_constants(Spheroid const& spheroid) : m_spheroid(spheroid) @@ -92,12 +92,27 @@ protected : * (CT(2.0) - CT(formula::flattening(spheroid)))) , m_ep2(m_e2 / (CT(1.0) - m_e2)) , m_ep(math::sqrt(m_ep2)) - , m_c2((m_a2 / CT(2.0)) + - ((math::sqr(get_radius<2>(spheroid)) * boost::math::atanh(math::sqrt(m_e2))) - / (CT(2.0) * math::sqrt(m_e2)))) + , m_c2(authalic_radius(spheroid, m_a2, m_e2)) {} }; + static inline CT authalic_radius(Spheroid const& sph, CT const& a2, CT const& e2) + { + CT const c0 = 0; + + if (math::equals(e2, c0)) + { + return a2; + } + + CT const sqrt_e2 = math::sqrt(e2); + CT const c2 = 2; + + return (a2 / c2) + + ((math::sqr(get_radius<2>(sph)) * boost::math::atanh(sqrt_e2)) + / (c2 * sqrt_e2)); + } + struct area_sums { CT m_excess_sum; diff --git a/test/algorithms/Jamfile.v2 b/test/algorithms/Jamfile.v2 index cb01090ef..6797b4147 100644 --- a/test/algorithms/Jamfile.v2 +++ b/test/algorithms/Jamfile.v2 @@ -4,7 +4,7 @@ # Copyright (c) 2008-2015 Bruno Lalande, Paris, France. # Copyright (c) 2009-2015 Mateusz Loskot, London, UK. # -# This file was modified by Oracle on 2014, 2015, 2016,2017. +# This file was modified by Oracle on 2014, 2015, 2016, 2017. # Modifications copyright (c) 2014-2017, Oracle and/or its affiliates. # # Contributed and/or modified by Vissarion Fisikopoulos, on behalf of Oracle @@ -33,8 +33,10 @@ test-suite boost-geometry-algorithms [ run is_convex.cpp : : : : algorithms_is_convex ] [ run is_empty.cpp : : : : algorithms_is_empty ] [ run is_simple.cpp : : : : algorithms_is_simple ] + [ run is_simple_geo.cpp : : : : algorithms_is_simple_geo ] [ run is_valid.cpp : : : : algorithms_is_valid ] [ run is_valid_failure.cpp : : : : algorithms_is_valid_failure ] + [ run is_valid_geo.cpp : : : : algorithms_is_valid_geo ] [ run make.cpp : : : : algorithms_make ] [ run maximum_gap.cpp : : : : algorithms_maximum_gap ] [ run num_geometries.cpp : : : : algorithms_num_geometries ] diff --git a/test/algorithms/area/area_sph_geo.cpp b/test/algorithms/area/area_sph_geo.cpp index 70185c1d8..9cde3b45a 100644 --- a/test/algorithms/area/area_sph_geo.cpp +++ b/test/algorithms/area/area_sph_geo.cpp @@ -389,6 +389,21 @@ void test_spherical_geo() // for select geography::STGeomFromText('POLYGON((4.892 52.373,4.23 52.08, // 4.479 51.930,5.119 52.093,4.892 52.373))',4326).STArea()/1000000.0 } + + { + bg::model::polygon geometry_sph; + std::string wkt = "POLYGON((0 0, 5 0, 5 5, 0 5, 0 0))"; + bg::read_wkt(wkt, geometry_sph); + + area = bg::area(geometry_sph, bg::strategy::area::spherical(6371228.0)); + BOOST_CHECK_CLOSE(area, 308932296103.83051, 0.0001); + + bg::model::polygon geometry_geo; + bg::read_wkt(wkt, geometry_geo); + + area = bg::area(geometry_geo, bg::strategy::area::geographic(bg::srs::spheroid(6371228.0, 6371228.0))); + BOOST_CHECK_CLOSE(area, 308932296103.82574, 0.001); + } } int test_main(int, char* []) diff --git a/test/algorithms/buffer/buffer_multi_point.cpp b/test/algorithms/buffer/buffer_multi_point.cpp index fb3b61fb6..3d0e94a07 100644 --- a/test/algorithms/buffer/buffer_multi_point.cpp +++ b/test/algorithms/buffer/buffer_multi_point.cpp @@ -24,6 +24,8 @@ static std::string const grid_a = "MULTIPOINT(5 0,6 0,7 0, 5 1,7 1, 0 13,8 13) static std::string const mysql_report_2015_02_25_1 = "MULTIPOINT(-9 19,9 -6,-4 4,16 -14,-3 16,14 9)"; static std::string const mysql_report_2015_02_25_2 = "MULTIPOINT(-2 11,-15 3,6 4,-14 0,20 -7,-17 -1)"; +static std::string const mysql_report_3 = "MULTIPOINT(0 0,0 0,0 0,0 0,0 0)"; + template void test_all() { @@ -78,6 +80,18 @@ void test_all() mysql_report_2015_02_25_1, join, end_flat, distance_strategy(6051788), side_strategy, bg::strategy::buffer::point_circle(800), 115057490003226.125, 1.0); + + { + multi_point_type g; + bg::read_wkt(mysql_report_3, g); + test_buffer("mysql_report_3", g, + bg::strategy::buffer::join_round(36), + bg::strategy::buffer::end_round(36), + distance_strategy(1), + side_strategy, + bg::strategy::buffer::point_circle(36), + true, 1, 0, 3.12566719800474635, 1.0, NULL); + } } template diff --git a/test/algorithms/is_simple.cpp b/test/algorithms/is_simple.cpp index a61ba6216..41cef5ed5 100644 --- a/test/algorithms/is_simple.cpp +++ b/test/algorithms/is_simple.cpp @@ -13,36 +13,7 @@ #define BOOST_TEST_MODULE test_is_simple #endif -#include -#include - -#include -#include - -#include - -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#include - -#include -#include -#include - -#include - -#ifdef BOOST_GEOMETRY_TEST_DEBUG -#include "pretty_print_geometry.hpp" -#endif +#include "test_is_simple.hpp" namespace bg = ::boost::geometry; @@ -61,71 +32,6 @@ typedef bg::model::multi_polygon multi_polygon_type; typedef bg::model::box box_type; -//---------------------------------------------------------------------------- - - -template -void test_simple(Geometry const& geometry, bool expected_result, - bool check_validity = true) -{ -#ifdef BOOST_GEOMETRY_TEST_DEBUG - std::cout << "=======" << std::endl; -#endif - - bool simple = bg::is_simple(geometry); - - BOOST_ASSERT( ! check_validity || bg::is_valid(geometry) ); - BOOST_CHECK_MESSAGE( simple == expected_result, - "Expected: " << expected_result - << " detected: " << simple - << " wkt: " << bg::wkt(geometry) ); - - typedef typename bg::strategy::intersection::services::default_strategy - < - CSTag - >::type strategy_type; - - bool simple_s = bg::is_simple(geometry, strategy_type()); - - BOOST_CHECK_EQUAL(simple, simple_s); - -#ifdef BOOST_GEOMETRY_TEST_DEBUG - std::cout << "Geometry: "; - pretty_print_geometry::apply(std::cout, geometry); - std::cout << std::endl; - std::cout << std::boolalpha; - std::cout << "is simple: " << simple << std::endl; - std::cout << "expected result: " << expected_result << std::endl; - std::cout << "=======" << std::endl; - std::cout << std::endl << std::endl; - std::cout << std::noboolalpha; -#endif -} - - -template -void test_simple(Geometry const& geometry, - bool expected_result, - bool check_validity = true) -{ - typedef typename bg::cs_tag::type cs_tag; - test_simple(geometry, expected_result, check_validity); -} - -template -void test_simple(boost::variant const& variant_geometry, - bool expected_result, - bool check_validity = true) -{ - typedef typename bg::cs_tag::type cs_tag; - test_simple(variant_geometry, expected_result, check_validity); -} - - - -//---------------------------------------------------------------------------- - - BOOST_AUTO_TEST_CASE( test_is_simple_point ) { #ifdef BOOST_GEOMETRY_TEST_DEBUG diff --git a/test/algorithms/is_simple_geo.cpp b/test/algorithms/is_simple_geo.cpp new file mode 100644 index 000000000..30a01a30c --- /dev/null +++ b/test/algorithms/is_simple_geo.cpp @@ -0,0 +1,59 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) +// Unit Test + +// Copyright (c) 2014-2017, Oracle and/or its affiliates. + +// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle + +// Licensed under the Boost Software License version 1.0. +// http://www.boost.org/users/license.html + +#ifndef BOOST_TEST_MODULE +#define BOOST_TEST_MODULE test_is_simple_geo +#endif + +#include "test_is_simple.hpp" + + +typedef bg::model::point > point_type; +typedef bg::model::segment segment_type; +typedef bg::model::linestring linestring_type; +typedef bg::model::multi_linestring multi_linestring_type; +// ccw open and closed polygons +typedef bg::model::polygon open_ccw_polygon_type; +typedef bg::model::polygon closed_ccw_polygon_type; +// multi-geometries +typedef bg::model::multi_point multi_point_type; +typedef bg::model::multi_polygon multi_polygon_type; +// box +typedef bg::model::box box_type; + + +BOOST_AUTO_TEST_CASE( test_is_simple_geo_linestring ) +{ + typedef linestring_type G; + + bg::strategy::intersection::geographic_segments<> s; + + test_simple_s(from_wkt("LINESTRING(0 0, -90 0, 90 0)"), s, true); + test_simple_s(from_wkt("LINESTRING(0 90, -90 0, 90 0)"), s, false); + test_simple_s(from_wkt("LINESTRING(0 90, -90 50, 90 0)"), s, false); + test_simple_s(from_wkt("LINESTRING(0 90, -90 -50, 90 0)"), s, true); + + test_simple_s(from_wkt("LINESTRING(35 0, 110 36, 159 0, 82 30)"), s, false); + test_simple_s(from_wkt("LINESTRING(135 0, -150 36, -101 0, -178 30)"), s, false); + test_simple_s(from_wkt("LINESTRING(45 0, 120 36, 169 0, 92 30)"), s, false); + test_simple_s(from_wkt("LINESTRING(179 0, -179 1, -179 0, 179 1)"), s, false); +} + +BOOST_AUTO_TEST_CASE( test_is_simple_geo_multilinestring ) +{ + typedef multi_linestring_type G; + + bg::strategy::intersection::geographic_segments<> s; + + test_simple_s(from_wkt("MULTILINESTRING((35 0, 110 36),(159 0, 82 30))"), s, false); + test_simple_s(from_wkt("MULTILINESTRING((135 0, -150 36),(-101 0, -178 30))"), s, false); + test_simple_s(from_wkt("MULTILINESTRING((45 0, 120 36),(169 0, 92 30))"), s, false); + test_simple_s(from_wkt("MULTILINESTRING((179 0, -179 1),(-179 0, 179 1))"), s, false); +} diff --git a/test/algorithms/is_valid_geo.cpp b/test/algorithms/is_valid_geo.cpp new file mode 100644 index 000000000..e2a54146b --- /dev/null +++ b/test/algorithms/is_valid_geo.cpp @@ -0,0 +1,38 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) +// Unit Test + +// Copyright (c) 2014-2017, Oracle and/or its affiliates. + +// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle +// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle + +// Licensed under the Boost Software License version 1.0. +// http://www.boost.org/users/license.html + +#ifndef BOOST_TEST_MODULE +#define BOOST_TEST_MODULE test_is_valid_geo +#endif + +#include +#include + +#include + +#include "test_is_valid.hpp" + +#include + +#include +#include +#include + +BOOST_AUTO_TEST_CASE( test_is_valid_geo_polygon ) +{ + typedef bg::model::point > pt; + typedef bg::model::polygon G; + + typedef validity_tester_geo_areal tester; + typedef test_valid test; + + test::apply("p01", "POLYGON((-1 -1, 1 -1, 1 1, -1 1, -1 -1),(-0.5 -0.5, -0.5 0.5, 0.0 0.0, -0.5 -0.5),(0.0 0.0, 0.5 0.5, 0.5 -0.5, 0.0 0.0))", true); +} diff --git a/test/algorithms/overlay/relative_order.cpp b/test/algorithms/overlay/relative_order.cpp index e26f39066..8d2a5b47a 100644 --- a/test/algorithms/overlay/relative_order.cpp +++ b/test/algorithms/overlay/relative_order.cpp @@ -31,6 +31,9 @@ # include #endif +#include +#include + template void test_with_point(std::string const& /*caseid*/, @@ -46,7 +49,12 @@ void test_with_point(std::string const& /*caseid*/, P si = bg::make

(si_x, si_y); P sj = bg::make

(sj_x, sj_y); - int order = bg::detail::overlay::get_relative_order

::apply(pi, pj, ri, rj, si, sj); + typedef typename bg::strategy::side::services::default_strategy + < + typename bg::cs_tag

::type + >::type strategy_type; + + int order = bg::detail::overlay::get_relative_order::apply(pi, pj, ri, rj, si, sj, strategy_type()); BOOST_CHECK_EQUAL(order, expected_order); diff --git a/test/algorithms/overlay/sort_by_side.cpp b/test/algorithms/overlay/sort_by_side.cpp index 5635d46f6..b311dccc7 100644 --- a/test/algorithms/overlay/sort_by_side.cpp +++ b/test/algorithms/overlay/sort_by_side.cpp @@ -49,12 +49,14 @@ template typename Turns, typename Clusters, typename Geometry1, - typename Geometry2 + typename Geometry2, + typename SideStrategy > std::vector test_gather_cluster_properties(std::string const& case_id, Clusters& clusters, Turns& turns, bg::detail::overlay::operation_type for_operation, - Geometry1 const& geometry1, Geometry2 const& geometry2) + Geometry1 const& geometry1, Geometry2 const& geometry2, + SideStrategy const& strategy) { using namespace boost::geometry; using namespace boost::geometry::detail::overlay; @@ -69,7 +71,7 @@ std::vector test_gather_cluster_properties(std::string const& case_ // right side typedef sort_by_side::side_sorter < - Reverse1, Reverse2, OverlayType, point_type, std::less + Reverse1, Reverse2, OverlayType, point_type, SideStrategy, std::less > sbs_type; for (typename Clusters::iterator mit = clusters.begin(); @@ -82,7 +84,7 @@ std::vector test_gather_cluster_properties(std::string const& case_ return result; } - sbs_type sbs; + sbs_type sbs(strategy); point_type turn_point; // should be all the same for all turns in cluster bool first = true; @@ -165,7 +167,7 @@ std::vector apply_overlay(std::string const& case_id, // Gather cluster properties, with test option return test_gather_cluster_properties(case_id, clusters, turns, bg::detail::overlay::operation_from_overlay::value, - geometry1, geometry2); + geometry1, geometry2, strategy.get_side_strategy()); } diff --git a/test/algorithms/overlay/sort_by_side_basic.cpp b/test/algorithms/overlay/sort_by_side_basic.cpp index 877de7c50..15c85c285 100644 --- a/test/algorithms/overlay/sort_by_side_basic.cpp +++ b/test/algorithms/overlay/sort_by_side_basic.cpp @@ -89,13 +89,14 @@ std::vector apply_get_turns(std::string const& case_id, // Define sorter, sorting counter-clockwise such that polygons are on the // right side + typedef typename Strategy::side_strategy_type side_strategy; typedef bg::detail::overlay::sort_by_side::side_sorter < false, false, overlay_union, - point_type, std::less + point_type, side_strategy, std::less > sbs_type; - sbs_type sbs; + sbs_type sbs(strategy.get_side_strategy()); std::cout << "Case: " << case_id << std::endl; @@ -187,7 +188,7 @@ std::vector apply_get_turns(std::string const& case_id, } else { - BOOST_CHECK_MESSAGE(right_count[rank] == ranked_point.count_right, + BOOST_CHECK_MESSAGE(right_count[rank] == int(ranked_point.count_right), " caseid=" << case_id << " ranks: conflict in right_count=" << ranked_point.count_right << " vs " << right_count[rank]); diff --git a/test/algorithms/set_operations/union/union.cpp b/test/algorithms/set_operations/union/union.cpp index d36c842f4..a0e13f82d 100644 --- a/test/algorithms/set_operations/union/union.cpp +++ b/test/algorithms/set_operations/union/union.cpp @@ -398,9 +398,9 @@ void test_areal() // Robustness issues, followed out buffer-robustness-tests, test them also reverse #if ! defined(BOOST_GEOMETRY_NO_ROBUSTNESS) test_one("buffer_rt_f", buffer_rt_f[0], buffer_rt_f[1], - 1, 0, if_typed(18, 23), 4.60853); + 1, 0, 23, 4.60853); test_one("buffer_rt_f_rev", buffer_rt_f[1], buffer_rt_f[0], - 1, 0, if_typed(18, 23), 4.60853); + 1, 0, 23, 4.60853); test_one("buffer_rt_g", buffer_rt_g[0], buffer_rt_g[1], 1, 0, if_typed(18, 17), 16.571); test_one("buffer_rt_g_rev", buffer_rt_g[1], buffer_rt_g[0], diff --git a/test/algorithms/test_is_simple.hpp b/test/algorithms/test_is_simple.hpp new file mode 100644 index 000000000..d4162d04b --- /dev/null +++ b/test/algorithms/test_is_simple.hpp @@ -0,0 +1,121 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) +// Unit Test + +// Copyright (c) 2014-2017, Oracle and/or its affiliates. + +// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle +// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle + +// Licensed under the Boost Software License version 1.0. +// http://www.boost.org/users/license.html + + +#include +#include + +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include + +#include +#include +#include + +#include + +#ifdef BOOST_GEOMETRY_TEST_DEBUG +#include "pretty_print_geometry.hpp" +#endif + +namespace bg = ::boost::geometry; + +template +void test_simple_s(Geometry const& geometry, + Strategy const& strategy, + bool expected_result, + bool check_validity = true) +{ + bool simple = bg::is_simple(geometry, strategy); + bool valid = ! check_validity || bg::is_valid(geometry, strategy); + + BOOST_CHECK_MESSAGE( valid == true, + "Expected valid geometry, " + << " wkt: " << bg::wkt(geometry) ); + + BOOST_CHECK_MESSAGE( simple == expected_result, + "Expected: " << expected_result + << " detected: " << simple + << " wkt: " << bg::wkt(geometry) ); +} + +template +void test_simple(Geometry const& geometry, bool expected_result, + bool check_validity = true) +{ +#ifdef BOOST_GEOMETRY_TEST_DEBUG + std::cout << "=======" << std::endl; +#endif + + bool simple = bg::is_simple(geometry); + bool valid = ! check_validity || bg::is_valid(geometry); + + BOOST_CHECK_MESSAGE( valid == true, + "Expected valid geometry, " + << " wkt: " << bg::wkt(geometry) ); + + BOOST_CHECK_MESSAGE( simple == expected_result, + "Expected: " << expected_result + << " detected: " << simple + << " wkt: " << bg::wkt(geometry) ); + + typedef typename bg::strategy::intersection::services::default_strategy + < + CSTag + >::type strategy_type; + + test_simple_s(geometry, strategy_type(), expected_result, check_validity); + +#ifdef BOOST_GEOMETRY_TEST_DEBUG + std::cout << "Geometry: "; + pretty_print_geometry::apply(std::cout, geometry); + std::cout << std::endl; + std::cout << std::boolalpha; + std::cout << "is simple: " << simple << std::endl; + std::cout << "expected result: " << expected_result << std::endl; + std::cout << "=======" << std::endl; + std::cout << std::endl << std::endl; + std::cout << std::noboolalpha; +#endif +} + +template +void test_simple(Geometry const& geometry, + bool expected_result, + bool check_validity = true) +{ + typedef typename bg::cs_tag::type cs_tag; + test_simple(geometry, expected_result, check_validity); +} + +template +void test_simple(boost::variant const& variant_geometry, + bool expected_result, + bool check_validity = true) +{ + typedef typename bg::cs_tag::type cs_tag; + test_simple(variant_geometry, expected_result, check_validity); +} diff --git a/test/algorithms/test_is_valid.hpp b/test/algorithms/test_is_valid.hpp index 2776327d9..c230eca19 100644 --- a/test/algorithms/test_is_valid.hpp +++ b/test/algorithms/test_is_valid.hpp @@ -325,6 +325,30 @@ struct validity_tester_areal }; +template +struct validity_tester_geo_areal +{ + template + static inline bool apply(Geometry const& geometry) + { + bg::is_valid_default_policy visitor; + bg::strategy::intersection::geographic_segments<> s; + return bg::is_valid(geometry, visitor, s); + } + + template + static inline std::string reason(Geometry const& geometry) + { + std::ostringstream oss; + bg::failing_reason_policy visitor(oss); + bg::strategy::intersection::geographic_segments<> s; + bg::is_valid(geometry, visitor, s); + return oss.str(); + } + +}; + + //----------------------------------------------------------------------------