// Boost.Geometry (aka GGL, Generic Geometry Library) // Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. // This file was modified by Oracle on 2016. // Modifications copyright (c) 2016 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) #ifndef BOOST_GEOMETRY_GEOMETRY_POLICIES_RELATE_INTERSECTION_POINTS_HPP #define BOOST_GEOMETRY_GEOMETRY_POLICIES_RELATE_INTERSECTION_POINTS_HPP #include #include #include #include #include #include namespace boost { namespace geometry { namespace policies { namespace relate { /*! \brief Policy calculating the intersection points themselves */ template < typename ReturnType > struct segments_intersection_points { typedef ReturnType return_type; template < typename Segment1, typename Segment2, typename SegmentIntersectionInfo > static inline return_type segments_crosses(side_info const&, SegmentIntersectionInfo const& sinfo, Segment1 const& s1, Segment2 const& s2) { return_type result; result.count = 1; bool use_a = true; // Prefer one segment if one is on or near an endpoint bool const a_near_end = sinfo.robust_ra.near_end(); bool const b_near_end = sinfo.robust_rb.near_end(); if (a_near_end && ! b_near_end) { use_a = true; } else if (b_near_end && ! a_near_end) { use_a = false; } else { // Prefer shorter segment typedef typename SegmentIntersectionInfo::promoted_type ptype; ptype const len_a = sinfo.comparable_length_a(); ptype const len_b = sinfo.comparable_length_b(); if (len_b < len_a) { use_a = false; } // else use_a is true but was already assigned like that } if (use_a) { sinfo.assign_a(result.intersections[0], s1, s2); } else { sinfo.assign_b(result.intersections[0], s1, s2); } result.fractions[0].assign(sinfo); return result; } template static inline return_type segments_collinear( Segment1 const& a, Segment2 const& b, bool /*opposite*/, int a1_wrt_b, int a2_wrt_b, int b1_wrt_a, int b2_wrt_a, Ratio const& ra_from_wrt_b, Ratio const& ra_to_wrt_b, Ratio const& rb_from_wrt_a, Ratio const& rb_to_wrt_a) { return_type result; unsigned int index = 0, count_a = 0, count_b = 0; Ratio on_a[2]; // The conditions "index < 2" are necessary for non-robust handling, // if index would be 2 this indicate an (currently uncatched) error // IMPORTANT: the order of conditions is different as in direction.hpp if (a1_wrt_b >= 1 && a1_wrt_b <= 3 // ra_from_wrt_b.on_segment() && index < 2) { // a1--------->a2 // b1----->b2 // // ra1 (relative to b) is between 0/1: // -> First point of A is intersection point detail::assign_point_from_index<0>(a, result.intersections[index]); result.fractions[index].assign(Ratio::zero(), ra_from_wrt_b); on_a[index] = Ratio::zero(); index++; count_a++; } if (b1_wrt_a == 2 //rb_from_wrt_a.in_segment() && index < 2) { // We take the first intersection point of B // a1--------->a2 // b1----->b2 // But only if it is not located on A // a1--------->a2 // b1----->b2 rb_from_wrt_a == 0/1 -> a already taken detail::assign_point_from_index<0>(b, result.intersections[index]); result.fractions[index].assign(rb_from_wrt_a, Ratio::zero()); on_a[index] = rb_from_wrt_a; index++; count_b++; } if (a2_wrt_b >= 1 && a2_wrt_b <= 3 //ra_to_wrt_b.on_segment() && index < 2) { // Similarly, second IP (here a2) // a1--------->a2 // b1----->b2 detail::assign_point_from_index<1>(a, result.intersections[index]); result.fractions[index].assign(Ratio::one(), ra_to_wrt_b); on_a[index] = Ratio::one(); index++; count_a++; } if (b2_wrt_a == 2 // rb_to_wrt_a.in_segment() && index < 2) { detail::assign_point_from_index<1>(b, result.intersections[index]); result.fractions[index].assign(rb_to_wrt_a, Ratio::one()); on_a[index] = rb_to_wrt_a; index++; count_b++; } // TEMPORARY // If both are from b, and b is reversed w.r.t. a, we swap IP's // to align them w.r.t. a // get_turn_info still relies on some order (in some collinear cases) if (index == 2 && on_a[1] < on_a[0]) { std::swap(result.fractions[0], result.fractions[1]); std::swap(result.intersections[0], result.intersections[1]); } result.count = index; return result; } static inline return_type disjoint() { return return_type(); } static inline return_type error(std::string const&) { return return_type(); } // Both degenerate template static inline return_type degenerate(Segment const& segment, bool) { return_type result; result.count = 1; set<0>(result.intersections[0], get<0, 0>(segment)); set<1>(result.intersections[0], get<0, 1>(segment)); return result; } // One degenerate template static inline return_type one_degenerate(Segment const& degenerate_segment, Ratio const& ratio, bool a_degenerate) { return_type result; result.count = 1; set<0>(result.intersections[0], get<0, 0>(degenerate_segment)); set<1>(result.intersections[0], get<0, 1>(degenerate_segment)); if (a_degenerate) { // IP lies on ratio w.r.t. segment b result.fractions[0].assign(Ratio::zero(), ratio); } else { result.fractions[0].assign(ratio, Ratio::zero()); } return result; } }; }} // namespace policies::relate }} // namespace boost::geometry #endif // BOOST_GEOMETRY_GEOMETRY_POLICIES_RELATE_INTERSECTION_POINTS_HPP