diff options
author | Chanho Park <chanho61.park@samsung.com> | 2014-12-11 18:55:56 +0900 |
---|---|---|
committer | Chanho Park <chanho61.park@samsung.com> | 2014-12-11 18:55:56 +0900 |
commit | 08c1e93fa36a49f49325a07fe91ff92c964c2b6c (patch) | |
tree | 7a7053ceb8874b28ec4b868d4c49b500008a102e /boost/geometry/policies | |
parent | bb4dd8289b351fae6b55e303f189127a394a1edd (diff) | |
download | boost-08c1e93fa36a49f49325a07fe91ff92c964c2b6c.tar.gz boost-08c1e93fa36a49f49325a07fe91ff92c964c2b6c.tar.bz2 boost-08c1e93fa36a49f49325a07fe91ff92c964c2b6c.zip |
Imported Upstream version 1.57.0upstream/1.57.0
Diffstat (limited to 'boost/geometry/policies')
-rw-r--r-- | boost/geometry/policies/disjoint_interrupt_policy.hpp | 67 | ||||
-rw-r--r-- | boost/geometry/policies/predicate_based_interrupt_policy.hpp | 101 | ||||
-rw-r--r-- | boost/geometry/policies/relate/de9im.hpp | 9 | ||||
-rw-r--r-- | boost/geometry/policies/relate/direction.hpp | 266 | ||||
-rw-r--r-- | boost/geometry/policies/relate/intersection_points.hpp | 245 | ||||
-rw-r--r-- | boost/geometry/policies/relate/intersection_ratios.hpp | 127 | ||||
-rw-r--r-- | boost/geometry/policies/relate/tupled.hpp | 116 | ||||
-rw-r--r-- | boost/geometry/policies/robustness/get_rescale_policy.hpp | 290 | ||||
-rw-r--r-- | boost/geometry/policies/robustness/no_rescale_policy.hpp | 66 | ||||
-rw-r--r-- | boost/geometry/policies/robustness/rescale_policy.hpp | 83 | ||||
-rw-r--r-- | boost/geometry/policies/robustness/robust_point_type.hpp | 30 | ||||
-rw-r--r-- | boost/geometry/policies/robustness/robust_type.hpp | 67 | ||||
-rw-r--r-- | boost/geometry/policies/robustness/segment_ratio.hpp | 239 | ||||
-rw-r--r-- | boost/geometry/policies/robustness/segment_ratio_type.hpp | 28 |
14 files changed, 1410 insertions, 324 deletions
diff --git a/boost/geometry/policies/disjoint_interrupt_policy.hpp b/boost/geometry/policies/disjoint_interrupt_policy.hpp new file mode 100644 index 0000000000..2a6e54b079 --- /dev/null +++ b/boost/geometry/policies/disjoint_interrupt_policy.hpp @@ -0,0 +1,67 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2014 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2008-2014 Bruno Lalande, Paris, France. +// Copyright (c) 2009-2014 Mateusz Loskot, London, UK. +// Copyright (c) 2013-2014 Adam Wulkiewicz, Lodz, Poland. + +// This file was modified by Oracle on 2013-2014. +// Modifications copyright (c) 2013-2014, 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 + +// Parts of Boost.Geometry are redesigned from Geodan's Geographic Library +// (geolib/GGL), copyright (c) 1995-2010 Geodan, 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_POLICIES_DISJOINT_INTERRUPT_POLICY_HPP +#define BOOST_GEOMETRY_ALGORITHMS_POLICIES_DISJOINT_INTERRUPT_POLICY_HPP + +#include <boost/range.hpp> + + +namespace boost { namespace geometry +{ + + +#ifndef DOXYGEN_NO_DETAIL +namespace detail { namespace disjoint +{ + + +struct disjoint_interrupt_policy +{ + static bool const enabled = true; + bool has_intersections; + + inline disjoint_interrupt_policy() + : has_intersections(false) + {} + + template <typename Range> + inline bool apply(Range const& range) + { + // If there is any IP in the range, it is NOT disjoint + if (boost::size(range) > 0) + { + has_intersections = true; + return true; + } + return false; + } +}; + + + +}} // namespace detail::disjoint +#endif // DOXYGEN_NO_DETAIL + + +}} // namespace boost::geometry + + +#endif // BOOST_GEOMETRY_ALGORITHMS_POLICIES_DISJOINT_INTERRUPT_POLICY_HPP diff --git a/boost/geometry/policies/predicate_based_interrupt_policy.hpp b/boost/geometry/policies/predicate_based_interrupt_policy.hpp new file mode 100644 index 0000000000..0021b12dc6 --- /dev/null +++ b/boost/geometry/policies/predicate_based_interrupt_policy.hpp @@ -0,0 +1,101 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2014, Oracle and/or its affiliates. + +// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle + +// Licensed under the Boost Software License version 1.0. +// http://www.boost.org/users/license.html + +#ifndef BOOST_GEOMETRY_ALGORITHMS_POLICIES_PREDICATE_BASED_INTERRUPT_POLICY_HPP +#define BOOST_GEOMETRY_ALGORITHMS_POLICIES_PREDICATE_BASED_INTERRUPT_POLICY_HPP + +#include <boost/range.hpp> + +#include <boost/geometry/algorithms/detail/check_iterator_range.hpp> + + +namespace boost { namespace geometry +{ + + +#ifndef DOXYGEN_NO_DETAIL +namespace detail { namespace overlay +{ + + +template +< + typename IsAcceptableTurnPredicate, + bool AllowEmptyTurnRange = true // by default, allow an empty turn range +> +struct stateless_predicate_based_interrupt_policy +{ + static bool const enabled = true; + bool has_intersections; // set to true if there is at least one + // unacceptable turn + + inline stateless_predicate_based_interrupt_policy() + : has_intersections(false) + {} + + template <typename Range> + inline bool apply(Range const& range) + { + // if there is at least one unacceptable turn in the range, return false + has_intersections = !detail::check_iterator_range + < + IsAcceptableTurnPredicate, + AllowEmptyTurnRange + >::apply(boost::begin(range), boost::end(range)); + + return has_intersections; + } +}; + + + + +template +< + typename IsAcceptableTurnPredicate, + bool AllowEmptyTurnRange = true // by default, allow an empty turn range +> +struct predicate_based_interrupt_policy +{ + static bool const enabled = true; + bool has_intersections; // set to true if there is at least one + // unacceptable turn + IsAcceptableTurnPredicate const& m_predicate; + + inline + predicate_based_interrupt_policy(IsAcceptableTurnPredicate const& predicate) + : has_intersections(false) + , m_predicate(predicate) + {} + + template <typename Range> + inline bool apply(Range const& range) + { + // if there is at least one unacceptable turn in the range, return false + has_intersections = !detail::check_iterator_range + < + IsAcceptableTurnPredicate, + AllowEmptyTurnRange + >::apply(boost::begin(range), boost::end(range), m_predicate); + + return has_intersections; + } +}; + + + + +}} // namespace detail::overlay +#endif // DOXYGEN_NO_DETAIL + + +}} // namespace boost::geometry + + +#endif // BOOST_GEOMETRY_ALGORITHMS_POLICIES_PREDICATE_BASED_INTERRUPT_POLICY_HPP diff --git a/boost/geometry/policies/relate/de9im.hpp b/boost/geometry/policies/relate/de9im.hpp index 766d80b220..e2d6b5111c 100644 --- a/boost/geometry/policies/relate/de9im.hpp +++ b/boost/geometry/policies/relate/de9im.hpp @@ -158,15 +158,6 @@ struct segments_de9im false, false, false, true); } - static inline return_type collinear_disjoint() - { - return de9im_segment(0,0, - -1, -1, 1, - -1, -1, 0, - 1, 0, 2, - true); - } - }; diff --git a/boost/geometry/policies/relate/direction.hpp b/boost/geometry/policies/relate/direction.hpp index cfbaf7dd15..02fed94b10 100644 --- a/boost/geometry/policies/relate/direction.hpp +++ b/boost/geometry/policies/relate/direction.hpp @@ -88,7 +88,8 @@ struct direction_type // New information side_info sides; - int arrival[2]; // 1=arrival, -1departure, 0=neutral; == how_a//how_b + // THIS IS EQUAL TO arrival_a, arrival_b - they probably can go now we have robust fractions + int arrival[2]; // 1=arrival, -1=departure, 0=neutral; == how_a//how_b // About arrival[0] (== arrival of a2 w.r.t. b) for COLLINEAR cases @@ -110,28 +111,19 @@ struct direction_type }; - -template <typename S1, typename S2, typename CalculationType = void> struct segments_direction { typedef direction_type return_type; - typedef S1 segment_type1; - typedef S2 segment_type2; - typedef typename select_calculation_type - < - S1, S2, CalculationType - >::type coordinate_type; - - // Get the same type, but at least a double - typedef typename select_most_precise<coordinate_type, double>::type rtype; - - - template <typename R> - static inline return_type segments_intersect(side_info const& sides, - R const&, - coordinate_type const& dx1, coordinate_type const& dy1, - coordinate_type const& dx2, coordinate_type const& dy2, - S1 const& s1, S2 const& s2) + + template + < + typename Segment1, + typename Segment2, + typename SegmentIntersectionInfo + > + static inline return_type segments_crosses(side_info const& sides, + SegmentIntersectionInfo const& , + Segment1 const& , Segment2 const& ) { bool const ra0 = sides.get<0,0>() == 0; bool const ra1 = sides.get<0,1>() == 0; @@ -140,95 +132,153 @@ struct segments_direction return // opposite and same starting point (FROM) - ra0 && rb0 ? calculate_side<1>(sides, dx1, dy1, s1, s2, 'f', -1, -1) + ra0 && rb0 ? calculate_side<1>(sides, 'f', -1, -1) // opposite and point to each other (TO) - : ra1 && rb1 ? calculate_side<0>(sides, dx1, dy1, s1, s2, 't', 1, 1) + : ra1 && rb1 ? calculate_side<0>(sides, 't', 1, 1) // not opposite, forming an angle, first a then b, // directed either both left, or both right // Check side of B2 from A. This is not calculated before - : ra1 && rb0 ? angle<1>(sides, dx1, dy1, s1, s2, 'a', 1, -1) + : ra1 && rb0 ? angle<1>(sides, 'a', 1, -1) // not opposite, forming a angle, first b then a, // directed either both left, or both right - : ra0 && rb1 ? angle<0>(sides, dx1, dy1, s1, s2, 'a', -1, 1) + : ra0 && rb1 ? angle<0>(sides, 'a', -1, 1) // b starts from interior of a - : rb0 ? starts_from_middle(sides, dx1, dy1, s1, s2, 'B', 0, -1) + : rb0 ? starts_from_middle(sides, 'B', 0, -1) // a starts from interior of b (#39) - : ra0 ? starts_from_middle(sides, dx1, dy1, s1, s2, 'A', -1, 0) + : ra0 ? starts_from_middle(sides, 'A', -1, 0) // b ends at interior of a, calculate direction of A from IP - : rb1 ? b_ends_at_middle(sides, dx2, dy2, s1, s2) + : rb1 ? b_ends_at_middle(sides) // a ends at interior of b - : ra1 ? a_ends_at_middle(sides, dx1, dy1, s1, s2) + : ra1 ? a_ends_at_middle(sides) // normal intersection - : calculate_side<1>(sides, dx1, dy1, s1, s2, 'i', -1, -1) + : calculate_side<1>(sides, 'i', -1, -1) ; } - static inline return_type collinear_touch( - coordinate_type const& , - coordinate_type const& , int arrival_a, int arrival_b) + template <typename Ratio> + static inline int arrival_value(Ratio const& r_from, Ratio const& r_to) { - // Though this is 'collinear', we handle it as To/From/Angle because it is the same. - // It only does NOT have a direction. - side_info sides; - //int const arrive = how == 'T' ? 1 : -1; - bool opposite = arrival_a == arrival_b; - return - ! opposite - ? return_type(sides, 'a', arrival_a, arrival_b) - : return_type(sides, arrival_a == 0 ? 't' : 'f', arrival_a, arrival_b, 0, 0, true); + // a1--------->a2 + // b1----->b2 + // a departs: -1 + + // a1--------->a2 + // b1----->b2 + // a arrives: 1 + + // a1--------->a2 + // b1----->b2 + // both arrive there -> r-to = 1/1, or 0/1 (on_segment) + + // First check the TO (for arrival), then FROM (for departure) + return r_to.in_segment() ? 1 + : r_to.on_segment() ? 0 + : r_from.on_segment() ? -1 + : -1 + ; } - template <typename S> - static inline return_type collinear_interior_boundary_intersect(S const& , bool, - int arrival_a, int arrival_b, bool opposite) + template <typename Ratio> + static inline void analyze(Ratio const& r, + int& in_segment_count, + int& on_end_count, + int& outside_segment_count) { - return_type r('c', opposite); - r.arrival[0] = arrival_a; - r.arrival[1] = arrival_b; - return r; + if (r.on_end()) + { + on_end_count++; + } + else if (r.in_segment()) + { + in_segment_count++; + } + else + { + outside_segment_count++; + } } - static inline return_type collinear_a_in_b(S1 const& , bool opposite) - { - return_type r('c', opposite); - r.arrival[0] = 1; - r.arrival[1] = -1; - return r; - } - static inline return_type collinear_b_in_a(S2 const& , bool opposite) + template <typename Segment1, typename Segment2, typename Ratio> + static inline return_type segments_collinear( + Segment1 const& , Segment2 const&, + 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 r('c', opposite); - r.arrival[0] = -1; - r.arrival[1] = 1; - return r; - } + // If segments are opposite, the ratio of the FROM w.r.t. the other + // is larger than the ratio of the TO w.r.t. the other + bool const opposite = ra_to_wrt_b < ra_from_wrt_b; - static inline return_type collinear_overlaps( - coordinate_type const& , coordinate_type const& , - coordinate_type const& , coordinate_type const& , - int arrival_a, int arrival_b, bool opposite) - { return_type r('c', opposite); - r.arrival[0] = arrival_a; - r.arrival[1] = arrival_b; + + // IMPORTANT: the order of conditions is different as in intersection_points.hpp + // We assign A in 0 and B in 1 + r.arrival[0] = arrival_value(ra_from_wrt_b, ra_to_wrt_b); + r.arrival[1] = arrival_value(rb_from_wrt_a, rb_to_wrt_a); + + // Analyse them + int a_in_segment_count = 0; + int a_on_end_count = 0; + int a_outside_segment_count = 0; + int b_in_segment_count = 0; + int b_on_end_count = 0; + int b_outside_segment_count = 0; + analyze(ra_from_wrt_b, + a_in_segment_count, a_on_end_count, a_outside_segment_count); + analyze(ra_to_wrt_b, + a_in_segment_count, a_on_end_count, a_outside_segment_count); + analyze(rb_from_wrt_a, + b_in_segment_count, b_on_end_count, b_outside_segment_count); + analyze(rb_to_wrt_a, + b_in_segment_count, b_on_end_count, b_outside_segment_count); + + if (a_on_end_count == 1 + && b_on_end_count == 1 + && a_outside_segment_count == 1 + && b_outside_segment_count == 1) + { + // This is a collinear touch + // --------> A (or B) + // <---------- B (or A) + // We adapt the "how" + // TODO: how was to be refactored anyway, + if (! opposite) + { + r.how = 'a'; + } + else + { + r.how = r.arrival[0] == 0 ? 't' : 'f'; + } + } + else if (a_on_end_count == 2 + && b_on_end_count == 2) + { + r.how = 'e'; + } + return r; } - static inline return_type segment_equal(S1 const& , bool opposite) + template <typename Segment> + static inline return_type degenerate(Segment const& , bool) { - return return_type('e', opposite); + return return_type('0', false); } - static inline return_type degenerate(S1 const& , bool) + template <typename Segment, typename Ratio> + static inline return_type one_degenerate(Segment const& , + Ratio const& , + bool) { + // To be decided return return_type('0', false); } @@ -237,11 +287,6 @@ struct segments_direction return return_type('d', false); } - static inline return_type collinear_disjoint() - { - return return_type('d', false); - } - static inline return_type error(std::string const&) { // Return "E" to denote error @@ -252,62 +297,29 @@ struct segments_direction private : - static inline bool is_left - ( - coordinate_type const& ux, - coordinate_type const& uy, - coordinate_type const& vx, - coordinate_type const& vy - ) - { - // This is a "side calculation" as in the strategies, but here terms are precalculated - // We might merge this with side, offering a pre-calculated term (in fact already done using cross-product) - // Waiting for implementing spherical... - - rtype const zero = rtype(); - return geometry::detail::determinant<rtype>(ux, uy, vx, vy) > zero; - } - template <std::size_t I> static inline return_type calculate_side(side_info const& sides, - coordinate_type const& dx1, coordinate_type const& dy1, - S1 const& s1, S2 const& s2, char how, int how_a, int how_b) { - coordinate_type dpx = get<I, 0>(s2) - get<0, 0>(s1); - coordinate_type dpy = get<I, 1>(s2) - get<0, 1>(s1); - - return is_left(dx1, dy1, dpx, dpy) - ? return_type(sides, how, how_a, how_b, -1, 1) - : return_type(sides, how, how_a, how_b, 1, -1); + int const dir = sides.get<1, I>() == 1 ? 1 : -1; + return return_type(sides, how, how_a, how_b, -dir, dir); } template <std::size_t I> static inline return_type angle(side_info const& sides, - coordinate_type const& dx1, coordinate_type const& dy1, - S1 const& s1, S2 const& s2, char how, int how_a, int how_b) { - coordinate_type dpx = get<I, 0>(s2) - get<0, 0>(s1); - coordinate_type dpy = get<I, 1>(s2) - get<0, 1>(s1); - - return is_left(dx1, dy1, dpx, dpy) - ? return_type(sides, how, how_a, how_b, 1, 1) - : return_type(sides, how, how_a, how_b, -1, -1); + int const dir = sides.get<1, I>() == 1 ? 1 : -1; + return return_type(sides, how, how_a, how_b, dir, dir); } static inline return_type starts_from_middle(side_info const& sides, - coordinate_type const& dx1, coordinate_type const& dy1, - S1 const& s1, S2 const& s2, char which, int how_a, int how_b) { // Calculate ARROW of b segment w.r.t. s1 - coordinate_type dpx = get<1, 0>(s2) - get<0, 0>(s1); - coordinate_type dpy = get<1, 1>(s2) - get<0, 1>(s1); - - int dir = is_left(dx1, dy1, dpx, dpy) ? 1 : -1; + int dir = sides.get<1, 1>() == 1 ? 1 : -1; // From other perspective, then reverse bool const is_a = which == 'A'; @@ -326,31 +338,19 @@ private : // To be harmonized - static inline return_type a_ends_at_middle(side_info const& sides, - coordinate_type const& dx, coordinate_type const& dy, - S1 const& s1, S2 const& s2) + static inline return_type a_ends_at_middle(side_info const& sides) { - coordinate_type dpx = get<1, 0>(s2) - get<0, 0>(s1); - coordinate_type dpy = get<1, 1>(s2) - get<0, 1>(s1); - // Ending at the middle, one ARRIVES, the other one is NEUTRAL - // (because it both "arrives" and "departs" there - return is_left(dx, dy, dpx, dpy) - ? return_type(sides, 'm', 1, 0, 1, 1) - : return_type(sides, 'm', 1, 0, -1, -1); + // (because it both "arrives" and "departs" there) + int const dir = sides.get<1, 1>() == 1 ? 1 : -1; + return return_type(sides, 'm', 1, 0, dir, dir); } - static inline return_type b_ends_at_middle(side_info const& sides, - coordinate_type const& dx, coordinate_type const& dy, - S1 const& s1, S2 const& s2) + static inline return_type b_ends_at_middle(side_info const& sides) { - coordinate_type dpx = get<1, 0>(s1) - get<0, 0>(s2); - coordinate_type dpy = get<1, 1>(s1) - get<0, 1>(s2); - - return is_left(dx, dy, dpx, dpy) - ? return_type(sides, 'm', 0, 1, 1, 1) - : return_type(sides, 'm', 0, 1, -1, -1); + int const dir = sides.get<0, 1>() == 1 ? 1 : -1; + return return_type(sides, 'm', 0, 1, dir, dir); } }; diff --git a/boost/geometry/policies/relate/intersection_points.hpp b/boost/geometry/policies/relate/intersection_points.hpp index d7d5199051..aa2f697a2a 100644 --- a/boost/geometry/policies/relate/intersection_points.hpp +++ b/boost/geometry/policies/relate/intersection_points.hpp @@ -16,12 +16,12 @@ #include <boost/concept_check.hpp> #include <boost/numeric/conversion/cast.hpp> -#include <boost/geometry/arithmetic/determinant.hpp> +#include <boost/geometry/algorithms/detail/assign_indexed_point.hpp> #include <boost/geometry/core/access.hpp> #include <boost/geometry/strategies/side_info.hpp> #include <boost/geometry/util/select_calculation_type.hpp> #include <boost/geometry/util/select_most_precise.hpp> - +#include <boost/geometry/util/math.hpp> namespace boost { namespace geometry { @@ -30,106 +30,153 @@ namespace policies { namespace relate { -template <typename S1, typename S2, typename ReturnType, typename CalculationType = void> +/*! +\brief Policy calculating the intersection points themselves + */ +template +< + typename ReturnType +> struct segments_intersection_points { typedef ReturnType return_type; - typedef S1 segment_type1; - typedef S2 segment_type2; - - typedef typename select_calculation_type - < - S1, S2, CalculationType - >::type coordinate_type; - - template <typename R> - static inline return_type segments_intersect(side_info const&, - R const& r, - coordinate_type const& dx1, coordinate_type const& dy1, - coordinate_type const& dx2, coordinate_type const& dy2, - S1 const& s1, S2 const& s2) - { - typedef typename geometry::coordinate_type - < - typename return_type::point_type - >::type return_coordinate_type; - - coordinate_type const s1x = get<0, 0>(s1); - coordinate_type const s1y = get<0, 1>(s1); - - return_type result; - result.count = 1; - set<0>(result.intersections[0], - boost::numeric_cast<return_coordinate_type>(R(s1x) + r * R(dx1))); - set<1>(result.intersections[0], - boost::numeric_cast<return_coordinate_type>(R(s1y) + r * R(dy1))); - return result; - } - - static inline return_type collinear_touch(coordinate_type const& x, - coordinate_type const& y, int, int) + template + < + typename Point, + typename Segment, + typename SegmentRatio, + typename T + > + static inline void assign(Point& point, + Segment const& segment, + SegmentRatio const& ratio, + T const& dx, T const& dy) { - return_type result; - result.count = 1; - set<0>(result.intersections[0], x); - set<1>(result.intersections[0], y); - return result; + typedef typename geometry::coordinate_type<Point>::type coordinate_type; + + // Calculate the intersection point based on segment_ratio + // Up to now, division was postponed. Here we divide using numerator/ + // denominator. In case of integer this results in an integer + // division. + BOOST_ASSERT(ratio.denominator() != 0); + set<0>(point, boost::numeric_cast<coordinate_type>( + get<0, 0>(segment) + + ratio.numerator() * dx / ratio.denominator())); + set<1>(point, boost::numeric_cast<coordinate_type>( + get<0, 1>(segment) + + ratio.numerator() * dy / ratio.denominator())); } - template <typename S> - static inline return_type collinear_inside(S const& s, int index1 = 0, int index2 = 1) + + 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 = 2; - set<0>(result.intersections[index1], get<0, 0>(s)); - set<1>(result.intersections[index1], get<0, 1>(s)); - set<0>(result.intersections[index2], get<1, 0>(s)); - set<1>(result.intersections[index2], get<1, 1>(s)); - return result; - } + result.count = 1; - template <typename S> - static inline return_type collinear_interior_boundary_intersect(S const& s, bool a_in_b, - int, int, bool opposite) - { - int index1 = opposite && ! a_in_b ? 1 : 0; - return collinear_inside(s, index1, 1 - index1); - } + if (sinfo.robust_ra < sinfo.robust_rb) + { + assign(result.intersections[0], s1, sinfo.robust_ra, + sinfo.dx_a, sinfo.dy_a); + } + else + { + assign(result.intersections[0], s2, sinfo.robust_rb, + sinfo.dx_b, sinfo.dy_b); + } - static inline return_type collinear_a_in_b(S1 const& s, bool) - { - return collinear_inside(s); - } - static inline return_type collinear_b_in_a(S2 const& s, bool opposite) - { - int index1 = opposite ? 1 : 0; - return collinear_inside(s, index1, 1 - index1); - } + result.fractions[0].assign(sinfo); - static inline return_type collinear_overlaps( - coordinate_type const& x1, coordinate_type const& y1, - coordinate_type const& x2, coordinate_type const& y2, - int, int, bool) - { - return_type result; - result.count = 2; - set<0>(result.intersections[0], x1); - set<1>(result.intersections[0], y1); - set<0>(result.intersections[1], x2); - set<1>(result.intersections[1], y2); return result; } - static inline return_type segment_equal(S1 const& s, bool) + template <typename Segment1, typename Segment2, typename Ratio> + static inline return_type segments_collinear( + Segment1 const& a, Segment2 const& b, + 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; - result.count = 2; - // TODO: order of IP's - set<0>(result.intersections[0], get<0, 0>(s)); - set<1>(result.intersections[0], get<0, 1>(s)); - set<0>(result.intersections[1], get<1, 0>(s)); - set<1>(result.intersections[1], get<1, 1>(s)); + 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 (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 (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 (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 (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; } @@ -142,17 +189,35 @@ struct segments_intersection_points return return_type(); } - static inline return_type collinear_disjoint() + // Both degenerate + template <typename Segment> + static inline return_type degenerate(Segment const& segment, bool) { - return return_type(); + 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; } - static inline return_type degenerate(S1 const& s, bool) + // One degenerate + template <typename Segment, typename Ratio> + 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>(s)); - set<1>(result.intersections[0], get<0, 1>(s)); + 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; } }; diff --git a/boost/geometry/policies/relate/intersection_ratios.hpp b/boost/geometry/policies/relate/intersection_ratios.hpp new file mode 100644 index 0000000000..81ecba0b54 --- /dev/null +++ b/boost/geometry/policies/relate/intersection_ratios.hpp @@ -0,0 +1,127 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-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_GEOMETRY_POLICIES_RELATE_INTERSECTION_RATIOS_HPP +#define BOOST_GEOMETRY_GEOMETRY_POLICIES_RELATE_INTERSECTION_RATIOS_HPP + + +#include <algorithm> +#include <string> + +#include <boost/concept_check.hpp> +#include <boost/numeric/conversion/cast.hpp> + +#include <boost/geometry/algorithms/detail/assign_indexed_point.hpp> +#include <boost/geometry/core/access.hpp> +#include <boost/geometry/strategies/side_info.hpp> + + +namespace boost { namespace geometry +{ + +namespace policies { namespace relate +{ + + +/*! +\brief Policy returning segment ratios +\note Template argument FractionType should be a fraction_type<SegmentRatio> + */ +template +< + typename FractionType +> +struct segments_intersection_ratios +{ + typedef FractionType return_type; + + template + < + typename Segment1, + typename Segment2, + typename SegmentIntersectionInfo + > + static inline return_type segments_crosses(side_info const&, + SegmentIntersectionInfo const& sinfo, + Segment1 const& , Segment2 const& ) + { + return_type result; + result.assign(sinfo); + return result; + } + + template <typename Segment1, typename Segment2, typename Ratio> + static inline return_type segments_collinear( + Segment1 const& , Segment2 const& , + Ratio const& ra_from_wrt_b, Ratio const& ra_to_wrt_b, + Ratio const& rb_from_wrt_a, Ratio const& rb_to_wrt_a) + { + // We have only one result, for (potentially) two IP's, + // so we take a first one + return_type result; + + if (ra_from_wrt_b.on_segment()) + { + result.assign(Ratio::zero(), ra_from_wrt_b); + } + else if (rb_from_wrt_a.in_segment()) + { + result.assign(rb_from_wrt_a, Ratio::zero()); + } + else if (ra_to_wrt_b.on_segment()) + { + result.assign(Ratio::one(), ra_to_wrt_b); + } + else if (rb_to_wrt_a.in_segment()) + { + result.assign(rb_to_wrt_a, Ratio::one()); + } + + return result; + } + + static inline return_type disjoint() + { + return return_type(); + } + static inline return_type error(std::string const&) + { + return return_type(); + } + + template <typename Segment> + static inline return_type degenerate(Segment const& segment, bool) + { + return return_type(); + } + + template <typename Segment, typename Ratio> + static inline return_type one_degenerate(Segment const& , + Ratio const& ratio, bool a_degenerate) + { + return_type result; + if (a_degenerate) + { + // IP lies on ratio w.r.t. segment b + result.assign(Ratio::zero(), ratio); + } + else + { + result.assign(ratio, Ratio::zero()); + } + return result; + } + +}; + + +}} // namespace policies::relate + +}} // namespace boost::geometry + +#endif // BOOST_GEOMETRY_GEOMETRY_POLICIES_RELATE_INTERSECTION_RATIOS_HPP diff --git a/boost/geometry/policies/relate/tupled.hpp b/boost/geometry/policies/relate/tupled.hpp index f6713c44c9..6da9095c4e 100644 --- a/boost/geometry/policies/relate/tupled.hpp +++ b/boost/geometry/policies/relate/tupled.hpp @@ -14,8 +14,6 @@ #include <boost/tuple/tuple.hpp> #include <boost/geometry/strategies/side_info.hpp> -#include <boost/geometry/util/select_calculation_type.hpp> -#include <boost/geometry/util/select_most_precise.hpp> namespace boost { namespace geometry { @@ -26,7 +24,7 @@ namespace policies { namespace relate // "tupled" to return intersection results together. // Now with two, with some meta-programming and derivations it can also be three (or more) -template <typename Policy1, typename Policy2, typename CalculationType = void> +template <typename Policy1, typename Policy2> struct segments_tupled { typedef boost::tuple @@ -35,107 +33,50 @@ struct segments_tupled typename Policy2::return_type > return_type; - // Take segments of first policy, they should be equal - typedef typename Policy1::segment_type1 segment_type1; - typedef typename Policy1::segment_type2 segment_type2; - - typedef typename select_calculation_type - < - segment_type1, - segment_type2, - CalculationType - >::type coordinate_type; - - // Get the same type, but at least a double - typedef typename select_most_precise<coordinate_type, double>::type rtype; - - template <typename R> - static inline return_type segments_intersect(side_info const& sides, - R const& r, - coordinate_type const& dx1, coordinate_type const& dy1, - coordinate_type const& dx2, coordinate_type const& dy2, - segment_type1 const& s1, segment_type2 const& s2) - { - return boost::make_tuple - ( - Policy1::segments_intersect(sides, r, - dx1, dy1, dx2, dy2, s1, s2), - Policy2::segments_intersect(sides, r, - dx1, dy1, dx2, dy2, s1, s2) - ); - } - - static inline return_type collinear_touch(coordinate_type const& x, - coordinate_type const& y, int arrival_a, int arrival_b) - { - return boost::make_tuple - ( - Policy1::collinear_touch(x, y, arrival_a, arrival_b), - Policy2::collinear_touch(x, y, arrival_a, arrival_b) - ); - } - - template <typename S> - static inline return_type collinear_interior_boundary_intersect(S const& segment, - bool a_within_b, - int arrival_a, int arrival_b, bool opposite) - { - return boost::make_tuple - ( - Policy1::collinear_interior_boundary_intersect(segment, a_within_b, arrival_a, arrival_b, opposite), - Policy2::collinear_interior_boundary_intersect(segment, a_within_b, arrival_a, arrival_b, opposite) - ); - } - - static inline return_type collinear_a_in_b(segment_type1 const& segment, - bool opposite) - { - return boost::make_tuple - ( - Policy1::collinear_a_in_b(segment, opposite), - Policy2::collinear_a_in_b(segment, opposite) - ); - } - static inline return_type collinear_b_in_a(segment_type2 const& segment, - bool opposite) + template <typename Segment1, typename Segment2, typename SegmentIntersectionInfo> + static inline return_type segments_crosses(side_info const& sides, + SegmentIntersectionInfo const& sinfo, + Segment1 const& s1, Segment2 const& s2) { return boost::make_tuple ( - Policy1::collinear_b_in_a(segment, opposite), - Policy2::collinear_b_in_a(segment, opposite) + Policy1::segments_crosses(sides, sinfo, s1, s2), + Policy2::segments_crosses(sides, sinfo, s1, s2) ); } - - static inline return_type collinear_overlaps( - coordinate_type const& x1, coordinate_type const& y1, - coordinate_type const& x2, coordinate_type const& y2, - int arrival_a, int arrival_b, bool opposite) + template <typename Segment1, typename Segment2, typename Ratio> + static inline return_type segments_collinear( + Segment1 const& segment1, Segment2 const& segment2, + Ratio const& ra1, Ratio const& ra2, Ratio const& rb1, Ratio const& rb2) { return boost::make_tuple ( - Policy1::collinear_overlaps(x1, y1, x2, y2, arrival_a, arrival_b, opposite), - Policy2::collinear_overlaps(x1, y1, x2, y2, arrival_a, arrival_b, opposite) + Policy1::segments_collinear(segment1, segment2, ra1, ra2, rb1, rb2), + Policy2::segments_collinear(segment1, segment2, ra1, ra2, rb1, rb2) ); } - static inline return_type segment_equal(segment_type1 const& s, - bool opposite) + template <typename Segment> + static inline return_type degenerate(Segment const& segment, + bool a_degenerate) { return boost::make_tuple ( - Policy1::segment_equal(s, opposite), - Policy2::segment_equal(s, opposite) + Policy1::degenerate(segment, a_degenerate), + Policy2::degenerate(segment, a_degenerate) ); } - static inline return_type degenerate(segment_type1 const& segment, - bool a_degenerate) + template <typename Segment, typename Ratio> + static inline return_type one_degenerate(Segment const& segment, + Ratio const& ratio, + bool a_degenerate) { return boost::make_tuple ( - Policy1::degenerate(segment, a_degenerate), - Policy2::degenerate(segment, a_degenerate) + Policy1::one_degenerate(segment, ratio, a_degenerate), + Policy2::one_degenerate(segment, ratio, a_degenerate) ); } @@ -157,15 +98,6 @@ struct segments_tupled ); } - static inline return_type collinear_disjoint() - { - return boost::make_tuple - ( - Policy1::collinear_disjoint(), - Policy2::collinear_disjoint() - ); - } - }; }} // namespace policies::relate diff --git a/boost/geometry/policies/robustness/get_rescale_policy.hpp b/boost/geometry/policies/robustness/get_rescale_policy.hpp new file mode 100644 index 0000000000..ed7c1eb94c --- /dev/null +++ b/boost/geometry/policies/robustness/get_rescale_policy.hpp @@ -0,0 +1,290 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2014 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2014 Bruno Lalande, Paris, France. +// Copyright (c) 2014 Mateusz Loskot, London, UK. +// Copyright (c) 2014 Adam Wulkiewicz, Lodz, Poland. + +// 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_POLICIES_ROBUSTNESS_GET_RESCALE_POLICY_HPP +#define BOOST_GEOMETRY_POLICIES_ROBUSTNESS_GET_RESCALE_POLICY_HPP + + +#include <cstddef> + +#include <boost/type_traits.hpp> +#include <boost/mpl/assert.hpp> + +#include <boost/geometry/core/tag_cast.hpp> + +#include <boost/geometry/algorithms/envelope.hpp> +#include <boost/geometry/algorithms/expand.hpp> +#include <boost/geometry/algorithms/detail/recalculate.hpp> +#include <boost/geometry/algorithms/detail/get_max_size.hpp> +#include <boost/geometry/policies/robustness/robust_type.hpp> + +#include <boost/geometry/geometries/point.hpp> +#include <boost/geometry/geometries/box.hpp> + +#include <boost/geometry/policies/robustness/no_rescale_policy.hpp> +#include <boost/geometry/policies/robustness/rescale_policy.hpp> + +#include <boost/geometry/util/promote_floating_point.hpp> + +namespace boost { namespace geometry +{ + +#ifndef DOXYGEN_NO_DETAIL +namespace detail { namespace get_rescale_policy +{ + +template <typename Point, typename RobustPoint, typename Geometry, typename Factor> +static inline void init_rescale_policy(Geometry const& geometry, + Point& min_point, + RobustPoint& min_robust_point, + Factor& factor) +{ + // Get bounding boxes + model::box<Point> env = geometry::return_envelope<model::box<Point> >(geometry); + + // Scale this to integer-range + typedef typename promote_floating_point + < + typename geometry::coordinate_type<Point>::type + >::type num_type; + num_type const diff = boost::numeric_cast<num_type>(detail::get_max_size(env)); + num_type const range = 10000000.0; // Define a large range to get precise integer coordinates + num_type const half = 0.5; + factor = math::equals(diff, num_type()) ? 1 + : boost::numeric_cast<num_type>( + boost::numeric_cast<boost::long_long_type>(half + range / diff)); + + // Assign input/output minimal points + detail::assign_point_from_index<0>(env, min_point); + num_type const two = 2; + boost::long_long_type const min_coordinate + = boost::numeric_cast<boost::long_long_type>(-range / two); + assign_values(min_robust_point, min_coordinate, min_coordinate); +} + +template <typename Point, typename RobustPoint, typename Geometry1, typename Geometry2, typename Factor> +static inline void init_rescale_policy(Geometry1 const& geometry1, + Geometry2 const& geometry2, + Point& min_point, + RobustPoint& min_robust_point, + Factor& factor) +{ + // Get bounding boxes + model::box<Point> env = geometry::return_envelope<model::box<Point> >(geometry1); + model::box<Point> env2 = geometry::return_envelope<model::box<Point> >(geometry2); + geometry::expand(env, env2); + + // TODO: merge this with implementation above + // Scale this to integer-range + typedef typename promote_floating_point + < + typename geometry::coordinate_type<Point>::type + >::type num_type; + num_type const diff = boost::numeric_cast<num_type>(detail::get_max_size(env)); + num_type const range = 10000000.0; // Define a large range to get precise integer coordinates + num_type const half = 0.5; + factor = math::equals(diff, num_type()) ? 1 + : boost::numeric_cast<num_type>( + boost::numeric_cast<boost::long_long_type>(half + range / diff)); + + // Assign input/output minimal points + detail::assign_point_from_index<0>(env, min_point); + num_type const two = 2; + boost::long_long_type const min_coordinate + = boost::numeric_cast<boost::long_long_type>(-range / two); + assign_values(min_robust_point, min_coordinate, min_coordinate); +} + + +template +< + typename Point, + bool IsFloatingPoint +> +struct rescale_policy_type +{ + typedef no_rescale_policy type; +}; + +// We rescale only all FP types +template +< + typename Point +> +struct rescale_policy_type<Point, true> +{ + typedef typename geometry::coordinate_type<Point>::type coordinate_type; + typedef model::point + < + typename detail::robust_type<coordinate_type>::type, + geometry::dimension<Point>::value, + typename geometry::coordinate_system<Point>::type + > robust_point_type; + typedef typename promote_floating_point<coordinate_type>::type factor_type; + typedef detail::robust_policy<Point, robust_point_type, factor_type> type; +}; + +template <typename Policy> +struct get_rescale_policy +{ + template <typename Geometry> + static inline Policy apply(Geometry const& geometry) + { + typedef typename point_type<Geometry>::type point_type; + typedef typename geometry::coordinate_type<Geometry>::type coordinate_type; + typedef typename promote_floating_point<coordinate_type>::type factor_type; + typedef model::point + < + typename detail::robust_type<coordinate_type>::type, + geometry::dimension<point_type>::value, + typename geometry::coordinate_system<point_type>::type + > robust_point_type; + + point_type min_point; + robust_point_type min_robust_point; + factor_type factor; + init_rescale_policy(geometry, min_point, min_robust_point, factor); + + return Policy(min_point, min_robust_point, factor); + } + + template <typename Geometry1, typename Geometry2> + static inline Policy apply(Geometry1 const& geometry1, Geometry2 const& geometry2) + { + typedef typename point_type<Geometry1>::type point_type; + typedef typename geometry::coordinate_type<Geometry1>::type coordinate_type; + typedef typename promote_floating_point<coordinate_type>::type factor_type; + typedef model::point + < + typename detail::robust_type<coordinate_type>::type, + geometry::dimension<point_type>::value, + typename geometry::coordinate_system<point_type>::type + > robust_point_type; + + point_type min_point; + robust_point_type min_robust_point; + factor_type factor; + init_rescale_policy(geometry1, geometry2, min_point, min_robust_point, factor); + + return Policy(min_point, min_robust_point, factor); + } +}; + +// Specialization for no-rescaling +template <> +struct get_rescale_policy<no_rescale_policy> +{ + template <typename Geometry> + static inline no_rescale_policy apply(Geometry const& ) + { + return no_rescale_policy(); + } + + template <typename Geometry1, typename Geometry2> + static inline no_rescale_policy apply(Geometry1 const& , Geometry2 const& ) + { + return no_rescale_policy(); + } +}; + + +}} // namespace detail::get_rescale_policy +#endif // DOXYGEN_NO_DETAIL + +template<typename Point> +struct rescale_policy_type + : public detail::get_rescale_policy::rescale_policy_type + < + Point, +#if defined(BOOST_GEOMETRY_NO_ROBUSTNESS) + false +#else + boost::is_floating_point + < + typename geometry::coordinate_type<Point>::type + >::type::value +#endif + > +{ + static const bool is_point + = boost::is_same + < + typename geometry::tag<Point>::type, + geometry::point_tag + >::type::value; + + BOOST_MPL_ASSERT_MSG((is_point), + INVALID_INPUT_GEOMETRY, + (typename geometry::tag<Point>::type)); +}; + + +template +< + typename Geometry1, + typename Geometry2, + typename Tag1 = typename tag_cast + < + typename tag<Geometry1>::type, + box_tag, + pointlike_tag, + linear_tag, + areal_tag + >::type, + typename Tag2 = typename tag_cast + < + typename tag<Geometry2>::type, + box_tag, + pointlike_tag, + linear_tag, + areal_tag + >::type +> +struct rescale_overlay_policy_type + // Default: no rescaling + : public detail::get_rescale_policy::rescale_policy_type + < + typename geometry::point_type<Geometry1>::type, + false + > +{}; + +// Areal/areal: get rescale policy based on coordinate type +template +< + typename Geometry1, + typename Geometry2 +> +struct rescale_overlay_policy_type<Geometry1, Geometry2, areal_tag, areal_tag> + : public rescale_policy_type + < + typename geometry::point_type<Geometry1>::type + > +{}; + + +template <typename Policy, typename Geometry> +inline Policy get_rescale_policy(Geometry const& geometry) +{ + return detail::get_rescale_policy::get_rescale_policy<Policy>::apply(geometry); +} + +template <typename Policy, typename Geometry1, typename Geometry2> +inline Policy get_rescale_policy(Geometry1 const& geometry1, Geometry2 const& geometry2) +{ + return detail::get_rescale_policy::get_rescale_policy<Policy>::apply(geometry1, geometry2); +} + + +}} // namespace boost::geometry + + +#endif // BOOST_GEOMETRY_POLICIES_ROBUSTNESS_GET_RESCALE_POLICY_HPP diff --git a/boost/geometry/policies/robustness/no_rescale_policy.hpp b/boost/geometry/policies/robustness/no_rescale_policy.hpp new file mode 100644 index 0000000000..a7899842c1 --- /dev/null +++ b/boost/geometry/policies/robustness/no_rescale_policy.hpp @@ -0,0 +1,66 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2013 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2013 Bruno Lalande, Paris, France. +// Copyright (c) 2013 Mateusz Loskot, London, UK. +// Copyright (c) 2013 Adam Wulkiewicz, Lodz, Poland. + +// 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_POLICIES_ROBUSTNESS_NO_RESCALE_POLICY_HPP +#define BOOST_GEOMETRY_POLICIES_ROBUSTNESS_NO_RESCALE_POLICY_HPP + +#include <stddef.h> + +#include <boost/geometry/core/coordinate_type.hpp> +#include <boost/geometry/policies/robustness/robust_point_type.hpp> +#include <boost/geometry/policies/robustness/segment_ratio.hpp> +#include <boost/geometry/policies/robustness/segment_ratio_type.hpp> + +namespace boost { namespace geometry +{ + +#ifndef DOXYGEN_NO_DETAIL +namespace detail +{ + +// Probably this will be moved out of namespace detail +struct no_rescale_policy +{ + static bool const enabled = false; + + // We don't rescale but return the reference of the input + template <std::size_t Dimension, typename Value> + inline Value const& apply(Value const& value) const + { + return value; + } +}; + +} // namespace detail +#endif + + +// Implement meta-functions for this policy +template <typename Point> +struct robust_point_type<Point, detail::no_rescale_policy> +{ + // The point itself + typedef Point type; +}; + +template <typename Point> +struct segment_ratio_type<Point, detail::no_rescale_policy> +{ + // Define a segment_ratio defined on coordinate type, e.g. + // int/int or float/float + typedef typename geometry::coordinate_type<Point>::type coordinate_type; + typedef segment_ratio<coordinate_type> type; +}; + + +}} // namespace boost::geometry + +#endif // BOOST_GEOMETRY_POLICIES_ROBUSTNESS_NO_RESCALE_POLICY_HPP diff --git a/boost/geometry/policies/robustness/rescale_policy.hpp b/boost/geometry/policies/robustness/rescale_policy.hpp new file mode 100644 index 0000000000..5b3b566976 --- /dev/null +++ b/boost/geometry/policies/robustness/rescale_policy.hpp @@ -0,0 +1,83 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2014 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2014 Bruno Lalande, Paris, France. +// Copyright (c) 2014 Mateusz Loskot, London, UK. +// Copyright (c) 2014 Adam Wulkiewicz, Lodz, Poland. + +// 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_POLICIES_ROBUSTNESS_RESCALE_POLICY_HPP +#define BOOST_GEOMETRY_POLICIES_ROBUSTNESS_RESCALE_POLICY_HPP + +#include <cstddef> + +#include <boost/type_traits.hpp> + +#include <boost/geometry/policies/robustness/segment_ratio.hpp> +#include <boost/geometry/policies/robustness/segment_ratio_type.hpp> +#include <boost/geometry/policies/robustness/robust_point_type.hpp> + +namespace boost { namespace geometry +{ + +#ifndef DOXYGEN_NO_DETAIL +namespace detail +{ + +template <typename FpPoint, typename IntPoint, typename CalculationType> +struct robust_policy +{ + static bool const enabled = true; + + typedef typename geometry::coordinate_type<IntPoint>::type output_ct; + + robust_policy(FpPoint const& fp_min, IntPoint const& int_min, CalculationType const& the_factor) + : m_fp_min(fp_min) + , m_int_min(int_min) + , m_multiplier(the_factor) + { + } + + template <std::size_t Dimension, typename Value> + inline output_ct apply(Value const& value) const + { + // a + (v-b)*f + CalculationType const a = static_cast<CalculationType>(get<Dimension>(m_int_min)); + CalculationType const b = static_cast<CalculationType>(get<Dimension>(m_fp_min)); + CalculationType const result = a + (value - b) * m_multiplier; + return static_cast<output_ct>(result); + } + + FpPoint m_fp_min; + IntPoint m_int_min; + CalculationType m_multiplier; +}; + +} // namespace detail +#endif + + +// Implement meta-functions for this policy + +// Define the IntPoint as a robust-point type +template <typename Point, typename FpPoint, typename IntPoint, typename CalculationType> +struct robust_point_type<Point, detail::robust_policy<FpPoint, IntPoint, CalculationType> > +{ + typedef IntPoint type; +}; + +// Meta function for rescaling, if rescaling is done segment_ratio is based on long long +template <typename Point, typename FpPoint, typename IntPoint, typename CalculationType> +struct segment_ratio_type<Point, detail::robust_policy<FpPoint, IntPoint, CalculationType> > +{ + typedef segment_ratio<boost::long_long_type> type; +}; + + +}} // namespace boost::geometry + + +#endif // BOOST_GEOMETRY_POLICIES_ROBUSTNESS_RESCALE_POLICY_HPP diff --git a/boost/geometry/policies/robustness/robust_point_type.hpp b/boost/geometry/policies/robustness/robust_point_type.hpp new file mode 100644 index 0000000000..25639227f0 --- /dev/null +++ b/boost/geometry/policies/robustness/robust_point_type.hpp @@ -0,0 +1,30 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2013 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2013 Bruno Lalande, Paris, France. +// Copyright (c) 2013 Mateusz Loskot, London, UK. +// Copyright (c) 2013 Adam Wulkiewicz, Lodz, Poland. + +// 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_POLICIES_ROBUSTNESS_ROBUST_POINT_TYPE_HPP +#define BOOST_GEOMETRY_POLICIES_ROBUSTNESS_ROBUST_POINT_TYPE_HPP + +namespace boost { namespace geometry +{ + +// Meta-function to typedef a robust point type for a policy +template <typename Point, typename Policy> +struct robust_point_type +{ + // By default, the point itself is the robust type + typedef Point type; +}; + + +}} // namespace boost::geometry + + +#endif // BOOST_GEOMETRY_POLICIES_ROBUSTNESS_ROBUST_POINT_TYPE_HPP diff --git a/boost/geometry/policies/robustness/robust_type.hpp b/boost/geometry/policies/robustness/robust_type.hpp new file mode 100644 index 0000000000..4cfb2c4d91 --- /dev/null +++ b/boost/geometry/policies/robustness/robust_type.hpp @@ -0,0 +1,67 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2014 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2014 Bruno Lalande, Paris, France. +// Copyright (c) 2014 Mateusz Loskot, London, UK. +// Copyright (c) 2014 Adam Wulkiewicz, Lodz, Poland. + +// 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_POLICIES_ROBUSTNESS_ROBUST_TYPE_HPP +#define BOOST_GEOMETRY_POLICIES_ROBUSTNESS_ROBUST_TYPE_HPP + + +#include <boost/type_traits.hpp> +#include <boost/config.hpp> + + +namespace boost { namespace geometry +{ + +#ifndef DOXYGEN_NO_DETAIL + +namespace detail_dispatch +{ + +template <typename CoordinateType, typename IsFloatingPoint> +struct robust_type +{ +}; + +template <typename CoordinateType> +struct robust_type<CoordinateType, boost::false_type> +{ + typedef CoordinateType type; +}; + +template <typename CoordinateType> +struct robust_type<CoordinateType, boost::true_type> +{ + typedef boost::long_long_type type; +}; + +} // namespace detail_dispatch + +namespace detail +{ + +template <typename CoordinateType> +struct robust_type +{ + typedef typename detail_dispatch::robust_type + < + CoordinateType, + typename boost::is_floating_point<CoordinateType>::type + >::type type; +}; + +} // namespace detail +#endif // DOXYGEN_NO_DETAIL + + +}} // namespace boost::geometry + + +#endif // BOOST_GEOMETRY_POLICIES_ROBUSTNESS_ROBUST_TYPE_HPP diff --git a/boost/geometry/policies/robustness/segment_ratio.hpp b/boost/geometry/policies/robustness/segment_ratio.hpp new file mode 100644 index 0000000000..8b55605c7f --- /dev/null +++ b/boost/geometry/policies/robustness/segment_ratio.hpp @@ -0,0 +1,239 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2013 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_POLICIES_ROBUSTNESS_SEGMENT_RATIO_HPP +#define BOOST_GEOMETRY_POLICIES_ROBUSTNESS_SEGMENT_RATIO_HPP + +#include <boost/assert.hpp> +#include <boost/config.hpp> +#include <boost/rational.hpp> + +#include <boost/geometry/util/math.hpp> +#include <boost/geometry/util/promote_floating_point.hpp> + +namespace boost { namespace geometry +{ + + +namespace detail { namespace segment_ratio +{ + +template +< + typename Type, + bool IsIntegral = boost::is_integral<Type>::type::value +> +struct less {}; + +template <typename Type> +struct less<Type, true> +{ + template <typename Ratio> + static inline bool apply(Ratio const& lhs, Ratio const& rhs) + { + return boost::rational<Type>(lhs.numerator(), lhs.denominator()) + < boost::rational<Type>(rhs.numerator(), rhs.denominator()); + } +}; + +template <typename Type> +struct less<Type, false> +{ + template <typename Ratio> + static inline bool apply(Ratio const& lhs, Ratio const& rhs) + { + BOOST_ASSERT(lhs.denominator() != 0); + BOOST_ASSERT(rhs.denominator() != 0); + return lhs.numerator() * rhs.denominator() + < rhs.numerator() * lhs.denominator(); + } +}; + +template +< + typename Type, + bool IsIntegral = boost::is_integral<Type>::type::value +> +struct equal {}; + +template <typename Type> +struct equal<Type, true> +{ + template <typename Ratio> + static inline bool apply(Ratio const& lhs, Ratio const& rhs) + { + return boost::rational<Type>(lhs.numerator(), lhs.denominator()) + == boost::rational<Type>(rhs.numerator(), rhs.denominator()); + } +}; + +template <typename Type> +struct equal<Type, false> +{ + template <typename Ratio> + static inline bool apply(Ratio const& lhs, Ratio const& rhs) + { + BOOST_ASSERT(lhs.denominator() != 0); + BOOST_ASSERT(rhs.denominator() != 0); + return geometry::math::equals + ( + lhs.numerator() * rhs.denominator(), + rhs.numerator() * lhs.denominator() + ); + } +}; + +}} + +//! Small class to keep a ratio (e.g. 1/4) +//! Main purpose is intersections and checking on 0, 1, and smaller/larger +//! The prototype used Boost.Rational. However, we also want to store FP ratios, +//! (so numerator/denominator both in float) +//! and Boost.Rational starts with GCD which we prefer to avoid if not necessary +//! On a segment means: this ratio is between 0 and 1 (both inclusive) +//! +template <typename Type> +class segment_ratio +{ +public : + typedef Type numeric_type; + + // Type-alias for the type itself + typedef segment_ratio<Type> thistype; + + inline segment_ratio() + : m_numerator(0) + , m_denominator(1) + , m_approximation(0) + {} + + inline segment_ratio(const Type& nominator, const Type& denominator) + : m_numerator(nominator) + , m_denominator(denominator) + { + initialize(); + } + + inline Type const& numerator() const { return m_numerator; } + inline Type const& denominator() const { return m_denominator; } + + inline void assign(const Type& nominator, const Type& denominator) + { + m_numerator = nominator; + m_denominator = denominator; + initialize(); + } + + inline void initialize() + { + // Minimal normalization + // 1/-4 => -1/4, -1/-4 => 1/4 + if (m_denominator < 0) + { + m_numerator = -m_numerator; + m_denominator = -m_denominator; + } + + typedef typename promote_floating_point<Type>::type num_type; + static const num_type scale = 1000000.0; + m_approximation = + m_denominator == 0 ? 0 + : boost::numeric_cast<double> + ( + boost::numeric_cast<num_type>(m_numerator) * scale + / boost::numeric_cast<num_type>(m_denominator) + ); + } + + inline bool is_zero() const { return math::equals(m_numerator, 0); } + inline bool is_one() const { return math::equals(m_numerator, m_denominator); } + inline bool on_segment() const + { + // e.g. 0/4 or 4/4 or 2/4 + return m_numerator >= 0 && m_numerator <= m_denominator; + } + inline bool in_segment() const + { + // e.g. 1/4 + return m_numerator > 0 && m_numerator < m_denominator; + } + inline bool on_end() const + { + // e.g. 0/4 or 4/4 + return is_zero() || is_one(); + } + inline bool left() const + { + // e.g. -1/4 + return m_numerator < 0; + } + inline bool right() const + { + // e.g. 5/4 + return m_numerator > m_denominator; + } + + inline bool close_to(thistype const& other) const + { + return geometry::math::abs(m_approximation - other.m_approximation) < 2; + } + + inline bool operator< (thistype const& other) const + { + return close_to(other) + ? detail::segment_ratio::less<Type>::apply(*this, other) + : m_approximation < other.m_approximation; + } + + inline bool operator== (thistype const& other) const + { + return close_to(other) + && detail::segment_ratio::equal<Type>::apply(*this, other); + } + + static inline thistype zero() + { + static thistype result(0, 1); + return result; + } + + static inline thistype one() + { + static thistype result(1, 1); + return result; + } + +#if defined(BOOST_GEOMETRY_DEFINE_STREAM_OPERATOR_SEGMENT_RATIO) + friend std::ostream& operator<<(std::ostream &os, segment_ratio const& ratio) + { + os << ratio.m_numerator << "/" << ratio.m_denominator + << " (" << (static_cast<double>(ratio.m_numerator) + / static_cast<double>(ratio.m_denominator)) + << ")"; + return os; + } +#endif + + + +private : + Type m_numerator; + Type m_denominator; + + // Contains ratio on scale 0..1000000 (for 0..1) + // This is an approximation for fast and rough comparisons + // Boost.Rational is used if the approximations are close. + // Reason: performance, Boost.Rational does a GCD by default and also the + // comparisons contain while-loops. + double m_approximation; +}; + + +}} // namespace boost::geometry + +#endif // BOOST_GEOMETRY_POLICIES_ROBUSTNESS_SEGMENT_RATIO_HPP diff --git a/boost/geometry/policies/robustness/segment_ratio_type.hpp b/boost/geometry/policies/robustness/segment_ratio_type.hpp new file mode 100644 index 0000000000..19e935bbb9 --- /dev/null +++ b/boost/geometry/policies/robustness/segment_ratio_type.hpp @@ -0,0 +1,28 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2013 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2013 Bruno Lalande, Paris, France. +// Copyright (c) 2013 Mateusz Loskot, London, UK. +// Copyright (c) 2013 Adam Wulkiewicz, Lodz, Poland. + +// 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_POLICIES_ROBUSTNESS_SEGMENT_RATIO_TYPE_HPP +#define BOOST_GEOMETRY_POLICIES_ROBUSTNESS_SEGMENT_RATIO_TYPE_HPP + +#include <boost/geometry/algorithms/not_implemented.hpp> + +namespace boost { namespace geometry +{ + +// Meta-function to access segment-ratio for a policy +template <typename Point, typename Policy> +struct segment_ratio_type {}; // : not_implemented<> {}; + + +}} // namespace boost::geometry + + +#endif // BOOST_GEOMETRY_POLICIES_ROBUSTNESS_SEGMENT_RATIO_TYPE_HPP |