diff --git a/doc/quickref.xml b/doc/quickref.xml index 6bca7566c..0d6de52ca 100644 --- a/doc/quickref.xml +++ b/doc/quickref.xml @@ -614,6 +614,8 @@ strategy::simplify::douglas_peucker + + Transform @@ -625,9 +627,7 @@ strategy::transform::rotate_transformer - - - + Within strategy::winding diff --git a/doc/release_notes.qbk b/doc/release_notes.qbk index 9d859a22e..8d98af080 100644 --- a/doc/release_notes.qbk +++ b/doc/release_notes.qbk @@ -19,6 +19,25 @@ [section:release_notes Release Notes] +[/=================] +[heading Boost 1.71] +[/=================] + +[*Improvements] + +* [@https://github.com/boostorg/geometry/pull/568 568] Add a constructor that takes matrix_type to matrix_transformer. +* [@https://github.com/boostorg/geometry/pull/605 605] Improvement of handling of coordinate systems in various algorithms. +* Various improvements related to robustness of set and relational operation. + +[*Solved issues] + +* [@https://github.com/boostorg/geometry/issues/596 596] boost::geometry::buffer generates (multi)polygon with spike. + +[*Bugfixes] + +* [@https://github.com/boostorg/geometry/pull/595 595] Fix inaccuracy in geographic point-segment distance computation. +* Fix various compiler warnings. + [/=================] [heading Boost 1.70] [/=================] diff --git a/include/boost/geometry/algorithms/detail/buffer/buffer_inserter.hpp b/include/boost/geometry/algorithms/detail/buffer/buffer_inserter.hpp index a969b21cf..c79abcc7a 100644 --- a/include/boost/geometry/algorithms/detail/buffer/buffer_inserter.hpp +++ b/include/boost/geometry/algorithms/detail/buffer/buffer_inserter.hpp @@ -31,14 +31,16 @@ #include #include +#include #include #include -#include #include #include #include +#include + #include @@ -175,6 +177,16 @@ struct buffer_range } } + static inline bool similar_direction(output_point_type const& p0, + output_point_type const& p1, + output_point_type const& p2) + { + typedef model::infinite_line line_type; + line_type const p = detail::make::make_infinite_line(p0, p1); + line_type const q = detail::make::make_infinite_line(p1, p2); + return arithmetic::similar_direction(p, q); + } + template static inline geometry::strategy::buffer::join_selector get_join_type( output_point_type const& p0, @@ -185,13 +197,8 @@ struct buffer_range 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) - ) ? geometry::strategy::buffer::join_continue + : similar_direction(p0, p1, p2) + ? geometry::strategy::buffer::join_continue : geometry::strategy::buffer::join_spike; } 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 8a4618da4..de3f3c2b4 100644 --- a/include/boost/geometry/algorithms/detail/buffer/buffered_piece_collection.hpp +++ b/include/boost/geometry/algorithms/detail/buffer/buffered_piece_collection.hpp @@ -179,23 +179,22 @@ struct buffered_piece_collection typename IntersectionStrategy::cs_tag >::type rescale_policy_type; - typedef typename geometry::segment_ratio_type + typedef geometry::segment_ratio < - point_type, - RobustPolicy - >::type segment_ratio_type; + typename geometry::coordinate_type::type + > ratio_type; typedef buffer_turn_info < point_type, robust_point_type, - segment_ratio_type + ratio_type > buffer_turn_info_type; typedef buffer_turn_operation < point_type, - segment_ratio_type + ratio_type > buffer_turn_operation_type; typedef std::vector turn_vector_type; @@ -206,7 +205,7 @@ struct buffered_piece_collection int operation_index; robust_point_type point; segment_identifier seg_id; - segment_ratio_type fraction; + ratio_type fraction; }; struct piece @@ -484,25 +483,25 @@ struct buffered_piece_collection // intersection-point -> outgoing) // for all (co-located) points still present in the map - for (iterator_type it = boost::begin(m_turns); - it != boost::end(m_turns); - ++it) + for (iterator_type tit = boost::begin(m_turns); + tit != boost::end(m_turns); + ++tit) { typename occupation_map_type::iterator mit = - occupation_map.find(it->get_robust_point()); + occupation_map.find(tit->get_robust_point()); if (mit != occupation_map.end()) { buffer_occupation_info& info = mit->second; for (int i = 0; i < 2; i++) { - add_incoming_and_outgoing_angles(it->get_robust_point(), *it, + add_incoming_and_outgoing_angles(tit->get_robust_point(), *tit, m_pieces, - i, it->operations[i].seg_id, + i, tit->operations[i].seg_id, info); } - it->count_on_multi++; + tit->count_on_multi++; } } @@ -526,10 +525,10 @@ struct buffered_piece_collection #endif // Get left turns from all clusters - for (typename occupation_map_type::iterator it = occupation_map.begin(); - it != occupation_map.end(); ++it) + for (typename occupation_map_type::iterator mit = occupation_map.begin(); + mit != occupation_map.end(); ++mit) { - it->second.get_left_turns(it->first, m_turns, m_side_strategy); + mit->second.get_left_turns(mit->first, m_turns, m_side_strategy); } } diff --git a/include/boost/geometry/algorithms/detail/buffer/line_line_intersection.hpp b/include/boost/geometry/algorithms/detail/buffer/line_line_intersection.hpp index 11f1c689a..ec50d91a8 100644 --- a/include/boost/geometry/algorithms/detail/buffer/line_line_intersection.hpp +++ b/include/boost/geometry/algorithms/detail/buffer/line_line_intersection.hpp @@ -10,9 +10,9 @@ #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_BUFFER_LINE_LINE_INTERSECTION_HPP -#include +#include +#include #include -#include namespace boost { namespace geometry { @@ -22,55 +22,33 @@ namespace boost { namespace geometry namespace detail { namespace buffer { - -// TODO: once change this to proper strategy -// It is different from current segment intersection because these are not segments but lines -// If we have the Line concept, we can create a strategy -// Assumes a convex corner +// TODO: it might once be changed this to proper strategy struct line_line_intersection { - template - static inline strategy::buffer::join_selector apply(Point const& pi, Point const& pj, - Point const& qi, Point const& qj, Point& ip) + static inline strategy::buffer::join_selector + apply(Point const& pi, Point const& pj, + Point const& qi, Point const& qj, + Point& ip) { typedef typename coordinate_type::type ct; + typedef model::infinite_line line_type; - // Construct lines in general form (ax + by + c = 0), - // (will be replaced by a general_form structure in a next PR) - ct const pa = get<1>(pi) - get<1>(pj); - ct const pb = get<0>(pj) - get<0>(pi); - ct const pc = -pa * get<0>(pi) - pb * get<1>(pi); + line_type const p = detail::make::make_infinite_line(pi, pj); + line_type const q = detail::make::make_infinite_line(qi, qj); - ct const qa = get<1>(qi) - get<1>(qj); - ct const qb = get<0>(qj) - get<0>(qi); - ct const qc = -qa * get<0>(qi) - qb * get<1>(qi); - - ct const denominator = pb * qa - pa * qb; - - // Even if the corner was checked before (so it is convex now), that - // was done on the original geometry. This function runs on the buffered - // geometries, where sides are generated and might be slightly off. In - // Floating Point, that slightly might just exceed the limit and we have - // to check it again. - - // For round joins, it will not be used at all. - // For miter joins, there is a miter limit - // If segments are parallel/collinear we must be distinguish two cases: - // they continue each other, or they form a spike - ct const zero = ct(); - if (math::equals(denominator, zero)) + if (arithmetic::intersection_point(p, q, ip)) { - return parallel_continue(qb, -qa, pb, -pa) - ? strategy::buffer::join_continue - : strategy::buffer::join_spike - ; + return strategy::buffer::join_convex; } - set<0>(ip, (pc * qb - pb * qc) / denominator); - set<1>(ip, (pa * qc - pc * qa) / denominator); - - return strategy::buffer::join_convex; + // The lines do not intersect. + // Distinguish between continuing lines (having a similar direction) + // and spikes (having the opposite direction). + return arithmetic::similar_direction(p, q) + ? strategy::buffer::join_continue + : strategy::buffer::join_spike + ; } }; diff --git a/include/boost/geometry/algorithms/detail/buffer/parallel_continue.hpp b/include/boost/geometry/algorithms/detail/buffer/parallel_continue.hpp deleted file mode 100644 index 119d64de7..000000000 --- a/include/boost/geometry/algorithms/detail/buffer/parallel_continue.hpp +++ /dev/null @@ -1,33 +0,0 @@ -// Boost.Geometry (aka GGL, Generic Geometry Library) - -// Copyright (c) 2012-2014 Barend Gehrels, Amsterdam, the Netherlands. - -// 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) - -#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_BUFFER_PARALLEL_CONTINUE_HPP -#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_BUFFER_PARALLEL_CONTINUE_HPP - - -namespace boost { namespace geometry -{ - -#ifndef DOXYGEN_NO_DETAIL -namespace detail { namespace buffer -{ - -template -inline bool parallel_continue(T dx1, T dy1, T dx2, T dy2) -{ - T const dot = dx1 * dx2 + dy1 * dy2; - return dot > 0; -} - -}} // namespace detail::buffer -#endif // DOXYGEN_NO_DETAIL - - -}} // namespace boost::geometry - -#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_BUFFER_PARALLEL_CONTINUE_HPP diff --git a/include/boost/geometry/algorithms/detail/calculate_point_order.hpp b/include/boost/geometry/algorithms/detail/calculate_point_order.hpp new file mode 100644 index 000000000..a3024076e --- /dev/null +++ b/include/boost/geometry/algorithms/detail/calculate_point_order.hpp @@ -0,0 +1,370 @@ +// Boost.Geometry + +// Copyright (c) 2019, 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_GEOMETRY_ALGORITHMS_DETAIL_CALCULATE_POINT_ORDER_HPP +#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_CALCULATE_POINT_ORDER_HPP + + +#include + +#include + +#include +#include +#include +#include +#include +#include + + +namespace boost { namespace geometry +{ + +namespace detail +{ + +template +struct clean_point +{ + explicit clean_point(Iter const& iter) + : m_iter(iter), m_azi(0), m_razi(0), m_azi_diff(0) + , m_is_azi_valid(false), m_is_azi_diff_valid(false) + {} + + typename boost::iterators::iterator_reference::type ref() const + { + return *m_iter; + } + + CalcT const& azimuth() const + { + return m_azi; + } + + CalcT const& reverse_azimuth() const + { + return m_razi; + } + + CalcT const& azimuth_difference() const + { + return m_azi_diff; + } + + void set_azimuths(CalcT const& azi, CalcT const& razi) + { + m_azi = azi; + m_razi = razi; + m_is_azi_valid = true; + } + + void set_azimuth_invalid() + { + m_is_azi_valid = false; + } + + bool is_azimuth_valid() const + { + return m_is_azi_valid; + } + + void set_azimuth_difference(CalcT const& diff) + { + m_azi_diff = diff; + m_is_azi_diff_valid = true; + } + + void set_azimuth_difference_invalid() + { + m_is_azi_diff_valid = false; + } + + bool is_azimuth_difference_valid() const + { + return m_is_azi_diff_valid; + } + +private: + Iter m_iter; + CalcT m_azi; + CalcT m_razi; + CalcT m_azi_diff; + // NOTE: these flags could be removed and replaced with some magic number + // assigned to the above variables, e.g. CalcT(1000). + bool m_is_azi_valid; + bool m_is_azi_diff_valid; +}; + +struct calculate_point_order_by_azimuth +{ + template + static geometry::order_selector apply(Ring const& ring, Strategy const& strategy) + { + typedef typename boost::range_iterator::type iter_t; + typedef typename Strategy::template result_type::type calc_t; + typedef clean_point clean_point_t; + typedef std::vector cleaned_container_t; + typedef typename cleaned_container_t::iterator cleaned_iter_t; + + calc_t const zero = 0; + calc_t const pi = math::pi(); + + std::size_t const count = boost::size(ring); + if (count < 3) + { + return geometry::order_undetermined; + } + + // non-duplicated, non-spike points + cleaned_container_t cleaned; + cleaned.reserve(count); + + for (iter_t it = boost::begin(ring); it != boost::end(ring); ++it) + { + // Add point + cleaned.push_back(clean_point_t(it)); + + while (cleaned.size() >= 3) + { + cleaned_iter_t it0 = cleaned.end() - 3; + cleaned_iter_t it1 = cleaned.end() - 2; + cleaned_iter_t it2 = cleaned.end() - 1; + + calc_t diff; + if (get_or_calculate_azimuths_difference(*it0, *it1, *it2, diff, strategy) + && ! math::equals(math::abs(diff), pi)) + { + // neither duplicate nor a spike - difference already stored + break; + } + else + { + // spike detected + // TODO: angles have to be invalidated only if spike is detected + // for duplicates it'd be ok to leave them + it0->set_azimuth_invalid(); + it0->set_azimuth_difference_invalid(); + it2->set_azimuth_difference_invalid(); + cleaned.erase(it1); + } + } + } + + // filter-out duplicates and spikes at the front and back of cleaned + cleaned_iter_t cleaned_b = cleaned.begin(); + cleaned_iter_t cleaned_e = cleaned.end(); + std::size_t cleaned_count = cleaned.size(); + bool found = false; + do + { + found = false; + while(cleaned_count >= 3) + { + cleaned_iter_t it0 = cleaned_e - 2; + cleaned_iter_t it1 = cleaned_e - 1; + cleaned_iter_t it2 = cleaned_b; + cleaned_iter_t it3 = cleaned_b + 1; + + calc_t diff = 0; + if (! get_or_calculate_azimuths_difference(*it0, *it1, *it2, diff, strategy) + || math::equals(math::abs(diff), pi)) + { + // spike at the back + // TODO: angles have to be invalidated only if spike is detected + // for duplicates it'd be ok to leave them + it0->set_azimuth_invalid(); + it0->set_azimuth_difference_invalid(); + it2->set_azimuth_difference_invalid(); + --cleaned_e; + --cleaned_count; + found = true; + } + else if (! get_or_calculate_azimuths_difference(*it1, *it2, *it3, diff, strategy) + || math::equals(math::abs(diff), pi)) + { + // spike at the front + // TODO: angles have to be invalidated only if spike is detected + // for duplicates it'd be ok to leave them + it1->set_azimuth_invalid(); + it1->set_azimuth_difference_invalid(); + it3->set_azimuth_difference_invalid(); + ++cleaned_b; + --cleaned_count; + found = true; + } + else + { + break; + } + } + } + while (found); + + if (cleaned_count < 3) + { + return geometry::order_undetermined; + } + + // calculate the sum of external angles + calc_t angles_sum = zero; + for (cleaned_iter_t it = cleaned_b; it != cleaned_e; ++it) + { + cleaned_iter_t it0 = (it == cleaned_b ? cleaned_e - 1 : it - 1); + cleaned_iter_t it2 = (it == cleaned_e - 1 ? cleaned_b : it + 1); + + calc_t diff = 0; + get_or_calculate_azimuths_difference(*it0, *it, *it2, diff, strategy); + + angles_sum += diff; + } + +#ifdef BOOST_GEOMETRY_DEBUG_POINT_ORDER + std::cout << angles_sum << " for " << geometry::wkt(ring) << std::endl; +#endif + + return angles_sum == zero ? geometry::order_undetermined + : angles_sum > zero ? geometry::clockwise + : geometry::counterclockwise; + } + +private: + template + static bool get_or_calculate_azimuths_difference(clean_point & p0, + clean_point & p1, + clean_point const& p2, + T & diff, + Strategy const& strategy) + { + if (p1.is_azimuth_difference_valid()) + { + diff = p1.azimuth_difference(); + return true; + } + + T azi1, razi1, azi2, razi2; + if (get_or_calculate_azimuths(p0, p1, azi1, razi1, strategy) + && get_or_calculate_azimuths(p1, p2, azi2, razi2, strategy)) + { + diff = strategy.apply(p0.ref(), p1.ref(), p2.ref(), razi1, azi2); + p1.set_azimuth_difference(diff); + return true; + } + return false; + } + + template + static bool get_or_calculate_azimuths(clean_point & p0, + clean_point const& p1, + T & azi, T & razi, + Strategy const& strategy) + { + if (p0.is_azimuth_valid()) + { + azi = p0.azimuth(); + razi = p0.reverse_azimuth(); + return true; + } + + if (strategy.apply(p0.ref(), p1.ref(), azi, razi)) + { + p0.set_azimuths(azi, razi); + return true; + } + + return false; + } +}; + +struct calculate_point_order_by_area +{ + template + static geometry::order_selector apply(Ring const& ring, Strategy const& strategy) + { + typedef detail::area::ring_area + < + geometry::order_as_direction::value>::value, + geometry::closure::value + > ring_area_type; + + typedef typename area_result + < + Ring, Strategy + >::type result_type; + + result_type const result = ring_area_type::apply(ring, strategy); + + result_type const zero = 0; + return result == zero ? geometry::order_undetermined + : result > zero ? geometry::clockwise + : geometry::counterclockwise; + } +}; + +} // namespace detail + +namespace dispatch +{ + +template +< + typename Strategy, + typename VersionTag = typename Strategy::version_tag +> +struct calculate_point_order +{ + BOOST_MPL_ASSERT_MSG + ( + false, NOT_IMPLEMENTED_FOR_THIS_TAG, (types) + ); +}; + +template +struct calculate_point_order + : geometry::detail::calculate_point_order_by_area +{}; + +template +struct calculate_point_order + : geometry::detail::calculate_point_order_by_azimuth +{}; + + +} // namespace dispatch + +namespace detail +{ + +template +inline geometry::order_selector calculate_point_order(Ring const& ring, Strategy const& strategy) +{ + concepts::check(); + + return dispatch::calculate_point_order::apply(ring, strategy); +} + +template +inline geometry::order_selector calculate_point_order(Ring const& ring) +{ + typedef typename strategy::point_order::services::default_strategy + < + typename geometry::cs_tag::type + >::type strategy_type; + + concepts::check(); + + return dispatch::calculate_point_order::apply(ring, strategy_type()); +} + + +} // namespace detail + +}} // namespace boost::geometry + + +#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_CALCULATE_POINT_ORDER_HPP diff --git a/include/boost/geometry/algorithms/detail/closest_feature/point_to_range.hpp b/include/boost/geometry/algorithms/detail/closest_feature/point_to_range.hpp index df6789013..e5e8c6c25 100644 --- a/include/boost/geometry/algorithms/detail/closest_feature/point_to_range.hpp +++ b/include/boost/geometry/algorithms/detail/closest_feature/point_to_range.hpp @@ -71,8 +71,11 @@ protected: // check if other segments are closer for (++prev, ++it; it != last; ++prev, ++it) { - Distance dist = strategy.apply(point, *prev, *it); - if (geometry::math::equals(dist, zero)) + Distance const dist = strategy.apply(point, *prev, *it); + + // Stop only if we find exactly zero distance + // otherwise it may stop at some very small value and miss the min + if (dist == zero) { dist_min = zero; it_min1 = prev; diff --git a/include/boost/geometry/algorithms/detail/direction_code.hpp b/include/boost/geometry/algorithms/detail/direction_code.hpp index ab3b1e0a2..38c65afa2 100644 --- a/include/boost/geometry/algorithms/detail/direction_code.hpp +++ b/include/boost/geometry/algorithms/detail/direction_code.hpp @@ -12,11 +12,13 @@ // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) -#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_DIRECITON_CODE_HPP -#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_DIRECITON_CODE_HPP +#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_DIRECTION_CODE_HPP +#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_DIRECTION_CODE_HPP #include +#include +#include #include #include #include @@ -32,20 +34,6 @@ namespace boost { namespace geometry namespace detail { - -// TODO: remove -template -inline int sign_of_difference(Point1 const& point1, Point2 const& point2) -{ - return - math::equals(geometry::get(point1), geometry::get(point2)) - ? - 0 - : - (geometry::get(point1) > geometry::get(point2) ? 1 : -1); -} - - template struct direction_code_impl { @@ -57,42 +45,30 @@ struct direction_code_impl { template static inline int apply(Point1 const& segment_a, Point1 const& segment_b, - Point2 const& p) + Point2 const& point) { 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))) ) + typedef model::infinite_line line_type; + + // point b is often equal to the specified point, check that first + line_type const q = detail::make::make_infinite_line(segment_b, point); + if (arithmetic::is_degenerate(q)) { 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) + line_type const p = detail::make::make_infinite_line(segment_a, segment_b); + if (arithmetic::is_degenerate(p)) { - s1 = x1 > 0 ? 1 : -1; - s2 = x2 > 0 ? 1 : -1; - } - else - { - s1 = y1 > 0 ? 1 : -1; - s2 = y2 > 0 ? 1 : -1; + return 0; } - return s1 == s2 ? -1 : 1; + // p extends a-b if direction is similar + return arithmetic::similar_direction(p, q) ? 1 : -1; } }; @@ -277,4 +253,4 @@ inline int direction_code(Point1 const& segment_a, Point1 const& segment_b, }} // namespace boost::geometry -#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_DIRECITON_CODE_HPP +#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_DIRECTION_CODE_HPP diff --git a/include/boost/geometry/algorithms/detail/disjoint/linear_linear.hpp b/include/boost/geometry/algorithms/detail/disjoint/linear_linear.hpp index 7b830f7d1..cefa5e9f8 100644 --- a/include/boost/geometry/algorithms/detail/disjoint/linear_linear.hpp +++ b/include/boost/geometry/algorithms/detail/disjoint/linear_linear.hpp @@ -34,10 +34,10 @@ #include #include #include +#include #include #include -#include #include @@ -59,28 +59,17 @@ struct disjoint_segment { typedef typename point_type::type point_type; - // We don't need to rescale to detect disjointness - typedef no_rescale_policy rescale_policy_type; - rescale_policy_type robust_policy; - - typedef segment_intersection_points - < - point_type, - typename segment_ratio_type - < - point_type, - rescale_policy_type - >::type - > intersection_return_type; + typedef segment_intersection_points intersection_return_type; typedef policies::relate::segments_intersection_points < intersection_return_type > intersection_policy; - intersection_return_type is = strategy.apply(segment1, segment2, - intersection_policy(), - robust_policy); + detail::segment_as_subrange sub_range1(segment1); + detail::segment_as_subrange sub_range2(segment2); + intersection_return_type is = strategy.apply(sub_range1, sub_range2, + intersection_policy()); return is.count == 0; } @@ -105,18 +94,17 @@ struct disjoint_linear Strategy const& strategy) { typedef typename geometry::point_type::type point_type; - typedef detail::no_rescale_policy rescale_policy_type; - typedef typename geometry::segment_ratio_type + typedef geometry::segment_ratio < - point_type, rescale_policy_type - >::type segment_ratio_type; + typename coordinate_type::type + > ratio_type; typedef overlay::turn_info < point_type, - segment_ratio_type, + ratio_type, typename detail::get_turns::turn_operation_type < - Geometry1, Geometry2, segment_ratio_type + Geometry1, Geometry2, ratio_type >::type > turn_info_type; @@ -139,7 +127,7 @@ struct disjoint_linear Geometry1, Geometry2, assign_disjoint_policy > >::apply(0, geometry1, 1, geometry2, - strategy, rescale_policy_type(), turns, interrupt_policy); + strategy, detail::no_rescale_policy(), turns, interrupt_policy); return !interrupt_policy.has_intersections; } diff --git a/include/boost/geometry/algorithms/detail/equals/implementation.hpp b/include/boost/geometry/algorithms/detail/equals/implementation.hpp index f39ae0b8b..4088478d5 100644 --- a/include/boost/geometry/algorithms/detail/equals/implementation.hpp +++ b/include/boost/geometry/algorithms/detail/equals/implementation.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 2014, 2015, 2016, 2017, 2018. -// Modifications copyright (c) 2014-2018 Oracle and/or its affiliates. +// This file was modified by Oracle on 2014, 2015, 2016, 2017, 2018, 2019. +// Modifications copyright (c) 2014-2019 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 @@ -275,6 +275,15 @@ private: } }; +struct equals_always_false +{ + template + static inline bool apply(Geometry1 const& , Geometry2 const& , Strategy const& ) + { + return false; + } +}; + }} // namespace detail::equals #endif // DOXYGEN_NO_DETAIL @@ -285,81 +294,92 @@ namespace dispatch { template -struct equals +struct equals : detail::equals::point_point<0, DimensionCount> {}; template -struct equals +struct equals : detail::equals::equals_by_relate {}; template -struct equals +struct equals : detail::equals::equals_by_relate {}; template -struct equals +struct equals : detail::equals::box_box<0, DimensionCount> {}; template -struct equals +struct equals : detail::equals::equals_by_collection_or_relate {}; template -struct equals +struct equals : detail::equals::equals_by_collection_or_relate {}; template -struct equals +struct equals : detail::equals::equals_by_collection_or_relate {}; template -struct equals +struct equals : detail::equals::equals_by_collection {}; template -struct equals +struct equals : detail::equals::equals_by_collection {}; template -struct equals +struct equals : detail::equals::segment_segment {}; template -struct equals +struct equals : detail::equals::equals_by_relate {}; template -struct equals +struct equals : detail::equals::equals_by_relate {}; template -struct equals +struct equals : detail::equals::equals_by_relate {}; +template +struct equals + : detail::equals::equals_by_relate +{}; + +template +struct equals + : detail::equals::equals_by_relate +{}; + template struct equals < MultiPolygon1, MultiPolygon2, multi_polygon_tag, multi_polygon_tag, + areal_tag, areal_tag, 2, Reverse > @@ -372,6 +392,7 @@ struct equals < Polygon, MultiPolygon, polygon_tag, multi_polygon_tag, + areal_tag, areal_tag, 2, Reverse > @@ -383,6 +404,7 @@ struct equals < MultiPolygon, Ring, multi_polygon_tag, ring_tag, + areal_tag, areal_tag, 2, Reverse > @@ -390,6 +412,42 @@ struct equals {}; +// NOTE: degenerated linear geometries, e.g. segment or linestring containing +// 2 equal points, are considered to be invalid. Though theoretically +// degenerated segments and linestrings could be treated as points and +// multi-linestrings as multi-points. +// This reasoning could also be applied to boxes. + +template +struct equals + : detail::equals::equals_always_false +{}; + +template +struct equals + : detail::equals::equals_always_false +{}; + +template +struct equals + : detail::equals::equals_always_false +{}; + +template +struct equals + : detail::equals::equals_always_false +{}; + +template +struct equals + : detail::equals::equals_always_false +{}; + +template +struct equals + : detail::equals::equals_always_false +{}; + } // namespace dispatch #endif // DOXYGEN_NO_DISPATCH diff --git a/include/boost/geometry/algorithms/detail/equals/interface.hpp b/include/boost/geometry/algorithms/detail/equals/interface.hpp index eacf95e9f..1e4918836 100644 --- a/include/boost/geometry/algorithms/detail/equals/interface.hpp +++ b/include/boost/geometry/algorithms/detail/equals/interface.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 2014, 2015, 2016, 2017. -// Modifications copyright (c) 2014-2017 Oracle and/or its affiliates. +// This file was modified by Oracle on 2014, 2015, 2016, 2017, 2019. +// Modifications copyright (c) 2014-2019 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 @@ -52,6 +52,8 @@ template typename Geometry2, typename Tag1 = typename tag::type, typename Tag2 = typename tag::type, + typename CastedTag1 = typename tag_cast::type, + typename CastedTag2 = typename tag_cast::type, std::size_t DimensionCount = dimension::type::value, bool Reverse = reverse_dispatch::type::value > @@ -64,10 +66,11 @@ template < typename Geometry1, typename Geometry2, typename Tag1, typename Tag2, + typename CastedTag1, typename CastedTag2, std::size_t DimensionCount > -struct equals - : equals +struct equals + : equals { template static inline bool apply(Geometry1 const& g1, Geometry2 const& g2, Strategy const& strategy) @@ -76,6 +79,7 @@ struct equals < Geometry2, Geometry1, Tag2, Tag1, + CastedTag2, CastedTag1, DimensionCount, false >::apply(g2, g1, strategy); diff --git a/include/boost/geometry/algorithms/detail/get_left_turns.hpp b/include/boost/geometry/algorithms/detail/get_left_turns.hpp index 1fec47a01..2e0275a9b 100644 --- a/include/boost/geometry/algorithms/detail/get_left_turns.hpp +++ b/include/boost/geometry/algorithms/detail/get_left_turns.hpp @@ -247,17 +247,11 @@ inline void block_turns(AngleCollection& sorted, std::size_t cluster_size) for (typename boost::range_iterator::type it = sorted.begin(); it != sorted.end(); ++it) { - signed_size_type cluster_index = static_cast(it->cluster_index); - signed_size_type previous_index = cluster_index - 1; - if (previous_index < 0) - { - previous_index = cluster_size - 1; - } - signed_size_type next_index = cluster_index + 1; - if (next_index >= static_cast(cluster_size)) - { - next_index = 0; - } + std::size_t const cluster_index = it->cluster_index; + std::size_t const previous_index + = cluster_index == 0 ? cluster_size - 1 : cluster_index - 1; + std::size_t const next_index + = cluster_index + 1 >= cluster_size ? 0 : cluster_index + 1; if (directions[cluster_index].first && directions[cluster_index].second) diff --git a/include/boost/geometry/algorithms/detail/intersects/implementation.hpp b/include/boost/geometry/algorithms/detail/intersects/implementation.hpp index f9b5402d0..cbb442ce4 100644 --- a/include/boost/geometry/algorithms/detail/intersects/implementation.hpp +++ b/include/boost/geometry/algorithms/detail/intersects/implementation.hpp @@ -29,7 +29,6 @@ #include #include #include -#include #include @@ -53,13 +52,8 @@ struct self_intersects < Geometry, Geometry >::type strategy_type; - typedef detail::no_rescale_policy rescale_policy_type; - typedef detail::overlay::turn_info - < - point_type, - typename segment_ratio_type::type - > turn_info; + typedef detail::overlay::turn_info turn_info; std::deque turns; @@ -69,14 +63,13 @@ struct self_intersects > turn_policy; strategy_type strategy; - rescale_policy_type robust_policy; detail::disjoint::disjoint_interrupt_policy policy; // TODO: skip_adjacent should be set to false detail::self_get_turn_points::get_turns < false, turn_policy - >::apply(geometry, strategy, robust_policy, turns, policy, 0, true); + >::apply(geometry, strategy, detail::no_rescale_policy(), turns, policy, 0, true); return policy.has_intersections; } }; diff --git a/include/boost/geometry/algorithms/detail/is_simple/linear.hpp b/include/boost/geometry/algorithms/detail/is_simple/linear.hpp index 57bc295e5..a9a3aaf31 100644 --- a/include/boost/geometry/algorithms/detail/is_simple/linear.hpp +++ b/include/boost/geometry/algorithms/detail/is_simple/linear.hpp @@ -206,14 +206,7 @@ inline bool has_self_intersections(Linear const& linear, Strategy const& strateg typedef typename point_type::type point_type; // compute self turns - typedef detail::overlay::turn_info - < - point_type, - geometry::segment_ratio - < - typename geometry::coordinate_type::type - > - > turn_info; + typedef detail::overlay::turn_info turn_info; std::deque turns; diff --git a/include/boost/geometry/algorithms/detail/is_valid/has_valid_self_turns.hpp b/include/boost/geometry/algorithms/detail/is_valid/has_valid_self_turns.hpp index 1978e8309..e99e41133 100644 --- a/include/boost/geometry/algorithms/detail/is_valid/has_valid_self_turns.hpp +++ b/include/boost/geometry/algorithms/detail/is_valid/has_valid_self_turns.hpp @@ -63,7 +63,7 @@ public: typedef detail::overlay::turn_info < point_type, - typename geometry::segment_ratio_type + typename segment_ratio_type < point_type, rescale_policy_type @@ -87,11 +87,13 @@ public: is_acceptable_turn > interrupt_policy; + // Calculate self-turns, skipping adjacent segments detail::self_get_turn_points::self_turns(geometry, strategy, robust_policy, turns, - interrupt_policy); + interrupt_policy, + 0, true); if (interrupt_policy.has_intersections) { diff --git a/include/boost/geometry/algorithms/detail/make/make.hpp b/include/boost/geometry/algorithms/detail/make/make.hpp new file mode 100644 index 000000000..87631992a --- /dev/null +++ b/include/boost/geometry/algorithms/detail/make/make.hpp @@ -0,0 +1,60 @@ +// Boost.Geometry + +// Copyright (c) 2019 Barend Gehrels, Amsterdam, the Netherlands. + +// 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) + +#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_MAKE_MAKE_HPP +#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_MAKE_MAKE_HPP + +#include +#include + +namespace boost { namespace geometry +{ + +#ifndef DOXYGEN_NO_DETAIL +namespace detail { namespace make +{ + +template +inline +model::infinite_line make_infinite_line(Coordinate const& x1, + Coordinate const& y1, Coordinate const& x2, Coordinate const& y2) +{ + model::infinite_line result; + result.a = y1 - y2; + result.b = x2 - x1; + result.c = -result.a * x1 - result.b * y1; + return result; +} + +template +inline +model::infinite_line make_infinite_line(Point const& a, Point const& b) +{ + return make_infinite_line(geometry::get<0>(a), geometry::get<1>(a), + geometry::get<0>(b), geometry::get<1>(b)); +} + +template +inline +model::infinite_line make_infinite_line(Segment const& segment) +{ + return make_infinite_line(geometry::get<0, 0>(segment), + geometry::get<0, 1>(segment), + geometry::get<1, 0>(segment), + geometry::get<1, 1>(segment)); +} + + + +}} // namespace detail::make +#endif // DOXYGEN_NO_DETAIL + + +}} // namespace boost::geometry + +#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_MAKE_MAKE_HPP 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 d82c34cc7..fbb126bbc 100644 --- a/include/boost/geometry/algorithms/detail/overlay/enrich_intersection_points.hpp +++ b/include/boost/geometry/algorithms/detail/overlay/enrich_intersection_points.hpp @@ -426,12 +426,6 @@ inline void enrich_intersection_points(Turns& turns, std::vector > mapped_vector_type; - // As long as turn indexes are not used yet, turns might be erased from - // the vector - // For now start turns are disabled. - // TODO: remove code or fix inconsistencies within validity and relations - // detail::overlay::erase_colocated_start_turns(turns, geometry1, geometry2); - // From here on, turn indexes are used (in clusters, next_index, etc) // and may only be flagged as discarded diff --git a/include/boost/geometry/algorithms/detail/overlay/get_distance_measure.hpp b/include/boost/geometry/algorithms/detail/overlay/get_distance_measure.hpp index a306cb442..a4de22b27 100644 --- a/include/boost/geometry/algorithms/detail/overlay/get_distance_measure.hpp +++ b/include/boost/geometry/algorithms/detail/overlay/get_distance_measure.hpp @@ -12,6 +12,8 @@ #include #include #include +#include +#include #include #include @@ -100,26 +102,14 @@ struct get_distance_measure static result_type apply(SegmentPoint const& p1, SegmentPoint const& p2, Point const& p) { - typedef CalculationType ct; + // Get the distance measure / side value + // It is not a real distance and purpose is + // to detect small differences in collinearity - // Construct a line in general form (ax + by + c = 0), - // (will be replaced by a general_form structure in next PR) - ct const x1 = geometry::get<0>(p1); - ct const y1 = geometry::get<1>(p1); - ct const x2 = geometry::get<0>(p2); - ct const y2 = geometry::get<1>(p2); - ct const a = y1 - y2; - ct const b = x2 - x1; - ct const c = -a * x1 - b * y1; - - // Returns a distance measure - // https://en.wikipedia.org/wiki/Distance_from_a_point_to_a_line#Line_defined_by_an_equation - // dividing by sqrt(a*a+b*b) is not necessary for this distance measure, - // it is not a real distance and purpose is to detect small differences - // in collinearity + typedef model::infinite_line line_type; + line_type const line = detail::make::make_infinite_line(p1, p2); result_type result; - result.measure = a * geometry::get<0>(p) + b * geometry::get<1>(p) + c; - + result.measure = arithmetic::side_value(line, p); return result; } }; diff --git a/include/boost/geometry/algorithms/detail/overlay/get_intersection_points.hpp b/include/boost/geometry/algorithms/detail/overlay/get_intersection_points.hpp index 5a3360375..4b0e9ed79 100644 --- a/include/boost/geometry/algorithms/detail/overlay/get_intersection_points.hpp +++ b/include/boost/geometry/algorithms/detail/overlay/get_intersection_points.hpp @@ -22,11 +22,10 @@ #include #include +#include #include -#include - namespace boost { namespace geometry { @@ -56,45 +55,25 @@ struct get_turn_without_info UniqueSubRange2 const& range_q, TurnInfo const& , Strategy const& strategy, - RobustPolicy const& robust_policy, + RobustPolicy const& , OutputIterator out) { + // Make sure this is only called with no rescaling + BOOST_STATIC_ASSERT((boost::is_same + < + no_rescale_policy_tag, + typename rescale_policy_type::type + >::value)); + typedef typename TurnInfo::point_type turn_point_type; typedef policies::relate::segments_intersection_points < - segment_intersection_points - < - turn_point_type, - typename geometry::segment_ratio_type - < - turn_point_type, RobustPolicy - >::type - > + segment_intersection_points > policy_type; - typedef model::referring_segment segment_type1; - typedef model::referring_segment segment_type2; - Point1 const& pi = range_p.at(0); - Point1 const& pj = range_p.at(1); - Point2 const& qi = range_q.at(0); - Point2 const& qj = range_q.at(1); - segment_type1 p1(pi, pj); - segment_type2 q1(qi, qj); - - typedef typename geometry::robust_point_type - < - Point1, RobustPolicy - >::type robust_point_type; - - robust_point_type pi_rob, pj_rob, qi_rob, qj_rob; - geometry::recalculate(pi_rob, pi, robust_policy); - geometry::recalculate(pj_rob, pj, robust_policy); - geometry::recalculate(qi_rob, qi, robust_policy); - geometry::recalculate(qj_rob, qj, robust_policy); - typename policy_type::return_type result - = strategy.apply(p1, q1, policy_type(), robust_policy, - pi_rob, pj_rob, qi_rob, qj_rob); + typename policy_type::return_type const result + = strategy.apply(range_p, range_q, policy_type()); for (std::size_t i = 0; i < result.count; i++) { diff --git a/include/boost/geometry/algorithms/detail/overlay/get_turn_info.hpp b/include/boost/geometry/algorithms/detail/overlay/get_turn_info.hpp index f726fc1a0..7404dabb4 100644 --- a/include/boost/geometry/algorithms/detail/overlay/get_turn_info.hpp +++ b/include/boost/geometry/algorithms/detail/overlay/get_turn_info.hpp @@ -153,12 +153,14 @@ struct base_turn_handler typename UmbrellaStrategy, typename TurnInfo > - static inline void both_collinear(UniqueSubRange1 const& range_p, + static inline void both_collinear( + UniqueSubRange1 const& range_p, UniqueSubRange2 const& range_q, - UmbrellaStrategy const& umbrella_strategy, + UmbrellaStrategy const&, std::size_t index_p, std::size_t index_q, TurnInfo& ti) { + boost::ignore_unused(range_p, range_q); BOOST_GEOMETRY_ASSERT(IndexP + IndexQ == 1); BOOST_GEOMETRY_ASSERT(index_p > 0 && index_p <= 2); BOOST_GEOMETRY_ASSERT(index_q > 0 && index_q <= 2); @@ -617,133 +619,6 @@ struct equal : public base_turn_handler } }; - -template -< - typename TurnInfo -> -struct start : public base_turn_handler -{ - template - < - typename UniqueSubRange1, - typename UniqueSubRange2, - typename IntersectionInfo, - typename DirInfo, - typename SideCalculator, - typename UmbrellaStrategy - > - static inline bool apply(UniqueSubRange1 const& range_p, - UniqueSubRange2 const& range_q, - TurnInfo& ti, - IntersectionInfo const& info, - DirInfo const& dir_info, - SideCalculator const& side, - UmbrellaStrategy const& ) - { - // For now disabled. TODO: remove all code or fix inconsistencies - // within validity and relations - return false; - - if (dir_info.opposite) - { - // They should not be collinear - return false; - } - - int const side_pj_q1 = side.pj_wrt_q1(); - int const side_qj_p1 = side.qj_wrt_p1(); - - // Get side values at starting point - typedef detail::distance_measure - < - typename select_coordinate_type - < - typename UniqueSubRange1::point_type, - typename UniqueSubRange2::point_type - >::type - > dm_type; - - typedef typename UmbrellaStrategy::cs_tag cs_tag; - dm_type const dm_pi_q1 = get_distance_measure(range_q.at(0), range_q.at(1), range_p.at(0)); - dm_type const dm_qi_p1 = get_distance_measure(range_p.at(0), range_p.at(1), range_q.at(0)); - - if (dir_info.how_a == -1 && dir_info.how_b == -1) - { - // Both p and q leave - if (dm_pi_q1.is_zero() && dm_qi_p1.is_zero()) - { - // Exactly collinear, not necessary to handle it - return false; - } - - if (! (dm_pi_q1.is_small() && dm_qi_p1.is_small())) - { - // Not nearly collinear - return false; - } - - if (side_qj_p1 == 0) - { - // Collinear is not handled - return false; - } - - ui_else_iu(side_qj_p1 == -1, ti); - } - else if (dir_info.how_b == -1) - { - // p ---------------> - // | - // | q q leaves - // v - // - - if (dm_qi_p1.is_zero() || ! dm_qi_p1.is_small()) - { - // Exactly collinear - return false; - } - - if (side_qj_p1 == 0) - { - // Collinear is not handled - return false; - } - - ui_else_iu(side_qj_p1 == -1, ti); - } - else if (dir_info.how_a == -1) - { - if (dm_pi_q1.is_zero() || ! dm_pi_q1.is_small()) - { - // It starts exactly, not necessary to handle it - return false; - } - - // p leaves - if (side_pj_q1 == 0) - { - // Collinear is not handled - return false; - } - - ui_else_iu(side_pj_q1 == 1, ti); - } - else - { - // Not supported - return false; - } - - // Copy intersection point - assign_point(ti, method_start, info, 0); - return true; - } - -}; - - template < typename TurnInfo, @@ -1167,6 +1042,8 @@ struct get_turn_info switch(method) { case 'a' : // "angle" + case 'f' : // "from" + case 's' : // "start" do_only_convert = true; break; @@ -1208,20 +1085,6 @@ struct get_turn_info *out++ = tp; } break; - case 'f' : - case 's' : - { - // "from" or "start" without rescaling, it is in some cases necessary to handle - if (start::apply(range_p, range_q, tp, inters.i_info(), inters.d_info(), inters.sides(), umbrella_strategy)) - { - *out++ = tp; - } - else - { - do_only_convert = true; - } - } - break; case 'e': { if ( ! inters.d_info().opposite ) diff --git a/include/boost/geometry/algorithms/detail/overlay/get_turn_info_helpers.hpp b/include/boost/geometry/algorithms/detail/overlay/get_turn_info_helpers.hpp index 478811860..734b3051b 100644 --- a/include/boost/geometry/algorithms/detail/overlay/get_turn_info_helpers.hpp +++ b/include/boost/geometry/algorithms/detail/overlay/get_turn_info_helpers.hpp @@ -22,7 +22,7 @@ #include #include #include -#include +#include #include namespace boost { namespace geometry { @@ -153,18 +153,20 @@ template typename UniqueSubRange1, typename UniqueSubRange2, typename RobustPolicy > -struct robust_points +struct robust_point_calculator { typedef typename geometry::robust_point_type < typename UniqueSubRange1::point_type, RobustPolicy >::type robust_point1_type; + typedef typename geometry::robust_point_type + < + typename UniqueSubRange2::point_type, RobustPolicy + >::type robust_point2_type; - typedef robust_point1_type robust_point2_type; - - inline robust_points(UniqueSubRange1 const& range_p, - UniqueSubRange2 const& range_q, - RobustPolicy const& robust_policy) + inline robust_point_calculator(UniqueSubRange1 const& range_p, + UniqueSubRange2 const& range_q, + RobustPolicy const& robust_policy) : m_robust_policy(robust_policy) , m_range_p(range_p) , m_range_q(range_q) @@ -214,18 +216,52 @@ private : mutable bool m_qk_retrieved; }; +// Default version (empty - specialized below) template < typename UniqueSubRange1, typename UniqueSubRange2, - typename TurnPoint, typename UmbrellaStrategy, typename RobustPolicy> -class intersection_info_base - : private robust_points + typename TurnPoint, typename UmbrellaStrategy, + typename RobustPolicy, + typename Tag = typename rescale_policy_type::type +> +class intersection_info_base {}; + +// Version with rescaling, having robust points +template +< + typename UniqueSubRange1, typename UniqueSubRange2, + typename TurnPoint, typename UmbrellaStrategy, + typename RobustPolicy +> +class intersection_info_base { - typedef robust_points base; + typedef robust_point_calculator + < + UniqueSubRange1, UniqueSubRange2, + RobustPolicy + > + robust_calc_type; public: - typedef typename base::robust_point1_type robust_point1_type; - typedef typename base::robust_point2_type robust_point2_type; + typedef segment_intersection_points + < + TurnPoint, + geometry::segment_ratio + > intersection_point_type; + typedef policies::relate::segments_tupled + < + policies::relate::segments_intersection_points + < + intersection_point_type + >, + policies::relate::segments_direction + > intersection_policy_type; + + typedef typename intersection_policy_type::return_type result_type; + + typedef typename robust_calc_type::robust_point1_type robust_point1_type; + typedef typename robust_calc_type::robust_point2_type robust_point2_type; typedef robust_subrange_adapter robust_subrange1; typedef robust_subrange_adapter robust_subrange2; @@ -246,28 +282,31 @@ public: UniqueSubRange2 const& range_q, UmbrellaStrategy const& umbrella_strategy, RobustPolicy const& robust_policy) - : base(range_p, range_q, robust_policy) - , m_range_p(range_p) + : m_range_p(range_p) , m_range_q(range_q) - , m_robust_range_p(range_p, base::m_rpi, base::m_rpj, robust_policy) - , m_robust_range_q(range_q, base::m_rqi, base::m_rqj, robust_policy) + , m_robust_calc(range_p, range_q, robust_policy) + , m_robust_range_p(range_p, m_robust_calc.m_rpi, m_robust_calc.m_rpj, robust_policy) + , m_robust_range_q(range_q, m_robust_calc.m_rqi, m_robust_calc.m_rqj, robust_policy) , m_side_calc(m_robust_range_p, m_robust_range_q, umbrella_strategy.get_side_strategy()) + , m_result(umbrella_strategy.apply(range_p, range_q, + intersection_policy_type(), + m_robust_range_p, m_robust_range_q)) {} - inline typename UniqueSubRange1::point_type const& pi() const { return m_range_p.at(0); } - inline typename UniqueSubRange2::point_type const& qi() const { return m_range_q.at(0); } + inline bool p_is_last_segment() const { return m_range_p.is_last_segment(); } + inline bool q_is_last_segment() const { return m_range_q.is_last_segment(); } - inline robust_point1_type const& rpi() const { return base::m_rpi; } - inline robust_point1_type const& rpj() const { return base::m_rpj; } - inline robust_point1_type const& rpk() const { return base::get_rpk(); } + inline robust_point1_type const& rpi() const { return m_robust_calc.m_rpi; } + inline robust_point1_type const& rpj() const { return m_robust_calc.m_rpj; } + inline robust_point1_type const& rpk() const { return m_robust_calc.get_rpk(); } - inline robust_point2_type const& rqi() const { return base::m_rqi; } - inline robust_point2_type const& rqj() const { return base::m_rqj; } - inline robust_point2_type const& rqk() const { return base::get_rqk(); } + inline robust_point2_type const& rqi() const { return m_robust_calc.m_rqi; } + inline robust_point2_type const& rqj() const { return m_robust_calc.m_rqj; } + inline robust_point2_type const& rqk() const { return m_robust_calc.get_rqk(); } inline side_calculator_type const& sides() const { return m_side_calc; } - + robust_swapped_side_calculator_type get_swapped_sides() const { robust_swapped_side_calculator_type result( @@ -276,31 +315,49 @@ public: return result; } +private : + // Owned by get_turns UniqueSubRange1 const& m_range_p; UniqueSubRange2 const& m_range_q; -private : + // Owned by this class + robust_calc_type m_robust_calc; robust_subrange1 m_robust_range_p; robust_subrange2 m_robust_range_q; side_calculator_type m_side_calc; + +protected : + result_type m_result; }; +// Version without rescaling template < typename UniqueSubRange1, typename UniqueSubRange2, - typename TurnPoint, typename UmbrellaStrategy + typename TurnPoint, typename UmbrellaStrategy, + typename RobustPolicy > class intersection_info_base + TurnPoint, UmbrellaStrategy, RobustPolicy, no_rescale_policy_tag> { public: + + typedef segment_intersection_points intersection_point_type; + typedef policies::relate::segments_tupled + < + policies::relate::segments_intersection_points + < + intersection_point_type + >, + policies::relate::segments_direction + > intersection_policy_type; + + typedef typename intersection_policy_type::return_type result_type; + typedef typename UniqueSubRange1::point_type point1_type; typedef typename UniqueSubRange2::point_type point2_type; - typedef typename UniqueSubRange1::point_type robust_point1_type; - typedef typename UniqueSubRange2::point_type robust_point2_type; - typedef typename UmbrellaStrategy::cs_tag cs_tag; typedef typename UmbrellaStrategy::side_strategy_type side_strategy_type; @@ -315,13 +372,17 @@ public: intersection_info_base(UniqueSubRange1 const& range_p, UniqueSubRange2 const& range_q, UmbrellaStrategy const& umbrella_strategy, - no_rescale_policy const& /*robust_policy*/) + no_rescale_policy const& ) : m_range_p(range_p) , m_range_q(range_q) , m_side_calc(range_p, range_q, umbrella_strategy.get_side_strategy()) + , m_result(umbrella_strategy.apply(range_p, range_q, intersection_policy_type())) {} + inline bool p_is_last_segment() const { return m_range_p.is_last_segment(); } + inline bool q_is_last_segment() const { return m_range_q.is_last_segment(); } + inline point1_type const& rpi() const { return m_side_calc.get_pi(); } inline point1_type const& rpj() const { return m_side_calc.get_pj(); } inline point1_type const& rpk() const { return m_side_calc.get_pk(); } @@ -340,13 +401,16 @@ public: return result; } -protected : +private : // Owned by get_turns UniqueSubRange1 const& m_range_p; UniqueSubRange2 const& m_range_q; -private : - // Owned here, passed by .get_side_strategy() + + // Owned by this class side_calculator_type m_side_calc; + +protected : + result_type m_result; }; @@ -365,37 +429,17 @@ class intersection_info TurnPoint, UmbrellaStrategy, RobustPolicy> base; public: - typedef segment_intersection_points - < - TurnPoint, - typename geometry::segment_ratio_type - < - TurnPoint, RobustPolicy - >::type - > intersection_point_type; typedef typename UniqueSubRange1::point_type point1_type; typedef typename UniqueSubRange2::point_type point2_type; - // NOTE: formerly defined in intersection_strategies - typedef policies::relate::segments_tupled - < - policies::relate::segments_intersection_points - < - intersection_point_type - >, - policies::relate::segments_direction - > intersection_policy_type; - typedef UmbrellaStrategy intersection_strategy_type; typedef typename UmbrellaStrategy::side_strategy_type side_strategy_type; typedef typename UmbrellaStrategy::cs_tag cs_tag; - typedef model::referring_segment segment_type1; - typedef model::referring_segment segment_type2; typedef typename base::side_calculator_type side_calculator_type; + typedef typename base::result_type result_type; - typedef typename intersection_policy_type::return_type result_type; typedef typename boost::tuples::element<0, result_type>::type i_info_type; // intersection_info typedef typename boost::tuples::element<1, result_type>::type d_info_type; // dir_info @@ -405,20 +449,13 @@ public: RobustPolicy const& robust_policy) : base(range_p, range_q, umbrella_strategy, robust_policy) - , m_result(umbrella_strategy.apply( - segment_type1(range_p.at(0), range_p.at(1)), - segment_type2(range_q.at(0), range_q.at(1)), - intersection_policy_type(), - robust_policy, - base::rpi(), base::rpj(), - base::rqi(), base::rqj())) , m_intersection_strategy(umbrella_strategy) , m_robust_policy(robust_policy) {} - inline result_type const& result() const { return m_result; } - inline i_info_type const& i_info() const { return m_result.template get<0>(); } - inline d_info_type const& d_info() const { return m_result.template get<1>(); } + inline result_type const& result() const { return base::m_result; } + inline i_info_type const& i_info() const { return base::m_result.template get<0>(); } + inline d_info_type const& d_info() const { return base::m_result.template get<1>(); } inline side_strategy_type get_side_strategy() const { @@ -428,7 +465,7 @@ public: // TODO: it's more like is_spike_ip_p inline bool is_spike_p() const { - if (base::m_range_p.is_last_segment()) + if (base::p_is_last_segment()) { return false; } @@ -443,7 +480,7 @@ public: } // TODO: why is q used to determine spike property in p? - bool const has_qk = ! base::m_range_q.is_last_segment(); + bool const has_qk = ! base::q_is_last_segment(); int const qk_p1 = has_qk ? base::sides().qk_wrt_p1() : 0; int const qk_p2 = has_qk ? base::sides().qk_wrt_p2() : 0; @@ -467,7 +504,7 @@ public: inline bool is_spike_q() const { - if (base::m_range_q.is_last_segment()) + if (base::q_is_last_segment()) { return false; } @@ -481,7 +518,7 @@ public: } // TODO: why is p used to determine spike property in q? - bool const has_pk = ! base::m_range_p.is_last_segment(); + bool const has_pk = ! base::p_is_last_segment(); int const pk_q1 = has_pk ? base::sides().pk_wrt_q1() : 0; int const pk_q2 = has_pk ? base::sides().pk_wrt_q2() : 0; @@ -523,7 +560,6 @@ private: } } - result_type m_result; UmbrellaStrategy const& m_intersection_strategy; RobustPolicy const& m_robust_policy; }; diff --git a/include/boost/geometry/algorithms/detail/overlay/get_turns.hpp b/include/boost/geometry/algorithms/detail/overlay/get_turns.hpp index 886f8b683..a19691d61 100644 --- a/include/boost/geometry/algorithms/detail/overlay/get_turns.hpp +++ b/include/boost/geometry/algorithms/detail/overlay/get_turns.hpp @@ -209,7 +209,6 @@ private : RobustPolicy m_robust_policy; }; - template < typename Geometry1, typename Geometry2, diff --git a/include/boost/geometry/algorithms/detail/overlay/handle_colocations.hpp b/include/boost/geometry/algorithms/detail/overlay/handle_colocations.hpp index c417e7d1a..d948f9f27 100644 --- a/include/boost/geometry/algorithms/detail/overlay/handle_colocations.hpp +++ b/include/boost/geometry/algorithms/detail/overlay/handle_colocations.hpp @@ -84,15 +84,6 @@ struct turn_operation_index signed_size_type op_index; // only 0,1 }; -struct is_discarded -{ - template - inline bool operator()(Turn const& turn) const - { - return turn.discarded; - } -}; - template struct less_by_fraction_and_type { @@ -534,80 +525,6 @@ inline segment_identifier get_preceding_segment_id(segment_identifier const& id, return result; } -// Turns marked with method can be generated but are often duplicate, -// unless (by floating point precision) the preceding touching turn is just missed. -// This means that all (nearly) colocated with preceding touching turn -// can be deleted. This is done before colocation itself (because in colocated, -// they are only discarded, and that can give issues in traversal) -template -inline void erase_colocated_start_turns(Turns& turns, - Geometry0 const& geometry0, Geometry1 const& geometry1) -{ - typedef std::pair seg_id_pair; - typedef std::map map_type; - - typedef typename boost::range_value::type turn_type; - typedef typename boost::range_iterator::type turn_it; - typedef map_type::const_iterator map_it; - - // Collect starting turns into map - map_type preceding_segments; - std::size_t turn_index = 0; - for (turn_it it = boost::begin(turns); it != boost::end(turns); ++it, ++turn_index) - { - turn_type const& turn = *it; - if (turn.method == method_start) - { - // Insert identifiers for preceding segments of both operations. - // (For self turns geometry1 == geometry2) - seg_id_pair const pair( - get_preceding_segment_id(turn.operations[0].seg_id, geometry0, geometry1), - get_preceding_segment_id(turn.operations[1].seg_id, geometry0, geometry1)); - - // There should exist only one turn with such ids - BOOST_GEOMETRY_ASSERT(preceding_segments.find(pair) == preceding_segments.end()); - - preceding_segments[pair] = turn_index; - } - } - - if (preceding_segments.empty()) - { - return; - } - - // Find touching turns on preceding segment id combinations - bool has_discarded = false; - for (turn_it it = boost::begin(turns); it != boost::end(turns); ++it) - { - turn_type const& turn = *it; - if (turn.method == method_touch) - { - seg_id_pair const pair(turn.operations[0].seg_id, - turn.operations[1].seg_id); - - map_it mit = preceding_segments.find(pair); - - if (mit != preceding_segments.end()) - { - // The found touching turn precedes the found starting turn. - // (To be completely sure we could verify if turn.point is (nearly) equal) - // These turns are duplicate, discard the starting turn. - has_discarded = true; - turn_type& extra_turn = turns[mit->second]; - extra_turn.discarded = true; - } - } - } - - if (has_discarded) - { - turns.erase(std::remove_if(boost::begin(turns), boost::end(turns), - is_discarded()), - boost::end(turns)); - } -} - template < overlay_type OverlayType, @@ -833,7 +750,7 @@ struct is_turn_index return indexed.turn_index == m_index; } - std::size_t m_index; + signed_size_type m_index; }; diff --git a/include/boost/geometry/algorithms/detail/overlay/intersection_insert.hpp b/include/boost/geometry/algorithms/detail/overlay/intersection_insert.hpp index 5e55d9db2..9232b0f40 100644 --- a/include/boost/geometry/algorithms/detail/overlay/intersection_insert.hpp +++ b/include/boost/geometry/algorithms/detail/overlay/intersection_insert.hpp @@ -35,8 +35,9 @@ #include #include #include +#include -#include +#include #include #include @@ -71,52 +72,32 @@ struct intersection_segment_segment_point > static inline OutputIterator apply(Segment1 const& segment1, Segment2 const& segment2, - RobustPolicy const& robust_policy, + RobustPolicy const& , OutputIterator out, Strategy const& strategy) { + // Make sure this is only called with no rescaling + BOOST_STATIC_ASSERT((boost::is_same + < + no_rescale_policy_tag, + typename rescale_policy_type::type + >::value)); + typedef typename point_type::type point_type; - typedef typename geometry::robust_point_type - < - typename geometry::point_type::type, - RobustPolicy - >::type robust_point_type; - - // TODO: rescale segment -> robust points - robust_point_type pi_rob, pj_rob, qi_rob, qj_rob; - { - // Workaround: - point_type pi, pj, qi, qj; - assign_point_from_index<0>(segment1, pi); - assign_point_from_index<1>(segment1, pj); - assign_point_from_index<0>(segment2, qi); - assign_point_from_index<1>(segment2, qj); - geometry::recalculate(pi_rob, pi, robust_policy); - geometry::recalculate(pj_rob, pj, robust_policy); - geometry::recalculate(qi_rob, qi, robust_policy); - geometry::recalculate(qj_rob, qj, robust_policy); - } - // Get the intersection point (or two points) - typedef segment_intersection_points - < - point_type, - typename segment_ratio_type - < - point_type, RobustPolicy - >::type - > intersection_return_type; + typedef segment_intersection_points intersection_return_type; typedef policies::relate::segments_intersection_points < intersection_return_type > policy_type; + detail::segment_as_subrange sub_range1(segment1); + detail::segment_as_subrange sub_range2(segment2); + intersection_return_type - is = strategy.apply(segment1, segment2, - policy_type(), robust_policy, - pi_rob, pj_rob, qi_rob, qj_rob); + is = strategy.apply(sub_range1, sub_range2, policy_type()); for (std::size_t i = 0; i < is.count; i++) { @@ -144,13 +125,14 @@ struct intersection_linestring_linestring_point OutputIterator out, Strategy const& strategy) { - typedef typename point_type::type point_type; + // Make sure this is only called with no rescaling + BOOST_STATIC_ASSERT((boost::is_same + < + no_rescale_policy_tag, + typename rescale_policy_type::type + >::value)); - typedef detail::overlay::turn_info - < - point_type, - typename segment_ratio_type::type - > turn_info; + typedef detail::overlay::turn_info turn_info; std::deque turns; geometry::get_intersection_points(linestring1, linestring2, @@ -408,6 +390,13 @@ struct intersection_of_linestring_with_areal OutputIterator out, Strategy const& strategy) { + // Make sure this is only called with no rescaling + BOOST_STATIC_ASSERT((boost::is_same + < + no_rescale_policy_tag, + typename rescale_policy_type::type + >::value)); + if (boost::size(linestring) == 0) { return out; @@ -423,21 +412,26 @@ struct intersection_of_linestring_with_areal > follower; typedef typename point_type::type point_type; + + typedef geometry::segment_ratio + < + typename coordinate_type::type + > ratio_type; + #ifdef BOOST_GEOMETRY_SETOPS_LA_OLD_BEHAVIOR typedef detail::overlay::traversal_turn_info < - point_type, - typename geometry::segment_ratio_type::type + point_type, ratio_type > turn_info; #else typedef detail::overlay::turn_info < point_type, - typename geometry::segment_ratio_type::type, + ratio_type, detail::overlay::turn_operation_linear < point_type, - typename geometry::segment_ratio_type::type + ratio_type > > turn_info; #endif @@ -602,19 +596,23 @@ struct intersection_linear_areal_point OutputIterator out, Strategy const& strategy) { - typedef typename geometry::segment_ratio_type - < - PointOut, RobustPolicy - >::type segment_ratio_type; + // Make sure this is only called with no rescaling + BOOST_STATIC_ASSERT((boost::is_same + < + no_rescale_policy_tag, + typename rescale_policy_type::type + >::value)); + + typedef geometry::segment_ratio::type> ratio_type; typedef detail::overlay::turn_info < PointOut, - segment_ratio_type, + ratio_type, detail::overlay::turn_operation_linear < PointOut, - segment_ratio_type + ratio_type > > turn_info; @@ -1288,9 +1286,10 @@ inline OutputIterator intersection_insert(Geometry1 const& geometry1, concepts::check(); concepts::check(); - typedef typename geometry::rescale_policy_type + typedef typename geometry::rescale_overlay_policy_type < - typename geometry::point_type::type, // TODO from both + Geometry1, + Geometry2, typename Strategy::cs_tag >::type rescale_policy_type; diff --git a/include/boost/geometry/algorithms/detail/overlay/overlay.hpp b/include/boost/geometry/algorithms/detail/overlay/overlay.hpp index e52d3741a..ab2d1c406 100644 --- a/include/boost/geometry/algorithms/detail/overlay/overlay.hpp +++ b/include/boost/geometry/algorithms/detail/overlay/overlay.hpp @@ -287,7 +287,7 @@ struct overlay typedef detail::overlay::traversal_turn_info < point_type, - typename geometry::segment_ratio_type::type + typename segment_ratio_type::type > turn_info; typedef std::deque turn_container_type; @@ -318,15 +318,20 @@ std::cout << "get turns" << std::endl; visitor.visit_turns(1, turns); #if ! defined(BOOST_GEOMETRY_NO_SELF_TURNS) - if (needs_self_turns::apply(geometry1)) + if (! turns.empty() || OverlayType == overlay_dissolve) { - self_get_turn_points::self_turns(geometry1, - strategy, robust_policy, turns, policy, 0); - } - if (needs_self_turns::apply(geometry2)) - { - self_get_turn_points::self_turns(geometry2, - strategy, robust_policy, turns, policy, 1); + // Calculate self turns if the output contains turns already, + // and if necessary (e.g.: multi-geometry, polygon with interior rings) + if (needs_self_turns::apply(geometry1)) + { + self_get_turn_points::self_turns(geometry1, + strategy, robust_policy, turns, policy, 0); + } + if (needs_self_turns::apply(geometry2)) + { + self_get_turn_points::self_turns(geometry2, + strategy, robust_policy, turns, policy, 1); + } } #endif diff --git a/include/boost/geometry/algorithms/detail/overlay/segment_as_subrange.hpp b/include/boost/geometry/algorithms/detail/overlay/segment_as_subrange.hpp new file mode 100644 index 000000000..deac13ba4 --- /dev/null +++ b/include/boost/geometry/algorithms/detail/overlay/segment_as_subrange.hpp @@ -0,0 +1,54 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2019-2019 Barend Gehrels, Amsterdam, the Netherlands. + +// 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) + +#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_SEGMENT_AS_SUBRANGE_HPP +#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_SEGMENT_AS_SUBRANGE_HPP + + +#include +#include + +#include + +namespace boost { namespace geometry +{ + +#ifndef DOXYGEN_NO_DETAIL +namespace detail +{ + +template +struct segment_as_subrange +{ + segment_as_subrange(Segment const& s) + : m_segment(s) + { + geometry::set<0>(m_p1, geometry::get<0, 0>(m_segment)); + geometry::set<1>(m_p1, geometry::get<0, 1>(m_segment)); + geometry::set<0>(m_p2, geometry::get<1, 0>(m_segment)); + geometry::set<1>(m_p2, geometry::get<1, 1>(m_segment)); + } + + typedef typename geometry::point_type::type point_type; + + point_type const& at(std::size_t index) const + { + return index == 0 ? m_p1 : m_p2; + } + + point_type m_p1, m_p2; + + Segment const& m_segment; +}; + +} // namespace detail +#endif // DOXYGEN_NO_DETAIL + +}} // namespace boost::geometry + +#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_SEGMENT_AS_SUBRANGE_HPP diff --git a/include/boost/geometry/algorithms/detail/overlay/turn_info.hpp b/include/boost/geometry/algorithms/detail/overlay/turn_info.hpp index e976bdb03..5f4569bd6 100644 --- a/include/boost/geometry/algorithms/detail/overlay/turn_info.hpp +++ b/include/boost/geometry/algorithms/detail/overlay/turn_info.hpp @@ -16,6 +16,7 @@ #include #include #include +#include namespace boost { namespace geometry { @@ -33,7 +34,6 @@ enum method_type method_touch_interior, method_collinear, method_equal, - method_start, method_error }; @@ -77,7 +77,7 @@ struct turn_operation template < typename Point, - typename SegmentRatio, + typename SegmentRatio = geometry::segment_ratio::type>, typename Operation = turn_operation, typename Container = boost::array > diff --git a/include/boost/geometry/algorithms/detail/partition.hpp b/include/boost/geometry/algorithms/detail/partition.hpp index 8eb0c7b1f..b8a50007b 100644 --- a/include/boost/geometry/algorithms/detail/partition.hpp +++ b/include/boost/geometry/algorithms/detail/partition.hpp @@ -3,8 +3,8 @@ // Copyright (c) 2011-2015 Barend Gehrels, Amsterdam, the Netherlands. // Copyright (c) 2017 Adam Wulkiewicz, Lodz, Poland. -// This file was modified by Oracle on 2015, 2017. -// Modifications copyright (c) 2015-2017 Oracle and/or its affiliates. +// This file was modified by Oracle on 2015, 2017, 2018, 2019. +// Modifications copyright (c) 2015-2019 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 @@ -19,6 +19,8 @@ #include #include #include +#include + #include #include #include @@ -30,15 +32,35 @@ namespace boost { namespace geometry namespace detail { namespace partition { +template ::value> +struct divide_interval +{ + static inline T apply(T const& mi, T const& ma) + { + static T const two = 2; + return (mi + ma) / two; + } +}; + +template +struct divide_interval +{ + static inline T apply(T const& mi, T const& ma) + { + // avoid overflow + return mi / 2 + ma / 2 + (mi % 2 + ma % 2) / 2; + } +}; + template inline void divide_box(Box const& box, Box& lower_box, Box& upper_box) { typedef typename coordinate_type::type ctype; // Divide input box into two parts, e.g. left/right - ctype two = 2; - ctype mid = (geometry::get(box) - + geometry::get(box)) / two; + ctype mid = divide_interval::apply( + geometry::get(box), + geometry::get(box)); lower_box = box; upper_box = box; 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 502a5b0bb..e5ba6e30d 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 @@ -35,26 +35,6 @@ 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) // @@ -81,15 +61,7 @@ inline bool point_is_spike_or_equal(Point1 const& last_point, // prev | back if (side == 0) { // Last point is collinear w.r.t previous segment. -#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; } diff --git a/include/boost/geometry/algorithms/detail/relate/de9im.hpp b/include/boost/geometry/algorithms/detail/relate/de9im.hpp index 713a3fc8f..be745bfda 100644 --- a/include/boost/geometry/algorithms/detail/relate/de9im.hpp +++ b/include/boost/geometry/algorithms/detail/relate/de9im.hpp @@ -2,8 +2,8 @@ // Copyright (c) 2007-2015 Barend Gehrels, Amsterdam, the Netherlands. -// 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, 2019. +// Modifications copyright (c) 2013-2019 Oracle and/or its affiliates. // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle @@ -22,7 +22,6 @@ #include #include -#include #include #include @@ -318,9 +317,9 @@ struct static_mask_touches_impl // Using the above mask the result would be always false template struct static_mask_touches_impl - : not_implemented::type, - typename geometry::tag::type> -{}; +{ + typedef geometry::detail::relate::false_mask type; +}; template struct static_mask_touches_type @@ -377,12 +376,9 @@ template typename Geometry1, typename Geometry2, std::size_t Dim > struct static_mask_crosses_impl - : not_implemented - < - typename geometry::tag::type, - typename geometry::tag::type - > -{}; +{ + typedef geometry::detail::relate::false_mask type; +}; // dim(G1) == 1 && dim(G2) == 1 - L/L template struct static_mask_crosses_impl @@ -406,12 +402,9 @@ template std::size_t Dim2 = geometry::topological_dimension::value > struct static_mask_overlaps_impl - : not_implemented - < - typename geometry::tag::type, - typename geometry::tag::type - > -{}; +{ + typedef geometry::detail::relate::false_mask type; +}; // dim(G1) == D && dim(G2) == D - P/P A/A template struct static_mask_overlaps_impl diff --git a/include/boost/geometry/algorithms/detail/relate/relate_impl.hpp b/include/boost/geometry/algorithms/detail/relate/relate_impl.hpp index 2ec2361c0..ae963c4b0 100644 --- a/include/boost/geometry/algorithms/detail/relate/relate_impl.hpp +++ b/include/boost/geometry/algorithms/detail/relate/relate_impl.hpp @@ -2,8 +2,8 @@ // Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. -// 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, 2019. +// Modifications copyright (c) 2013-2019 Oracle and/or its affiliates. // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle @@ -30,25 +30,19 @@ namespace detail { namespace relate { struct implemented_tag {}; -template