diff --git a/doc/index/make_qbk.py b/doc/index/make_qbk.py index e8fbb3432..bff630488 100755 --- a/doc/index/make_qbk.py +++ b/doc/index/make_qbk.py @@ -21,6 +21,13 @@ def run_command(command): if os.system(command) != 0: raise Exception("Error running %s" % command) +def remove_all_files(dir): + if os.path.exists(dir): + for f in os.listdir(dir): + os.remove(dir+f) + +remove_all_files("xml/") + run_command("doxygen Doxyfile") run_command(cmd % ("classboost_1_1geometry_1_1index_1_1rtree", "rtree")) run_command(cmd % ("group__rtree__functions", "rtree_functions")) diff --git a/doc/index/src/examples/rtree/Jamfile.v2 b/doc/index/src/examples/rtree/Jamfile.v2 index 79778b9ab..bc04ddd33 100644 --- a/doc/index/src/examples/rtree/Jamfile.v2 +++ b/doc/index/src/examples/rtree/Jamfile.v2 @@ -17,8 +17,10 @@ exe interprocess : interprocess.cpp /boost/thread//boost_thread : acc:-lrt acc-pa_risc:-lrt - gcc-mingw:"-lole32 -loleaut32 -lpsapi -ladvapi32" hpux,gcc:"-Wl,+as,mpas" +# gcc-mingw:"-lole32 -loleaut32 -lpsapi -ladvapi32" + gcc,windows:"-lole32 -loleaut32 -lpsapi -ladvapi32" + windows,clang:"-lole32 -loleaut32 -lpsapi -ladvapi32" : multi : # requirements diff --git a/doc/make_qbk.py b/doc/make_qbk.py index de32ecf15..74514753d 100755 --- a/doc/make_qbk.py +++ b/doc/make_qbk.py @@ -40,9 +40,14 @@ def run_command(command): if os.system(command) != 0: raise Exception("Error running %s" % command) +def remove_all_files(dir): + if os.path.exists(dir): + for f in os.listdir(dir): + os.remove(dir+f) + def call_doxygen(): - os.chdir("doxy"); - run_command("rm -f doxygen_output/xml/*.xml") + os.chdir("doxy") + remove_all_files("doxygen_output/xml/") run_command(doxygen_cmd) os.chdir("..") diff --git a/doc/reference/algorithms/difference_behavior.qbk b/doc/reference/algorithms/difference_behavior.qbk index 0044026c8..25c20b66c 100644 --- a/doc/reference/algorithms/difference_behavior.qbk +++ b/doc/reference/algorithms/difference_behavior.qbk @@ -1,7 +1,12 @@ [/============================================================================ Boost.Geometry (aka GGL, Generic Geometry Library) - Copyright (c) 2011-2012 Barend Gehrels, Amsterdam, the Netherlands. + Copyright (c) 2011-2014 Barend Gehrels, Amsterdam, the Netherlands. + + This file was modified by Oracle on 2014. + Modifications copyright (c) 2014, Oracle and/or its affiliates. + + Contributed and/or modified by Menelaos Karavelas, 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 @@ -14,6 +19,8 @@ [[__2dim__][All combinations of: box, ring, polygon, multi_polygon]] [[__1dim__ / __2dim__][A combinations of a (multi) linestring with a (multi) polygon results in a collection of linestrings]] +[[__1dim__][All combinations of: linestring, multi_linestring; results in a collection of linestrings]] +[[__0dim__][All combinations of: point, multi_point; results in a collection of points]] [[__other__][__nyiversion__]] [[__sph__][__nyiversion__]] [[Three dimensional][__nyiversion__]] diff --git a/doc/release_notes.qbk b/doc/release_notes.qbk index 249510236..b4712e2b9 100644 --- a/doc/release_notes.qbk +++ b/doc/release_notes.qbk @@ -27,11 +27,15 @@ * [@https://svn.boost.org/trac/boost/ticket/9245 9245] Check for process errors in make_qbk.py * [@https://svn.boost.org/trac/boost/ticket/9081 9081] Booleans create self-intersecting polygons from non-self-intersecting polygons * [@https://svn.boost.org/trac/boost/ticket/8310 8310] Wrong results with overlapping polygons (fixed using point_on_surface for disjoint) +* [@https://svn.boost.org/trac/boost/ticket/9871 9871] Remove spike in polygon with only a spike [*Bugfixes] * intersects(polygon) could return a self-intersection-point for its closing point, fixed +[*Solved tickets] + +* [@https://svn.boost.org/trac/boost/ticket/9563 9563] (Sym)difference not successful, fixed by rescaling to robust type [/=================] [heading Boost 1.55] diff --git a/extensions/test/algorithms/buffer/multi_polygon_buffer.cpp b/extensions/test/algorithms/buffer/multi_polygon_buffer.cpp index ee21d6f20..0b7cc2edb 100644 --- a/extensions/test/algorithms/buffer/multi_polygon_buffer.cpp +++ b/extensions/test/algorithms/buffer/multi_polygon_buffer.cpp @@ -281,13 +281,18 @@ void test_all() test_one("rt_d", rt_d, 18.8726, 0.3); test_one("rt_d", rt_d, 19.8823, 0.3); test_one("rt_e", rt_e, 14.1866, 0.3); +#if ! defined(BOOST_GEOMETRY_RESCALE_TO_ROBUST) test_one("rt_e", rt_e, 15.1198, 0.3); // This does not add anything: test_one("rt_f", rt_f, 4.28937, 0.3); + test_one("rt_f", rt_f, 4.60853, 0.3); +#endif test_one("rt_g1", rt_g1, 24.719, 1.0); +#if ! defined(BOOST_GEOMETRY_RESCALE_TO_ROBUST) test_one("rt_g1", rt_g1, 30.3137, 1.0); test_one("rt_g2", rt_g2, 18.5711, 1.0); +#endif test_one("rt_g3", rt_g3, 16.5711, 1.0); test_one("rt_h", rt_h, 47.6012, 1.0); @@ -299,13 +304,17 @@ void test_all() test_one("rt_k", rt_k, 42.0092, 1.0); test_one("rt_k", rt_k, 48.0563, 1.0); // This does not add anything: test_one("rt_l", rt_l, 14.1074, 1.0); +#if ! defined(BOOST_GEOMETRY_RESCALE_TO_ROBUST) test_one("rt_l", rt_l, 19.3995, 1.0); +#endif test_one("rt_m1", rt_m1, 14.1074, 1.0); +#if ! defined(BOOST_GEOMETRY_RESCALE_TO_ROBUST) test_one("rt_m1", rt_m1, 19.4853, 1.0); test_one("rt_m2", rt_m2, 21.4853, 1.0); // This does not add anything: test_one("rt_n", rt_n, 14.1074, 1.0); test_one("rt_n", rt_n, 18.4853, 1.0); +#endif test_one("rt_o1", rt_o1, 17.536, 1.0); test_one("rt_o1", rt_o1, 20.9142, 1.0); @@ -323,7 +332,10 @@ void test_all() test_one("rt_p7", rt_p7, 26.2279, 1.0); test_one("rt_p8", rt_p8, 29.0563, 1.0); test_one("rt_p9", rt_p9, 26.1421, 1.0); +#if ! defined(BOOST_GEOMETRY_RESCALE_TO_ROBUST) test_one("rt_p10", rt_p10, 23.3995, 1.0); +#endif + test_one("rt_p11", rt_p11, 28.7426, 1.0); test_one("rt_p12", rt_p12, 22.5711, 1.0); test_one("rt_p13", rt_p13, 19.9142, 1.0); @@ -340,10 +352,14 @@ void test_all() test_one("rt_q1", rt_q1, 27, 1.0); test_one("rt_q2", rt_q2, 26.4853, 1.0); +#if ! defined(BOOST_GEOMETRY_RESCALE_TO_ROBUST) test_one("rt_r", rt_r, 21.0761, 1.0); +#endif test_one("rt_s1", rt_s1, 20.4853, 1.0); test_one("rt_s2", rt_s2, 24.6495, 1.0); +#if ! defined(BOOST_GEOMETRY_RESCALE_TO_ROBUST) test_one("rt_t", rt_t, 15.6569, 1.0); +#endif } diff --git a/extensions/test/algorithms/buffer/polygon_buffer.cpp b/extensions/test/algorithms/buffer/polygon_buffer.cpp index 0b4625f19..9ccb127ea 100644 --- a/extensions/test/algorithms/buffer/polygon_buffer.cpp +++ b/extensions/test/algorithms/buffer/polygon_buffer.cpp @@ -138,9 +138,13 @@ void test_all() test_one("tipped_aitch9", tipped_aitch, 76.6457, 0.9); test_one("tipped_aitch13", tipped_aitch, 90.641, 1.3); +#if ! defined(BOOST_GEOMETRY_RESCALE_TO_ROBUST) test_one("snake4", snake, 64.44, 0.4); +#endif test_one("snake5", snake, 72, 0.5); +#if ! defined(BOOST_GEOMETRY_RESCALE_TO_ROBUST) test_one("snake6", snake, 75.44, 0.6); +#endif test_one("snake16", snake, 114.24, 1.6); test_one("funnelgate2", funnelgate, 120.982, 2); @@ -347,4 +351,4 @@ select from bowl -*/ \ No newline at end of file +*/ diff --git a/extensions/test/algorithms/buffer/test_buffer.hpp b/extensions/test/algorithms/buffer/test_buffer.hpp index 5ec6787a7..5941be63e 100644 --- a/extensions/test/algorithms/buffer/test_buffer.hpp +++ b/extensions/test/algorithms/buffer/test_buffer.hpp @@ -53,12 +53,14 @@ #if defined(TEST_WITH_SVG) #include -template -void post_map(Geometry const& geometry, Mapper& mapper) +template +void post_map(Geometry const& geometry, Mapper& mapper, RescalePolicy const& rescale_policy) { + typedef typename bg::point_type::type point_type; typedef bg::detail::overlay::turn_info < - typename bg::point_type::type + point_type, + typename bg::segment_ratio_type::type > turn_info; std::vector turns; @@ -67,7 +69,7 @@ void post_map(Geometry const& geometry, Mapper& mapper) bg::self_turns < bg::detail::overlay::assign_null_policy - >(geometry, turns, policy); + >(geometry, rescale_policy, turns, policy); BOOST_FOREACH(turn_info const& turn, turns) { @@ -218,12 +220,20 @@ void test_buffer(std::string const& caseid, Geometry const& geometry, > distance_strategy(distance_left, distance_right); + typedef typename bg::point_type::type point_type; + typedef typename bg::rescale_policy_type::type + rescale_policy_type; + + rescale_policy_type rescale_policy + = bg::get_rescale_policy(geometry); + std::vector buffered; bg::buffer_inserter(geometry, std::back_inserter(buffered), distance_strategy, join_strategy, - end_strategy + end_strategy, + rescale_policy #ifdef BOOST_GEOMETRY_DEBUG_WITH_MAPPER , mapper #endif @@ -299,7 +309,7 @@ void test_buffer(std::string const& caseid, Geometry const& geometry, { mapper.map(polygon, "opacity:0.4;fill:rgb(255,255,128);stroke:rgb(0,0,0);stroke-width:3"); //mapper.map(polygon, "opacity:0.2;fill:none;stroke:rgb(255,0,0);stroke-width:3"); - post_map(polygon, mapper); + post_map(polygon, mapper, rescale_policy); } #endif } diff --git a/include/boost/geometry/algorithms/detail/get_max_size.hpp b/include/boost/geometry/algorithms/detail/get_max_size.hpp new file mode 100644 index 000000000..8ac43e78b --- /dev/null +++ b/include/boost/geometry/algorithms/detail/get_max_size.hpp @@ -0,0 +1,64 @@ +// 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_ALGORITHMS_DETAIL_GET_MAX_SIZE_HPP +#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_GET_MAX_SIZE_HPP + + +#include + +#include +#include + +namespace boost { namespace geometry +{ + +#ifndef DOXYGEN_NO_DETAIL +namespace detail +{ + +template +struct get_max_size_box +{ + static inline typename coordinate_type::type apply(Box const& box) + { + typename coordinate_type::type s + = geometry::math::abs(geometry::get<1, Dimension>(box) - geometry::get<0, Dimension>(box)); + + return (std::max)(s, get_max_size_box::apply(box)); + } +}; + +template +struct get_max_size_box +{ + static inline typename coordinate_type::type apply(Box const& box) + { + return geometry::math::abs(geometry::get<1, 0>(box) - geometry::get<0, 0>(box)); + } +}; + +// This might be implemented later on for other geometries too. +// Not dispatched yet. +template +inline typename coordinate_type::type get_max_size(Box const& box) +{ + return get_max_size_box::value - 1>::apply(box); +} + +} // namespace detail +#endif // DOXYGEN_NO_DETAIL + + +}} // namespace boost::geometry + + +#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_GET_MAX_SIZE_HPP diff --git a/include/boost/geometry/algorithms/detail/has_self_intersections.hpp b/include/boost/geometry/algorithms/detail/has_self_intersections.hpp index bb7bcb9bc..65a58ee8c 100644 --- a/include/boost/geometry/algorithms/detail/has_self_intersections.hpp +++ b/include/boost/geometry/algorithms/detail/has_self_intersections.hpp @@ -16,7 +16,10 @@ #include #include #include -#include + +#include +#include +#include #include @@ -57,15 +60,19 @@ namespace detail { namespace overlay { -template -inline bool has_self_intersections(Geometry const& geometry, RescalePolicy const& rescale_policy) +template +inline bool has_self_intersections(Geometry const& geometry, RobustPolicy const& robust_policy) { typedef typename point_type::type point_type; - typedef detail::overlay::turn_info turn_info; + typedef turn_info + < + point_type, + typename segment_ratio_type::type + > turn_info; std::deque turns; detail::disjoint::disjoint_interrupt_policy policy; - geometry::self_turns(geometry, rescale_policy, turns, policy); + geometry::self_turns(geometry, robust_policy, turns, policy); #ifdef BOOST_GEOMETRY_DEBUG_HAS_SELF_INTERSECTIONS bool first = true; @@ -115,7 +122,14 @@ inline bool has_self_intersections(Geometry const& geometry, RescalePolicy const template inline bool has_self_intersections(Geometry const& geometry) { - return has_self_intersections(geometry, detail::no_rescale_policy()); + typedef typename geometry::point_type::type point_type; + typedef typename geometry::rescale_policy_type::type + rescale_policy_type; + + rescale_policy_type robust_policy + = geometry::get_rescale_policy(geometry); + + return has_self_intersections(geometry, robust_policy); } diff --git a/include/boost/geometry/algorithms/detail/intersection_side.hpp b/include/boost/geometry/algorithms/detail/intersection_side.hpp new file mode 100644 index 000000000..a4eff620a --- /dev/null +++ b/include/boost/geometry/algorithms/detail/intersection_side.hpp @@ -0,0 +1,128 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2011-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_INTERSECTION_SIDE_HPP +#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_INTERSECTION_SIDE_HPP + +#include +#include +#include +#include +#include +#include +#include + +namespace boost { namespace geometry +{ + +namespace detail { namespace intersection_side +{ + + +//! Calculates the side (left=1,right=-1,collinear=0) of the intersection point +//! of p/q (if any) with respect to segment s. +//! This is not done by calculating IP p/q and calling side, because that is +//! (even if robust_policy is used) not robust: the IP can be rounded off. +//! So it is done by investigating the sides of the segments, and calculating +//! the segment_ratios of the IP and check which side it is. +//! Return value is conform geometry::side +//! Currently all points are of same type +//! Even if there is no IP at all, a side is returned. IP is not calculated on +//! itself +template +inline int intersection_side(Point const& pi, Point const& pj, + Point const& qi, Point const& qj, + Point const& si, Point const& sj, + RobustPolicy const& robust_policy) +{ + typedef typename geometry::robust_point_type + < + Point, + RobustPolicy + >::type robust_point_type; + typedef typename geometry::segment_ratio_type + < + Point, + RobustPolicy + >::type segment_ratio_type; + + robust_point_type pi_rob, pj_rob, qi_rob, qj_rob, si_rob, sj_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); + geometry::recalculate(si_rob, si, robust_policy); + geometry::recalculate(sj_rob, sj, robust_policy); + + typedef typename geometry::strategy::side::services::default_strategy + < + typename geometry::cs_tag::type + >::type side_strategy; + + int const side_pi = side_strategy::apply(pi_rob, si_rob, sj_rob); + int const side_pj = side_strategy::apply(pj_rob, si_rob, sj_rob); + if (side_pi == side_pj) + { + return side_pi; + } + + int const side_qi = side_strategy::apply(qi_rob, si_rob, sj_rob); + int const side_qj = side_strategy::apply(qj_rob, si_rob, sj_rob); + if (side_qi == side_qj) + { + // Same here, see comment above + return side_qi; + } + + typedef model::referring_segment segment_type; + + segment_type p(pi, pj); + segment_type q(qi, qj); + segment_type s(si, sj); + + // No segment lies on the left or right or completely collinear + // Relate segments p // q and p // s, don't calculate IP's but just return + // the ratios. Both ratios called "robust_ra" are measured on p and can be + // related. + fraction_type ratio_p_wrt_q + = strategy::intersection::relate_cartesian_segments + < + policies::relate::segments_intersection_ratios + < + fraction_type + > + >::apply(p, q, robust_policy, pi_rob, pj_rob, qi_rob, qj_rob); + + fraction_type ratio_p_wrt_s + = strategy::intersection::relate_cartesian_segments + < + policies::relate::segments_intersection_ratios + < + fraction_type + > + >::apply(p, s, robust_policy, pi_rob, pj_rob, si_rob, sj_rob); + + return + + // Closer to the segment start point of p -> side of pi + ratio_p_wrt_q.robust_ra < ratio_p_wrt_s.robust_ra ? side_pi + + // Ratios are equal, IP must be exactly on the segment + : ratio_p_wrt_q.robust_ra == ratio_p_wrt_s.robust_ra ? 0 + + // ratio p wrt q is larger than ratio p wrt s + // So: close to the segment end point of p -> side of pj + : side_pj; +} + + +}} // namespace detail::intersection_side + +}} // namespace boost::geometry + +#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_INTERSECTION_SIDE_HPP diff --git a/include/boost/geometry/algorithms/detail/overlay/append_no_dups_or_spikes.hpp b/include/boost/geometry/algorithms/detail/overlay/append_no_dups_or_spikes.hpp index 8112e3e6b..b911b6b6d 100644 --- a/include/boost/geometry/algorithms/detail/overlay/append_no_dups_or_spikes.hpp +++ b/include/boost/geometry/algorithms/detail/overlay/append_no_dups_or_spikes.hpp @@ -24,35 +24,118 @@ namespace boost { namespace geometry namespace detail { namespace overlay { -template -inline void append_no_dups_or_spikes(Range& range, Point const& point) +// TODO: move this / rename this +template +inline bool points_equal_or_close(Point1 const& point1, + Point2 const& point2, + RobustPolicy const& robust_policy) +{ + if (detail::equals::equals_point_point(point1, point2)) + { + return true; + } + + if (! RobustPolicy::enabled) + { + return false; + } + + // Try using specified robust policy + typedef typename geometry::robust_point_type + < + Point1, + RobustPolicy + >::type robust_point_type; + + robust_point_type point1_rob, point2_rob; + geometry::recalculate(point1_rob, point1, robust_policy); + geometry::recalculate(point2_rob, point2, robust_policy); + + return detail::equals::equals_point_point(point1_rob, point2_rob); +} + + +template +inline void append_no_dups_or_spikes(Range& range, Point const& point, + RobustPolicy const& robust_policy) { #ifdef BOOST_GEOMETRY_DEBUG_INTERSECTION std::cout << " add: (" << geometry::get<0>(point) << ", " << geometry::get<1>(point) << ")" << std::endl; #endif + // The code below thies condition checks all spikes/dups + // for geometries >= 3 points. + // So we have to check the first potential duplicate differently + if (boost::size(range) == 1 + && points_equal_or_close(*(boost::begin(range)), point, robust_policy)) + { + return; + } traits::push_back::apply(range, point); - // If a point is equal, or forming a spike, remove the pen-ultimate point because this one caused the spike. - // If so, the now-new-pen-ultimate point can again cause a spike (possibly at a corner). So keep doing this. - // Besides spikes it will also avoid duplicates. + // If a point is equal, or forming a spike, remove the pen-ultimate point + // because this one caused the spike. + // If so, the now-new-pen-ultimate point can again cause a spike + // (possibly at a corner). So keep doing this. + // Besides spikes it will also avoid adding duplicates. while(boost::size(range) >= 3 - && point_is_spike_or_equal(point, *(boost::end(range) - 3), *(boost::end(range) - 2))) + && point_is_spike_or_equal(point, + *(boost::end(range) - 3), + *(boost::end(range) - 2), + robust_policy)) { // Use the Concept/traits, so resize and append again traits::resize::apply(range, boost::size(range) - 2); traits::push_back::apply(range, point); } +} - // There might still be one duplicate not catched by the condition above - if (boost::size(range) == 2 - && geometry::detail::equals::equals_point_point(*boost::begin(range), point)) +template +inline void clean_closing_dups_and_spikes(Range& range, + RobustPolicy const& robust_policy) +{ + int const minsize + = core_detail::closure::minimum_ring_size + < + geometry::closure::value + >::value; + + if (boost::size(range) <= minsize) { - traits::clear::apply(range); - traits::push_back::apply(range, point); + return; } + + typedef typename boost::range_iterator::type iterator_type; + const bool closed = geometry::closure::value == geometry::closed; + bool found = false; + do + { + found = false; + iterator_type first = boost::begin(range); + iterator_type second = first + 1; + iterator_type ultimate = boost::end(range) - 1; + if (closed) + { + ultimate--; + } + + // Check if closing point is a spike (this is so if the second point is + // considered as a spike w.r.t. the last segment) + if (point_is_spike_or_equal(*second, *ultimate, *first, robust_policy)) + { + range.erase(first); + if (closed) + { + // Remove closing last point + traits::resize::apply(range, boost::size(range) - 1); + // Add new closing point + traits::push_back::apply(range, *boost::begin(range)); + } + found = true; + } + } while(found && boost::size(range) > minsize); } diff --git a/include/boost/geometry/algorithms/detail/overlay/backtrack_check_si.hpp b/include/boost/geometry/algorithms/detail/overlay/backtrack_check_si.hpp index 580fe431a..90901dee7 100644 --- a/include/boost/geometry/algorithms/detail/overlay/backtrack_check_si.hpp +++ b/include/boost/geometry/algorithms/detail/overlay/backtrack_check_si.hpp @@ -79,14 +79,14 @@ class backtrack_check_self_intersections public : typedef state state_type; - template + template static inline void apply(std::size_t size_at_start, - Rings& rings, typename boost::range_value::type& ring, + Rings& rings, Ring& ring, Turns& turns, Operation& operation, std::string const& , Geometry1 const& geometry1, Geometry2 const& geometry2, - RescalePolicy const& rescale_policy, + RobustPolicy const& robust_policy, state_type& state ) { @@ -96,8 +96,8 @@ public : if (! state.m_checked) { state.m_checked = true; - has_self_intersections(geometry1, rescale_policy); - has_self_intersections(geometry2, rescale_policy); + has_self_intersections(geometry1, robust_policy); + has_self_intersections(geometry2, robust_policy); } // Make bad output clean diff --git a/include/boost/geometry/algorithms/detail/overlay/calculate_distance_policy.hpp b/include/boost/geometry/algorithms/detail/overlay/calculate_distance_policy.hpp deleted file mode 100644 index 1c8bba65f..000000000 --- a/include/boost/geometry/algorithms/detail/overlay/calculate_distance_policy.hpp +++ /dev/null @@ -1,64 +0,0 @@ -// Boost.Geometry (aka GGL, Generic Geometry Library) - -// Copyright (c) 2007-2012 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_CALCULATE_DISTANCE_POLICY_HPP -#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_CALCULATE_DISTANCE_POLICY_HPP - - -#include - - -namespace boost { namespace geometry -{ - - -#ifndef DOXYGEN_NO_DETAIL -namespace detail { namespace overlay -{ - - -/*! - \brief Policy calculating distance - \details get_turn_info has an optional policy to get some - extra information. - This policy calculates the distance (using default distance strategy) - */ -struct calculate_distance_policy -{ - static bool const include_no_turn = false; - static bool const include_degenerate = false; - static bool const include_opposite = false; - - template - < - typename Info, - typename Point1, - typename Point2, - typename IntersectionInfo, - typename DirInfo - > - static inline void apply(Info& info, Point1 const& p1, Point2 const& p2, - IntersectionInfo const&, DirInfo const&) - { - info.operations[0].enriched.distance - = geometry::comparable_distance(info.point, p1); - info.operations[1].enriched.distance - = geometry::comparable_distance(info.point, p2); - } - -}; - - -}} // namespace detail::overlay -#endif //DOXYGEN_NO_DETAIL - - -}} // namespace boost::geometry - - -#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_CALCULATE_DISTANCE_POLICY_HPP diff --git a/include/boost/geometry/algorithms/detail/overlay/copy_segments.hpp b/include/boost/geometry/algorithms/detail/overlay/copy_segments.hpp index 8d487d599..f2306d4d9 100644 --- a/include/boost/geometry/algorithms/detail/overlay/copy_segments.hpp +++ b/include/boost/geometry/algorithms/detail/overlay/copy_segments.hpp @@ -22,6 +22,7 @@ #include #include #include +#include #include #include #include @@ -38,34 +39,37 @@ namespace detail { namespace copy_segments { -template -< - typename Ring, - bool Reverse, - typename SegmentIdentifier, - typename RangeOut -> +template struct copy_segments_ring { - typedef typename closeable_view + template + < + typename Ring, + typename SegmentIdentifier, + typename RobustPolicy, + typename RangeOut + > + static inline void apply(Ring const& ring, + SegmentIdentifier const& seg_id, int to_index, + RobustPolicy const& robust_policy, + RangeOut& current_output) + { + typedef typename closeable_view < Ring const, closure::value >::type cview_type; - typedef typename reversible_view + typedef typename reversible_view < cview_type const, Reverse ? iterate_reverse : iterate_forward >::type rview_type; - typedef typename boost::range_iterator::type iterator; - typedef geometry::ever_circling_iterator ec_iterator; + typedef typename boost::range_iterator::type iterator; + typedef geometry::ever_circling_iterator ec_iterator; + - static inline void apply(Ring const& ring, - SegmentIdentifier const& seg_id, int to_index, - RangeOut& current_output) - { cview_type cview(ring); rview_type view(cview); @@ -93,27 +97,27 @@ struct copy_segments_ring for (size_type i = 0; i < count; ++i, ++it) { - detail::overlay::append_no_dups_or_spikes(current_output, *it); + detail::overlay::append_no_dups_or_spikes(current_output, *it, robust_policy); } } }; -template -< - typename LineString, - bool Reverse, - typename SegmentIdentifier, - typename RangeOut -> +template struct copy_segments_linestring { - - typedef typename boost::range_iterator::type iterator; - + template + < + typename LineString, + typename SegmentIdentifier, + typename RobustPolicy, + typename RangeOut + > static inline void apply(LineString const& ls, SegmentIdentifier const& seg_id, int to_index, + RobustPolicy const& robust_policy, RangeOut& current_output) { + typedef typename boost::range_iterator::type iterator; int const from_index = seg_id.segment_index + 1; // Sanity check @@ -129,54 +133,54 @@ struct copy_segments_linestring for (size_type i = 0; i < count; ++i, ++it) { - detail::overlay::append_no_dups_or_spikes(current_output, *it); + detail::overlay::append_no_dups_or_spikes(current_output, *it, + robust_policy); } } }; -template -< - typename Polygon, - bool Reverse, - typename SegmentIdentifier, - typename RangeOut -> +template struct copy_segments_polygon { + template + < + typename Polygon, + typename SegmentIdentifier, + typename RobustPolicy, + typename RangeOut + > static inline void apply(Polygon const& polygon, SegmentIdentifier const& seg_id, int to_index, + RobustPolicy const& robust_policy, RangeOut& current_output) { // Call ring-version with the right ring - copy_segments_ring - < - typename geometry::ring_type::type, - Reverse, - SegmentIdentifier, - RangeOut - >::apply - ( - seg_id.ring_index < 0 - ? geometry::exterior_ring(polygon) - : geometry::interior_rings(polygon)[seg_id.ring_index], - seg_id, to_index, - current_output - ); + copy_segments_ring::apply + ( + seg_id.ring_index < 0 + ? geometry::exterior_ring(polygon) + : geometry::interior_rings(polygon)[seg_id.ring_index], + seg_id, to_index, + robust_policy, + current_output + ); } }; -template -< - typename Box, - bool Reverse, - typename SegmentIdentifier, - typename RangeOut -> +template struct copy_segments_box { + template + < + typename Box, + typename SegmentIdentifier, + typename RobustPolicy, + typename RangeOut + > static inline void apply(Box const& box, SegmentIdentifier const& seg_id, int to_index, + RobustPolicy const& robust_policy, RangeOut& current_output) { int index = seg_id.segment_index + 1; @@ -195,7 +199,8 @@ struct copy_segments_box // (see comments in ring-version) for (int i = 0; i < count; i++, index++) { - detail::overlay::append_no_dups_or_spikes(current_output, bp[index % 5]); + detail::overlay::append_no_dups_or_spikes(current_output, + bp[index % 5], robust_policy); } } @@ -213,80 +218,33 @@ namespace dispatch template < typename Tag, - typename GeometryIn, - bool Reverse, - typename SegmentIdentifier, - typename RangeOut + bool Reverse > -struct copy_segments -{ - BOOST_MPL_ASSERT_MSG - ( - false, NOT_OR_NOT_YET_IMPLEMENTED_FOR_THIS_GEOMETRY_TYPE - , (types) - ); -}; - - -template -< - typename Ring, - bool Reverse, - typename SegmentIdentifier, - typename RangeOut -> -struct copy_segments - : detail::copy_segments::copy_segments_ring - < - Ring, Reverse, SegmentIdentifier, RangeOut - > +struct copy_segments : not_implemented {}; - -template -< - typename LineString, - bool Reverse, - typename SegmentIdentifier, - typename RangeOut -> -struct copy_segments - : detail::copy_segments::copy_segments_linestring - < - LineString, Reverse, SegmentIdentifier, RangeOut - > -{}; - -template -< - typename Polygon, - bool Reverse, - typename SegmentIdentifier, - typename RangeOut -> -struct copy_segments - : detail::copy_segments::copy_segments_polygon - < - Polygon, Reverse, SegmentIdentifier, RangeOut - > +template +struct copy_segments + : detail::copy_segments::copy_segments_ring {}; -template -< - typename Box, - bool Reverse, - typename SegmentIdentifier, - typename RangeOut -> -struct copy_segments - : detail::copy_segments::copy_segments_box - < - Box, Reverse, SegmentIdentifier, RangeOut - > +template +struct copy_segments + : detail::copy_segments::copy_segments_linestring {}; +template +struct copy_segments + : detail::copy_segments::copy_segments_polygon +{}; + + +template +struct copy_segments + : detail::copy_segments::copy_segments_box +{}; } // namespace dispatch @@ -303,10 +261,12 @@ template bool Reverse, typename Geometry, typename SegmentIdentifier, + typename RobustPolicy, typename RangeOut > inline void copy_segments(Geometry const& geometry, SegmentIdentifier const& seg_id, int to_index, + RobustPolicy const& robust_policy, RangeOut& range_out) { concept::check(); @@ -314,11 +274,8 @@ inline void copy_segments(Geometry const& geometry, dispatch::copy_segments < typename tag::type, - Geometry, - Reverse, - SegmentIdentifier, - RangeOut - >::apply(geometry, seg_id, to_index, range_out); + Reverse + >::apply(geometry, seg_id, to_index, robust_policy, range_out); } diff --git a/include/boost/geometry/algorithms/detail/overlay/enrich_intersection_points.hpp b/include/boost/geometry/algorithms/detail/overlay/enrich_intersection_points.hpp index 6cf7d920d..5a7ad53a5 100644 --- a/include/boost/geometry/algorithms/detail/overlay/enrich_intersection_points.hpp +++ b/include/boost/geometry/algorithms/detail/overlay/enrich_intersection_points.hpp @@ -30,6 +30,7 @@ #include #include #include +#include #ifdef BOOST_GEOMETRY_DEBUG_ENRICH # include #endif @@ -79,9 +80,9 @@ template bool Reverse1, bool Reverse2, typename Strategy > -struct sort_on_segment_and_distance +struct sort_on_segment_and_ratio { - inline sort_on_segment_and_distance(TurnPoints const& turn_points + inline sort_on_segment_and_ratio(TurnPoints const& turn_points , Geometry1 const& geometry1 , Geometry2 const& geometry2 , Strategy const& strategy @@ -104,7 +105,7 @@ private : typedef model::point < - typename geometry::robust_type + typename detail::robust_type < typename select_coordinate_type::type >::type, @@ -128,7 +129,7 @@ private : geometry::copy_segment_points(m_geometry1, m_geometry2, right.subject.other_id, si, sj); - geometry::zoom_to_robust(pi, pj, ri, rj, si, sj, + detail::zoom_to_robust(pi, pj, ri, rj, si, sj, pi_rob, pj_rob, ri_rob, rj_rob, si_rob, sj_rob); } @@ -157,9 +158,7 @@ public : if (sl == sr) { // Both left and right are located on the SAME segment. - typedef typename geometry::coordinate_type::type coordinate_type; - coordinate_type diff = geometry::math::abs(left.subject.enriched.distance - right.subject.enriched.distance); - if (diff < geometry::math::relaxed_epsilon(10)) + if (left.subject.fraction == right.subject.fraction) { // First check "real" intersection (crosses) // -> distance zero due to precision, solve it by sorting @@ -173,13 +172,12 @@ public : // Indicate that this is necessary. *m_clustered = true; - return left.subject.enriched.distance < right.subject.enriched.distance; + return left.subject.fraction < right.subject.fraction; } } return sl == sr - ? left.subject.enriched.distance < right.subject.enriched.distance + ? left.subject.fraction < right.subject.fraction : sl < sr; - } }; @@ -217,14 +215,14 @@ template typename Container, typename TurnPoints, typename Geometry1, typename Geometry2, - typename RescalePolicy, + typename RobustPolicy, typename Strategy > inline void enrich_sort(Container& operations, TurnPoints& turn_points, operation_type for_operation, Geometry1 const& geometry1, Geometry2 const& geometry2, - RescalePolicy const& rescale_policy, + RobustPolicy const& robust_policy, Strategy const& strategy) { typedef typename IndexType::type operations_type; @@ -232,7 +230,7 @@ inline void enrich_sort(Container& operations, bool clustered = false; std::sort(boost::begin(operations), boost::end(operations), - sort_on_segment_and_distance + sort_on_segment_and_ratio < TurnPoints, IndexType, @@ -262,8 +260,7 @@ inline void enrich_sort(Container& operations, if (prev_op.seg_id == op.seg_id && (turn_points[prev->index].method != method_crosses || turn_points[it->index].method != method_crosses) - && geometry::math::equals(prev_op.enriched.distance, - op.enriched.distance)) + && prev_op.fraction == op.fraction) { if (begin_cluster == boost::end(operations)) { @@ -273,14 +270,14 @@ inline void enrich_sort(Container& operations, else if (begin_cluster != boost::end(operations)) { handle_cluster(begin_cluster, it, turn_points, - for_operation, geometry1, geometry2, rescale_policy, strategy); + for_operation, geometry1, geometry2, robust_policy, strategy); begin_cluster = boost::end(operations); } } if (begin_cluster != boost::end(operations)) { handle_cluster(begin_cluster, it, turn_points, - for_operation, geometry1, geometry2, rescale_policy, strategy); + for_operation, geometry1, geometry2, robust_policy, strategy); } } @@ -370,7 +367,7 @@ inline void enrich_assign(Container& operations, std::cout << it->index << " meth: " << method_char(turn_points[it->index].method) << " seg: " << op.seg_id - << " dst: " << boost::numeric_cast(op.enriched.distance) + << " dst: " << op.fraction // needs define << " op: " << operation_char(turn_points[it->index].operations[0].operation) << operation_char(turn_points[it->index].operations[1].operation) << " dsc: " << (turn_points[it->index].discarded ? "T" : "F") @@ -453,13 +450,13 @@ template bool Reverse1, bool Reverse2, typename TurnPoints, typename Geometry1, typename Geometry2, - typename RescalePolicy, + typename RobustPolicy, typename Strategy > inline void enrich_intersection_points(TurnPoints& turn_points, detail::overlay::operation_type for_operation, Geometry1 const& geometry1, Geometry2 const& geometry2, - RescalePolicy const& rescale_policy, + RobustPolicy const& robust_policy, Strategy const& strategy) { typedef typename boost::range_value::type turn_point_type; @@ -514,7 +511,7 @@ inline void enrich_intersection_points(TurnPoints& turn_points, << mit->first << std::endl; #endif detail::overlay::enrich_sort(mit->second, turn_points, for_operation, - geometry1, geometry2, rescale_policy, strategy); + geometry1, geometry2, robust_policy, strategy); } for (typename mapped_vector_type::iterator mit diff --git a/include/boost/geometry/algorithms/detail/overlay/enrichment_info.hpp b/include/boost/geometry/algorithms/detail/overlay/enrichment_info.hpp index d92a0a969..6668c9924 100644 --- a/include/boost/geometry/algorithms/detail/overlay/enrichment_info.hpp +++ b/include/boost/geometry/algorithms/detail/overlay/enrichment_info.hpp @@ -10,9 +10,6 @@ #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_ENRICHMENT_INFO_HPP -#include - - namespace boost { namespace geometry { @@ -31,24 +28,10 @@ namespace detail { namespace overlay template struct enrichment_info { - typedef typename strategy::distance::services::return_type - < - typename strategy::distance::services::comparable_type - < - typename strategy::distance::services::default_strategy - < - point_tag, - P - >::type - >::type, - P, P - >::type distance_type; - inline enrichment_info() : travels_to_vertex_index(-1) , travels_to_ip_index(-1) , next_ip_index(-1) - , distance(distance_type()) {} // vertex to which is free travel after this IP, @@ -61,8 +44,6 @@ struct enrichment_info // index of next IP on this segment, -1 if there is no one int next_ip_index; - - distance_type distance; // distance-measurement from segment.first to IP }; diff --git a/include/boost/geometry/algorithms/detail/overlay/follow.hpp b/include/boost/geometry/algorithms/detail/overlay/follow.hpp index 2eb5aa93d..38dc05119 100644 --- a/include/boost/geometry/algorithms/detail/overlay/follow.hpp +++ b/include/boost/geometry/algorithms/detail/overlay/follow.hpp @@ -157,15 +157,19 @@ struct action_selector typename LineStringOut, typename LineString, typename Point, - typename Operation + typename Operation, + typename RobustPolicy > static inline void enter(LineStringOut& current_piece, LineString const& , segment_identifier& segment_id, int , Point const& point, - Operation const& operation, OutputIterator& ) + Operation const& operation, + RobustPolicy const& , + OutputIterator& ) { // On enter, append the intersection point and remember starting point + // TODO: we don't check on spikes for linestrings (?). Consider this. detail::overlay::append_no_duplicates(current_piece, point); segment_id = operation.seg_id; } @@ -176,17 +180,20 @@ struct action_selector typename LineStringOut, typename LineString, typename Point, - typename Operation + typename Operation, + typename RobustPolicy > static inline void leave(LineStringOut& current_piece, LineString const& linestring, segment_identifier& segment_id, int index, Point const& point, - Operation const& , OutputIterator& out) + Operation const& , + RobustPolicy const& robust_policy, + OutputIterator& out) { // On leave, copy all segments from starting point, append the intersection point // and add the output piece - geometry::copy_segments(linestring, segment_id, index, current_piece); + geometry::copy_segments(linestring, segment_id, index, robust_policy, current_piece); detail::overlay::append_no_duplicates(current_piece, point); if (::boost::size(current_piece) > 1) { @@ -225,8 +232,15 @@ struct action_selector return entered; } - template - static inline bool included(Point const& point, Geometry const& geometry) + template + < + typename Point, + typename Geometry, + typename RobustPolicy + > + static inline bool included(Point const& point, + Geometry const& geometry, + RobustPolicy const& ) { return geometry::covered_by(point, geometry); } @@ -245,16 +259,19 @@ struct action_selector typename LineStringOut, typename LineString, typename Point, - typename Operation + typename Operation, + typename RobustPolicy > static inline void enter(LineStringOut& current_piece, LineString const& linestring, segment_identifier& segment_id, int index, Point const& point, - Operation const& operation, OutputIterator& out) + Operation const& operation, + RobustPolicy const& robust_policy, + OutputIterator& out) { normal_action::leave(current_piece, linestring, segment_id, index, - point, operation, out); + point, operation, robust_policy, out); } template @@ -263,16 +280,19 @@ struct action_selector typename LineStringOut, typename LineString, typename Point, - typename Operation + typename Operation, + typename RobustPolicy > static inline void leave(LineStringOut& current_piece, LineString const& linestring, segment_identifier& segment_id, int index, Point const& point, - Operation const& operation, OutputIterator& out) + Operation const& operation, + RobustPolicy const& robust_policy, + OutputIterator& out) { normal_action::enter(current_piece, linestring, segment_id, index, - point, operation, out); + point, operation, robust_policy, out); } template @@ -296,10 +316,17 @@ struct action_selector return ! normal_action::is_entered(entered); } - template - static inline bool included(Point const& point, Geometry const& geometry) + template + < + typename Point, + typename Geometry, + typename RobustPolicy + > + static inline bool included(Point const& point, + Geometry const& geometry, + RobustPolicy const& robust_policy) { - return ! normal_action::included(point, geometry); + return ! normal_action::included(point, geometry, robust_policy); } }; @@ -349,9 +376,9 @@ class follow inline bool use_distance(Turn const& left, Turn const& right) const { - return geometry::math::equals(left.operations[0].enriched.distance, right.operations[0].enriched.distance) + return left.operations[0].fraction == right.operations[0].fraction ? use_operation(left, right) - : left.operations[0].enriched.distance < right.operations[0].enriched.distance + : left.operations[0].fraction < right.operations[0].fraction ; } @@ -372,16 +399,30 @@ class follow public : - template - static inline bool included(Point const& point, Geometry const& geometry) + template + < + typename Point, + typename Geometry, + typename RobustPolicy + > + static inline bool included(Point const& point, + Geometry const& geometry, + RobustPolicy const& robust_policy) { - return following::action_selector::included(point, geometry); + return following::action_selector::included(point, geometry, robust_policy); } - template + template + < + typename Turns, + typename OutputIterator, + typename RobustPolicy + > static inline OutputIterator apply(LineString const& linestring, Polygon const& polygon, detail::overlay::operation_type , // TODO: this parameter might be redundant - Turns& turns, OutputIterator out) + Turns& turns, + RobustPolicy const& robust_policy, + OutputIterator out) { typedef typename boost::range_iterator::type turn_iterator; typedef typename boost::range_value::type turn_type; @@ -423,14 +464,20 @@ public : debug_traverse(*it, *iit, "-> Entering"); entered = true; - action::enter(current_piece, linestring, current_segment_id, iit->seg_id.segment_index, it->point, *iit, out); + action::enter(current_piece, linestring, current_segment_id, + iit->seg_id.segment_index, it->point, *iit, + robust_policy, + out); } else if (following::is_leaving(*it, *iit, entered, first, linestring, polygon)) { debug_traverse(*it, *iit, "-> Leaving"); entered = false; - action::leave(current_piece, linestring, current_segment_id, iit->seg_id.segment_index, it->point, *iit, out); + action::leave(current_piece, linestring, current_segment_id, + iit->seg_id.segment_index, it->point, *iit, + robust_policy, + out); } first = false; } @@ -439,6 +486,7 @@ public : { geometry::copy_segments(linestring, current_segment_id, boost::size(linestring) - 1, + robust_policy, current_piece); } diff --git a/include/boost/geometry/algorithms/detail/overlay/follow_linear_linear.hpp b/include/boost/geometry/algorithms/detail/overlay/follow_linear_linear.hpp index b90214d49..c009df00d 100644 --- a/include/boost/geometry/algorithms/detail/overlay/follow_linear_linear.hpp +++ b/include/boost/geometry/algorithms/detail/overlay/follow_linear_linear.hpp @@ -11,6 +11,7 @@ #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_FOLLOW_LINEAR_LINEAR_HPP #include +#include #include #include @@ -123,7 +124,7 @@ static inline bool is_isolated_point(Turn const& turn, return false; } - if ( turn.method == method_collinear ) + if ( turn.method == method_none ) { BOOST_ASSERT( operation.operation == operation_continue ); return true; @@ -184,13 +185,16 @@ protected: static inline OutputIterator process_turn(TurnIterator it, TurnOperationIterator op_it, - bool& first, bool& entered, + bool& entered, std::size_t& enter_count, Linestring const& linestring, LinestringOut& current_piece, SegmentIdentifier& current_segment_id, OutputIterator oit) { + // We don't rescale linear/linear + detail::no_rescale_policy robust_policy; + if ( is_entering(*it, *op_it) ) { #ifdef GEOMETRY_TEST_DEBUG @@ -203,7 +207,7 @@ protected: action::enter(current_piece, linestring, current_segment_id, op_it->seg_id.segment_index, - it->point, *op_it, oit); + it->point, *op_it, robust_policy, oit); } ++enter_count; } @@ -220,7 +224,7 @@ protected: action::leave(current_piece, linestring, current_segment_id, op_it->seg_id.segment_index, - it->point, *op_it, oit); + it->point, *op_it, robust_policy, oit); } } else if ( FollowIsolatedPoints @@ -244,7 +248,6 @@ protected: entered = true; } - first = false; return oit; } @@ -262,9 +265,13 @@ protected: { if ( action::is_entered(entered) ) { + // We don't rescale linear/linear + detail::no_rescale_policy robust_policy; + geometry::copy_segments(linestring, current_segment_id, boost::size(linestring) - 1, + robust_policy, current_piece); } @@ -281,17 +288,9 @@ public: template static inline OutputIterator apply(Linestring const& linestring, Linear const& linear, - TurnIterator start, TurnIterator beyond, + TurnIterator first, TurnIterator beyond, OutputIterator oit) { - typedef typename boost::range_iterator - < - typename std::iterator_traits - < - TurnIterator - >::value_type::container_type const - >::type turn_operation_iterator; - // Iterate through all intersection points (they are // ordered along the each line) @@ -299,15 +298,12 @@ public: geometry::segment_identifier current_segment_id(0, -1, -1, -1); bool entered = false; - bool first = true; std::size_t enter_count = 0; - for (TurnIterator it = start; it != beyond; ++it) + for (TurnIterator it = first; it != beyond; ++it) { - turn_operation_iterator op_it = boost::begin(it->operations); - - oit = process_turn(it, op_it, - first, entered, enter_count, + oit = process_turn(it, boost::begin(it->operations), + entered, enter_count, linestring, current_piece, current_segment_id, oit); @@ -365,8 +361,7 @@ protected: struct copy_linestrings_in_range { static inline OutputIt - apply(linestring_iterator begin, linestring_iterator beyond, - OutputIt oit) + apply(linestring_iterator, linestring_iterator, OutputIt oit) { return oit; } @@ -376,10 +371,10 @@ protected: struct copy_linestrings_in_range { static inline OutputIt - apply(linestring_iterator begin, linestring_iterator beyond, + apply(linestring_iterator first, linestring_iterator beyond, OutputIt oit) { - for (linestring_iterator ls_it = begin; ls_it != beyond; ++ls_it) + for (linestring_iterator ls_it = first; ls_it != beyond; ++ls_it) { LinestringOut line_out; geometry::convert(*ls_it, line_out); @@ -389,68 +384,80 @@ protected: } }; + template + static inline int get_multi_index(TurnIterator it) + { + return boost::begin(it->operations)->seg_id.multi_index; + } + + class has_other_multi_id + { + private: + int m_multi_id; + + public: + has_other_multi_id(int multi_id) + : m_multi_id(multi_id) {} + + template + bool operator()(Turn const& turn) const + { + return boost::begin(turn.operations)->seg_id.multi_index + != m_multi_id; + } + }; + public: template static inline OutputIterator apply(MultiLinestring const& multilinestring, Linear const& linear, - TurnIterator start, TurnIterator beyond, + TurnIterator first, TurnIterator beyond, OutputIterator oit) { - BOOST_ASSERT( start != beyond ); + BOOST_ASSERT( first != beyond ); typedef copy_linestrings_in_range < OutputIterator, OverlayType > copy_linestrings; - linestring_iterator ls_begin = boost::begin(multilinestring); - linestring_iterator ls_end = boost::end(multilinestring); + linestring_iterator ls_first = boost::begin(multilinestring); + linestring_iterator ls_beyond = boost::end(multilinestring); // Iterate through all intersection points (they are - // ordered along the each line) + // ordered along the each linestring) - int current_multi_id = - boost::begin(start->operations)->seg_id.multi_index; + int current_multi_id = get_multi_index(first); - oit = copy_linestrings::apply(ls_begin, - ls_begin + current_multi_id, + oit = copy_linestrings::apply(ls_first, + ls_first + current_multi_id, oit); - TurnIterator turns_begin = start, turns_end; + TurnIterator per_ls_next = first; do { - // find last turn with this multi-index - turns_end = turns_begin; - ++turns_end; - while ( turns_end != beyond ) - { - if ( boost::begin(turns_end->operations)->seg_id.multi_index - != current_multi_id ) - { - break; - } - ++turns_end; - } + TurnIterator per_ls_current = per_ls_next; - oit = Base::apply(*(boost::begin(multilinestring) - + current_multi_id), - linear, turns_begin, turns_end, oit); + // find turn with different multi-index + per_ls_next = std::find_if(per_ls_current, beyond, + has_other_multi_id(current_multi_id)); - int new_multi_id(0); - linestring_iterator ls_beyond_last = ls_end; - if ( turns_end != beyond ) + oit = Base::apply(*(ls_first + current_multi_id), + linear, per_ls_current, per_ls_next, oit); + + int next_multi_id(-1); + linestring_iterator ls_next = ls_beyond; + if ( per_ls_next != beyond ) { - new_multi_id = - boost::begin(turns_end->operations)->seg_id.multi_index; - ls_beyond_last = ls_begin + new_multi_id; + next_multi_id = get_multi_index(per_ls_next); + ls_next = ls_first + next_multi_id; } - oit = copy_linestrings::apply(ls_begin + current_multi_id + 1, - ls_beyond_last, + oit = copy_linestrings::apply(ls_first + current_multi_id + 1, + ls_next, oit); - current_multi_id = new_multi_id; - turns_begin = turns_end; + current_multi_id = next_multi_id; } - while ( turns_end != beyond ); + while ( per_ls_next != beyond ); return oit; } 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 7d882d003..3e27a0490 100644 --- a/include/boost/geometry/algorithms/detail/overlay/get_intersection_points.hpp +++ b/include/boost/geometry/algorithms/detail/overlay/get_intersection_points.hpp @@ -14,10 +14,10 @@ #include #include -#include #include +#include namespace boost { namespace geometry { @@ -36,35 +36,45 @@ template > struct get_turn_without_info { - typedef strategy_intersection - < - typename cs_tag::type, - Point1, - Point2, - typename TurnInfo::point_type - > si; - - typedef typename si::segment_intersection_strategy_type strategy; - - - - template + template static inline OutputIterator apply( Point1 const& pi, Point1 const& pj, Point1 const& pk, Point2 const& qi, Point2 const& qj, Point2 const& qk, bool /*is_p_first*/, bool /*is_p_last*/, bool /*is_q_first*/, bool /*is_q_last*/, TurnInfo const& , - RescalePolicy const& rescale_policy, + RobustPolicy const& robust_policy, OutputIterator out) { + typedef strategy_intersection + < + typename cs_tag::type, + Point1, + Point2, + typename TurnInfo::point_type, + RobustPolicy + > si; + + typedef typename si::segment_intersection_strategy_type strategy; + typedef model::referring_segment segment_type1; typedef model::referring_segment segment_type2; - segment_type1 p1(pi, pj), p2(pj, pk); - segment_type2 q1(qi, qj), q2(qj, qk); + segment_type1 p1(pi, pj); + segment_type2 q1(qi, qj); - // - typename strategy::return_type result = strategy::apply(p1, q1); + 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 strategy::return_type result + = strategy::apply(p1, q1, robust_policy, + pi_rob, pj_rob, qi_rob, qj_rob); for (std::size_t i = 0; i < result.template get<0>().count; i++) { @@ -88,10 +98,12 @@ template < typename Geometry1, typename Geometry2, + typename RobustPolicy, typename Turns > inline void get_intersection_points(Geometry1 const& geometry1, Geometry2 const& geometry2, + RobustPolicy const& robust_policy, Turns& turns) { concept::check_concepts_and_equal_dimensions(); @@ -108,7 +120,8 @@ inline void get_intersection_points(Geometry1 const& geometry1, typename cs_tag::type, Geometry1, Geometry2, - typename boost::range_value::type + typename point_type::type, // TODO from both + RobustPolicy >::segment_intersection_strategy_type segment_intersection_strategy_type; detail::get_turns::no_interrupt_policy interrupt_policy; @@ -135,7 +148,7 @@ inline void get_intersection_points(Geometry1 const& geometry1, >::type::apply( 0, geometry1, 1, geometry2, - detail::no_rescale_policy(), + robust_policy, turns, interrupt_policy); } diff --git a/include/boost/geometry/algorithms/detail/overlay/get_relative_order.hpp b/include/boost/geometry/algorithms/detail/overlay/get_relative_order.hpp index 522ef6838..50a14ea24 100644 --- a/include/boost/geometry/algorithms/detail/overlay/get_relative_order.hpp +++ b/include/boost/geometry/algorithms/detail/overlay/get_relative_order.hpp @@ -36,15 +36,10 @@ namespace detail { namespace overlay template struct get_relative_order { - typedef strategy_intersection + typedef typename strategy::side::services::default_strategy < - typename cs_tag::type, - Point1, - Point1, - Point1 - > si; - - typedef typename si::side_strategy_type strategy; + typename cs_tag::type + >::type strategy; template static inline int value_via_product(Point const& ti, Point const& tj, 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 c038eb00c..376f5a71f 100644 --- a/include/boost/geometry/algorithms/detail/overlay/get_turn_info.hpp +++ b/include/boost/geometry/algorithms/detail/overlay/get_turn_info.hpp @@ -16,9 +16,12 @@ #include #include +#include #include +#include + // Silence warning C4127: conditional expression is constant #if defined(_MSC_VER) @@ -57,13 +60,16 @@ public: namespace detail { namespace overlay { -template +template struct side_calculator { typedef boost::geometry::strategy::side::side_by_triangle<> side; // todo: get from coordinate system - inline side_calculator(Point1 const& pi, Point1 const& pj, Point1 const& pk, - Point2 const& qi, Point2 const& qj, Point2 const& qk) + inline side_calculator(Pi const& pi, Pj const& pj, Pk const& pk, + Qi const& qi, Qj const& qj, Qk const& qk) : m_pi(pi), m_pj(pj), m_pk(pk) , m_qi(qi), m_qj(qj), m_qk(qk) {} @@ -76,12 +82,12 @@ struct side_calculator inline int pk_wrt_q2() const { return side::apply(m_qj, m_qk, m_pk); } inline int qk_wrt_p2() const { return side::apply(m_pj, m_pk, m_qk); } - Point1 const& m_pi; - Point1 const& m_pj; - Point1 const& m_pk; - Point2 const& m_qi; - Point2 const& m_qj; - Point2 const& m_qk; + Pi const& m_pi; + Pj const& m_pj; + Pk const& m_pk; + Qi const& m_qi; + Qj const& m_qj; + Qk const& m_qk; }; struct base_turn_handler @@ -124,6 +130,26 @@ struct base_turn_handler { both(ti, condition ? operation_union : operation_intersection); } + + template + static inline void assign_point(TurnInfo& ti, + method_type method, + IntersectionInfo const& info, int index) + { + ti.method = method; + BOOST_ASSERT(index >= 0 && unsigned(index) < info.count); // TODO remove this + geometry::convert(info.intersections[index], ti.point); + ti.operations[0].fraction = info.fractions[index].robust_ra; + ti.operations[1].fraction = info.fractions[index].robust_rb; + } + + template + static inline int non_opposite_to_index(IntersectionInfo const& info) + { + return info.fractions[0].robust_rb < info.fractions[1].robust_rb + ? 1 : 0; + } + }; @@ -151,8 +177,7 @@ struct touch_interior : public base_turn_handler DirInfo const& dir_info, SidePolicy const& side) { - ti.method = method_touch_interior; - geometry::convert(intersection_info.intersections[0], ti.point); + assign_point(ti, method_touch_interior, intersection_info, 0); // Both segments of q touch segment p somewhere in its interior // 1) We know: if q comes from LEFT or RIGHT @@ -271,8 +296,7 @@ struct touch : public base_turn_handler DirInfo const& dir_info, SidePolicy const& side) { - ti.method = method_touch; - geometry::convert(intersection_info.intersections[0], ti.point); + assign_point(ti, method_touch, intersection_info, 0); int const side_qi_p1 = dir_info.sides.template get<1, 0>(); int const side_qk_p1 = side.qk_wrt_p1(); @@ -286,13 +310,9 @@ struct touch : public base_turn_handler int const side_pk_p = side.pk_wrt_p1(); int const side_qk_q = side.qk_wrt_q1(); - bool const both_continue = side_pk_p == 0 && side_qk_q == 0; - bool const robustness_issue_in_continue = both_continue && side_pk_q2 != 0; - bool const q_turns_left = side_qk_q == 1; bool const block_q = side_qk_p1 == 0 && ! same(side_qi_p1, side_qk_q) - && ! robustness_issue_in_continue ; // If Pk at same side as Qi/Qk @@ -464,13 +484,12 @@ struct equal : public base_turn_handler Point1 const& , Point1 const& , Point1 const& , Point2 const& , Point2 const& , Point2 const& , TurnInfo& ti, - IntersectionInfo const& intersection_info, - DirInfo const& , + IntersectionInfo const& info, + DirInfo const& , SidePolicy const& side) { - ti.method = method_equal; - // Copy the SECOND intersection point - geometry::convert(intersection_info.intersections[1], ti.point); + // Copy the intersection point in TO direction + assign_point(ti, method_equal, info, non_opposite_to_index(info)); int const side_pk_q2 = side.pk_wrt_q2(); int const side_pk_p = side.pk_wrt_p1(); @@ -538,7 +557,7 @@ struct equal_opposite : public base_turn_handler } for (unsigned int i = 0; i < intersection_info.count; i++) { - geometry::convert(intersection_info.intersections[i], tp.point); + assign_point(tp, method_none, intersection_info, i); AssignPolicy::apply(tp, pi, qi, intersection_info, dir_info); *out++ = tp; } @@ -596,12 +615,12 @@ struct collinear : public base_turn_handler Point1 const& , Point1 const& , Point1 const& , Point2 const& , Point2 const& , Point2 const& , TurnInfo& ti, - IntersectionInfo const& intersection_info, + IntersectionInfo const& info, DirInfo const& dir_info, SidePolicy const& side) { - ti.method = method_collinear; - geometry::convert(intersection_info.intersections[1], ti.point); + // Copy the intersection point in TO direction + assign_point(ti, method_collinear, info, non_opposite_to_index(info)); int const arrival = dir_info.arrival[0]; // Should not be 0, this is checked before @@ -616,9 +635,6 @@ struct collinear : public base_turn_handler : side_q ; - int const side_pk = side.pk_wrt_q1(); - int const side_qk = side.qk_wrt_p1(); - // See comments above, // resulting in a strange sort of mathematic rule here: // The arrival-info multiplied by the relevant side @@ -626,15 +642,7 @@ struct collinear : public base_turn_handler int const product = arrival * side_p_or_q; - // Robustness: side_p is supposed to be equal to side_pk (because p/q are collinear) - // and side_q to side_qk - bool const robustness_issue = side_pk != side_p || side_qk != side_q; - - if (robustness_issue) - { - handle_robustness(ti, arrival, side_p, side_q, side_pk, side_qk); - } - else if(product == 0) + if(product == 0) { both(ti, operation_continue); } @@ -644,37 +652,6 @@ struct collinear : public base_turn_handler } } - static inline void handle_robustness(TurnInfo& ti, int arrival, - int side_p, int side_q, int side_pk, int side_qk) - { - // We take the longer one, i.e. if q arrives in p (arrival == -1), - // then p exceeds q and we should take p for a union... - - bool use_p_for_union = arrival == -1; - - // ... unless one of the sides consistently directs to the other side - int const consistent_side_p = side_p == side_pk ? side_p : 0; - int const consistent_side_q = side_q == side_qk ? side_q : 0; - if (arrival == -1 && (consistent_side_p == -1 || consistent_side_q == 1)) - { - use_p_for_union = false; - } - if (arrival == 1 && (consistent_side_p == 1 || consistent_side_q == -1)) - { - use_p_for_union = true; - } - - //std::cout << "ROBUSTNESS -> Collinear " - // << " arr: " << arrival - // << " dir: " << side_p << " " << side_q - // << " rev: " << side_pk << " " << side_qk - // << " cst: " << cside_p << " " << cside_q - // << std::boolalpha << " " << use_p_for_union - // << std::endl; - - ui_else_iu(use_p_for_union, ti); - } - }; template @@ -716,21 +693,12 @@ private : typename IntersectionInfo > static inline bool set_tp(Point const& , Point const& , Point const& , int side_rk_r, - bool const handle_robustness, Point const& , Point const& , int side_rk_s, + bool const handle_robustness, + Point const& , Point const& , int side_rk_s, TurnInfo& tp, IntersectionInfo const& intersection_info) { - if (handle_robustness) - { - // For Robustness: also calculate rk w.r.t. the other line. Because they are collinear opposite, that direction should be the reverse of the first direction. - // If this is not the case, we make it all-collinear, so zero - if (side_rk_r != 0 && side_rk_r != -side_rk_s) - { -#ifdef BOOST_GEOMETRY_DEBUG_ROBUSTNESS - std::cout << "Robustness correction: " << side_rk_r << " / " << side_rk_s << std::endl; -#endif - side_rk_r = 0; - } - } + boost::ignore_unused_variable_warning(handle_robustness); + boost::ignore_unused_variable_warning(side_rk_s); operation_type blocked = operation_blocked; switch(side_rk_r) @@ -768,7 +736,7 @@ private : // If P arrives within Q, set info on P (which is done above, index=0), // this turn-info belongs to the second intersection point, index=1 // (see e.g. figure CLO1) - geometry::convert(intersection_info.intersections[1 - Index], tp.point); + assign_point(tp, method_collinear, intersection_info, 1 - Index); return true; } @@ -826,8 +794,6 @@ public: { TurnInfo tp = tp_model; - tp.method = method_collinear; - // If P arrives within Q, there is a turn dependent on P if ( dir_info.arrival[0] == 1 && is_pk_valid @@ -862,7 +828,7 @@ public: } for (unsigned int i = 0; i < intersection_info.count; i++) { - geometry::convert(intersection_info.intersections[i], tp.point); + assign_point(tp, method_collinear, intersection_info, i); AssignPolicy::apply(tp, pi, qi, intersection_info, dir_info); *out++ = tp; } @@ -893,8 +859,7 @@ struct crosses : public base_turn_handler IntersectionInfo const& intersection_info, DirInfo const& dir_info) { - ti.method = method_crosses; - geometry::convert(intersection_info.intersections[0], ti.point); + assign_point(ti, method_crosses, intersection_info, 0); // In all casees: // If Q crosses P from left to right @@ -908,14 +873,12 @@ struct crosses : public base_turn_handler } }; -template -struct only_convert +struct only_convert : public base_turn_handler { - template + template static inline void apply(TurnInfo& ti, IntersectionInfo const& intersection_info) { - ti.method = method_collinear; - geometry::convert(intersection_info.intersections[0], ti.point); + assign_point(ti, method_none, intersection_info, 0); // was collinear ti.operations[0].operation = operation_continue; ti.operations[1].operation = operation_continue; } @@ -972,7 +935,7 @@ struct get_turn_info typename Point1, typename Point2, typename TurnInfo, - typename RescalePolicy, + typename RobustPolicy, typename OutputIterator > static inline OutputIterator apply( @@ -981,27 +944,42 @@ struct get_turn_info bool /*is_p_first*/, bool /*is_p_last*/, bool /*is_q_first*/, bool /*is_q_last*/, TurnInfo const& tp_model, - RescalePolicy const& , // TODO: this will be used. rescale_policy, + RobustPolicy const& robust_policy, OutputIterator out) { + typedef typename geometry::robust_point_type + < + Point1, RobustPolicy + >::type robust_point_type; + + robust_point_type pi_rob, pj_rob, pk_rob, qi_rob, qj_rob, qk_rob; + geometry::recalculate(pi_rob, pi, robust_policy); + geometry::recalculate(pj_rob, pj, robust_policy); + geometry::recalculate(pk_rob, pk, robust_policy); + geometry::recalculate(qi_rob, qi, robust_policy); + geometry::recalculate(qj_rob, qj, robust_policy); + geometry::recalculate(qk_rob, qk, robust_policy); + typedef model::referring_segment segment_type1; typedef model::referring_segment segment_type2; - segment_type1 p1(pi, pj), p2(pj, pk); - segment_type2 q1(qi, qj), q2(qj, qk); + segment_type1 p1(pi, pj); + segment_type2 q1(qi, qj); - side_calculator side_calc(pi, pj, pk, qi, qj, qk); + side_calculator side_calc(pi_rob, pj_rob, pk_rob, qi_rob, qj_rob, qk_rob); typedef strategy_intersection < typename cs_tag::type, Point1, Point2, - typename TurnInfo::point_type + typename TurnInfo::point_type, + RobustPolicy > si; typedef typename si::segment_intersection_strategy_type strategy; - typename strategy::return_type result = strategy::apply(p1, q1); + typename strategy::return_type result = strategy::apply(p1, q1, + robust_policy, pi_rob, pj_rob, qi_rob, qj_rob); char const method = result.template get<1>().how; @@ -1017,7 +995,7 @@ struct get_turn_info if (AssignPolicy::include_no_turn && result.template get<0>().count > 0) { - only_convert::apply(tp, + only_convert::apply(tp, result.template get<0>()); AssignPolicy::apply(tp, pi, qi, result.template get<0>(), result.template get<1>()); *out++ = tp; @@ -1044,7 +1022,7 @@ struct get_turn_info else { // Swap p/q - side_calculator swapped_side_calc(qi, qj, qk, pi, pj, pk); + side_calculator swapped_side_calc(qi, qj, qk, pi, pj, pk); policy::template apply<1>(qi, qj, qk, pi, pj, pk, tp, result.template get<0>(), result.template get<1>(), swapped_side_calc); @@ -1132,7 +1110,7 @@ struct get_turn_info // degenerate points if (AssignPolicy::include_degenerate) { - only_convert::apply(tp, result.template get<0>()); + only_convert::apply(tp, result.template get<0>()); AssignPolicy::apply(tp, pi, qi, result.template get<0>(), result.template get<1>()); *out++ = tp; } diff --git a/include/boost/geometry/algorithms/detail/overlay/get_turn_info_for_endpoint.hpp b/include/boost/geometry/algorithms/detail/overlay/get_turn_info_for_endpoint.hpp index 78a1e715b..ceb291691 100644 --- a/include/boost/geometry/algorithms/detail/overlay/get_turn_info_for_endpoint.hpp +++ b/include/boost/geometry/algorithms/detail/overlay/get_turn_info_for_endpoint.hpp @@ -21,10 +21,13 @@ namespace boost { namespace geometry { #ifndef DOXYGEN_NO_DETAIL namespace detail { namespace overlay { +// TURN_OPERATION + enum turn_position { position_middle, position_front, position_back }; +template struct turn_operation_linear - : public turn_operation + : public turn_operation { turn_operation_linear() : position(position_middle) @@ -35,6 +38,154 @@ struct turn_operation_linear bool is_collinear; // valid only for Linear geometry }; +template +class intersection_info +{ + typedef typename strategy_intersection + < + typename cs_tag::type, + Point1, + Point2, + TurnPoint, + RobustPolicy + >::segment_intersection_strategy_type strategy; + +public: + typedef model::referring_segment segment_type1; + typedef model::referring_segment segment_type2; + typedef side_calculator side_calculator_type; + + typedef typename strategy::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 + + intersection_info(Point1 const& pi, Point1 const& pj, Point1 const& pk, + Point2 const& qi, Point2 const& qj, Point2 const& qk, + RobustPolicy const& robust_policy) + : m_result(strategy::apply(segment_type1(pi, pj), + segment_type2(qi, qj), + robust_policy)) + , m_side_calc(pi, pj, pk, qi, qj, qk) + , m_robust_policy(robust_policy) + {} + + inline Point1 const& pi() const { return m_side_calc.m_pi; } + inline Point1 const& pj() const { return m_side_calc.m_pj; } + inline Point1 const& pk() const { return m_side_calc.m_pk; } + + inline Point2 const& qi() const { return m_side_calc.m_qi; } + inline Point2 const& qj() const { return m_side_calc.m_qj; } + inline Point2 const& qk() const { return m_side_calc.m_qk; } + + inline side_calculator_type const& sides() const { return m_side_calc; } + 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>(); } + + // TODO: not it's more like is_spike_ip_p + inline bool is_spike_p() const + { + if ( m_side_calc.pk_wrt_p1() == 0 ) + { + if ( ! is_ip_j<0>() ) + return false; + + int const qk_p1 = m_side_calc.qk_wrt_p1(); + int const qk_p2 = m_side_calc.qk_wrt_p2(); + + if ( qk_p1 == -qk_p2 ) + { + if ( qk_p1 == 0 ) + { + return is_spike_of_collinear(pi(), pj(), pk()); + } + + return true; + } + } + + return false; + } + + // TODO: not it's more like is_spike_ip_q + inline bool is_spike_q() const + { + if ( m_side_calc.qk_wrt_q1() == 0 ) + { + if ( ! is_ip_j<1>() ) + return false; + + int const pk_q1 = m_side_calc.pk_wrt_q1(); + int const pk_q2 = m_side_calc.pk_wrt_q2(); + + if ( pk_q1 == -pk_q2 ) + { + if ( pk_q1 == 0 ) + { + return is_spike_of_collinear(qi(), qj(), qk()); + } + + return true; + } + } + + return false; + } + +private: + template + inline bool is_spike_of_collinear(Point const& i, Point const& j, Point const& k) const + { + typedef model::referring_segment seg_t; + + typedef strategy_intersection + < + typename cs_tag::type, Point, Point, Point, RobustPolicy + > si; + + typedef typename si::segment_intersection_strategy_type strategy; + + typename strategy::return_type result + = strategy::apply(seg_t(i, j), seg_t(j, k), m_robust_policy); + + return result.template get<0>().count == 2; + } + + template + bool is_ip_j() const + { + int arrival = d_info().arrival[OpId]; + bool same_dirs = d_info().dir_a == 0 && d_info().dir_b == 0; + + if ( same_dirs ) + { + if ( i_info().count == 2 ) + { + if ( ! d_info().opposite ) + { + return arrival != -1; + } + else + { + return arrival != -1; + } + } + else + { + return arrival == 0; + } + } + else + { + return arrival == 1; + } + } + + result_type m_result; + side_calculator_type m_side_calc; + RobustPolicy const& m_robust_policy; +}; + // SEGMENT_INTERSECTION RESULT // C H0 H1 A0 A1 O IP1 IP2 @@ -117,170 +268,99 @@ struct turn_operation_linear // |--------> 1 0 1 0 1 F u/x (P is vertical) // -template -struct get_turn_info_for_endpoint +class linear_intersections { - BOOST_STATIC_ASSERT(EnableFirst || EnableLast); - - template - static inline bool apply(Point1 const& pi, Point1 const& pj, Point1 const& pk, - Point2 const& qi, Point2 const& qj, Point2 const& qk, - bool is_p_first, bool is_p_last, - bool is_q_first, bool is_q_last, - TurnInfo const& tp_model, - IntersectionResult const& result, - method_type /*method*/, - OutputIterator out) +public: + template + linear_intersections(Point1 const& pi, + Point2 const& qi, + IntersectionResult const& result, + bool is_p_last, bool is_q_last) { - std::size_t ip_count = result.template get<0>().count; - // no intersection points - if ( ip_count == 0 ) - return false; - - int segment_index0 = tp_model.operations[0].seg_id.segment_index; - int segment_index1 = tp_model.operations[1].seg_id.segment_index; - BOOST_ASSERT(segment_index0 >= 0 && segment_index1 >= 0); - - if ( !is_p_first && !is_p_last && !is_q_first && !is_q_last ) - return false; - - operation_type p_operation0 = operation_none; - operation_type q_operation0 = operation_none; - operation_type p_operation1 = operation_none; - operation_type q_operation1 = operation_none; - bool p0i, p0j, q0i, q0j; // assign false? - bool p1i, p1j, q1i, q1j; // assign false? - - bool opposite = result.template get<1>().opposite; - - { - int p_how = result.template get<1>().how_a; - int q_how = result.template get<1>().how_b; - int p_arrival = result.template get<1>().arrival[0]; - int q_arrival = result.template get<1>().arrival[1]; - bool same_dirs = result.template get<1>().dir_a == 0 && result.template get<1>().dir_b == 0; - - handle_segment(is_p_first, is_p_last, p_how, p_arrival, - is_q_first, is_q_last, q_how, q_arrival, - opposite, ip_count, same_dirs, - result.template get<0>().intersections[0], - result.template get<0>().intersections[1], - p_operation0, q_operation0, p_operation1, q_operation1, - p0i, p0j, q0i, q0j, - p1i, p1j, q1i, q1j, - pi, pj, pk, qi, qj, qk); - } - - bool append0_last - = analyse_segment_and_assign_ip(pi, pj, pk, qi, qj, qk, - result.template get<0>().intersections[0], - is_p_first, is_p_last, is_q_first, is_q_last, - p0i, p0j, q0i, q0j, - p_operation0, q_operation0, - tp_model, result, out); - - // NOTE: opposite && ip_count == 1 may be true! - - // don't ignore only for collinear opposite - bool result_ignore_ip0 = append0_last && ( ip_count == 1 || !opposite ); - - if ( p_operation1 == operation_none ) - return result_ignore_ip0; - - bool append1_last - = analyse_segment_and_assign_ip(pi, pj, pk, qi, qj, qk, - result.template get<0>().intersections[1], - is_p_first, is_p_last, is_q_first, is_q_last, - p1i, p1j, q1i, q1j, - p_operation1, q_operation1, - tp_model, result, out); - - // don't ignore only for collinear opposite - bool result_ignore_ip1 = append1_last && !opposite /*&& ip_count == 2*/; - - return result_ignore_ip0 || result_ignore_ip1; - } - - template - static inline - void handle_segment(bool /*first_a*/, bool last_a, int how_a, int arrival_a, - bool /*first_b*/, bool last_b, int how_b, int arrival_b, - bool opposite, std::size_t ip_count, bool same_dirs/*collinear*/, - Point const& ip0, Point const& /*ip1*/, - operation_type & op0_a, operation_type & op0_b, - operation_type & op1_a, operation_type & op1_b, - bool & i0_a, bool & j0_a, bool & i0_b, bool & j0_b, - bool & i1_a, bool & j1_a, bool & i1_b, bool & j1_b, - Point1 const& pi, Point1 const& /*pj*/, Point1 const& /*pk*/, - Point2 const& qi, Point2 const& /*qj*/, Point2 const& /*qk*/) - { - namespace ov = overlay; - - i0_a = false; j0_a = false; i0_b = false; j0_b = false; - i1_a = false; j1_a = false; i1_b = false; j1_b = false; + int arrival_a = result.template get<1>().arrival[0]; + int arrival_b = result.template get<1>().arrival[1]; + bool same_dirs = result.template get<1>().dir_a == 0 + && result.template get<1>().dir_b == 0; if ( same_dirs ) { - if ( ip_count == 2 ) + if ( result.template get<0>().count == 2 ) { - BOOST_ASSERT( how_a == 0 && how_b == 0 ); - - if ( !opposite ) + if ( ! result.template get<1>().opposite ) { - op0_a = operation_intersection; - op0_b = operation_intersection; - op1_a = arrival_to_union_or_blocked(arrival_a, last_a); - op1_b = arrival_to_union_or_blocked(arrival_b, last_b); + ips[0].p_operation = operation_intersection; + ips[0].q_operation = operation_intersection; + ips[1].p_operation = union_or_blocked_same_dirs(arrival_a, is_p_last); + ips[1].q_operation = union_or_blocked_same_dirs(arrival_b, is_q_last); - i0_a = equals::equals_point_point(pi, ip0); - i0_b = equals::equals_point_point(qi, ip0); - j1_a = arrival_a != -1; - j1_b = arrival_b != -1; + ips[0].is_pi + = equals::equals_point_point( + pi, result.template get<0>().intersections[0]); + ips[0].is_qi + = equals::equals_point_point( + qi, result.template get<0>().intersections[0]); + ips[1].is_pj = arrival_a != -1; + ips[1].is_qj = arrival_b != -1; } else { - op0_a = operation_intersection; - op0_b = arrival_to_union_or_blocked(arrival_b, last_b); - op1_a = arrival_to_union_or_blocked(arrival_a, last_a); - op1_b = operation_intersection; + ips[0].p_operation = operation_intersection; + ips[0].q_operation = union_or_blocked_same_dirs(arrival_b, is_q_last); + ips[1].p_operation = union_or_blocked_same_dirs(arrival_a, is_p_last); + ips[1].q_operation = operation_intersection; - i0_a = arrival_b != 1; - j0_b = arrival_b != -1; - j1_a = arrival_a != -1; - i1_b = arrival_a != 1; + ips[0].is_pi = arrival_b != 1; + ips[0].is_qj = arrival_b != -1; + ips[1].is_pj = arrival_a != -1; + ips[1].is_qi = arrival_a != 1; } } else { - BOOST_ASSERT(ip_count == 1); - op0_a = arrival_to_union_or_blocked(arrival_a, last_a); - op0_b = arrival_to_union_or_blocked(arrival_b, last_b); + BOOST_ASSERT(result.template get<0>().count == 1); + ips[0].p_operation = union_or_blocked_same_dirs(arrival_a, is_p_last); + ips[0].q_operation = union_or_blocked_same_dirs(arrival_b, is_q_last); - i0_a = how_a == -1; - i0_b = how_b == -1; - j0_a = arrival_a == 0; - j0_b = arrival_b == 0; + ips[0].is_pi = arrival_a == -1; + ips[0].is_qi = arrival_b == -1; + ips[0].is_pj = arrival_a == 0; + ips[0].is_qj = arrival_b == 0; } } else { - op0_a = how_to_union_or_blocked(how_a, last_a); - op0_b = how_to_union_or_blocked(how_b, last_b); + ips[0].p_operation = union_or_blocked_different_dirs(arrival_a, is_p_last); + ips[0].q_operation = union_or_blocked_different_dirs(arrival_b, is_q_last); - i0_a = how_a == -1; - i0_b = how_b == -1; - j0_a = how_a == 1; - j0_b = how_b == 1; + ips[0].is_pi = arrival_a == -1; + ips[0].is_qi = arrival_b == -1; + ips[0].is_pj = arrival_a == 1; + ips[0].is_qj = arrival_b == 1; } } + struct ip_info + { + inline ip_info() + : p_operation(operation_none), q_operation(operation_none) + , is_pi(false), is_pj(false), is_qi(false), is_qj(false) + {} + + operation_type p_operation, q_operation; + bool is_pi, is_pj, is_qi, is_qj; + }; + + template + ip_info const& get() const + { + BOOST_STATIC_ASSERT(I < 2); + return ips[I]; + } + +private: + // only if collinear (same_dirs) - static inline operation_type arrival_to_union_or_blocked(int arrival, bool is_last) + static inline operation_type union_or_blocked_same_dirs(int arrival, bool is_last) { if ( arrival == 1 ) return operation_blocked; @@ -292,75 +372,171 @@ struct get_turn_info_for_endpoint } // only if not collinear (!same_dirs) - static inline operation_type how_to_union_or_blocked(int how, bool is_last) + static inline operation_type union_or_blocked_different_dirs(int arrival, bool is_last) { - if ( how == 1 ) + if ( arrival == 1 ) //return operation_blocked; return is_last ? operation_blocked : operation_union; else return operation_union; } + ip_info ips[2]; +}; + +template +struct get_turn_info_for_endpoint +{ + BOOST_STATIC_ASSERT(EnableFirst || EnableLast); + + template + static inline bool apply(Point1 const& pi, Point1 const& pj, Point1 const& pk, + Point2 const& qi, Point2 const& qj, Point2 const& qk, + bool is_p_first, bool is_p_last, + bool is_q_first, bool is_q_last, + TurnInfo const& tp_model, + IntersectionInfo const& inters, + method_type /*method*/, + OutputIterator out) + { + std::size_t ip_count = inters.i_info().count; + // no intersection points + if ( ip_count == 0 ) + return false; + + int segment_index0 = tp_model.operations[0].seg_id.segment_index; + int segment_index1 = tp_model.operations[1].seg_id.segment_index; + BOOST_ASSERT(segment_index0 >= 0 && segment_index1 >= 0); + + if ( !is_p_first && !is_p_last && !is_q_first && !is_q_last ) + return false; + + linear_intersections intersections(pi, qi, inters.result(), is_p_last, is_q_last); + + bool append0_last + = analyse_segment_and_assign_ip(pi, pj, pk, qi, qj, qk, + is_p_first, is_p_last, is_q_first, is_q_last, + intersections.template get<0>(), + tp_model, inters, 0, out); + + // NOTE: opposite && ip_count == 1 may be true! + bool opposite = inters.d_info().opposite; + + // don't ignore only for collinear opposite + bool result_ignore_ip0 = append0_last && ( ip_count == 1 || !opposite ); + + if ( intersections.template get<1>().p_operation == operation_none ) + return result_ignore_ip0; + + bool append1_last + = analyse_segment_and_assign_ip(pi, pj, pk, qi, qj, qk, + is_p_first, is_p_last, is_q_first, is_q_last, + intersections.template get<1>(), + tp_model, inters, 1, out); + + // don't ignore only for collinear opposite + bool result_ignore_ip1 = append1_last && !opposite /*&& ip_count == 2*/; + + return result_ignore_ip0 || result_ignore_ip1; + } + template static inline bool analyse_segment_and_assign_ip(Point1 const& pi, Point1 const& pj, Point1 const& pk, Point2 const& qi, Point2 const& qj, Point2 const& qk, - Point const& ip, bool is_p_first, bool is_p_last, bool is_q_first, bool is_q_last, - bool is_pi_ip, bool is_pj_ip, - bool is_qi_ip, bool is_qj_ip, - operation_type p_operation, - operation_type q_operation, + linear_intersections::ip_info const& ip_info, TurnInfo const& tp_model, - IntersectionResult const& result, + IntersectionInfo const& inters, + int ip_index, OutputIterator out) { #ifdef BOOST_GEOMETRY_DEBUG_GET_TURNS_LINEAR_LINEAR // may this give false positives for INTs? - BOOST_ASSERT(is_pi_ip == equals::equals_point_point(pi, ip)); - BOOST_ASSERT(is_qi_ip == equals::equals_point_point(qi, ip)); - BOOST_ASSERT(is_pj_ip == equals::equals_point_point(pj, ip)); - BOOST_ASSERT(is_qj_ip == equals::equals_point_point(qj, ip)); + typename IntersectionResult::point_type const& + inters_pt = result.template get<0>().intersections[ip_index]; + BOOST_ASSERT(ip_info.is_pi == equals::equals_point_point(pi, inters_pt)); + BOOST_ASSERT(ip_info.is_qi == equals::equals_point_point(qi, inters_pt)); + BOOST_ASSERT(ip_info.is_pj == equals::equals_point_point(pj, inters_pt)); + BOOST_ASSERT(ip_info.is_qj == equals::equals_point_point(qj, inters_pt)); #endif // TODO - calculate first/last only if needed - bool is_p_first_ip = is_p_first && is_pi_ip; - bool is_p_last_ip = is_p_last && is_pj_ip; - bool is_q_first_ip = is_q_first && is_qi_ip; - bool is_q_last_ip = is_q_last && is_qj_ip; + bool is_p_first_ip = is_p_first && ip_info.is_pi; + bool is_p_last_ip = is_p_last && ip_info.is_pj; + bool is_q_first_ip = is_q_first && ip_info.is_qi; + bool is_q_last_ip = is_q_last && ip_info.is_qj; bool append_first = EnableFirst && (is_p_first_ip || is_q_first_ip); bool append_last = EnableLast && (is_p_last_ip || is_q_last_ip); + operation_type p_operation = ip_info.p_operation; + operation_type q_operation = ip_info.q_operation; + if ( append_first || append_last ) { - bool handled = handle_internal(pi, pj, pk, qi, qj, qk, ip, + bool handled = handle_internal(pi, pj, pk, qi, qj, qk, is_p_first_ip, is_p_last_ip, is_q_first_ip, is_q_last_ip, - is_qi_ip, is_qj_ip, - tp_model, result, p_operation, q_operation); + ip_info.is_qi, ip_info.is_qj, + tp_model, inters.result(), ip_index, + p_operation, q_operation); if ( !handled ) { - handle_internal(qi, qj, qk, pi, pj, pk, ip, + handle_internal(qi, qj, qk, pi, pj, pk, is_q_first_ip, is_q_last_ip, is_p_first_ip, is_p_last_ip, - is_pi_ip, is_pj_ip, - tp_model, result, q_operation, p_operation); + ip_info.is_pi, ip_info.is_pj, + tp_model, inters.result(), ip_index, + q_operation, p_operation); } if ( p_operation != operation_none ) { - assign(pi, qi, result, ip, - endpoint_ip_method(is_pi_ip, is_pj_ip, is_qi_ip, is_qj_ip), - p_operation, q_operation, - ip_position(is_p_first_ip, is_p_last_ip), - ip_position(is_q_first_ip, is_q_last_ip), - tp_model, out); + method_type method = endpoint_ip_method(ip_info.is_pi, ip_info.is_pj, + ip_info.is_qi, ip_info.is_qj); + turn_position p_pos = ip_position(is_p_first_ip, is_p_last_ip); + turn_position q_pos = ip_position(is_q_first_ip, is_q_last_ip); + + // handle spikes + + // P is spike and should be handled + if ( !is_p_last + && ip_info.is_pj // this check is redundant (also in is_spike_p) but faster + && inters.i_info().count == 2 + && inters.is_spike_p() ) + { + assign(pi, qi, inters.result(), ip_index, method, operation_blocked, q_operation, + p_pos, q_pos, tp_model, out); + assign(pi, qi, inters.result(), ip_index, method, operation_intersection, q_operation, + p_pos, q_pos, tp_model, out); + } + // Q is spike and should be handled + else if ( !is_q_last + && ip_info.is_qj // this check is redundant (also in is_spike_q) but faster + && inters.i_info().count == 2 + && inters.is_spike_q() ) + { + assign(pi, qi, inters.result(), ip_index, method, p_operation, operation_blocked, + p_pos, q_pos, tp_model, out); + assign(pi, qi, inters.result(), ip_index, method, p_operation, operation_intersection, + p_pos, q_pos, tp_model, out); + } + // no spikes + else + { + assign(pi, qi, inters.result(), ip_index, method, p_operation, q_operation, + p_pos, q_pos, tp_model, out); + } } } @@ -372,21 +548,17 @@ struct get_turn_info_for_endpoint template static inline bool handle_internal(Point1 const& i1, Point1 const& j1, Point1 const& /*k1*/, Point2 const& i2, Point2 const& j2, Point2 const& k2, - Point const& ip, - bool first1, bool last1, - bool first2, bool last2, - bool ip_i2, bool ip_j2, - TurnInfo const& tp_model, - IntersectionResult const& result, + bool first1, bool last1, bool first2, bool last2, + bool ip_i2, bool ip_j2, TurnInfo const& tp_model, + IntersectionResult const& result, int ip_index, operation_type & op1, operation_type & op2) { - boost::ignore_unused_variable_warning(ip); + boost::ignore_unused_variable_warning(ip_index); boost::ignore_unused_variable_warning(tp_model); if ( !first2 && !last2 ) @@ -395,8 +567,10 @@ struct get_turn_info_for_endpoint { #ifdef BOOST_GEOMETRY_DEBUG_GET_TURNS_LINEAR_LINEAR // may this give false positives for INTs? - BOOST_ASSERT(ip_i2 == equals::equals_point_point(i2, ip)); - BOOST_ASSERT(ip_j2 == equals::equals_point_point(j2, ip)); + typename IntersectionResult::point_type const& + inters_pt = result.template get<0>().intersections[ip_index]; + BOOST_ASSERT(ip_i2 == equals::equals_point_point(i2, inters_pt)); + BOOST_ASSERT(ip_j2 == equals::equals_point_point(j2, inters_pt)); #endif if ( ip_i2 ) { @@ -407,10 +581,7 @@ struct get_turn_info_for_endpoint } else if ( ip_j2 ) { -// NOTE: this conversion may be problematic - Point1 i2_conv; - geometry::convert(i2, i2_conv); - side_calculator side_calc(i2_conv, i1, j1, i2, j2, k2); + side_calculator side_calc(i2, i1, j1, i2, j2, k2); std::pair operations = operations_of_equal(side_calc); @@ -441,8 +612,10 @@ struct get_turn_info_for_endpoint { #ifdef BOOST_GEOMETRY_DEBUG_GET_TURNS_LINEAR_LINEAR // may this give false positives for INTs? - BOOST_ASSERT(ip_i2 == equals::equals_point_point(i2, ip)); - BOOST_ASSERT(ip_j2 == equals::equals_point_point(j2, ip)); + typename IntersectionResult::point_type const& + inters_pt = result.template get<0>().intersections[ip_index]; + BOOST_ASSERT(ip_i2 == equals::equals_point_point(i2, inters_pt)); + BOOST_ASSERT(ip_j2 == equals::equals_point_point(j2, inters_pt)); #endif if ( ip_i2 ) { @@ -453,11 +626,7 @@ struct get_turn_info_for_endpoint } else if ( ip_j2 ) { -// NOTE: this conversion may be problematic - Point1 i2_conv; - geometry::convert(i2, i2_conv); - - side_calculator side_calc(i2_conv, j1, i1, i2, j2, k2); + side_calculator side_calc(i2, j1, i1, i2, j2, k2); std::pair operations = operations_of_equal(side_calc); @@ -507,12 +676,11 @@ struct get_turn_info_for_endpoint template static inline void assign(Point1 const& pi, Point2 const& qi, IntersectionResult const& result, - Point const& ip, + int ip_index, method_type method, operation_type op0, operation_type op1, turn_position pos0, turn_position pos1, @@ -520,8 +688,11 @@ struct get_turn_info_for_endpoint OutputIterator out) { TurnInfo tp = tp_model; - geometry::convert(ip, tp.point); - tp.method = method; + + //geometry::convert(ip, tp.point); + //tp.method = method; + base_turn_handler::assign_point(tp, method, result.template get<0>(), ip_index); + tp.operations[0].operation = op0; tp.operations[1].operation = op1; tp.operations[0].position = pos0; diff --git a/include/boost/geometry/algorithms/detail/overlay/get_turn_info_la.hpp b/include/boost/geometry/algorithms/detail/overlay/get_turn_info_la.hpp index 95a9e3a12..003bac689 100644 --- a/include/boost/geometry/algorithms/detail/overlay/get_turn_info_la.hpp +++ b/include/boost/geometry/algorithms/detail/overlay/get_turn_info_la.hpp @@ -28,12 +28,14 @@ namespace detail { namespace overlay { template struct get_turn_info_linear_areal { + static const bool handle_spikes = true; + template < typename Point1, typename Point2, typename TurnInfo, - typename RescalePolicy, + typename RobustPolicy, typename OutputIterator > static inline OutputIterator apply( @@ -42,29 +44,13 @@ struct get_turn_info_linear_areal bool is_p_first, bool is_p_last, bool is_q_first, bool is_q_last, TurnInfo const& tp_model, - RescalePolicy const& , // TODO: this will be used. rescale_policy, + RobustPolicy const& robust_policy, OutputIterator out) { - typedef model::referring_segment segment_type1; - typedef model::referring_segment segment_type2; - segment_type1 p1(pi, pj), p2(pj, pk); - segment_type2 q1(qi, qj), q2(qj, qk); + intersection_info + inters(pi, pj, pk, qi, qj, qk, robust_policy); - side_calculator side_calc(pi, pj, pk, qi, qj, qk); - - typedef strategy_intersection - < - typename cs_tag::type, - Point1, - Point2, - typename TurnInfo::point_type - > si; - - typedef typename si::segment_intersection_strategy_type strategy; - - typename strategy::return_type result = strategy::apply(p1, q1); - - char const method = result.template get<1>().how; + char const method = inters.d_info().how; // Copy, to copy possibly extended fields TurnInfo tp = tp_model; @@ -78,7 +64,7 @@ struct get_turn_info_linear_areal get_turn_info_for_endpoint( pi, pj, pk, qi, qj, qk, is_p_first, is_p_last, is_q_first, is_q_last, - tp_model, result, method_none, out); + tp_model, inters.result(), method_none, out); break; case 'd' : // disjoint: never do anything @@ -89,7 +75,7 @@ struct get_turn_info_linear_areal if ( get_turn_info_for_endpoint( pi, pj, pk, qi, qj, qk, is_p_first, is_p_last, is_q_first, is_q_last, - tp_model, result, method_touch_interior, out) ) + tp_model, inters.result(), method_touch_interior, out) ) { // do nothing } @@ -101,18 +87,18 @@ struct get_turn_info_linear_areal > policy; // If Q (1) arrives (1) - if (result.template get<1>().arrival[1] == 1) + if ( inters.d_info().arrival[1] == 1 ) { policy::template apply<0>(pi, pj, pk, qi, qj, qk, - tp, result.template get<0>(), result.template get<1>(), - side_calc); + tp, inters.i_info(), inters.d_info(), + inters.sides()); } else { // Swap p/q - side_calculator swapped_side_calc(qi, qj, qk, pi, pj, pk); + side_calculator swapped_side_calc(qi, qj, qk, pi, pj, pk); policy::template apply<1>(qi, qj, qk, pi, pj, pk, - tp, result.template get<0>(), result.template get<1>(), + tp, inters.i_info(), inters.d_info(), swapped_side_calc); } @@ -121,9 +107,16 @@ struct get_turn_info_linear_areal tp.operations[0].is_collinear = true; } - replace_method_and_operations_tm(tp.method, tp.operations[0].operation, tp.operations[1].operation); + replace_method_and_operations_tm(tp.method, + tp.operations[0].operation, + tp.operations[1].operation); - AssignPolicy::apply(tp, pi, qi, result.template get<0>(), result.template get<1>()); + // this function assumes that 'u' must be set for a spike + calculate_spike_operation(tp.operations[0].operation, + inters, is_p_last); + + AssignPolicy::apply(tp, pi, qi, inters.i_info(), inters.d_info()); + *out++ = tp; } } @@ -131,11 +124,11 @@ struct get_turn_info_linear_areal case 'i' : { crosses::apply(pi, pj, pk, qi, qj, qk, - tp, result.template get<0>(), result.template get<1>()); + tp, inters.i_info(), inters.d_info()); replace_operations_i(tp.operations[0].operation, tp.operations[1].operation); - AssignPolicy::apply(tp, pi, qi, result.template get<0>(), result.template get<1>()); + AssignPolicy::apply(tp, pi, qi, inters.i_info(), inters.d_info()); *out++ = tp; } break; @@ -145,24 +138,39 @@ struct get_turn_info_linear_areal if ( get_turn_info_for_endpoint( pi, pj, pk, qi, qj, qk, is_p_first, is_p_last, is_q_first, is_q_last, - tp_model, result, method_touch, out) ) + tp_model, inters.result(), method_touch, out) ) { // do nothing } else { touch::apply(pi, pj, pk, qi, qj, qk, - tp, result.template get<0>(), result.template get<1>(), side_calc); + tp, inters.i_info(), inters.d_info(), inters.sides()); if ( tp.operations[1].operation == operation_blocked ) { tp.operations[0].is_collinear = true; } - replace_method_and_operations_tm(tp.method, tp.operations[0].operation, tp.operations[1].operation); + replace_method_and_operations_tm(tp.method, + tp.operations[0].operation, + tp.operations[1].operation); - AssignPolicy::apply(tp, pi, qi, result.template get<0>(), result.template get<1>()); - *out++ = tp; + // this function assumes that 'u' must be set for a spike + bool ignore_spike + = calculate_spike_operation(tp.operations[0].operation, + inters, is_p_last); + +// TODO: move this into the append_xxx and call for each turn? + AssignPolicy::apply(tp, pi, qi, inters.i_info(), inters.d_info()); + + if ( ! handle_spikes + || ignore_spike + || ! append_opposite_spikes( // for 'i' or 'c' + tp, inters, is_p_last, is_q_last, out) ) + { + *out++ = tp; + } } } break; @@ -171,7 +179,7 @@ struct get_turn_info_linear_areal if ( get_turn_info_for_endpoint( pi, pj, pk, qi, qj, qk, is_p_first, is_p_last, is_q_first, is_q_last, - tp_model, result, method_equal, out) ) + tp_model, inters.result(), method_equal, out) ) { // do nothing } @@ -179,26 +187,26 @@ struct get_turn_info_linear_areal { tp.operations[0].is_collinear = true; - if ( ! result.template get<1>().opposite ) + if ( ! inters.d_info().opposite ) { // Both equal // or collinear-and-ending at intersection point equal::apply(pi, pj, pk, qi, qj, qk, - tp, result.template get<0>(), result.template get<1>(), side_calc); + tp, inters.i_info(), inters.d_info(), inters.sides()); replacer_of_method_and_operations_ec replacer(method_touch); replacer(tp.method, tp.operations[0].operation, tp.operations[1].operation); - // TODO: This isn't correct handling, hence commented out - /*spike_detector spike_detect(side_calc); - if ( tp.operations[0].operation == operation_union - && spike_detect.is_spike_p()) +// TODO: move this into the append_xxx and call for each turn? + AssignPolicy::apply(tp, pi, qi, inters.i_info(), inters.d_info()); + + // conditionally handle spikes + if ( ! handle_spikes + || ! append_collinear_spikes(tp, inters, is_p_last, is_q_last, + method_touch, append_equal, out) ) { - tp.operations[0].operation = operation_continue; - }*/ - - AssignPolicy::apply(tp, pi, qi, result.template get<0>(), result.template get<1>()); - *out++ = tp; + *out++ = tp; // no spikes + } } else { @@ -207,7 +215,7 @@ struct get_turn_info_linear_areal TurnInfo, AssignPolicy >::apply(pi, qi, - tp, out, result.template get<0>(), result.template get<1>()); + tp, out, inters.i_info(), inters.d_info()); } } } @@ -218,7 +226,7 @@ struct get_turn_info_linear_areal if ( get_turn_info_for_endpoint( pi, pj, pk, qi, qj, qk, is_p_first, is_p_last, is_q_first, is_q_last, - tp_model, result, method_collinear, out) ) + tp_model, inters.result(), method_collinear, out) ) { // do nothing } @@ -226,49 +234,67 @@ struct get_turn_info_linear_areal { tp.operations[0].is_collinear = true; - if (! result.template get<1>().opposite) + if ( ! inters.d_info().opposite ) { - if (result.template get<1>().arrival[0] == 0) + method_type method_replace = method_touch_interior; + append_version_c version = append_collinear; + + if ( inters.d_info().arrival[0] == 0 ) { // Collinear, but similar thus handled as equal equal::apply(pi, pj, pk, qi, qj, qk, - tp, result.template get<0>(), result.template get<1>(), side_calc); + tp, inters.i_info(), inters.d_info(), inters.sides()); - // TODO: This isn't correct handling, hence commented out - /*spike_detector spike_detect(side_calc); - if ( tp.operations[0].operation == operation_union - && spike_detect.is_spike_p()) - { - tp.operations[0].operation = operation_continue; - }*/ - - replacer_of_method_and_operations_ec replacer(method_touch); - replacer(tp.method, tp.operations[0].operation, tp.operations[1].operation); + method_replace = method_touch; + version = append_equal; } else { collinear::apply(pi, pj, pk, qi, qj, qk, - tp, result.template get<0>(), result.template get<1>(), side_calc); + tp, inters.i_info(), inters.d_info(), inters.sides()); - replacer_of_method_and_operations_ec replacer(method_touch_interior); - replacer(tp.method, tp.operations[0].operation, tp.operations[1].operation); + //method_replace = method_touch_interior; + //version = append_collinear; } - AssignPolicy::apply(tp, pi, qi, result.template get<0>(), result.template get<1>()); - *out++ = tp; + replacer_of_method_and_operations_ec replacer(method_replace); + replacer(tp.method, tp.operations[0].operation, tp.operations[1].operation); + +// TODO: move this into the append_xxx and call for each turn? + AssignPolicy::apply(tp, pi, qi, inters.i_info(), inters.d_info()); + + // conditionally handle spikes + if ( ! handle_spikes + || ! append_collinear_spikes(tp, inters, is_p_last, is_q_last, + method_replace, version, out) ) + { + // no spikes + *out++ = tp; + } } else { // Is this always 'm' ? replacer_of_method_and_operations_ec replacer(method_touch_interior); + // conditionally handle spikes + if ( handle_spikes ) + { + append_opposite_spikes( + tp, inters, is_p_last, is_q_last, out); + } + + // TODO: ignore for spikes? + // E.g. pass is_p_valid = !is_p_last && !is_pj_spike, + // the same with is_q_valid + collinear_opposite < TurnInfo, AssignPolicy >::apply(pi, pj, pk, qi, qj, qk, - tp, out, result.template get<0>(), result.template get<1>(), side_calc, - replacer); + tp, out, inters.i_info(), inters.d_info(), + inters.sides(), replacer); } } } @@ -278,8 +304,21 @@ struct get_turn_info_linear_areal // degenerate points if (AssignPolicy::include_degenerate) { - only_convert::apply(tp, result.template get<0>()); - AssignPolicy::apply(tp, pi, qi, result.template get<0>(), result.template get<1>()); + only_convert::apply(tp, inters.i_info()); + + if ( is_p_first + && equals::equals_point_point(pi, tp.point) ) + { + tp.operations[0].position = position_front; + } + else if ( is_p_last + && equals::equals_point_point(pj, tp.point) ) + { + tp.operations[0].position = position_back; + } + // tp.operations[1].position = position_middle; + + AssignPolicy::apply(tp, pi, qi, inters.i_info(), inters.d_info()); *out++ = tp; } } @@ -299,6 +338,128 @@ struct get_turn_info_linear_areal return out; } + template + static inline bool calculate_spike_operation(Operation & op, + IntersectionInfo const& inters, + bool is_p_last) + { + bool is_p_spike = op == operation_union + && ! is_p_last + && inters.is_spike_p(); + + // we don't know where the spike is going since for both directions 'u' is set + if ( is_p_spike ) + { + if ( inters.sides().pk_wrt_q1() < 0 && inters.sides().pk_wrt_q2() < 0 ) + { + op = operation_intersection; + return true; + } + } + + return false; + } + + enum append_version_c { append_equal, append_collinear }; + + template + static inline bool append_collinear_spikes(TurnInfo & tp, + IntersectionInfo const& inters, + bool is_p_last, bool is_q_last, + method_type method, append_version_c version, + OutIt out) + { + // method == touch || touch_interior + // both position == middle + + bool is_p_spike = ( version == append_equal ? + ( tp.operations[0].operation == operation_union + || tp.operations[0].operation == operation_intersection ) : + tp.operations[0].operation == operation_continue ) + && ! is_p_last + && inters.is_spike_p(); + + // TODO: throw an exception for spike in Areal? + /*bool is_q_spike = tp.operations[1].operation == spike_op + && ! is_q_last + && inters.is_spike_q();*/ + + if ( is_p_spike ) + { + tp.method = method; + tp.operations[0].operation = operation_blocked; + tp.operations[1].operation = operation_union; + *out++ = tp; + tp.operations[0].operation = operation_continue; // boundary + //tp.operations[1].operation = operation_union; + *out++ = tp; + + return true; + } + + return false; + } + + enum append_version_o { append_touches, append_collinear_opposite }; + + template + static inline bool append_opposite_spikes(TurnInfo & tp, + IntersectionInfo const& inters, + bool is_p_last, bool is_q_last, + OutIt out) + { + bool is_p_spike = ( Version == append_touches ? + ( tp.operations[0].operation == operation_continue + || tp.operations[0].operation == operation_intersection ) : + true ) + && ! is_p_last + && inters.is_spike_p(); + // TODO: throw an exception for spike in Areal? + /*bool is_q_spike = ( Version == append_touches ? + ( tp.operations[1].operation == operation_continue + || tp.operations[1].operation == operation_intersection ) : + true ) + && ! is_q_last + && inters.is_spike_q();*/ + + if ( is_p_spike && ( Version == append_touches || inters.d_info().arrival[0] == 1 ) ) + { + if ( Version == append_touches ) + { + tp.operations[0].is_collinear = true; + //tp.operations[1].is_collinear = ??? + tp.method = method_touch; + } + else + { + //tp.operations[0].is_collinear = true; + //tp.operations[1].is_collinear = true; + + BOOST_ASSERT(inters.i_info().count > 1); + base_turn_handler::assign_point(tp, method_touch_interior, inters.i_info(), 1); + + AssignPolicy::apply(tp, inters.pi(), inters.qi(), inters.i_info(), inters.d_info()); + } + + tp.operations[0].operation = operation_blocked; + tp.operations[1].operation = operation_continue; // boundary + *out++ = tp; + tp.operations[0].operation = operation_continue; // boundary + //tp.operations[1].operation = operation_continue; // boundary + *out++ = tp; + + return true; + } + + return false; + } + static inline void replace_method_and_operations_tm(method_type & method, operation_type & op0, operation_type & op1) @@ -323,6 +484,14 @@ struct get_turn_info_linear_areal { op1 = operation_union; } + + // spikes in 'm' + if ( method == method_error ) + { + method = method_touch_interior; + op0 = operation_union; + op1 = operation_union; + } } template @@ -371,6 +540,10 @@ struct get_turn_info_linear_areal op1 = operation_union; } + // NOTE: Spikes may NOT be handled for Linear endpoints because it's not + // possible to define a spike on an endpoint. Areal geometries must + // NOT have spikes at all. One thing that could be done is to throw + // an exception when spike is detected in Areal geometry. template (); + linear_intersections::ip_info const& ip1 = intersections.template get<1>(); const bool opposite = result.template get<1>().opposite; - const bool same_dirs = result.template get<1>().dir_a == 0 && result.template get<1>().dir_b == 0; - - { - const int p_how = result.template get<1>().how_a; - const int q_how = result.template get<1>().how_b; - const int p_arrival = result.template get<1>().arrival[0]; - const int q_arrival = result.template get<1>().arrival[1]; - - get_info_e::handle_segment( - is_p_first, is_p_last, p_how, p_arrival, - is_q_first, is_q_last, q_how, q_arrival, - opposite, ip_count, same_dirs, - result.template get<0>().intersections[0], - result.template get<0>().intersections[1], - p_operation0, q_operation0, p_operation1, q_operation1, - p0i, p0j, q0i, q0j, - p1i, p1j, q1i, q1j, - pi, pj, pk, qi, qj, qk); - } // ANALYSE AND ASSIGN FIRST // IP on the first point of Linear Geometry - if ( EnableFirst && is_p_first && p0i && !q0i ) // !q0i prevents duplication + if ( EnableFirst && is_p_first && ip0.is_pi && !ip0.is_qi ) // !q0i prevents duplication { TurnInfo tp = tp_model; tp.operations[0].position = position_front; @@ -445,19 +596,15 @@ struct get_turn_info_linear_areal { tp.operations[0].operation = operation_continue; tp.operations[1].operation = operation_union; - tp.method = q0j ? method_touch : method_touch_interior; + tp.method = ip0.is_qj ? method_touch : method_touch_interior; } else { - // NOTE: the conversion may be problematic - Point1 qi_conv; - geometry::convert(qi, qi_conv); - method_type replaced_method = method_touch_interior; - if ( q0j ) + if ( ip0.is_qj ) { - side_calculator side_calc(qi_conv, pi, pj, qi, qj, qk); + side_calculator side_calc(qi, pi, pj, qi, qj, qk); std::pair operations = get_info_e::operations_of_equal(side_calc); @@ -469,11 +616,9 @@ struct get_turn_info_linear_areal } else { -// NOTE: the conversion may be problematic - Point2 pi_conv; - geometry::convert(pi, pi_conv); - - side_calculator side_calc(qi_conv, pi, pj, qi, pi_conv, qj); + side_calculator side_calc(qi, pi, pj, qi, pi, qj); std::pair operations = get_info_e::operations_of_equal(side_calc); @@ -488,7 +633,7 @@ struct get_turn_info_linear_areal // equals<> or collinear<> will assign the second point, // we'd like to assign the first one - geometry::convert(result.template get<0>().intersections[0], tp.point); + base_turn_handler::assign_point(tp, tp.method, result.template get<0>(), 0); // NOTE: not really needed especially for the first point // for which there is no preceding segment (but consistent with the L/L) @@ -507,7 +652,7 @@ struct get_turn_info_linear_areal // IP on the last point of Linear Geometry if ( EnableLast && is_p_last - && ( ip_count > 1 ? (p1j && !q1i) : (p0j && !q0i) ) ) // prevents duplication + && ( ip_count > 1 ? (ip1.is_pj && !ip1.is_qi) : (ip0.is_pj && !ip0.is_qi) ) ) // prevents duplication { TurnInfo tp = tp_model; @@ -519,9 +664,7 @@ struct get_turn_info_linear_areal } else //if ( result.template get<0>().count == 1 ) { - Point1 qi_conv; - geometry::convert(qi, qi_conv); - side_calculator side_calc(qi_conv, pj, pi, qi, qj, qk); + side_calculator side_calc(qi, pj, pi, qi, qj, qk); std::pair operations = get_info_e::operations_of_equal(side_calc); @@ -538,7 +681,7 @@ struct get_turn_info_linear_areal } } - tp.method = ( ip_count > 1 ? q1j : q0j ) ? method_touch : method_touch_interior; + tp.method = ( ip_count > 1 ? ip1.is_qj : ip0.is_qj ) ? method_touch : method_touch_interior; tp.operations[0].operation = operation_blocked; tp.operations[0].position = position_back; tp.operations[1].position = position_middle; @@ -546,7 +689,7 @@ struct get_turn_info_linear_areal // equals<> or collinear<> will assign the second point, // we'd like to assign the first one std::size_t ip_index = ip_count > 1 ? 1 : 0; - geometry::convert(result.template get<0>().intersections[ip_index], tp.point); + base_turn_handler::assign_point(tp, tp.method, result.template get<0>(), ip_index); AssignPolicy::apply(tp, pi, qi, result.template get<0>(), result.template get<1>()); *out++ = tp; diff --git a/include/boost/geometry/algorithms/detail/overlay/get_turn_info_ll.hpp b/include/boost/geometry/algorithms/detail/overlay/get_turn_info_ll.hpp index dbb2c4a11..4f1cc5232 100644 --- a/include/boost/geometry/algorithms/detail/overlay/get_turn_info_ll.hpp +++ b/include/boost/geometry/algorithms/detail/overlay/get_turn_info_ll.hpp @@ -22,71 +22,17 @@ namespace boost { namespace geometry { #ifndef DOXYGEN_NO_DETAIL namespace detail { namespace overlay { -template > -class spike_detector -{ -public: - explicit spike_detector(SideCalc const& side_calc) - : m_side_calc(side_calc) - {} - - inline bool is_spike_p() const - { - if ( m_side_calc.pk_wrt_p1() == 0 ) - { - int const qk_p1 = m_side_calc.qk_wrt_p1(); - int const qk_p2 = m_side_calc.qk_wrt_p2(); - - if ( qk_p1 == -qk_p2 ) - { - if ( qk_p1 == 0 ) - { - // TODO check additional things - } - - return true; - } - } - - return false; - } - - inline bool is_spike_q() const - { - if ( m_side_calc.qk_wrt_q1() == 0 ) - { - int const pk_q1 = m_side_calc.pk_wrt_q1(); - int const pk_q2 = m_side_calc.pk_wrt_q2(); - - if ( pk_q1 == -pk_q2 ) - { - if ( pk_q1 == 0 ) - { - // TODO check additional things - } - - return true; - } - } - - return false; - } - -private: - SideCalc const& m_side_calc; -}; - template struct get_turn_info_linear_linear { + static const bool handle_spikes = true; + template < typename Point1, typename Point2, typename TurnInfo, - typename RescalePolicy, + typename RobustPolicy, typename OutputIterator > static inline OutputIterator apply( @@ -95,29 +41,13 @@ struct get_turn_info_linear_linear bool is_p_first, bool is_p_last, bool is_q_first, bool is_q_last, TurnInfo const& tp_model, - RescalePolicy const& , // TODO: this will be used. rescale_policy, + RobustPolicy const& robust_policy, OutputIterator out) { - typedef model::referring_segment segment_type1; - typedef model::referring_segment segment_type2; - segment_type1 p1(pi, pj), p2(pj, pk); - segment_type2 q1(qi, qj), q2(qj, qk); + intersection_info + inters(pi, pj, pk, qi, qj, qk, robust_policy); - side_calculator side_calc(pi, pj, pk, qi, qj, qk); - - typedef strategy_intersection - < - typename cs_tag::type, - Point1, - Point2, - typename TurnInfo::point_type - > si; - - typedef typename si::segment_intersection_strategy_type strategy; - - typename strategy::return_type result = strategy::apply(p1, q1); - - char const method = result.template get<1>().how; + char const method = inters.d_info().how; // Copy, to copy possibly extended fields TurnInfo tp = tp_model; @@ -131,7 +61,7 @@ struct get_turn_info_linear_linear get_turn_info_for_endpoint ::apply(pi, pj, pk, qi, qj, qk, is_p_first, is_p_last, is_q_first, is_q_last, - tp_model, result, method_none, out); + tp_model, inters, method_none, out); break; case 'd' : // disjoint: never do anything @@ -142,7 +72,7 @@ struct get_turn_info_linear_linear if ( get_turn_info_for_endpoint ::apply(pi, pj, pk, qi, qj, qk, is_p_first, is_p_last, is_q_first, is_q_last, - tp_model, result, method_touch_interior, out) ) + tp_model, inters, method_touch_interior, out) ) { // do nothing } @@ -154,21 +84,21 @@ struct get_turn_info_linear_linear > policy; // If Q (1) arrives (1) - if (result.template get<1>().arrival[1] == 1) + if ( inters.d_info().arrival[1] == 1) { policy::template apply<0>(pi, pj, pk, qi, qj, qk, - tp, result.template get<0>(), result.template get<1>(), - side_calc); + tp, inters.i_info(), inters.d_info(), + inters.sides()); } else { // Swap p/q - side_calculator swapped_side_calc(qi, qj, qk, pi, pj, pk); + side_calculator swapped_side_calc(qi, qj, qk, pi, pj, pk); policy::template apply<1>(qi, qj, qk, pi, pj, pk, - tp, result.template get<0>(), result.template get<1>(), - swapped_side_calc); + tp, inters.i_info(), inters.d_info(), + swapped_side_calc); } - + if ( tp.operations[0].operation == operation_blocked ) { tp.operations[1].is_collinear = true; @@ -178,9 +108,11 @@ struct get_turn_info_linear_linear tp.operations[0].is_collinear = true; } - replace_method_and_operations_tm(tp.method, tp.operations[0].operation, tp.operations[1].operation); + replace_method_and_operations_tm(tp.method, + tp.operations[0].operation, + tp.operations[1].operation); - AssignPolicy::apply(tp, pi, qi, result.template get<0>(), result.template get<1>()); + AssignPolicy::apply(tp, pi, qi, inters.i_info(), inters.d_info()); *out++ = tp; } } @@ -188,11 +120,11 @@ struct get_turn_info_linear_linear case 'i' : { crosses::apply(pi, pj, pk, qi, qj, qk, - tp, result.template get<0>(), result.template get<1>()); + tp, inters.i_info(), inters.d_info()); replace_operations_i(tp.operations[0].operation, tp.operations[1].operation); - AssignPolicy::apply(tp, pi, qi, result.template get<0>(), result.template get<1>()); + AssignPolicy::apply(tp, pi, qi, inters.i_info(), inters.d_info()); *out++ = tp; } break; @@ -202,14 +134,14 @@ struct get_turn_info_linear_linear if ( get_turn_info_for_endpoint ::apply(pi, pj, pk, qi, qj, qk, is_p_first, is_p_last, is_q_first, is_q_last, - tp_model, result, method_touch, out) ) + tp_model, inters, method_touch, out) ) { // do nothing } else { touch::apply(pi, pj, pk, qi, qj, qk, - tp, result.template get<0>(), result.template get<1>(), side_calc); + tp, inters.i_info(), inters.d_info(), inters.sides()); if ( tp.operations[0].operation == operation_blocked ) { @@ -220,10 +152,20 @@ struct get_turn_info_linear_linear tp.operations[0].is_collinear = true; } - replace_method_and_operations_tm(tp.method, tp.operations[0].operation, tp.operations[1].operation); + replace_method_and_operations_tm(tp.method, + tp.operations[0].operation, + tp.operations[1].operation); - AssignPolicy::apply(tp, pi, qi, result.template get<0>(), result.template get<1>()); - *out++ = tp; +// TODO: move this into the append_xxx and call for each turn? + AssignPolicy::apply(tp, pi, qi, inters.i_info(), inters.d_info()); + + if ( ! handle_spikes + || ! append_opposite_spikes(tp, inters, + is_p_last, is_q_last, + out) ) + { + *out++ = tp; + } } } break; @@ -232,7 +174,7 @@ struct get_turn_info_linear_linear if ( get_turn_info_for_endpoint ::apply(pi, pj, pk, qi, qj, qk, is_p_first, is_p_last, is_q_first, is_q_last, - tp_model, result, method_equal, out) ) + tp_model, inters, method_equal, out) ) { // do nothing } @@ -241,40 +183,38 @@ struct get_turn_info_linear_linear tp.operations[0].is_collinear = true; tp.operations[1].is_collinear = true; - if ( ! result.template get<1>().opposite ) + if ( ! inters.d_info().opposite ) { // Both equal // or collinear-and-ending at intersection point equal::apply(pi, pj, pk, qi, qj, qk, - tp, result.template get<0>(), result.template get<1>(), side_calc); + tp, inters.i_info(), inters.d_info(), inters.sides()); replacer_of_method_and_operations_ec replacer(method_touch); replacer(tp.method, tp.operations[0].operation, tp.operations[1].operation); - // TODO: This isn't correct handling, hence commented out - /*spike_detector spike_detect(side_calc); - if ( tp.operations[0].operation == operation_union - && spike_detect.is_spike_p()) +// TODO: move this into the append_xxx and call for each turn? + AssignPolicy::apply(tp, pi, qi, inters.i_info(), inters.d_info()); + + // conditionally handle spikes + if ( ! handle_spikes + || ! append_collinear_spikes(tp, inters, + is_p_last, is_q_last, + method_touch, operation_union, + out) ) { - tp.operations[0].operation = operation_continue; + *out++ = tp; // no spikes } - if ( tp.operations[1].operation == operation_union - && spike_detect.is_spike_q()) - { - tp.operations[1].operation = operation_continue; - }*/ - - AssignPolicy::apply(tp, pi, qi, result.template get<0>(), result.template get<1>()); - *out++ = tp; } else { + // TODO: ignore for spikes or generate something else than opposite? + equal_opposite < TurnInfo, AssignPolicy - >::apply(pi, qi, - tp, out, result.template get<0>(), result.template get<1>()); + >::apply(pi, qi, tp, out, inters.i_info(), inters.d_info()); } } } @@ -285,7 +225,7 @@ struct get_turn_info_linear_linear if ( get_turn_info_for_endpoint ::apply(pi, pj, pk, qi, qj, qk, is_p_first, is_p_last, is_q_first, is_q_last, - tp_model, result, method_collinear, out) ) + tp_model, inters, method_collinear, out) ) { // do nothing } @@ -294,63 +234,69 @@ struct get_turn_info_linear_linear tp.operations[0].is_collinear = true; tp.operations[1].is_collinear = true; - if (! result.template get<1>().opposite) - { - if (result.template get<1>().arrival[0] == 0) + if ( ! inters.d_info().opposite ) + { + method_type method_replace = method_touch_interior; + operation_type spike_op = operation_continue; + + if ( inters.d_info().arrival[0] == 0 ) { // Collinear, but similar thus handled as equal equal::apply(pi, pj, pk, qi, qj, qk, - tp, result.template get<0>(), result.template get<1>(), side_calc); + tp, inters.i_info(), inters.d_info(), inters.sides()); - // NOTE: don't change the method only if methods are WRT IPs, not segments! - // (currently this approach is used) - // override assigned method - //tp.method = method_collinear; - - replacer_of_method_and_operations_ec replacer(method_touch); - replacer(tp.method, tp.operations[0].operation, tp.operations[1].operation); - - // TODO: This isn't correct handling, hence commented out - /*spike_detector spike_detect(side_calc); - if ( tp.operations[0].operation == operation_union - && spike_detect.is_spike_p()) - { - tp.operations[0].operation = operation_continue; - } - if ( tp.operations[1].operation == operation_union - && spike_detect.is_spike_q()) - { - tp.operations[1].operation = operation_continue; - }*/ + method_replace = method_touch; + spike_op = operation_union; } else { collinear::apply(pi, pj, pk, qi, qj, qk, - tp, result.template get<0>(), result.template get<1>(), side_calc); + tp, inters.i_info(), inters.d_info(), inters.sides()); - replacer_of_method_and_operations_ec replacer(method_touch_interior); - replacer(tp.method, tp.operations[0].operation, tp.operations[1].operation); - - // TEST - //spike_detector spike_detect(side_calc); - //spike_detect.is_spike_p(); - //spike_detect.is_spike_q(); + //method_replace = method_touch_interior; + //spike_op = operation_continue; } - AssignPolicy::apply(tp, pi, qi, result.template get<0>(), result.template get<1>()); - *out++ = tp; + replacer_of_method_and_operations_ec replacer(method_replace); + replacer(tp.method, tp.operations[0].operation, tp.operations[1].operation); + +// TODO: move this into the append_xxx and call for each turn? + AssignPolicy::apply(tp, pi, qi, inters.i_info(), inters.d_info()); + + // conditionally handle spikes + if ( ! handle_spikes + || ! append_collinear_spikes(tp, inters, + is_p_last, is_q_last, + method_replace, spike_op, + out) ) + { + // no spikes + *out++ = tp; + } } else { // If this always 'm' ? replacer_of_method_and_operations_ec replacer(method_touch_interior); + // conditionally handle spikes + if ( handle_spikes ) + { + append_opposite_spikes(tp, inters, + is_p_last, is_q_last, + out); + } + + // TODO: ignore for spikes? + // E.g. pass is_p_valid = !is_p_last && !is_pj_spike, + // the same with is_q_valid + collinear_opposite < TurnInfo, AssignPolicy >::apply(pi, pj, pk, qi, qj, qk, - tp, out, result.template get<0>(), result.template get<1>(), side_calc, + tp, out, inters.i_info(), inters.d_info(), inters.sides(), replacer, !is_p_last, !is_q_last); } } @@ -361,8 +307,31 @@ struct get_turn_info_linear_linear // degenerate points if (AssignPolicy::include_degenerate) { - only_convert::apply(tp, result.template get<0>()); - AssignPolicy::apply(tp, pi, qi, result.template get<0>(), result.template get<1>()); + only_convert::apply(tp, inters.i_info()); + + // if any, only one of those should be true + if ( is_p_first + && equals::equals_point_point(pi, tp.point) ) + { + tp.operations[0].position = position_front; + } + else if ( is_p_last + && equals::equals_point_point(pj, tp.point) ) + { + tp.operations[0].position = position_back; + } + else if ( is_q_first + && equals::equals_point_point(qi, tp.point) ) + { + tp.operations[1].position = position_front; + } + else if ( is_q_last + && equals::equals_point_point(qj, tp.point) ) + { + tp.operations[1].position = position_back; + } + + AssignPolicy::apply(tp, pi, qi, inters.i_info(), inters.d_info()); *out++ = tp; } } @@ -382,6 +351,157 @@ struct get_turn_info_linear_linear return out; } + template + static inline bool append_collinear_spikes(TurnInfo & tp, + IntersectionInfo const& inters_info, + bool is_p_last, bool is_q_last, + method_type method, operation_type spike_op, + OutIt out) + { + // method == touch || touch_interior + // both position == middle + + bool is_p_spike = tp.operations[0].operation == spike_op + && ! is_p_last + && inters_info.is_spike_p(); + bool is_q_spike = tp.operations[1].operation == spike_op + && ! is_q_last + && inters_info.is_spike_q(); + + if ( is_p_spike && is_q_spike ) + { + tp.method = method; + tp.operations[0].operation = operation_blocked; + tp.operations[1].operation = operation_blocked; + *out++ = tp; + tp.operations[0].operation = operation_intersection; + tp.operations[1].operation = operation_intersection; + *out++ = tp; + + return true; + } + else if ( is_p_spike ) + { + tp.method = method; + tp.operations[0].operation = operation_blocked; + tp.operations[1].operation = operation_union; + *out++ = tp; + tp.operations[0].operation = operation_intersection; + //tp.operations[1].operation = operation_union; + *out++ = tp; + + return true; + } + else if ( is_q_spike ) + { + tp.method = method; + tp.operations[0].operation = operation_union; + tp.operations[1].operation = operation_blocked; + *out++ = tp; + //tp.operations[0].operation = operation_union; + tp.operations[1].operation = operation_intersection; + *out++ = tp; + + return true; + } + + return false; + } + + enum append_version { append_touches, append_collinear_opposite }; + + template + static inline bool append_opposite_spikes(TurnInfo & tp, + IntersectionInfo const& inters, + bool is_p_last, bool is_q_last, + OutIt out) + { + bool is_p_spike = ( Version == append_touches ? + ( tp.operations[0].operation == operation_continue + || tp.operations[0].operation == operation_intersection ) : + true ) + && ! is_p_last + && inters.is_spike_p(); + bool is_q_spike = ( Version == append_touches ? + ( tp.operations[1].operation == operation_continue + || tp.operations[1].operation == operation_intersection ) : + true ) + && ! is_q_last + && inters.is_spike_q(); + + bool res = false; + + if ( is_p_spike && ( Version == append_touches || inters.d_info().arrival[0] == 1 ) ) + { + if ( Version == append_touches ) + { + tp.operations[0].is_collinear = true; + //tp.operations[1].is_collinear = ??? + tp.method = method_touch; + } + else + { + //tp.operations[0].is_collinear = true; + //tp.operations[1].is_collinear = true; + + BOOST_ASSERT(inters.i_info().count > 1); + + base_turn_handler::assign_point(tp, method_touch_interior, + inters.i_info(), 1); + + AssignPolicy::apply(tp, inters.pi(), inters.qi(), + inters.i_info(), inters.d_info()); + } + + tp.operations[0].operation = operation_blocked; + tp.operations[1].operation = operation_intersection; + *out++ = tp; + tp.operations[0].operation = operation_intersection; + //tp.operations[1].operation = operation_intersection; + *out++ = tp; + + res = true; + } + + if ( is_q_spike && ( Version == append_touches || inters.d_info().arrival[1] == 1 ) ) + { + if ( Version == append_touches ) + { + //tp.operations[0].is_collinear = ??? + tp.operations[1].is_collinear = true; + tp.method = method_touch; + } + else + { + //tp.operations[0].is_collinear = true; + //tp.operations[1].is_collinear = true; + + BOOST_ASSERT(inters.i_info().count > 0); + + base_turn_handler::assign_point(tp, method_touch_interior, inters.i_info(), 0); + + AssignPolicy::apply(tp, inters.pi(), inters.qi(), + inters.i_info(), inters.d_info()); + } + + tp.operations[0].operation = operation_intersection; + tp.operations[1].operation = operation_blocked; + *out++ = tp; + //tp.operations[0].operation = operation_intersection; + tp.operations[1].operation = operation_intersection; + *out++ = tp; + + res = true; + } + + return res; + } + static inline void replace_method_and_operations_tm(method_type & method, operation_type & op0, operation_type & op1) @@ -412,6 +532,14 @@ struct get_turn_info_linear_linear { op1 = operation_union; } + + // spikes in 'm' + if ( method == method_error ) + { + method = method_touch_interior; + op0 = operation_union; + op1 = operation_union; + } } } diff --git a/include/boost/geometry/algorithms/detail/overlay/get_turns.hpp b/include/boost/geometry/algorithms/detail/overlay/get_turns.hpp index 4ca5c81bd..e0c6d0096 100644 --- a/include/boost/geometry/algorithms/detail/overlay/get_turns.hpp +++ b/include/boost/geometry/algorithms/detail/overlay/get_turns.hpp @@ -51,6 +51,7 @@ #include #include #include +#include #include #include #include @@ -171,12 +172,12 @@ class get_turns_in_sections public : // Returns true if terminated, false if interrupted - template + template static inline bool apply( int source_id1, Geometry1 const& geometry1, Section1 const& sec1, int source_id2, Geometry2 const& geometry2, Section2 const& sec2, bool skip_larger, - RescalePolicy const& rescale_policy, + RobustPolicy const& robust_policy, Turns& turns, InterruptPolicy& interrupt_policy) { @@ -216,7 +217,7 @@ public : range1_iterator prev1, it1, end1; get_start_point_iterator(sec1, view1, prev1, it1, end1, - index1, ndi1, dir1, sec2.bounding_box, rescale_policy); + index1, ndi1, dir1, sec2.bounding_box, robust_policy); // We need a circular iterator because it might run through the closing point. // One circle is actually enough but this one is just convenient. @@ -227,12 +228,12 @@ public : // section 2: [--------------] // section 1: |----|---|---|---|---| for (prev1 = it1++, next1++; - it1 != end1 && ! exceeding<0>(dir1, *prev1, sec2.bounding_box, rescale_policy); + it1 != end1 && ! exceeding<0>(dir1, *prev1, sec2.bounding_box, robust_policy); ++prev1, ++it1, ++index1, ++next1, ++ndi1) { ever_circling_iterator nd_next1( begin_range_1, end_range_1, next1, true); - advance_to_non_duplicate_next(nd_next1, it1, sec1, rescale_policy); + advance_to_non_duplicate_next(nd_next1, it1, sec1, robust_policy); int index2 = sec2.begin_index; int ndi2 = sec2.non_duplicate_index; @@ -240,12 +241,12 @@ public : range2_iterator prev2, it2, end2; get_start_point_iterator(sec2, view2, prev2, it2, end2, - index2, ndi2, dir2, sec1.bounding_box, rescale_policy); + index2, ndi2, dir2, sec1.bounding_box, robust_policy); ever_circling_iterator next2(begin_range_2, end_range_2, it2, true); next2++; for (prev2 = it2++, next2++; - it2 != end2 && ! exceeding<0>(dir2, *prev2, sec1.bounding_box, rescale_policy); + it2 != end2 && ! exceeding<0>(dir2, *prev2, sec1.bounding_box, robust_policy); ++prev2, ++it2, ++index2, ++next2, ++ndi2) { bool skip = same_source; @@ -271,7 +272,7 @@ public : // Move to the "non duplicate next" ever_circling_iterator nd_next2( begin_range_2, end_range_2, next2, true); - advance_to_non_duplicate_next(nd_next2, it2, sec2, rescale_policy); + advance_to_non_duplicate_next(nd_next2, it2, sec2, robust_policy); typedef typename boost::range_value::type turn_info; @@ -293,7 +294,7 @@ public : TurnPolicy::apply(*prev1, *it1, *nd_next1, *prev2, *it2, *nd_next2, is_1_first, is_1_last, is_2_first, is_2_last, - ti, rescale_policy, std::back_inserter(turns)); + ti, robust_policy, std::back_inserter(turns)); if (InterruptPolicy::enabled) { @@ -318,27 +319,34 @@ private : typedef typename model::referring_segment segment2_type; - template - static inline bool preceding(int dir, Point const& point, Box const& box, RescalePolicy const& rescale_policy) + template + static inline bool preceding(int dir, Point const& point, Box const& box, RobustPolicy const& robust_policy) { - boost::ignore_unused_variable_warning(rescale_policy); - return (dir == 1 && get(point) < get(box)) - || (dir == -1 && get(point) > get(box)); + typename robust_point_type::type robust_point; + geometry::recalculate(robust_point, point, robust_policy); + return (dir == 1 && get(robust_point) < get(box)) + || (dir == -1 && get(robust_point) > get(box)); } - template - static inline bool exceeding(int dir, Point const& point, Box const& box, RescalePolicy const& rescale_policy) + template + static inline bool exceeding(int dir, Point const& point, Box const& box, RobustPolicy const& robust_policy) { - boost::ignore_unused_variable_warning(rescale_policy); - return (dir == 1 && get(point) > get(box)) - || (dir == -1 && get(point) < get(box)); + typename robust_point_type::type robust_point; + geometry::recalculate(robust_point, point, robust_policy); + return (dir == 1 && get(robust_point) > get(box)) + || (dir == -1 && get(robust_point) < get(box)); } - template + template static inline void advance_to_non_duplicate_next(Iterator& next, - RangeIterator const& it, Section const& section, RescalePolicy const& rescale_policy) + RangeIterator const& it, Section const& section, RobustPolicy const& robust_policy) { - boost::ignore_unused_variable_warning(rescale_policy); + typedef typename robust_point_type::type robust_point_type; + robust_point_type robust_point_from_it; + robust_point_type robust_point_from_next; + geometry::recalculate(robust_point_from_it, *it, robust_policy); + geometry::recalculate(robust_point_from_next, *next, robust_policy); + // To see where the next segments bend to, in case of touch/intersections // on end points, we need (in case of degenerate/duplicate points) an extra // iterator which moves to the REAL next point, so non duplicate. @@ -349,10 +357,14 @@ private : // So advance to the "non duplicate next" // (the check is defensive, to avoid endless loops) std::size_t check = 0; - while(! detail::disjoint::disjoint_point_point(*it, *next) + while(! detail::disjoint::disjoint_point_point + ( + robust_point_from_it, robust_point_from_next + ) && check++ < section.range_count) { next++; + geometry::recalculate(robust_point_from_next, *next, robust_policy); } } @@ -360,14 +372,14 @@ private : // because of the logistics of "index" (the section-iterator automatically // skips to the begin-point, we loose the index or have to recalculate it) // So we mimic it here - template + template static inline void get_start_point_iterator(Section & section, Range const& range, typename boost::range_iterator::type& it, typename boost::range_iterator::type& prev, typename boost::range_iterator::type& end, int& index, int& ndi, - int dir, Box const& other_bounding_box, RescalePolicy const& rescale_policy) + int dir, Box const& other_bounding_box, RobustPolicy const& robust_policy) { it = boost::begin(range) + section.begin_index; end = boost::begin(range) + section.end_index + 1; @@ -375,7 +387,7 @@ private : // Mimic section-iterator: // Skip to point such that section interects other box prev = it++; - for(; it != end && preceding<0>(dir, *it, other_bounding_box, rescale_policy); + for(; it != end && preceding<0>(dir, *it, other_bounding_box, robust_policy); prev = it++, index++, ndi++) {} // Go back one step because we want to start completely preceding @@ -407,7 +419,7 @@ template bool Reverse1, bool Reverse2, typename Turns, typename TurnPolicy, - typename RescalePolicy, + typename RobustPolicy, typename InterruptPolicy > struct section_visitor @@ -416,17 +428,17 @@ struct section_visitor Geometry1 const& m_geometry1; int m_source_id2; Geometry2 const& m_geometry2; - RescalePolicy const& m_rescale_policy; + RobustPolicy const& m_rescale_policy; Turns& m_turns; InterruptPolicy& m_interrupt_policy; section_visitor(int id1, Geometry1 const& g1, int id2, Geometry2 const& g2, - RescalePolicy const& rescale_policy, + RobustPolicy const& robust_policy, Turns& turns, InterruptPolicy& ip) : m_source_id1(id1), m_geometry1(g1) , m_source_id2(id2), m_geometry2(g2) - , m_rescale_policy(rescale_policy) + , m_rescale_policy(robust_policy) , m_turns(turns) , m_interrupt_policy(ip) {} @@ -465,32 +477,39 @@ class get_turns_generic { public: - template + template static inline void apply( int source_id1, Geometry1 const& geometry1, int source_id2, Geometry2 const& geometry2, - RescalePolicy const& rescale_policy, + RobustPolicy const& robust_policy, Turns& turns, InterruptPolicy& interrupt_policy) { // First create monotonic sections... typedef typename boost::range_value::type ip_type; typedef typename ip_type::point_type point_type; - typedef model::box box_type; + + typedef model::box + < + typename geometry::robust_point_type + < + point_type, RobustPolicy + >::type + > box_type; typedef typename geometry::sections sections_type; sections_type sec1, sec2; - geometry::sectionalize(geometry1, rescale_policy, true, sec1, 0); - geometry::sectionalize(geometry2, rescale_policy, true, sec2, 1); + geometry::sectionalize(geometry1, robust_policy, true, sec1, 0); + geometry::sectionalize(geometry2, robust_policy, true, sec2, 1); // ... and then partition them, intersecting overlapping sections in visitor method section_visitor < Geometry1, Geometry2, Reverse1, Reverse2, - Turns, TurnPolicy, RescalePolicy, InterruptPolicy - > visitor(source_id1, geometry1, source_id2, geometry2, rescale_policy, turns, interrupt_policy); + Turns, TurnPolicy, RobustPolicy, InterruptPolicy + > visitor(source_id1, geometry1, source_id2, geometry2, robust_policy, turns, interrupt_policy); geometry::partition < @@ -530,11 +549,11 @@ struct get_turns_cs >::type iterator_type; - template + template static inline void apply( int source_id1, Range const& range, int source_id2, Box const& box, - RescalePolicy const& rescale_policy, + RobustPolicy const& robust_policy, Turns& turns, InterruptPolicy& interrupt_policy, int multi_index = -1, int ring_index = -1) @@ -605,7 +624,7 @@ struct get_turns_cs // NOTE: some dummy values could be passed below since this would be called only for Polygons and Boxes index == 0, unsigned(index) == segments_count1, - rescale_policy, + robust_policy, turns, interrupt_policy); // Future performance enhancement: // return if told by the interrupt policy @@ -634,7 +653,7 @@ private: else return 0; } - template + template static inline void get_turns_with_box(segment_identifier const& seg_id, int source_id2, // Points from a range: point_type const& rp0, @@ -647,7 +666,7 @@ private: box_point_type const& bp3, bool const is_range_first, bool const is_range_last, - RescalePolicy const& rescale_policy, + RobustPolicy const& robust_policy, // Output Turns& turns, InterruptPolicy& interrupt_policy) @@ -667,25 +686,25 @@ private: TurnPolicy::apply(rp0, rp1, rp2, bp0, bp1, bp2, is_range_first, is_range_last, true, false, - ti, rescale_policy, std::back_inserter(turns)); + ti, robust_policy, std::back_inserter(turns)); ti.operations[1].seg_id = segment_identifier(source_id2, -1, -1, 1); TurnPolicy::apply(rp0, rp1, rp2, bp1, bp2, bp3, is_range_first, is_range_last, false, false, - ti, rescale_policy, std::back_inserter(turns)); + ti, robust_policy, std::back_inserter(turns)); ti.operations[1].seg_id = segment_identifier(source_id2, -1, -1, 2); TurnPolicy::apply(rp0, rp1, rp2, bp2, bp3, bp0, is_range_first, is_range_last, false, false, - ti, rescale_policy, std::back_inserter(turns)); + ti, robust_policy, std::back_inserter(turns)); ti.operations[1].seg_id = segment_identifier(source_id2, -1, -1, 3); TurnPolicy::apply(rp0, rp1, rp2, bp3, bp0, bp1, is_range_first, is_range_last, false, true, - ti, rescale_policy, std::back_inserter(turns)); + ti, robust_policy, std::back_inserter(turns)); if (InterruptPolicy::enabled) { @@ -705,11 +724,11 @@ template > struct get_turns_polygon_cs { - template + template static inline void apply( int source_id1, Polygon const& polygon, int source_id2, Box const& box, - RescalePolicy const& rescale_policy, + RobustPolicy const& robust_policy, Turns& turns, InterruptPolicy& interrupt_policy, int multi_index = -1) { @@ -725,7 +744,7 @@ struct get_turns_polygon_cs intersector_type::apply( source_id1, geometry::exterior_ring(polygon), source_id2, box, - rescale_policy, + robust_policy, turns, interrupt_policy, multi_index, -1); @@ -739,7 +758,7 @@ struct get_turns_polygon_cs intersector_type::apply( source_id1, *it, source_id2, box, - rescale_policy, + robust_policy, turns, interrupt_policy, multi_index, i); } @@ -772,24 +791,24 @@ struct get_turn_info_type {}; -template ::type, typename Tag2 = typename tag::type, typename TagBase1 = typename topological_tag_base::type, typename TagBase2 = typename topological_tag_base::type> struct turn_operation_type { - typedef overlay::turn_operation type; + typedef overlay::turn_operation type; }; -template -struct turn_operation_type +template +struct turn_operation_type { - typedef overlay::turn_operation_linear type; + typedef overlay::turn_operation_linear type; }; -template -struct turn_operation_type +template +struct turn_operation_type { - typedef overlay::turn_operation_linear type; + typedef overlay::turn_operation_linear type; }; }} // namespace detail::get_turns @@ -870,11 +889,11 @@ template > struct get_turns_reversed { - template + template static inline void apply( int source_id1, Geometry1 const& g1, int source_id2, Geometry2 const& g2, - RescalePolicy const& rescale_policy, + RobustPolicy const& robust_policy, Turns& turns, InterruptPolicy& interrupt_policy) { @@ -884,7 +903,7 @@ struct get_turns_reversed Geometry2, Geometry1, Reverse2, Reverse1, TurnPolicy - >::apply(source_id2, g2, source_id1, g1, rescale_policy, + >::apply(source_id2, g2, source_id1, g1, robust_policy, turns, interrupt_policy); } }; @@ -913,26 +932,18 @@ template typename AssignPolicy, typename Geometry1, typename Geometry2, - typename RescalePolicy, + typename RobustPolicy, typename Turns, typename InterruptPolicy > inline void get_turns(Geometry1 const& geometry1, Geometry2 const& geometry2, - RescalePolicy const& rescale_policy, + RobustPolicy const& robust_policy, Turns& turns, InterruptPolicy& interrupt_policy) { concept::check_concepts_and_equal_dimensions(); - //typedef typename strategy_intersection - // < - // typename cs_tag::type, - // Geometry1, - // Geometry2, - // typename boost::range_value::type - // >::segment_intersection_strategy_type segment_intersection_strategy_type; - typedef detail::overlay::get_turn_info TurnPolicy; //typedef detail::get_turns::get_turn_info_type TurnPolicy; @@ -958,7 +969,7 @@ inline void get_turns(Geometry1 const& geometry1, >::type::apply( 0, geometry1, 1, geometry2, - rescale_policy, + robust_policy, turns, interrupt_policy); } diff --git a/include/boost/geometry/algorithms/detail/overlay/handle_tangencies.hpp b/include/boost/geometry/algorithms/detail/overlay/handle_tangencies.hpp index 7e73701a7..92d162032 100644 --- a/include/boost/geometry/algorithms/detail/overlay/handle_tangencies.hpp +++ b/include/boost/geometry/algorithms/detail/overlay/handle_tangencies.hpp @@ -14,8 +14,17 @@ #include #include #include +#include + +#include +#include +#include #include +#if defined(BOOST_GEOMETRY_DEBUG_HANDLE_TANGENCIES) +#include +#endif + #include #include @@ -33,7 +42,7 @@ template typename TurnPoints, typename Indexed, typename Geometry1, typename Geometry2, - typename RescalePolicy, + typename RobustPolicy, bool Reverse1, bool Reverse2, typename Strategy > @@ -42,12 +51,12 @@ struct sort_in_cluster inline sort_in_cluster(TurnPoints const& turn_points , Geometry1 const& geometry1 , Geometry2 const& geometry2 - , RescalePolicy const& rescale_policy + , RobustPolicy const& robust_policy , Strategy const& strategy) : m_turn_points(turn_points) , m_geometry1(geometry1) , m_geometry2(geometry2) - , m_rescale_policy(rescale_policy) + , m_rescale_policy(robust_policy) , m_strategy(strategy) {} @@ -56,15 +65,15 @@ private : TurnPoints const& m_turn_points; Geometry1 const& m_geometry1; Geometry2 const& m_geometry2; - RescalePolicy const& m_rescale_policy; + RobustPolicy const& m_rescale_policy; Strategy const& m_strategy; typedef typename Indexed::type turn_operation_type; typedef typename geometry::point_type::type point_type; typedef model::point - < - typename geometry::robust_type + < + typename detail::robust_type < typename select_coordinate_type::type >::type, @@ -72,6 +81,8 @@ private : typename geometry::coordinate_system::type > robust_point_type; + // Still called by #case_102_multi, #case_107_multi + // #case_recursive_boxes_3 inline void get_situation_map(Indexed const& left, Indexed const& right, robust_point_type& pi_rob, robust_point_type& pj_rob, robust_point_type& ri_rob, robust_point_type& rj_rob, @@ -89,47 +100,67 @@ private : geometry::copy_segment_points(m_geometry1, m_geometry2, right.subject.other_id, si, sj); - geometry::zoom_to_robust(pi, pj, ri, rj, si, sj, - pi_rob, pj_rob, - ri_rob, rj_rob, - si_rob, sj_rob); + + geometry::recalculate(pi_rob, pi, m_rescale_policy); + geometry::recalculate(pj_rob, pj, m_rescale_policy); + geometry::recalculate(ri_rob, ri, m_rescale_policy); + geometry::recalculate(rj_rob, rj, m_rescale_policy); + geometry::recalculate(si_rob, si, m_rescale_policy); + geometry::recalculate(sj_rob, sj, m_rescale_policy); } +#if BOOST_GEOMETRY_HANDLE_TANGENCIES_WITH_OVERLAP_INFO + // This method was still called but did no effect whatsoever on the results, + // with or without robustness-rescaling. + // Probable cause: we rescale in this file ourselves, ignoring passed policy + // TODO: check this more. + // Besides this, it currently does not compile for yet unknown reasons + // (does not find specialization for segment_ratio_type) + // It is currently only called from the Unit Test "multi_intersection.cpp" + // Determine how p/r and p/s are located. - static inline void overlap_info(robust_point_type const& pi, robust_point_type const& pj, + inline void overlap_info( + robust_point_type const& pi, robust_point_type const& pj, robust_point_type const& ri, robust_point_type const& rj, robust_point_type const& si, robust_point_type const& sj, - bool& pr_overlap, bool& ps_overlap, bool& rs_overlap) + bool& pr_overlap, bool& ps_overlap, bool& rs_overlap) const { // Determine how p/r and p/s are located. // One of them is coming from opposite direction. - typedef model::referring_segment segment_type; + typedef segment_intersection_points + < + point_type, + typename segment_ratio_type + < + point_type, RobustPolicy + >::type + > intersection_return_type; + typedef strategy::intersection::relate_cartesian_segments < policies::relate::segments_intersection_points < - segment_type, - segment_type, - segment_intersection_points + intersection_return_type > > policy; + typedef model::referring_segment segment_type; segment_type p(pi, pj); segment_type r(ri, rj); segment_type s(si, sj); - // Get the intersection point (or two points) - segment_intersection_points pr = policy::apply(p, r); - segment_intersection_points ps = policy::apply(p, s); - segment_intersection_points rs = policy::apply(r, s); + intersection_return_type pr = policy::apply(p, r, m_rescale_policy, pi, pj, ri, rj); + intersection_return_type ps = policy::apply(p, s, m_rescale_policy, pi, pj, si, sj); + intersection_return_type rs = policy::apply(r, s, m_rescale_policy, ri, rj, si, sj); // Check on overlap pr_overlap = pr.count == 2; ps_overlap = ps.count == 2; rs_overlap = rs.count == 2; } +#endif #ifdef BOOST_GEOMETRY_DEBUG_HANDLE_TANGENCIES @@ -141,11 +172,15 @@ private : { if (skip) return; + std::cout << "Case: " << header << " for " << left.index << " / " << right.index << std::endl; + robust_point_type pi, pj, ri, rj, si, sj; get_situation_map(left, right, pi, pj, ri, rj, si, sj); +#if BOOST_GEOMETRY_HANDLE_TANGENCIES_WITH_OVERLAP_INFO bool prc = false, psc = false, rsc = false; overlap_info(pi, pj, ri, rj, si, sj, prc, psc, rsc); +#endif int const side_ri_p = m_strategy.apply(pi, pj, ri); int const side_rj_p = m_strategy.apply(pi, pj, rj); @@ -154,7 +189,6 @@ private : int const side_si_r = m_strategy.apply(ri, rj, si); int const side_sj_r = m_strategy.apply(ri, rj, sj); - std::cout << "Case: " << header << " for " << left.index << " / " << right.index << std::endl; #ifdef BOOST_GEOMETRY_DEBUG_HANDLE_TANGENCIES_MORE std::cout << " Segment p:" << geometry::wkt(pi) << " .. " << geometry::wkt(pj) << std::endl; std::cout << " Segment r:" << geometry::wkt(ri) << " .. " << geometry::wkt(rj) << std::endl; @@ -172,7 +206,9 @@ private : << " ri//p: " << side_ri_p << " si//p: " << side_si_p << " si//r: " << side_si_r +#if BOOST_GEOMETRY_HANDLE_TANGENCIES_WITH_OVERLAP_INFO << " cnts: " << int(prc) << "," << int(psc) << "," << int(rsc) +#endif //<< " idx: " << left.index << "/" << right.index ; @@ -365,9 +401,13 @@ private : #endif } +#if BOOST_GEOMETRY_HANDLE_TANGENCIES_WITH_OVERLAP_INFO // We need EXTRA information here: are p/r/s overlapping? bool pr_ov = false, ps_ov = false, rs_ov = false; overlap_info(pi, pj, ri, rj, si, sj, pr_ov, ps_ov, rs_ov); +#else + // std::cout << "Boost.Geometry: skipping overlap_info" << std::endl; +#endif // One coming from right (#83,#90) // One coming from left (#90, #94, #95) @@ -375,12 +415,14 @@ private : { bool ret = false; +#if BOOST_GEOMETRY_HANDLE_TANGENCIES_WITH_OVERLAP_INFO if (pr_ov || ps_ov) { int r = side_ri_p != 0 ? side_ri_p : side_si_p; ret = r * side_si_r == 1; } else +#endif { ret = side_si_r == 1; } @@ -397,6 +439,7 @@ private : // Take the one NOT overlapping bool ret = false; bool found = false; +#if BOOST_GEOMETRY_HANDLE_TANGENCIES_WITH_OVERLAP_INFO if (pr_ov && ! ps_ov) { ret = true; @@ -407,6 +450,7 @@ private : ret = false; found = true; } +#endif debug_consider(0, left, right, header, false, "aligned", ret); if (found) @@ -655,14 +699,14 @@ template typename TurnPoints, typename Geometry1, typename Geometry2, - typename RescalePolicy, + typename RobustPolicy, typename Strategy > inline void handle_cluster(Iterator begin_cluster, Iterator end_cluster, TurnPoints& turn_points, operation_type for_operation, Geometry1 const& geometry1, Geometry2 const& geometry2, - RescalePolicy& rescale_policy, + RobustPolicy& robust_policy, Strategy const& strategy) { // First inspect and (possibly) discard rows @@ -677,15 +721,15 @@ inline void handle_cluster(Iterator begin_cluster, Iterator end_cluster, TurnPoints, IndexType, Geometry1, Geometry2, - RescalePolicy, + RobustPolicy, Reverse1, Reverse2, Strategy - >(turn_points, geometry1, geometry2, rescale_policy, strategy)); + >(turn_points, geometry1, geometry2, robust_policy, strategy)); #if defined(BOOST_GEOMETRY_DEBUG_HANDLE_TANGENCIES) typedef typename IndexType::type operations_type; operations_type const& op = turn_points[begin_cluster->index].operations[begin_cluster->operation_index]; - std::cout << std::endl << "Clustered points on equal distance " << op.enriched.distance << std::endl; + std::cout << std::endl << "Clustered points on equal distance " << op.fraction << std::endl; std::cout << "->Indexes "; for (Iterator it = begin_cluster; it != end_cluster; ++it) diff --git a/include/boost/geometry/algorithms/detail/overlay/intersection_insert.hpp b/include/boost/geometry/algorithms/detail/overlay/intersection_insert.hpp index b6575ad3f..b3d3e80d8 100644 --- a/include/boost/geometry/algorithms/detail/overlay/intersection_insert.hpp +++ b/include/boost/geometry/algorithms/detail/overlay/intersection_insert.hpp @@ -33,7 +33,10 @@ #include #include #include -#include + +#include +#include +#include #include @@ -58,25 +61,58 @@ struct intersection_segment_segment_point template < typename Segment1, typename Segment2, + typename RobustPolicy, typename OutputIterator, typename Strategy > static inline OutputIterator apply(Segment1 const& segment1, - Segment2 const& segment2, OutputIterator out, + Segment2 const& segment2, + RobustPolicy const& robust_policy, + OutputIterator out, Strategy const& ) { 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) - segment_intersection_points is - = strategy::intersection::relate_cartesian_segments + typedef segment_intersection_points + < + point_type, + typename segment_ratio_type + < + point_type, RobustPolicy + >::type + > intersection_return_type; + + typedef strategy::intersection::relate_cartesian_segments < policies::relate::segments_intersection_points < - Segment1, - Segment2, - segment_intersection_points + intersection_return_type > - >::apply(segment1, segment2); + > policy; + + intersection_return_type is = policy::apply(segment1, segment2, + robust_policy, pi_rob, pj_rob, qi_rob, qj_rob); for (std::size_t i = 0; i < is.count; i++) { @@ -94,18 +130,25 @@ struct intersection_linestring_linestring_point template < typename Linestring1, typename Linestring2, + typename RobustPolicy, typename OutputIterator, typename Strategy > static inline OutputIterator apply(Linestring1 const& linestring1, - Linestring2 const& linestring2, OutputIterator out, + Linestring2 const& linestring2, + RobustPolicy const& robust_policy, + OutputIterator out, Strategy const& ) { typedef typename point_type::type point_type; - typedef detail::overlay::turn_info turn_info; + typedef detail::overlay::turn_info + < + point_type, + typename segment_ratio_type::type + > turn_info; std::deque turns; - geometry::get_intersection_points(linestring1, linestring2, turns); + geometry::get_intersection_points(linestring1, linestring2, robust_policy, turns); for (typename boost::range_iterator const>::type it = boost::begin(turns); it != boost::end(turns); ++it) @@ -149,9 +192,11 @@ struct intersection_of_linestring_with_areal template < typename LineString, typename Areal, + typename RobustPolicy, typename OutputIterator, typename Strategy > static inline OutputIterator apply(LineString const& linestring, Areal const& areal, + RobustPolicy const& robust_policy, OutputIterator out, Strategy const& ) { @@ -169,8 +214,11 @@ struct intersection_of_linestring_with_areal > follower; typedef typename point_type::type point_type; - - typedef detail::overlay::traversal_turn_info turn_info; + typedef detail::overlay::traversal_turn_info + < + point_type, + typename geometry::segment_ratio_type::type + > turn_info; std::deque turns; detail::get_turns::no_interrupt_policy policy; @@ -178,8 +226,8 @@ struct intersection_of_linestring_with_areal < false, (OverlayType == overlay_intersection ? ReverseAreal : !ReverseAreal), - detail::overlay::calculate_distance_policy - >(linestring, areal, detail::no_rescale_policy(), turns, policy); + detail::overlay::assign_null_policy + >(linestring, areal, robust_policy, turns, policy); if (turns.empty()) { @@ -195,8 +243,7 @@ struct intersection_of_linestring_with_areal return out; } - - if (follower::included(border_point, areal)) + if (follower::included(border_point, areal, robust_policy)) { LineStringOut copy; geometry::convert(linestring, copy); @@ -217,7 +264,7 @@ struct intersection_of_linestring_with_areal ( linestring, areal, geometry::detail::overlay::operation_intersection, - turns, out + turns, robust_policy, out ); } }; @@ -359,9 +406,11 @@ struct intersection_insert false, true, false > { - template + template static inline OutputIterator apply(Linestring const& linestring, - Box const& box, OutputIterator out, Strategy const& ) + Box const& box, + RobustPolicy const& , + OutputIterator out, Strategy const& ) { typedef typename point_type::type point_type; strategy::intersection::liang_barsky lb_strategy; @@ -435,9 +484,11 @@ struct intersection_insert false, true, false > { - template + template static inline OutputIterator apply(Segment const& segment, - Box const& box, OutputIterator out, Strategy const& ) + Box const& box, + RobustPolicy const& ,// TODO: propagate to clip_range_with_box + OutputIterator out, Strategy const& ) { geometry::segment_view range(segment); @@ -467,19 +518,25 @@ struct intersection_insert Areal1, Areal2, false > { - template + template static inline OutputIterator apply(Geometry1 const& geometry1, - Geometry2 const& geometry2, OutputIterator out, Strategy const& ) + Geometry2 const& geometry2, + RobustPolicy const& robust_policy, + OutputIterator out, Strategy const& ) { - typedef detail::overlay::turn_info turn_info; + typedef detail::overlay::turn_info + < + PointOut, + typename segment_ratio_type::type + > turn_info; std::vector turns; detail::get_turns::no_interrupt_policy policy; geometry::get_turns < false, false, detail::overlay::assign_null_policy - >(geometry1, geometry2, detail::no_rescale_policy(), turns, policy); + >(geometry1, geometry2, robust_policy, turns, policy); for (typename std::vector::const_iterator it = turns.begin(); it != turns.end(); ++it) { @@ -499,9 +556,11 @@ template > struct intersection_insert_reversed { - template + template static inline OutputIterator apply(Geometry1 const& g1, - Geometry2 const& g2, OutputIterator out, + Geometry2 const& g2, + RobustPolicy const& robust_policy, + OutputIterator out, Strategy const& strategy) { return intersection_insert @@ -509,7 +568,7 @@ struct intersection_insert_reversed Geometry2, Geometry1, GeometryOut, OverlayType, Reverse2, Reverse1, ReverseOut - >::apply(g2, g1, out, strategy); + >::apply(g2, g1, robust_policy, out, strategy); } }; @@ -656,35 +715,37 @@ template bool ReverseSecond, overlay_type OverlayType, typename Geometry1, typename Geometry2, + typename RobustPolicy, typename OutputIterator, typename Strategy > inline OutputIterator insert(Geometry1 const& geometry1, Geometry2 const& geometry2, + RobustPolicy robust_policy, OutputIterator out, Strategy const& strategy) { return boost::mpl::if_c + < + geometry::reverse_dispatch::type::value, + geometry::dispatch::intersection_insert_reversed < - geometry::reverse_dispatch::type::value, - geometry::dispatch::intersection_insert_reversed - < - Geometry1, Geometry2, - GeometryOut, - OverlayType, - overlay::do_reverse::value>::value, - overlay::do_reverse::value, ReverseSecond>::value, - overlay::do_reverse::value>::value - >, - geometry::dispatch::intersection_insert - < - Geometry1, Geometry2, - GeometryOut, - OverlayType, - geometry::detail::overlay::do_reverse::value>::value, - geometry::detail::overlay::do_reverse::value, ReverseSecond>::value - > - >::type::apply(geometry1, geometry2, out, strategy); + Geometry1, Geometry2, + GeometryOut, + OverlayType, + overlay::do_reverse::value>::value, + overlay::do_reverse::value, ReverseSecond>::value, + overlay::do_reverse::value>::value + >, + geometry::dispatch::intersection_insert + < + Geometry1, Geometry2, + GeometryOut, + OverlayType, + geometry::detail::overlay::do_reverse::value>::value, + geometry::detail::overlay::do_reverse::value, ReverseSecond>::value + > + >::type::apply(geometry1, geometry2, robust_policy, out, strategy); } @@ -723,10 +784,14 @@ inline OutputIterator intersection_insert(Geometry1 const& geometry1, concept::check(); concept::check(); + typedef typename Strategy::rescale_policy_type rescale_policy_type; + rescale_policy_type robust_policy + = geometry::get_rescale_policy(geometry1, geometry2); + return detail::intersection::insert < GeometryOut, false, overlay_intersection - >(geometry1, geometry2, out, strategy); + >(geometry1, geometry2, robust_policy, out, strategy); } @@ -760,12 +825,18 @@ inline OutputIterator intersection_insert(Geometry1 const& geometry1, concept::check(); concept::check(); + typedef typename geometry::rescale_policy_type + < + typename geometry::point_type::type // TODO from both + >::type rescale_policy_type; + typedef strategy_intersection < typename cs_tag::type, Geometry1, Geometry2, - typename geometry::point_type::type + typename geometry::point_type::type, + rescale_policy_type > strategy; return intersection_insert(geometry1, geometry2, out, diff --git a/include/boost/geometry/algorithms/detail/overlay/linear_linear.hpp b/include/boost/geometry/algorithms/detail/overlay/linear_linear.hpp index 62789f341..d0a4d56f0 100644 --- a/include/boost/geometry/algorithms/detail/overlay/linear_linear.hpp +++ b/include/boost/geometry/algorithms/detail/overlay/linear_linear.hpp @@ -144,10 +144,10 @@ protected: typename IntersectionInfo, typename DirInfo > - static inline void apply(Info& info, Point1 const& p1, Point2 const& p2, - IntersectionInfo const& ii, DirInfo const& di) + static inline void apply(Info& , Point1 const& , Point2 const& , + IntersectionInfo const& , DirInfo const& ) { - calculate_distance_policy::apply(info, p1, p2, ii, di); + //calculate_distance_policy::apply(info, p1, p2, ii, di); } }; @@ -224,10 +224,11 @@ protected: public: template < - typename OutputIterator, typename Strategy + typename RobustPolicy, typename OutputIterator, typename Strategy > static inline OutputIterator apply(Linear1 const& linear1, Linear2 const& linear2, + RobustPolicy const&, OutputIterator oit, Strategy const& ) { @@ -244,9 +245,6 @@ public: if ( turns.empty() ) { // the two linear geometries are disjoint -#ifdef GEOMETRY_TEST_DEBUG - std::cout << "NO INTERSECTIONS" << std::endl; -#endif return linear_linear_no_intersections < LinestringOut, @@ -284,10 +282,11 @@ struct linear_linear_linestring { template < - typename OutputIterator, typename Strategy + typename RobustPolicy, typename OutputIterator, typename Strategy > static inline OutputIterator apply(Linear1 const& linear1, Linear2 const& linear2, + RobustPolicy const& robust_policy, OutputIterator oit, Strategy const& strategy) { @@ -304,7 +303,7 @@ struct linear_linear_linestring Linear2, Linear1, LinestringOut, overlay_difference, EnableFilterContinueTurns, EnableRemoveDuplicateTurns, EnableDegenerateTurns - >::apply(linear2, linear1, oit, strategy); + >::apply(linear2, linear1, robust_policy, oit, strategy); } }; diff --git a/include/boost/geometry/algorithms/detail/overlay/overlay.hpp b/include/boost/geometry/algorithms/detail/overlay/overlay.hpp index 7328148bd..c194283f9 100644 --- a/include/boost/geometry/algorithms/detail/overlay/overlay.hpp +++ b/include/boost/geometry/algorithms/detail/overlay/overlay.hpp @@ -18,7 +18,6 @@ #include -#include #include #include #include @@ -27,7 +26,7 @@ #include #include -#include +#include #include #include @@ -38,6 +37,9 @@ #include #include +#include + + #ifdef BOOST_GEOMETRY_DEBUG_ASSEMBLE # include #endif @@ -156,9 +158,10 @@ template > struct overlay { - template + template static inline OutputIterator apply( Geometry1 const& geometry1, Geometry2 const& geometry2, + RobustPolicy const& robust_policy, OutputIterator out, Strategy const& ) { @@ -177,8 +180,13 @@ struct overlay >(geometry1, geometry2, out); } + typedef typename geometry::coordinate_type::type coordinate_type; typedef typename geometry::point_type::type point_type; - typedef detail::overlay::traversal_turn_info turn_info; + typedef detail::overlay::traversal_turn_info + < + point_type, + typename geometry::segment_ratio_type::type + > turn_info; typedef std::deque container_type; typedef std::deque @@ -192,8 +200,6 @@ struct overlay boost::timer timer; #endif - detail::no_rescale_policy rescale_policy; - #ifdef BOOST_GEOMETRY_DEBUG_ASSEMBLE std::cout << "get turns" << std::endl; #endif @@ -201,8 +207,8 @@ std::cout << "get turns" << std::endl; geometry::get_turns < Reverse1, Reverse2, - detail::overlay::calculate_distance_policy - >(geometry1, geometry2, rescale_policy, turn_points, policy); + detail::overlay::assign_null_policy + >(geometry1, geometry2, robust_policy, turn_points, policy); #ifdef BOOST_GEOMETRY_TIME_OVERLAY std::cout << "get_turns: " << timer.elapsed() << std::endl; @@ -217,7 +223,7 @@ std::cout << "enrich" << std::endl; ? geometry::detail::overlay::operation_union : geometry::detail::overlay::operation_intersection, geometry1, geometry2, - rescale_policy, + robust_policy, side_strategy); #ifdef BOOST_GEOMETRY_TIME_OVERLAY @@ -238,7 +244,7 @@ std::cout << "traverse" << std::endl; Direction == overlay_union ? geometry::detail::overlay::operation_union : geometry::detail::overlay::operation_intersection, - rescale_policy, + robust_policy, turn_points, rings ); diff --git a/include/boost/geometry/algorithms/detail/overlay/pointlike_pointlike.hpp b/include/boost/geometry/algorithms/detail/overlay/pointlike_pointlike.hpp index 4150a2514..8a63e78aa 100644 --- a/include/boost/geometry/algorithms/detail/overlay/pointlike_pointlike.hpp +++ b/include/boost/geometry/algorithms/detail/overlay/pointlike_pointlike.hpp @@ -142,9 +142,10 @@ template > struct point_point_point { - template + template static inline OutputIterator apply(Point1 const& point1, Point2 const& point2, + RobustPolicy const& , OutputIterator oit, Strategy const&) { @@ -175,9 +176,10 @@ template > struct multipoint_point_point { - template + template static inline OutputIterator apply(MultiPoint const& multipoint, Point const& point, + RobustPolicy const& , OutputIterator oit, Strategy const&) { @@ -209,9 +211,10 @@ template > struct point_multipoint_point { - template + template static inline OutputIterator apply(Point const& point, MultiPoint const& multipoint, + RobustPolicy const& , OutputIterator oit, Strategy const&) { @@ -244,9 +247,10 @@ template > struct multipoint_multipoint_point { - template + template static inline OutputIterator apply(MultiPoint1 const& multipoint1, MultiPoint2 const& multipoint2, + RobustPolicy const& robust_policy, OutputIterator oit, Strategy const& strategy) { @@ -256,7 +260,7 @@ struct multipoint_multipoint_point return multipoint_multipoint_point < MultiPoint2, MultiPoint1, PointOut, OverlayType - >::apply(multipoint2, multipoint1, oit, strategy); + >::apply(multipoint2, multipoint1, robust_policy, oit, strategy); } std::vector::type> @@ -399,9 +403,10 @@ template > struct union_pointlike_pointlike_point { - template + template static inline OutputIterator apply(PointLike1 const& pointlike1, PointLike2 const& pointlike2, + RobustPolicy const& robust_policy, OutputIterator oit, Strategy const& strategy) { @@ -412,7 +417,7 @@ struct union_pointlike_pointlike_point PointLike2, PointLike1, PointOut, overlay_difference, typename tag::type, typename tag::type - >::apply(pointlike2, pointlike1, oit, strategy); + >::apply(pointlike2, pointlike1, robust_policy, oit, strategy); } }; diff --git a/include/boost/geometry/algorithms/detail/overlay/self_turn_points.hpp b/include/boost/geometry/algorithms/detail/overlay/self_turn_points.hpp index ec757359f..fd6182ee0 100644 --- a/include/boost/geometry/algorithms/detail/overlay/self_turn_points.hpp +++ b/include/boost/geometry/algorithms/detail/overlay/self_turn_points.hpp @@ -55,18 +55,18 @@ template typename Geometry, typename Turns, typename TurnPolicy, - typename RescalePolicy, + typename RobustPolicy, typename InterruptPolicy > struct self_section_visitor { Geometry const& m_geometry; - RescalePolicy const& m_rescale_policy; + RobustPolicy const& m_rescale_policy; Turns& m_turns; InterruptPolicy& m_interrupt_policy; inline self_section_visitor(Geometry const& g, - RescalePolicy const& rp, + RobustPolicy const& rp, Turns& turns, InterruptPolicy& ip) : m_geometry(g) , m_rescale_policy(rp) @@ -110,10 +110,10 @@ struct self_section_visitor template struct get_turns { - template + template static inline bool apply( Geometry const& geometry, - RescalePolicy const& rescale_policy, + RobustPolicy const& robust_policy, Turns& turns, InterruptPolicy& interrupt_policy) { @@ -127,13 +127,13 @@ struct get_turns > sections_type; sections_type sec; - geometry::sectionalize(geometry, rescale_policy, false, sec); + geometry::sectionalize(geometry, robust_policy, false, sec); self_section_visitor < Geometry, - Turns, TurnPolicy, RescalePolicy, InterruptPolicy - > visitor(geometry, rescale_policy, turns, interrupt_policy); + Turns, TurnPolicy, RobustPolicy, InterruptPolicy + > visitor(geometry, robust_policy, turns, interrupt_policy); try { @@ -198,10 +198,10 @@ struct self_get_turn_points TurnPolicy > { - template + template static inline bool apply( Box const& , - RescalePolicy const& , + RobustPolicy const& , Turns& , InterruptPolicy& ) { @@ -243,12 +243,12 @@ template < typename AssignPolicy, typename Geometry, - typename RescalePolicy, + typename RobustPolicy, typename Turns, typename InterruptPolicy > inline void self_turns(Geometry const& geometry, - RescalePolicy const& rescale_policy, + RobustPolicy const& robust_policy, Turns& turns, InterruptPolicy& interrupt_policy) { concept::check(); @@ -260,7 +260,7 @@ inline void self_turns(Geometry const& geometry, typename tag::type, Geometry, TurnPolicy - >::apply(geometry, rescale_policy, turns, interrupt_policy); + >::apply(geometry, robust_policy, turns, interrupt_policy); } diff --git a/include/boost/geometry/algorithms/detail/overlay/stream_info.hpp b/include/boost/geometry/algorithms/detail/overlay/stream_info.hpp index eebe38194..51fd1b3dc 100644 --- a/include/boost/geometry/algorithms/detail/overlay/stream_info.hpp +++ b/include/boost/geometry/algorithms/detail/overlay/stream_info.hpp @@ -35,7 +35,6 @@ namespace detail { namespace overlay template std::ostream& operator<<(std::ostream &os, turn_info

const& info) { - typename geometry::coordinate_type

::type d = info.distance; os << "\t" << " src " << info.seg_id.source_index << " seg " << info.seg_id.segment_index @@ -54,7 +53,7 @@ namespace detail { namespace overlay << " nxt seg " << info.travels_to_vertex_index << " , ip " << info.travels_to_ip_index << " , or " << info.next_ip_index - << " dst " << double(d) + << " frac " << info.fraction << info.visit_state; if (info.flagged) { diff --git a/include/boost/geometry/algorithms/detail/overlay/traversal_info.hpp b/include/boost/geometry/algorithms/detail/overlay/traversal_info.hpp index 810a27af0..6ee32c17c 100644 --- a/include/boost/geometry/algorithms/detail/overlay/traversal_info.hpp +++ b/include/boost/geometry/algorithms/detail/overlay/traversal_info.hpp @@ -24,15 +24,21 @@ namespace detail { namespace overlay { -template -struct traversal_turn_operation : public turn_operation +template +struct traversal_turn_operation : public turn_operation { - enrichment_info

enriched; + enrichment_info enriched; visit_info visited; }; -template -struct traversal_turn_info : public turn_info > +template +struct traversal_turn_info + : public turn_info + < + Point, + SegmentRatio, + traversal_turn_operation + > {}; diff --git a/include/boost/geometry/algorithms/detail/overlay/traverse.hpp b/include/boost/geometry/algorithms/detail/overlay/traverse.hpp index 3317dcea8..d3c9997e8 100644 --- a/include/boost/geometry/algorithms/detail/overlay/traverse.hpp +++ b/include/boost/geometry/algorithms/detail/overlay/traverse.hpp @@ -13,7 +13,6 @@ #include -#include #include #include #include @@ -94,14 +93,16 @@ template typename G1, typename G2, typename Turns, - typename IntersectionInfo + typename IntersectionInfo, + typename RobustPolicy > inline bool assign_next_ip(G1 const& g1, G2 const& g2, Turns& turns, typename boost::range_iterator::type& ip, GeometryOut& current_output, IntersectionInfo& info, - segment_identifier& seg_id) + segment_identifier& seg_id, + RobustPolicy const& robust_policy) { info.visited.set_visited(); set_visited_for_continue(*ip, info); @@ -122,12 +123,14 @@ inline bool assign_next_ip(G1 const& g1, G2 const& g2, { geometry::copy_segments(g1, info.seg_id, info.enriched.travels_to_vertex_index, + robust_policy, current_output); } else { geometry::copy_segments(g2, info.seg_id, info.enriched.travels_to_vertex_index, + robust_policy, current_output); } seg_id = info.seg_id; @@ -139,7 +142,8 @@ inline bool assign_next_ip(G1 const& g1, G2 const& g2, seg_id = info.seg_id; } - detail::overlay::append_no_dups_or_spikes(current_output, ip->point); + detail::overlay::append_no_dups_or_spikes(current_output, ip->point, + robust_policy); return true; } @@ -230,11 +234,11 @@ template class traverse { public : - template + template static inline void apply(Geometry1 const& geometry1, Geometry2 const& geometry2, detail::overlay::operation_type operation, - RescalePolicy const& rescale_policy, + RobustPolicy const& robust_policy, Turns& turns, Rings& rings) { typedef typename boost::range_value::type ring_type; @@ -279,7 +283,8 @@ public : set_visited_for_continue(*it, *iit); ring_type current_output; - geometry::append(current_output, it->point); + detail::overlay::append_no_dups_or_spikes(current_output, + it->point, robust_policy); turn_iterator current = it; turn_operation_iterator_type current_iit = iit; @@ -289,13 +294,14 @@ public : geometry1, geometry2, turns, current, current_output, - *iit, current_seg_id)) + *iit, current_seg_id, + robust_policy)) { Backtrack::apply( size_at_start, rings, current_output, turns, *current_iit, "No next IP", - geometry1, geometry2, rescale_policy, state); + geometry1, geometry2, robust_policy, state); } if (! detail::overlay::select_next_ip( @@ -308,7 +314,7 @@ public : size_at_start, rings, current_output, turns, *iit, "Dead end at start", - geometry1, geometry2, rescale_policy, state); + geometry1, geometry2, robust_policy, state); } else { @@ -330,7 +336,7 @@ public : size_at_start, rings, current_output, turns, *iit, "Visit again", - geometry1, geometry2, rescale_policy, state); + geometry1, geometry2, robust_policy, state); } else { @@ -349,7 +355,8 @@ public : detail::overlay::assign_next_ip( geometry1, geometry2, turns, current, current_output, - *current_iit, current_seg_id); + *current_iit, current_seg_id, + robust_policy); if (! detail::overlay::select_next_ip( operation, @@ -364,7 +371,7 @@ public : size_at_start, rings, current_output, turns, *iit, "Dead end", - geometry1, geometry2, rescale_policy, state); + geometry1, geometry2, robust_policy, state); } else { @@ -380,7 +387,7 @@ public : size_at_start, rings, current_output, turns, *iit, "Endless loop", - geometry1, geometry2, rescale_policy, state); + geometry1, geometry2, robust_policy, state); } } } @@ -391,6 +398,7 @@ public : detail::overlay::debug_traverse(*current, *iit, "->Finished"); if (geometry::num_points(current_output) >= min_num_points) { + clean_closing_dups_and_spikes(current_output, robust_policy); rings.push_back(current_output); } } diff --git a/include/boost/geometry/algorithms/detail/overlay/turn_info.hpp b/include/boost/geometry/algorithms/detail/overlay/turn_info.hpp index 6bd8d3156..9dd54d377 100644 --- a/include/boost/geometry/algorithms/detail/overlay/turn_info.hpp +++ b/include/boost/geometry/algorithms/detail/overlay/turn_info.hpp @@ -54,11 +54,13 @@ enum method_type The class is to be included in the turn_info class, either direct or a derived or similar class with more (e.g. enrichment) information. */ +template struct turn_operation { operation_type operation; segment_identifier seg_id; segment_identifier other_id; + SegmentRatio fraction; inline turn_operation() : operation(operation_none) @@ -78,7 +80,8 @@ struct turn_operation template < typename Point, - typename Operation = turn_operation, + typename SegmentRatio, + typename Operation = turn_operation, typename Container = boost::array > struct turn_info 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 23078bf64..cd3acb5ba 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 @@ -14,6 +14,8 @@ #include #include +#include +#include #include #include @@ -25,8 +27,18 @@ namespace boost { namespace geometry namespace detail { +// Checks if a point ("last_point") causes a spike w.r.t. +// the specified two other points (segment_a, segment_b) +// +// x-------x------x +// a lp b +// +// Above, lp generates a spike w.r.t. segment(a,b) +// So specify last point first, then (a,b) (this is unordered, so unintuitive) template -static inline bool point_is_spike_or_equal(Point1 const& last_point, Point2 const& segment_a, Point3 const& segment_b) +static inline bool point_is_spike_or_equal(Point1 const& last_point, + Point2 const& segment_a, + Point3 const& segment_b) { typedef typename strategy::side::services::default_strategy < @@ -62,6 +74,49 @@ static inline bool point_is_spike_or_equal(Point1 const& last_point, Point2 cons return false; } +template +< + typename Point1, + typename Point2, + typename Point3, + typename RobustPolicy +> +static inline bool point_is_spike_or_equal(Point1 const& last_point, + Point2 const& segment_a, + Point3 const& segment_b, + RobustPolicy const& robust_policy) +{ + if (point_is_spike_or_equal(last_point, segment_a, segment_b)) + { + return true; + } + + if (! RobustPolicy::enabled) + { + return false; + } + + // Try using specified robust policy + typedef typename geometry::robust_point_type + < + Point1, + RobustPolicy + >::type robust_point_type; + + robust_point_type last_point_rob, segment_a_rob, segment_b_rob; + geometry::recalculate(last_point_rob, last_point, robust_policy); + geometry::recalculate(segment_a_rob, segment_a, robust_policy); + geometry::recalculate(segment_b_rob, segment_b, robust_policy); + + return point_is_spike_or_equal + ( + last_point_rob, + segment_a_rob, + segment_b_rob + ); +} + + } // namespace detail #endif diff --git a/include/boost/geometry/algorithms/detail/recalculate.hpp b/include/boost/geometry/algorithms/detail/recalculate.hpp index 03f634eac..4e3e883a2 100644 --- a/include/boost/geometry/algorithms/detail/recalculate.hpp +++ b/include/boost/geometry/algorithms/detail/recalculate.hpp @@ -22,6 +22,7 @@ #include #include #include +#include #include #include @@ -33,9 +34,6 @@ #include -#include - - namespace boost { namespace geometry { @@ -72,7 +70,7 @@ struct recalculate_indexed static inline void apply(Geometry1& geometry1, Geometry2 const& geometry2, Strategy const& strategy) { // Do it for both indices in one dimension - std::size_t const dim = Dimension - 1; + static std::size_t const dim = Dimension - 1; geometry::set<0, dim>(geometry1, strategy.template apply(geometry::get<0, dim>(geometry2))); geometry::set<1, dim>(geometry1, strategy.template apply(geometry::get<1, dim>(geometry2))); recalculate_indexed::apply(geometry1, geometry2, strategy); @@ -89,7 +87,71 @@ struct recalculate_indexed<0> } }; +struct range_to_range +{ + template + < + typename Range1, + typename Range2, + typename Strategy + > + static inline void apply(Range1& destination, Range2 const& source, + Strategy const& strategy) + { + typedef typename geometry::point_type::type point_type; + typedef recalculate_point::value> per_point; + geometry::clear(destination); + for (typename boost::range_iterator::type it + = boost::begin(source); + it != boost::end(source); + ++it) + { + point_type p; + per_point::apply(p, *it, strategy); + geometry::append(destination, p); + } + } +}; + +struct polygon_to_polygon +{ + template + < + typename Polygon1, + typename Polygon2, + typename Strategy + > + static inline void apply(Polygon1& destination, Polygon2 const& source, + Strategy const& strategy) + { + typedef range_to_range per_ring; + + per_ring::apply(geometry::exterior_ring(destination), + geometry::exterior_ring(source), strategy); + + traits::resize + < + typename boost::remove_reference + < + typename traits::interior_mutable_type::type + >::type + >::apply(interior_rings(destination), num_interior_rings(source)); + + typename interior_return_type::type rings_dest + = interior_rings(destination); + typename interior_return_type::type rings_source + = interior_rings(source); + + BOOST_AUTO_TPL(it_source, boost::begin(rings_source)); + BOOST_AUTO_TPL(it_dest, boost::begin(rings_dest)); + + for ( ; it_source != boost::end(rings_source); ++it_source, ++it_dest) + { + per_ring::apply(*it_dest, *it_source, strategy); + } + } +}; }} // namespace detail::recalculate #endif // DOXYGEN_NO_DETAIL @@ -105,14 +167,8 @@ template typename Tag1 = typename geometry::tag::type, typename Tag2 = typename geometry::tag::type > -struct recalculate -{ - BOOST_MPL_ASSERT_MSG - ( - false, NOT_OR_NOT_YET_IMPLEMENTED_FOR_THIS_GEOMETRY_TYPE - , (types) - ); -}; +struct recalculate : not_implemented +{}; template struct recalculate @@ -129,6 +185,10 @@ struct recalculate : detail::recalculate::recalculate_indexed::value> {}; +template +struct recalculate + : detail::recalculate::polygon_to_polygon +{}; } // namespace dispatch #endif // DOXYGEN_NO_DISPATCH diff --git a/include/boost/geometry/algorithms/detail/relate/areal_areal.hpp b/include/boost/geometry/algorithms/detail/relate/areal_areal.hpp index bc5b619a7..fea695e7c 100644 --- a/include/boost/geometry/algorithms/detail/relate/areal_areal.hpp +++ b/include/boost/geometry/algorithms/detail/relate/areal_areal.hpp @@ -17,6 +17,8 @@ #include #include +#include +#include #include #include @@ -193,7 +195,7 @@ struct areal_areal // TODO: If Areal geometry may have infinite size, change the following line: // The result should be FFFFFFFFF - set::value>(result);// FFFFFFFFd, d in [1,9] or T + relate::set::value>(result);// FFFFFFFFd, d in [1,9] or T if ( result.interrupt ) return; @@ -561,13 +563,6 @@ struct areal_areal static const bool transpose_result = OpId != 0; static const int other_id = (OpId + 1) % 2; - static const iterate_direction direction = order_as_direction::value>::value; - static const closure_selector closure = geometry::closure::value; - - typedef typename ring_type::type ring_type; - typedef typename reversible_view::type reversible_type; - typedef typename closeable_view::type closeable_type; - public: inline uncertain_rings_analyser(Result & result, Geometry const& geom, diff --git a/include/boost/geometry/algorithms/detail/relate/boundary_checker.hpp b/include/boost/geometry/algorithms/detail/relate/boundary_checker.hpp index d7506a40e..99553b9fe 100644 --- a/include/boost/geometry/algorithms/detail/relate/boundary_checker.hpp +++ b/include/boost/geometry/algorithms/detail/relate/boundary_checker.hpp @@ -12,6 +12,7 @@ #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_RELATE_BOUNDARY_CHECKER_HPP #include +#include #include #include @@ -54,34 +55,6 @@ public: return has_boundary; } - template - bool is_boundary(point_type const& pt, segment_identifier const& sid) const - { - if ( !has_boundary ) - return false; - - if ( BoundaryQuery == boundary_front ) - { - return sid.segment_index == 0 - && detail::equals::equals_point_point(pt, range::front(geometry)); - } - else if ( BoundaryQuery == boundary_back ) - { - return sid.segment_index + 2 == geometry::num_points(geometry) - && detail::equals::equals_point_point(pt, range::back(geometry)); - } - else if ( BoundaryQuery == boundary_any ) - { - return ( sid.segment_index == 0 - && detail::equals::equals_point_point(pt, range::front(geometry)) ) - || ( sid.segment_index + 2 == geometry::num_points(geometry) - && detail::equals::equals_point_point(pt, range::back(geometry)) ); - } - - BOOST_ASSERT(false); - return false; - } - private: bool has_boundary; Geometry const& geometry; @@ -97,41 +70,10 @@ public: : is_filled(false), geometry(g) {} - template - bool is_endpoint_boundary(point_type const& pt) const - { - return is_boundary_point(pt); - } - - template - bool is_boundary(point_type const& pt, segment_identifier const& sid) const - { - if ( BoundaryQuery == boundary_front ) - { - if ( sid.segment_index != 0 ) - return false; - } - - if ( BoundaryQuery == boundary_back ) - { - if ( sid.segment_index + 2 != geometry::num_points(sub_range(geometry, sid)) ) - return false; - } - - if ( BoundaryQuery == boundary_any ) - { - if ( sid.segment_index != 0 - && sid.segment_index + 2 != geometry::num_points(sub_range(geometry, sid)) ) - return false; - } - - return is_boundary_point(pt); - } - -private: // First call O(NlogN) // Each next call O(logN) - bool is_boundary_point(point_type const& pt) const + template + bool is_endpoint_boundary(point_type const& pt) const { typedef typename boost::range_size::type size_type; size_type multi_count = boost::size(geometry); @@ -176,6 +118,7 @@ private: return equal_points_count % 2 != 0;// && equal_points_count > 0; // the number is odd and > 0 } +private: mutable bool is_filled; // TODO: store references/pointers instead of points? mutable std::vector boundary_points; diff --git a/include/boost/geometry/algorithms/detail/relate/follow_helpers.hpp b/include/boost/geometry/algorithms/detail/relate/follow_helpers.hpp index 0521f132e..78fa03798 100644 --- a/include/boost/geometry/algorithms/detail/relate/follow_helpers.hpp +++ b/include/boost/geometry/algorithms/detail/relate/follow_helpers.hpp @@ -23,9 +23,8 @@ namespace boost { namespace geometry #ifndef DOXYGEN_NO_DETAIL namespace detail { namespace relate { -// TODO: -// For 1-point linestrings or with all equal points turns won't be generated! -// Check for those degenerated cases may be connected with this one! +// NOTE: This iterates through single geometries for which turns were not generated. +// It doesn't mean that the geometry is disjoint, only that no turns were detected. template // WARNING! This class stores pointers! // Passing a reference to local variable will result in undefined behavior! - -// TODO: rename to point_id_ref? template -class point_identifier +class point_info { public: - point_identifier() : sid_ptr(0), pt_ptr(0) {} - point_identifier(segment_identifier const& sid, Point const& pt) + point_info() : sid_ptr(NULL), pt_ptr(NULL) {} + point_info(Point const& pt, segment_identifier const& sid) : sid_ptr(boost::addressof(sid)) , pt_ptr(boost::addressof(pt)) {} @@ -165,10 +162,10 @@ private: // WARNING! This class stores pointers! // Passing a reference to local variable will result in undefined behavior! -class same_single_geometry +class same_single { public: - same_single_geometry(segment_identifier const& sid) + same_single(segment_identifier const& sid) : sid_ptr(boost::addressof(sid)) {} @@ -178,7 +175,7 @@ public: } template - bool operator()(point_identifier const& pid) const + bool operator()(point_info const& pid) const { return operator()(pid.seg_id()); } @@ -206,12 +203,12 @@ private: // WARNING! This class stores pointers! // Passing a reference to local variable will result in undefined behavior! -template +template class segment_watcher { public: segment_watcher() - : m_seg_id_ptr(0) + : m_seg_id_ptr(NULL) {} bool update(segment_identifier const& seg_id) @@ -234,21 +231,24 @@ class exit_watcher static const std::size_t other_op_id = (OpId + 1) % 2; typedef typename TurnInfo::point_type point_type; - typedef point_identifier point_info; + typedef detail::relate::point_info point_info; public: exit_watcher() - : exit_operation(overlay::operation_none) - , exit_turn(0) + : m_exit_operation(overlay::operation_none) + , m_exit_turn_ptr(NULL) {} void enter(TurnInfo const& turn) { - other_entry_points.push_back( - point_info(turn.operations[other_op_id].seg_id, turn.point) ); + m_other_entry_points.push_back( + point_info(turn.point, turn.operations[other_op_id].seg_id) ); } - void exit(TurnInfo const& turn) + // TODO: exit_per_geometry parameter looks not very safe + // wrong value may be easily passed + + void exit(TurnInfo const& turn, bool exit_per_geometry = true) { //segment_identifier const& seg_id = turn.operations[op_id].seg_id; segment_identifier const& other_id = turn.operations[other_op_id].seg_id; @@ -256,63 +256,76 @@ public: typedef typename std::vector::iterator point_iterator; // search for the entry point in the same range of other geometry - point_iterator entry_it = std::find_if(other_entry_points.begin(), - other_entry_points.end(), - same_single_geometry(other_id)); + point_iterator entry_it = std::find_if(m_other_entry_points.begin(), + m_other_entry_points.end(), + same_single(other_id)); // this end point has corresponding entry point - if ( entry_it != other_entry_points.end() ) + if ( entry_it != m_other_entry_points.end() ) { - // here we know that we possibly left LS - // we must still check if we didn't get back on the same point - exit_operation = exit_op; - exit_turn = boost::addressof(turn); - // erase the corresponding entry point - other_entry_points.erase(entry_it); + m_other_entry_points.erase(entry_it); + + if ( exit_per_geometry || m_other_entry_points.empty() ) + { + // here we know that we possibly left LS + // we must still check if we didn't get back on the same point + m_exit_operation = exit_op; + m_exit_turn_ptr = boost::addressof(turn); + } } } bool is_outside() const { // if we didn't entered anything in the past, we're outside - return other_entry_points.empty(); + return m_other_entry_points.empty(); + } + + bool is_outside(TurnInfo const& turn) const + { + return m_other_entry_points.empty() + || std::find_if(m_other_entry_points.begin(), + m_other_entry_points.end(), + same_single( + turn.operations[other_op_id].seg_id)) + == m_other_entry_points.end(); } overlay::operation_type get_exit_operation() const { - return exit_operation; + return m_exit_operation; } point_type const& get_exit_point() const { - BOOST_ASSERT(exit_operation != overlay::operation_none); - BOOST_ASSERT(exit_turn); - return exit_turn->point; + BOOST_ASSERT(m_exit_operation != overlay::operation_none); + BOOST_ASSERT(m_exit_turn_ptr); + return m_exit_turn_ptr->point; } TurnInfo const& get_exit_turn() const { - BOOST_ASSERT(exit_operation != overlay::operation_none); - BOOST_ASSERT(exit_turn); - return *exit_turn; + BOOST_ASSERT(m_exit_operation != overlay::operation_none); + BOOST_ASSERT(m_exit_turn_ptr); + return *m_exit_turn_ptr; } void reset_detected_exit() { - exit_operation = overlay::operation_none; + m_exit_operation = overlay::operation_none; } void reset() { - exit_operation = overlay::operation_none; - other_entry_points.clear(); + m_exit_operation = overlay::operation_none; + m_other_entry_points.clear(); } private: - overlay::operation_type exit_operation; - const TurnInfo * exit_turn; - std::vector other_entry_points; // TODO: use map here or sorted vector? + overlay::operation_type m_exit_operation; + const TurnInfo * m_exit_turn_ptr; + std::vector m_other_entry_points; // TODO: use map here or sorted vector? }; template @@ -327,8 +340,10 @@ inline bool turn_on_the_same_ip(Turn const& prev_turn, Turn const& curr_turn) return false; } + // TODO: will this work if between segments there will be some number of degenerated ones? + if ( prev_seg_id.segment_index != curr_seg_id.segment_index - && ( ! geometry::math::equals(curr_turn.operations[OpId].enriched.distance, 0) + && ( ! curr_turn.operations[OpId].fraction.is_zero() || prev_seg_id.segment_index + 1 != curr_seg_id.segment_index ) ) { return false; @@ -361,97 +376,22 @@ static inline bool is_ip_on_boundary(IntersectionPoint const& ip, // IP on the last point of the linestring if ( (BoundaryQuery == boundary_back || BoundaryQuery == boundary_any) - && operation_info.operation == overlay::operation_blocked ) + && operation_info.position == overlay::position_back ) { - BOOST_ASSERT(operation_info.position == overlay::position_back); // check if this point is a boundary res = boundary_checker.template is_endpoint_boundary(ip); - -#ifdef BOOST_GEOMETRY_DEBUG_RELATE - BOOST_ASSERT(res == boundary_checker.template is_boundary(ip, seg_id)); -#endif } // IP on the last point of the linestring else if ( (BoundaryQuery == boundary_front || BoundaryQuery == boundary_any) - && operation_info.position == overlay::position_front ) + && operation_info.position == overlay::position_front ) { // check if this point is a boundary res = boundary_checker.template is_endpoint_boundary(ip); - -#ifdef BOOST_GEOMETRY_DEBUG_RELATE - BOOST_ASSERT(res == boundary_checker.template is_boundary(ip, seg_id)); -#endif - } - // IP somewhere in the interior - else - { -#ifdef BOOST_GEOMETRY_DEBUG_RELATE - BOOST_ASSERT(res == boundary_checker.template is_boundary(ip, seg_id)); -#endif } return res; } -// TODO: The tool like this would be useful but this can't be done with the current implementation of -// reversible and closeable views because the reference to local variable would be returned! - -//template -//struct normalized_range_type -//{ -// static const iterate_direction direction = order_as_direction::value>::value; -// static const closure_selector closure = geometry::closure::value; -// -// typedef typename ring_type::type ring_type; -// typedef typename reversible_view -// < -// typename boost::mpl::if_c -// < -// boost::is_const::value, -// ring_type const, -// ring_type -// >::type, -// direction -// >::type reversible_type; -// typedef typename closeable_view -// < -// typename boost::mpl::if_c -// < -// boost::is_const::value, -// reversible_type const, -// reversible_type -// >::type, -// closure -// >::type closeable_type; -// -// typedef closeable_type type; -//}; -// -//template -//struct normalized_range -//{ -// template -// static inline -// typename normalized_range_type::type -// apply(Range & rng) -// { -// typename normalized_range_type::reversible_type -// rev_view(rng); -// typename normalized_range_type::closeable_type -// view(rev_view); -// -//// ERROR! HERE THE REFERENCE TO LOCAL rev_view IS RETURNED! -// return view; -// } -//}; -// -//template -//inline -//typename normalized_range_type::type -//normalized_sub_range(Geometry & geometry, Id const& id) -//{ -// return normalized_range::apply(detail::sub_range(geometry, id)); -//} }} // namespace detail::relate #endif // DOXYGEN_NO_DETAIL diff --git a/include/boost/geometry/algorithms/detail/relate/linear_areal.hpp b/include/boost/geometry/algorithms/detail/relate/linear_areal.hpp index 880f1e483..40c161582 100644 --- a/include/boost/geometry/algorithms/detail/relate/linear_areal.hpp +++ b/include/boost/geometry/algorithms/detail/relate/linear_areal.hpp @@ -17,6 +17,8 @@ #include #include +#include +#include #include #include @@ -25,6 +27,8 @@ #include #include +#include + namespace boost { namespace geometry { @@ -194,7 +198,7 @@ struct linear_areal // TODO: If Areal geometry may have infinite size, change the following line: // The result should be FFFFFFFFF - set::value, TransposeResult>(result);// FFFFFFFFd, d in [1,9] or T + relate::set::value, TransposeResult>(result);// FFFFFFFFd, d in [1,9] or T if ( result.interrupt ) return; @@ -232,20 +236,14 @@ struct linear_areal // This is set here because in the case if empty Areal geometry were passed // those shouldn't be set - set(result);// FFFFFF2Fd + relate::set(result);// FFFFFF2Fd if ( result.interrupt ) return; { // for different multi or same ring id: x, u, i, c // for same multi and different ring id: c, i, u, x - typedef turns::less - < - 0, turns::less_greater_op_for_other_same_m_diff_r - < - turns::op_to_int<0,2,3,1,4,0> - > - > less; + typedef turns::less<0, turns::less_op_linear_areal> less; std::sort(turns.begin(), turns.end(), less()); turns_analyser analyser; @@ -261,7 +259,7 @@ struct linear_areal // If 'c' (insersection_boundary) was not found we know that any Ls isn't equal to one of the Rings if ( !interrupt_policy.is_boundary_found ) { - set(result); + relate::set(result); } // Don't calculate it if it's required else if ( may_update(result) ) @@ -292,7 +290,7 @@ struct linear_areal if ( it->operations[1].seg_id.ring_index > -1 ) { // we can be sure that the exterior overlaps the boundary - set(result); + relate::set(result); break; } // if there was some previous ring @@ -307,7 +305,7 @@ struct linear_areal single_geometry(geometry2, *prev_seg_id_ptr)) ) { // we can be sure that the exterior overlaps the boundary - set(result); + relate::set(result); break; } } @@ -320,7 +318,7 @@ struct linear_areal && prev_seg_id_ptr->ring_index + 1 < it->operations[1].seg_id.ring_index ) { // we can be sure that the exterior overlaps the boundary - set(result); + relate::set(result); break; } } @@ -335,20 +333,14 @@ struct linear_areal if ( !has_boundary_inters.result ) { // we can be sure that the exterior overlaps the boundary - set(result); + relate::set(result); break; } // else there is 1d overlap with the boundary so we must analyse the boundary else { // u, c - typedef turns::less - < - 1, turns::less_greater_op_for_other_same_m_diff_r - < - turns::op_to_int<0,1,0,0,2,0> - > - > less; + typedef turns::less<1, turns::less_op_areal_linear> less; std::sort(it, next, less()); // analyse @@ -364,7 +356,7 @@ struct linear_areal if ( analyser.is_union_detected ) { // we can be sure that the boundary of Areal overlaps the exterior of Linear - set(result); + relate::set(result); break; } } @@ -384,7 +376,7 @@ struct linear_areal single_geometry(geometry2, *prev_seg_id_ptr)) ) { // we can be sure that the exterior overlaps the boundary - set(result); + relate::set(result); } } } @@ -460,10 +452,11 @@ struct linear_areal public: turns_analyser() - : m_previous_turn_ptr(0) + : m_previous_turn_ptr(NULL) , m_previous_operation(overlay::operation_none) , m_boundary_counter(0) , m_interior_detected(false) + , m_first_interior_other_id_ptr(NULL) {} template operations[op_id].seg_id; - //segment_identifier const& other_id = it->operations[other_op_id].seg_id; + segment_identifier const& other_id = it->operations[other_op_id].seg_id; const bool first_in_range = m_seg_watcher.update(seg_id); @@ -521,6 +514,13 @@ struct linear_areal if ( op == overlay::operation_blocked ) return; + if ( ( op == overlay::operation_intersection + || op == overlay::operation_continue ) + && turn_on_the_same_ip(m_exit_watcher.get_exit_turn(), *it) ) + { + fake_enter_detected = true; + } + m_exit_watcher.reset_detected_exit(); } @@ -548,33 +548,20 @@ struct linear_areal { m_interior_detected = false; } + else if ( op == overlay::operation_union ) + { +// TODO: this probably is not a good way of handling the interiors/enters +// the solution similar to exit_watcher would be more robust +// all enters should be kept and handled. +// maybe integrate it with the exit_watcher -> enter_exit_watcher + if ( m_first_interior_other_id_ptr + && m_first_interior_other_id_ptr->multi_index == other_id.multi_index ) + { + m_interior_detected = false; + } + } } - // if the new linestring started just now, - // but the previous one went out on the previous point, - // we must check if the boundary of the previous segment is outside - // NOTE: couldn't it be integrated with the handling of the union above? - // THIS IS REDUNDANT WITH THE HANDLING OF THE END OF THE RANGE - //if ( first_in_range - // && ! fake_enter_detected - // && m_previous_operation == overlay::operation_union ) - //{ - // BOOST_ASSERT(it != first); - // BOOST_ASSERT(m_previous_turn_ptr); - - // segment_identifier const& prev_seg_id = m_previous_turn_ptr->operations[op_id].seg_id; - - // bool prev_back_b = is_endpoint_on_boundary( - // range::back(sub_geometry::get(geometry, prev_seg_id)), - // boundary_checker); - - // // if there is a boundary on the last point - // if ( prev_back_b ) - // { - // update(res); - // } - //} - // i/u, c/u if ( op == overlay::operation_intersection || op == overlay::operation_continue ) // operation_boundary/operation_boundary_intersection @@ -592,9 +579,15 @@ struct linear_areal // interiors overlaps //update(res); - // don't update now - // we might enter a boundary of some other ring on the same IP - m_interior_detected = true; +// TODO: think about the implementation of the more robust version +// this way only the first enter will be handled + if ( !m_interior_detected ) + { + // don't update now + // we might enter a boundary of some other ring on the same IP + m_interior_detected = true; + m_first_interior_other_id_ptr = boost::addressof(other_id); + } } } else // operation_boundary @@ -675,7 +668,8 @@ struct linear_areal // we're inside, possibly going out right now if ( ! no_enters_detected ) { - if ( op_blocked ) + if ( op_blocked + && it->operations[op_id].position == overlay::position_back ) // ignore spikes! { // check if this is indeed the boundary point // NOTE: is_ip_on_boundary<>() should be called here but the result will be the same @@ -780,7 +774,8 @@ struct linear_areal // here, the possible exit is the real one // we know that we entered and now we exit if ( /*m_exit_watcher.get_exit_operation() == overlay::operation_union // THIS CHECK IS REDUNDANT - ||*/ m_previous_operation == overlay::operation_union ) + ||*/ m_previous_operation == overlay::operation_union + && !m_interior_detected ) { // for sure update(res); @@ -801,10 +796,12 @@ struct linear_areal } } // we might enter some Areal and didn't go out, - else if ( m_previous_operation == overlay::operation_intersection ) + else if ( m_previous_operation == overlay::operation_intersection + || m_interior_detected ) { // just in case update(res); + m_interior_detected = false; BOOST_ASSERT(first != last); BOOST_ASSERT(m_previous_turn_ptr); @@ -822,14 +819,6 @@ struct linear_areal } } - // handle the interior overlap - if ( m_interior_detected ) - { - // just in case - update(res); - m_interior_detected = false; - } - BOOST_ASSERT_MSG(m_previous_operation != overlay::operation_continue, "Unexpected operation! Probably the error in get_turns(L,A) or relate(L,A)"); @@ -848,28 +837,13 @@ struct linear_areal if ( turn.operations[op_id].position == overlay::position_front ) return false; - static const bool reverse2 = detail::overlay::do_reverse< - geometry::point_order::value - >::value; - - typedef typename closeable_view - < - typename range_type::type const, - closure::value - >::type range2_cview; - - typedef typename reversible_view - < - range2_cview const, - reverse2 ? iterate_reverse : iterate_forward - >::type range2_view; - - typedef typename sub_range_return_type::type range1_ref; - - range1_ref range1 = sub_range(geometry1, turn.operations[op_id].seg_id); - range2_cview const cview(sub_range(geometry2, turn.operations[other_op_id].seg_id)); - range2_view const range2(cview); - + typename sub_range_return_type::type + range1 = sub_range(geometry1, turn.operations[op_id].seg_id); + + typedef detail::normalized_view const range2_type; + typedef typename boost::range_iterator::type range2_iterator; + range2_type range2(sub_range(geometry2, turn.operations[other_op_id].seg_id)); + std::size_t s1 = boost::size(range1); std::size_t s2 = boost::size(range2); BOOST_ASSERT(s1 > 1 && s2 > 2); @@ -897,10 +871,9 @@ struct linear_areal std::size_t q_seg_jk = (q_seg_ij + 1) % seg_count2; // TODO: the following function should return immediately, however the worst case complexity is O(N) // It would be good to replace it with some O(1) mechanism - typename boost::range_iterator::type - qk_it = find_next_non_duplicated(boost::begin(range2), - boost::begin(range2) + q_seg_jk, - boost::end(range2)); + range2_iterator qk_it = find_next_non_duplicated(boost::begin(range2), + boost::begin(range2) + q_seg_jk, + boost::end(range2)); // Will this sequence of points be always correct? overlay::side_calculator side_calc(qi_conv, new_pj, pi, qi, qj, *qk_it); @@ -962,11 +935,12 @@ struct linear_areal private: exit_watcher m_exit_watcher; - segment_watcher m_seg_watcher; + segment_watcher m_seg_watcher; TurnInfo * m_previous_turn_ptr; overlay::operation_type m_previous_operation; unsigned m_boundary_counter; bool m_interior_detected; + const segment_identifier * m_first_interior_other_id_ptr; }; // call analyser.apply() for each turn in range diff --git a/include/boost/geometry/algorithms/detail/relate/linear_linear.hpp b/include/boost/geometry/algorithms/detail/relate/linear_linear.hpp index 177161f79..aab01f2e2 100644 --- a/include/boost/geometry/algorithms/detail/relate/linear_linear.hpp +++ b/include/boost/geometry/algorithms/detail/relate/linear_linear.hpp @@ -17,6 +17,7 @@ #include #include +#include #include #include @@ -67,18 +68,28 @@ public: return true; } - update(m_result); - m_flags |= 1; - - // check if there is a boundary - if ( m_flags < 2 - && ( m_boundary_checker.template - is_endpoint_boundary(range::front(linestring)) - || m_boundary_checker.template - is_endpoint_boundary(range::back(linestring)) ) ) + // point-like linestring + if ( count == 2 + && equals::equals_point_point(range::front(linestring), + range::back(linestring)) ) { - update(m_result); - m_flags |= 2; + update(m_result); + } + else + { + update(m_result); + m_flags |= 1; + + // check if there is a boundary + if ( m_flags < 2 + && ( m_boundary_checker.template + is_endpoint_boundary(range::front(linestring)) + || m_boundary_checker.template + is_endpoint_boundary(range::back(linestring)) ) ) + { + update(m_result); + m_flags |= 2; + } } return m_flags != 3 @@ -91,126 +102,6 @@ private: unsigned m_flags; }; -//enum linestring_kind { linestring_exterior, linestring_point, linestring_closed, linestring_open }; -// -//template -//linestring_kind check_linestring_kind(Linestring const& ls) -//{ -// std::size_t count = boost::size(ls); -// if ( count == 0 ) -// return linestring_exterior; -// else if ( count == 1 ) -// return linestring_point; -// else -// { -// bool equal_fb = equals::equals_point_point(range::front(ls), range::back(ls)); -// if ( equal_fb ) -// { -// typedef typename boost::range_iterator::type iterator; -// iterator first = boost::begin(ls); -// ++first; -// iterator last = boost::end(ls); -// --last; -// for ( iterator it = first ; it != last ; ++it ) -// { -// if ( !equals::equals_point_point(range::front(ls), *it) ) -// return linestring_closed; -// } -// -// return linestring_point; -// } -// else -// return linestring_open; -// } -//} - -// Called in a loop for: -// Ls/Ls - worst O(N) - 1x point_in_geometry(MLs) -// Ls/MLs - worst O(N) - 1x point_in_geometry(MLs) -// MLs/Ls - worst O(N^2) - Bx point_in_geometry(Ls) -// MLs/MLs - worst O(N^2) - Bx point_in_geometry(Ls) -// TODO: later use spatial index -//template -//class disjoint_linestring_pred_with_point_size_handling -//{ -// static const bool transpose_result = OpId != 0; -// -//public: -// disjoint_linestring_pred_with_point_size_handling(Result & res, -// BoundaryChecker & boundary_checker, -// OtherGeometry const& other_geometry) -// : m_result_ptr(boost::addressof(res)) -// , m_boundary_checker_ptr(boost::addressof(boundary_checker)) -// , m_other_geometry(boost::addressof(other_geometry)) -// , m_detected_mask_point(0) -// , m_detected_open_boundary(false) -// {} -// -// template -// bool operator()(Linestring const& linestring) -// { -// linestring_kind lk = check_linestring_kind(linestring); -// -// if ( lk == linestring_point ) // just an optimization -// { -// if ( m_detected_mask_point != 7 ) -// { -// // check the relation -// int pig = within::point_in_geometry(range::front(linestring), *m_other_geometry); -// -// // point inside -// if ( pig > 0 ) -// { -// update(*m_result_ptr); -// m_detected_mask_point |= 1; -// } -// // point on boundary -// else if ( pig == 0 ) -// { -// update(*m_result_ptr); -// m_detected_mask_point |= 2; -// } -// // point outside -// else -// { -// update(*m_result_ptr); -// m_detected_mask_point |= 4; -// } -// } -// } -// // NOTE: For closed Linestrings I/I=1 could be set automatically -// // but for MultiLinestrings endpoints of closed Linestrings must also be checked for boundary -// else if ( lk == linestring_open || lk == linestring_closed ) -// { -// if ( !m_detected_open_boundary ) // just an optimization -// { -// update(*m_result_ptr); -// -// // check if there is a boundary -// if ( m_boundary_checker_ptr->template -// is_endpoint_boundary(range::front(linestring)) -// || m_boundary_checker_ptr->template -// is_endpoint_boundary(range::back(linestring)) ) -// { -// update(*m_result_ptr); -// -// m_detected_open_boundary = true; -// } -// } -// } -// -// bool all_detected = m_detected_mask_point == 7 && m_detected_open_boundary; -// return !all_detected && !m_result_ptr->interrupt; -// } -// -//private: -// Result * m_result_ptr; -// BoundaryChecker * m_boundary_checker_ptr; -// const OtherGeometry * m_other_geometry; -// char m_detected_mask_point; -// bool m_detected_open_boundary; -//}; - template struct linear_linear { @@ -223,7 +114,7 @@ struct linear_linear static inline void apply(Geometry1 const& geometry1, Geometry2 const& geometry2, Result & result) { // The result should be FFFFFFFFF - set::value>(result);// FFFFFFFFd, d in [1,9] or T + relate::set::value>(result);// FFFFFFFFd, d in [1,9] or T if ( result.interrupt ) return; @@ -234,7 +125,12 @@ struct linear_linear interrupt_policy_linear_linear interrupt_policy(result); - turns::get_turns::apply(turns, geometry1, geometry2, interrupt_policy); + turns::get_turns + < + Geometry1, + Geometry2, + detail::get_turns::get_turn_info_type > + >::apply(turns, geometry1, geometry2, interrupt_policy); if ( result.interrupt ) return; @@ -264,14 +160,7 @@ struct linear_linear || may_update(result) || may_update(result) ) { - // x, u, i, c - typedef turns::less - < - 0, turns::less_greater_op_for_other_same_m_diff_r - < - turns::op_to_int<0,2,3,1,4,0> - > - > less; + typedef turns::less<0, turns::less_op_linear_linear> less; std::sort(turns.begin(), turns.end(), less()); turns_analyser analyser; @@ -291,14 +180,7 @@ struct linear_linear || may_update(result) || may_update(result) ) { - // x, u, i, c - typedef turns::less - < - 1, turns::less_greater_op_for_other_same_m_diff_r - < - turns::op_to_int<0,2,3,1,4,0> - > - > less; + typedef turns::less<1, turns::less_op_linear_linear> less; std::sort(turns.begin(), turns.end(), less()); turns_analyser analyser; @@ -364,8 +246,9 @@ struct linear_linear public: turns_analyser() - : m_previous_turn_ptr(0) + : m_previous_turn_ptr(NULL) , m_previous_operation(overlay::operation_none) + , m_degenerated_turn_ptr(NULL) {} template operations[op_id].operation; - if ( op != overlay::operation_union - && op != overlay::operation_intersection - && op != overlay::operation_blocked ) - { - return; - } - segment_identifier const& seg_id = it->operations[op_id].seg_id; segment_identifier const& other_id = it->operations[other_op_id].seg_id; const bool first_in_range = m_seg_watcher.update(seg_id); + if ( op != overlay::operation_union + && op != overlay::operation_intersection + && op != overlay::operation_blocked ) + { + // degenerated turn + if ( op == overlay::operation_continue + && it->method == overlay::method_none + && m_exit_watcher.is_outside(*it) + /*&& ( m_exit_watcher.get_exit_operation() == overlay::operation_none + || ! turn_on_the_same_ip(m_exit_watcher.get_exit_turn(), *it) )*/ ) + { + // TODO: rewrite the above condition + + // WARNING! For spikes the above condition may be TRUE + // When degenerated turns are be marked in a different way than c,c/c + // different condition will be checked + + handle_degenerated(res, *it, + geometry, other_geometry, + boundary_checker, other_boundary_checker, + first_in_range); + + // TODO: not elegant solution! should be rewritten. + if ( it->operations[op_id].position == overlay::position_back ) + { + m_previous_operation = overlay::operation_blocked; + m_exit_watcher.reset_detected_exit(); + } + } + + return; + } + + // reset + m_degenerated_turn_ptr = NULL; + // handle possible exit bool fake_enter_detected = false; if ( m_exit_watcher.get_exit_operation() == overlay::operation_union ) @@ -423,34 +335,15 @@ struct linear_linear if ( op == overlay::operation_blocked ) return; + if ( op == overlay::operation_intersection + && turn_on_the_same_ip(m_exit_watcher.get_exit_turn(), *it) ) + { + fake_enter_detected = true; + } + m_exit_watcher.reset_detected_exit(); } - // if the new linestring started just now, - // but the previous one went out on the previous point, - // we must check if the boundary of the previous segment is outside - // NOTE: couldn't it be integrated with the handling of the union above? - // THIS IS REDUNDANT WITH THE HANDLING OF THE END OF THE RANGE - //if ( first_in_range - // && ! fake_enter_detected - // && m_previous_operation == overlay::operation_union ) - //{ - // BOOST_ASSERT(it != first); - // BOOST_ASSERT(m_previous_turn_ptr); - - // segment_identifier const& prev_seg_id = m_previous_turn_ptr->operations[op_id].seg_id; - - // bool prev_back_b = is_endpoint_on_boundary( - // range::back(sub_geometry::get(geometry, prev_seg_id)), - // boundary_checker); - - // // if there is a boundary on the last point - // if ( prev_back_b ) - // { - // update(res); - // } - //} - // i/i, i/x, i/u if ( op == overlay::operation_intersection ) { @@ -459,8 +352,9 @@ struct linear_linear // interiors overlaps update(res); - - bool this_b = is_ip_on_boundary(it->point, + + bool this_b = it->operations[op_id].position == overlay::position_front // ignore spikes! + && is_ip_on_boundary(it->point, it->operations[op_id], boundary_checker, seg_id); @@ -489,7 +383,9 @@ struct linear_linear else { // if we didn't enter in the past, we were outside - if ( was_outside && !fake_enter_detected ) + if ( was_outside + && ! fake_enter_detected + && it->operations[op_id].position != overlay::position_front ) { update(res); @@ -521,7 +417,7 @@ struct linear_linear // to exit we must be currently inside and the current segment must be collinear if ( !was_outside && is_collinear ) { - m_exit_watcher.exit(*it); + m_exit_watcher.exit(*it, false); } bool op_blocked = op == overlay::operation_blocked; @@ -530,7 +426,8 @@ struct linear_linear // possibly going out right now if ( ! was_outside && is_collinear ) { - if ( op_blocked ) + if ( op_blocked + && it->operations[op_id].position == overlay::position_back ) // ignore spikes! { // check if this is indeed the boundary point // NOTE: is_ip_on_boundary<>() should be called here but the result will be the same @@ -665,24 +562,33 @@ struct linear_linear // here, the possible exit is the real one // we know that we entered and now we exit if ( /*m_exit_watcher.get_exit_operation() == overlay::operation_union // THIS CHECK IS REDUNDANT - ||*/ m_previous_operation == overlay::operation_union ) + ||*/ m_previous_operation == overlay::operation_union + || m_degenerated_turn_ptr ) { - // for sure update(res); BOOST_ASSERT(first != last); - BOOST_ASSERT(m_previous_turn_ptr); - segment_identifier const& prev_seg_id = m_previous_turn_ptr->operations[op_id].seg_id; - - bool prev_back_b = is_endpoint_on_boundary( - range::back(sub_range(geometry, prev_seg_id)), - boundary_checker); - - // if there is a boundary on the last point - if ( prev_back_b ) + const TurnInfo * turn_ptr = NULL; + if ( m_degenerated_turn_ptr ) + turn_ptr = m_degenerated_turn_ptr; + else if ( m_previous_turn_ptr ) + turn_ptr = m_previous_turn_ptr; + + if ( turn_ptr ) { - update(res); + segment_identifier const& prev_seg_id = turn_ptr->operations[op_id].seg_id; + + //BOOST_ASSERT(!boost::empty(sub_range(geometry, prev_seg_id))); + bool prev_back_b = is_endpoint_on_boundary( + range::back(sub_range(geometry, prev_seg_id)), + boundary_checker); + + // if there is a boundary on the last point + if ( prev_back_b ) + { + update(res); + } } } @@ -690,13 +596,127 @@ struct linear_linear // reset exit watcher before the analysis of the next Linestring // note that if there are some enters stored there may be some error above m_exit_watcher.reset(); + + m_previous_turn_ptr = NULL; + m_previous_operation = overlay::operation_none; + m_degenerated_turn_ptr = NULL; + } + + template + void handle_degenerated(Result & res, + Turn const& turn, + Geometry const& geometry, + OtherGeometry const& other_geometry, + BoundaryChecker const& boundary_checker, + OtherBoundaryChecker const& other_boundary_checker, + bool first_in_range) + { + typename detail::single_geometry_return_type::type + ls1_ref = detail::single_geometry(geometry, turn.operations[op_id].seg_id); + typename detail::single_geometry_return_type::type + ls2_ref = detail::single_geometry(other_geometry, turn.operations[op_id].other_id); + + // only one of those should be true: + + if ( turn.operations[op_id].position == overlay::position_front ) + { + // valid, point-sized + if ( boost::size(ls2_ref) == 2 ) + { + bool front_b = is_endpoint_on_boundary(turn.point, boundary_checker); + + if ( front_b ) + { + update(res); + } + else + { + update(res); + } + + // operation 'c' should be last for the same IP so we know that the next point won't be the same + update(res); + + m_degenerated_turn_ptr = boost::addressof(turn); + } + } + else if ( turn.operations[op_id].position == overlay::position_back ) + { + // valid, point-sized + if ( boost::size(ls2_ref) == 2 ) + { + update(res); + + bool back_b = is_endpoint_on_boundary(turn.point, boundary_checker); + + if ( back_b ) + { + update(res); + } + else + { + update(res); + } + + if ( first_in_range ) + { + //BOOST_ASSERT(!boost::empty(ls1_ref)); + bool front_b = is_endpoint_on_boundary( + range::front(ls1_ref), boundary_checker); + if ( front_b ) + { + update(res); + } + } + } + } + else if ( turn.operations[op_id].position == overlay::position_middle + && turn.operations[other_op_id].position == overlay::position_middle ) + { + update(res); + + // here we don't know which one is degenerated + + bool is_point1 = boost::size(ls1_ref) == 2 + && equals::equals_point_point(range::front(ls1_ref), range::back(ls1_ref)); + bool is_point2 = boost::size(ls2_ref) == 2 + && equals::equals_point_point(range::front(ls2_ref), range::back(ls2_ref)); + + // if the second one is degenerated + if ( !is_point1 && is_point2 ) + { + update(res); + + if ( first_in_range ) + { + //BOOST_ASSERT(!boost::empty(ls1_ref)); + bool front_b = is_endpoint_on_boundary( + range::front(ls1_ref), boundary_checker); + if ( front_b ) + { + update(res); + } + } + + m_degenerated_turn_ptr = boost::addressof(turn); + } + } + + // NOTE: other.position == front and other.position == back + // will be handled later, for the other geometry } private: exit_watcher m_exit_watcher; - segment_watcher m_seg_watcher; - TurnInfo * m_previous_turn_ptr; + segment_watcher m_seg_watcher; + const TurnInfo * m_previous_turn_ptr; overlay::operation_type m_previous_operation; + const TurnInfo * m_degenerated_turn_ptr; }; template ::interruption_enabled; }; -template +template ::value> struct result_handler_type : not_implemented {}; template -struct result_handler_type +struct result_handler_type { typedef matrix_handler type; }; template -struct result_handler_type +struct result_handler_type { typedef mask_handler < @@ -224,7 +227,7 @@ struct result_handler_type }; template -struct result_handler_type > +struct result_handler_type, false> { typedef mask_handler < @@ -241,7 +244,7 @@ template -struct result_handler_type > +struct result_handler_type, false> { typedef static_mask_handler < @@ -254,6 +257,20 @@ struct result_handler_type type; }; +template +struct result_handler_type +{ + typedef static_mask_handler + < + StaticSequence, + interruption_enabled + < + Geometry1, + Geometry2 + >::value + > type; +}; + template inline typename result_handler_type diff --git a/include/boost/geometry/algorithms/detail/relate/result.hpp b/include/boost/geometry/algorithms/detail/relate/result.hpp index 270661af2..db41323c3 100644 --- a/include/boost/geometry/algorithms/detail/relate/result.hpp +++ b/include/boost/geometry/algorithms/detail/relate/result.hpp @@ -468,7 +468,7 @@ struct check_dispatch< boost::tuple > template static inline bool apply(mask_type const& mask, Matrix const& matrix) { - return check_dispatch_tuple::template apply(mask, matrix); + return check_dispatch_tuple::apply(mask, matrix); } }; @@ -480,7 +480,7 @@ struct check_dispatch< boost::tuples::cons > template static inline bool apply(mask_type const& mask, Matrix const& matrix) { - return check_dispatch_tuple::template apply(mask, matrix); + return check_dispatch_tuple::apply(mask, matrix); } }; @@ -620,8 +620,8 @@ public: // static_should_handle_element -template -struct static_should_handle_element +template +struct static_should_handle_element_dispatch { static const char mask_el = StaticMask::template get::value; static const bool value = mask_el == 'F' @@ -629,6 +629,56 @@ struct static_should_handle_element || ( mask_el >= '0' && mask_el <= '9' ); }; +template +struct static_should_handle_element_sequence +{ + typedef typename boost::mpl::deref::type StaticMask; + + static const bool value + = static_should_handle_element_dispatch + < + StaticMask, + F1, F2, + boost::mpl::is_sequence::value + >::value + || static_should_handle_element_sequence + < + typename boost::mpl::next::type, + Last, + F1, F2 + >::value; +}; + +template +struct static_should_handle_element_sequence +{ + static const bool value = false; +}; + +template +struct static_should_handle_element_dispatch +{ + static const bool value + = static_should_handle_element_sequence + < + typename boost::mpl::begin::type, + typename boost::mpl::end::type, + F1, F2 + >::value; +}; + +template +struct static_should_handle_element +{ + static const bool value + = static_should_handle_element_dispatch + < + StaticMask, + F1, F2, + boost::mpl::is_sequence::value + >::value; +}; + // static_interrupt template @@ -1081,7 +1131,7 @@ template ::value, std::size_t Dim2 = topological_dimension::value> -struct static_mask_touches_type +struct static_mask_touches_impl { typedef boost::mpl::vector< static_mask<'F', 'T', '*', '*', '*', '*', '*', '*', '*'>, @@ -1092,11 +1142,16 @@ struct static_mask_touches_type // According to OGC, doesn't apply to P/P // Using the above mask the result would be always false template -struct static_mask_touches_type +struct static_mask_touches_impl : not_implemented::type, typename geometry::tag::type> {}; +template +struct static_mask_touches_type + : static_mask_touches_impl +{}; + // WITHIN typedef static_mask<'T', '*', 'F', '*', '*', 'F', '*', '*', '*'> static_mask_within; diff --git a/include/boost/geometry/algorithms/detail/relate/turns.hpp b/include/boost/geometry/algorithms/detail/relate/turns.hpp index 68eade8f0..c373e9f63 100644 --- a/include/boost/geometry/algorithms/detail/relate/turns.hpp +++ b/include/boost/geometry/algorithms/detail/relate/turns.hpp @@ -15,9 +15,9 @@ #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_RELATE_TURNS_HPP #include +#include #include #include -#include #include @@ -26,44 +26,11 @@ namespace boost { namespace geometry { #ifndef DOXYGEN_NO_DETAIL namespace detail { namespace relate { namespace turns { -// TURN_INFO - -// distance_info -// enriched_distance_info -// distance_enriched_info -// distance_enrichment_info - -template -struct enriched_info +template +struct assign_policy + : overlay::assign_null_policy { - typedef typename strategy::distance::services::return_type - < - typename strategy::distance::services::comparable_type - < - typename strategy::distance::services::default_strategy - < - point_tag, - P - >::type - >::type, - P, P - >::type distance_type; - - inline enriched_info() - : distance(distance_type()) - {} - - distance_type distance; // distance-measurement from segment.first to IP -}; - -// turn_operation_linear_with_distance -// distance_enriched_turn_operation_linear - -template -struct enriched_turn_operation_linear - : public overlay::turn_operation_linear -{ - enriched_info

enriched; + static bool const include_degenerate = IncludeDegenerate; }; // GET_TURNS @@ -71,16 +38,21 @@ struct enriched_turn_operation_linear template > + = detail::get_turns::get_turn_info_type > > struct get_turns { typedef typename geometry::point_type::type point1_type; typedef overlay::turn_info - < - point1_type, - enriched_turn_operation_linear - > turn_info; + < + point1_type, + typename segment_ratio_type::type, + typename detail::get_turns::turn_operation_type + < + Geometry1, Geometry2, + typename segment_ratio_type::type + >::type + > turn_info; template static inline void apply(Turns & turns, @@ -98,6 +70,8 @@ struct get_turns Geometry2 const& geometry2, InterruptPolicy & interrupt_policy) { + typedef typename geometry::point_type::type point1_type; + static const bool reverse1 = detail::overlay::do_reverse::value>::value; static const bool reverse2 = detail::overlay::do_reverse::value>::value; @@ -135,28 +109,48 @@ struct op_to_int } }; -template > -struct less_greater_op_for_other_same_m_diff_r +template +struct less_op_xxx_linear { template inline bool operator()(Op const& left, Op const& right) { static OpToInt op_to_int; + return op_to_int(left) < op_to_int(right); + } +}; + +struct less_op_linear_linear + : less_op_xxx_linear< op_to_int<0,2,3,1,4,0> > +{}; + +struct less_op_linear_areal +{ + template + inline bool operator()(Op const& left, Op const& right) + { + static turns::op_to_int<0,2,3,1,4,0> op_to_int_xuic; + static turns::op_to_int<0,3,2,1,4,0> op_to_int_xiuc; if ( left.other_id.multi_index == right.other_id.multi_index ) { if ( left.other_id.ring_index == right.other_id.ring_index ) - return op_to_int(left) < op_to_int(right); + return op_to_int_xuic(left) < op_to_int_xuic(right); else - return op_to_int(left) > op_to_int(right); + return op_to_int_xiuc(left) < op_to_int_xiuc(right); } else { - return op_to_int(left) < op_to_int(right); + //return op_to_int_xuic(left) < op_to_int_xuic(right); + return left.other_id.multi_index < right.other_id.multi_index; } } }; +struct less_op_areal_linear + : less_op_xxx_linear< op_to_int<0,1,0,0,2,0> > +{}; + struct less_op_areal_areal { template @@ -201,20 +195,20 @@ struct less_op_areal_areal // sort turns by G1 - source_index == 0 by: // seg_id -> distance -> operation template > + typename LessOp = less_op_xxx_linear< op_to_int<> > > struct less { BOOST_STATIC_ASSERT(OpId < 2); template static inline - bool use_distance(Op const& left, Op const& right) + bool use_fraction(Op const& left, Op const& right) { static LessOp less_op; - if ( geometry::math::equals(left.enriched.distance, right.enriched.distance) ) + if ( left.fraction == right.fraction ) return less_op(left, right); else - return left.enriched.distance < right.enriched.distance; + return left.fraction < right.fraction; } template @@ -223,7 +217,7 @@ struct less segment_identifier const& sl = left.operations[OpId].seg_id; segment_identifier const& sr = right.operations[OpId].seg_id; - return sl < sr || ( sl == sr && use_distance(left.operations[OpId], right.operations[OpId]) ); + return sl < sr || ( sl == sr && use_fraction(left.operations[OpId], right.operations[OpId]) ); } }; diff --git a/include/boost/geometry/algorithms/detail/sections/sectionalize.hpp b/include/boost/geometry/algorithms/detail/sections/sectionalize.hpp index c4b6ac7c5..af35794e2 100644 --- a/include/boost/geometry/algorithms/detail/sections/sectionalize.hpp +++ b/include/boost/geometry/algorithms/detail/sections/sectionalize.hpp @@ -29,7 +29,7 @@ #include #include -#include +#include #include #include @@ -37,13 +37,17 @@ #include #include + #include #include +#include +#include #include #include #include + namespace boost { namespace geometry { @@ -257,22 +261,25 @@ struct sectionalize_part template < typename Range, // Can be closeable_view - typename RescalePolicy, + typename RobustPolicy, typename Sections > static inline void apply(Sections& sections, Range const& range, - RescalePolicy const& rescale_policy, + RobustPolicy const& robust_policy, bool make_rescaled_boxes, ring_identifier ring_id, std::size_t max_count) { - boost::ignore_unused_variable_warning(rescale_policy); + boost::ignore_unused_variable_warning(robust_policy); boost::ignore_unused_variable_warning(make_rescaled_boxes); typedef model::referring_segment segment_type; typedef typename boost::range_value::type section_type; - + typedef model::segment + < + typename robust_point_type::type + > robust_segment_type; typedef typename boost::range_iterator::type iterator_type; if ( boost::empty(range) ) @@ -294,12 +301,14 @@ struct sectionalize_part ++previous, ++it, index++) { segment_type segment(*previous, *it); + robust_segment_type robust_segment; + geometry::recalculate(robust_segment, segment, robust_policy); int direction_classes[DimensionCount] = {0}; get_direction_loop < 0, DimensionCount - >::apply(segment, direction_classes); + >::apply(robust_segment, direction_classes); // if "dir" == 0 for all point-dimensions, it is duplicate. // Those sections might be omitted, if wished, lateron @@ -313,7 +322,7 @@ struct sectionalize_part if (check_duplicate_loop < 0, geometry::dimension::type::value - >::apply(segment) + >::apply(robust_segment) ) { duplicate = true; @@ -365,10 +374,11 @@ struct sectionalize_part < int, 0, DimensionCount >::apply(direction_classes, section.directions); - geometry::expand(section.bounding_box, *previous); + + expand_box(*previous, robust_policy, section); } - geometry::expand(section.bounding_box, *it); + expand_box(*it, robust_policy, section); section.end_index = index + 1; section.count++; if (! duplicate) @@ -394,6 +404,16 @@ struct sectionalize_part sections[last_non_duplicate_index].is_non_duplicate_last = true; } } + + template + static inline void expand_box(InputPoint const& point, + RobustPolicy const& robust_policy, + Section& section) + { + typename geometry::point_type::type robust_point; + geometry::recalculate(robust_point, point, robust_policy); + geometry::expand(section.bounding_box, robust_point); + } }; @@ -408,11 +428,11 @@ struct sectionalize_range template < typename Range, - typename RescalePolicy, + typename RobustPolicy, typename Sections > static inline void apply(Range const& range, - RescalePolicy const& rescale_policy, + RobustPolicy const& robust_policy, bool make_rescaled_boxes, Sections& sections, ring_identifier ring_id, @@ -442,7 +462,7 @@ struct sectionalize_range } sectionalize_part - ::apply(sections, view, rescale_policy, make_rescaled_boxes, ring_id, max_count); + ::apply(sections, view, robust_policy, make_rescaled_boxes, ring_id, max_count); } }; @@ -456,11 +476,11 @@ struct sectionalize_polygon template < typename Polygon, - typename RescalePolicy, + typename RobustPolicy, typename Sections > static inline void apply(Polygon const& poly, - RescalePolicy const& rescale_policy, + RobustPolicy const& robust_policy, bool make_rescaled_boxes, Sections& sections, ring_identifier ring_id, std::size_t max_count) @@ -474,7 +494,7 @@ struct sectionalize_polygon > per_range; ring_id.ring_index = -1; - per_range::apply(exterior_ring(poly), rescale_policy, make_rescaled_boxes, sections, ring_id, max_count); + per_range::apply(exterior_ring(poly), robust_policy, make_rescaled_boxes, sections, ring_id, max_count); ring_id.ring_index++; typename interior_return_type::type rings @@ -482,7 +502,7 @@ struct sectionalize_polygon for (BOOST_AUTO_TPL(it, boost::begin(rings)); it != boost::end(rings); ++it, ++ring_id.ring_index) { - per_range::apply(*it, rescale_policy, make_rescaled_boxes, sections, ring_id, max_count); + per_range::apply(*it, robust_policy, make_rescaled_boxes, sections, ring_id, max_count); } } }; @@ -496,11 +516,11 @@ struct sectionalize_box template < typename Box, - typename RescalePolicy, + typename RobustPolicy, typename Sections > static inline void apply(Box const& box, - RescalePolicy const& rescale_policy, + RobustPolicy const& robust_policy, bool make_rescaled_boxes, Sections& sections, ring_identifier const& ring_id, std::size_t max_count) @@ -532,7 +552,7 @@ struct sectionalize_box closed, false, point_type, DimensionCount - >::apply(points, rescale_policy, make_rescaled_boxes, sections, + >::apply(points, robust_policy, make_rescaled_boxes, sections, ring_id, max_count); } }; @@ -551,7 +571,7 @@ inline void set_section_unique_ids(Sections& sections) } template -inline void enlargeSections(Sections& sections) +inline void enlarge_sections(Sections& sections) { // Robustness issue. Increase sections a tiny bit such that all points are really within (and not on border) // Reason: turns might, rarely, be missed otherwise (case: "buffer_mp1") @@ -669,9 +689,9 @@ struct sectionalize \param sections structure with sections \param source_index index to assign to the ring_identifiers */ -template +template inline void sectionalize(Geometry const& geometry, - RescalePolicy const& rescale_policy, + RobustPolicy const& robust_policy, bool make_rescaled_boxes, Sections& sections, int source_index = 0) @@ -690,26 +710,28 @@ inline void sectionalize(Geometry const& geometry, Geometry, Reverse, Sections::value - >::apply(geometry, rescale_policy, make_rescaled_boxes, sections, ring_id, 10); + >::apply(geometry, robust_policy, make_rescaled_boxes, sections, ring_id, 10); detail::sectionalize::set_section_unique_ids(sections); - if (make_rescaled_boxes) + if (! make_rescaled_boxes) { - detail::sectionalize::enlargeSections(sections); + detail::sectionalize::enlarge_sections(sections); } } +#if defined(BOOST_GEOMETRY_UNIT_TEST_SECTIONALIZE) // Backwards compatibility template inline void sectionalize(Geometry const& geometry, - Sections& sections, - int source_index = 0) + Sections& sections, + int source_index = 0) { - return sectionalize(geometry, detail::no_rescale_policy(), - false, sections, - source_index); + return geometry::sectionalize(geometry, detail::no_rescale_policy(), + false, sections, + source_index); } +#endif }} // namespace boost::geometry diff --git a/include/boost/geometry/algorithms/detail/turns/compare_turns.hpp b/include/boost/geometry/algorithms/detail/turns/compare_turns.hpp index 5314f9e9a..f06140b7b 100644 --- a/include/boost/geometry/algorithms/detail/turns/compare_turns.hpp +++ b/include/boost/geometry/algorithms/detail/turns/compare_turns.hpp @@ -79,11 +79,10 @@ struct less_seg_dist_other_op } template - static inline bool use_distance(Op const& left, Op const& right) + static inline bool use_fraction(Op const& left, Op const& right) { - return left.enriched.distance < right.enriched.distance - || ( geometry::math::equals(left.enriched.distance, - right.enriched.distance) + return left.fraction < right.fraction + || ( geometry::math::equals(left.fraction, right.fraction) && use_other_id(left, right) ); } @@ -94,7 +93,7 @@ struct less_seg_dist_other_op segment_identifier const& sl = left.operations[OpId].seg_id; segment_identifier const& sr = right.operations[OpId].seg_id; - return sl < sr || ( sl == sr && use_distance(left.operations[OpId], right.operations[OpId]) ); + return sl < sr || ( sl == sr && use_fraction(left.operations[OpId], right.operations[OpId]) ); } }; diff --git a/include/boost/geometry/algorithms/detail/turns/print_turns.hpp b/include/boost/geometry/algorithms/detail/turns/print_turns.hpp index b6ceed3e8..5093c1a80 100644 --- a/include/boost/geometry/algorithms/detail/turns/print_turns.hpp +++ b/include/boost/geometry/algorithms/detail/turns/print_turns.hpp @@ -52,6 +52,11 @@ static inline void print_turns(Geometry1 const& g1, else out << '\n'; + double fraction[2]; + + fraction[0] = turn.operations[0].fraction.numerator() + / turn.operations[0].fraction.denominator(); + out << geometry::operation_char(turn.operations[0].operation) <<": seg: " << turn.operations[0].seg_id.source_index << ", m: " << turn.operations[0].seg_id.multi_index @@ -61,11 +66,15 @@ static inline void print_turns(Geometry1 const& g1, << ", m: " << turn.operations[0].other_id.multi_index << ", r: " << turn.operations[0].other_id.ring_index << ", s: " << turn.operations[0].other_id.segment_index; + out << ", fr: " << fraction[0]; out << ", col?: " << turn.operations[0].is_collinear; out << ' ' << geometry::dsv(turn.point) << ' '; out << '\n'; + fraction[1] = turn.operations[1].fraction.numerator() + / turn.operations[1].fraction.denominator(); + out << geometry::operation_char(turn.operations[1].operation) << ": seg: " << turn.operations[1].seg_id.source_index << ", m: " << turn.operations[1].seg_id.multi_index @@ -75,6 +84,7 @@ static inline void print_turns(Geometry1 const& g1, << ", m: " << turn.operations[1].other_id.multi_index << ", r: " << turn.operations[1].other_id.ring_index << ", s: " << turn.operations[1].other_id.segment_index; + out << ", fr: " << fraction[1]; out << ", col?: " << turn.operations[1].is_collinear; out << ' ' << geometry::dsv(turn.point) << ' '; diff --git a/include/boost/geometry/algorithms/detail/within/point_in_geometry.hpp b/include/boost/geometry/algorithms/detail/within/point_in_geometry.hpp index 014f5a824..fc386d84b 100644 --- a/include/boost/geometry/algorithms/detail/within/point_in_geometry.hpp +++ b/include/boost/geometry/algorithms/detail/within/point_in_geometry.hpp @@ -20,7 +20,7 @@ #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_WITHIN_POINT_IN_GEOMETRY_HPP #include -#include +#include #include #include @@ -114,7 +114,10 @@ inline int point_in_range(Point const& point, Range const& range) Geometry >::type strategy_type2; - BOOST_STATIC_ASSERT(boost::is_same::value); + static const bool same_strategies = boost::is_same::value; + BOOST_MPL_ASSERT_MSG((same_strategies), + DEFAULT_WITHIN_AND_COVERED_BY_STRATEGIES_NOT_COMPATIBLE, + (strategy_type, strategy_type2)); return point_in_range(point, range, strategy_type()); } @@ -419,7 +422,10 @@ inline int point_in_geometry(Point const& point, Geometry const& geometry) Geometry >::type strategy_type2; - BOOST_STATIC_ASSERT(boost::is_same::value); + static const bool same_strategies = boost::is_same::value; + BOOST_MPL_ASSERT_MSG((same_strategies), + DEFAULT_WITHIN_AND_COVERED_BY_STRATEGIES_NOT_COMPATIBLE, + (strategy_type, strategy_type2)); return point_in_geometry(point, geometry, strategy_type()); } diff --git a/include/boost/geometry/algorithms/detail/zoom_to_robust.hpp b/include/boost/geometry/algorithms/detail/zoom_to_robust.hpp index 1eec9d48f..ac78a200b 100644 --- a/include/boost/geometry/algorithms/detail/zoom_to_robust.hpp +++ b/include/boost/geometry/algorithms/detail/zoom_to_robust.hpp @@ -20,93 +20,21 @@ #include #include #include +#include #include +#include + +#include namespace boost { namespace geometry { -#ifndef DOXYGEN_NO_DETAIL -namespace detail { namespace zoom_to_robust -{ - -template -struct get_max_size -{ - static inline typename coordinate_type::type apply(Box const& box) - { - typename coordinate_type::type s - = geometry::math::abs(geometry::get<1, Dimension>(box) - geometry::get<0, Dimension>(box)); - - return (std::max)(s, get_max_size::apply(box)); - } -}; - -template -struct get_max_size -{ - static inline typename coordinate_type::type apply(Box const& box) - { - return geometry::math::abs(geometry::get<1, 0>(box) - geometry::get<0, 0>(box)); - } -}; - -template -struct rescale_strategy -{ - typedef typename geometry::coordinate_type::type output_ct; - - rescale_strategy(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 - inline output_ct apply(Value const& value) const - { - // a + (v-b)*f - CalculationType const a = static_cast(get(m_int_min)); - CalculationType const b = static_cast(get(m_fp_min)); - CalculationType const result = a + (value - b) * m_multiplier; - return static_cast(result); - } - - FpPoint const& m_fp_min; - IntPoint const& m_int_min; - CalculationType m_multiplier; -}; - -}} // namespace detail::zoom_to_robust -#endif // DOXYGEN_NO_DETAIL - -template -inline typename coordinate_type::type get_max_size(Box const& box) -{ - return detail::zoom_to_robust::get_max_size::value - 1>::apply(box); -} #ifndef DOXYGEN_NO_DISPATCH namespace dispatch { -template -struct robust_type -{ -}; - -template -struct robust_type -{ - typedef CoordinateType type; -}; - -template -struct robust_type -{ - typedef int type; // long long? -}; template @@ -160,9 +88,9 @@ struct zoom_to_robust geometry::expand(env, g6); // Scale this to integer-range - typename geometry::coordinate_type::type diff = get_max_size(env); + typename geometry::coordinate_type::type diff = detail::get_max_size(env); double range = 1000000000.0; // Define a large range to get precise integer coordinates - double factor = double(int(range / double(diff))); + double factor = double(boost::long_long_type(range / double(diff))); // Assign input/output minimal points point1_type min_point1; @@ -170,9 +98,9 @@ struct zoom_to_robust typedef typename point_type::type point2_type; point2_type min_point2; - assign_values(min_point2, int(-range/2.0), int(-range/2.0)); + assign_values(min_point2, boost::long_long_type(-range/2.0), boost::long_long_type(-range/2.0)); - detail::zoom_to_robust::rescale_strategy strategy(min_point1, min_point2, factor); + detail::robust_policy strategy(min_point1, min_point2, factor); geometry::recalculate(og1, g1, strategy); geometry::recalculate(og2, g2, strategy); @@ -187,15 +115,9 @@ struct zoom_to_robust } // namespace dispatch #endif // DOXYGEN_NO_DISPATCH -template -struct robust_type +#ifndef DOXYGEN_NO_DETAIL +namespace detail { - typedef typename dispatch::robust_type - < - CoordinateType, - typename boost::is_floating_point::type - >::type type; -}; template @@ -209,21 +131,21 @@ inline void zoom_to_robust(Geometry1 const& g1a, Geometry1 const& g1b, Geometry2 // Get the envelop of inputs model::box env; - envelope(g1a, env); - expand(env, g1b); + geometry::envelope(g1a, env); + geometry::expand(env, g1b); // Scale this to integer-range - typename coordinate_type::type diff = get_max_size(env); + typename coordinate_type::type diff = detail::get_max_size(env); double range = 1000000000.0; // Define a large range to get precise integer coordinates double factor = range / diff; // Assign input/output minimal points detail::assign_point_from_index<0>(env, min_point1); - assign_values(min_point2, int(-range/2.0), int(-range/2.0)); + assign_values(min_point2, boost::long_long_type(-range/2.0), boost::long_long_type(-range/2.0)); - detail::zoom_to_robust::rescale_strategy strategy(min_point1, min_point2, factor); - recalculate(g2a, g1a, strategy); - recalculate(g2b, g1b, strategy); + detail::robust_policy strategy(min_point1, min_point2, factor); + geometry::recalculate(g2a, g1a, strategy); + geometry::recalculate(g2b, g1b, strategy); } template @@ -248,6 +170,9 @@ void zoom_to_robust(Geometry1 const& g1, Geometry2 const& g2, Geometry3 const& g >::apply(g1, g2, g3, g4, g5, g6, og1, og2, og3, og4, og5, og6); } +} // namespace detail +#endif // DOXYGEN_NO_DETAIL + }} // namespace boost::geometry diff --git a/include/boost/geometry/algorithms/difference.hpp b/include/boost/geometry/algorithms/difference.hpp index dad1f942b..780436f01 100644 --- a/include/boost/geometry/algorithms/difference.hpp +++ b/include/boost/geometry/algorithms/difference.hpp @@ -12,6 +12,7 @@ #include #include +#include namespace boost { namespace geometry { @@ -43,11 +44,14 @@ template typename GeometryOut, typename Geometry1, typename Geometry2, + typename RobustPolicy, typename OutputIterator, typename Strategy > inline OutputIterator difference_insert(Geometry1 const& geometry1, - Geometry2 const& geometry2, OutputIterator out, + Geometry2 const& geometry2, + RobustPolicy const& robust_policy, + OutputIterator out, Strategy const& strategy) { concept::check(); @@ -61,7 +65,7 @@ inline OutputIterator difference_insert(Geometry1 const& geometry1, overlay_difference, geometry::detail::overlay::do_reverse::value>::value, geometry::detail::overlay::do_reverse::value, true>::value - >::apply(geometry1, geometry2, out, strategy); + >::apply(geometry1, geometry2, robust_policy, out, strategy); } /*! @@ -85,10 +89,13 @@ template typename GeometryOut, typename Geometry1, typename Geometry2, + typename RobustPolicy, typename OutputIterator > inline OutputIterator difference_insert(Geometry1 const& geometry1, - Geometry2 const& geometry2, OutputIterator out) + Geometry2 const& geometry2, + RobustPolicy const& robust_policy, + OutputIterator out) { concept::check(); concept::check(); @@ -99,11 +106,12 @@ inline OutputIterator difference_insert(Geometry1 const& geometry1, typename cs_tag::type, Geometry1, Geometry2, - typename geometry::point_type::type + typename geometry::point_type::type, + RobustPolicy > strategy; return difference_insert(geometry1, geometry2, - out, strategy()); + robust_policy, out, strategy()); } @@ -140,8 +148,17 @@ inline void difference(Geometry1 const& geometry1, typedef typename boost::range_value::type geometry_out; concept::check(); + typedef typename geometry::rescale_overlay_policy_type + < + Geometry1, + Geometry2 + >::type rescale_policy_type; + + rescale_policy_type robust_policy + = geometry::get_rescale_policy(geometry1, geometry2); + detail::difference::difference_insert( - geometry1, geometry2, + geometry1, geometry2, robust_policy, std::back_inserter(output_collection)); } diff --git a/include/boost/geometry/algorithms/disjoint.hpp b/include/boost/geometry/algorithms/disjoint.hpp index 6f026b1f5..ac9de681d 100644 --- a/include/boost/geometry/algorithms/disjoint.hpp +++ b/include/boost/geometry/algorithms/disjoint.hpp @@ -39,7 +39,6 @@ #include #include #include -#include #include @@ -48,6 +47,10 @@ #include #include +#include +#include + + namespace boost { namespace geometry { @@ -116,8 +119,12 @@ struct disjoint_linear static inline bool apply(Geometry1 const& geometry1, Geometry2 const& geometry2) { typedef typename geometry::point_type::type point_type; - - typedef overlay::turn_info turn_info; + typedef detail::no_rescale_policy rescale_policy_type; + typedef overlay::turn_info + < + point_type, + typename segment_ratio_type::type + > turn_info; std::deque turns; static const bool reverse1 = overlay::do_reverse::value>::value; // should be false @@ -127,11 +134,12 @@ struct disjoint_linear // 1) Stop at any intersection // 2) In assignment, include also degenerate points (which are normally skipped) disjoint_interrupt_policy policy; + rescale_policy_type robust_policy; geometry::get_turns < reverse1, reverse2, assign_disjoint_policy - >(geometry1, geometry2, detail::no_rescale_policy(), turns, policy); + >(geometry1, geometry2, robust_policy, turns, policy); return !policy.has_intersections; } @@ -144,16 +152,28 @@ struct disjoint_segment { typedef typename point_type::type point_type; - segment_intersection_points is + // 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; + + intersection_return_type is = strategy::intersection::relate_cartesian_segments < policies::relate::segments_intersection_points < - Segment1, - Segment2, - segment_intersection_points + intersection_return_type > - >::apply(segment1, segment2); + >::apply(segment1, segment2, robust_policy); return is.count == 0; } diff --git a/include/boost/geometry/algorithms/intersection.hpp b/include/boost/geometry/algorithms/intersection.hpp index 3125752db..500cacc9f 100644 --- a/include/boost/geometry/algorithms/intersection.hpp +++ b/include/boost/geometry/algorithms/intersection.hpp @@ -13,6 +13,7 @@ #include #include #include +#include namespace boost { namespace geometry @@ -27,11 +28,15 @@ struct intersection_box_box { template < - typename Box1, typename Box2, typename BoxOut, + typename Box1, typename Box2, + typename RobustPolicy, + typename BoxOut, typename Strategy > static inline bool apply(Box1 const& box1, - Box2 const& box2, BoxOut& box_out, + Box2 const& box2, + RobustPolicy const& robust_policy, + BoxOut& box_out, Strategy const& strategy) { typedef typename coordinate_type::type ct; @@ -50,7 +55,7 @@ struct intersection_box_box set(box_out, max1 > max2 ? max2 : max1); return intersection_box_box - ::apply(box1, box2, box_out, strategy); + ::apply(box1, box2, robust_policy, box_out, strategy); } }; @@ -59,10 +64,13 @@ struct intersection_box_box { template < - typename Box1, typename Box2, typename BoxOut, + typename Box1, typename Box2, + typename RobustPolicy, + typename BoxOut, typename Strategy > - static inline bool apply(Box1 const&, Box2 const&, BoxOut&, Strategy const&) + static inline bool apply(Box1 const&, Box2 const&, + RobustPolicy const&, BoxOut&, Strategy const&) { return true; } @@ -88,9 +96,10 @@ template > struct intersection { - template + template static inline bool apply(Geometry1 const& geometry1, Geometry2 const& geometry2, + RobustPolicy const& robust_policy, GeometryOut& geometry_out, Strategy const& strategy) { @@ -100,7 +109,7 @@ struct intersection < Geometry1, Geometry2, OneOut, overlay_intersection - >::apply(geometry1, geometry2, std::back_inserter(geometry_out), strategy); + >::apply(geometry1, geometry2, robust_policy, std::back_inserter(geometry_out), strategy); return true; } @@ -122,10 +131,11 @@ struct intersection > : intersection { - template + template static inline bool apply( Geometry1 const& g1, Geometry2 const& g2, + RobustPolicy const& robust_policy, GeometryOut& out, Strategy const& strategy) { @@ -133,7 +143,7 @@ struct intersection Geometry2, Geometry1, Tag2, Tag1, false - >::apply(g2, g1, out, strategy); + >::apply(g2, g1, robust_policy, out, strategy); } }; @@ -186,19 +196,29 @@ inline bool intersection(Geometry1 const& geometry1, concept::check(); concept::check(); + typedef typename geometry::rescale_overlay_policy_type + < + Geometry1, + Geometry2 + >::type rescale_policy_type; + + rescale_policy_type robust_policy + = geometry::get_rescale_policy(geometry1, geometry2); + typedef strategy_intersection < typename cs_tag::type, Geometry1, Geometry2, - typename geometry::point_type::type + typename geometry::point_type::type, + rescale_policy_type > strategy; - - return dispatch::intersection< - Geometry1, - Geometry2 - >::apply(geometry1, geometry2, geometry_out, strategy()); + return dispatch::intersection + < + Geometry1, + Geometry2 + >::apply(geometry1, geometry2, robust_policy, geometry_out, strategy()); } diff --git a/include/boost/geometry/algorithms/intersects.hpp b/include/boost/geometry/algorithms/intersects.hpp index e72c8aa83..8aa45d56c 100644 --- a/include/boost/geometry/algorithms/intersects.hpp +++ b/include/boost/geometry/algorithms/intersects.hpp @@ -19,9 +19,11 @@ #include #include -#include #include +#include +#include + namespace boost { namespace geometry { @@ -44,31 +46,40 @@ inline bool intersects(Geometry const& geometry) { concept::check(); + typedef typename geometry::point_type::type point_type; + typedef typename rescale_policy_type::type + rescale_policy_type; typedef detail::overlay::turn_info < - typename geometry::point_type::type + point_type, + typename segment_ratio_type::type > turn_info; - std::deque turns; - typedef typename strategy_intersection - < - typename cs_tag::type, - Geometry, - Geometry, - typename geometry::point_type::type - >::segment_intersection_strategy_type segment_intersection_strategy_type; + std::deque turns; typedef detail::overlay::get_turn_info < detail::overlay::assign_null_policy > TurnPolicy; + typedef typename strategy_intersection + < + typename cs_tag::type, + Geometry, + Geometry, + point_type, + rescale_policy_type + >::segment_intersection_strategy_type segment_intersection_strategy_type; + + rescale_policy_type robust_policy + = geometry::get_rescale_policy(geometry); + detail::disjoint::disjoint_interrupt_policy policy; detail::self_get_turn_points::get_turns < TurnPolicy - >::apply(geometry, detail::no_rescale_policy(), turns, policy); + >::apply(geometry, robust_policy, turns, policy); return policy.has_intersections; } diff --git a/include/boost/geometry/algorithms/point_on_surface.hpp b/include/boost/geometry/algorithms/point_on_surface.hpp index e6427b628..a6f7ed71d 100644 --- a/include/boost/geometry/algorithms/point_on_surface.hpp +++ b/include/boost/geometry/algorithms/point_on_surface.hpp @@ -315,13 +315,13 @@ inline bool calculate_point_on_surface(Geometry const& geometry, Point& point) /*! -\brief Returns point guaranteed to lie on the surface +\brief Assigns a Point guaranteed to lie on the surface of the Geometry \tparam Geometry geometry type. This also defines the type of the output point -\param point to assign -\param geometry geometry to take point from +\param geometry Geometry to take point from +\param point Point to assign */ template -inline void point_on_surface(Geometry const& geometry, Point& point) +inline void point_on_surface(Geometry const& geometry, Point & point) { concept::check(); concept::check(); @@ -334,12 +334,18 @@ inline void point_on_surface(Geometry const& geometry, Point& point) } } - +/*! +\brief Returns point guaranteed to lie on the surface of the Geometry +\tparam Geometry geometry type. This also defines the type of the output point +\param geometry Geometry to take point from +\return The Point guaranteed to lie on the surface of the Geometry + */ template -inline typename geometry::point_type::type return_point_on_surface(Geometry const& geometry) +inline typename geometry::point_type::type +return_point_on_surface(Geometry const& geometry) { typename geometry::point_type::type result; - point_on_surface(geometry, result); + geometry::point_on_surface(geometry, result); return result; } diff --git a/include/boost/geometry/algorithms/remove_spikes.hpp b/include/boost/geometry/algorithms/remove_spikes.hpp index 634391b64..62845135f 100644 --- a/include/boost/geometry/algorithms/remove_spikes.hpp +++ b/include/boost/geometry/algorithms/remove_spikes.hpp @@ -69,7 +69,7 @@ struct range_remove_spikes std::size_t const min_num_points = core_detail::closure::minimum_ring_size < geometry::closure::value - >::value; + >::value - 1; // subtract one: a polygon with only one spike should result into one point if (n < min_num_points) { return; @@ -104,13 +104,13 @@ struct range_remove_spikes found = false; // Check for spike in first point int const penultimate = 2; - while(cleaned.size() > 3 && detail::point_is_spike_or_equal(cleaned.front(), *(cleaned.end() - penultimate), cleaned.back())) + while(cleaned.size() >= 3 && detail::point_is_spike_or_equal(cleaned.front(), *(cleaned.end() - penultimate), cleaned.back())) { cleaned.pop_back(); found = true; } // Check for spike in second point - while(cleaned.size() > 3 && detail::point_is_spike_or_equal(*(cleaned.begin() + 1), cleaned.back(), cleaned.front())) + while(cleaned.size() >= 3 && detail::point_is_spike_or_equal(*(cleaned.begin() + 1), cleaned.back(), cleaned.front())) { cleaned.pop_front(); found = true; @@ -118,6 +118,13 @@ struct range_remove_spikes } while (found); + if (cleaned.size() == 2) + { + // Ticket #9871: open polygon with only two points. + // the second point forms, by definition, a spike + cleaned.pop_back(); + } + // Close if necessary if (geometry::closure::value == geometry::closed) { diff --git a/include/boost/geometry/algorithms/sym_difference.hpp b/include/boost/geometry/algorithms/sym_difference.hpp index 28affc43c..de34c9c7b 100644 --- a/include/boost/geometry/algorithms/sym_difference.hpp +++ b/include/boost/geometry/algorithms/sym_difference.hpp @@ -46,11 +46,14 @@ template typename GeometryOut, typename Geometry1, typename Geometry2, + typename RobustPolicy, typename OutputIterator, typename Strategy > inline OutputIterator sym_difference_insert(Geometry1 const& geometry1, - Geometry2 const& geometry2, OutputIterator out, + Geometry2 const& geometry2, + RobustPolicy const& robust_policy, + OutputIterator out, Strategy const& strategy) { concept::check(); @@ -64,7 +67,7 @@ inline OutputIterator sym_difference_insert(Geometry1 const& geometry1, overlay_difference, geometry::detail::overlay::do_reverse::value>::value, geometry::detail::overlay::do_reverse::value, true>::value - >::apply(geometry1, geometry2, out, strategy); + >::apply(geometry1, geometry2, robust_policy, out, strategy); out = geometry::dispatch::intersection_insert < Geometry2, Geometry1, @@ -73,7 +76,7 @@ inline OutputIterator sym_difference_insert(Geometry1 const& geometry1, geometry::detail::overlay::do_reverse::value>::value, geometry::detail::overlay::do_reverse::value, true>::value, geometry::detail::overlay::do_reverse::value>::value - >::apply(geometry2, geometry1, out, strategy); + >::apply(geometry2, geometry1, robust_policy, out, strategy); return out; } @@ -97,10 +100,12 @@ template typename GeometryOut, typename Geometry1, typename Geometry2, + typename RobustPolicy, typename OutputIterator > inline OutputIterator sym_difference_insert(Geometry1 const& geometry1, - Geometry2 const& geometry2, OutputIterator out) + Geometry2 const& geometry2, + RobustPolicy const& robust_policy, OutputIterator out) { concept::check(); concept::check(); @@ -111,10 +116,11 @@ inline OutputIterator sym_difference_insert(Geometry1 const& geometry1, typename cs_tag::type, Geometry1, Geometry2, - typename geometry::point_type::type + typename geometry::point_type::type, + RobustPolicy > strategy_type; - return sym_difference_insert(geometry1, geometry2, out, strategy_type()); + return sym_difference_insert(geometry1, geometry2, robust_policy, out, strategy_type()); } }} // namespace detail::sym_difference @@ -150,8 +156,17 @@ inline void sym_difference(Geometry1 const& geometry1, typedef typename boost::range_value::type geometry_out; concept::check(); + typedef typename geometry::rescale_overlay_policy_type + < + Geometry1, + Geometry2 + >::type rescale_policy_type; + + rescale_policy_type robust_policy + = geometry::get_rescale_policy(geometry1, geometry2); + detail::sym_difference::sym_difference_insert( - geometry1, geometry2, + geometry1, geometry2, robust_policy, std::back_inserter(output_collection)); } diff --git a/include/boost/geometry/algorithms/touches.hpp b/include/boost/geometry/algorithms/touches.hpp index a34ac777e..5ffc3eb34 100644 --- a/include/boost/geometry/algorithms/touches.hpp +++ b/include/boost/geometry/algorithms/touches.hpp @@ -5,8 +5,8 @@ // Copyright (c) 2009-2012 Mateusz Loskot, London, UK. // Copyright (c) 2013 Adam Wulkiewicz, Lodz, Poland. -// This file was modified by Oracle on 2013. -// Modifications copyright (c) 2013, Oracle and/or its affiliates. +// This file was modified by Oracle on 2013, 2014. +// Modifications copyright (c) 2013, 2014, Oracle and/or its affiliates. // Parts of Boost.Geometry are redesigned from Geodan's Geographic Library // (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands. @@ -15,6 +15,8 @@ // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) +// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle + #ifndef BOOST_GEOMETRY_ALGORITHMS_TOUCHES_HPP #define BOOST_GEOMETRY_ALGORITHMS_TOUCHES_HPP @@ -29,10 +31,13 @@ #include #include #include +#include #include #include #include +#include + namespace boost { namespace geometry { @@ -40,6 +45,86 @@ namespace boost { namespace geometry namespace detail { namespace touches { +// Box/Box + +template +< + std::size_t Dimension, + std::size_t DimensionCount +> +struct box_box_loop +{ + template + static inline bool apply(Box1 const& b1, Box2 const& b2, bool & touch) + { + typedef typename coordinate_type::type coordinate_type1; + typedef typename coordinate_type::type coordinate_type2; + + coordinate_type1 const& min1 = get(b1); + coordinate_type1 const& max1 = get(b1); + coordinate_type2 const& min2 = get(b2); + coordinate_type2 const& max2 = get(b2); + + // TODO assert or exception? + //BOOST_ASSERT(min1 <= max1 && min2 <= max2); + + if ( max1 < min2 || max2 < min1 ) + { + return false; + } + + if ( max1 == min2 || max2 == min1 ) + { + touch = true; + } + + return box_box_loop + < + Dimension + 1, + DimensionCount + >::apply(b1, b2, touch); + } +}; + +template +< + std::size_t DimensionCount +> +struct box_box_loop +{ + template + static inline bool apply(Box1 const& , Box2 const&, bool &) + { + return true; + } +}; + +struct box_box +{ + template + static inline bool apply(Box1 const& b1, Box2 const& b2) + { + BOOST_STATIC_ASSERT((boost::is_same + < + typename geometry::coordinate_system::type, + typename geometry::coordinate_system::type + >::value + )); + assert_dimension_equal(); + + bool touches = false; + bool ok = box_box_loop + < + 0, + dimension::type::value + >::apply(b1, b2, touches); + + return ok && touches; + } +}; + +// Areal/Areal + struct areal_interrupt_policy { static bool const enabled = true; @@ -117,134 +202,6 @@ struct areal_interrupt_policy } }; -template -struct linear_areal_interrupt_policy -{ - static bool const enabled = true; - bool found_touch; - bool found_not_touch; - - Linear const& linear; - - // dummy variable required by self_get_turn_points::get_turns - static bool const has_intersections = false; - - inline bool result() - { - return found_touch && !found_not_touch; - } - - inline linear_areal_interrupt_policy(Linear const& l) - : found_touch(false), found_not_touch(false), linear(l) - {} - - template - inline bool apply(Range const& range) - { - // if already rejected (temp workaround?) - if ( found_not_touch ) - return true; - - typedef typename boost::range_iterator::type iterator; - for ( iterator it = boost::begin(range) ; it != boost::end(range) ; ++it ) - { - if ( it->operations[0].operation == overlay::operation_intersection ) - { - if ( it->operations[1].operation == overlay::operation_union && - is_turn_on_last_point(*it) ) - { - found_touch = true; - continue; - } - else - { - found_not_touch = true; - return true; - } - } - - switch(it->method) - { - case overlay::method_crosses: - found_not_touch = true; - return true; - case overlay::method_equal: - case overlay::method_touch: - case overlay::method_touch_interior: - case overlay::method_collinear: - if ( ok_for_touch(*it) ) - { - found_touch = true; - } - else - { - found_not_touch = true; - return true; - } - break; - case overlay::method_none : - case overlay::method_disjoint : - case overlay::method_error : - break; - } - } - - return false; - } - - template - inline bool ok_for_touch(Turn const& turn) - { - return turn.both(overlay::operation_union) - || turn.both(overlay::operation_blocked) - || turn.combination(overlay::operation_union, overlay::operation_blocked) - - || turn.both(overlay::operation_continue) - || turn.combination(overlay::operation_union, overlay::operation_intersection) - ; - } - - template - inline bool is_turn_on_last_point(Turn const& turn) - { - typename sub_range_return_type::type - g = sub_range(linear, turn.operations[0].seg_id); - - std::size_t s = boost::size(g); - - if ( s == 0 ) - return false; // shouldn't return here - else if ( s == 1 ) - return equals::equals_point_point(turn.point, *boost::begin(g)); // nor here - else - return equals::equals_point_point(turn.point, *(boost::end(g)-1)); - } -}; - -template -struct turns_count_interrupt_policy -{ - static bool const enabled = true; - std::size_t turns_count; - - // dummy variable required by self_get_turn_points::get_turns - static bool const has_intersections = false; - - inline turns_count_interrupt_policy() - : turns_count(0) - {} - - template - inline bool apply(Range const& range) - { - turns_count += boost::size(range); - if ( Max < turns_count ) - return true; - return false; - } -}; - - template struct check_each_ring_for_within { @@ -261,16 +218,13 @@ struct check_each_ring_for_within { typename geometry::point_type::type p; geometry::point_on_border(p, range); - if (geometry::within(p, m_geometry)) + if ( !has_within && geometry::within(p, m_geometry) ) { has_within = true; } } }; -// TODO: currently this function checks if a point of at least one range from g2 is within g1 -// shouldn't it check the opposite? - template inline bool rings_containing(FirstGeometry const& geometry1, SecondGeometry const& geometry2) @@ -286,9 +240,12 @@ struct areal_areal static inline bool apply(Geometry1 const& geometry1, Geometry2 const& geometry2) { + typedef detail::no_rescale_policy rescale_policy_type; + typedef typename geometry::point_type::type point_type; typedef detail::overlay::turn_info < - typename geometry::point_type::type + point_type, + typename segment_ratio_type::type > turn_info; typedef detail::overlay::get_turn_info @@ -298,12 +255,13 @@ struct areal_areal std::deque turns; detail::touches::areal_interrupt_policy policy; + rescale_policy_type robust_policy; boost::geometry::get_turns < detail::overlay::do_reverse::value>::value, detail::overlay::do_reverse::value>::value, detail::overlay::assign_null_policy - >(geometry1, geometry2, detail::no_rescale_policy(), turns, policy); + >(geometry1, geometry2, robust_policy, turns, policy); return policy.result() && ! geometry::detail::touches::rings_containing(geometry1, geometry2) @@ -311,99 +269,17 @@ struct areal_areal } }; -template -struct linear_areal +// P/* + +struct use_point_in_geometry { - static inline - bool apply(Geometry1 const& geometry1, Geometry2 const& geometry2) - { - typedef detail::overlay::turn_info - < - typename geometry::point_type::type - > turn_info; - - typedef detail::overlay::get_turn_info - < - detail::overlay::assign_null_policy - > policy_type; - - std::deque turns; - detail::touches::linear_areal_interrupt_policy policy(geometry1); - boost::geometry::get_turns - < - detail::overlay::do_reverse::value>::value, - detail::overlay::do_reverse::value>::value, - detail::overlay::assign_null_policy - >(geometry1, geometry2, detail::no_rescale_policy(), turns, policy); - - return policy.result() - && ! geometry::detail::touches::rings_containing(geometry2, geometry1); - } -}; - -template -struct point_geometry -{ - static inline - bool apply(Point const& point, Geometry const& geometry) + template + static inline bool apply(Point const& point, Geometry const& geometry) { return detail::within::point_in_geometry(point, geometry) == 0; } }; -template -struct linestring_linestring -{ - static inline - bool apply(Geometry1 const& geometry1, Geometry2 const& geometry2) - { - std::size_t s1 = boost::size(geometry1); - std::size_t s2 = boost::size(geometry2); - // TODO: throw on empty input? - if ( s1 == 0 || s2 == 0 ) - return false; - - typedef detail::overlay::turn_info - < - typename geometry::point_type::type - > turn_info; - - typedef detail::overlay::get_turn_info - < - detail::overlay::assign_null_policy - > policy_type; - - std::deque turns; - turns_count_interrupt_policy<2> policy; - boost::geometry::get_turns - < - detail::overlay::do_reverse::value>::value, - detail::overlay::do_reverse::value>::value, - detail::overlay::assign_null_policy - >(geometry1, geometry2, detail::no_rescale_policy(), turns, policy); - - if ( 2 < policy.turns_count ) - return false; - else if ( 2 == policy.turns_count ) - { - return ( detail::equals::equals_point_point(turns[0].point, *(boost::end(geometry1)-1)) - && detail::equals::equals_point_point(turns[1].point, *(boost::end(geometry2)-1)) ) - || ( detail::equals::equals_point_point(turns[0].point, *(boost::end(geometry2)-1)) - && detail::equals::equals_point_point(turns[1].point, *(boost::end(geometry1)-1)) ); - } - else if ( 1 == policy.turns_count ) - { - return detail::equals::equals_point_point(turns[0].point, *(boost::end(geometry1)-1)) - || detail::equals::equals_point_point(turns[0].point, *(boost::end(geometry2)-1)); - } - else - { - return detail::within::point_in_geometry(*boost::begin(geometry1), geometry2) >= 0 - || detail::within::point_in_geometry(*boost::begin(geometry2), geometry1) >= 0; - } - } -}; - }} #endif // DOXYGEN_NO_DETAIL @@ -417,11 +293,12 @@ template typename Geometry1, typename Geometry2, typename Tag1 = typename tag::type, typename Tag2 = typename tag::type, - typename CastedTag1 = typename tag_cast::type, - typename CastedTag2 = typename tag_cast::type, + typename CastedTag1 = typename tag_cast::type, + typename CastedTag2 = typename tag_cast::type, bool Reverse = reverse_dispatch::type::value > -struct touches : not_implemented +struct touches + : not_implemented {}; // If reversal is needed, perform it @@ -440,10 +317,10 @@ struct touches } }; -// touches(Pt, Pt), touches(Pt, MPt), touches(MPt, MPt) +// P/P + template -struct touches - : detail::touches::point_geometry +struct touches { static inline bool apply(Geometry1 const& , Geometry2 const& ) { @@ -451,38 +328,64 @@ struct touches } }; -// touches(Point, Linear), touches(Point, Areal) +// P/* + template -struct touches - : detail::touches::point_geometry +struct touches + : detail::touches::use_point_in_geometry {}; // TODO: support touches(MPt, Linear/Areal) -// touches(Linestring, Linestring) -template -struct touches - : detail::touches::linestring_linestring +// Box/Box + +template +struct touches + : detail::touches::box_box {}; -// TODO: support touches(MLs, MLs) and touches(Ls, MLs) +template +struct touches + : detail::touches::box_box +{}; + +// L/L + +template +struct touches + : detail::relate::relate_base + < + detail::relate::static_mask_touches_type, + Linear1, + Linear2 + > +{}; + +// L/A -// touches(Linear, Areal) template struct touches - : detail::touches::linear_areal + : detail::relate::relate_base + < + detail::relate::static_mask_touches_type, + Linear, + Areal + > {}; -// e.g. for touches(Poly, MLs) -template -struct touches -{ - static inline bool apply(Areal const& areal, Linear const& linear) - { - return detail::touches::linear_areal::apply(linear, areal); - } -}; -// touches(Areal, Areal) +// A/L +template +struct touches + : detail::relate::relate_base + < + detail::relate::static_mask_touches_type, + Areal, + Linear + > +{}; + +// A/A + template struct touches : detail::touches::areal_areal @@ -585,10 +488,13 @@ struct self_touches { concept::check(); + typedef detail::no_rescale_policy rescale_policy_type; + typedef typename geometry::point_type::type point_type; typedef detail::overlay::turn_info - < - typename geometry::point_type::type - > turn_info; + < + point_type, + typename segment_ratio_type::type + > turn_info; typedef detail::overlay::get_turn_info < @@ -597,10 +503,11 @@ struct self_touches std::deque turns; detail::touches::areal_interrupt_policy policy; + rescale_policy_type robust_policy; detail::self_get_turn_points::get_turns < policy_type - >::apply(geometry, detail::no_rescale_policy(), turns, policy); + >::apply(geometry, robust_policy, turns, policy); return policy.result(); } diff --git a/include/boost/geometry/algorithms/union.hpp b/include/boost/geometry/algorithms/union.hpp index a6ad7be44..ca9b8ff11 100644 --- a/include/boost/geometry/algorithms/union.hpp +++ b/include/boost/geometry/algorithms/union.hpp @@ -23,6 +23,7 @@ #include #include #include +#include #include #include @@ -71,15 +72,17 @@ struct union_insert true >: union_insert { - template + template static inline OutputIterator apply(Geometry1 const& g1, - Geometry2 const& g2, OutputIterator out, + Geometry2 const& g2, + RobustPolicy const& robust_policy, + OutputIterator out, Strategy const& strategy) { return union_insert < Geometry2, Geometry1, GeometryOut - >::apply(g2, g1, out, strategy); + >::apply(g2, g1, robust_policy, out, strategy); } }; @@ -180,18 +183,20 @@ template < typename GeometryOut, typename Geometry1, typename Geometry2, + typename RobustPolicy, typename OutputIterator, typename Strategy > inline OutputIterator insert(Geometry1 const& geometry1, Geometry2 const& geometry2, + RobustPolicy const& robust_policy, OutputIterator out, Strategy const& strategy) { return dispatch::union_insert < Geometry1, Geometry2, GeometryOut - >::apply(geometry1, geometry2, out, strategy); + >::apply(geometry1, geometry2, robust_policy, out, strategy); } /*! @@ -229,7 +234,11 @@ inline OutputIterator union_insert(Geometry1 const& geometry1, concept::check(); concept::check(); - return detail::union_::insert(geometry1, geometry2, out, strategy); + typedef typename Strategy::rescale_policy_type rescale_policy_type; + rescale_policy_type robust_policy + = geometry::get_rescale_policy(geometry1, geometry2); + + return detail::union_::insert(geometry1, geometry2, robust_policy, out, strategy); } /*! @@ -261,12 +270,19 @@ inline OutputIterator union_insert(Geometry1 const& geometry1, concept::check(); concept::check(); + typedef typename geometry::rescale_overlay_policy_type + < + Geometry1, + Geometry2 + >::type rescale_policy_type; + typedef strategy_intersection < typename cs_tag::type, Geometry1, Geometry2, - typename geometry::point_type::type + typename geometry::point_type::type, + rescale_policy_type > strategy; return union_insert(geometry1, geometry2, out, strategy()); diff --git a/include/boost/geometry/core/tag.hpp b/include/boost/geometry/core/tag.hpp index 9f6a3577e..6bffcb932 100644 --- a/include/boost/geometry/core/tag.hpp +++ b/include/boost/geometry/core/tag.hpp @@ -14,7 +14,6 @@ #ifndef BOOST_GEOMETRY_CORE_TAG_HPP #define BOOST_GEOMETRY_CORE_TAG_HPP - #include #include diff --git a/include/boost/geometry/extensions/algorithms/buffer/buffer_inserter.hpp b/include/boost/geometry/extensions/algorithms/buffer/buffer_inserter.hpp index 767182177..063d4283f 100644 --- a/include/boost/geometry/extensions/algorithms/buffer/buffer_inserter.hpp +++ b/include/boost/geometry/extensions/algorithms/buffer/buffer_inserter.hpp @@ -447,7 +447,8 @@ template typename OutputIterator, typename DistanceStrategy, typename JoinStrategy, - typename EndStrategy + typename EndStrategy, + typename RobustPolicy #ifdef BOOST_GEOMETRY_DEBUG_WITH_MAPPER , typename Mapper #endif @@ -455,7 +456,8 @@ template inline void buffer_inserter(GeometryInput const& geometry_input, OutputIterator out, DistanceStrategy const& distance_strategy, JoinStrategy const& join_strategy, - EndStrategy const& end_strategy + EndStrategy const& end_strategy, + RobustPolicy const& robust_policy #ifdef BOOST_GEOMETRY_DEBUG_WITH_MAPPER , Mapper& mapper #endif @@ -467,8 +469,9 @@ inline void buffer_inserter(GeometryInput const& geometry_input, OutputIterator detail::buffer::buffered_piece_collection #endif < - typename geometry::ring_type::type - > collection; + typename geometry::ring_type::type, + RobustPolicy + > collection(robust_policy); dispatch::buffer_inserter < @@ -495,7 +498,7 @@ inline void buffer_inserter(GeometryInput const& geometry_input, OutputIterator #ifdef BOOST_GEOMETRY_DEBUG_WITH_MAPPER //collection.map_turns(mapper); - collection.map_pieces(mapper); //, false, true); + collection.template map_pieces(mapper); //, false, true); //collection.map_traverse(mapper); #endif diff --git a/include/boost/geometry/extensions/algorithms/buffer/buffer_policies.hpp b/include/boost/geometry/extensions/algorithms/buffer/buffer_policies.hpp index 8efc0af46..5039c514b 100644 --- a/include/boost/geometry/extensions/algorithms/buffer/buffer_policies.hpp +++ b/include/boost/geometry/extensions/algorithms/buffer/buffer_policies.hpp @@ -21,7 +21,6 @@ #include #include -#include #include @@ -46,14 +45,14 @@ class backtrack_for_buffer public : typedef detail::overlay::backtrack_state state_type; - template + template static inline void apply(std::size_t size_at_start, Rings& rings, typename boost::range_value::type& ring, Turns& turns, Operation& operation, std::string const& /*reason*/, Geometry const& , Geometry const& , - RescalePolicy const& , + RobustPolicy const& , state_type& state ) { @@ -88,8 +87,6 @@ struct turn_assign_for_buffer template static inline void apply(Turn& turn, Point1 const& p1, Point2 const& p2, IntersectionInfo const& intersection_info, DirInfo const& dir_info) { - detail::overlay::calculate_distance_policy::apply(turn, p1, p2, - intersection_info, dir_info); if (dir_info.opposite && intersection_info.count == 2) { turn.is_opposite = true; @@ -99,8 +96,9 @@ struct turn_assign_for_buffer // Should follow traversal-turn-concept (enrichment, visit structure) // and adds index in piece vector to find it back -template -struct buffer_turn_operation : public detail::overlay::traversal_turn_operation +template +struct buffer_turn_operation + : public detail::overlay::traversal_turn_operation { int piece_index; bool include_in_occupation_map; @@ -112,8 +110,14 @@ struct buffer_turn_operation : public detail::overlay::traversal_turn_operation< }; // Version for buffer including type of location, is_opposite, and helper variables -template -struct buffer_turn_info : public detail::overlay::turn_info > +template +struct buffer_turn_info + : public detail::overlay::turn_info + < + Point, + SegmentRatio, + buffer_turn_operation + > { bool is_opposite; diff --git a/include/boost/geometry/extensions/algorithms/buffer/buffered_piece_collection.hpp b/include/boost/geometry/extensions/algorithms/buffer/buffered_piece_collection.hpp index 4055d39f1..1f7e6efee 100644 --- a/include/boost/geometry/extensions/algorithms/buffer/buffered_piece_collection.hpp +++ b/include/boost/geometry/extensions/algorithms/buffer/buffered_piece_collection.hpp @@ -30,7 +30,6 @@ #include #include -#include #include #include #include @@ -104,61 +103,7 @@ struct check_original }; -template -class relaxed_side -{ -public : - - // Template member function, because it is not always trivial - // or convenient to explicitly mention the typenames in the - // strategy-struct itself. - - // Types can be all three different. Therefore it is - // not implemented (anymore) as "segment" - - static inline int apply(P const& p1, P const& p2, P const& p) - { - typedef typename coordinate_type

::type coordinate_type; - - coordinate_type const x = get<0>(p); - coordinate_type const y = get<1>(p); - - coordinate_type const sx1 = get<0>(p1); - coordinate_type const sy1 = get<1>(p1); - coordinate_type const sx2 = get<0>(p2); - coordinate_type const sy2 = get<1>(p2); - - // Promote float->double, small int->int - typedef typename geometry::select_most_precise - < - coordinate_type, - double - >::type promoted_type; - - promoted_type const dx = sx2 - sx1; - promoted_type const dy = sy2 - sy1; - promoted_type const dpx = x - sx1; - promoted_type const dpy = y - sy1; - - promoted_type const s - = geometry::detail::determinant - ( - dx, dy, - dpx, dpy - ); - - promoted_type const zero = promoted_type(); - promoted_type const relaxed_epsilon = std::numeric_limits::epsilon() * 5.0; - - return math::abs(s) < relaxed_epsilon ? 0 - : s > zero ? 1 - : -1; - } -}; - - - -template +template struct buffered_piece_collection { typedef typename geometry::point_type::type point_type; @@ -193,20 +138,42 @@ struct buffered_piece_collection std::map, std::set > m_turn_indices_per_segment_pair; + typedef typename geometry::rescale_policy_type + < + typename geometry::point_type::type + >::type rescale_policy_type; + + typedef typename geometry::segment_ratio_type + < + point_type, + RobustPolicy + >::type segment_ratio_type; + + typedef buffer_turn_info + < + point_type, + segment_ratio_type + > buffer_turn_info_type; + + typedef buffer_turn_operation + < + point_type, + segment_ratio_type + > buffer_turn_operation_type; + + typedef std::vector turn_vector_type; - typedef std::vector > turn_vector_type; typedef detail::overlay::get_turn_info < turn_assign_for_buffer > turn_policy; turn_vector_type m_turns; - geometry::detail::no_rescale_policy m_rescale_policy; - - // To check clustered locations we keep track of segments being opposite somewhere std::set m_in_opposite_segments; + RobustPolicy const& m_rescale_policy; + struct buffer_occupation_info : public occupation_info > { std::set seg_ids; @@ -216,10 +183,9 @@ struct buffered_piece_collection typedef occupation_map occupation_map_type; occupation_map_type m_occupation_map; - struct redundant_turn { - inline bool operator()(buffer_turn_info const& turn) const + inline bool operator()(buffer_turn_info_type const& turn) const { // Erase discarded turns (location not OK) and the turns // only used to detect oppositeness. @@ -228,6 +194,10 @@ struct buffered_piece_collection } }; + buffered_piece_collection(RobustPolicy const& robust_policy) + : m_rescale_policy(robust_policy) + {} + inline bool is_neighbor(piece const& piece1, piece const& piece2) const { @@ -294,7 +264,7 @@ struct buffered_piece_collection iterator it2_first = boost::begin(ring2) + seg_id2.segment_index; iterator it2_last = boost::begin(ring2) + piece2.last_segment_index; - buffer_turn_info the_model; + buffer_turn_info_type the_model; the_model.operations[0].piece_index = piece1.index; the_model.operations[0].seg_id = piece1.first_seg_id; @@ -340,32 +310,7 @@ struct buffered_piece_collection } } - inline segment_relation_code get_segment_relation(point_type const& point, - segment_identifier const& seg_id) const - { - typedef typename boost::range_iterator const>::type iterator_type; - iterator_type it = boost::begin(offsetted_rings[seg_id.multi_index]) + seg_id.segment_index; - iterator_type prev = it++; - int side = side_strategy::apply(point, *prev, *it); - if (side == 0) - { - if (geometry::equals(point, *prev)) - { - return segment_relation_on_left; - } - else if (geometry::equals(point, *it)) - { - return segment_relation_on_right; - } - else if (collinear_point_on_segment(point, *prev, *it)) - { - return segment_relation_within; - } - } - return segment_relation_disjoint; - } - - inline void add_angles(int turn_index, int operation_index, point_type const& point, buffer_turn_operation const& operation) + inline void add_angles(int turn_index, int operation_index, point_type const& point, buffer_turn_operation_type const& operation) { point_type mapped_point; buffer_occupation_info& info = m_occupation_map.find_or_insert(point, mapped_point); @@ -384,7 +329,7 @@ struct buffered_piece_collection { m_occupation_map.insert_turn_index(turn_index); - buffer_turn_info const& turn = m_turns[turn_index]; + buffer_turn_info_type const& turn = m_turns[turn_index]; //std::cout << "Adding point " << turn_index << " " << geometry::wkt(turn.point) << std::endl; @@ -395,7 +340,7 @@ struct buffered_piece_collection - inline void classify_turn(buffer_turn_info& turn, piece const& pc) const + inline void classify_turn(buffer_turn_info_type& turn, piece const& pc) const { if (pc.type == buffered_flat_end) { @@ -440,10 +385,10 @@ struct buffered_piece_collection { // The piece is a full (pseudo) circle. There are no helper segments. We only check if it is the turn is inside the generated circle, // or on the border. - int const side_wrt_circle = side_on_convex_range< /*relaxed_side */ side_strategy >(turn.point, + int const side_wrt_circle = side_on_convex_range(turn.point, boost::begin(ring) + seg_id.segment_index, boost::begin(ring) + pc.last_segment_index, - seg_id, on_segment_seg_id); + seg_id, on_segment_seg_id, m_rescale_policy); switch (side_wrt_circle) { case 0 : turn.count_on_offsetted++; break; @@ -452,17 +397,17 @@ struct buffered_piece_collection return; } - int side_helper = side_on_convex_range(turn.point, pc.helper_segments); + int side_helper = side_on_convex_range(turn.point, pc.helper_segments, m_rescale_policy); if (side_helper == 1) { // Left or outside return; } - int const side_offsetted = side_on_convex_range< /*relaxed_side */ side_strategy >(turn.point, + int const side_offsetted = side_on_convex_range(turn.point, boost::begin(ring) + seg_id.segment_index, boost::begin(ring) + pc.last_segment_index, - seg_id, on_segment_seg_id); + seg_id, on_segment_seg_id, m_rescale_policy); if (side_offsetted == 1) { return; @@ -479,8 +424,8 @@ struct buffered_piece_collection } if (side_helper == 0) { - if (geometry::equals(turn.point, pc.helper_segments.back()) - || geometry::equals(turn.point, pc.helper_segments.front())) + if (detail::overlay::points_equal_or_close(turn.point, pc.helper_segments.back(), m_rescale_policy) + || detail::overlay::points_equal_or_close(turn.point, pc.helper_segments.front(), m_rescale_policy)) { turn.count_on_corner++; } @@ -692,17 +637,6 @@ struct buffered_piece_collection } } -#define BOOST_GEOMETRY_DEBUG_BUFFER_SITUATION_MAP -#ifdef BOOST_GEOMETRY_DEBUG_BUFFER_SITUATION_MAP - inline int get_side(point_type const& point, Ring const& ring, int segment_index) - { - typedef typename boost::range_iterator iterator_type; - iterator_type it = boost::begin(ring) + segment_index; - iterator_type prev = it++; - return side_strategy::apply(point, *prev, *it); - } -#endif - template static inline point_type const& select_for_side(Iterator first, Iterator second, int index) { @@ -723,53 +657,32 @@ struct buffered_piece_collection iterator_type prev1 = it1++; iterator_type prev2 = it2++; - int code1 = side_strategy::apply(select_for_side(prev1, it1, which), *prev2, *it2); - int code2 = side_strategy::apply(select_for_side(prev2, it2, which), *prev1, *it1); + typedef typename geometry::robust_point_type + < + point_type, + RobustPolicy + >::type robust_point_type; + + robust_point_type p1_rob, p2_rob, prev1_rob, prev2_rob, cur1_rob, cur2_rob; + geometry::recalculate(p1_rob, select_for_side(prev1, it1, which), m_rescale_policy); + geometry::recalculate(p2_rob, select_for_side(prev2, it2, which), m_rescale_policy); + geometry::recalculate(prev1_rob, *prev1, m_rescale_policy); + geometry::recalculate(prev2_rob, *prev2, m_rescale_policy); + geometry::recalculate(cur1_rob, *it1, m_rescale_policy); + geometry::recalculate(cur2_rob, *it2, m_rescale_policy); + + int const code1 = side_strategy::apply(p1_rob, prev2_rob, cur2_rob); + int const code2 = side_strategy::apply(p2_rob, prev1_rob, cur1_rob); if (code1 == 1 && code2 == -1) return 1; if (code1 == -1 && code2 == 1) return -1; - // ROBUSTNESS: in near collinear cases one might be zero, the other non-zero. - // This happens several times. - if (code1 != 0) return code1; - if (code2 != 0) return -code2; - - // // Check if the other side gives some more info - // // (I've never seen this is the case though it might be so, if they are much longer. - //int code1f = side_strategy::apply(*prev1, *prev2, *it2); - //int code2f = side_strategy::apply(*prev2, *prev1, *it1); - - // if (code1f != 0 || code2f != 0) - // { - // std::cout << "From: " << code1f << " " << code2f << std::endl; - // if (code1f != 0) return -code1f; - // if (code2f != 0) return code2f; - // } - - // Collinear? -#ifdef BOOST_GEOMETRY_DEBUG_BUFFER_SITUATION_MAP - //std::cout << "Collinear: " << code1 << " " << code2 << std::endl; -#endif return 0; } - - - inline void debug_segment(segment_identifier id) - { - typedef typename boost::range_iterator const>::type iterator; - - buffered_ring const& ring = offsetted_rings[id.multi_index]; - iterator it = boost::begin(ring) + id.segment_index; - iterator prev = it++; - geometry::model::referring_segment segment(*prev, *it); - //std::cout << geometry::wkt(*prev) << " " << geometry::wkt(*it) << std::endl; - } - - struct cluster_info { - inline cluster_info(int i, point_type p, buffer_turn_operation op) + inline cluster_info(int i, point_type p, buffer_turn_operation_type op) : turn_index(i) , point(p) , operation(op) @@ -781,7 +694,7 @@ struct buffered_piece_collection int turn_index; point_type point; - buffer_turn_operation operation; + buffer_turn_operation_type operation; }; struct clustered_info @@ -791,14 +704,6 @@ struct buffered_piece_collection std::vector intersecting_segments; }; -#ifdef OLD - struct situation_info - { - std::set turn_indices; - std::set seg_ids; - }; -#endif - static inline bool add_mutual_intersection(clustered_info const& cluster, segment_identifier const& seg_id) { bool result = false; @@ -838,19 +743,12 @@ struct buffered_piece_collection return true; } - if (geometry::equals(a.point, b.point)) + if (detail::overlay::points_equal_or_close(a.point, b.point, m_rescale_policy)) { std::cout << "="; return true; } - relaxed_less comparator; - if (comparator.equals(a.point, b.point)) - { - std::cout << "*"; - return true; - } - return false; } @@ -891,7 +789,7 @@ struct buffered_piece_collection for (typename boost::range_iterator::type it = boost::begin(m_turns); it != boost::end(m_turns); ++it, ++index) { - buffer_turn_info const& turn = *it; + buffer_turn_info_type const& turn = *it; // Take care with all the indices map[turn.operations[0].seg_id].piece_index = turn.operations[0].piece_index; @@ -924,7 +822,7 @@ struct buffered_piece_collection for (typename boost::range_iterator::type it = boost::begin(m_turns); it != boost::end(m_turns); ++it, ++index) { - buffer_turn_info& turn = *it; + buffer_turn_info_type& turn = *it; //std::cout << "Referring to point " << geometry::wkt(turn.point) << std::endl; if (m_in_opposite_segments.count(turn.operations[0].seg_id) > 0 || m_in_opposite_segments.count(turn.operations[1].seg_id) > 0) @@ -941,7 +839,7 @@ struct buffered_piece_collection for (typename boost::range_iterator::type it = boost::begin(m_turns); it != boost::end(m_turns); ++it, ++index) { - buffer_turn_info& turn = *it; + buffer_turn_info_type& turn = *it; if (m_in_opposite_segments.count(turn.operations[0].seg_id) == 0 && m_in_opposite_segments.count(turn.operations[1].seg_id) == 0) { diff --git a/include/boost/geometry/extensions/algorithms/buffer/buffered_piece_collection_with_mapper.hpp b/include/boost/geometry/extensions/algorithms/buffer/buffered_piece_collection_with_mapper.hpp index 2cd7bb220..4ef8c2307 100644 --- a/include/boost/geometry/extensions/algorithms/buffer/buffered_piece_collection_with_mapper.hpp +++ b/include/boost/geometry/extensions/algorithms/buffer/buffered_piece_collection_with_mapper.hpp @@ -26,18 +26,24 @@ namespace detail { namespace buffer #ifdef BOOST_GEOMETRY_DEBUG_WITH_MAPPER -template +template struct buffered_piece_collection_with_mapper - : public buffered_piece_collection + : public buffered_piece_collection { + typedef buffered_piece_collection super_type; + + buffered_piece_collection_with_mapper(RobustPolicy const& robust_policy) + : super_type(robust_policy) + {} template inline void map_opposite_locations(Mapper& mapper) { + typedef typename super_type::occupation_map_type occupation_map_type; for (typename boost::range_iterator::type it = - boost::begin(m_occupation_map.map); - it != boost::end(m_occupation_map.map); ++it) + boost::begin(this->m_occupation_map.map); + it != boost::end(this->m_occupation_map.map); ++it) { mapper.map(it->first, it->second.occupied() ? "fill:rgb(255,0,255);" : "fill:rgb(0,192,0);", 7); @@ -55,6 +61,8 @@ struct buffered_piece_collection_with_mapper bool const incoming = it->second.angles[i].incoming; segment_identifier seg_id = it->second.angles[i].seg_id; + typedef typename super_type::point_type point_type; + geometry::model::linestring line; point_type p1, p2; geometry::set<0>(p1, geometry::get<0>(it->first) + cos(angle) * 0.1); @@ -90,13 +98,16 @@ struct buffered_piece_collection_with_mapper template inline void map_turns(Mapper& mapper) { + typedef typename super_type::point_type point_type; + typedef typename super_type::turn_vector_type turn_vector_type; + typedef typename geometry::coordinate_type::type coordinate_type; std::map, int> offsets; int index = 0; for (typename boost::range_iterator::type it = - boost::begin(m_turns); it != boost::end(m_turns); ++it) + boost::begin(this->m_turns); it != boost::end(this->m_turns); ++it) { if (! it->opposite()) { @@ -152,8 +163,9 @@ struct buffered_piece_collection_with_mapper template inline void map_pieces(Mapper& mapper, bool pieces = true, bool indices = true) { - for(typename piece_vector::const_iterator it = boost::begin(m_pieces); - it != boost::end(m_pieces); + typedef typename super_type::piece_vector piece_vector; + for(typename piece_vector::const_iterator it = boost::begin(this->m_pieces); + it != boost::end(this->m_pieces); ++it) { Ring corner; @@ -162,7 +174,7 @@ struct buffered_piece_collection_with_mapper if (seg_id.segment_index >= 0) { - buffered_ring const& ring = offsetted_rings[seg_id.multi_index]; + buffered_ring const& ring = this->offsetted_rings[seg_id.multi_index]; std::copy(boost::begin(ring) + seg_id.segment_index, boost::begin(ring) + it->last_segment_index, @@ -207,6 +219,8 @@ struct buffered_piece_collection_with_mapper { // Put starting piece_index / segment_index in centroid + typedef typename super_type::point_type point_type; + point_type centroid; if (corner.size() > 3) { @@ -227,8 +241,10 @@ struct buffered_piece_collection_with_mapper template inline void map_offsetted_points(Mapper& mapper) { - for(typename buffered_ring_collection >::const_iterator oit = boost::begin(offsetted_rings); - oit != boost::end(offsetted_rings); + typedef typename super_type::point_type point_type; + + for(typename buffered_ring_collection >::const_iterator oit = boost::begin(this->offsetted_rings); + oit != boost::end(this->offsetted_rings); ++oit) { int index = 0; @@ -245,8 +261,8 @@ struct buffered_piece_collection_with_mapper template inline void map_traverse(Mapper& mapper) { - for(typename buffered_ring_collection::const_iterator it = boost::begin(traversed_rings); - it != boost::end(traversed_rings); + for(typename buffered_ring_collection::const_iterator it = boost::begin(this->traversed_rings); + it != boost::end(this->traversed_rings); ++it) { mapper.map(*it, "opacity:0.4;fill:none;stroke:rgb(0,255,0);stroke-width:8"); @@ -256,8 +272,8 @@ struct buffered_piece_collection_with_mapper template inline void map_offsetted(Mapper& mapper) { - for(typename buffered_ring_collection >::const_iterator it = boost::begin(offsetted_rings); - it != boost::end(offsetted_rings); + for(typename buffered_ring_collection >::const_iterator it = boost::begin(this->offsetted_rings); + it != boost::end(this->offsetted_rings); ++it) { if (it->discarded()) diff --git a/include/boost/geometry/extensions/algorithms/buffer/buffered_ring.hpp b/include/boost/geometry/extensions/algorithms/buffer/buffered_ring.hpp index 579d4e614..3aec0c677 100644 --- a/include/boost/geometry/extensions/algorithms/buffer/buffered_ring.hpp +++ b/include/boost/geometry/extensions/algorithms/buffer/buffered_ring.hpp @@ -179,33 +179,15 @@ struct copy_segment_point {}; -template -< - typename MultiRing, - bool Reverse, - typename SegmentIdentifier, - typename RangeOut -> +template struct copy_segments < detail::buffer::buffered_ring_collection_tag, - MultiRing, - Reverse, - SegmentIdentifier, - RangeOut + Reverse > : detail::copy_segments::copy_segments_multi < - MultiRing, - SegmentIdentifier, - RangeOut, - detail::copy_segments::copy_segments_ring - < - typename boost::range_value::type, - Reverse, - SegmentIdentifier, - RangeOut - > + detail::copy_segments::copy_segments_ring > {}; diff --git a/include/boost/geometry/extensions/algorithms/buffer/side_on_convex_range.hpp b/include/boost/geometry/extensions/algorithms/buffer/side_on_convex_range.hpp index 8cb1e3101..d1ae7c37c 100644 --- a/include/boost/geometry/extensions/algorithms/buffer/side_on_convex_range.hpp +++ b/include/boost/geometry/extensions/algorithms/buffer/side_on_convex_range.hpp @@ -52,9 +52,11 @@ inline bool collinear_point_on_segment(P0 const& subject, P1 const& p1, P2 const } -template -inline int side_on_convex_range(Point const& subject, Range const& range) +template +inline int side_on_convex_range(Point const& subject, + Range const& range, RobustPolicy const& robust_policy) { + // TODO merge this implementation with next function with same name if (boost::empty(range)) { return 1; @@ -62,17 +64,26 @@ inline int side_on_convex_range(Point const& subject, Range const& range) bool has_collinear = false; - typedef typename boost::range_iterator - < - Range const - >::type iterator_type; + typedef typename geometry::robust_point_type + < + Point, + RobustPolicy + >::type robust_point_type; + + typedef typename boost::range_iterator::type iterator_type; iterator_type it = boost::begin(range); - for (iterator_type prev = it++; - it != boost::end(range); - prev = it++) + + robust_point_type subject_rob, previous_rob; + geometry::recalculate(subject_rob, subject, robust_policy); + geometry::recalculate(previous_rob, *it, robust_policy); + + for (++it; it != boost::end(range); ++it) { - int const side = SideStrategy::apply(subject, *prev, *it); + robust_point_type current_rob; + geometry::recalculate(current_rob, *it, robust_policy); + + int const side = SideStrategy::apply(subject_rob, previous_rob, current_rob); switch(side) { case 1 : @@ -81,28 +92,50 @@ inline int side_on_convex_range(Point const& subject, Range const& range) // Check if it is really on the segment. // If not, it is either on the left (because polygon is convex) // or it is still on one of the other segments (if segments are collinear) - if (collinear_point_on_segment(subject, *prev, *it)) + if (collinear_point_on_segment(subject_rob, previous_rob, current_rob)) { return 0; } has_collinear = true; break; } + previous_rob = current_rob; } return has_collinear ? 1 : -1; } -template +template static inline int side_on_convex_range(Point const& subject, Iterator first, Iterator last, /* by value: */ segment_identifier seg_id, - segment_identifier& on_segment_seg_id) + segment_identifier& on_segment_seg_id, + RobustPolicy const& robust_policy) { + + typedef typename geometry::robust_point_type + < + Point, + RobustPolicy + >::type robust_point_type; + bool has_collinear = false; Iterator it = first; - for (Iterator prev = it++; it != last; prev = it++, seg_id.segment_index++) + + if (it == last) { - int side = SideStrategy::apply(subject, *prev, *it); + return 1; + } + + robust_point_type subject_rob, previous_rob; + geometry::recalculate(subject_rob, subject, robust_policy); + geometry::recalculate(previous_rob, *it, robust_policy); + + for (++it; it != last; ++it, seg_id.segment_index++) + { + robust_point_type current_rob; + geometry::recalculate(current_rob, *it, robust_policy); + + int const side = SideStrategy::apply(subject_rob, previous_rob, current_rob); switch(side) { case 1 : @@ -111,7 +144,7 @@ static inline int side_on_convex_range(Point const& subject, // Check if it is REALLY on the segment. // If not, it is either on the left (because polygon is convex) // or it is still on one of the other segments (if segments are collinear) - if (collinear_point_on_segment(subject, *prev, *it)) + if (collinear_point_on_segment(subject_rob, previous_rob, current_rob)) { on_segment_seg_id = seg_id; return 0; @@ -119,6 +152,7 @@ static inline int side_on_convex_range(Point const& subject, has_collinear = true; break; } + previous_rob = current_rob; } return has_collinear ? 1 : -1; } diff --git a/include/boost/geometry/extensions/algorithms/dissolve.hpp b/include/boost/geometry/extensions/algorithms/dissolve.hpp index 8ed9700b6..14e4a9b9f 100644 --- a/include/boost/geometry/extensions/algorithms/dissolve.hpp +++ b/include/boost/geometry/extensions/algorithms/dissolve.hpp @@ -21,7 +21,6 @@ #include #include #include -#include #include @@ -110,7 +109,7 @@ struct dissolve_ring_or_polygon detail::dissolve::no_interrupt_policy policy; geometry::self_turns < - detail::overlay::calculate_distance_policy + detail::overlay::assign_null_policy >(geometry, rescale_policy, turns, policy); // The dissolve process is not necessary if there are no turns at all diff --git a/include/boost/geometry/iterators/concatenate_iterator.hpp b/include/boost/geometry/iterators/concatenate_iterator.hpp index c0c4f5e08..e7a849769 100644 --- a/include/boost/geometry/iterators/concatenate_iterator.hpp +++ b/include/boost/geometry/iterators/concatenate_iterator.hpp @@ -10,7 +10,9 @@ #ifndef BOOST_GEOMETRY_ITERATORS_CONCATENATE_ITERATOR_HPP #define BOOST_GEOMETRY_ITERATORS_CONCATENATE_ITERATOR_HPP -#include +#include +#include +#include #include #include #include @@ -57,18 +59,26 @@ public: (concatenate_iterator const& other) : m_it1(other.m_it1), m_end1(other.m_end1), m_it2(other.m_it2) { - BOOST_STATIC_ASSERT - ( boost::is_convertible::value - && boost::is_convertible::value ); + static const bool are_conv + = boost::is_convertible::value + && boost::is_convertible::value; + + BOOST_MPL_ASSERT_MSG((are_conv), + NOT_CONVERTIBLE, + (types)); } template concatenate_iterator operator=(concatenate_iterator const& other) { - BOOST_STATIC_ASSERT - ( boost::is_convertible::value - && boost::is_convertible::value ); + static const bool are_conv + = boost::is_convertible::value + && boost::is_convertible::value; + + BOOST_MPL_ASSERT_MSG((are_conv), + NOT_CONVERTIBLE, + (types)); m_it1 = other.m_it1; m_end1 = other.m_end1; diff --git a/include/boost/geometry/iterators/flatten_iterator.hpp b/include/boost/geometry/iterators/flatten_iterator.hpp index 1d264f006..b9a9e532e 100644 --- a/include/boost/geometry/iterators/flatten_iterator.hpp +++ b/include/boost/geometry/iterators/flatten_iterator.hpp @@ -10,7 +10,9 @@ #ifndef BOOST_GEOMETRY_ITERATORS_FLATTEN_ITERATOR_HPP #define BOOST_GEOMETRY_ITERATORS_FLATTEN_ITERATOR_HPP -#include +#include +#include +#include #include #include #include @@ -84,15 +86,19 @@ public: m_outer_end(other.m_outer_end), m_inner_it(other.m_inner_it) { - BOOST_STATIC_ASSERT( boost::is_convertible - < - OtherOuterIterator, OuterIterator - >::value - && boost::is_convertible - < - OtherInnerIterator, InnerIterator - >::value ); - + static const bool are_conv + = boost::is_convertible + < + OtherOuterIterator, OuterIterator + >::value + && boost::is_convertible + < + OtherInnerIterator, InnerIterator + >::value; + + BOOST_MPL_ASSERT_MSG((are_conv), + NOT_CONVERTIBLE, + (types)); } template @@ -112,14 +118,19 @@ public: OtherAccessInnerEnd > const& other) { - BOOST_STATIC_ASSERT( boost::is_convertible - < - OtherOuterIterator, OuterIterator - >::value - && boost::is_convertible - < - OtherInnerIterator, InnerIterator - >::value ); + static const bool are_conv + = boost::is_convertible + < + OtherOuterIterator, OuterIterator + >::value + && boost::is_convertible + < + OtherInnerIterator, InnerIterator + >::value; + + BOOST_MPL_ASSERT_MSG((are_conv), + NOT_CONVERTIBLE, + (types)); m_outer_it = other.m_outer_it; m_outer_end = other.m_outer_end; @@ -184,17 +195,17 @@ private: OtherAccessInnerEnd > const& other) const { - if ( this->m_outer_it != other.m_outer_it ) + if ( m_outer_it != other.m_outer_it ) { return false; } - if ( this->m_outer_it == m_outer_end ) + if ( m_outer_it == m_outer_end ) { return true; } - return this->m_inner_it == other.m_inner_it; + return m_inner_it == other.m_inner_it; } inline void increment() diff --git a/include/boost/geometry/iterators/point_iterator.hpp b/include/boost/geometry/iterators/point_iterator.hpp index a0fc2da4b..660cc03fa 100644 --- a/include/boost/geometry/iterators/point_iterator.hpp +++ b/include/boost/geometry/iterators/point_iterator.hpp @@ -10,6 +10,15 @@ #ifndef BOOST_GEOMETRY_ITERATORS_POINT_ITERATOR_HPP #define BOOST_GEOMETRY_ITERATORS_POINT_ITERATOR_HPP +#include +#include +#include + +#include +#include +#include +#include + #include #include @@ -234,12 +243,15 @@ public: point_iterator(point_iterator const& other) : base(*other.base_ptr()) { - BOOST_STATIC_ASSERT - ( boost::is_convertible - < - typename dispatch::point_iterator_type::type, - typename dispatch::point_iterator_type::type - >::value ); + static const bool is_conv + = boost::is_convertible< + typename dispatch::point_iterator_type::type, + typename dispatch::point_iterator_type::type + >::value; + + BOOST_MPL_ASSERT_MSG((is_conv), + NOT_CONVERTIBLE, + (point_iterator)); } }; diff --git a/include/boost/geometry/iterators/point_iterator_type.hpp b/include/boost/geometry/iterators/point_iterator_type.hpp index 4d50e42c4..d8606d5ad 100644 --- a/include/boost/geometry/iterators/point_iterator_type.hpp +++ b/include/boost/geometry/iterators/point_iterator_type.hpp @@ -14,9 +14,14 @@ #include #include +#include +#include + #include +#include #include #include + #include #include @@ -107,12 +112,12 @@ private: typedef typename detail_dispatch::point_iterator_inner_range_type < Polygon - >::type InnerRange; + >::type inner_range; public: typedef concatenate_iterator < - typename boost::range_iterator::type, + typename boost::range_iterator::type, flatten_iterator < typename boost::range_iterator @@ -121,14 +126,14 @@ public: >::type, typename dispatch::point_iterator_type < - InnerRange + inner_range >::type, typename detail_dispatch::point_iterator_value_type < Polygon >::type, - dispatch::points_begin, - dispatch::points_end + dispatch::points_begin, + dispatch::points_end >, typename detail_dispatch::point_iterator_value_type::type > type; @@ -149,19 +154,19 @@ private: typedef typename detail_dispatch::point_iterator_inner_range_type < MultiLinestring - >::type InnerRange; + >::type inner_range; public: typedef flatten_iterator < typename boost::range_iterator::type, - typename dispatch::point_iterator_type::type, + typename dispatch::point_iterator_type::type, typename detail_dispatch::point_iterator_value_type < MultiLinestring >::type, - dispatch::points_begin, - dispatch::points_end + dispatch::points_begin, + dispatch::points_end > type; }; @@ -173,19 +178,19 @@ private: typedef typename detail_dispatch::point_iterator_inner_range_type < MultiPolygon - >::type InnerRange; + >::type inner_range; public: typedef flatten_iterator < typename boost::range_iterator::type, - typename dispatch::point_iterator_type::type, + typename dispatch::point_iterator_type::type, typename detail_dispatch::point_iterator_value_type < MultiPolygon >::type, - dispatch::points_begin, - dispatch::points_end + dispatch::points_begin, + dispatch::points_end > type; }; diff --git a/include/boost/geometry/multi/algorithms/detail/overlay/copy_segments.hpp b/include/boost/geometry/multi/algorithms/detail/overlay/copy_segments.hpp index f3a0532ac..e6d62dffb 100644 --- a/include/boost/geometry/multi/algorithms/detail/overlay/copy_segments.hpp +++ b/include/boost/geometry/multi/algorithms/detail/overlay/copy_segments.hpp @@ -28,17 +28,19 @@ namespace detail { namespace copy_segments { -template -< - typename MultiGeometry, - typename SegmentIdentifier, - typename RangeOut, - typename Policy -> +template struct copy_segments_multi { + template + < + typename MultiGeometry, + typename SegmentIdentifier, + typename RobustPolicy, + typename RangeOut + > static inline void apply(MultiGeometry const& multi_geometry, SegmentIdentifier const& seg_id, int to_index, + RobustPolicy const& robust_policy, RangeOut& current_output) { @@ -50,7 +52,9 @@ struct copy_segments_multi // Call the single-version Policy::apply(multi_geometry[seg_id.multi_index], - seg_id, to_index, current_output); + seg_id, to_index, + robust_policy, + current_output); } }; @@ -64,33 +68,11 @@ namespace dispatch { -template -< - typename MultiPolygon, - bool Reverse, - typename SegmentIdentifier, - typename RangeOut -> -struct copy_segments - < - multi_polygon_tag, - MultiPolygon, - Reverse, - SegmentIdentifier, - RangeOut - > +template +struct copy_segments : detail::copy_segments::copy_segments_multi < - MultiPolygon, - SegmentIdentifier, - RangeOut, - detail::copy_segments::copy_segments_polygon - < - typename boost::range_value::type, - Reverse, - SegmentIdentifier, - RangeOut - > + detail::copy_segments::copy_segments_polygon > {}; diff --git a/include/boost/geometry/multi/algorithms/detail/overlay/get_turns.hpp b/include/boost/geometry/multi/algorithms/detail/overlay/get_turns.hpp index 53664fab4..b61775b8f 100644 --- a/include/boost/geometry/multi/algorithms/detail/overlay/get_turns.hpp +++ b/include/boost/geometry/multi/algorithms/detail/overlay/get_turns.hpp @@ -39,11 +39,11 @@ template > struct get_turns_multi_polygon_cs { - template + template static inline void apply( int source_id1, Multi const& multi, int source_id2, Box const& box, - RescalePolicy const& rescale_policy, + RobustPolicy const& robust_policy, Turns& turns, InterruptPolicy& interrupt_policy) { typedef typename boost::range_iterator @@ -63,7 +63,7 @@ struct get_turns_multi_polygon_cs Reverse, ReverseBox, TurnPolicy >::apply(source_id1, *it, source_id2, box, - rescale_policy, turns, interrupt_policy, i); + robust_policy, turns, interrupt_policy, i); } } }; diff --git a/include/boost/geometry/multi/algorithms/detail/sections/sectionalize.hpp b/include/boost/geometry/multi/algorithms/detail/sections/sectionalize.hpp index 29bea08db..1778fe9eb 100644 --- a/include/boost/geometry/multi/algorithms/detail/sections/sectionalize.hpp +++ b/include/boost/geometry/multi/algorithms/detail/sections/sectionalize.hpp @@ -43,11 +43,11 @@ struct sectionalize_multi template < typename MultiGeometry, - typename RescalePolicy, + typename RobustPolicy, typename Sections > static inline void apply(MultiGeometry const& multi, - RescalePolicy const& rescale_policy, + RobustPolicy const& robust_policy, bool make_rescaled_boxes, Sections& sections, ring_identifier ring_id, std::size_t max_count) { @@ -57,7 +57,7 @@ struct sectionalize_multi it != boost::end(multi); ++it, ++ring_id.multi_index) { - Policy::apply(*it, rescale_policy, make_rescaled_boxes, sections, ring_id, max_count); + Policy::apply(*it, robust_policy, make_rescaled_boxes, sections, ring_id, max_count); } } }; diff --git a/include/boost/geometry/multi/algorithms/intersection.hpp b/include/boost/geometry/multi/algorithms/intersection.hpp index ddb9aed81..3b7f9d572 100644 --- a/include/boost/geometry/multi/algorithms/intersection.hpp +++ b/include/boost/geometry/multi/algorithms/intersection.hpp @@ -45,10 +45,13 @@ struct intersection_multi_linestring_multi_linestring_point template < typename MultiLinestring1, typename MultiLinestring2, + typename RobustPolicy, typename OutputIterator, typename Strategy > static inline OutputIterator apply(MultiLinestring1 const& ml1, - MultiLinestring2 const& ml2, OutputIterator out, + MultiLinestring2 const& ml2, + RobustPolicy const& robust_policy, + OutputIterator out, Strategy const& strategy) { // Note, this loop is quadratic w.r.t. number of linestrings per input. @@ -68,7 +71,7 @@ struct intersection_multi_linestring_multi_linestring_point ++it2) { out = intersection_linestring_linestring_point - ::apply(*it1, *it2, out, strategy); + ::apply(*it1, *it2, robust_policy, out, strategy); } } @@ -83,10 +86,13 @@ struct intersection_linestring_multi_linestring_point template < typename Linestring, typename MultiLinestring, + typename RobustPolicy, typename OutputIterator, typename Strategy > static inline OutputIterator apply(Linestring const& linestring, - MultiLinestring const& ml, OutputIterator out, + MultiLinestring const& ml, + RobustPolicy const& robust_policy, + OutputIterator out, Strategy const& strategy) { for (typename boost::range_iterator @@ -97,7 +103,7 @@ struct intersection_linestring_multi_linestring_point ++it) { out = intersection_linestring_linestring_point - ::apply(linestring, *it, out, strategy); + ::apply(linestring, *it, robust_policy, out, strategy); } return out; @@ -118,9 +124,11 @@ struct intersection_of_multi_linestring_with_areal template < typename MultiLinestring, typename Areal, + typename RobustPolicy, typename OutputIterator, typename Strategy > static inline OutputIterator apply(MultiLinestring const& ml, Areal const& areal, + RobustPolicy const& robust_policy, OutputIterator out, Strategy const& strategy) { @@ -134,7 +142,7 @@ struct intersection_of_multi_linestring_with_areal out = intersection_of_linestring_with_areal < ReverseAreal, LineStringOut, OverlayType - >::apply(*it, areal, out, strategy); + >::apply(*it, areal, robust_policy, out, strategy); } return out; @@ -154,16 +162,18 @@ struct intersection_of_areal_with_multi_linestring template < typename Areal, typename MultiLinestring, + typename RobustPolicy, typename OutputIterator, typename Strategy > static inline OutputIterator apply(Areal const& areal, MultiLinestring const& ml, + RobustPolicy const& robust_policy, OutputIterator out, Strategy const& strategy) { return intersection_of_multi_linestring_with_areal < ReverseAreal, LineStringOut, OverlayType - >::apply(ml, areal, out, strategy); + >::apply(ml, areal, robust_policy, out, strategy); } }; @@ -175,10 +185,13 @@ struct clip_multi_linestring template < typename MultiLinestring, typename Box, + typename RobustPolicy, typename OutputIterator, typename Strategy > static inline OutputIterator apply(MultiLinestring const& multi_linestring, - Box const& box, OutputIterator out, Strategy const& ) + Box const& box, + RobustPolicy const& robust_policy, + OutputIterator out, Strategy const& ) { typedef typename point_type::type point_type; strategy::intersection::liang_barsky lb_strategy; @@ -187,7 +200,7 @@ struct clip_multi_linestring it != boost::end(multi_linestring); ++it) { out = detail::intersection::clip_range_with_box - (box, *it, out, lb_strategy); + (box, *it, robust_policy, out, lb_strategy); } return out; } diff --git a/include/boost/geometry/policies/relate/de9im.hpp b/include/boost/geometry/policies/relate/de9im.hpp index 766d80b22..e2d6b5111 100644 --- a/include/boost/geometry/policies/relate/de9im.hpp +++ b/include/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/include/boost/geometry/policies/relate/direction.hpp b/include/boost/geometry/policies/relate/direction.hpp index 16293a9de..6d4946741 100644 --- a/include/boost/geometry/policies/relate/direction.hpp +++ b/include/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 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::type rtype; - - - template - static inline return_type segments_intersect(side_info const& sides, - R const&, - coordinate_type const& , coordinate_type const& , - coordinate_type const& , coordinate_type const& , - S1 const& , S2 const& ) + 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; @@ -171,63 +163,112 @@ struct segments_direction ; } - static inline return_type collinear_touch( - coordinate_type const& , - coordinate_type const& , int arrival_a, int arrival_b) + template + 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 - static inline return_type collinear_interior_boundary_intersect(S const& , bool, - int arrival_a, int arrival_b, bool opposite) + template + static inline void analyze(Ratio const& r, + int& in_segment_count, + int& on_end_count, + int& outside_segment_count) { + if (r.on_end()) + { + on_end_count++; + } + else if (r.in_segment()) + { + in_segment_count++; + } + else + { + outside_segment_count++; + } + } + + template + 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) + { + // 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; + 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 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) - { - return_type r('c', opposite); - r.arrival[0] = -1; - r.arrival[1] = 1; - return r; - } - - 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; - return r; - } - - static inline return_type segment_equal(S1 const& , bool opposite) - { - return return_type('e', opposite); - } - - static inline return_type degenerate(S1 const& , bool) + template + static inline return_type degenerate(Segment const& , bool) { return return_type('0', false); } @@ -237,11 +278,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 diff --git a/include/boost/geometry/policies/relate/intersection_points.hpp b/include/boost/geometry/policies/relate/intersection_points.hpp index 7a378475b..c860da288 100644 --- a/include/boost/geometry/policies/relate/intersection_points.hpp +++ b/include/boost/geometry/policies/relate/intersection_points.hpp @@ -16,7 +16,7 @@ #include #include -#include +#include #include #include #include @@ -29,106 +29,154 @@ namespace boost { namespace geometry namespace policies { namespace relate { -template + +/*! +\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 - static inline return_type segments_intersect(side_info const&, - R const& r, - coordinate_type const& dx1, coordinate_type const& dy1, - coordinate_type const& , coordinate_type const& , - S1 const& s1, S2 const& ) + 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) { - typedef typename geometry::coordinate_type - < - typename return_type::point_type - >::type return_coordinate_type; + typedef typename geometry::coordinate_type::type 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], - geometry::math::round(R(s1x) + r * R(dx1))); - set<1>(result.intersections[0], - geometry::math::round(R(s1y) + r * R(dy1))); - - return result; + // Calculate the intersection point based on segment_ratio + // Up to know, division was postponed. Here we divide using numerator/ + // denominator. In case of integer this might result in an integer + // division. + BOOST_ASSERT(ratio.denominator() != 0); + set<0>(point, boost::numeric_cast( + get<0, 0>(segment) + + ratio.numerator() * dx / ratio.denominator())); + set<1>(point, boost::numeric_cast( + get<0, 1>(segment) + + ratio.numerator() * dy / ratio.denominator())); } - static inline return_type collinear_touch(coordinate_type const& x, - coordinate_type const& y, int, int) + + 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; - set<0>(result.intersections[0], x); - set<1>(result.intersections[0], y); + + 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); + } + + result.fractions[0].assign(sinfo); + return result; } - template - static inline return_type collinear_inside(S const& s, int index1 = 0, int index2 = 1) + template + 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; - 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; - } + int index = 0, count_a = 0, count_b = 0; + Ratio on_a[2]; - template - 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); - } + // The conditions "index < 2" are necessary for non-robust handling, + // if index would be 2 this indicate an (currently uncatched) error - 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); - } + // 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 - 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; - } + 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; - static inline return_type segment_equal(S1 const& s, bool) - { - 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)); return result; } @@ -141,17 +189,13 @@ struct segments_intersection_points return return_type(); } - static inline return_type collinear_disjoint() - { - return return_type(); - } - - static inline return_type degenerate(S1 const& s, bool) + template + static inline return_type degenerate(Segment const& segment, bool) { 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>(segment)); + set<1>(result.intersections[0], get<0, 1>(segment)); return result; } }; diff --git a/include/boost/geometry/policies/relate/intersection_ratios.hpp b/include/boost/geometry/policies/relate/intersection_ratios.hpp new file mode 100644 index 000000000..0e4506eda --- /dev/null +++ b/include/boost/geometry/policies/relate/intersection_ratios.hpp @@ -0,0 +1,109 @@ +// 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 +#include + +#include +#include + +#include +#include +#include + + +namespace boost { namespace geometry +{ + +namespace policies { namespace relate +{ + + +/*! +\brief Policy returning segment ratios +\note Template argument FractionType should be a fraction_type + */ +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 + 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 + static inline return_type degenerate(Segment const& segment, bool) + { + return return_type(); + } +}; + + +}} // namespace policies::relate + +}} // namespace boost::geometry + +#endif // BOOST_GEOMETRY_GEOMETRY_POLICIES_RELATE_INTERSECTION_RATIOS_HPP diff --git a/include/boost/geometry/policies/relate/tupled.hpp b/include/boost/geometry/policies/relate/tupled.hpp index e78ccfbc1..543aac6bc 100644 --- a/include/boost/geometry/policies/relate/tupled.hpp +++ b/include/boost/geometry/policies/relate/tupled.hpp @@ -14,8 +14,6 @@ #include #include -#include -#include 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 +template struct segments_tupled { typedef boost::tuple @@ -35,101 +33,32 @@ 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::type rtype; - - template - 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) + template + static inline return_type segments_crosses(side_info const& sides, + SegmentIntersectionInfo const& sinfo, + Segment1 const& s1, Segment2 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) + Policy1::segments_crosses(sides, sinfo, s1, s2), + Policy2::segments_crosses(sides, sinfo, s1, s2) ); } - static inline return_type collinear_touch(coordinate_type const& x, - coordinate_type const& y, int arrival_a, int arrival_b) + template + 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_touch(x, y, arrival_a, arrival_b), - Policy2::collinear_touch(x, y, arrival_a, arrival_b) + Policy1::segments_collinear(segment1, segment2, ra1, ra2, rb1, rb2), + Policy2::segments_collinear(segment1, segment2, ra1, ra2, rb1, rb2) ); } - template - 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) - { - return boost::make_tuple - ( - Policy1::collinear_b_in_a(segment, opposite), - Policy2::collinear_b_in_a(segment, opposite) - ); - } - - - 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) - { - 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) - ); - } - - static inline return_type segment_equal(segment_type1 const& s, - bool opposite) - { - return boost::make_tuple - ( - Policy1::segment_equal(s, opposite), - Policy2::segment_equal(s, opposite) - ); - } - - static inline return_type degenerate(segment_type1 const& segment, + template + static inline return_type degenerate(Segment const& segment, bool a_degenerate) { return boost::make_tuple @@ -157,15 +86,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/include/boost/geometry/policies/robustness/get_rescale_policy.hpp b/include/boost/geometry/policies/robustness/get_rescale_policy.hpp new file mode 100644 index 000000000..8b92567e3 --- /dev/null +++ b/include/boost/geometry/policies/robustness/get_rescale_policy.hpp @@ -0,0 +1,285 @@ +// 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 + +#include + +#include + +#include +#include +#include +#include +#include + +#include +#include + +#include +#include + +#include + +namespace boost { namespace geometry +{ + +#ifndef DOXYGEN_NO_DETAIL +namespace detail { namespace get_rescale_policy +{ + +template +static inline void init_rescale_policy(Geometry const& geometry, + Point& min_point, + RobustPoint& min_robust_point, + Factor& factor) +{ + // Get bounding boxes + model::box env = geometry::return_envelope >(geometry); + + // Scale this to integer-range + typedef typename promote_floating_point + < + typename geometry::coordinate_type::type + >::type num_type; + num_type const diff = boost::numeric_cast(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 = boost::numeric_cast( + boost::numeric_cast(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(-range / two); + assign_values(min_robust_point, min_coordinate, min_coordinate); +} + +template +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 env = geometry::return_envelope >(geometry1); + model::box env2 = geometry::return_envelope >(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::type + >::type num_type; + num_type const diff = boost::numeric_cast(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 = boost::numeric_cast( + boost::numeric_cast(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(-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 +{ + typedef typename geometry::coordinate_type::type coordinate_type; + typedef model::point + < + typename detail::robust_type::type, + geometry::dimension::value, + typename geometry::coordinate_system::type + > robust_point_type; + typedef typename promote_floating_point::type factor_type; + typedef detail::robust_policy type; +}; + +template +struct get_rescale_policy +{ + template + static inline Policy apply(Geometry const& geometry) + { + typedef typename point_type::type point_type; + typedef typename geometry::coordinate_type::type coordinate_type; + typedef typename promote_floating_point::type factor_type; + typedef model::point + < + typename detail::robust_type::type, + geometry::dimension::value, + typename geometry::coordinate_system::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 + static inline Policy apply(Geometry1 const& geometry1, Geometry2 const& geometry2) + { + typedef typename point_type::type point_type; + typedef typename geometry::coordinate_type::type coordinate_type; + typedef typename promote_floating_point::type factor_type; + typedef model::point + < + typename detail::robust_type::type, + geometry::dimension::value, + typename geometry::coordinate_system::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 +{ + template + static inline no_rescale_policy apply(Geometry const& ) + { + return no_rescale_policy(); + } + + template + static inline no_rescale_policy apply(Geometry1 const& , Geometry2 const& ) + { + return no_rescale_policy(); + } +}; + + +}} // namespace detail::get_rescale_policy +#endif // DOXYGEN_NO_DETAIL + +template +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::type + >::type::value +#endif + > +{ + BOOST_STATIC_ASSERT + (( + boost::is_same + < + typename geometry::tag::type, + geometry::point_tag + >::type::value + )); +}; + + +template +< + typename Geometry1, + typename Geometry2, + typename Tag1 = typename tag_cast + < + typename tag::type, + box_tag, + pointlike_tag, + linear_tag, + areal_tag + >::type, + typename Tag2 = typename tag_cast + < + typename tag::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::type, + false + > +{}; + +// Areal/areal: get rescale policy based on coordinate type +template +< + typename Geometry1, + typename Geometry2 +> +struct rescale_overlay_policy_type + : public rescale_policy_type + < + typename geometry::point_type::type + > +{}; + + +template +inline Policy get_rescale_policy(Geometry const& geometry) +{ + return detail::get_rescale_policy::get_rescale_policy::apply(geometry); +} + +template +inline Policy get_rescale_policy(Geometry1 const& geometry1, Geometry2 const& geometry2) +{ + return detail::get_rescale_policy::get_rescale_policy::apply(geometry1, geometry2); +} + + +}} // namespace boost::geometry + + +#endif // BOOST_GEOMETRY_POLICIES_ROBUSTNESS_GET_RESCALE_POLICY_HPP diff --git a/include/boost/geometry/policies/robustness/no_rescale_policy.hpp b/include/boost/geometry/policies/robustness/no_rescale_policy.hpp new file mode 100644 index 000000000..a7899842c --- /dev/null +++ b/include/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 + +#include +#include +#include +#include + +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 + inline Value const& apply(Value const& value) const + { + return value; + } +}; + +} // namespace detail +#endif + + +// Implement meta-functions for this policy +template +struct robust_point_type +{ + // The point itself + typedef Point type; +}; + +template +struct segment_ratio_type +{ + // Define a segment_ratio defined on coordinate type, e.g. + // int/int or float/float + typedef typename geometry::coordinate_type::type coordinate_type; + typedef segment_ratio type; +}; + + +}} // namespace boost::geometry + +#endif // BOOST_GEOMETRY_POLICIES_ROBUSTNESS_NO_RESCALE_POLICY_HPP diff --git a/include/boost/geometry/policies/robustness/rescale_policy.hpp b/include/boost/geometry/policies/robustness/rescale_policy.hpp new file mode 100644 index 000000000..570ba8bef --- /dev/null +++ b/include/boost/geometry/policies/robustness/rescale_policy.hpp @@ -0,0 +1,82 @@ +// 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 + +#include + +#include +#include + +namespace boost { namespace geometry +{ + +#ifndef DOXYGEN_NO_DETAIL +namespace detail +{ + +template +struct robust_policy +{ + static bool const enabled = true; + + typedef typename geometry::coordinate_type::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 + inline output_ct apply(Value const& value) const + { + // a + (v-b)*f + CalculationType const a = static_cast(get(m_int_min)); + CalculationType const b = static_cast(get(m_fp_min)); + CalculationType const result = a + (value - b) * m_multiplier; + return static_cast(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 +struct robust_point_type > +{ + typedef IntPoint type; +}; + +// Meta function for rescaling, if rescaling is done segment_ratio is based on long long +template +struct segment_ratio_type > +{ + typedef segment_ratio type; +}; + + +}} // namespace boost::geometry + + +#endif // BOOST_GEOMETRY_POLICIES_ROBUSTNESS_RESCALE_POLICY_HPP diff --git a/include/boost/geometry/policies/robustness/robust_point_type.hpp b/include/boost/geometry/policies/robustness/robust_point_type.hpp new file mode 100644 index 000000000..35f719865 --- /dev/null +++ b/include/boost/geometry/policies/robustness/robust_point_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_ROBUST_POINT_TYPE_HPP +#define BOOST_GEOMETRY_POLICIES_ROBUSTNESS_ROBUST_POINT_TYPE_HPP + +#include + +namespace boost { namespace geometry +{ + +// Meta-function to typedef a robust point type for a policy +template +struct robust_point_type {}; //: not_implemented<> {}; + + +}} // namespace boost::geometry + + +#endif // BOOST_GEOMETRY_POLICIES_ROBUSTNESS_ROBUST_POINT_TYPE_HPP diff --git a/include/boost/geometry/policies/robustness/robust_type.hpp b/include/boost/geometry/policies/robustness/robust_type.hpp new file mode 100644 index 000000000..4cfb2c4d9 --- /dev/null +++ b/include/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 +#include + + +namespace boost { namespace geometry +{ + +#ifndef DOXYGEN_NO_DETAIL + +namespace detail_dispatch +{ + +template +struct robust_type +{ +}; + +template +struct robust_type +{ + typedef CoordinateType type; +}; + +template +struct robust_type +{ + typedef boost::long_long_type type; +}; + +} // namespace detail_dispatch + +namespace detail +{ + +template +struct robust_type +{ + typedef typename detail_dispatch::robust_type + < + CoordinateType, + typename boost::is_floating_point::type + >::type type; +}; + +} // namespace detail +#endif // DOXYGEN_NO_DETAIL + + +}} // namespace boost::geometry + + +#endif // BOOST_GEOMETRY_POLICIES_ROBUSTNESS_ROBUST_TYPE_HPP diff --git a/include/boost/geometry/policies/robustness/segment_ratio.hpp b/include/boost/geometry/policies/robustness/segment_ratio.hpp new file mode 100644 index 000000000..d55e8492e --- /dev/null +++ b/include/boost/geometry/policies/robustness/segment_ratio.hpp @@ -0,0 +1,236 @@ +// 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 +#include +#include + +#include +#include + +namespace boost { namespace geometry +{ + + +namespace detail { namespace segment_ratio +{ + +template +< + typename Type, + bool IsIntegral = boost::is_integral::type::value +> +struct less {}; + +template +struct less +{ + template + static inline bool apply(Ratio const& lhs, Ratio const& rhs) + { + return boost::rational(lhs.numerator(), lhs.denominator()) + < boost::rational(rhs.numerator(), rhs.denominator()); + } +}; + +template +struct less +{ + template + 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::value +> +struct equal {}; + +template +struct equal +{ + template + static inline bool apply(Ratio const& lhs, Ratio const& rhs) + { + return boost::rational(lhs.numerator(), lhs.denominator()) + == boost::rational(rhs.numerator(), rhs.denominator()); + } +}; + +template +struct equal +{ + template + 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 +class segment_ratio +{ +public : + typedef Type numeric_type; + + // Type-alias for the type itself + typedef segment_ratio 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 num_type; + static const num_type scale = 1000000.0; + m_approximation = + m_denominator == 0 ? 0 + : boost::numeric_cast + ( + boost::numeric_cast(m_numerator) * scale + / boost::numeric_cast(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::apply(*this, other) + : m_approximation < other.m_approximation; + } + + inline bool operator== (thistype const& other) const + { + return close_to(other) + && detail::segment_ratio::equal::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; + 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. + int m_approximation; +}; + + +}} // namespace boost::geometry + +#endif // BOOST_GEOMETRY_POLICIES_ROBUSTNESS_SEGMENT_RATIO_HPP diff --git a/include/boost/geometry/algorithms/detail/rescale.hpp b/include/boost/geometry/policies/robustness/segment_ratio_type.hpp similarity index 56% rename from include/boost/geometry/algorithms/detail/rescale.hpp rename to include/boost/geometry/policies/robustness/segment_ratio_type.hpp index 889a978da..19e935bbb 100644 --- a/include/boost/geometry/algorithms/detail/rescale.hpp +++ b/include/boost/geometry/policies/robustness/segment_ratio_type.hpp @@ -9,24 +9,20 @@ // 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_RESCALE_HPP -#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_RESCALE_HPP +#ifndef BOOST_GEOMETRY_POLICIES_ROBUSTNESS_SEGMENT_RATIO_TYPE_HPP +#define BOOST_GEOMETRY_POLICIES_ROBUSTNESS_SEGMENT_RATIO_TYPE_HPP +#include namespace boost { namespace geometry { -#ifndef DOXYGEN_NO_DETAIL +// Meta-function to access segment-ratio for a policy +template +struct segment_ratio_type {}; // : not_implemented<> {}; -// To be removed later, when we will initialize a real policy -namespace detail -{ -struct no_rescale_policy {}; -} - -#endif }} // namespace boost::geometry -#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_RESCALE_HPP +#endif // BOOST_GEOMETRY_POLICIES_ROBUSTNESS_SEGMENT_RATIO_TYPE_HPP diff --git a/include/boost/geometry/strategies/agnostic/hull_graham_andrew.hpp b/include/boost/geometry/strategies/agnostic/hull_graham_andrew.hpp index 8413a1d12..98d2f8949 100644 --- a/include/boost/geometry/strategies/agnostic/hull_graham_andrew.hpp +++ b/include/boost/geometry/strategies/agnostic/hull_graham_andrew.hpp @@ -319,7 +319,7 @@ private: typedef typename strategy::side::services::default_strategy::type side; output.push_back(p); - register std::size_t output_size = output.size(); + std::size_t output_size = output.size(); while (output_size >= 3) { rev_iterator rit = output.rbegin(); diff --git a/include/boost/geometry/strategies/cartesian/cart_intersect.hpp b/include/boost/geometry/strategies/cartesian/cart_intersect.hpp index 1da85cf2b..b704abe3d 100644 --- a/include/boost/geometry/strategies/cartesian/cart_intersect.hpp +++ b/include/boost/geometry/strategies/cartesian/cart_intersect.hpp @@ -19,6 +19,9 @@ #include #include +#include +#include +#include #include #include @@ -28,6 +31,11 @@ #include #include +#include + +#include +#include + #if defined(BOOST_GEOMETRY_DEBUG_ROBUSTNESS) # include @@ -42,38 +50,6 @@ namespace strategy { namespace intersection { -#ifndef DOXYGEN_NO_DETAIL -namespace detail -{ - -template -static inline void segment_arrange(Segment const& s, T& s_1, T& s_2, bool& swapped) -{ - s_1 = get<0, Dimension>(s); - s_2 = get<1, Dimension>(s); - if (s_1 > s_2) - { - std::swap(s_1, s_2); - swapped = true; - } -} - -template -inline typename geometry::point_type::type get_from_index( - Segment const& segment) -{ - typedef typename geometry::point_type::type point_type; - point_type point; - geometry::detail::assign::assign_point_from_index - < - Segment, point_type, Index, 0, dimension::type::value - >::apply(segment, point); - return point; -} - -} -#endif - /*! \see http://mathworld.wolfram.com/Line-LineIntersection.html */ @@ -81,97 +57,91 @@ template struct relate_cartesian_segments { typedef typename Policy::return_type return_type; - typedef typename Policy::segment_type1 segment_type1; - typedef typename Policy::segment_type2 segment_type2; - //typedef typename point_type::type point_type; - //BOOST_CONCEPT_ASSERT( (concept::Point) ); - - BOOST_CONCEPT_ASSERT( (concept::ConstSegment) ); - BOOST_CONCEPT_ASSERT( (concept::ConstSegment) ); - - typedef typename select_calculation_type - ::type coordinate_type; - -#if defined(BOOST_GEOMETRY_DEBUG_ROBUSTNESS) - static inline void debug_segments(std::string const& header, segment_type1 const& a, segment_type2 const& b) + template + static inline void cramers_rule(D const& dx_a, D const& dy_a, + D const& dx_b, D const& dy_b, W const& wx, W const& wy, + // out: + ResultType& d, ResultType& da) { - std::cout << "Robustness issue: " << header << std::endl; - std::cout - << "A: " << wkt(a) << std::endl - << "B: " << wkt(b) << std::endl - ; + // Cramers rule + d = geometry::detail::determinant(dx_a, dy_a, dx_b, dy_b); + da = geometry::detail::determinant(dx_b, dy_b, wx, wy); + // Ratio is da/d , collinear if d == 0, intersecting if 0 <= r <= 1 + // IntersectionPoint = (x1 + r * dx_a, y1 + r * dy_a) } -#endif + // Relate segments a and b - static inline return_type apply(segment_type1 const& a, segment_type2 const& b) + template + static inline return_type apply(Segment1 const& a, Segment2 const& b, + RobustPolicy const& robust_policy) { - coordinate_type const dx_a = get<1, 0>(a) - get<0, 0>(a); // distance in x-dir - coordinate_type const dx_b = get<1, 0>(b) - get<0, 0>(b); - coordinate_type const dy_a = get<1, 1>(a) - get<0, 1>(a); // distance in y-dir - coordinate_type const dy_b = get<1, 1>(b) - get<0, 1>(b); - return apply(a, b, dx_a, dy_a, dx_b, dy_b); + // type them all as in Segment1 - TODO reconsider this, most precise? + typedef typename geometry::point_type::type point_type; + + typedef typename geometry::robust_point_type + < + point_type, RobustPolicy + >::type robust_point_type; + + point_type a0, a1, b0, b1; + robust_point_type a0_rob, a1_rob, b0_rob, b1_rob; + + detail::assign_point_from_index<0>(a, a0); + detail::assign_point_from_index<1>(a, a1); + detail::assign_point_from_index<0>(b, b0); + detail::assign_point_from_index<1>(b, b1); + + geometry::recalculate(a0_rob, a0, robust_policy); + geometry::recalculate(a1_rob, a1, robust_policy); + geometry::recalculate(b0_rob, b0, robust_policy); + geometry::recalculate(b1_rob, b1, robust_policy); + + return apply(a, b, robust_policy, a0_rob, a1_rob, b0_rob, b1_rob); } - // Relate segments a and b using precalculated differences. - // This can save two or four subtractions in many cases - static inline return_type apply(segment_type1 const& a, segment_type2 const& b, - coordinate_type const& dx_a, coordinate_type const& dy_a, - coordinate_type const& dx_b, coordinate_type const& dy_b) + // The main entry-routine, calculating intersections of segments a / b + template + static inline return_type apply(Segment1 const& a, Segment2 const& b, + RobustPolicy const& robust_policy, + RobustPoint const& robust_a1, RobustPoint const& robust_a2, + RobustPoint const& robust_b1, RobustPoint const& robust_b2) { - typedef side::side_by_triangle side; - side_info sides; + BOOST_CONCEPT_ASSERT( (concept::ConstSegment) ); + BOOST_CONCEPT_ASSERT( (concept::ConstSegment) ); - coordinate_type const zero = 0; - bool const a_is_point = math::equals(dx_a, zero) && math::equals(dy_a, zero); - bool const b_is_point = math::equals(dx_b, zero) && math::equals(dy_b, zero); + boost::ignore_unused_variable_warning(robust_policy); + + typedef typename select_calculation_type + ::type coordinate_type; + + using geometry::detail::equals::equals_point_point; + bool const a_is_point = equals_point_point(robust_a1, robust_a2); + bool const b_is_point = equals_point_point(robust_b1, robust_b2); + + typedef side::side_by_triangle side; if(a_is_point && b_is_point) { - if(math::equals(get<1,0>(a), get<1,0>(b)) && math::equals(get<1,1>(a), get<1,1>(b))) - { - Policy::degenerate(a, true); - } - else - { - return Policy::disjoint(); - } + return equals_point_point(robust_a1, robust_b2) + ? Policy::degenerate(a, true) + : Policy::disjoint() + ; } - bool collinear_use_first = math::abs(dx_a) + math::abs(dx_b) >= math::abs(dy_a) + math::abs(dy_b); - - sides.set<0> - ( - side::apply(detail::get_from_index<0>(b) - , detail::get_from_index<1>(b) - , detail::get_from_index<0>(a)), - side::apply(detail::get_from_index<0>(b) - , detail::get_from_index<1>(b) - , detail::get_from_index<1>(a)) - ); - sides.set<1> - ( - side::apply(detail::get_from_index<0>(a) - , detail::get_from_index<1>(a) - , detail::get_from_index<0>(b)), - side::apply(detail::get_from_index<0>(a) - , detail::get_from_index<1>(a) - , detail::get_from_index<1>(b)) - ); + side_info sides; + sides.set<0>(side::apply(robust_b1, robust_b2, robust_a1), + side::apply(robust_b1, robust_b2, robust_a2)); + sides.set<1>(side::apply(robust_a1, robust_a2, robust_b1), + side::apply(robust_a1, robust_a2, robust_b2)); bool collinear = sides.collinear(); - robustness_verify_collinear(a, b, a_is_point, b_is_point, sides, collinear); - robustness_verify_meeting(a, b, sides, collinear, collinear_use_first); - if (sides.same<0>() || sides.same<1>()) { // Both points are at same side of other segment, we can leave - if (robustness_verify_same_side(a, b, sides)) - { - return Policy::disjoint(); - } + return Policy::disjoint(); } // Degenerate cases: segments of single point, lying on other segment, are not disjoint @@ -189,677 +159,164 @@ struct relate_cartesian_segments coordinate_type, double >::type promoted_type; + typedef typename geometry::coordinate_type + < + RobustPoint + >::type robust_coordinate_type; + + typedef typename segment_ratio_type + < + typename geometry::point_type::type, // TODO: most precise point? + RobustPolicy + >::type ratio_type; + + segment_intersection_info + < + coordinate_type, + promoted_type, + ratio_type + > sinfo; + + sinfo.dx_a = get<1, 0>(a) - get<0, 0>(a); // distance in x-dir + sinfo.dx_b = get<1, 0>(b) - get<0, 0>(b); + sinfo.dy_a = get<1, 1>(a) - get<0, 1>(a); // distance in y-dir + sinfo.dy_b = get<1, 1>(b) - get<0, 1>(b); + + robust_coordinate_type const robust_dx_a = get<0>(robust_a2) - get<0>(robust_a1); + robust_coordinate_type const robust_dx_b = get<0>(robust_b2) - get<0>(robust_b1); + robust_coordinate_type const robust_dy_a = get<1>(robust_a2) - get<1>(robust_a1); + robust_coordinate_type const robust_dy_b = get<1>(robust_b2) - get<1>(robust_b1); + // r: ratio 0-1 where intersection divides A/B // (only calculated for non-collinear segments) - promoted_type r; if (! collinear) { - // Calculate determinants - Cramers rule - coordinate_type const wx = get<0, 0>(a) - get<0, 0>(b); - coordinate_type const wy = get<0, 1>(a) - get<0, 1>(b); - promoted_type const d = geometry::detail::determinant(dx_a, dy_a, dx_b, dy_b); - promoted_type const da = geometry::detail::determinant(dx_b, dy_b, wx, wy); + robust_coordinate_type robust_da0, robust_da; + robust_coordinate_type robust_db0, robust_db; - coordinate_type const zero = coordinate_type(); - if (math::equals(d, zero)) + cramers_rule(robust_dx_a, robust_dy_a, robust_dx_b, robust_dy_b, + get<0>(robust_a1) - get<0>(robust_b1), + get<1>(robust_a1) - get<1>(robust_b1), + robust_da0, robust_da); + + cramers_rule(robust_dx_b, robust_dy_b, robust_dx_a, robust_dy_a, + get<0>(robust_b1) - get<0>(robust_a1), + get<1>(robust_b1) - get<1>(robust_a1), + robust_db0, robust_db); + + if (robust_da0 == 0) { - // This is still a collinear case (because of FP imprecision this can occur here) - // sides.debug(); + // If this is the case, no rescaling is done for FP precision. + // We set it to collinear, but it indicates a robustness issue. sides.set<0>(0,0); sides.set<1>(0,0); collinear = true; } else { - r = da / d; - - if (! robustness_verify_r(a, b, r)) - { - return Policy::disjoint(); - } - - if (robustness_verify_disjoint_at_one_collinear(a, b, sides)) - { - return Policy::disjoint(); - } - + sinfo.robust_ra.assign(robust_da, robust_da0); + sinfo.robust_rb.assign(robust_db, robust_db0); } } if(collinear) { + bool const collinear_use_first + = geometry::math::abs(robust_dx_a) + geometry::math::abs(robust_dx_b) + >= geometry::math::abs(robust_dy_a) + geometry::math::abs(robust_dy_b); if (collinear_use_first) { - return relate_collinear<0>(a, b); + return relate_collinear<0, ratio_type>(a, b, robust_a1, robust_a2, robust_b1, robust_b2); } else { // Y direction contains larger segments (maybe dx is zero) - return relate_collinear<1>(a, b); + return relate_collinear<1, ratio_type>(a, b, robust_a1, robust_a2, robust_b1, robust_b2); } } - return Policy::segments_intersect(sides, r, - dx_a, dy_a, dx_b, dy_b, - a, b); + return Policy::segments_crosses(sides, sinfo, a, b); } -private : - - - // Ratio should lie between 0 and 1 - // Also these three conditions might be of FP imprecision, the segments were actually (nearly) collinear - template - static inline bool robustness_verify_r( - segment_type1 const& a, segment_type2 const& b, - T& r) +private: + template + < + std::size_t Dimension, + typename RatioType, + typename Segment1, + typename Segment2, + typename RobustPoint + > + static inline return_type relate_collinear(Segment1 const& a, + Segment2 const& b, + RobustPoint const& robust_a1, RobustPoint const& robust_a2, + RobustPoint const& robust_b1, RobustPoint const& robust_b2) { - T const zero = 0; - T const one = 1; - if (r < zero || r > one) - { - if (verify_disjoint<0>(a, b) || verify_disjoint<1>(a, b)) - { - // Can still be disjoint (even if not one is left or right from another) - // This is e.g. in case #snake4 of buffer test. - return false; - } - - //std::cout << "ROBUSTNESS: correction of r " << r << std::endl; - // sides.debug(); - - // ROBUSTNESS: the r value can in epsilon-cases much larger than 1, while (with perfect arithmetic) - // it should be one. It can be 1.14 or even 1.98049 or 2 (while still intersecting) - - // If segments are crossing (we can see that with the sides) - // and one is inside the other, there must be an intersection point. - // We correct for that. - // This is (only) in case #ggl_list_20110820_christophe in unit tests - - // If segments are touching (two sides zero), of course they should intersect - // This is (only) in case #buffer_rt_i in the unit tests) - - // If one touches in the middle, they also should intersect (#buffer_rt_j) - - // Note that even for ttmath r is occasionally > 1, e.g. 1.0000000000000000000000036191231203575 -#if defined(BOOST_GEOMETRY_DEBUG_ROBUSTNESS) - debug_segments("correcting r", a, b); - std::cout << " --> r=" << r; - if (r > 1.00000000000001 || r < -0.00000000000001) - { - std::cout << " !!!"; - } - std::cout << std::endl << std::endl; -#endif - - if (r > one) - { - r = one; - } - else if (r < zero) - { - r = zero; - } - } - return true; - } - - template - static inline bool analyse_equal(segment_type1 const& a, segment_type2 const& b) - { - coordinate_type const a_1 = geometry::get<0, Dimension>(a); - coordinate_type const a_2 = geometry::get<1, Dimension>(a); - coordinate_type const b_1 = geometry::get<0, Dimension>(b); - coordinate_type const b_2 = geometry::get<1, Dimension>(b); - return math::equals(a_1, b_1) - || math::equals(a_2, b_1) - || math::equals(a_1, b_2) - || math::equals(a_2, b_2) - ; - } - - static inline void robustness_verify_collinear( - segment_type1 const& a, segment_type2 const& b, - bool a_is_point, bool b_is_point, - side_info& sides, - bool& collinear) - { - bool only_0_collinear = sides.zero<0>() && ! b_is_point && ! sides.zero<1>(); - bool only_1_collinear = sides.zero<1>() && ! a_is_point && ! sides.zero<0>(); - if (only_0_collinear || only_1_collinear) - { - typename geometry::point_type::type a0 = detail::get_from_index<0>(a); - typename geometry::point_type::type a1 = detail::get_from_index<1>(a); - typename geometry::point_type::type b0 = detail::get_from_index<0>(b); - typename geometry::point_type::type b1 = detail::get_from_index<1>(b); - bool ae = false, be = false; - - // If one of the segments is collinear, the other is probably so too. - side_info check; - coordinate_type factor = 1; - int iteration = 0; - bool collinear_consistent = false; - do - { - typedef side::side_by_triangle side; - - // We have a robustness issue. We keep increasing epsilon until we have a consistent set - coordinate_type const two = 2; - factor *= two; - coordinate_type epsilon = math::relaxed_epsilon(factor); - check.set<0> - ( - side::apply_with_epsilon(b0, b1, a0, epsilon), - side::apply_with_epsilon(b0, b1, a1, epsilon) - ); - check.set<1> - ( - side::apply_with_epsilon(a0, a1, b0, epsilon), - side::apply_with_epsilon(a0, a1, b1, epsilon) - ); - ae = point_equals_with_epsilon(a0, a1, epsilon); - be = point_equals_with_epsilon(b0, b1, epsilon); - - collinear_consistent = true; - if ( (check.zero<0>() && ! be && ! check.zero<1>()) - || (check.zero<1>() && ! ae && ! check.zero<0>()) - ) - { - collinear_consistent = false; - } - -#if defined(BOOST_GEOMETRY_DEBUG_ROBUSTNESS) - std::cout - << "*** collinear_consistent: " - << iteration << std::boolalpha - << " consistent: " << collinear_consistent - << " equals: " << ae << "," << be - << " epsilon: " << epsilon - << " "; - check.debug(); -#endif - - - } while (! collinear_consistent && iteration++ < 10); - - sides = check; - collinear = sides.collinear(); - } - } - - static inline void robustness_verify_meeting( - segment_type1 const& a, segment_type2 const& b, - side_info& sides, - bool& collinear, bool& collinear_use_first) - { - if (sides.meeting()) - { - // If two segments meet each other at their segment-points, two sides are zero, - // the other two are not (unless collinear but we don't mean those here). - // However, in near-epsilon ranges it can happen that two sides are zero - // but they do not meet at their segment-points. - // In that case they are nearly collinear and handled as such. - - if (! point_equals - ( - select(sides.zero_index<0>(), a), - select(sides.zero_index<1>(), b) - ) - ) - { - - typename geometry::point_type::type a0 = detail::get_from_index<0>(a); - typename geometry::point_type::type a1 = detail::get_from_index<1>(a); - typename geometry::point_type::type b0 = detail::get_from_index<0>(b); - typename geometry::point_type::type b1 = detail::get_from_index<1>(b); - - side_info check; - coordinate_type factor = 1; - coordinate_type epsilon = math::relaxed_epsilon(factor); - int iteration = 1; - bool points_meet = false; - bool meeting_consistent = false; - do - { - typedef side::side_by_triangle side; - - // We have a robustness issue. We keep increasing epsilon until we have a consistent set - coordinate_type const two = 2; - factor *= two; - epsilon = math::relaxed_epsilon(factor); - check.set<0> - ( - side::apply_with_epsilon(b0, b1, a0, epsilon), - side::apply_with_epsilon(b0, b1, a1, epsilon) - ); - check.set<1> - ( - side::apply_with_epsilon(a0, a1, b0, epsilon), - side::apply_with_epsilon(a0, a1, b1, epsilon) - ); - - meeting_consistent = true; - if (check.meeting()) - { - points_meet = point_equals_with_epsilon - ( - select(check.zero_index<0>(), a), - select(check.zero_index<1>(), b), - epsilon - ); - if (! points_meet) - { - meeting_consistent = false; - - } - } - -#if defined(BOOST_GEOMETRY_DEBUG_ROBUSTNESS) - std::cout - << "*** meeting_consistent: " - << iteration << std::boolalpha - << " consistent: " << meeting_consistent - << " epsilon: " << epsilon - << " "; - check.debug(); -#endif - - - } while (! meeting_consistent && iteration++ < 10); - - - sides = check; - - if (! sides.meeting() - && ((sides.zero<0>() && !sides.zero<1>()) - || (! sides.zero<0>() && sides.zero<1>()) - ) - ) - { - // Set sides to zero - sides.set<0>(0,0); - sides.set<1>(0,0); -#if defined(BOOST_GEOMETRY_DEBUG_ROBUSTNESS) - std::cout << "ADAPTED New side info: " << std::endl; - sides.debug(); -#endif - } - - collinear = sides.collinear(); - - if (collinear_use_first && analyse_equal<0>(a, b)) - { - collinear_use_first = false; -#if defined(BOOST_GEOMETRY_DEBUG_ROBUSTNESS) - std::cout << "Use [1] to check collinearity" << std::endl; -#endif - } - else if (! collinear_use_first && analyse_equal<1>(a, b)) - { - collinear_use_first = true; -#if defined(BOOST_GEOMETRY_DEBUG_ROBUSTNESS) - std::cout << "Use [0] to check collinearity" << std::endl; -#endif - } - } - } - } - - // Verifies and if necessary correct missed touch because of robustness - // This is the case at multi_polygon_buffer unittest #rt_m - static inline bool robustness_verify_same_side( - segment_type1 const& a, segment_type2 const& b, - side_info& sides) - { - int corrected = 0; - if (sides.one_touching<0>()) - { - if (point_equals( - select(sides.zero_index<0>(), a), - select(0, b) - )) - { - sides.correct_to_zero<1, 0>(); - corrected = 1; - } - if (point_equals - ( - select(sides.zero_index<0>(), a), - select(1, b) - )) - { - sides.correct_to_zero<1, 1>(); - corrected = 2; - } - } - else if (sides.one_touching<1>()) - { - if (point_equals( - select(sides.zero_index<1>(), b), - select(0, a) - )) - { - sides.correct_to_zero<0, 0>(); - corrected = 3; - } - if (point_equals - ( - select(sides.zero_index<1>(), b), - select(1, a) - )) - { - sides.correct_to_zero<0, 1>(); - corrected = 4; - } - } - - return corrected == 0; - } - - static inline bool robustness_verify_disjoint_at_one_collinear( - segment_type1 const& a, segment_type2 const& b, - side_info const& sides) - { - if (sides.one_of_all_zero()) - { - if (verify_disjoint<0>(a, b) || verify_disjoint<1>(a, b)) - { - return true; - } - } - return false; - } - - template - static inline typename point_type::type select(int index, Segment const& segment) - { - return index == 0 - ? detail::get_from_index<0>(segment) - : detail::get_from_index<1>(segment) - ; - } - - // We cannot use geometry::equals here. Besides that this will be changed - // to compare segment-coordinate-values directly (not necessary to retrieve point first) - template - static inline bool point_equals(Point1 const& point1, Point2 const& point2) - { - return math::equals(get<0>(point1), get<0>(point2)) - && math::equals(get<1>(point1), get<1>(point2)) - ; - } - - template - static inline bool point_equals_with_epsilon(Point1 const& point1, Point2 const& point2, T const& epsilon) - { - // Check if difference is within espilon range (epsilon can be 0 for integer) - return math::abs(geometry::get<0>(point1) - geometry::get<0>(point2)) <= epsilon - && math::abs(geometry::get<1>(point1) - geometry::get<1>(point2)) <= epsilon - ; - } - - - // We cannot use geometry::equals here. Besides that this will be changed - // to compare segment-coordinate-values directly (not necessary to retrieve point first) - template - static inline bool point_equality(Point1 const& point1, Point2 const& point2, - bool& equals_0, bool& equals_1) - { - equals_0 = math::equals(get<0>(point1), get<0>(point2)); - equals_1 = math::equals(get<1>(point1), get<1>(point2)); - return equals_0 && equals_1; - } - - template - static inline bool verify_disjoint(segment_type1 const& a, - segment_type2 const& b) - { - coordinate_type a_1, a_2, b_1, b_2; - bool a_swapped = false, b_swapped = false; - detail::segment_arrange(a, a_1, a_2, a_swapped); - detail::segment_arrange(b, b_1, b_2, b_swapped); - return math::smaller(a_2, b_1) || math::larger(a_1, b_2); - } - - template - static inline return_type relate_collinear(segment_type1 const& a, - segment_type2 const& b) - { - coordinate_type a_1, a_2, b_1, b_2; - bool a_swapped = false, b_swapped = false; - detail::segment_arrange(a, a_1, a_2, a_swapped); - detail::segment_arrange(b, b_1, b_2, b_swapped); - if (math::smaller(a_2, b_1) || math::larger(a_1, b_2)) - //if (a_2 < b_1 || a_1 > b_2) - { - return Policy::disjoint(); - } - return relate_collinear(a, b, a_1, a_2, b_1, b_2, a_swapped, b_swapped); + return relate_collinear(a, b, + get(robust_a1), + get(robust_a2), + get(robust_b1), + get(robust_b2)); } /// Relate segments known collinear - static inline return_type relate_collinear(segment_type1 const& a - , segment_type2 const& b - , coordinate_type a_1, coordinate_type a_2 - , coordinate_type b_1, coordinate_type b_2 - , bool a_swapped, bool b_swapped) + template + < + typename RatioType, + typename Segment1, + typename Segment2, + typename RobustType + > + static inline return_type relate_collinear(Segment1 const& a + , Segment2 const& b + , RobustType oa_1, RobustType oa_2 + , RobustType ob_1, RobustType ob_2 + ) { - // All ca. 150 lines are about collinear rays - // The intersections, if any, are always boundary points of the segments. No need to calculate anything. - // However we want to find out HOW they intersect, there are many cases. - // Most sources only provide the intersection (above) or that there is a collinearity (but not the points) - // or some spare sources give the intersection points (calculated) but not how they align. - // This source tries to give everything and still be efficient. - // It is therefore (and because of the extensive clarification comments) rather long... + // Calculate the ratios where a starts in b, b starts in a + // a1--------->a2 (2..7) + // b1----->b2 (5..8) + // length_a: 7-2=5 + // length_b: 8-5=3 + // b1 is located w.r.t. a at ratio: (5-2)/5=3/5 (on a) + // b2 is located w.r.t. a at ratio: (8-2)/5=6/5 (right of a) + // a1 is located w.r.t. b at ratio: (2-5)/3=-3/3 (left of b) + // a2 is located w.r.t. b at ratio: (7-5)/3=2/3 (on b) + // A arrives (a2 on b), B departs (b1 on a) - // \see http://mpa.itc.it/radim/g50history/CMP/4.2.1-CERL-beta-libes/file475.txt - // \see http://docs.codehaus.org/display/GEOTDOC/Point+Set+Theory+and+the+DE-9IM+Matrix - // \see http://mathworld.wolfram.com/Line-LineIntersection.html + // If both are reversed: + // a2<---------a1 (7..2) + // b2<-----b1 (8..5) + // length_a: 2-7=-5 + // length_b: 5-8=-3 + // b1 is located w.r.t. a at ratio: (8-7)/-5=-1/5 (before a starts) + // b2 is located w.r.t. a at ratio: (5-7)/-5=2/5 (on a) + // a1 is located w.r.t. b at ratio: (7-8)/-3=1/3 (on b) + // a2 is located w.r.t. b at ratio: (2-8)/-3=6/3 (after b ends) - // Because of collinearity the case is now one-dimensional and can be checked using intervals - // This function is called either horizontally or vertically - // We get then two intervals: - // a_1-------------a_2 where a_1 < a_2 - // b_1-------------b_2 where b_1 < b_2 - // In all figures below a_1/a_2 denotes arranged intervals, a1-a2 or a2-a1 are still unarranged + // If both one is reversed: + // a1--------->a2 (2..7) + // b2<-----b1 (8..5) + // length_a: 7-2=+5 + // length_b: 5-8=-3 + // b1 is located w.r.t. a at ratio: (8-2)/5=6/5 (after a ends) + // b2 is located w.r.t. a at ratio: (5-2)/5=3/5 (on a) + // a1 is located w.r.t. b at ratio: (2-8)/-3=6/3 (after b ends) + // a2 is located w.r.t. b at ratio: (7-8)/-3=1/3 (on b) + RobustType const length_a = oa_2 - oa_1; // no abs, see above + RobustType const length_b = ob_2 - ob_1; - // Handle "equal", in polygon neighbourhood comparisons a common case + RatioType const ra_from(oa_1 - ob_1, length_b); + RatioType const ra_to(oa_2 - ob_1, length_b); + RatioType const rb_from(ob_1 - oa_1, length_a); + RatioType const rb_to(ob_2 - oa_1, length_a); - bool const opposite = a_swapped ^ b_swapped; - bool const both_swapped = a_swapped && b_swapped; - - // Check if segments are equal or opposite equal... - bool const swapped_a1_eq_b1 = math::equals(a_1, b_1); - bool const swapped_a2_eq_b2 = math::equals(a_2, b_2); - - if (swapped_a1_eq_b1 && swapped_a2_eq_b2) + if ((ra_from.left() && ra_to.left()) || (ra_from.right() && ra_to.right())) { - return Policy::segment_equal(a, opposite); + return Policy::disjoint(); } - bool const swapped_a2_eq_b1 = math::equals(a_2, b_1); - bool const swapped_a1_eq_b2 = math::equals(a_1, b_2); - - bool const a1_eq_b1 = both_swapped ? swapped_a2_eq_b2 : a_swapped ? swapped_a2_eq_b1 : b_swapped ? swapped_a1_eq_b2 : swapped_a1_eq_b1; - bool const a2_eq_b2 = both_swapped ? swapped_a1_eq_b1 : a_swapped ? swapped_a1_eq_b2 : b_swapped ? swapped_a2_eq_b1 : swapped_a2_eq_b2; - - bool const a1_eq_b2 = both_swapped ? swapped_a2_eq_b1 : a_swapped ? swapped_a2_eq_b2 : b_swapped ? swapped_a1_eq_b1 : swapped_a1_eq_b2; - bool const a2_eq_b1 = both_swapped ? swapped_a1_eq_b2 : a_swapped ? swapped_a1_eq_b1 : b_swapped ? swapped_a2_eq_b2 : swapped_a2_eq_b1; - - - - - // The rest below will return one or two intersections. - // The delegated class can decide which is the intersection point, or two, build the Intersection Matrix (IM) - // For IM it is important to know which relates to which. So this information is given, - // without performance penalties to intersection calculation - - bool const has_common_points = swapped_a1_eq_b1 || swapped_a1_eq_b2 || swapped_a2_eq_b1 || swapped_a2_eq_b2; - - - // "Touch" -> one intersection point -> one but not two common points - // --------> A (or B) - // <---------- B (or A) - // a_2==b_1 (b_2==a_1 or a_2==b1) - - // The check a_2/b_1 is necessary because it excludes cases like - // -------> - // ---> - // ... which are handled lateron - - // Corresponds to 4 cases, of which the equal points are determined above - // #1: a1---->a2 b1--->b2 (a arrives at b's border) - // #2: a2<----a1 b2<---b1 (b arrives at a's border) - // #3: a1---->a2 b2<---b1 (both arrive at each others border) - // #4: a2<----a1 b1--->b2 (no arrival at all) - // Where the arranged forms have two forms: - // a_1-----a_2/b_1-------b_2 or reverse (B left of A) - if ((swapped_a2_eq_b1 || swapped_a1_eq_b2) && ! swapped_a1_eq_b1 && ! swapped_a2_eq_b2) - { - if (a2_eq_b1) return Policy::collinear_touch(get<1, 0>(a), get<1, 1>(a), 0, -1); - if (a1_eq_b2) return Policy::collinear_touch(get<0, 0>(a), get<0, 1>(a), -1, 0); - if (a2_eq_b2) return Policy::collinear_touch(get<1, 0>(a), get<1, 1>(a), 0, 0); - if (a1_eq_b1) return Policy::collinear_touch(get<0, 0>(a), get<0, 1>(a), -1, -1); - } - - - // "Touch/within" -> there are common points and also an intersection of interiors: - // Corresponds to many cases: - // #1a: a1------->a2 #1b: a1-->a2 - // b1--->b2 b1------->b2 - // #2a: a2<-------a1 #2b: a2<--a1 - // b1--->b2 b1------->b2 - // #3a: a1------->a2 #3b: a1-->a2 - // b2<---b1 b2<-------b1 - // #4a: a2<-------a1 #4b: a2<--a1 - // b2<---b1 b2<-------b1 - - // Note: next cases are similar and handled by the code - // #4c: a1--->a2 - // b1-------->b2 - // #4d: a1-------->a2 - // b1-->b2 - - // For case 1-4: a_1 < (b_1 or b_2) < a_2, two intersections are equal to segment B - // For case 5-8: b_1 < (a_1 or a_2) < b_2, two intersections are equal to segment A - if (has_common_points) - { - // Either A is in B, or B is in A, or (in case of robustness/equals) - // both are true, see below - bool a_in_b = (b_1 < a_1 && a_1 < b_2) || (b_1 < a_2 && a_2 < b_2); - bool b_in_a = (a_1 < b_1 && b_1 < a_2) || (a_1 < b_2 && b_2 < a_2); - - if (a_in_b && b_in_a) - { - // testcase "ggl_list_20110306_javier" - // In robustness it can occur that a point of A is inside B AND a point of B is inside A, - // still while has_common_points is true (so one point equals the other). - // If that is the case we select on length. - coordinate_type const length_a = geometry::math::abs(a_1 - a_2); - coordinate_type const length_b = geometry::math::abs(b_1 - b_2); - if (length_a > length_b) - { - a_in_b = false; - } - else - { - b_in_a = false; - } - } - - int const arrival_a = a_in_b ? 1 : -1; - if (a2_eq_b2) return Policy::collinear_interior_boundary_intersect(a_in_b ? a : b, a_in_b, 0, 0, false); - if (a1_eq_b2) return Policy::collinear_interior_boundary_intersect(a_in_b ? a : b, a_in_b, arrival_a, 0, true); - if (a2_eq_b1) return Policy::collinear_interior_boundary_intersect(a_in_b ? a : b, a_in_b, 0, -arrival_a, true); - if (a1_eq_b1) return Policy::collinear_interior_boundary_intersect(a_in_b ? a : b, a_in_b, arrival_a, -arrival_a, false); - } - - - - // "Inside", a completely within b or b completely within a - // 2 cases: - // case 1: - // a_1---a_2 -> take A's points as intersection points - // b_1------------b_2 - // case 2: - // a_1------------a_2 - // b_1---b_2 -> take B's points - if (a_1 > b_1 && a_2 < b_2) - { - // A within B - return Policy::collinear_a_in_b(a, opposite); - } - if (b_1 > a_1 && b_2 < a_2) - { - // B within A - return Policy::collinear_b_in_a(b, opposite); - } - - - /* - - Now that all cases with equal,touch,inside,disjoint, - degenerate are handled the only thing left is an overlap - - Either a1 is between b1,b2 - or a2 is between b1,b2 (a2 arrives) - - Next table gives an overview. - The IP's are ordered following the line A1->A2 - - | | - | a_2 in between | a_1 in between - | | - -----+---------------------------------+-------------------------- - | a1--------->a2 | a1--------->a2 - | b1----->b2 | b1----->b2 - | (b1,a2), a arrives | (a1,b2), b arrives - | | - -----+---------------------------------+-------------------------- - a sw.| a2<---------a1* | a2<---------a1* - | b1----->b2 | b1----->b2 - | (a1,b1), no arrival | (b2,a2), a and b arrive - | | - -----+---------------------------------+-------------------------- - | a1--------->a2 | a1--------->a2 - b sw.| b2<-----b1 | b2<-----b1 - | (b2,a2), a and b arrive | (a1,b1), no arrival - | | - -----+---------------------------------+-------------------------- - a sw.| a2<---------a1* | a2<---------a1* - b sw.| b2<-----b1 | b2<-----b1 - | (a1,b2), b arrives | (b1,a2), a arrives - | | - -----+---------------------------------+-------------------------- - * Note that a_1 < a_2, and a1 <> a_1; if a is swapped, - the picture might seem wrong but it (supposed to be) is right. - */ - - if (b_1 < a_2 && a_2 < b_2) - { - // Left column, from bottom to top - return - both_swapped ? Policy::collinear_overlaps(get<0, 0>(a), get<0, 1>(a), get<1, 0>(b), get<1, 1>(b), -1, 1, opposite) - : b_swapped ? Policy::collinear_overlaps(get<1, 0>(b), get<1, 1>(b), get<1, 0>(a), get<1, 1>(a), 1, 1, opposite) - : a_swapped ? Policy::collinear_overlaps(get<0, 0>(a), get<0, 1>(a), get<0, 0>(b), get<0, 1>(b), -1, -1, opposite) - : Policy::collinear_overlaps(get<0, 0>(b), get<0, 1>(b), get<1, 0>(a), get<1, 1>(a), 1, -1, opposite) - ; - } - if (b_1 < a_1 && a_1 < b_2) - { - // Right column, from bottom to top - return - both_swapped ? Policy::collinear_overlaps(get<0, 0>(b), get<0, 1>(b), get<1, 0>(a), get<1, 1>(a), 1, -1, opposite) - : b_swapped ? Policy::collinear_overlaps(get<0, 0>(a), get<0, 1>(a), get<0, 0>(b), get<0, 1>(b), -1, -1, opposite) - : a_swapped ? Policy::collinear_overlaps(get<1, 0>(b), get<1, 1>(b), get<1, 0>(a), get<1, 1>(a), 1, 1, opposite) - : Policy::collinear_overlaps(get<0, 0>(a), get<0, 1>(a), get<1, 0>(b), get<1, 1>(b), -1, 1, opposite) - ; - } - // Nothing should goes through. If any we have made an error -#if defined(BOOST_GEOMETRY_DEBUG_ROBUSTNESS) - debug_segments("unexpected behaviour", a, b); -#endif - return Policy::error("Robustness issue, relate_cartesian_segments, unexpected behaviour"); + return Policy::segments_collinear(a, b, ra_from, ra_to, rb_from, rb_to); } }; diff --git a/include/boost/geometry/strategies/intersection.hpp b/include/boost/geometry/strategies/intersection.hpp index 243f5b561..d97baf66d 100644 --- a/include/boost/geometry/strategies/intersection.hpp +++ b/include/boost/geometry/strategies/intersection.hpp @@ -20,38 +20,44 @@ #include #include +#include namespace boost { namespace geometry { -// The intersection strategy is a "compound strategy", -// it contains a segment-intersection-strategy -// and a side-strategy /*! -\tparam CalculationType \tparam_calculation -*/ +\brief "compound strategy", containing a segment-intersection-strategy + and a side-strategy + */ template < typename Tag, typename Geometry1, typename Geometry2, typename IntersectionPoint, + typename RobustPolicy, typename CalculationType = void > struct strategy_intersection { private : + // for development BOOST_STATIC_ASSERT((! boost::is_same::type::value)); + typedef typename geometry::point_type::type point1_type; typedef typename geometry::point_type::type point2_type; typedef typename model::referring_segment segment1_type; typedef typename model::referring_segment segment2_type; typedef segment_intersection_points + < + IntersectionPoint, + typename geometry::segment_ratio_type < - IntersectionPoint - > ip_type; + IntersectionPoint, RobustPolicy + >::type + > ip_type; public: typedef strategy::intersection::relate_cartesian_segments @@ -60,18 +66,9 @@ public: < policies::relate::segments_intersection_points < - segment1_type, - segment2_type, - ip_type, - CalculationType + ip_type > , policies::relate::segments_direction - < - segment1_type, - segment2_type, - CalculationType - >, - CalculationType >, CalculationType > segment_intersection_strategy_type; @@ -81,6 +78,8 @@ public: Tag, CalculationType >::type side_strategy_type; + + typedef RobustPolicy rescale_policy_type; }; diff --git a/include/boost/geometry/strategies/intersection_result.hpp b/include/boost/geometry/strategies/intersection_result.hpp index 15917a9eb..695db79c9 100644 --- a/include/boost/geometry/strategies/intersection_result.hpp +++ b/include/boost/geometry/strategies/intersection_result.hpp @@ -16,6 +16,7 @@ #include + namespace boost { namespace geometry { @@ -153,13 +154,47 @@ struct de9im_segment : public de9im #endif }; +template +struct fraction_type +{ + SegmentRatio robust_ra; // TODO this can be renamed now to "ra" + SegmentRatio robust_rb; + bool initialized; + inline fraction_type() + : initialized(false) + {} -template + template + inline void assign(Info const& info) + { + initialized = true; + robust_ra = info.robust_ra; + robust_rb = info.robust_rb; + } + + inline void assign(SegmentRatio const& a, SegmentRatio const& b) + { + initialized = true; + robust_ra = a; + robust_rb = b; + } + +}; + +// +/*! +\brief return-type for segment-intersection +\note Set in intersection_points.hpp, from segment_intersection_info +*/ +template struct segment_intersection_points { - std::size_t count; + std::size_t count; // The number of intersection points + + // TODO: combine intersections and fractions in one struct Point intersections[2]; + fraction_type fractions[2]; typedef Point point_type; segment_intersection_points() @@ -167,6 +202,18 @@ struct segment_intersection_points {} }; +// All assigned in cart_intersect, passed to intersection_points +template +struct segment_intersection_info +{ + typedef PromotedType promoted_type; + + CoordinateType dx_a, dy_a; + CoordinateType dx_b, dy_b; // TODO b can be removed + SegmentRatio robust_ra; + SegmentRatio robust_rb; +}; + }} // namespace boost::geometry diff --git a/include/boost/geometry/views/normalized_view.hpp b/include/boost/geometry/views/normalized_view.hpp new file mode 100644 index 000000000..dfa48f779 --- /dev/null +++ b/include/boost/geometry/views/normalized_view.hpp @@ -0,0 +1,116 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2008-2012 Bruno Lalande, Paris, France. +// Copyright (c) 2009-2012 Mateusz Loskot, London, UK. + +// This file was modified by Oracle on 2014. +// Modifications copyright (c) 2014 Oracle and/or its affiliates. + +// 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) + +// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle + +#ifndef BOOST_GEOMETRY_VIEWS_NORMALIZED_VIEW_HPP +#define BOOST_GEOMETRY_VIEWS_NORMALIZED_VIEW_HPP + + +#include +#include +#include +#include +#include +#include +#include +#include + +namespace boost { namespace geometry { + + +#ifndef DOXYGEN_NO_DETAIL + +namespace detail { + +template +struct normalized_view +{ + static const bool is_const = boost::is_const::value; + + //typedef typename ring_type::type ring_type; + + typedef typename detail::range_type::type range_type; + + typedef typename + boost::mpl::if_c + < + is_const, + range_type const, + range_type + >::type range; + + typedef typename + reversible_view + < + range, + order_as_direction + < + geometry::point_order::value + >::value + >::type reversible_type; + + typedef typename + boost::mpl::if_c + < + is_const, + reversible_type const, + reversible_type + >::type reversible; + + typedef typename + closeable_view + < + reversible, + geometry::closure::value + >::type closeable_type; + + typedef typename + boost::mpl::if_c + < + is_const, + closeable_type const, + closeable_type + >::type closeable; + + explicit inline normalized_view(range & r) + : m_reversible(r) + , m_closeable(m_reversible) + {} + + typedef typename boost::range_iterator::type iterator; + typedef typename boost::range_const_iterator::type const_iterator; + + inline const_iterator begin() const { return boost::begin(m_closeable); } + inline const_iterator end() const { return boost::end(m_closeable); } + + inline iterator begin() { return boost::begin(m_closeable); } + inline iterator end() { return boost::end(m_closeable); } + +private: + reversible_type m_reversible; + closeable_type m_closeable; +}; + +} // namespace detail + +#endif // DOXYGEN_NO_DETAIL + + +}} // namespace boost::geometry + + +#endif // BOOST_GEOMETRY_VIEWS_NORMALIZED_VIEW_HPP diff --git a/index/test/Jamfile.v2 b/index/test/Jamfile.v2 index 32ea1e376..c2a192e1c 100644 --- a/index/test/Jamfile.v2 +++ b/index/test/Jamfile.v2 @@ -20,7 +20,7 @@ project boost-geometry-index-test test-suite boost-geometry-index-varray : [ run varray_old.cpp ] - [ run varray.cpp ] + [ run varray.cpp : : : msvc:/bigobj ] ; build-project algorithms ; diff --git a/index/test/rtree/exceptions/Jamfile.v2 b/index/test/rtree/exceptions/Jamfile.v2 index c8b42604c..1728b245b 100644 --- a/index/test/rtree/exceptions/Jamfile.v2 +++ b/index/test/rtree/exceptions/Jamfile.v2 @@ -12,7 +12,12 @@ rule test_all for local fileb in [ glob *.cpp ] { - all_rules += [ run $(fileb) ] ; + all_rules += [ run $(fileb) + : # additional args + : # test-files + : # requirements + msvc:/bigobj + ] ; } return $(all_rules) ; diff --git a/index/test/rtree/generated/Jamfile.v2 b/index/test/rtree/generated/Jamfile.v2 index b3ac64804..f3900741b 100644 --- a/index/test/rtree/generated/Jamfile.v2 +++ b/index/test/rtree/generated/Jamfile.v2 @@ -12,7 +12,12 @@ rule test_all for local fileb in [ glob *.cpp ] { - all_rules += [ run $(fileb) ] ; + all_rules += [ run $(fileb) + : # additional args + : # test-files + : # requirements + msvc:/bigobj + ] ; } return $(all_rules) ; diff --git a/index/test/rtree/interprocess/Jamfile.v2 b/index/test/rtree/interprocess/Jamfile.v2 index d0643b45f..9e8a05f2a 100644 --- a/index/test/rtree/interprocess/Jamfile.v2 +++ b/index/test/rtree/interprocess/Jamfile.v2 @@ -18,9 +18,11 @@ rule test_all : # requirements acc:-lrt acc-pa_risc:-lrt - gcc-mingw:"-lole32 -loleaut32 -lpsapi -ladvapi32" hpux,gcc:"-Wl,+as,mpas" +# gcc-mingw:"-lole32 -loleaut32 -lpsapi -ladvapi32" + gcc,windows:"-lole32 -loleaut32 -lpsapi -ladvapi32" windows,clang:"-lole32 -loleaut32 -lpsapi -ladvapi32" + msvc:/bigobj ] ; } diff --git a/test/algorithms/Jamfile.v2 b/test/algorithms/Jamfile.v2 index 2367e494b..52c497af2 100644 --- a/test/algorithms/Jamfile.v2 +++ b/test/algorithms/Jamfile.v2 @@ -13,8 +13,6 @@ # Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at # http://www.boost.org/LICENSE_1_0.txt) -import testing ; - test-suite boost-geometry-algorithms : [ run append.cpp : : : msvc:/bigobj ] @@ -29,8 +27,8 @@ test-suite boost-geometry-algorithms [ run covered_by.cpp ] [ run crosses.cpp ] [ run difference.cpp : : : BOOST_GEOMETRY_TEST_ONLY_ONE_TYPE msvc:/bigobj ] - [ run difference_linear_linear.cpp /boost/test//boost_unit_test_framework ] - [ run difference_pl_pl.cpp /boost/test//boost_unit_test_framework ] + [ run difference_linear_linear.cpp ] + [ run difference_pl_pl.cpp ] [ run disjoint.cpp ] [ run distance.cpp : : : msvc:/bigobj ] [ run envelope.cpp ] @@ -38,26 +36,33 @@ test-suite boost-geometry-algorithms [ run expand.cpp ] [ run for_each.cpp ] [ run intersection.cpp : : : BOOST_GEOMETRY_TEST_ONLY_ONE_TYPE msvc:/bigobj ] - [ run intersection_linear_linear.cpp /boost/test//boost_unit_test_framework ] - [ run intersection_pl_pl.cpp /boost/test//boost_unit_test_framework ] + [ run intersection_linear_linear.cpp ] + [ run intersection_pl_pl.cpp ] [ run intersects.cpp : : : msvc:/bigobj ] [ run length.cpp ] [ run make.cpp ] [ run overlaps.cpp ] [ run perimeter.cpp ] [ run point_on_surface.cpp ] - [ run relate.cpp ] + [ run relate_areal_areal.cpp : : : msvc:/bigobj ] + [ run relate_linear_areal.cpp : : : msvc:/bigobj ] + [ run relate_linear_linear.cpp : : : msvc:/bigobj ] + [ run relate_pointlike_xxx.cpp : : : msvc:/bigobj ] [ run remove_spikes.cpp ] [ run reverse.cpp ] [ run simplify.cpp ] - [ run sym_difference_linear_linear.cpp /boost/test//boost_unit_test_framework ] + [ run sym_difference_linear_linear.cpp ] [ run touches.cpp ] [ run transform.cpp ] [ run union.cpp : : : BOOST_GEOMETRY_TEST_ONLY_ONE_TYPE ] - [ run union_linear_linear.cpp /boost/test//boost_unit_test_framework ] - [ run union_pl_pl.cpp /boost/test//boost_unit_test_framework ] + [ run union_linear_linear.cpp ] + [ run union_pl_pl.cpp ] [ run unique.cpp ] [ run within.cpp : : : msvc:/bigobj ] + [ run within_areal_areal.cpp : : : msvc:/bigobj ] + [ run within_linear_areal.cpp : : : msvc:/bigobj ] + [ run within_linear_linear.cpp : : : msvc:/bigobj ] + [ run within_pointlike_xxx.cpp : : : msvc:/bigobj ] ; build-project overlay diff --git a/test/algorithms/detail/Jamfile.v2 b/test/algorithms/detail/Jamfile.v2 index 015e2be6a..664583094 100644 --- a/test/algorithms/detail/Jamfile.v2 +++ b/test/algorithms/detail/Jamfile.v2 @@ -10,6 +10,7 @@ test-suite boost-geometry-algorithms-detail : + [ run intersection_side.cpp ] [ run partition.cpp ] ; diff --git a/test/algorithms/detail/intersection_side.cpp b/test/algorithms/detail/intersection_side.cpp new file mode 100644 index 000000000..a4d6e6fd0 --- /dev/null +++ b/test/algorithms/detail/intersection_side.cpp @@ -0,0 +1,197 @@ +// 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) + +#define BOOST_GEOMETRY_DEFINE_STREAM_OPERATOR_SEGMENT_RATIO + +#include + +#include + +#include +#include +#include +#include +#include +#include +#include + +#if defined(TEST_WITH_SVG) +# include +#endif + + +template +void test_one(std::string const& caseid, + T pi_x, T pi_y, T pj_x, T pj_y, // line p to intersect + T qi_x, T qi_y, T qj_x, T qj_y, // line q to intersect + T si_x, T si_y, T sj_x, T sj_y, // subject line to find side on of IP p/q + int expected_side) +{ + typedef bg::detail::no_rescale_policy robust_policy_type; + robust_policy_type robust_policy; + + Point pi = bg::make(pi_x, pi_y); + Point pj = bg::make(pj_x, pj_y); + Point qi = bg::make(qi_x, qi_y); + Point qj = bg::make(qj_x, qj_y); + Point si = bg::make(si_x, si_y); + Point sj = bg::make(sj_x, sj_y); + + typedef bg::model::referring_segment segment_type; + + segment_type p(pi, pj); + segment_type q(qi, qj); + segment_type s(si, sj); + + int detected_side = bg::detail::intersection_side::intersection_side(pi, pj, + qi, qj, si, sj, robust_policy); + + BOOST_CHECK_EQUAL(expected_side, detected_side); + +#if defined(TEST_WITH_SVG) + { + std::ostringstream filename; + filename << "intersection_side_" << caseid + << "_" << string_from_type::type>::name() + << ".svg"; + + std::ofstream svg(filename.str().c_str()); + + bg::svg_mapper mapper(svg, 500, 500); + mapper.add(p); + mapper.add(q); + mapper.add(s); + + mapper.map(p, "opacity:0.7;stroke:rgb(0,192,0);stroke-width:3"); + mapper.map(q, "opacity:0.7;stroke:rgb(0,0,255);stroke-width:3"); + mapper.map(s, "opacity:0.7;stroke:rgb(255,0,0);stroke-width:2"); + + std::string style = ";font-family='Verdana';font-weight:bold"; + std::string align = ";text-anchor:end;text-align:end"; + int offset = 8; + + mapper.text(pi, "pi", "fill:rgb(0,192,0)" + style, offset, offset); + mapper.text(pj, "pj", "fill:rgb(0,192,0)" + style, offset, offset); + + mapper.text(qi, "qi", "fill:rgb(0,0,255)" + style + align, -offset, offset); + mapper.text(qj, "qj", "fill:rgb(0,0,255)" + style + align, -offset, offset); + + mapper.text(si, "si", "fill:rgb(255,0,0)" + style + align, -offset, offset); + mapper.text(sj, "sj", "fill:rgb(255,0,0)" + style + align, -offset, offset); + + // Map the intersection point on the SVG + { + typedef typename bg::segment_ratio_type + < + Point, + robust_policy_type + >::type segment_ratio_type; + + // Get the intersection point (or two points) + bg::segment_intersection_points is + = bg::strategy::intersection::relate_cartesian_segments + < + bg::policies::relate::segments_intersection_points + < + bg::segment_intersection_points + > + >::apply(p, q, robust_policy); + + bg::fraction_type rs + = bg::strategy::intersection::relate_cartesian_segments + < + bg::policies::relate::segments_intersection_ratios + < + bg::fraction_type + > + >::apply(p, q, robust_policy); + + for (int i = 0; i < is.count; i++) + { + mapper.map(is.intersections[i], "opacity:0.8;stroke:rgb(255,128,0);stroke-width:3", 3); + std::ostringstream out; + out << detected_side << " " << is.fractions[i].robust_ra << " / " << is.fractions[i].robust_rb + << std::endl + << rs.robust_ra << " / " << rs.robust_rb; + mapper.text(is.intersections[i], out.str(), "fill:rgb(255,128,0)" + style + align, -2 * offset, offset); + } + } + } + +#endif + +} + + +template +void test_all() +{ + test_one("simplex_left", + 0, 0, 4, 4, // p + -1, 4, 3, 0, // q + 2, 0, 2, 4, // subject + 1); + test_one("simplex_right", + 0, 0, 4, 4, // p + 1, 4, 5, 0, // q + 2, 0, 2, 4, // subject + -1); + test_one("simplex_collinear", + 0, 0, 4, 4, // p + 0, 4, 4, 0, // q + 2, 0, 2, 4, // subject + 0); + + test_one("p_left", + 0, 0, 0, 4, // p + 1, 4, 5, 0, // q + 2, 0, 2, 4, // subject + 1); + + test_one("p_right", + 4, 0, 4, 4, // p + 1, 4, 5, 0, // q + 2, 0, 2, 4, // subject + -1); + test_one("p_left", + 1, 0, 1, 4, // p + 1, 4, 5, 0, // q + 2, 0, 2, 4, // subject + 1); + + test_one("p_collinear", + 2, -1, 2, 5, // p + 1, 4, 5, 0, // q + 2, 0, 2, 4, // subject + 0); + + test_one("q_left", + 0, 0, 4, 4, // p + 1, 4, 1, 0, // q + 2, 0, 2, 4, // subject + 1); + + test_one("q_right", + 0, 0, 4, 4, // p + 3, 4, 3, 0, // q + 2, 0, 2, 4, // subject + -1); + + test_one("q_collinear", + 0, 0, 4, 4, // p + 2, 1, 2, 3, // q + 2, 0, 2, 4, // subject + 0); +} + + +int test_main( int , char* [] ) +{ + test_all >(); + + return 0; +} diff --git a/test/algorithms/detail/sections/range_by_section.cpp b/test/algorithms/detail/sections/range_by_section.cpp index e1d1bca1d..fa804f1ff 100644 --- a/test/algorithms/detail/sections/range_by_section.cpp +++ b/test/algorithms/detail/sections/range_by_section.cpp @@ -10,6 +10,7 @@ #include #include +#define BOOST_GEOMETRY_UNIT_TEST_SECTIONALIZE #include diff --git a/test/algorithms/detail/sections/sectionalize.cpp b/test/algorithms/detail/sections/sectionalize.cpp index b4569fa24..8cf079db7 100644 --- a/test/algorithms/detail/sections/sectionalize.cpp +++ b/test/algorithms/detail/sections/sectionalize.cpp @@ -15,6 +15,7 @@ #include #include +#define BOOST_GEOMETRY_UNIT_TEST_SECTIONALIZE #include diff --git a/test/algorithms/difference.cpp b/test/algorithms/difference.cpp index f7d6c2a82..139c5c147 100644 --- a/test/algorithms/difference.cpp +++ b/test/algorithms/difference.cpp @@ -11,6 +11,10 @@ #include #include +// If defined, tests are run without rescaling-to-integer or robustness policy +// Test which would fail then are disabled automatically +// #define BOOST_GEOMETRY_NO_ROBUSTNESS + #include #include @@ -136,12 +140,13 @@ void test_all() 1, 5, 1.0, 1, 5, 1.0); + // The too small one might be discarded (depending on point-type / compiler) + // We check area only test_one("distance_zero", distance_zero[0], distance_zero[1], - 2, -1, 8.7048386, - if_typed(1, 2), // The too small one is discarded for floating point - -1, 0.0098387); - + -1, -1, 8.7048386, + -1, -1, 0.0098387, + 0.001); test_one("equal_holes_disjoint", equal_holes_disjoint[0], equal_holes_disjoint[1], @@ -233,10 +238,12 @@ void test_all() 1, 5, 1, 1, 5, 1); +#if ! defined(BOOST_GEOMETRY_NO_ROBUSTNESS) test_one("buffer_mp1", buffer_mp1[0], buffer_mp1[1], 1, 61, 10.2717, 1, 61, 10.2717); +#endif if (boost::is_same::value) { @@ -258,15 +265,38 @@ void test_all() 1, 0, 13); ***/ + // Isovist - the # output polygons differ per compiler/pointtype, (very) small + // rings might be discarded. We check area only test_one("isovist", isovist1[0], isovist1[1], - if_typed_tt(4, 2), -1, 0.279121, - 4, -1, 224.8892, - if_typed_tt(0.001, 0.1)); - + -1, -1, 0.279121, + -1, -1, 224.8892, + 0.001); // SQL Server gives: 0.279121891701124 and 224.889211358929 // PostGIS gives: 0.279121991127244 and 224.889205853156 + test_one("geos_1", + geos_1[0], geos_1[1], + 21, -1, 0.31640625, + 9, -1, 0.01953125); + // SQL Server gives: 0.28937764436705 and 0.000786406897532288 with 44/35 rings + // PostGIS gives: 0.30859375 and 0.033203125 with 35/35 rings + + test_one("geos_2", + geos_2[0], geos_2[1], + 1, -1, 138.6923828, + 1, -1, 211.859375); + + test_one("geos_3", + geos_3[0], geos_3[1], + 1, -1, 16211128.5, + 1, -1, 13180420.0); + + test_one("geos_4", + geos_4[0], geos_4[1], + 1, -1, 971.9163115, + 1, -1, 1332.4163115); + test_one("ggl_list_20110306_javier", ggl_list_20110306_javier[0], ggl_list_20110306_javier[1], 1, -1, 71495.3331, @@ -335,6 +365,24 @@ void test_all() 1, 10, 10.03103292, 0, 0, 0); +#if ! defined(BOOST_GEOMETRY_NO_ROBUSTNESS) + test_one("ticket_9081_15", + ticket_9081_15[0], ticket_9081_15[1], + 1, 10, 0.0334529710902111, + 0, 0, 0); +#endif + + test_one("ticket_9081_314", + ticket_9081_314[0], ticket_9081_314[1], + 2, 12, 0.0451236449624935, + 0, 0, 0); + +#if ! defined(BOOST_GEOMETRY_NO_ROBUSTNESS) + test_one("ticket_9563", + ticket_9563[0], ticket_9563[1], + 0, 0, 0, + 6, 24, 20.096189); +#endif // Other combi's { @@ -371,8 +419,6 @@ void test_all() 5, 22, 1.1901714, 5, 27, 1.6701714); } - - // Multi/box (should be moved to multi) { /* Tested with SQL Geometry: @@ -491,8 +537,8 @@ void test_specific() test_one("ggl_list_20120717_volker", ggl_list_20120717_volker[0], ggl_list_20120717_volker[1], - 1, 11, 3370866.2295081965, - 1, 5, 384, 0.01); + 1, 11, 3371540, + 0, 0, 0, 0.001); // output is discarded } diff --git a/test/algorithms/difference_linear_linear.cpp b/test/algorithms/difference_linear_linear.cpp index 66759fcc2..ecbcb438f 100644 --- a/test/algorithms/difference_linear_linear.cpp +++ b/test/algorithms/difference_linear_linear.cpp @@ -18,7 +18,7 @@ #define BOOST_GEOMETRY_DEBUG_SEGMENT_IDENTIFIER #endif -#include +#include #include "test_difference_linear_linear.hpp" diff --git a/test/algorithms/difference_pl_pl.cpp b/test/algorithms/difference_pl_pl.cpp index e18a9ab13..ed3cce984 100644 --- a/test/algorithms/difference_pl_pl.cpp +++ b/test/algorithms/difference_pl_pl.cpp @@ -18,7 +18,7 @@ #define BOOST_GEOMETRY_DEBUG_SEGMENT_IDENTIFIER #endif -#include +#include #include "test_set_ops_pl_pl.hpp" diff --git a/test/algorithms/disjoint.cpp b/test/algorithms/disjoint.cpp index d370ec87d..d765ef952 100644 --- a/test/algorithms/disjoint.cpp +++ b/test/algorithms/disjoint.cpp @@ -23,7 +23,7 @@ #include -#include +#include template diff --git a/test/algorithms/intersection.cpp b/test/algorithms/intersection.cpp index fa5f385fd..8a76473f3 100644 --- a/test/algorithms/intersection.cpp +++ b/test/algorithms/intersection.cpp @@ -15,6 +15,10 @@ #include #include +// If defined, tests are run without rescaling-to-integer or robustness policy +// Test which would fail then are disabled automatically +// #define BOOST_GEOMETRY_NO_ROBUSTNESS + #include #include @@ -162,6 +166,20 @@ void test_areal() // SQL Server gives: 88.1920416352664 // PostGIS gives: 88.19203677911 + test_one("geos_1", + geos_1[0], geos_1[1], + 1, -1, 3461.0214843); + test_one("geos_2", + geos_2[0], geos_2[1], + 0, 0, 0.0); + test_one("geos_3", + geos_3[0], geos_3[1], + 0, -0, 0.0); + test_one("geos_4", + geos_4[0], geos_4[1], + 1, -1, 0.08368849); + + if (! ccw && open) { // Pointcount for ttmath/double (both 5) or float (4) @@ -183,21 +201,18 @@ void test_areal() ggl_list_20110627_phillip[0], ggl_list_20110627_phillip[1], 1, if_typed_tt(6, 5), 11151.6618); -#ifdef _MSC_VER // gcc/linux behaves differently - if (! boost::is_same::value) - { - test_one("ggl_list_20110716_enrico", - ggl_list_20110716_enrico[0], ggl_list_20110716_enrico[1], - 3, - if_typed(21, 20), - 35723.8506317139); - } -#endif + test_one("ggl_list_20110716_enrico", + ggl_list_20110716_enrico[0], ggl_list_20110716_enrico[1], + 3, 16, 35723.8506317139); test_one("ggl_list_20131119_james", ggl_list_20131119_james[0], ggl_list_20131119_james[1], 1, 4, 6.6125873045, 0.1); + test_one("ggl_list_20140223_shalabuda", + ggl_list_20140223_shalabuda[0], ggl_list_20140223_shalabuda[1], + 1, 4, 3.77106); + #if 0 // TODO: fix this testcase, it should give 0 but instead it gives one of the input polygons // Mailed to the Boost.Geometry list on 2014/03/21 by 7415963@gmail.com @@ -206,30 +221,47 @@ void test_areal() 0, 0, 0, 0.1); #endif +#if ! defined(BOOST_GEOMETRY_NO_ROBUSTNESS) test_one("buffer_rt_f", buffer_rt_f[0], buffer_rt_f[1], 1, 4, 0.00029437899183903937, 0.01); +#endif test_one("buffer_rt_g", buffer_rt_g[0], buffer_rt_g[1], 1, 0, 2.914213562373); +#if ! defined(BOOST_GEOMETRY_NO_ROBUSTNESS) test_one("ticket_8254", ticket_8254[0], ticket_8254[1], - 1, 4, 3.63593e-08, 0.01); + 1, 4, 3.6334e-08, 0.01); +#endif test_one("ticket_6958", ticket_6958[0], ticket_6958[1], 1, 4, 4.34355e-05, 0.01); +#if ! defined(BOOST_GEOMETRY_NO_ROBUSTNESS) test_one("ticket_8652", ticket_8652[0], ticket_8652[1], - 1, 4, 0.0003, 0.00001); + 1, 4, 0.0003); +#endif test_one("ticket_8310a", ticket_8310a[0], ticket_8310a[1], - 1, 5, 0.3843747, 0.00001); + 1, 5, 0.3843747); test_one("ticket_8310b", ticket_8310b[0], ticket_8310b[1], - 1, 5, 0.3734379, 0.00001); + 1, 5, 0.3734379); test_one("ticket_8310c", ticket_8310c[0], ticket_8310c[1], - 1, 5, 0.4689541, 0.00001); + 1, 5, 0.4689541); + test_one("ticket_9081_15", + ticket_9081_15[0], ticket_9081_15[1], + 1, 4, 0.0068895780745301394); + +#if ! defined(BOOST_GEOMETRY_NO_ROBUSTNESS) + test_one("ticket_9563", ticket_9563[0], ticket_9563[1], + 1, 8, 129.90381); +#endif + +#if ! defined(BOOST_GEOMETRY_NO_ROBUSTNESS) test_one("buffer_mp1", buffer_mp1[0], buffer_mp1[1], 1, 31, 2.271707796); +#endif test_one("buffer_mp2", buffer_mp2[0], buffer_mp2[1], 1, 29, 0.457126); @@ -303,7 +335,6 @@ void test_boxes(std::string const& wkt1, std::string const& wkt2, double expecte } } - template void test_point_output() { @@ -369,7 +400,6 @@ void test_areal_linear() } - template void test_all() { @@ -385,20 +415,25 @@ void test_all() std::string clip = "box(2 2,8 8)"; test_areal_linear(); +#if ! defined(BOOST_GEOMETRY_TEST_ONLY_ONE_TYPE) test_areal_linear(); test_areal_linear(); test_areal_linear(); +#endif // Test polygons clockwise and counter clockwise test_areal(); +#if ! defined(BOOST_GEOMETRY_TEST_ONLY_ONE_TYPE) test_areal(); test_areal(); test_areal(); - +#endif test_areal_clip(); +#if ! defined(BOOST_GEOMETRY_TEST_ONLY_ONE_TYPE) test_areal_clip(); +#endif #if defined(TEST_FAIL_DIFFERENT_ORIENTATIONS) // Should NOT compile @@ -526,6 +561,34 @@ void test_rational() } +template +void test_boxes_per_d(P const& min1, P const& max1, P const& min2, P const& max2, bool expected_result) +{ + typedef bg::model::box

box; + + box box_out; + bool detected = bg::intersection(box(min1, max1), box(min2, max2), box_out); + + BOOST_CHECK_EQUAL(detected, expected_result); + if ( detected && expected_result ) + { + BOOST_CHECK( bg::equals(box_out, box(min2,max1)) ); + } +} + +template +void test_boxes_nd() +{ + typedef bg::model::point p1; + typedef bg::model::point p2; + typedef bg::model::point p3; + + test_boxes_per_d(p1(0), p1(5), p1(3), p1(6), true); + test_boxes_per_d(p2(0,0), p2(5,5), p2(3,3), p2(6,6), true); + test_boxes_per_d(p3(0,0,0), p3(5,5,5), p3(3,3,3), p3(6,6,6), true); +} + + int test_main(int, char* []) { test_all >(); @@ -542,7 +605,11 @@ int test_main(int, char* []) test_exception >(); test_pointer_version(); +#if ! defined(BOOST_GEOMETRY_RESCALE_TO_ROBUST) test_rational > >(); +#endif + + test_boxes_nd(); return 0; } diff --git a/test/algorithms/intersection_linear_linear.cpp b/test/algorithms/intersection_linear_linear.cpp index 695f8285c..930cb0f41 100644 --- a/test/algorithms/intersection_linear_linear.cpp +++ b/test/algorithms/intersection_linear_linear.cpp @@ -18,7 +18,7 @@ #define BOOST_GEOMETRY_DEBUG_SEGMENT_IDENTIFIER #endif -#include +#include #include "test_intersection_linear_linear.hpp" diff --git a/test/algorithms/intersection_pl_pl.cpp b/test/algorithms/intersection_pl_pl.cpp index 22d906d19..a405f558a 100644 --- a/test/algorithms/intersection_pl_pl.cpp +++ b/test/algorithms/intersection_pl_pl.cpp @@ -18,7 +18,7 @@ #define BOOST_GEOMETRY_DEBUG_SEGMENT_IDENTIFIER #endif -#include +#include #include "test_set_ops_pl_pl.hpp" diff --git a/test/algorithms/intersects.cpp b/test/algorithms/intersects.cpp index 24df6b9e9..8477d7907 100644 --- a/test/algorithms/intersects.cpp +++ b/test/algorithms/intersects.cpp @@ -306,7 +306,9 @@ int test_main( int , char* [] ) test_all >(); test_additional >(); +#if ! defined(BOOST_GEOMETRY_RESCALE_TO_ROBUST) test_all > >(); +#endif #if defined(HAVE_TTMATH) test_all >(); diff --git a/test/algorithms/overlay/Jamfile.v2 b/test/algorithms/overlay/Jamfile.v2 index a97c6b256..c4c4471b4 100644 --- a/test/algorithms/overlay/Jamfile.v2 +++ b/test/algorithms/overlay/Jamfile.v2 @@ -24,5 +24,5 @@ test-suite boost-geometry-algorithms-overlay [ run relative_order.cpp ] [ run select_rings.cpp ] [ run self_intersection_points.cpp ] - [ run traverse.cpp ] + [ run traverse.cpp : : : BOOST_GEOMETRY_TEST_ONLY_ONE_TYPE ] ; diff --git a/test/algorithms/overlay/assemble.cpp b/test/algorithms/overlay/assemble.cpp index f63e3b5ac..262f32f98 100644 --- a/test/algorithms/overlay/assemble.cpp +++ b/test/algorithms/overlay/assemble.cpp @@ -22,6 +22,7 @@ #include #include #include +#include #include #include @@ -40,12 +41,18 @@ template inline void test_assemble(std::string const& id, Geometry const& p, Geometry const& q, char operation = 'i') { + typedef typename bg::point_type::type point_type; + typedef typename bg::rescale_policy_type::type + rescale_policy_type; + rescale_policy_type rescale_policy + = bg::get_rescale_policy(p, q); + std::vector u, i, d1, d2; bg::detail::union_::union_insert(p, q, std::back_inserter(u)); bg::detail::intersection::intersection_insert(p, q, std::back_inserter(i)); - bg::detail::difference::difference_insert(p, q, std::back_inserter(d1)); - bg::detail::difference::difference_insert(q, p, std::back_inserter(d2)); + bg::detail::difference::difference_insert(p, q, rescale_policy, std::back_inserter(d1)); + bg::detail::difference::difference_insert(q, p, rescale_policy, std::back_inserter(d2)); if (operation == 'i') { @@ -72,21 +79,13 @@ inline void test_assemble(std::string const& id, Geometry const& p, Geometry con area_d2 += bg::area(g); } - type diff = (area_p + area_q) - area_u - area_i; type diff_d1 = (area_u - area_q) - area_d1; type diff_d2 = (area_u - area_p) - area_d2; - BOOST_CHECK_CLOSE(diff, 0.0, 0.001); - - // Gives small deviations on gcc: - // difference{0.001%} between diff_d1{1.1102230246251565e-016} and 0.0{0} exceeds 0.001% - //BOOST_CHECK_CLOSE(diff_d1, 0.0, 0.001); - //BOOST_CHECK_CLOSE(diff_d2, 0.0, 0.001); - bool ok = abs(diff) < 0.001 - || abs(diff_d1) < 0.001 - || abs(diff_d2) < 0.001; + && abs(diff_d1) < 0.001 + && abs(diff_d2) < 0.001; BOOST_CHECK_MESSAGE(ok, id << " diff: " diff --git a/test/algorithms/overlay/ccw_traverse.cpp b/test/algorithms/overlay/ccw_traverse.cpp index f66147c91..944f3937c 100644 --- a/test/algorithms/overlay/ccw_traverse.cpp +++ b/test/algorithms/overlay/ccw_traverse.cpp @@ -7,6 +7,8 @@ // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) +#define BOOST_GEOMETRY_DEFINE_STREAM_OPERATOR_SEGMENT_RATIO + #include #include #include @@ -25,6 +27,7 @@ #endif #include +#include #include @@ -42,19 +45,27 @@ inline typename bg::coordinate_type::type intersect(Geometry1 const& >::type side_strategy_type; + typedef typename bg::point_type::type point_type; + + typedef typename bg::rescale_policy_type::type + rescale_policy_type; + + rescale_policy_type rescale_policy + = bg::get_rescale_policy(g1, g2); + typedef bg::detail::overlay::traversal_turn_info - < - typename bg::point_type::type - > turn_info; + < + point_type, + typename bg::segment_ratio_type::type + > turn_info; std::vector turns; bg::detail::get_turns::no_interrupt_policy policy; - bg::detail::no_rescale_policy rescale_policy; bg::get_turns < rev::value, rev::value, - bg::detail::overlay::calculate_distance_policy + bg::detail::overlay::assign_null_policy >(g1, g2, rescale_policy, turns, policy); bg::enrich_intersection_points::value, rev::value >(turns, bg::detail::overlay::operation_intersection, @@ -161,8 +172,8 @@ inline typename bg::coordinate_type::type intersect(Geometry1 const& out << std::setprecision(3) - << "dist: " << turn.operations[0].enriched.distance - << " / " << turn.operations[1].enriched.distance + << "dist: " << turn.operations[0].fraction + << " / " << turn.operations[1].fraction << std::endl; offsets[p] += lineheight; diff --git a/test/algorithms/overlay/get_turn_info.cpp b/test/algorithms/overlay/get_turn_info.cpp index a58fcadaf..1d2c4daa6 100644 --- a/test/algorithms/overlay/get_turn_info.cpp +++ b/test/algorithms/overlay/get_turn_info.cpp @@ -42,17 +42,23 @@ void test_with_point(std::string const& caseid, P qj = bg::make

(qj_x, qj_y); P qk = bg::make

(qk_x, qk_y); + typedef typename bg::detail::no_rescale_policy rescale_policy_type; - typedef bg::detail::overlay::turn_info

turn_info; + typedef bg::detail::overlay::turn_info + < + P, + typename bg::segment_ratio_type::type + > turn_info; typedef std::vector tp_vector; turn_info model; tp_vector info; + rescale_policy_type rescale_policy; bg::detail::overlay::get_turn_info < bg::detail::overlay::assign_null_policy >::apply(pi, pj, pk, qi, qj, qk, false, false, false, false, // dummy parameters - model, bg::detail::no_rescale_policy(), std::back_inserter(info)); + model, rescale_policy, std::back_inserter(info)); if (info.size() == 0) diff --git a/test/algorithms/overlay/get_turns.cpp b/test/algorithms/overlay/get_turns.cpp index f8c38600a..c9a45521b 100644 --- a/test/algorithms/overlay/get_turns.cpp +++ b/test/algorithms/overlay/get_turns.cpp @@ -24,6 +24,7 @@ #include #include +#include #include @@ -42,8 +43,8 @@ // To test that "get_turns" can be called using additional information -template -struct my_turn_op : public bg::detail::overlay::turn_operation +template +struct my_turn_op : public bg::detail::overlay::turn_operation { }; @@ -57,14 +58,23 @@ struct test_get_turns std::size_t expected_count, G1 const& g1, G2 const& g2, double precision) { - typedef bg::detail::overlay::turn_info + typedef typename bg::point_type::type point_type; + typedef typename bg::rescale_policy_type::type + rescale_policy_type; + + rescale_policy_type rescale_policy + = bg::get_rescale_policy(g1, g2); + + typedef bg::detail::overlay::turn_info < - typename bg::point_type::type + point_type, + typename bg::segment_ratio_type::type > turn_info; std::vector turns; + bg::detail::get_turns::no_interrupt_policy policy; - bg::get_turns(g1, g2, bg::detail::no_rescale_policy(), turns, policy); + bg::get_turns(g1, g2, rescale_policy, turns, policy); BOOST_CHECK_MESSAGE( expected_count == boost::size(turns), diff --git a/test/algorithms/overlay/get_turns_linear_areal.cpp b/test/algorithms/overlay/get_turns_linear_areal.cpp index c807fdfde..804516afb 100644 --- a/test/algorithms/overlay/get_turns_linear_areal.cpp +++ b/test/algorithms/overlay/get_turns_linear_areal.cpp @@ -75,6 +75,62 @@ void test_all() test_geometry("LINESTRING(10 1,10 5,2 8)", "POLYGON((0 0,0 10,10 10,10 0,0 0),(10 5,2 8,2 2,10 5))", expected("mcu")("mic")("tcc")("txu")); + + // SPIKE - NON-ENDPOINT - NON-OPPOSITE + + // spike - neq eq + test_geometry("LINESTRING(2 2,4 4,1 1)", "POLYGON((0 0,4 4,6 3,6 0,0 0))", + expected("mcc")("txu")("tcu")("mxc")); + // spike - eq eq + test_geometry("LINESTRING(0 0,4 4,1 1)", "POLYGON((0 0,4 4,6 3,6 0,0 0))", + expected("tcc")("txu")("tcu")("mxc")); + // spike - eq neq + test_geometry("LINESTRING(0 0,3 3,1 1)", "POLYGON((0 0,4 4,6 3,6 0,0 0))", + expected("tcc")("mxu")("mcu")("mxc")); + // spike - neq neq + test_geometry("LINESTRING(1 1,3 3,2 2)", "POLYGON((0 0,4 4,6 3,6 0,0 0))", + expected("mcc")("mxu")("mcu")("mxc")); + // spike - out neq + test_geometry("LINESTRING(0 0,3 3,2 2)", "POLYGON((1 1,4 4,6 3,6 0,1 1))", + expected("mcc")("mxu")("mcu")("mxc")); + // spike - out eq + test_geometry("LINESTRING(0 0,4 4,2 2)", "POLYGON((1 1,4 4,6 3,6 0,1 1))", + expected("mcc")("txu")("tcu")("mxc")); + // spike - out out/eq + test_geometry("LINESTRING(0 0,4 4,2 2)", "POLYGON((1 0,4 4,6 3,1 0))", + expected("tuu")); + test_geometry("LINESTRING(0 0,4 4,2 2)", "POLYGON((0 1,4 4,6 3,6 0,-1 -1,0 1))", + expected("tiu")); + // spike - out out/neq + test_geometry("LINESTRING(0 0,4 4,2 2)", "POLYGON((4 0,4 5,6 3,4 0))", + expected("muu")); + test_geometry("LINESTRING(0 0,4 4,2 2)", "POLYGON((0 4,5 4,6 3,6 0,-1 -1,0 4))", + expected("miu")); + + test_geometry("LINESTRING(0 1,1 1,0 1)", "POLYGON((0 0,3 3,3 0,0 0))", + expected("muu")); + test_geometry("LINESTRING(0 1,3 3,0 1)", "POLYGON((0 0,3 3,3 0,0 0))", + expected("tuu")); + test_geometry("LINESTRING(0 1,0 0,0 1)", "POLYGON((0 0,3 3,3 0,0 0))", + expected("tuu")); + + // SPIKE - NON-ENDPOINT - OPPOSITE + + // opposite - eq eq + test_geometry("LINESTRING(6 6,4 4,0 0,2 2)", "POLYGON((-1 -1,0 0,4 4,6 3,-1 -1))", + expected("tcu")("txc")("tcc")("mxu")); + // opposite - neq eq + test_geometry("LINESTRING(6 6,4 4,0 0,2 2)", "POLYGON((-1 -1,0 0,5 5,6 3,-1 -1))", + expected("mcu")("txc")("tcc")("mxu")); + // opposite - eq, neq + test_geometry("LINESTRING(6 6,4 4,0 0,2 2)", "POLYGON((-2 -2,-1 -1,4 4,6 3,-2 -2))", + expected("tcu")("mxc")("mcc")("mxu")); + // opposite - neq neq + test_geometry("LINESTRING(6 6,4 4,0 0,2 2)", "POLYGON((-2 -2,-1 -1,3 3,6 3,-2 -2))", + expected("mcu")("mxc")("mcc")("mxu")); + // opposite - neq neq + test_geometry("LINESTRING(6 6,4 4,0 0,2 2)", "POLYGON((-2 -2,-1 -1,3 3,5 5,6 3,-2 -2))", + expected("mcu")("mxc")("mcc")("mxu")); } int test_main(int, char* []) diff --git a/test/algorithms/overlay/get_turns_linear_linear.cpp b/test/algorithms/overlay/get_turns_linear_linear.cpp index fdafbdae2..30760b3bc 100644 --- a/test/algorithms/overlay/get_turns_linear_linear.cpp +++ b/test/algorithms/overlay/get_turns_linear_linear.cpp @@ -109,6 +109,114 @@ void test_all() test_geometry("LINESTRING(1 0,7 0,8 1)", "LINESTRING(0 0,10 0,10 10,5 0,4 1)", expected("mii")("muu")("muu")); + // SPIKE - NON-ENDPOINT - NON-OPPOSITE + + // spike - neq eq + test_geometry("LINESTRING(2 2,4 4,1 1)", "LINESTRING(0 0,4 4,6 3)", + expected("mii")("txu")("tiu")("mxi")); + // spike - eq eq + test_geometry("LINESTRING(0 0,4 4,1 1)", "LINESTRING(0 0,4 4,6 3)", + expected("tii")("txu")("tiu")("mxi")); + // spike - eq neq + test_geometry("LINESTRING(0 0,3 3,1 1)", "LINESTRING(0 0,4 4,6 3)", + expected("tii")("mxu")("miu")("mxi")); + // spike - neq neq + test_geometry("LINESTRING(1 1,3 3,2 2)", "LINESTRING(0 0,4 4,6 3)", + expected("mii")("mxu")("miu")("mxi")); + // spike - out neq + test_geometry("LINESTRING(0 0,3 3,2 2)", "LINESTRING(1 1,4 4,6 3)", + expected("mii")("mxu")("miu")("mxi")); + // spike - out eq + test_geometry("LINESTRING(0 0,4 4,2 2)", "LINESTRING(1 1,4 4,6 3)", + expected("mii")("txu")("tiu")("mxi")); + // spike - out out/eq + test_geometry("LINESTRING(0 0,4 4,2 2)", "LINESTRING(1 0,4 4,6 3)", + expected("tuu")); + test_geometry("LINESTRING(0 0,4 4,2 2)", "LINESTRING(0 1,4 4,6 3)", + expected("tuu")); + // spike - out out/neq + test_geometry("LINESTRING(0 0,4 4,2 2)", "LINESTRING(4 0,4 5,6 3)", + expected("muu")); + test_geometry("LINESTRING(0 0,4 4,2 2)", "LINESTRING(0 4,5 4,6 3)", + expected("muu")); + + // SPIKE - NON-ENDPOINT - OPPOSITE + + // opposite - eq eq + test_geometry("LINESTRING(6 6,4 4,0 0,2 2)", "LINESTRING(-1 -1,0 0,4 4,6 3)", + expected("tiu")("txi")("tii")("mxu")); + test_geometry("LINESTRING(-1 -1,0 0,4 4,6 3)", "LINESTRING(6 6,4 4,0 0,2 2)", + expected("tui")("tix")("tii")("mux")); + // opposite - neq eq + test_geometry("LINESTRING(6 6,4 4,0 0,2 2)", "LINESTRING(-1 -1,0 0,5 5,6 3)", + expected("miu")("txi")("tii")("mxu")); + // opposite - eq neq + test_geometry("LINESTRING(6 6,4 4,0 0,2 2)", "LINESTRING(-2 -2,-1 -1,4 4,6 3)", + expected("tiu")("mxi")("mii")("mxu")); + // opposite - neq neq + test_geometry("LINESTRING(6 6,4 4,0 0,2 2)", "LINESTRING(-2 -2,-1 -1,3 3,6 3)", + expected("miu")("mxi")("mii")("mxu")); + // opposite - neq neq + test_geometry("LINESTRING(6 6,4 4,0 0,2 2)", "LINESTRING(-2 -2,-1 -1,3 3,5 5,6 3)", + expected("miu")("mxi")("mii")("mxu")); + // opposite - neq eq + test_geometry("LINESTRING(6 3,3 3,0 0)", "LINESTRING(0 0,2 2,3 3,1 1)", + expected("txi")("tix")("tii")("mux")); + + // SPIKE - ENDPOINT - NON-OPPOSITE + + // spike - neq eq + test_geometry("LINESTRING(2 2,4 4,1 1)", "LINESTRING(0 0,4 4)", + expected("mii")("txx")("tix")("mxi")); + test_geometry("LINESTRING(2 2,4 4,1 1)", "LINESTRING(4 4,0 0)", + expected("miu")("txi")("tii")("mxu")); + // spike - eq eq + test_geometry("LINESTRING(0 0,4 4,1 1)", "LINESTRING(0 0,4 4)", + expected("tii")("txx")("tix")("mxi")); + test_geometry("LINESTRING(0 0,4 4,1 1)", "LINESTRING(4 4,0 0)", + expected("tix")("txi")("tii")("mxu")); + // spike - eq neq + test_geometry("LINESTRING(0 0,3 3,1 1)", "LINESTRING(0 0,4 4)", + expected("tii")("mxu")("miu")("mxi")); + test_geometry("LINESTRING(0 0,3 3,1 1)", "LINESTRING(4 4,0 0)", + expected("tix")("mxi")("mii")("mxu")); + // spike - neq neq + test_geometry("LINESTRING(1 1,3 3,2 2)", "LINESTRING(0 0,4 4)", + expected("mii")("mxu")("miu")("mxi")); + test_geometry("LINESTRING(1 1,3 3,2 2)", "LINESTRING(4 4,0 0)", + expected("miu")("mxi")("mii")("mxu")); + // spike - out neq + test_geometry("LINESTRING(0 0,3 3,2 2)", "LINESTRING(1 1,4 4)", + expected("mii")("mxu")("miu")("mxi")); + test_geometry("LINESTRING(0 0,3 3,2 2)", "LINESTRING(4 4,1 1)", + expected("mix")("mxi")("mii")("mxu")); + // spike - out eq + test_geometry("LINESTRING(0 0,4 4,2 2)", "LINESTRING(1 1,4 4)", + expected("mii")("txx")("tix")("mxi")); + test_geometry("LINESTRING(0 0,4 4,2 2)", "LINESTRING(4 4,1 1)", + expected("mix")("txi")("tii")("mxu")); + // spike - out out/eq + test_geometry("LINESTRING(0 0,4 4,2 2)", "LINESTRING(1 0,4 4)", + expected("tux")); + test_geometry("LINESTRING(0 0,4 4,2 2)", "LINESTRING(0 1,4 4)", + expected("tux")); + // spike - out out/neq + test_geometry("LINESTRING(0 0,4 4,2 2)", "LINESTRING(4 0,4 5)", + expected("muu")); + test_geometry("LINESTRING(0 0,4 4,2 2)", "LINESTRING(0 4,5 4)", + expected("muu")); + + // TODO: + //test_geometry("LINESTRING(0 0,2 0,1 0)", "LINESTRING(0 1,0 0,2 0)", "1FF00F102"); + //test_geometry("LINESTRING(2 0,0 0,1 0)", "LINESTRING(0 1,0 0,2 0)", "1FF00F102"); + + //test_geometry("LINESTRING(0 0,3 3,1 1)", "LINESTRING(3 0,3 3,3 1)", "0F1FF0102"); + //test_geometry("LINESTRING(0 0,3 3,1 1)", "LINESTRING(2 0,2 3,2 1)", "0F1FF0102"); + //test_geometry("LINESTRING(0 0,3 3,1 1)", "LINESTRING(2 0,2 2,2 1)", "0F1FF0102"); + + //test_geometry("LINESTRING(0 0,2 2,3 3,4 4)", "LINESTRING(0 0,1 1,4 4)", "1FFF0FFF2"); + + //if ( boost::is_same::value ) //{ // to_svg("LINESTRING(0 0,1 0,2 0,2.5 0,3 1)", "LINESTRING(0 0,2 0,2.5 0,3 1)", "test11.svg"); @@ -129,6 +237,14 @@ void test_all() test_geometry("LINESTRING(2 2,5 -1,15 2,18 0,20 0)", "LINESTRING(30 0,19 0,18 0,0 0)", expected("iuu")("iuu")("tiu")("mxi")); + + test_geometry("MULTILINESTRING((0 0,10 0,5 0))", + "MULTILINESTRING((1 0,8 0,4 0))", + expected("mii")("mix")("mux")("mui")("mix")("mii")("mxu")("mxi")); + + /*test_geometry("MULTILINESTRING((0 0,10 0,5 0))", + "MULTILINESTRING((1 0,8 0,4 0),(2 0,9 0,5 0))", + expected("mii")("ccc")("ccc")("txx"));*/ } int test_main(int, char* []) diff --git a/test/algorithms/overlay/overlay_cases.hpp b/test/algorithms/overlay/overlay_cases.hpp index fa6647a02..c2b99bc3b 100644 --- a/test/algorithms/overlay/overlay_cases.hpp +++ b/test/algorithms/overlay/overlay_cases.hpp @@ -537,6 +537,12 @@ static std::string ggl_list_20131119_james[2] = "POLYGON((4 4,4 8,12 8,12 4,4 4))" }; +static std::string ggl_list_20140223_shalabuda[2] = +{ + "POLYGON((-7.1621621621621605058294335322 43.228378378378366164724866394, -4.52438675915238786018335304107 30.5670564439314631499655661173, -4.16280147451538873326626344351 27.5407467090450168711868172977, -6.19047619047618891130468909978 36.7666666666666515084216371179, -7.1621621621621605058294335322 43.228378378378366164724866394))", + "POLYGON((-8.16216216216216139400785323232 49.8783783783783789544941100758, -3.16280147451538873326626344351 44.228378378378366164724866394, 1 -10.5499999999999971578290569596, -1 2.25, -8.16216216216216139400785323232 49.8783783783783789544941100758))", +}; + static std::string ggl_list_20140321_7415963[2] = { @@ -546,7 +552,7 @@ static std::string ggl_list_20140321_7415963[2] = // GEOS "TestOverlay" test. // Note that the first one WAS invalid and is made valid using SQL Server 2008 Spatial MakeValid() function -static std::string geos_1_test_overlay[2] = +static std::string geos_1[2] = { // Original: POLYGON((5417148.108 5658342.603,5417139.016 5658338.009,5417126.791 5658331.833,5417116.292 5658327.518,5417112.871 5658325.598,5417110.25 5658324.127,5417106.071 5658321.781,5417104.226 5658320.745,5417093.266 5658315.008,5417091.265 5658313.961,5417085.335 5658310.857,5417060.44 5658326.26,5417064.68 5658327.52,5417088.83 5658336.46,5417088.52 5658337.31,5417102.92 5658342.65,5417103.26 5658341.83,5417111.76 5658345.51,5417121.662 5658349.583,5417121.878 5658349.672,5417125.217 5658351.119,5417131.761 5658353.388,5417137.589 5658356.276,5417142.166 5658359.67,5417146.599 5658364.988,5417151.395 5658370.641,5417150.853 5658371.392,5417152.59741167 5658373.52811061,5417154.92 5658376.37,5417155.18955743 5658376.89699992,5417154.919 5658376.371,5417155.814 5658378.111,5417157.051 5658380.297,5417158.004 5658382.304,5417159.014 5658384.47,5417159.775 5658386.619,5417160.629 5658389.278,5417161.5 5658399.49,5417160.773 5658404.194,5417159.41 5658413.02,5417158.853 5658414.442,5417153.671 5658427.659,5417153.67051161 5658427.6586943,5417153.67 5658427.66,5417152.73 5658427.07,5417149.993 5658436.599,5417148.81 5658439.42,5417149.233 5658439.67,5417148.36 5658440.81,5417146.41 5658446.6,5417144.321 5658453.127,5417144.32092232 5658453.13043826,5417154.59 5658458.01,5417154.99551047 5658455.8409905,5417155.446 5658453.413,5417157.23981414 5658448.75748237,5417157.22660892 5658448.57861162,5417157.22660849 5658448.57860592,5417157.22660865 5658448.57860812,5417157.128 5658447.265,5417157.64950997 5658446.06368023,5417157.64950961 5658446.06368108,5417158.314 5658444.533,5417172.322 5658417.957,5417174.99 5658418.57,5417175.23 5658417.74,5417176.696 5658412.61,5417177.875 5658408.488,5417178.76 5658405.39,5417178.1 5658393.55,5417178.08 5658393.36,5417177.11 5658384.95,5417178.151 5658384.915,5417178.14836289 5658384.91508866,5417178.12 5658384.83,5417177.91415246 5658383.81114117,5417176.927 5658378.944,5417176.603 5658377.341,5417176.73975922 5658378.01762048,5417176.6 5658377.34,5417176.51210558 5658376.89535766,5417176.428 5658376.483,5417175.235 5658370.602,5417171.577 5658362.886,5417170.762 5658360.107,5417168.522 5658357.989,5417166.042 5658355.047,5417164.137 5658352.264,5417162.642 5658351.593,5417160.702 5658350.843,5417160.05417889 5658350.5823586,5417158.82 5658350.09,5417158.82103105 5658350.0862195,5417159.50373263 5658350.36089455,5417158.818 5658350.085,5417159.055 5658349.214,5417155.754 5658347.679,5417156.78066321 5658348.15640928,5417155.7525011 5658347.6811561,5417155.161 5658348.532,5417149.028 5658343.237,5417152.26877967 5658346.03496647,5417149.03 5658343.24,5417148.78133339 5658343.06701453,5417148.108 5658342.603)) "POLYGON((5417085.33499 5658310.85699,5417060.44 5658326.26001,5417064.67999 5658327.52002,5417088.82999 5658336.46002,5417088.51999 5658337.31,5417102.92001 5658342.65002,5417103.26001 5658341.83002,5417111.76001 5658345.51001,5417121.66199 5658349.58301,5417121.87799 5658349.672,5417125.21701 5658351.11902,5417131.76099 5658353.388,5417137.58899 5658356.276,5417142.16599 5658359.66998,5417146.599 5658364.98798,5417151.39499 5658370.64099,5417150.853 5658371.39203,5417152.59741 5658373.52814,5417154.92001 5658376.37,5417155.18806 5658376.89407,5417155.814 5658378.11102,5417157.05099 5658380.297,5417158.004 5658382.30402,5417159.01401 5658384.46997,5417159.77499 5658386.61902,5417160.629 5658389.27802,5417161.5 5658399.48999,5417160.77301 5658404.19397,5417159.41 5658413.02002,5417158.853 5658414.44202,5417153.67099 5658427.659,5417153.6705 5658427.65869,5417153.67001 5658427.65997,5417152.73001 5658427.07001,5417149.99301 5658436.599,5417148.81 5658439.41998,5417149.233 5658439.66998,5417148.35999 5658440.81,5417146.41 5658446.59998,5417144.32101 5658453.12701,5417144.32092 5658453.13043,5417154.59 5658458.01001,5417154.99551 5658455.841,5417155.44601 5658453.41302,5417157.23981 5658448.75751,5417157.22662 5658448.57861,5417157.12799 5658447.26501,5417157.64951 5658446.06366,5417158.314 5658444.53302,5417172.32199 5658417.95697,5417174.98999 5658418.57001,5417175.23001 5658417.73999,5417176.69601 5658412.60999,5417177.875 5658408.48798,5417178.76001 5658405.39001,5417178.10001 5658393.54999,5417178.07999 5658393.35999,5417177.10999 5658384.95001,5417178.14837 5658384.91507,5417178.12 5658384.83002,5417177.91415 5658383.81116,5417176.927 5658378.94397,5417176.603 5658377.341,5417176.73975 5658378.01764,5417176.60001 5658377.34003,5417176.51212 5658376.89539,5417176.42801 5658376.48297,5417175.23499 5658370.60199,5417171.577 5658362.88599,5417170.76199 5658360.10699,5417168.522 5658357.98901,5417166.04199 5658355.047,5417164.13699 5658352.26398,5417162.642 5658351.59302,5417160.702 5658350.84302,5417160.05417 5658350.58234,5417158.82001 5658350.09003,5417158.82104 5658350.08625,5417158.81799 5658350.08502,5417159.05499 5658349.21399,5417155.754 5658347.67902,5417156.78067 5658348.15643,5417155.7525 5658347.68115,5417155.16101 5658348.53198,5417149.02802 5658343.237,5417152.26877 5658346.03497,5417149.03 5658343.23999,5417148.78134 5658343.06702,5417148.108 5658342.60303,5417139.01599 5658338.00897,5417126.79099 5658331.83301,5417116.29199 5658327.51801,5417112.871 5658325.59802,5417110.25 5658324.12701,5417106.07101 5658321.78101,5417104.22601 5658320.745,5417093.26599 5658315.008,5417091.26501 5658313.961,5417085.33499 5658310.85699))", @@ -623,6 +629,14 @@ static std::string ticket_8652[2] = "POLYGON((0.02 -2.77556e-17, 0.05 0.02, 0.05 -2.77556e-17, 0.02 -2.77556e-17))" }; +static std::string ticket_9756[2] = +{ + // NOTE: these polygons are not closed. That is the reason the union failed for the library user. + // the unit test calls "correct" so this test is not a problem for the library. The ticket is closed as invalid. + "POLYGON((440820.110024126 4047009.80267429, 440806.545727707 4046942.39533656, 440797.171880196 4046895.8425726, 440804.202135392 4046888.73092639, 440813.573458131 4046935.27114371, 440827.140279322 4047002.69102807))", + "POLYGON((440855.857887967 4046932.1248641, 440813.740724389 4046942.21109839, 440806.376538684 4046935.44583646, 440848.493702262 4046925.35960217))", +}; + static std::string ggl_list_20120229_volker[3] = { "POLYGON((1716 1554,2076 2250,2436 2352,2796 1248,3156 2484,3516 2688,3516 2688,3156 2484,2796 1248,2436 2352,2076 2250, 1716 1554))", @@ -757,10 +771,30 @@ static std::string collinear_opposite_straight[2] = "POLYGON((6 6,6 9,7 10,7 7,7 5,6 6))" }; +static std::string ticket_9081_15[2] = + { + "POLYGON((0.6733025292237357 0.1677633042748119,0.4903155795903966 0.2232818375071136,0.4271130992272586 0.3070047723327289,0.786116554767879 0.3837165261542967,0.6733025292237357 0.1677633042748119))", + "POLYGON((0.6331466887796691 0.351029969741811,0.7496863892358909 0.3759321389935647,0.7688695634785153 0.35070163001261,0.7290398105918782 0.2744578879686089,0.6331466887796691 0.351029969741811))" + }; + +static std::string ticket_9081_314[2] = + { + "POLYGON((0.4397162028773298 0.5045841729755439,0.8281201612335258 0.8974555101699454,0.7367863490883197 0.2443919592743702,0.4397162028773298 0.5045841729755439))", + "POLYGON((0.5414573257656662 0.6074955108670699,0.5789048944501695 0.6005510671998147,0.6254781598681494 0.5392960142449524,0.7838704066548215 0.5810567836448409,0.7367863490883197 0.2443919592743702,0.4522347054548293 0.4936197023297791,0.4539963238827925 0.4940841246816053,0.4402150043376781 0.5050887115944368,0.5414573257656662 0.6074955108670699))" + }; + static std::string ticket_9081_6690[2] = { "POLYGON((0.5489109414010371 0.5774835110050927,0.4099611282054447 0.4644351568071598,0.4294011278595494 0.4843224236729239,0.4205359995313906 0.5115225580860201,0.4441572412013468 0.5184999851878852,0.5489109414010371 0.5774835110050927))", "POLYGON((0.3984249865018206 0.4526335964808558,0.3621206996557855 0.4602288471829723,0.4183516736935784 0.4730187483833363,0.4099611282054451 0.4644351568071601,0.3984249865018206 0.4526335964808558))" }; +static std::string ticket_9563[2] = + { + "POLYGON((16.4030230586813990 21.4147098480789640, 17.3451877762964380 14.8677773110138890, 11.9421647176150360 6.4530674629349205, 5.5969769413186015 4.5852901519210345, 4.6548122237035621 11.1322226889861170, 10.0578352823849610 19.5469325370650790, 16.4030230586813990 21.4147098480789640, 16.4030230586813990 21.4147098480789640))", + "POLYGON((16.4030230586814020 21.414709848078967, 17.7828326880709360 18.936596729241124, 17.3451877762964410 14.867777311013885, 15.2073549240394820 10.298488470659295, 11.9421647176150340 6.4530674629349125, 8.4245222359685457 4.3618917414181650, 5.5969769413185944 4.5852901519210292, 4.2171673119290620 7.0634032707588670, 4.6548122237035567 11.132222688986115, 6.7926450759605128 15.701511529340699, 10.0578352823849570 19.546932537065082, 13.5754777640314510 21.638108258581831, 16.4030230586814020 21.414709848078967))" + }; + + + #endif // BOOST_GEOMETRY_TEST_OVERLAY_CASES_HPP diff --git a/test/algorithms/overlay/robustness/random_ellipses_stars.cpp b/test/algorithms/overlay/robustness/random_ellipses_stars.cpp index 2dca58bbc..2584aeea3 100644 --- a/test/algorithms/overlay/robustness/random_ellipses_stars.cpp +++ b/test/algorithms/overlay/robustness/random_ellipses_stars.cpp @@ -175,6 +175,7 @@ void test_all(std::string const& type, int seed, int count, p_q_settings setting } else if (type == "double") { + settings.tolerance = 1.0e-4; test_type(seed, count, settings); } #if defined(HAVE_TTMATH) diff --git a/test/algorithms/overlay/robustness/ticket_9081.cpp b/test/algorithms/overlay/robustness/ticket_9081.cpp index b56fbe9c6..9c2f81597 100644 --- a/test/algorithms/overlay/robustness/ticket_9081.cpp +++ b/test/algorithms/overlay/robustness/ticket_9081.cpp @@ -1,5 +1,4 @@ -// Boost.Geometry (aka GGL, Generic Geometry Library) -// Robustness Test +// Boost.Geometry (aka GGL, Generic Geometry Library) // Robustness Test // Copyright (c) 2013 Barend Gehrels, Amsterdam, the Netherlands. @@ -10,6 +9,7 @@ // Adapted from: the attachment of ticket 9081 #define CHECK_SELF_INTERSECTIONS +#define LIST_WKT #include #include @@ -69,14 +69,16 @@ inline void debug_with_svg(int index, char method, Geometry const& a, Geometry c std::ostringstream out; out << headera << std::endl << headerb; - mapper.text(boost::geometry::return_centroid(a), out.str(), - "fill:rgb(0,0,0);font-family:Arial;font-size:10px"); + mapper.map(boost::geometry::return_centroid(a), "fill:rgb(152,204,0);stroke:rgb(153,204,0);stroke-width:0.1", 3); + mapper.map(boost::geometry::return_centroid(b), "fill:rgb(51,51,153);stroke:rgb(153,204,0);stroke-width:0.1", 3); + mapper.text(boost::geometry::return_centroid(a), headera, "fill:rgb(0,0,0);font-family:Arial;font-size:10px"); + mapper.text(boost::geometry::return_centroid(b), headerb, "fill:rgb(0,0,0);font-family:Arial;font-size:10px"); } int main() { int num_orig = 50; - int num_rounds = 20000; + int num_rounds = 30000; srand(1234); std::cout << std::setprecision(16); std::map genesis; @@ -110,6 +112,10 @@ int main() out << "original " << poly_list.size(); genesis[poly_list.size()] = out.str(); poly_list.push_back(mp); + +#ifdef LIST_WKT + std::cout << "Original " << i << " " << boost::geometry::wkt(p) << std::endl; +#endif } @@ -120,7 +126,7 @@ int main() int a = rand() % poly_list.size(); int b = rand() % poly_list.size(); - //debug_with_svg(j, 'i', poly_list[a], poly_list[b], genesis[a], genesis[b]); + debug_with_svg(j, 'i', poly_list[a], poly_list[b], genesis[a], genesis[b]); { std::ostringstream out; out << boost::geometry::wkt(poly_list[a]); wkt1 = out.str(); } { std::ostringstream out; out << boost::geometry::wkt(poly_list[b]); wkt2 = out.str(); } @@ -133,6 +139,16 @@ int main() operation = "difference"; boost::geometry::difference(poly_list[a],poly_list[b],mp_d); boost::geometry::difference(poly_list[b],poly_list[a],mp_e); + +#ifdef LIST_WKT + std::cout << j << std::endl; + std::cout << " Genesis a " << genesis[a] << std::endl; + std::cout << " Genesis b " << genesis[b] << std::endl; + std::cout << " Intersection " << boost::geometry::wkt(mp_i) << std::endl; + std::cout << " Difference a " << boost::geometry::wkt(mp_d) << std::endl; + std::cout << " Difference b " << boost::geometry::wkt(mp_e) << std::endl; +#endif + #ifdef CHECK_SELF_INTERSECTIONS try { @@ -183,21 +199,21 @@ int main() if(boost::geometry::area(mp_i) > 0) { std::ostringstream out; - out << "intersection(" << genesis[a] << " , " << genesis[b] << ")"; + out << j << " intersection(" << genesis[a] << " , " << genesis[b] << ")"; genesis[poly_list.size()] = out.str(); poly_list.push_back(mp_i); } if(boost::geometry::area(mp_d) > 0) { std::ostringstream out; - out << "difference(" << genesis[a] << " - " << genesis[b] << ")"; + out << j << " difference(" << genesis[a] << " - " << genesis[b] << ")"; genesis[poly_list.size()] = out.str(); poly_list.push_back(mp_d); } if(boost::geometry::area(mp_e) > 0) { std::ostringstream out; - out << "difference(" << genesis[b] << ", " << genesis[a] << ")"; + out << j << " difference(" << genesis[b] << " - " << genesis[a] << ")"; genesis[poly_list.size()] = out.str(); poly_list.push_back(mp_e); } diff --git a/test/algorithms/overlay/self_intersection_points.cpp b/test/algorithms/overlay/self_intersection_points.cpp index 3602e40ea..b8c7969c8 100644 --- a/test/algorithms/overlay/self_intersection_points.cpp +++ b/test/algorithms/overlay/self_intersection_points.cpp @@ -24,6 +24,7 @@ #include //#include #include +#include #include #include @@ -48,20 +49,31 @@ static void test_self_intersection_points(std::string const& case_id, bool check_has_intersections, double precision = 0.001) { + typedef typename bg::point_type::type point_type; + //typedef typename bg::rescale_policy_type::type rescale_policy_type; + typedef bg::detail::no_rescale_policy rescale_policy_type; typedef bg::detail::overlay::turn_info - < - typename bg::point_type::type - > turn_info; + < + point_type, + typename bg::segment_ratio_type + < + point_type, rescale_policy_type + >::type + > turn_info; std::vector turns; + + rescale_policy_type rescale_policy + ; + // = bg::get_rescale_policy(geometry); ///bg::get_intersection_points(geometry, turns); bg::detail::self_get_turn_points::no_interrupt_policy policy; bg::self_turns < bg::detail::overlay::assign_null_policy - >(geometry, bg::detail::no_rescale_policy(), turns, policy); + >(geometry, rescale_policy, turns, policy); typedef typename bg::coordinate_type::type ct; diff --git a/test/algorithms/overlay/test_get_turns.hpp b/test/algorithms/overlay/test_get_turns.hpp index 41ee8400c..f5e72797d 100644 --- a/test/algorithms/overlay/test_get_turns.hpp +++ b/test/algorithms/overlay/test_get_turns.hpp @@ -57,16 +57,28 @@ void check_geometry_range( std::string const& wkt2, Range const& expected) { + typedef bg::detail::no_rescale_policy robust_policy_type; + typedef typename bg::point_type::type point_type; + + typedef typename bg::segment_ratio_type::type segment_ratio_type; + typedef bg::detail::overlay::turn_info < typename bg::point_type::type, - typename bg::detail::get_turns::turn_operation_type::type + segment_ratio_type, + typename bg::detail::get_turns::turn_operation_type + < + Geometry1, + Geometry2, + segment_ratio_type + >::type > turn_info; typedef bg::detail::overlay::assign_null_policy assign_policy_t; typedef bg::detail::get_turns::no_interrupt_policy interrupt_policy_t; std::vector turns; interrupt_policy_t interrupt_policy; + robust_policy_type robust_policy; // Don't switch the geometries typedef bg::detail::get_turns::get_turn_info_type turn_policy_t; @@ -75,7 +87,7 @@ void check_geometry_range( typename bg::tag::type, typename bg::tag::type, Geometry1, Geometry2, false, false, turn_policy_t - >::apply(0, g1, 1, g2, bg::detail::no_rescale_policy(), turns, interrupt_policy); + >::apply(0, g1, 1, g2, robust_policy, turns, interrupt_policy); bool ok = boost::size(expected) == turns.size(); diff --git a/test/algorithms/overlay/traverse.cpp b/test/algorithms/overlay/traverse.cpp index 8deb285c2..454e3791b 100644 --- a/test/algorithms/overlay/traverse.cpp +++ b/test/algorithms/overlay/traverse.cpp @@ -7,7 +7,8 @@ // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) -#define BOOST_GEOMETRY_TEST_ONLY_ONE_TYPE +#define BOOST_GEOMETRY_DEFINE_STREAM_OPERATOR_SEGMENT_RATIO +//#define BOOST_GEOMETRY_TEST_ONLY_ONE_TYPE //#define BOOST_GEOMETRY_OVERLAY_NO_THROW //#define HAVE_TTMATH @@ -42,7 +43,6 @@ #include #include #include -#include #include #include @@ -50,6 +50,7 @@ #include +#include #include #include @@ -73,6 +74,7 @@ static inline std::string operation(int d) return d == 1 ? "union" : "intersection"; } + namespace detail { @@ -144,16 +146,22 @@ struct test_traverse typename bg::cs_tag::type >::type side_strategy_type; + typedef typename bg::point_type::type point_type; + typedef typename bg::rescale_policy_type::type + rescale_policy_type; + + rescale_policy_type rescale_policy + = bg::get_rescale_policy(g1, g2); typedef bg::detail::overlay::traversal_turn_info - < - typename bg::point_type::type - > turn_info; + < + point_type, + typename bg::segment_ratio_type::type + > turn_info; std::vector turns; - bg::detail::no_rescale_policy rescale_policy; bg::detail::get_turns::no_interrupt_policy policy; - bg::get_turns(g1, g2, rescale_policy, turns, policy); + bg::get_turns(g1, g2, rescale_policy, turns, policy); bg::enrich_intersection_points(turns, Direction == 1 ? bg::detail::overlay::operation_union : bg::detail::overlay::operation_intersection, @@ -168,11 +176,12 @@ struct test_traverse < Reverse1, Reverse2, G1, G2 - >::apply(g1, g2, Direction, bg::detail::no_rescale_policy(), turns, v); + >::apply(g1, g2, Direction, rescale_policy, turns, v); // Check number of resulting rings BOOST_CHECK_MESSAGE(expected_count == boost::size(v), "traverse: " << id + << " (" << operation(Direction) << ")" << " #shapes expected: " << expected_count << " detected: " << boost::size(v) << " type: " << string_from_type @@ -226,7 +235,7 @@ struct test_traverse BOOST_FOREACH(turn_info const& turn, turns) { - int lineheight = 10; + int lineheight = 8; mapper.map(turn.point, "fill:rgb(255,128,0);" "stroke:rgb(0,0,0);stroke-width:1", 3); @@ -242,7 +251,7 @@ struct test_traverse boost::numeric_cast(half + ten * bg::get<1>(turn.point)) ); - std::string style = "fill:rgb(0,0,0);font-family:Arial;font-size:10px"; + std::string style = "fill:rgb(0,0,0);font-family:Arial;font-size:8px"; if (turn.discarded) { @@ -262,6 +271,9 @@ struct test_traverse << (turn.is_discarded() ? " (discarded) " : turn.blocked() ? " (blocked)" : "") << std::endl; + out << "r: " << turn.operations[0].fraction + << " ; " << turn.operations[1].fraction + << std::endl; if (turn.operations[0].enriched.next_ip_index != -1) { out << "ip: " << turn.operations[0].enriched.next_ip_index; @@ -322,9 +334,9 @@ struct test_traverse << std::endl << std::setprecision(3) - << "dist: " << turn.operations[0].enriched.distance - << " / " << turn.operations[1].enriched.distance - << std::endl + << "dist: " << turn.operations[0].fraction + << " / " << turn.operations[1].fraction + << std::endl; */ @@ -685,9 +697,12 @@ void test_all(bool test_self_tangencies = true, bool test_mixed = false) test_traverse::apply("72", 1, 10.65, case_72[0], case_72[1]); - - // other + test_traverse::apply("box_poly5", + 2, 4.7191, + "POLYGON((1.5 1.5, 1.5 2.5, 4.5 2.5, 4.5 1.5, 1.5 1.5))", + "POLYGON((2 1.3,2.4 1.7,2.8 1.8,3.4 1.2,3.7 1.6,3.4 2,4.1 2.5,4.5 2.5,4.5 2.3,5.0 2.3,5.0 2.1,4.5 2.1,4.5 1.9,4.0 1.9,4.5 1.2,4.9 0.8,2.9 0.7,2 1.3))"); + test_traverse::apply("collinear_overlaps", 1, 24, collinear_overlaps[0], collinear_overlaps[1]); @@ -729,9 +744,6 @@ void test_all(bool test_self_tangencies = true, bool test_mixed = false) static const bool is_float = boost::is_same::value; - static const bool is_double - = boost::is_same::value - || boost::is_same::value; static const double float_might_deviate_more = is_float ? 0.1 : 0.001; // In some cases up to 1 promille permitted @@ -789,17 +801,17 @@ void test_all(bool test_self_tangencies = true, bool test_mixed = false) if (! is_float_on_non_msvc) { test_traverse::apply("dz_1", - 3, 16.887537949472005, dz_1[0], dz_1[1]); + 2, 16.887537949472005, dz_1[0], dz_1[1]); test_traverse::apply("dz_1", 3, 1444.2621305732864, dz_1[0], dz_1[1]); test_traverse::apply("dz_2", 2, 68.678921274288541, dz_2[0], dz_2[1]); test_traverse::apply("dz_2", - 2, 1505.4202304878663, dz_2[0], dz_2[1]); + 1, 1505.4202304878663, dz_2[0], dz_2[1]); test_traverse::apply("dz_3", - 6, 192.49316937645651, dz_3[0], dz_3[1]); + 5, 192.49316937645651, dz_3[0], dz_3[1]); test_traverse::apply("dz_3", 6, 1446.496005965641, dz_3[0], dz_3[1]); @@ -813,18 +825,15 @@ void test_all(bool test_self_tangencies = true, bool test_mixed = false) // SNL (Subsidiestelsel Natuur & Landschap - verAANnen) - if (! is_float_on_non_msvc) - { - test_traverse::apply("snl-1", - 2, 286.996062095888, - snl_1[0], snl_1[1], - float_might_deviate_more); + test_traverse::apply("snl-1", + 2, 286.996062095888, + snl_1[0], snl_1[1], + float_might_deviate_more); - test_traverse::apply("snl-1", - 2, 51997.5408506132, - snl_1[0], snl_1[1], - float_might_deviate_more); - } + test_traverse::apply("snl-1", + 2, 51997.5408506132, + snl_1[0], snl_1[1], + float_might_deviate_more); { test_traverse::apply("isov", @@ -835,53 +844,6 @@ void test_all(bool test_self_tangencies = true, bool test_mixed = false) float_might_deviate_more); } - // GEOS tests - if (! is_float) - { - test_traverse::apply("geos_1_test_overlay", - 1, 3461.02330171138, geos_1_test_overlay[0], geos_1_test_overlay[1]); - test_traverse::apply("geos_1_test_overlay", - 1, 3461.31592235516, geos_1_test_overlay[0], geos_1_test_overlay[1]); - - if (! is_double) - { - test_traverse::apply("geos_2", - 2, 2.157e-6, // by bg/ttmath; sql server reports: 2.20530228034477E-06 - geos_2[0], geos_2[1]); - } - test_traverse::apply("geos_2", - 1, 350.550662845485, - geos_2[0], geos_2[1]); - } - - if (! is_float && ! is_double) - { - test_traverse::apply("geos_3", - 1, 2.484885e-7, - geos_3[0], geos_3[1]); - } - - if (! is_float_on_non_msvc) - { - // Sometimes output is reported as 29229056 -/* TODO fix this (BSG 2013-09-24) - test_traverse::apply("geos_3", - 1, 29391548.5, - geos_3[0], geos_3[1], - float_might_deviate_more); -*/ - - // Sometimes output is reported as 0.078125 - test_traverse::apply("geos_4", - 1, 0.0836884926070727, - geos_4[0], geos_4[1], - float_might_deviate_more); - } - - test_traverse::apply("geos_4", - 1, 2304.41633605957, - geos_4[0], geos_4[1]); - if (! is_float) { @@ -932,12 +894,11 @@ void test_all(bool test_self_tangencies = true, bool test_mixed = false) 1, 30, buffer_rt_g_boxes[4], buffer_rt_g_boxes[3]); + test_traverse::apply("buffer_rt_l", + 1, 19.3995, buffer_rt_l[0], buffer_rt_l[1]); - if (boost::is_same::value) - { - test_traverse::apply("buffer_mp2", - 1, 36.7535642, buffer_mp2[0], buffer_mp2[1], 0.01); - } + test_traverse::apply("buffer_mp2", + 1, 36.7535642, buffer_mp2[0], buffer_mp2[1], 0.01); test_traverse::apply("collinear_opposite_rr", 1, 6.41, collinear_opposite_right[0], collinear_opposite_right[1]); test_traverse::apply("collinear_opposite_ll", @@ -951,6 +912,10 @@ void test_all(bool test_self_tangencies = true, bool test_mixed = false) test_traverse::apply("ticket_7462", 1, 0.220582, ticket_7462[0], ticket_7462[1]); + test_traverse::apply + ("ticket_9081_15", 1, 0.006889578, + ticket_9081_15[0], ticket_9081_15[1]); + #ifdef BOOST_GEOMETRY_OVERLAY_NO_THROW { // NOTE: currently throws (normally) diff --git a/test/algorithms/overlay/traverse_gmp.cpp b/test/algorithms/overlay/traverse_gmp.cpp index 5d1cdee42..b3db22cce 100644 --- a/test/algorithms/overlay/traverse_gmp.cpp +++ b/test/algorithms/overlay/traverse_gmp.cpp @@ -35,7 +35,6 @@ #include #include #include -#include #include #include #include @@ -72,7 +71,7 @@ void test_traverse(std::string const& caseid, G1 const& g1, G2 const& g2) typedef typename boost::range_iterator >::type iterator; std::vector ips; - bg::get_turns(g1, g2, ips); + bg::get_turns(g1, g2, ips); bg::enrich_intersection_points(ips, g1, g2, strategy_type()); typedef bg::model::ring::type> ring_type; diff --git a/test/algorithms/point_on_surface.cpp b/test/algorithms/point_on_surface.cpp index 291bec005..b393a35b8 100644 --- a/test/algorithms/point_on_surface.cpp +++ b/test/algorithms/point_on_surface.cpp @@ -34,7 +34,7 @@ // Include from unit tests #include -#include +#include #include #if defined(BOOST_GEOMETRY_UNIT_TEST_MULTI) @@ -265,7 +265,7 @@ void test_all() test_geometry("dz_2", dz_2[0], 0, 0); test_geometry("dz_3", dz_3[0], 0, 0); test_geometry("dz_4", dz_4[0], 0, 0); - test_geometry("geos_1_test_overlay", geos_1_test_overlay[0], 0, 0); + test_geometry("geos_1", geos_1[0], 0, 0); test_geometry("geos_2", geos_2[0], 0, 0); test_geometry("geos_3", geos_3[0], 0, 0); test_geometry("geos_4", geos_4[0], 0, 0); diff --git a/test/algorithms/predef_relop.hpp b/test/algorithms/predef_relop.hpp new file mode 100644 index 000000000..eda98ac01 --- /dev/null +++ b/test/algorithms/predef_relop.hpp @@ -0,0 +1,33 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) +// Unit Test + +// Copyright (c) 2010-2012 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_PREDEF_RELOP_HPP +#define BOOST_GEOMETRY_PREDEF_RELOP_HPP + +#include + + +static std::string disjoint_simplex[2] = + {"POLYGON((0 0,0 2,2 2,0 0))", + "POLYGON((1 0,3 2,3 0,1 0))"}; + +static std::string touch_simplex[2] = + {"POLYGON((0 0,0 2,2 2,0 0))", + "POLYGON((2 2,3 2,3 0,2 2))"}; + +static std::string overlaps_box[2] = + {"POLYGON((0 0,0 2,2 2,0 0))", + "POLYGON((1 1,3 2,3 0,1 1))"}; + +static std::string within_simplex[2] = + {"POLYGON((0 0,1 4,4 1,0 0))", + "POLYGON((1 1,1 3,3 1,1 1))"}; + + + +#endif diff --git a/test/algorithms/relate.cpp b/test/algorithms/relate.cpp deleted file mode 100644 index d1bf8961a..000000000 --- a/test/algorithms/relate.cpp +++ /dev/null @@ -1,971 +0,0 @@ -// Boost.Geometry (aka GGL, Generic Geometry Library) - -// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. - -// This file was modified by Oracle on 2013, 2014. -// Modifications copyright (c) 2013-2014 Oracle and/or its affiliates. - -// 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) - -// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle - -#include - -#include -#include -#include -#include -#include - -#include - -#include -#include -#include - -#include -#include -#include - -#include -#include - -#include - -#include -#include -#include -#include - -//TEST -#include - -namespace bgdr = bg::detail::relate; - -std::string transposed(std::string matrix) -{ - std::swap(matrix[1], matrix[3]); - std::swap(matrix[2], matrix[6]); - std::swap(matrix[5], matrix[7]); - return matrix; -} - -template -void check_geometry(Geometry1 const& geometry1, - Geometry2 const& geometry2, - std::string const& wkt1, - std::string const& wkt2, - std::string const& expected) -{ - { - std::string res_str = bgdr::relate(geometry1, geometry2); - bool ok = boost::equal(res_str, expected); - BOOST_CHECK_MESSAGE(ok, - "relate: " << wkt1 - << " and " << wkt2 - << " -> Expected: " << expected - << " detected: " << res_str); - } - - // changed sequence of geometries - transposed result - { - std::string res_str = bgdr::relate(geometry2, geometry1, bgdr::matrix9()); - std::string expected_tr = transposed(expected); - bool ok = boost::equal(res_str, expected_tr); - BOOST_CHECK_MESSAGE(ok, - "relate: " << wkt2 - << " and " << wkt1 - << " -> Expected: " << expected_tr - << " detected: " << res_str); - } - - { - bool result = bgdr::relate(geometry1, geometry2, bgdr::mask9(expected)); - // TODO: SHOULD BE !interrupted - CHECK THIS! - BOOST_CHECK_MESSAGE(result, - "relate: " << wkt1 - << " and " << wkt2 - << " -> Expected: " << expected); - } - - if ( bg::detail::relate::interruption_enabled::value ) - { - // brake the expected output - std::string expected_interrupt = expected; - bool changed = false; - BOOST_FOREACH(char & c, expected_interrupt) - { - if ( c >= '0' && c <= '9' ) - { - if ( c == '0' ) - c = 'F'; - else - --c; - - changed = true; - } - } - - if ( changed ) - { - bool result = bgdr::relate(geometry1, geometry2, bgdr::mask9(expected_interrupt)); - // TODO: SHOULD BE interrupted - CHECK THIS! - BOOST_CHECK_MESSAGE(!result, - "relate: " << wkt1 - << " and " << wkt2 - << " -> Expected interrupt for:" << expected_interrupt); - } - } -} - -template -void test_geometry(std::string const& wkt1, - std::string const& wkt2, - std::string const& expected) -{ - Geometry1 geometry1; - Geometry2 geometry2; - bg::read_wkt(wkt1, geometry1); - bg::read_wkt(wkt2, geometry2); - check_geometry(geometry1, geometry2, wkt1, wkt2, expected); -} - -template -void test_point_point() -{ - test_geometry("POINT(0 0)", "POINT(0 0)", "0FFFFFFF2"); - test_geometry("POINT(1 0)", "POINT(0 0)", "FF0FFF0F2"); -} - -template -void test_point_multipoint() -{ - typedef bg::model::multi_point

mpt; - - test_geometry("POINT(0 0)", "MULTIPOINT(0 0)", "0FFFFFFF2"); - test_geometry("POINT(1 0)", "MULTIPOINT(0 0)", "FF0FFF0F2"); - test_geometry("POINT(0 0)", "MULTIPOINT(0 0, 1 0)", "0FFFFF0F2"); -} - -template -void test_multipoint_multipoint() -{ - typedef bg::model::multi_point

mpt; - - test_geometry("MULTIPOINT(0 0)", "MULTIPOINT(0 0)", "0FFFFFFF2"); - test_geometry("MULTIPOINT(1 0)", "MULTIPOINT(0 0)", "FF0FFF0F2"); - test_geometry("MULTIPOINT(0 0)", "MULTIPOINT(0 0, 1 0)", "0FFFFF0F2"); - test_geometry("MULTIPOINT(0 0, 1 0)", "MULTIPOINT(0 0)", "0F0FFFFF2"); - test_geometry("MULTIPOINT(0 0, 1 1)", "MULTIPOINT(0 0, 1 0)", "0F0FFF0F2"); - - //typedef bg::model::d2::point_xy ptf; - //typedef bg::model::multi_point mptf; - //test_geometry("MULTIPOINT(0 0)", "MULTIPOINT(0 0)", "0FFFFFFF2"); -} - -template -void test_point_linestring() -{ - typedef bg::model::linestring

ls; - - test_geometry("POINT(0 0)", "LINESTRING(0 0, 2 2, 3 2)", "F0FFFF102"); - test_geometry("POINT(1 1)", "LINESTRING(0 0, 2 2, 3 2)", "0FFFFF102"); - test_geometry("POINT(3 2)", "LINESTRING(0 0, 2 2, 3 2)", "F0FFFF102"); - test_geometry("POINT(1 0)", "LINESTRING(0 0, 2 2, 3 2)", "FF0FFF102"); - - test_geometry("POINT(0 0)", "LINESTRING(0 0, 2 2, 3 2, 0 0)", "0FFFFF1F2"); - test_geometry("POINT(1 1)", "LINESTRING(0 0, 2 2, 3 2, 0 0)", "0FFFFF1F2"); - test_geometry("POINT(3 2)", "LINESTRING(0 0, 2 2, 3 2, 0 0)", "0FFFFF1F2"); - test_geometry("POINT(1 0)", "LINESTRING(0 0, 2 2, 3 2, 0 0)", "FF0FFF1F2"); -} - -template -void test_point_multilinestring() -{ - typedef bg::model::linestring

ls; - typedef bg::model::multi_linestring mls; - - test_geometry("POINT(0 0)", "MULTILINESTRING((0 0, 2 0, 2 2),(0 0, 0 2))", "0FFFFF102"); - test_geometry("POINT(0 0)", "MULTILINESTRING((0 0, 2 0, 2 2),(0 0, 0 2, 2 2))", "0FFFFF1F2"); - test_geometry("POINT(0 0)", "MULTILINESTRING((0 0, 2 0, 2 2),(0 0, 0 2, 2 2),(0 0, 1 1))", "F0FFFF102"); - - test_geometry("POINT(0 0)", "MULTILINESTRING((0 0,5 0),(0 0,0 5,5 0),(0 0,-5 0),(0 0,0 -5,-5 0))", "0FFFFF1F2"); - test_geometry("POINT(5 0)", "MULTILINESTRING((0 0,5 0),(0 0,0 5,5 0),(0 0,-5 0),(0 0,0 -5,-5 0))", "0FFFFF1F2"); - test_geometry("POINT(1 0)", "MULTILINESTRING((0 0,5 0),(0 0,0 5,5 0),(0 0,-5 0),(0 0,0 -5,-5 0))", "0FFFFF1F2"); -} - -template -void test_linestring_linestring() -{ - typedef bg::model::linestring

ls; - - test_geometry("LINESTRING(0 0, 2 2, 3 2)", "LINESTRING(0 0, 2 2, 3 2)", "1FFF0FFF2"); - test_geometry("LINESTRING(0 0,3 2)", "LINESTRING(0 0, 2 2, 3 2)", "FF1F0F1F2"); - test_geometry("LINESTRING(1 0,2 2,2 3)", "LINESTRING(0 0, 2 2, 3 2)", "0F1FF0102"); - - test_geometry("LINESTRING(0 0,5 0)", "LINESTRING(0 0,1 1,2 0,2 -1)", "0F1F00102"); - - test_geometry("LINESTRING(0 0, 1 1, 2 2, 3 2)", "LINESTRING(0 0, 2 2, 3 2)", "1FFF0FFF2"); - test_geometry("LINESTRING(3 2, 2 2, 1 1, 0 0)", "LINESTRING(0 0, 2 2, 3 2)", "1FFF0FFF2"); - test_geometry("LINESTRING(0 0, 1 1, 2 2, 3 2)", "LINESTRING(3 2, 2 2, 0 0)", "1FFF0FFF2"); - test_geometry("LINESTRING(3 2, 2 2, 1 1, 0 0)", "LINESTRING(3 2, 2 2, 0 0)", "1FFF0FFF2"); - - test_geometry("LINESTRING(3 1, 2 2, 1 1, 0 0)", "LINESTRING(0 0, 2 2, 3 2)", "1F1F00102"); - test_geometry("LINESTRING(3 3, 2 2, 1 1, 0 0)", "LINESTRING(0 0, 2 2, 3 2)", "1F1F00102"); - - test_geometry("LINESTRING(0 0, 1 1, 2 2, 2 3)", "LINESTRING(0 0, 2 2, 2 3)", "1FFF0FFF2"); - test_geometry("LINESTRING(2 3, 2 2, 1 1, 0 0)", "LINESTRING(0 0, 2 2, 2 3)", "1FFF0FFF2"); - test_geometry("LINESTRING(0 0, 1 1, 2 2, 2 3)", "LINESTRING(2 3, 2 2, 0 0)", "1FFF0FFF2"); - test_geometry("LINESTRING(2 3, 2 2, 1 1, 0 0)", "LINESTRING(2 3, 2 2, 0 0)", "1FFF0FFF2"); - - test_geometry("LINESTRING(1 1, 2 2, 3 2)", "LINESTRING(0 0, 2 2, 4 2)", "1FF0FF102"); - - test_geometry("LINESTRING(3 2, 2 2, 1 1)", "LINESTRING(0 0, 2 2, 4 2)", "1FF0FF102"); - test_geometry("LINESTRING(1 1, 2 2, 3 2)", "LINESTRING(4 2, 2 2, 0 0)", "1FF0FF102"); - test_geometry("LINESTRING(3 2, 2 2, 1 1)", "LINESTRING(4 2, 2 2, 0 0)", "1FF0FF102"); - -// test_geometry("LINESTRING(1 1, 2 2, 2 2)", "LINESTRING(0 0, 2 2, 4 2)", true); - -// test_geometry("LINESTRING(1 1, 2 2, 3 3)", "LINESTRING(0 0, 2 2, 4 2)", false); -// test_geometry("LINESTRING(1 1, 2 2, 3 2, 3 3)", "LINESTRING(0 0, 2 2, 4 2)", false); -// test_geometry("LINESTRING(1 1, 2 2, 3 1)", "LINESTRING(0 0, 2 2, 4 2)", false); -// test_geometry("LINESTRING(1 1, 2 2, 3 2, 3 1)", "LINESTRING(0 0, 2 2, 4 2)", false); - -// test_geometry("LINESTRING(0 1, 1 1, 2 2, 3 2)", "LINESTRING(0 0, 2 2, 4 2)", false); -// test_geometry("LINESTRING(0 1, 0 0, 2 2, 3 2)", "LINESTRING(0 0, 2 2, 4 2)", false); -// test_geometry("LINESTRING(1 0, 1 1, 2 2, 3 2)", "LINESTRING(0 0, 2 2, 4 2)", false); -// test_geometry("LINESTRING(1 0, 0 0, 2 2, 3 2)", "LINESTRING(0 0, 2 2, 4 2)", false); - -// test_geometry("LINESTRING(0 0)", "LINESTRING(0 0)", false); -// test_geometry("LINESTRING(1 1)", "LINESTRING(0 0, 2 2)", true); -// test_geometry("LINESTRING(0 0)", "LINESTRING(0 0, 2 2)", false); -// test_geometry("LINESTRING(0 0, 1 1)", "LINESTRING(0 0)", false); - -// test_geometry("LINESTRING(0 0,5 0,3 0,6 0)", "LINESTRING(0 0,6 0)", true); -// test_geometry("LINESTRING(0 0,2 2,3 3,1 1)", "LINESTRING(0 0,3 3,6 3)", true); - - test_geometry("LINESTRING(0 0,2 2,3 3,1 1,5 3)", "LINESTRING(0 0,3 3,6 3)", "1F100F102"); - test_geometry("LINESTRING(5 3,1 1,3 3,2 2,0 0)", "LINESTRING(0 0,3 3,6 3)", "1F100F102"); - test_geometry("LINESTRING(0 0,2 2,3 3,1 1,5 3)", "LINESTRING(6 3,3 3,0 0)", "1F100F102"); - test_geometry("LINESTRING(5 3,1 1,3 3,2 2,0 0)", "LINESTRING(6 3,3 3,0 0)", "1F100F102"); - - // spikes - // FOR NOW DISABLED - /*test_geometry("LINESTRING(0 0,10 0)", - "LINESTRING(1 0,9 0,2 0)", "101FF0FF2"); - test_geometry("LINESTRING(0 0,2 2,3 3,1 1)", "LINESTRING(0 0,3 3,6 3)", "1FF00F102"); - test_geometry("LINESTRING(0 0,2 2,3 3,1 1)", "LINESTRING(0 0,4 4,6 3)", "1FF00F102");*/ - - test_geometry("LINESTRING(0 0,2 2,3 3,4 4)", "LINESTRING(0 0,1 1,4 4)", "1FFF0FFF2"); - - // loop i/i i/i u/u u/u - test_geometry("LINESTRING(0 0,10 0)", - "LINESTRING(1 1,1 0,6 0,6 1,4 1,4 0,9 0,9 1)", "1F1FF0102"); - - // self-intersecting and self-touching equal - test_geometry("LINESTRING(0 5,5 5,10 5,10 10,5 10,5 5,5 0)", - "LINESTRING(0 5,5 5,5 10,10 10,10 5,5 5,5 0)", "1FFF0FFF2"); - // self-intersecting loop and self-touching equal - test_geometry("LINESTRING(0 5,5 5,10 5,10 10,5 10,5 5,10 5,10 10,5 10,5 5,5 0)", - "LINESTRING(0 5,5 5,5 10,10 10,10 5,5 5,5 0)", "1FFF0FFF2"); - - test_geometry("LINESTRING(0 0,1 1)", "LINESTRING(0 1,1 0)", "0F1FF0102"); - test_geometry("LINESTRING(0 0,1 1)", "LINESTRING(1 1,2 0)", "FF1F00102"); - test_geometry("LINESTRING(0 0,1 1)", "LINESTRING(2 0,1 1)", "FF1F00102"); - - test_geometry("LINESTRING(0 0,1 0,2 1,3 5,4 0)", "LINESTRING(1 0,2 1,3 5)", "101FF0FF2"); - test_geometry("LINESTRING(0 0,1 0,2 1,3 5,4 0)", "LINESTRING(3 5,2 1,1 0)", "101FF0FF2"); - test_geometry("LINESTRING(1 0,2 1,3 5)", "LINESTRING(4 0,3 5,2 1,1 0,0 0)", "1FF0FF102"); - test_geometry("LINESTRING(3 5,2 1,1 0)", "LINESTRING(4 0,3 5,2 1,1 0,0 0)", "1FF0FF102"); - - test_geometry("LINESTRING(0 0,10 0)", "LINESTRING(-1 -1,1 0,10 0,20 -1)", "1F10F0102"); - test_geometry("LINESTRING(0 0,10 0)", "LINESTRING(20 -1,10 0,1 0,-1 -1)", "1F10F0102"); - - test_geometry("LINESTRING(-1 1,0 0,1 0,5 0,5 5,10 5,15 0,31 0)", - "LINESTRING(-1 -1,0 0,1 0,2 0,3 1,4 0,30 0)", - "101FF0102"); - test_geometry("LINESTRING(-1 1,0 0,1 0,5 0,5 5,10 5,15 0,31 0)", - "LINESTRING(30 0,4 0,3 1,2 0,1 0,0 0,-1 -1)", - "101FF0102"); - test_geometry("LINESTRING(31 0,15 0,10 5,5 5,5 0,1 0,0 0,-1 1)", - "LINESTRING(-1 -1,0 0,1 0,2 0,3 1,4 0,30 0)", - "101FF0102"); - test_geometry("LINESTRING(31 0,15 0,10 5,5 5,5 0,1 0,0 0,-1 1)", - "LINESTRING(30 0,4 0,3 1,2 0,1 0,0 0,-1 -1)", - "101FF0102"); - - // self-IP - test_geometry("LINESTRING(1 0,9 0)", - "LINESTRING(0 0,10 0,10 10,5 0,0 10)", - "1FF0FF102"); - test_geometry("LINESTRING(1 0,5 0,9 0)", - "LINESTRING(0 0,10 0,10 10,5 0,0 10)", - "1FF0FF102"); - test_geometry("LINESTRING(1 0,9 0)", - "LINESTRING(0 0,10 0,10 10,5 10,5 -1)", - "1FF0FF102"); - test_geometry("LINESTRING(1 0,9 0)", - "LINESTRING(0 0,10 0,5 0,5 5)", - "1FF0FF102"); - test_geometry("LINESTRING(1 0,7 0)", "LINESTRING(0 0,10 0,10 10,4 -1)", - "1FF0FF102"); - test_geometry("LINESTRING(1 0,5 0,7 0)", "LINESTRING(0 0,10 0,10 10,4 -1)", - "1FF0FF102"); - test_geometry("LINESTRING(1 0,7 0,8 1)", "LINESTRING(0 0,10 0,10 10,4 -1)", - "1F10F0102"); - test_geometry("LINESTRING(1 0,5 0,7 0,8 1)", "LINESTRING(0 0,10 0,10 10,4 -1)", - "1F10F0102"); - - // self-IP going out and in on the same point - test_geometry("LINESTRING(2 0,5 0,5 5,6 5,5 0,8 0)", "LINESTRING(1 0,9 0)", - "1F10FF102"); - - // duplicated points - test_geometry("LINESTRING(1 1, 2 2, 2 2)", "LINESTRING(0 0, 2 2, 4 2)", "1FF0FF102"); - test_geometry("LINESTRING(1 1, 1 1, 2 2)", "LINESTRING(0 0, 2 2, 4 2)", "1FF0FF102"); - - // linear ring - test_geometry("LINESTRING(0 0,10 0)", "LINESTRING(5 0,9 0,5 5,1 0,5 0)", "1F1FF01F2"); - test_geometry("LINESTRING(0 0,5 0,10 0)", "LINESTRING(5 0,9 0,5 5,1 0,5 0)", "1F1FF01F2"); - test_geometry("LINESTRING(0 0,5 0,10 0)", "LINESTRING(5 0,10 0,5 5,1 0,5 0)", "1F10F01F2"); - - test_geometry("LINESTRING(0 0,5 0)", "LINESTRING(5 0,10 0,5 5,0 0,5 0)", "1FF0FF1F2"); - test_geometry("LINESTRING(0 0,5 0)", "LINESTRING(5 0,10 0,5 5,5 0)", "FF10F01F2"); - - //to_svg("LINESTRING(0 0,5 0)", "LINESTRING(5 0,10 0,5 5,5 0)", "test_relate_00.svg"); - - // INVALID LINESTRINGS - // 1-point LS (a Point) NOT disjoint - //test_geometry("LINESTRING(1 0)", "LINESTRING(0 0,5 0)", "0FFFFF102"); - //test_geometry("LINESTRING(0 0,5 0)", "LINESTRING(1 0)", "0F1FF0FF2"); - //test_geometry("LINESTRING(0 0,5 0)", "LINESTRING(1 0,1 0)", "0F1FF0FF2"); - //test_geometry("LINESTRING(0 0,5 0)", "LINESTRING(1 0,1 0,1 0)", "0F1FF0FF2"); - // Point/Point - //test_geometry("LINESTRING(0 0)", "LINESTRING(0 0)", "0FFFFFFF2"); - - // OTHER MASKS - { - namespace bgdr = bg::detail::relate; - ls ls1, ls2, ls3, ls4; - bg::read_wkt("LINESTRING(0 0,2 0)", ls1); - bg::read_wkt("LINESTRING(2 0,4 0)", ls2); - bg::read_wkt("LINESTRING(1 0,1 1)", ls3); - bg::read_wkt("LINESTRING(1 0,4 0)", ls4); - BOOST_CHECK(bgdr::relate(ls1, ls2, bgdr::mask9("FT*******") - || bgdr::mask9("F**T*****") - || bgdr::mask9("F***T****"))); - BOOST_CHECK(bgdr::relate(ls1, ls3, bgdr::mask9("FT*******") - || bgdr::mask9("F**T*****") - || bgdr::mask9("F***T****"))); - BOOST_CHECK(bgdr::relate(ls3, ls1, bgdr::mask9("FT*******") - || bgdr::mask9("F**T*****") - || bgdr::mask9("F***T****"))); - BOOST_CHECK(bgdr::relate(ls2, ls4, bgdr::mask9("T*F**F***"))); // within - } -} - -template -void test_linestring_multi_linestring() -{ - typedef bg::model::linestring

ls; - typedef bg::model::multi_linestring mls; - - // LS disjoint - test_geometry("LINESTRING(0 0,10 0)", "MULTILINESTRING((1 0,2 0),(1 1,2 1))", "101FF0102"); - // linear ring disjoint - test_geometry("LINESTRING(0 0,10 0)", "MULTILINESTRING((1 0,2 0),(1 1,2 1,2 2,1 1))", "101FF01F2"); - // 2xLS forming non-simple linear ring disjoint - test_geometry("LINESTRING(0 0,10 0)", "MULTILINESTRING((1 0,2 0),(1 1,2 1,2 2),(1 1,2 2))", "101FF01F2"); - - // INVALID LINESTRINGS - // 1-point LS (a Point) disjoint - //test_geometry("LINESTRING(0 0,10 0)", "MULTILINESTRING((1 0,2 0),(1 1))", "101FF00F2"); - //test_geometry("LINESTRING(0 0,10 0)", "MULTILINESTRING((1 0,2 0),(1 1,1 1))", "101FF00F2"); - //test_geometry("LINESTRING(0 0,10 0)", "MULTILINESTRING((1 0,2 0),(1 1,1 1,1 1))", "101FF00F2"); - // 1-point LS (a Point) NOT disjoint - //test_geometry("LINESTRING(0 0,10 0)", "MULTILINESTRING((1 0,9 0),(2 0))", "101FF0FF2"); - //test_geometry("LINESTRING(0 0,10 0)", "MULTILINESTRING((1 0,9 0),(2 0,2 0))", "101FF0FF2"); - //test_geometry("LINESTRING(0 0,10 0)", "MULTILINESTRING((1 0,9 0),(2 0,2 0,2 0))", "101FF0FF2"); -} - -template -void test_multi_linestring_multi_linestring() -{ - typedef bg::model::linestring

ls; - typedef bg::model::multi_linestring mls; - - test_geometry("MULTILINESTRING((0 0,0 0,18 0,18 0,19 0,19 0,19 0,30 0,30 0))", - "MULTILINESTRING((0 10,5 0,20 0,20 0,30 0))", - "1F1F00102"); - test_geometry("MULTILINESTRING((0 0,0 0,18 0,18 0,19 0,19 0,19 0,30 0,30 0))", - //"MULTILINESTRING((0 10,5 0,20 0,20 0,30 0),(1 10,1 10,1 0,1 0,1 -10),(2 0,2 0),(3 0,3 0,3 0),(0 0,0 0,0 10,0 10),(30 0,30 0,31 0,31 0))", - "MULTILINESTRING((0 10,5 0,20 0,20 0,30 0),(1 10,1 10,1 0,1 0,1 -10),(0 0,0 0,0 10,0 10),(30 0,30 0,31 0,31 0))", - "1F100F102"); - test_geometry("MULTILINESTRING((0 0,0 0,18 0,18 0,19 0,19 0,19 0,30 0,30 0))", - "MULTILINESTRING((0 10,5 0,20 0,20 0,30 0),(0 0,0 0,0 10,0 10))", - "1F1F0F1F2"); -} - -template -void test_linestring_polygon() -{ - typedef bg::model::linestring

ls; - typedef bg::model::polygon

poly; - typedef bg::model::ring

ring; - - // LS disjoint - test_geometry("LINESTRING(11 0,11 10)", "POLYGON((0 0,0 10,10 10,10 0,0 0))", "FF1FF0212"); - test_geometry("LINESTRING(11 0,11 10)", "POLYGON((0 0,0 10,10 10,10 0,0 0))", "FF1FF0212"); - - // II BB - test_geometry("LINESTRING(0 0,10 10)", "POLYGON((0 0,0 10,10 10,10 0,0 0))", "1FFF0F212"); - test_geometry("LINESTRING(5 0,5 5,10 5)", "POLYGON((0 0,0 10,10 10,10 0,0 0))", "1FFF0F212"); - test_geometry("LINESTRING(5 1,5 5,9 5)", "POLYGON((0 0,0 10,10 10,10 0,0 0))", "1FF0FF212"); - - // IE - test_geometry("LINESTRING(11 1,11 5)", "POLYGON((0 0,0 10,10 10,10 0,0 0))", "FF1FF0212"); - // IE IB0 - test_geometry("LINESTRING(11 1,10 5)", "POLYGON((0 0,0 10,10 10,10 0,0 0))", "FF1F00212"); - // IE IB1 - test_geometry("LINESTRING(11 1,10 5,10 10)", "POLYGON((0 0,0 10,10 10,10 0,0 0))", "F11F00212"); - test_geometry("LINESTRING(11 1,10 10,0 10)", "POLYGON((0 0,0 10,10 10,10 0,0 0))", "F11F00212"); - test_geometry("LINESTRING(11 1,10 0,0 0)", "POLYGON((0 0,0 10,10 10,10 0,0 0))", "F11F00212"); - test_geometry("LINESTRING(0 -1,1 0,2 0)", "POLYGON((0 0,0 10,10 10,10 0,0 0))", "F11F00212"); - // IE IB0 II - test_geometry("LINESTRING(11 1,10 5,5 5)", "POLYGON((0 0,0 10,10 10,10 0,0 0))", "1010F0212"); - // IE IB0 lring - test_geometry("LINESTRING(11 1,10 5,11 5,11 1)", "POLYGON((0 0,0 10,10 10,10 0,0 0))", "F01FFF212"); - // IE IB1 lring - test_geometry("LINESTRING(11 1,10 5,10 10,11 5,11 1)", "POLYGON((0 0,0 10,10 10,10 0,0 0))", "F11FFF212"); - - // IB1 II - test_geometry("LINESTRING(0 0,5 0,5 5)", "POLYGON((0 0,0 10,10 10,10 0,0 0))", "11F00F212"); - // BI0 II IB1 - test_geometry("LINESTRING(5 0,5 5,10 5,10 10)", "POLYGON((0 0,0 10,10 10,10 0,0 0))", "11FF0F212"); - - // IB1 II IB1 - test_geometry("LINESTRING(1 0,2 0,3 1,4 0,5 0)", "POLYGON((0 0,0 10,10 10,10 0,0 0))", "11FF0F212"); - // IB1 IE IB1 - test_geometry("LINESTRING(1 0,2 0,3 -1,4 0,5 0)", "POLYGON((0 0,0 10,10 10,10 0,0 0))", "F11F0F212"); - - // II IB1 - test_geometry("LINESTRING(5 5,10 5,10 10)", "POLYGON((0 0,0 10,10 10,10 0,0 0))", "11F00F212"); - // IB1 II - test_geometry("LINESTRING(10 10,10 5,5 5)", "POLYGON((0 0,0 10,10 10,10 0,0 0))", "11F00F212"); - // IE IB1 - test_geometry("LINESTRING(15 5,10 5,10 10)", "POLYGON((0 0,0 10,10 10,10 0,0 0))", "F11F00212"); - // IB1 IE - test_geometry("LINESTRING(10 10,10 5,15 5)", "POLYGON((0 0,0 10,10 10,10 0,0 0))", "F11F00212"); - - // duplicated points - { - // II IB0 IE - test_geometry("LINESTRING(5 5,10 5,15 10)", "POLYGON((0 0,0 10,10 10,10 0,0 0))", "1010F0212"); - test_geometry("LINESTRING(5 5,5 5,5 5,10 5,10 5,10 5,15 10,15 10,15 10)", - "POLYGON((0 0,0 0,0 0,0 10,0 10,0 10,10 10,10 10,10 10,10 0,10 0,10 0,0 0,0 0,0 0))", - "1010F0212"); - test_geometry("LINESTRING(5 5,5 5,5 5,10 0,10 0,10 0,15 10,15 10,15 10)", - "POLYGON((0 0,0 0,0 0,0 10,0 10,0 10,10 10,10 10,10 10,10 0,10 0,10 0,0 0,0 0,0 0))", - "1010F0212"); - // IE IB0 II - test_geometry("LINESTRING(15 10,15 10,15 10,10 5,10 5,10 5,5 5,5 5,5 5)", - "POLYGON((0 0,0 0,0 0,0 10,0 10,0 10,10 10,10 10,10 10,10 0,10 0,10 0,0 0,0 0,0 0))", - "1010F0212"); - test_geometry("LINESTRING(15 10,15 10,15 10,10 0,10 0,10 0,5 5,5 5,5 5)", - "POLYGON((0 0,0 0,0 0,0 10,0 10,0 10,10 10,10 10,10 10,10 0,10 0,10 0,0 0,0 0,0 0))", - "1010F0212"); - - // TEST - //test_geometry("LINESTRING(5 5,5 5,5 5)", "POLYGON((0 0,0 10,10 10,10 0,0 0))", "1010F0212"); - test_geometry("LINESTRING(5 5,5 5,5 5,15 5,15 5,15 5)", "POLYGON((0 0,0 10,10 10,10 0,0 0))", "1010F0212"); - } - - // non-simple polygon with hole - test_geometry("LINESTRING(9 1,10 5,9 9)", - "POLYGON((0 0,0 10,10 10,10 0,0 0),(10 5,2 8,2 2,10 5))", - "10F0FF212"); - test_geometry("LINESTRING(10 1,10 5,10 9)", - "POLYGON((0 0,0 10,10 10,10 0,0 0),(10 5,2 8,2 2,10 5))", - "F1FF0F212"); - test_geometry("LINESTRING(2 8,10 5,2 2)", - "POLYGON((0 0,0 10,10 10,10 0,0 0),(10 5,2 8,2 2,10 5))", - "F1FF0F212"); - test_geometry("LINESTRING(10 1,10 5,2 2)", - "POLYGON((0 0,0 10,10 10,10 0,0 0),(10 5,2 8,2 2,10 5))", - "F1FF0F212"); - test_geometry("LINESTRING(10 1,10 5,2 8)", - "POLYGON((0 0,0 10,10 10,10 0,0 0),(10 5,2 8,2 2,10 5))", - "F1FF0F212"); - - // non-simple polygon with hole, linear ring - test_geometry("LINESTRING(9 1,10 5,9 9,1 9,1 1,9 1)", - "POLYGON((0 0,0 10,10 10,10 0,0 0),(10 5,2 8,2 2,10 5))", - "10FFFF212"); - test_geometry("LINESTRING(10 5,10 9,11 5,10 1,10 5)", - "POLYGON((0 0,0 10,10 10,10 0,0 0),(10 5,2 8,2 2,10 5))", - "F11FFF212"); - test_geometry("LINESTRING(11 5,10 1,10 5,10 9,11 5)", - "POLYGON((0 0,0 10,10 10,10 0,0 0),(10 5,2 8,2 2,10 5))", - "F11FFF212"); - - // non-simple polygon with self-touching holes - test_geometry("LINESTRING(7 1,8 5,7 9)", - "POLYGON((0 0,0 10,10 10,10 0,0 0),(8 1,9 1,9 9,8 9,8 1),(2 2,8 5,2 8,2 2))", - "10F0FF212"); - test_geometry("LINESTRING(8 2,8 5,8 8)", - "POLYGON((0 0,0 10,10 10,10 0,0 0),(8 1,9 1,9 9,8 9,8 1),(2 2,8 5,2 8,2 2))", - "F1FF0F212"); - test_geometry("LINESTRING(2 8,8 5,2 2)", - "POLYGON((0 0,0 10,10 10,10 0,0 0),(8 1,9 1,9 9,8 9,8 1),(2 2,8 5,2 8,2 2))", - "F1FF0F212"); - - // non-simple polygon self-touching - test_geometry("LINESTRING(9 1,10 5,9 9)", - "POLYGON((0 0,0 10,10 10,10 5,2 8,2 2,10 5,10 0,0 0))", - "10F0FF212"); - test_geometry("LINESTRING(10 1,10 5,10 9)", - "POLYGON((0 0,0 10,10 10,10 5,2 8,2 2,10 5,10 0,0 0))", - "F1FF0F212"); - test_geometry("LINESTRING(2 8,10 5,2 2)", - "POLYGON((0 0,0 10,10 10,10 5,2 8,2 2,10 5,10 0,0 0))", - "F1FF0F212"); - - // non-simple polygon self-touching, linear ring - test_geometry("LINESTRING(9 1,10 5,9 9,1 9,1 1,9 1)", - "POLYGON((0 0,0 10,10 10,10 5,2 8,2 2,10 5,10 0,0 0))", - "10FFFF212"); - test_geometry("LINESTRING(10 5,10 9,11 5,10 1,10 5)", - "POLYGON((0 0,0 10,10 10,10 5,2 8,2 2,10 5,10 0,0 0))", - "F11FFF212"); - test_geometry("LINESTRING(11 5,10 1,10 5,10 9,11 5)", - "POLYGON((0 0,0 10,10 10,10 5,2 8,2 2,10 5,10 0,0 0))", - "F11FFF212"); - - // polygons with some ring equal to the linestring - test_geometry("LINESTRING(0 0,10 0,10 10,0 10,0 0)", - "POLYGON((0 0,0 10,10 10,10 0,0 0))", - "F1FFFF2F2"); - test_geometry("LINESTRING(0 0,10 0,10 10,0 10,0 0)", - "POLYGON((0 0,0 10,10 10,10 0,0 0),(2 2,5 5,2 8,2 2))", - "F1FFFF212"); - test_geometry("LINESTRING(2 2,5 5,2 8,2 2)", - "POLYGON((0 0,0 10,10 10,10 0,0 0),(2 2,5 5,2 8,2 2))", - "F1FFFF212"); - - // self-IP going on the boundary then into the exterior and to the boundary again - test_geometry("LINESTRING(2 10,5 10,5 15,6 15,5 10,8 10)", "POLYGON((0 0,0 10,10 10,10 0,0 0))", - "F11F0F212"); - // self-IP going on the boundary then into the interior and to the boundary again - test_geometry("LINESTRING(2 10,5 10,5 5,6 5,5 10,8 10)", "POLYGON((0 0,0 10,10 10,10 0,0 0))", - "11FF0F212"); - - // ccw - { - typedef bg::model::polygon ccwpoly; - - // IE IB0 II - test_geometry("LINESTRING(11 1,10 5,5 5)", "POLYGON((0 0,10 0,10 10,0 10,0 0))", "1010F0212"); - // IE IB1 II - test_geometry("LINESTRING(11 1,10 1,10 5,5 5)", "POLYGON((0 0,10 0,10 10,0 10,0 0))", "1110F0212"); - test_geometry("LINESTRING(11 1,10 5,10 1,5 5)", "POLYGON((0 0,10 0,10 10,0 10,0 0))", "1110F0212"); - // II IB0 IE - test_geometry("LINESTRING(5 1,10 5,11 1)", "POLYGON((0 0,10 0,10 10,0 10,0 0))", "1010F0212"); - // IE IB1 II - test_geometry("LINESTRING(5 5,10 1,10 5,11 5)", "POLYGON((0 0,10 0,10 10,0 10,0 0))", "1110F0212"); - test_geometry("LINESTRING(5 5,10 5,10 1,11 5)", "POLYGON((0 0,10 0,10 10,0 10,0 0))", "1110F0212"); - - } - -} - -template -void test_linestring_multi_polygon() -{ - typedef bg::model::linestring

ls; - typedef bg::model::polygon

poly; - typedef bg::model::multi_polygon mpoly; - - test_geometry("LINESTRING(10 1,10 5,10 9)", - "MULTIPOLYGON(((0 20,0 30,10 30,10 20,0 20)),((0 0,0 10,10 10,10 0,0 0),(10 5,2 8,2 2,10 5)))", - "F1FF0F212"); - test_geometry("LINESTRING(10 1,10 5,10 9)", - "MULTIPOLYGON(((0 20,0 30,10 30,10 20,0 20)),((0 0,0 10,10 10,10 0,0 0)))", - "F1FF0F212"); - - test_geometry("LINESTRING(10 1,10 5,2 2)", - "MULTIPOLYGON(((0 20,0 30,10 30,10 20,0 20)),((0 0,0 10,10 10,10 0,0 0),(10 5,2 8,2 2,10 5)))", - "F1FF0F212"); - test_geometry("LINESTRING(10 1,10 5,2 2)", - "MULTIPOLYGON(((0 20,0 30,10 30,10 20,0 20)),((0 0,0 10,10 10,10 0,0 0)))", - "11F00F212"); - - test_geometry("LINESTRING(10 1,10 5,2 2)", - "MULTIPOLYGON(((0 0,0 10,10 10,10 0,0 0),(10 5,2 8,2 2,10 5)),((10 5,3 3,3 7,10 5)))", - "F1FF0F212"); - test_geometry("LINESTRING(10 1,10 5,2 8)", - "MULTIPOLYGON(((0 0,0 10,10 10,10 0,0 0),(10 5,2 8,2 2,10 5)),((10 5,3 3,3 7,10 5)))", - "F1FF0F212"); - test_geometry("LINESTRING(10 1,10 5,3 3)", - "MULTIPOLYGON(((0 0,0 10,10 10,10 0,0 0),(10 5,2 8,2 2,10 5)),((10 5,3 3,3 7,10 5)))", - "F1FF0F212"); - test_geometry("LINESTRING(10 1,10 5,3 7)", - "MULTIPOLYGON(((0 0,0 10,10 10,10 0,0 0),(10 5,2 8,2 2,10 5)),((10 5,3 3,3 7,10 5)))", - "F1FF0F212"); - test_geometry("LINESTRING(10 1,10 5,5 5)", - "MULTIPOLYGON(((0 0,0 10,10 10,10 0,0 0),(10 5,2 8,2 2,10 5)),((10 5,3 3,3 7,10 5)))", - "11F00F212"); - - test_geometry("LINESTRING(0 0,10 0,10 10,0 10,0 0)", - "MULTIPOLYGON(((0 0,0 10,10 10,10 0,0 0)),((20 0,20 10,30 20,20 0)))", - "F1FFFF212"); -} - -template -void test_multi_linestring_multi_polygon() -{ - typedef bg::model::linestring

ls; - typedef bg::model::polygon

poly; - typedef bg::model::multi_linestring mls; - typedef bg::model::multi_polygon mpoly; - - // polygons with some ring equal to the linestrings - test_geometry("MULTILINESTRING((0 0,10 0,10 10,0 10,0 0),(20 20,50 50,20 80,20 20))", - "MULTIPOLYGON(((0 0,0 10,10 10,10 0,0 0)))", - "F11FFF2F2"); - - test_geometry("MULTILINESTRING((0 0,10 0,10 10,0 10,0 0),(2 2,5 5,2 8,2 2))", - "MULTIPOLYGON(((0 0,0 10,10 10,10 0,0 0),(2 2,5 5,2 8,2 2)))", - "F1FFFF2F2"); - - - test_geometry("MULTILINESTRING((0 0,10 0,10 10),(10 10,0 10,0 0))", - "MULTIPOLYGON(((0 0,0 10,10 10,10 0,0 0)))", - "F1FFFF2F2"); - test_geometry("MULTILINESTRING((0 0,10 0,10 10),(10 10,0 10,0 0),(20 20,50 50,20 80,20 20))", - "MULTIPOLYGON(((0 0,0 10,10 10,10 0,0 0)))", - "F11FFF2F2"); - - // disjoint - test_geometry("MULTILINESTRING((20 20,30 30),(30 30,40 40))", - "MULTIPOLYGON(((0 0,0 10,10 10,10 0,0 0)))", - "FF1FF0212"); -} - -template -void polygon_polygon() -{ - typedef bg::model::polygon

poly; - typedef bg::model::ring

ring; - - // touching - test_geometry("POLYGON((0 0,0 10,10 10,10 0,0 0))", - "POLYGON((10 0,10 10,20 10,20 0,10 0))", - "FF2F11212"); - test_geometry("POLYGON((0 0,0 10,10 10,10 0,0 0))", - "POLYGON((0 -10,0 0,10 0,10 -10,0 -10))", - "FF2F11212"); - test_geometry("POLYGON((0 0,0 10,10 10,10 0,0 0))", - "POLYGON((10 0,15 10,20 10,20 0,10 0))", - "FF2F01212"); - - // containing - test_geometry("POLYGON((0 0,0 10,10 10,10 0,0 0))", - "POLYGON((5 5,5 10,6 10,6 5,5 5))", - "212F11FF2"); - test_geometry("POLYGON((0 0,0 10,10 10,10 0,0 0))", - "POLYGON((5 5,5 10,6 5,5 5))", - "212F01FF2"); - test_geometry("POLYGON((0 0,0 10,10 10,10 0,0 0))", - "POLYGON((5 5,5 6,6 6,6 5,5 5))", - "212FF1FF2"); - - // fully containing - test_geometry("POLYGON((0 0,0 10,10 10,10 0,0 0))", - "POLYGON((5 5,5 9,6 9,6 5,5 5))", - "212FF1FF2"); - // fully containing, with a hole - test_geometry("POLYGON((0 0,0 10,10 10,10 0,0 0),(3 3,7 3,7 7,3 7,3 3))", - "POLYGON((1 1,1 9,9 9,9 1,1 1))", - "2121F12F2"); - // fully containing, both with holes - test_geometry("POLYGON((0 0,0 10,10 10,10 0,0 0),(3 3,7 3,7 7,3 7,3 3))", - "POLYGON((1 1,1 9,9 9,9 1,1 1),(2 2,8 2,8 8,2 8,2 2))", - "212FF1FF2"); - // fully containing, both with holes - test_geometry("POLYGON((0 0,0 10,10 10,10 0,0 0),(3 3,7 3,7 7,3 7,3 3))", - "POLYGON((1 1,1 9,9 9,9 1,1 1),(4 4,6 4,6 6,4 6,4 4))", - "2121F1212"); - - // overlapping - test_geometry("POLYGON((0 0,0 10,10 10,10 0,0 0))", - "POLYGON((5 0,5 10,20 10,20 0,5 0))", - "212111212"); - test_geometry("POLYGON((0 0,0 10,10 10,10 0,0 0))", - "POLYGON((5 0,5 10,20 10,20 0,5 0))", - "212111212"); - test_geometry("POLYGON((0 0,0 10,10 10,10 0,0 0))", - "POLYGON((5 0,5 10,20 10,20 0,5 0))", - "212111212"); - test_geometry("POLYGON((0 0,0 10,10 10,15 5,10 0,0 0))", - "POLYGON((10 0,5 5,10 10,20 10,20 0,10 0))", - "212101212"); - - // equal - test_geometry("POLYGON((0 0,0 10,10 10,10 0,0 0))", - "POLYGON((10 10,10 5,10 0,5 0,0 0,0 10,5 10,10 10))", - "2FFF1FFF2"); - // hole-sized - test_geometry("POLYGON((0 0,0 10,10 10,10 0,0 0),(5 5,6 5,6 6,5 6,5 5))", - "POLYGON((5 5,5 6,6 6,6 5,5 5))", - "FF2F112F2"); - - // disjoint - test_geometry("POLYGON((0 0,0 10,10 10,10 0,0 0))", - "POLYGON((0 20,0 30,10 30,10 20,0 20))", - "FF2FF1212"); - // disjoint - test_geometry("POLYGON((0 0,0 10,10 10,10 0,0 0),(3 3,7 3,7 7,3 7,3 3))", - "POLYGON((0 20,0 30,10 30,10 20,0 20))", - "FF2FF1212"); - - // equal non-simple / non-simple hole - test_geometry("POLYGON((0 0,0 10,10 10,10 0,0 0),(5 5,10 5,5 6,5 5))", - "POLYGON((0 0,0 10,10 10,10 5,5 6,5 5,10 5,10 0,0 0))", - "2FFF1FFF2"); - - // within non-simple / simple - test_geometry("POLYGON((0 0,0 10,10 10,10 5,5 6,5 5,10 5,10 0,0 0))", - "POLYGON((0 0,5 5,10 5,10 0,0 0))", - "212F11FF2"); - // within non-simple hole / simple - test_geometry("POLYGON((0 0,0 10,10 10,10 0,0 0),(5 5,10 5,5 6,5 5))", - "POLYGON((0 0,5 5,10 5,10 0,0 0))", - "212F11FF2"); - - - // not within non-simple / simple - test_geometry("POLYGON((0 0,0 10,10 10,10 5,5 6,5 5,10 5,10 0,0 0))", - "POLYGON((0 0,0 10,10 10,10 0,0 0))", - "2FF11F2F2"); - // not within non-simple hole / simple - test_geometry("POLYGON((0 0,0 10,10 10,10 0,0 0),(5 5,10 5,5 6,5 5))", - "POLYGON((0 0,0 10,10 10,10 0,0 0))", - "2FF11F2F2"); - // not within simple hole / simple - test_geometry("POLYGON((0 0,0 10,10 10,10 0,0 0),(5 5,9 5,5 6,5 5))", - "POLYGON((0 0,0 10,10 10,9 5,10 0,0 0))", - "2121112F2"); - - // within non-simple fake hole / simple - test_geometry("POLYGON((0 0,0 10,10 10,10 5,4 7,4 3,10 5,10 0,0 0))", - "POLYGON((0 0,0 10,10 10,10 0,0 0))", - "2FF11F2F2"); - // within non-simple fake hole / non-simple fake hole - test_geometry("POLYGON((0 0,0 10,10 10,10 5,4 7,4 3,10 5,10 0,0 0))", - "POLYGON((0 0,0 10,10 10,10 5,5 6,5 4,10 5,10 0,0 0))", - "2FF11F212"); - // within non-simple fake hole / non-simple hole - test_geometry("POLYGON((0 0,0 10,10 10,10 5,4 7,4 3,10 5,10 0,0 0))", - "POLYGON((0 0,0 10,10 10,10 0,0 0),(10 5,5 6,5 4,10 5))", - "2FF11F212"); - // containing non-simple fake hole / non-simple hole - test_geometry("POLYGON((0 0,0 10,10 10,10 5,4 7,4 3,10 5,10 0,0 0))", - "POLYGON((0 0,0 10,10 10,10 0,0 0),(10 5,3 8,3 2,10 5))", - "212F11FF2"); - - // within non-simple hole / simple - test_geometry("POLYGON((0 0,0 10,10 10,10 0,0 0),(10 5,4 7,4 3,10 5))", - "POLYGON((0 0,0 10,10 10,10 0,0 0))", - "2FF11F2F2"); - // within non-simple hole / non-simple fake hole - test_geometry("POLYGON((0 0,0 10,10 10,10 0,0 0),(10 5,4 7,4 3,10 5))", - "POLYGON((0 0,0 10,10 10,10 5,5 6,5 4,10 5,10 0,0 0))", - "2FF11F212"); - // containing non-simple hole / non-simple fake hole - test_geometry("POLYGON((0 0,0 10,10 10,10 0,0 0),(10 5,4 7,4 3,10 5))", - "POLYGON((0 0,0 10,10 10,10 5,3 8,3 2,10 5,10 0,0 0))", - "212F11FF2"); - // equal non-simple hole / non-simple fake hole - test_geometry("POLYGON((0 0,0 10,10 10,10 0,0 0),(10 5,4 7,4 3,10 5))", - "POLYGON((0 0,0 10,10 10,10 5,4 7,4 3,10 5,10 0,0 0))", - "2FFF1FFF2"); - // within non-simple hole / non-simple hole - test_geometry("POLYGON((0 0,0 10,10 10,10 0,0 0),(10 5,4 7,4 3,10 5))", - "POLYGON((0 0,0 10,10 10,10 0,0 0),(10 5,5 6,5 4,10 5))", - "2FF11F212"); - // containing non-simple hole / non-simple hole - test_geometry("POLYGON((0 0,0 10,10 10,10 0,0 0),(10 5,4 7,4 3,10 5))", - "POLYGON((0 0,0 10,10 10,10 0,0 0),(10 5,3 8,3 2,10 5))", - "212F11FF2"); - // equal non-simple hole / non-simple hole - test_geometry("POLYGON((0 0,0 10,10 10,10 0,0 0),(10 5,4 7,4 3,10 5))", - "POLYGON((0 0,0 10,10 10,10 0,0 0),(10 5,4 7,4 3,10 5))", - "2FFF1FFF2"); - - // intersecting non-simple hole / non-simple hole - touching holes - test_geometry("POLYGON((0 0,0 10,10 10,10 0,0 0),(5 5,10 5,5 6,5 5))", - "POLYGON((0 0,0 10,10 10,10 0,0 0),(0 5,5 4,5 5,0 5))", - "21211F2F2"); - // intersecting non-simple fake hole / non-simple hole - touching holes - test_geometry("POLYGON((0 0,0 10,10 10,10 5,5 6,5 5,10 5,10 0,0 0))", - "POLYGON((0 0,0 10,10 10,10 0,0 0),(0 5,5 4,5 5,0 5))", - "21211F2F2"); - // intersecting non-simple fake hole / non-simple fake hole - touching holes - test_geometry("POLYGON((0 0,0 10,10 10,10 5,5 6,5 5,10 5,10 0,0 0))", - "POLYGON((0 0,0 5,5 4,5 5,0 5,0 10,10 10,10 0,0 0))", - "21211F2F2"); - - // intersecting simple - i/i - test_geometry("POLYGON((0 0,0 10,4 10,6 8,5 5,6 2,4 0,0 0))", - "POLYGON((5 5,4 8,6 10,10 10,10 0,6 0,4 2,5 5))", - "212101212"); - // intersecting non-simple hole / non-simple hole - i/i - test_geometry("POLYGON((0 0,0 10,4 10,6 8,5 5,6 2,4 0,0 0),(5 5,2 6,2 4,5 5))", - "POLYGON((5 5,4 8,6 10,10 10,10 0,6 0,4 2,5 5),(5 5,8 4,8 6,5 5))", - "212101212"); - // intersecting non-simple hole / simple - i/i - test_geometry("POLYGON((0 0,0 10,4 10,6 8,5 5,6 2,4 0,0 0),(5 5,2 6,2 4,5 5))", - "POLYGON((5 5,4 8,6 10,10 10,10 0,6 0,4 2,5 5))", - "212101212"); - - // no turns - disjoint inside a hole - test_geometry("POLYGON((0 0,0 10,10 10,10 0,0 0),(1 1,9 1,9 9,1 9,1 1))", - "POLYGON((3 3,3 7,7 7,7 3,3 3))", - "FF2FF1212"); - // no turns - within - test_geometry("POLYGON((0 0,0 10,10 10,10 0,0 0),(1 1,9 1,9 9,1 9,1 1))", - "POLYGON((-1 -1,-1 11,11 11,11 -1,-1 -1))", - "2FF1FF212"); - // no-turns - intersects - test_geometry("POLYGON((0 0,0 10,10 10,10 0,0 0),(2 2,8 2,8 8,2 8,2 2))", - "POLYGON((1 1,1 9,9 9,9 1,1 1))", - "2121F12F2"); - // no-turns - intersects, hole in a hole - test_geometry("POLYGON((0 0,0 10,10 10,10 0,0 0),(2 2,8 2,8 8,2 8,2 2))", - "POLYGON((1 1,1 9,9 9,9 1,1 1),(3 3,7 3,7 7,3 7,3 3))", - "2121F1212"); - - // no-turns ring - for exteriors - test_geometry("POLYGON((0 0,0 10,10 10,10 0,0 0),(2 2,8 2,8 8,2 8,2 2))", - "POLYGON((1 1,1 9,9 9,9 1,1 1),(2 2,8 2,8 8,2 8,2 2))", - "212F11FF2"); - // no-turns ring - for interiors - test_geometry("POLYGON((0 0,0 10,10 10,10 0,0 0),(3 3,7 3,7 7,3 7,3 3))", - "POLYGON((0 0,0 10,10 10,10 0,0 0),(2 2,8 2,8 8,2 8,2 2))", - "212F11FF2"); - - { - test_geometry("POLYGON((0 0,0 10,10 10,10 0,0 0))", - "POLYGON((5 5,5 10,6 10,6 5,5 5))", - "212F11FF2"); - - test_geometry("POLYGON((0 0,0 10,10 10,10 0,0 0))", - "POLYGON((10 0,10 10,20 10,20 0,10 0))", - "FF2F11212"); - - namespace bgdr = bg::detail::relate; - poly p1, p2, p3; - bg::read_wkt("POLYGON((0 0,0 10,10 10,10 0,0 0))", p1); - bg::read_wkt("POLYGON((10 0,10 10,20 10,20 0,10 0))", p2); - bg::read_wkt("POLYGON((5 5,5 10,6 10,6 5,5 5))", p3); - BOOST_CHECK(bgdr::relate(p1, p2, bgdr::mask9("FT*******") - || bgdr::mask9("F**T*****") - || bgdr::mask9("F***T****"))); // touches() - BOOST_CHECK(bgdr::relate(p1, p3, bgdr::mask9("T*****FF*"))); // contains() - BOOST_CHECK(bgdr::relate(p2, p3, bgdr::mask9("FF*FF****"))); // disjoint() - } - - // CCW - { - typedef bg::model::polygon poly; - // within non-simple hole / simple - test_geometry("POLYGON((0 0,10 0,10 10,0 10,0 0),(5 5,5 6,10 5,5 5))", - "POLYGON((0 0,10 0,10 5,5 5,0 0))", - "212F11FF2"); - } - // OPEN - { - typedef bg::model::polygon poly; - // within non-simple hole / simple - test_geometry("POLYGON((0 0,0 10,10 10,10 0),(5 5,10 5,5 6))", - "POLYGON((0 0,5 5,10 5,10 0))", - "212F11FF2"); - } - // CCW, OPEN - { - typedef bg::model::polygon poly; - // within non-simple hole / simple - test_geometry("POLYGON((0 0,10 0,10 10,0 10),(5 5,5 6,10 5))", - "POLYGON((0 0,10 0,10 5,5 5))", - "212F11FF2"); - } -} - -template -void polygon_multi_polygon() -{ - typedef bg::model::polygon

poly; - typedef bg::model::ring

ring; - typedef bg::model::multi_polygon mpoly; - - test_geometry("POLYGON((0 0,0 10,10 10,10 0,0 0))", - "MULTIPOLYGON(((5 5,5 10,6 10,6 5,5 5)),((0 20,0 30,10 30,10 20,0 20)))", - "212F11212"); - test_geometry("POLYGON((0 0,0 10,10 10,10 0,0 0))", - "MULTIPOLYGON(((5 5,5 10,6 10,6 5,5 5)),((0 20,0 30,10 30,10 20,0 20)))", - "212F11212"); -} - -template -void multi_polygon_multi_polygon() -{ - typedef bg::model::polygon

poly; - typedef bg::model::multi_polygon mpoly; - - test_geometry("MULTIPOLYGON(((0 0,0 10,10 10,10 0,0 0)))", - "MULTIPOLYGON(((5 5,5 10,6 10,6 5,5 5)),((0 20,0 30,10 30,10 20,0 20)))", - "212F11212"); - test_geometry("MULTIPOLYGON(((0 0,0 10,10 10,10 0,0 0)),((0 20,0 30,10 30,10 20,0 20)))", - "MULTIPOLYGON(((5 5,5 10,6 10,6 5,5 5)))", - "212F11FF2"); - - test_geometry("MULTIPOLYGON(((0 0,0 10,10 10,10 0,0 0)))", - "MULTIPOLYGON(((5 5,5 6,6 6,6 5,5 5)),((0 20,0 30,10 30,10 20,0 20)))", - "212FF1212"); - test_geometry("MULTIPOLYGON(((0 0,0 10,10 10,10 0,0 0)),((0 20,0 30,10 30,10 20,0 20)))", - "MULTIPOLYGON(((5 5,5 6,6 6,6 5,5 5)))", - "212FF1FF2"); -} - -template -void test_all() -{ - test_point_point

(); - test_point_multipoint

(); - test_multipoint_multipoint

(); - test_point_linestring

(); - test_point_multilinestring

(); - test_linestring_linestring

(); - test_linestring_multi_linestring

(); - test_multi_linestring_multi_linestring

(); - test_linestring_polygon

(); - test_linestring_multi_polygon

(); - test_multi_linestring_multi_polygon

(); - polygon_polygon

(); - polygon_multi_polygon

(); - multi_polygon_multi_polygon

(); -} - -int test_main( int , char* [] ) -{ - test_all >(); - test_all >(); - -#if defined(HAVE_TTMATH) - test_all >(); -#endif - - return 0; -} diff --git a/test/algorithms/relate_areal_areal.cpp b/test/algorithms/relate_areal_areal.cpp new file mode 100644 index 000000000..761ad89cb --- /dev/null +++ b/test/algorithms/relate_areal_areal.cpp @@ -0,0 +1,326 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. + +// This file was modified by Oracle on 2013, 2014. +// Modifications copyright (c) 2013-2014 Oracle and/or its affiliates. + +// 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) + +// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle + +#include + +#include +#include + +//TEST +//#include + +template +void test_polygon_polygon() +{ + typedef bg::model::polygon

poly; + typedef bg::model::ring

ring; + + // touching + test_geometry("POLYGON((0 0,0 10,10 10,10 0,0 0))", + "POLYGON((10 0,10 10,20 10,20 0,10 0))", + "FF2F11212"); + test_geometry("POLYGON((0 0,0 10,10 10,10 0,0 0))", + "POLYGON((0 -10,0 0,10 0,10 -10,0 -10))", + "FF2F11212"); + test_geometry("POLYGON((0 0,0 10,10 10,10 0,0 0))", + "POLYGON((10 0,15 10,20 10,20 0,10 0))", + "FF2F01212"); + + // containing + test_geometry("POLYGON((0 0,0 10,10 10,10 0,0 0))", + "POLYGON((5 5,5 10,6 10,6 5,5 5))", + "212F11FF2"); + test_geometry("POLYGON((0 0,0 10,10 10,10 0,0 0))", + "POLYGON((5 5,5 10,6 5,5 5))", + "212F01FF2"); + test_geometry("POLYGON((0 0,0 10,10 10,10 0,0 0))", + "POLYGON((5 5,5 6,6 6,6 5,5 5))", + "212FF1FF2"); + + // fully containing + test_geometry("POLYGON((0 0,0 10,10 10,10 0,0 0))", + "POLYGON((5 5,5 9,6 9,6 5,5 5))", + "212FF1FF2"); + // fully containing, with a hole + test_geometry("POLYGON((0 0,0 10,10 10,10 0,0 0),(3 3,7 3,7 7,3 7,3 3))", + "POLYGON((1 1,1 9,9 9,9 1,1 1))", + "2121F12F2"); + // fully containing, both with holes + test_geometry("POLYGON((0 0,0 10,10 10,10 0,0 0),(3 3,7 3,7 7,3 7,3 3))", + "POLYGON((1 1,1 9,9 9,9 1,1 1),(2 2,8 2,8 8,2 8,2 2))", + "212FF1FF2"); + // fully containing, both with holes + test_geometry("POLYGON((0 0,0 10,10 10,10 0,0 0),(3 3,7 3,7 7,3 7,3 3))", + "POLYGON((1 1,1 9,9 9,9 1,1 1),(4 4,6 4,6 6,4 6,4 4))", + "2121F1212"); + + // overlapping + test_geometry("POLYGON((0 0,0 10,10 10,10 0,0 0))", + "POLYGON((5 0,5 10,20 10,20 0,5 0))", + "212111212"); + test_geometry("POLYGON((0 0,0 10,10 10,10 0,0 0))", + "POLYGON((5 0,5 10,20 10,20 0,5 0))", + "212111212"); + test_geometry("POLYGON((0 0,0 10,10 10,10 0,0 0))", + "POLYGON((5 0,5 10,20 10,20 0,5 0))", + "212111212"); + test_geometry("POLYGON((0 0,0 10,10 10,15 5,10 0,0 0))", + "POLYGON((10 0,5 5,10 10,20 10,20 0,10 0))", + "212101212"); + + // equal + test_geometry("POLYGON((0 0,0 10,10 10,10 0,0 0))", + "POLYGON((10 10,10 5,10 0,5 0,0 0,0 10,5 10,10 10))", + "2FFF1FFF2"); + // hole-sized + test_geometry("POLYGON((0 0,0 10,10 10,10 0,0 0),(5 5,6 5,6 6,5 6,5 5))", + "POLYGON((5 5,5 6,6 6,6 5,5 5))", + "FF2F112F2"); + + // disjoint + test_geometry("POLYGON((0 0,0 10,10 10,10 0,0 0))", + "POLYGON((0 20,0 30,10 30,10 20,0 20))", + "FF2FF1212"); + // disjoint + test_geometry("POLYGON((0 0,0 10,10 10,10 0,0 0),(3 3,7 3,7 7,3 7,3 3))", + "POLYGON((0 20,0 30,10 30,10 20,0 20))", + "FF2FF1212"); + + // equal non-simple / non-simple hole + test_geometry("POLYGON((0 0,0 10,10 10,10 0,0 0),(5 5,10 5,5 6,5 5))", + "POLYGON((0 0,0 10,10 10,10 5,5 6,5 5,10 5,10 0,0 0))", + "2FFF1FFF2"); + + // within non-simple / simple + test_geometry("POLYGON((0 0,0 10,10 10,10 5,5 6,5 5,10 5,10 0,0 0))", + "POLYGON((0 0,5 5,10 5,10 0,0 0))", + "212F11FF2"); + // within non-simple hole / simple + test_geometry("POLYGON((0 0,0 10,10 10,10 0,0 0),(5 5,10 5,5 6,5 5))", + "POLYGON((0 0,5 5,10 5,10 0,0 0))", + "212F11FF2"); + + + // not within non-simple / simple + test_geometry("POLYGON((0 0,0 10,10 10,10 5,5 6,5 5,10 5,10 0,0 0))", + "POLYGON((0 0,0 10,10 10,10 0,0 0))", + "2FF11F2F2"); + // not within non-simple hole / simple + test_geometry("POLYGON((0 0,0 10,10 10,10 0,0 0),(5 5,10 5,5 6,5 5))", + "POLYGON((0 0,0 10,10 10,10 0,0 0))", + "2FF11F2F2"); + // not within simple hole / simple + test_geometry("POLYGON((0 0,0 10,10 10,10 0,0 0),(5 5,9 5,5 6,5 5))", + "POLYGON((0 0,0 10,10 10,9 5,10 0,0 0))", + "2121112F2"); + + // within non-simple fake hole / simple + test_geometry("POLYGON((0 0,0 10,10 10,10 5,4 7,4 3,10 5,10 0,0 0))", + "POLYGON((0 0,0 10,10 10,10 0,0 0))", + "2FF11F2F2"); + // within non-simple fake hole / non-simple fake hole + test_geometry("POLYGON((0 0,0 10,10 10,10 5,4 7,4 3,10 5,10 0,0 0))", + "POLYGON((0 0,0 10,10 10,10 5,5 6,5 4,10 5,10 0,0 0))", + "2FF11F212"); + // within non-simple fake hole / non-simple hole + test_geometry("POLYGON((0 0,0 10,10 10,10 5,4 7,4 3,10 5,10 0,0 0))", + "POLYGON((0 0,0 10,10 10,10 0,0 0),(10 5,5 6,5 4,10 5))", + "2FF11F212"); + // containing non-simple fake hole / non-simple hole + test_geometry("POLYGON((0 0,0 10,10 10,10 5,4 7,4 3,10 5,10 0,0 0))", + "POLYGON((0 0,0 10,10 10,10 0,0 0),(10 5,3 8,3 2,10 5))", + "212F11FF2"); + + // within non-simple hole / simple + test_geometry("POLYGON((0 0,0 10,10 10,10 0,0 0),(10 5,4 7,4 3,10 5))", + "POLYGON((0 0,0 10,10 10,10 0,0 0))", + "2FF11F2F2"); + // within non-simple hole / non-simple fake hole + test_geometry("POLYGON((0 0,0 10,10 10,10 0,0 0),(10 5,4 7,4 3,10 5))", + "POLYGON((0 0,0 10,10 10,10 5,5 6,5 4,10 5,10 0,0 0))", + "2FF11F212"); + // containing non-simple hole / non-simple fake hole + test_geometry("POLYGON((0 0,0 10,10 10,10 0,0 0),(10 5,4 7,4 3,10 5))", + "POLYGON((0 0,0 10,10 10,10 5,3 8,3 2,10 5,10 0,0 0))", + "212F11FF2"); + // equal non-simple hole / non-simple fake hole + test_geometry("POLYGON((0 0,0 10,10 10,10 0,0 0),(10 5,4 7,4 3,10 5))", + "POLYGON((0 0,0 10,10 10,10 5,4 7,4 3,10 5,10 0,0 0))", + "2FFF1FFF2"); + // within non-simple hole / non-simple hole + test_geometry("POLYGON((0 0,0 10,10 10,10 0,0 0),(10 5,4 7,4 3,10 5))", + "POLYGON((0 0,0 10,10 10,10 0,0 0),(10 5,5 6,5 4,10 5))", + "2FF11F212"); + // containing non-simple hole / non-simple hole + test_geometry("POLYGON((0 0,0 10,10 10,10 0,0 0),(10 5,4 7,4 3,10 5))", + "POLYGON((0 0,0 10,10 10,10 0,0 0),(10 5,3 8,3 2,10 5))", + "212F11FF2"); + // equal non-simple hole / non-simple hole + test_geometry("POLYGON((0 0,0 10,10 10,10 0,0 0),(10 5,4 7,4 3,10 5))", + "POLYGON((0 0,0 10,10 10,10 0,0 0),(10 5,4 7,4 3,10 5))", + "2FFF1FFF2"); + + // intersecting non-simple hole / non-simple hole - touching holes + test_geometry("POLYGON((0 0,0 10,10 10,10 0,0 0),(5 5,10 5,5 6,5 5))", + "POLYGON((0 0,0 10,10 10,10 0,0 0),(0 5,5 4,5 5,0 5))", + "21211F2F2"); + // intersecting non-simple fake hole / non-simple hole - touching holes + test_geometry("POLYGON((0 0,0 10,10 10,10 5,5 6,5 5,10 5,10 0,0 0))", + "POLYGON((0 0,0 10,10 10,10 0,0 0),(0 5,5 4,5 5,0 5))", + "21211F2F2"); + // intersecting non-simple fake hole / non-simple fake hole - touching holes + test_geometry("POLYGON((0 0,0 10,10 10,10 5,5 6,5 5,10 5,10 0,0 0))", + "POLYGON((0 0,0 5,5 4,5 5,0 5,0 10,10 10,10 0,0 0))", + "21211F2F2"); + + // intersecting simple - i/i + test_geometry("POLYGON((0 0,0 10,4 10,6 8,5 5,6 2,4 0,0 0))", + "POLYGON((5 5,4 8,6 10,10 10,10 0,6 0,4 2,5 5))", + "212101212"); + // intersecting non-simple hole / non-simple hole - i/i + test_geometry("POLYGON((0 0,0 10,4 10,6 8,5 5,6 2,4 0,0 0),(5 5,2 6,2 4,5 5))", + "POLYGON((5 5,4 8,6 10,10 10,10 0,6 0,4 2,5 5),(5 5,8 4,8 6,5 5))", + "212101212"); + // intersecting non-simple hole / simple - i/i + test_geometry("POLYGON((0 0,0 10,4 10,6 8,5 5,6 2,4 0,0 0),(5 5,2 6,2 4,5 5))", + "POLYGON((5 5,4 8,6 10,10 10,10 0,6 0,4 2,5 5))", + "212101212"); + + // no turns - disjoint inside a hole + test_geometry("POLYGON((0 0,0 10,10 10,10 0,0 0),(1 1,9 1,9 9,1 9,1 1))", + "POLYGON((3 3,3 7,7 7,7 3,3 3))", + "FF2FF1212"); + // no turns - within + test_geometry("POLYGON((0 0,0 10,10 10,10 0,0 0),(1 1,9 1,9 9,1 9,1 1))", + "POLYGON((-1 -1,-1 11,11 11,11 -1,-1 -1))", + "2FF1FF212"); + // no-turns - intersects + test_geometry("POLYGON((0 0,0 10,10 10,10 0,0 0),(2 2,8 2,8 8,2 8,2 2))", + "POLYGON((1 1,1 9,9 9,9 1,1 1))", + "2121F12F2"); + // no-turns - intersects, hole in a hole + test_geometry("POLYGON((0 0,0 10,10 10,10 0,0 0),(2 2,8 2,8 8,2 8,2 2))", + "POLYGON((1 1,1 9,9 9,9 1,1 1),(3 3,7 3,7 7,3 7,3 3))", + "2121F1212"); + + // no-turns ring - for exteriors + test_geometry("POLYGON((0 0,0 10,10 10,10 0,0 0),(2 2,8 2,8 8,2 8,2 2))", + "POLYGON((1 1,1 9,9 9,9 1,1 1),(2 2,8 2,8 8,2 8,2 2))", + "212F11FF2"); + // no-turns ring - for interiors + test_geometry("POLYGON((0 0,0 10,10 10,10 0,0 0),(3 3,7 3,7 7,3 7,3 3))", + "POLYGON((0 0,0 10,10 10,10 0,0 0),(2 2,8 2,8 8,2 8,2 2))", + "212F11FF2"); + + { + test_geometry("POLYGON((0 0,0 10,10 10,10 0,0 0))", + "POLYGON((5 5,5 10,6 10,6 5,5 5))", + "212F11FF2"); + + test_geometry("POLYGON((0 0,0 10,10 10,10 0,0 0))", + "POLYGON((10 0,10 10,20 10,20 0,10 0))", + "FF2F11212"); + + namespace bgdr = bg::detail::relate; + poly p1, p2, p3; + bg::read_wkt("POLYGON((0 0,0 10,10 10,10 0,0 0))", p1); + bg::read_wkt("POLYGON((10 0,10 10,20 10,20 0,10 0))", p2); + bg::read_wkt("POLYGON((5 5,5 10,6 10,6 5,5 5))", p3); + BOOST_CHECK(bgdr::relate(p1, p2, bgdr::mask9("FT*******") + || bgdr::mask9("F**T*****") + || bgdr::mask9("F***T****"))); // touches() + BOOST_CHECK(bgdr::relate(p1, p3, bgdr::mask9("T*****FF*"))); // contains() + BOOST_CHECK(bgdr::relate(p2, p3, bgdr::mask9("FF*FF****"))); // disjoint() + } + + // CCW + { + typedef bg::model::polygon poly; + // within non-simple hole / simple + test_geometry("POLYGON((0 0,10 0,10 10,0 10,0 0),(5 5,5 6,10 5,5 5))", + "POLYGON((0 0,10 0,10 5,5 5,0 0))", + "212F11FF2"); + } + // OPEN + { + typedef bg::model::polygon poly; + // within non-simple hole / simple + test_geometry("POLYGON((0 0,0 10,10 10,10 0),(5 5,10 5,5 6))", + "POLYGON((0 0,5 5,10 5,10 0))", + "212F11FF2"); + } + // CCW, OPEN + { + typedef bg::model::polygon poly; + // within non-simple hole / simple + test_geometry("POLYGON((0 0,10 0,10 10,0 10),(5 5,5 6,10 5))", + "POLYGON((0 0,10 0,10 5,5 5))", + "212F11FF2"); + } +} + +template +void test_polygon_multi_polygon() +{ + typedef bg::model::polygon

poly; + typedef bg::model::ring

ring; + typedef bg::model::multi_polygon mpoly; + + test_geometry("POLYGON((0 0,0 10,10 10,10 0,0 0))", + "MULTIPOLYGON(((5 5,5 10,6 10,6 5,5 5)),((0 20,0 30,10 30,10 20,0 20)))", + "212F11212"); + test_geometry("POLYGON((0 0,0 10,10 10,10 0,0 0))", + "MULTIPOLYGON(((5 5,5 10,6 10,6 5,5 5)),((0 20,0 30,10 30,10 20,0 20)))", + "212F11212"); +} + +template +void test_multi_polygon_multi_polygon() +{ + typedef bg::model::polygon

poly; + typedef bg::model::multi_polygon mpoly; + + test_geometry("MULTIPOLYGON(((0 0,0 10,10 10,10 0,0 0)))", + "MULTIPOLYGON(((5 5,5 10,6 10,6 5,5 5)),((0 20,0 30,10 30,10 20,0 20)))", + "212F11212"); + test_geometry("MULTIPOLYGON(((0 0,0 10,10 10,10 0,0 0)),((0 20,0 30,10 30,10 20,0 20)))", + "MULTIPOLYGON(((5 5,5 10,6 10,6 5,5 5)))", + "212F11FF2"); + + test_geometry("MULTIPOLYGON(((0 0,0 10,10 10,10 0,0 0)))", + "MULTIPOLYGON(((5 5,5 6,6 6,6 5,5 5)),((0 20,0 30,10 30,10 20,0 20)))", + "212FF1212"); + test_geometry("MULTIPOLYGON(((0 0,0 10,10 10,10 0,0 0)),((0 20,0 30,10 30,10 20,0 20)))", + "MULTIPOLYGON(((5 5,5 6,6 6,6 5,5 5)))", + "212FF1FF2"); +} + +template +void test_all() +{ + test_polygon_polygon

(); + test_polygon_multi_polygon

(); + test_multi_polygon_multi_polygon

(); +} + +int test_main( int , char* [] ) +{ + test_all >(); + test_all >(); + +#if defined(HAVE_TTMATH) + test_all >(); +#endif + + return 0; +} diff --git a/test/algorithms/relate_linear_areal.cpp b/test/algorithms/relate_linear_areal.cpp new file mode 100644 index 000000000..436f0b973 --- /dev/null +++ b/test/algorithms/relate_linear_areal.cpp @@ -0,0 +1,330 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. + +// This file was modified by Oracle on 2013, 2014. +// Modifications copyright (c) 2013-2014 Oracle and/or its affiliates. + +// 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) + +// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle + +#include + +#include +#include +#include + +//TEST +//#include + +template +void test_linestring_polygon() +{ + typedef bg::model::linestring

ls; + typedef bg::model::polygon

poly; + typedef bg::model::ring

ring; + + // LS disjoint + test_geometry("LINESTRING(11 0,11 10)", "POLYGON((0 0,0 10,10 10,10 0,0 0))", "FF1FF0212"); + test_geometry("LINESTRING(11 0,11 10)", "POLYGON((0 0,0 10,10 10,10 0,0 0))", "FF1FF0212"); + + // II BB + test_geometry("LINESTRING(0 0,10 10)", "POLYGON((0 0,0 10,10 10,10 0,0 0))", "1FFF0F212"); + test_geometry("LINESTRING(5 0,5 5,10 5)", "POLYGON((0 0,0 10,10 10,10 0,0 0))", "1FFF0F212"); + test_geometry("LINESTRING(5 1,5 5,9 5)", "POLYGON((0 0,0 10,10 10,10 0,0 0))", "1FF0FF212"); + + // IE + test_geometry("LINESTRING(11 1,11 5)", "POLYGON((0 0,0 10,10 10,10 0,0 0))", "FF1FF0212"); + // IE IB0 + test_geometry("LINESTRING(11 1,10 5)", "POLYGON((0 0,0 10,10 10,10 0,0 0))", "FF1F00212"); + // IE IB1 + test_geometry("LINESTRING(11 1,10 5,10 10)", "POLYGON((0 0,0 10,10 10,10 0,0 0))", "F11F00212"); + test_geometry("LINESTRING(11 1,10 10,0 10)", "POLYGON((0 0,0 10,10 10,10 0,0 0))", "F11F00212"); + test_geometry("LINESTRING(11 1,10 0,0 0)", "POLYGON((0 0,0 10,10 10,10 0,0 0))", "F11F00212"); + test_geometry("LINESTRING(0 -1,1 0,2 0)", "POLYGON((0 0,0 10,10 10,10 0,0 0))", "F11F00212"); + // IE IB0 II + test_geometry("LINESTRING(11 1,10 5,5 5)", "POLYGON((0 0,0 10,10 10,10 0,0 0))", "1010F0212"); + // IE IB0 lring + test_geometry("LINESTRING(11 1,10 5,11 5,11 1)", "POLYGON((0 0,0 10,10 10,10 0,0 0))", "F01FFF212"); + // IE IB1 lring + test_geometry("LINESTRING(11 1,10 5,10 10,11 5,11 1)", "POLYGON((0 0,0 10,10 10,10 0,0 0))", "F11FFF212"); + + // IB1 II + test_geometry("LINESTRING(0 0,5 0,5 5)", "POLYGON((0 0,0 10,10 10,10 0,0 0))", "11F00F212"); + // BI0 II IB1 + test_geometry("LINESTRING(5 0,5 5,10 5,10 10)", "POLYGON((0 0,0 10,10 10,10 0,0 0))", "11FF0F212"); + + // IB1 II IB1 + test_geometry("LINESTRING(1 0,2 0,3 1,4 0,5 0)", "POLYGON((0 0,0 10,10 10,10 0,0 0))", "11FF0F212"); + // IB1 IE IB1 + test_geometry("LINESTRING(1 0,2 0,3 -1,4 0,5 0)", "POLYGON((0 0,0 10,10 10,10 0,0 0))", "F11F0F212"); + + // II IB1 + test_geometry("LINESTRING(5 5,10 5,10 10)", "POLYGON((0 0,0 10,10 10,10 0,0 0))", "11F00F212"); + // IB1 II + test_geometry("LINESTRING(10 10,10 5,5 5)", "POLYGON((0 0,0 10,10 10,10 0,0 0))", "11F00F212"); + // IE IB1 + test_geometry("LINESTRING(15 5,10 5,10 10)", "POLYGON((0 0,0 10,10 10,10 0,0 0))", "F11F00212"); + // IB1 IE + test_geometry("LINESTRING(10 10,10 5,15 5)", "POLYGON((0 0,0 10,10 10,10 0,0 0))", "F11F00212"); + + // duplicated points + { + // II IB0 IE + test_geometry("LINESTRING(5 5,10 5,15 10)", "POLYGON((0 0,0 10,10 10,10 0,0 0))", "1010F0212"); + test_geometry("LINESTRING(5 5,5 5,5 5,10 5,10 5,10 5,15 10,15 10,15 10)", + "POLYGON((0 0,0 0,0 0,0 10,0 10,0 10,10 10,10 10,10 10,10 0,10 0,10 0,0 0,0 0,0 0))", + "1010F0212"); + test_geometry("LINESTRING(5 5,5 5,5 5,10 0,10 0,10 0,15 10,15 10,15 10)", + "POLYGON((0 0,0 0,0 0,0 10,0 10,0 10,10 10,10 10,10 10,10 0,10 0,10 0,0 0,0 0,0 0))", + "1010F0212"); + // IE IB0 II + test_geometry("LINESTRING(15 10,15 10,15 10,10 5,10 5,10 5,5 5,5 5,5 5)", + "POLYGON((0 0,0 0,0 0,0 10,0 10,0 10,10 10,10 10,10 10,10 0,10 0,10 0,0 0,0 0,0 0))", + "1010F0212"); + test_geometry("LINESTRING(15 10,15 10,15 10,10 0,10 0,10 0,5 5,5 5,5 5)", + "POLYGON((0 0,0 0,0 0,0 10,0 10,0 10,10 10,10 10,10 10,10 0,10 0,10 0,0 0,0 0,0 0))", + "1010F0212"); + + // TEST + //test_geometry("LINESTRING(5 5,5 5,5 5)", "POLYGON((0 0,0 10,10 10,10 0,0 0))", "1010F0212"); + test_geometry("LINESTRING(5 5,5 5,5 5,15 5,15 5,15 5)", "POLYGON((0 0,0 10,10 10,10 0,0 0))", "1010F0212"); + } + + // non-simple polygon with hole + test_geometry("LINESTRING(9 1,10 5,9 9)", + "POLYGON((0 0,0 10,10 10,10 0,0 0),(10 5,2 8,2 2,10 5))", + "10F0FF212"); + test_geometry("LINESTRING(10 1,10 5,10 9)", + "POLYGON((0 0,0 10,10 10,10 0,0 0),(10 5,2 8,2 2,10 5))", + "F1FF0F212"); + test_geometry("LINESTRING(2 8,10 5,2 2)", + "POLYGON((0 0,0 10,10 10,10 0,0 0),(10 5,2 8,2 2,10 5))", + "F1FF0F212"); + test_geometry("LINESTRING(10 1,10 5,2 2)", + "POLYGON((0 0,0 10,10 10,10 0,0 0),(10 5,2 8,2 2,10 5))", + "F1FF0F212"); + test_geometry("LINESTRING(10 1,10 5,2 8)", + "POLYGON((0 0,0 10,10 10,10 0,0 0),(10 5,2 8,2 2,10 5))", + "F1FF0F212"); + + // non-simple polygon with hole, linear ring + test_geometry("LINESTRING(9 1,10 5,9 9,1 9,1 1,9 1)", + "POLYGON((0 0,0 10,10 10,10 0,0 0),(10 5,2 8,2 2,10 5))", + "10FFFF212"); + test_geometry("LINESTRING(10 5,10 9,11 5,10 1,10 5)", + "POLYGON((0 0,0 10,10 10,10 0,0 0),(10 5,2 8,2 2,10 5))", + "F11FFF212"); + test_geometry("LINESTRING(11 5,10 1,10 5,10 9,11 5)", + "POLYGON((0 0,0 10,10 10,10 0,0 0),(10 5,2 8,2 2,10 5))", + "F11FFF212"); + + // non-simple polygon with self-touching holes + test_geometry("LINESTRING(7 1,8 5,7 9)", + "POLYGON((0 0,0 10,10 10,10 0,0 0),(8 1,9 1,9 9,8 9,8 1),(2 2,8 5,2 8,2 2))", + "10F0FF212"); + test_geometry("LINESTRING(8 2,8 5,8 8)", + "POLYGON((0 0,0 10,10 10,10 0,0 0),(8 1,9 1,9 9,8 9,8 1),(2 2,8 5,2 8,2 2))", + "F1FF0F212"); + test_geometry("LINESTRING(2 8,8 5,2 2)", + "POLYGON((0 0,0 10,10 10,10 0,0 0),(8 1,9 1,9 9,8 9,8 1),(2 2,8 5,2 8,2 2))", + "F1FF0F212"); + + // non-simple polygon self-touching + test_geometry("LINESTRING(9 1,10 5,9 9)", + "POLYGON((0 0,0 10,10 10,10 5,2 8,2 2,10 5,10 0,0 0))", + "10F0FF212"); + test_geometry("LINESTRING(10 1,10 5,10 9)", + "POLYGON((0 0,0 10,10 10,10 5,2 8,2 2,10 5,10 0,0 0))", + "F1FF0F212"); + test_geometry("LINESTRING(2 8,10 5,2 2)", + "POLYGON((0 0,0 10,10 10,10 5,2 8,2 2,10 5,10 0,0 0))", + "F1FF0F212"); + + // non-simple polygon self-touching, linear ring + test_geometry("LINESTRING(9 1,10 5,9 9,1 9,1 1,9 1)", + "POLYGON((0 0,0 10,10 10,10 5,2 8,2 2,10 5,10 0,0 0))", + "10FFFF212"); + test_geometry("LINESTRING(10 5,10 9,11 5,10 1,10 5)", + "POLYGON((0 0,0 10,10 10,10 5,2 8,2 2,10 5,10 0,0 0))", + "F11FFF212"); + test_geometry("LINESTRING(11 5,10 1,10 5,10 9,11 5)", + "POLYGON((0 0,0 10,10 10,10 5,2 8,2 2,10 5,10 0,0 0))", + "F11FFF212"); + + // polygons with some ring equal to the linestring + test_geometry("LINESTRING(0 0,10 0,10 10,0 10,0 0)", + "POLYGON((0 0,0 10,10 10,10 0,0 0))", + "F1FFFF2F2"); + test_geometry("LINESTRING(0 0,10 0,10 10,0 10,0 0)", + "POLYGON((0 0,0 10,10 10,10 0,0 0),(2 2,5 5,2 8,2 2))", + "F1FFFF212"); + test_geometry("LINESTRING(2 2,5 5,2 8,2 2)", + "POLYGON((0 0,0 10,10 10,10 0,0 0),(2 2,5 5,2 8,2 2))", + "F1FFFF212"); + + // self-IP going on the boundary then into the exterior and to the boundary again + test_geometry("LINESTRING(2 10,5 10,5 15,6 15,5 10,8 10)", "POLYGON((0 0,0 10,10 10,10 0,0 0))", + "F11F0F212"); + // self-IP going on the boundary then into the interior and to the boundary again + test_geometry("LINESTRING(2 10,5 10,5 5,6 5,5 10,8 10)", "POLYGON((0 0,0 10,10 10,10 0,0 0))", + "11FF0F212"); + + // self-IP with a hole -> B to I to B to E + test_geometry("LINESTRING(0 0,3 3)", "POLYGON((0 0,0 10,10 10,10 0,0 0),(0 0,9 1,9 9,1 9,0 0))", + "FF1F00212"); + + // ccw + { + typedef bg::model::polygon ccwpoly; + + // IE IB0 II + test_geometry("LINESTRING(11 1,10 5,5 5)", "POLYGON((0 0,10 0,10 10,0 10,0 0))", "1010F0212"); + // IE IB1 II + test_geometry("LINESTRING(11 1,10 1,10 5,5 5)", "POLYGON((0 0,10 0,10 10,0 10,0 0))", "1110F0212"); + test_geometry("LINESTRING(11 1,10 5,10 1,5 5)", "POLYGON((0 0,10 0,10 10,0 10,0 0))", "1110F0212"); + // II IB0 IE + test_geometry("LINESTRING(5 1,10 5,11 1)", "POLYGON((0 0,10 0,10 10,0 10,0 0))", "1010F0212"); + // IE IB1 II + test_geometry("LINESTRING(5 5,10 1,10 5,11 5)", "POLYGON((0 0,10 0,10 10,0 10,0 0))", "1110F0212"); + test_geometry("LINESTRING(5 5,10 5,10 1,11 5)", "POLYGON((0 0,10 0,10 10,0 10,0 0))", "1110F0212"); + + } + + { + // SPIKES + + test_geometry("LINESTRING(0 0,2 2,3 3,1 1)", "POLYGON((0 0,3 3,3 0,0 0))", "F1FF0F212"); + test_geometry("LINESTRING(0 0,3 3,1 1)", "POLYGON((0 0,3 3,3 0,0 0))", "F1FF0F212"); + test_geometry("LINESTRING(0 0,2 2,1 1)", "POLYGON((0 0,3 3,3 0,0 0))", "F1FF0F212"); + test_geometry("LINESTRING(1 1,3 3,2 2)", "POLYGON((0 0,3 3,3 0,0 0))", "F1FF0F212"); + test_geometry("LINESTRING(1 1,2 2,1 1)", "POLYGON((0 0,3 3,3 0,0 0))", "F1FFFF212"); + + test_geometry("LINESTRING(3 3,1 1,0 0,2 2)", "POLYGON((0 0,3 3,3 0,0 0))", "F1FF0F212"); + test_geometry("LINESTRING(3 3,0 0,2 2)", "POLYGON((0 0,3 3,3 0,0 0))", "F1FF0F212"); + test_geometry("LINESTRING(2 2,0 0,1 1)", "POLYGON((0 0,3 3,3 0,0 0))", "F1FF0F212"); + test_geometry("LINESTRING(3 3,1 1,2 2)", "POLYGON((0 0,3 3,3 0,0 0))", "F1FF0F212"); + test_geometry("LINESTRING(2 2,1 1,2 2)", "POLYGON((0 0,3 3,3 0,0 0))", "F1FFFF212"); + + test_geometry("LINESTRING(0 0,2 2,4 4,1 1)", "POLYGON((0 0,3 3,3 0,0 0))", "F11F0F212"); + + test_geometry("LINESTRING(0 1,1 1,0 1)", "POLYGON((0 0,3 3,3 0,0 0))", "F01FFF212"); + test_geometry("LINESTRING(0 1,3 3,0 1)", "POLYGON((0 0,3 3,3 0,0 0))", "F01FFF212"); + test_geometry("LINESTRING(0 1,0 0,0 1)", "POLYGON((0 0,3 3,3 0,0 0))", "F01FFF212"); + + test_geometry("LINESTRING(0 1,1 1,-1 1)", "POLYGON((0 0,3 3,3 0,0 0))", "F01FF0212"); + } +} + +template +void test_linestring_multi_polygon() +{ + typedef bg::model::linestring

ls; + typedef bg::model::polygon

poly; + typedef bg::model::multi_polygon mpoly; + + test_geometry("LINESTRING(10 1,10 5,10 9)", + "MULTIPOLYGON(((0 20,0 30,10 30,10 20,0 20)),((0 0,0 10,10 10,10 0,0 0),(10 5,2 8,2 2,10 5)))", + "F1FF0F212"); + test_geometry("LINESTRING(10 1,10 5,10 9)", + "MULTIPOLYGON(((0 20,0 30,10 30,10 20,0 20)),((0 0,0 10,10 10,10 0,0 0)))", + "F1FF0F212"); + + test_geometry("LINESTRING(10 1,10 5,2 2)", + "MULTIPOLYGON(((0 20,0 30,10 30,10 20,0 20)),((0 0,0 10,10 10,10 0,0 0),(10 5,2 8,2 2,10 5)))", + "F1FF0F212"); + test_geometry("LINESTRING(10 1,10 5,2 2)", + "MULTIPOLYGON(((0 20,0 30,10 30,10 20,0 20)),((0 0,0 10,10 10,10 0,0 0)))", + "11F00F212"); + + test_geometry("LINESTRING(10 1,10 5,2 2)", + "MULTIPOLYGON(((0 0,0 10,10 10,10 0,0 0),(10 5,2 8,2 2,10 5)),((10 5,3 3,3 7,10 5)))", + "F1FF0F212"); + test_geometry("LINESTRING(10 1,10 5,2 8)", + "MULTIPOLYGON(((0 0,0 10,10 10,10 0,0 0),(10 5,2 8,2 2,10 5)),((10 5,3 3,3 7,10 5)))", + "F1FF0F212"); + test_geometry("LINESTRING(10 1,10 5,3 3)", + "MULTIPOLYGON(((0 0,0 10,10 10,10 0,0 0),(10 5,2 8,2 2,10 5)),((10 5,3 3,3 7,10 5)))", + "F1FF0F212"); + test_geometry("LINESTRING(10 1,10 5,3 7)", + "MULTIPOLYGON(((0 0,0 10,10 10,10 0,0 0),(10 5,2 8,2 2,10 5)),((10 5,3 3,3 7,10 5)))", + "F1FF0F212"); + test_geometry("LINESTRING(10 1,10 5,5 5)", + "MULTIPOLYGON(((0 0,0 10,10 10,10 0,0 0),(10 5,2 8,2 2,10 5)),((10 5,3 3,3 7,10 5)))", + "11F00F212"); + + test_geometry("LINESTRING(0 0,10 0,10 10,0 10,0 0)", + "MULTIPOLYGON(((0 0,0 10,10 10,10 0,0 0)),((20 0,20 10,30 20,20 0)))", + "F1FFFF212"); + + // degenerated points + test_geometry("LINESTRING(5 5,10 10,10 10,10 10,15 15)", + "MULTIPOLYGON(((0 0,0 10,10 10,10 0,0 0)),((10 10,10 20,20 20,20 10,10 10)))", + "10F0FF212"); + + // self-IP polygon with a hole and second polygon with a hole -> B to I to B to B to I to B to E + test_geometry("LINESTRING(0 0,3 3)", + "MULTIPOLYGON(((0 0,0 10,10 10,10 0,0 0),(0 0,9 1,9 9,1 9,0 0)),((0 0,2 8,8 8,8 2,0 0),(0 0,7 3,7 7,3 7,0 0)))", + "FF1F00212"); + // self-IP polygon with a hole and second polygon -> B to I to B to B to I + test_geometry("LINESTRING(0 0,3 3)", + "MULTIPOLYGON(((0 0,0 10,10 10,10 0,0 0),(0 0,9 1,9 9,1 9,0 0)),((0 0,2 8,8 8,8 2,0 0)))", + "1FF00F212"); + test_geometry("LINESTRING(0 0,3 3)", + "MULTIPOLYGON(((0 0,2 8,8 8,8 2,0 0)),((0 0,0 10,10 10,10 0,0 0),(0 0,9 1,9 9,1 9,0 0)))", + "1FF00F212"); +} + +template +void test_multi_linestring_multi_polygon() +{ + typedef bg::model::linestring

ls; + typedef bg::model::polygon

poly; + typedef bg::model::multi_linestring mls; + typedef bg::model::multi_polygon mpoly; + + // polygons with some ring equal to the linestrings + test_geometry("MULTILINESTRING((0 0,10 0,10 10,0 10,0 0),(20 20,50 50,20 80,20 20))", + "MULTIPOLYGON(((0 0,0 10,10 10,10 0,0 0)))", + "F11FFF2F2"); + + test_geometry("MULTILINESTRING((0 0,10 0,10 10,0 10,0 0),(2 2,5 5,2 8,2 2))", + "MULTIPOLYGON(((0 0,0 10,10 10,10 0,0 0),(2 2,5 5,2 8,2 2)))", + "F1FFFF2F2"); + + + test_geometry("MULTILINESTRING((0 0,10 0,10 10),(10 10,0 10,0 0))", + "MULTIPOLYGON(((0 0,0 10,10 10,10 0,0 0)))", + "F1FFFF2F2"); + test_geometry("MULTILINESTRING((0 0,10 0,10 10),(10 10,0 10,0 0),(20 20,50 50,20 80,20 20))", + "MULTIPOLYGON(((0 0,0 10,10 10,10 0,0 0)))", + "F11FFF2F2"); + + // disjoint + test_geometry("MULTILINESTRING((20 20,30 30),(30 30,40 40))", + "MULTIPOLYGON(((0 0,0 10,10 10,10 0,0 0)))", + "FF1FF0212"); +} + +template +void test_all() +{ + test_linestring_polygon

(); + test_linestring_multi_polygon

(); + test_multi_linestring_multi_polygon

(); +} + +int test_main( int , char* [] ) +{ + test_all >(); + test_all >(); + +#if defined(HAVE_TTMATH) + test_all >(); +#endif + + return 0; +} diff --git a/test/algorithms/relate_linear_linear.cpp b/test/algorithms/relate_linear_linear.cpp new file mode 100644 index 000000000..ed5852aa7 --- /dev/null +++ b/test/algorithms/relate_linear_linear.cpp @@ -0,0 +1,351 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. + +// This file was modified by Oracle on 2013, 2014. +// Modifications copyright (c) 2013-2014 Oracle and/or its affiliates. + +// 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) + +// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle + +#include + +#include +#include + +//TEST +//#include + +template +void test_linestring_linestring() +{ + typedef bg::model::linestring

ls; + + test_geometry("LINESTRING(0 0, 2 2, 3 2)", "LINESTRING(0 0, 2 2, 3 2)", "1FFF0FFF2"); + test_geometry("LINESTRING(0 0,3 2)", "LINESTRING(0 0, 2 2, 3 2)", "FF1F0F1F2"); + test_geometry("LINESTRING(1 0,2 2,2 3)", "LINESTRING(0 0, 2 2, 3 2)", "0F1FF0102"); + + test_geometry("LINESTRING(0 0,5 0)", "LINESTRING(0 0,1 1,2 0,2 -1)", "0F1F00102"); + + test_geometry("LINESTRING(0 0, 1 1, 2 2, 3 2)", "LINESTRING(0 0, 2 2, 3 2)", "1FFF0FFF2"); + test_geometry("LINESTRING(3 2, 2 2, 1 1, 0 0)", "LINESTRING(0 0, 2 2, 3 2)", "1FFF0FFF2"); + test_geometry("LINESTRING(0 0, 1 1, 2 2, 3 2)", "LINESTRING(3 2, 2 2, 0 0)", "1FFF0FFF2"); + test_geometry("LINESTRING(3 2, 2 2, 1 1, 0 0)", "LINESTRING(3 2, 2 2, 0 0)", "1FFF0FFF2"); + + test_geometry("LINESTRING(3 1, 2 2, 1 1, 0 0)", "LINESTRING(0 0, 2 2, 3 2)", "1F1F00102"); + test_geometry("LINESTRING(3 3, 2 2, 1 1, 0 0)", "LINESTRING(0 0, 2 2, 3 2)", "1F1F00102"); + + test_geometry("LINESTRING(0 0, 1 1, 2 2, 2 3)", "LINESTRING(0 0, 2 2, 2 3)", "1FFF0FFF2"); + test_geometry("LINESTRING(2 3, 2 2, 1 1, 0 0)", "LINESTRING(0 0, 2 2, 2 3)", "1FFF0FFF2"); + test_geometry("LINESTRING(0 0, 1 1, 2 2, 2 3)", "LINESTRING(2 3, 2 2, 0 0)", "1FFF0FFF2"); + test_geometry("LINESTRING(2 3, 2 2, 1 1, 0 0)", "LINESTRING(2 3, 2 2, 0 0)", "1FFF0FFF2"); + + test_geometry("LINESTRING(1 1, 2 2, 3 2)", "LINESTRING(0 0, 2 2, 4 2)", "1FF0FF102"); + + test_geometry("LINESTRING(3 2, 2 2, 1 1)", "LINESTRING(0 0, 2 2, 4 2)", "1FF0FF102"); + test_geometry("LINESTRING(1 1, 2 2, 3 2)", "LINESTRING(4 2, 2 2, 0 0)", "1FF0FF102"); + test_geometry("LINESTRING(3 2, 2 2, 1 1)", "LINESTRING(4 2, 2 2, 0 0)", "1FF0FF102"); + +// test_geometry("LINESTRING(1 1, 2 2, 2 2)", "LINESTRING(0 0, 2 2, 4 2)", true); + +// test_geometry("LINESTRING(1 1, 2 2, 3 3)", "LINESTRING(0 0, 2 2, 4 2)", false); +// test_geometry("LINESTRING(1 1, 2 2, 3 2, 3 3)", "LINESTRING(0 0, 2 2, 4 2)", false); +// test_geometry("LINESTRING(1 1, 2 2, 3 1)", "LINESTRING(0 0, 2 2, 4 2)", false); +// test_geometry("LINESTRING(1 1, 2 2, 3 2, 3 1)", "LINESTRING(0 0, 2 2, 4 2)", false); + +// test_geometry("LINESTRING(0 1, 1 1, 2 2, 3 2)", "LINESTRING(0 0, 2 2, 4 2)", false); +// test_geometry("LINESTRING(0 1, 0 0, 2 2, 3 2)", "LINESTRING(0 0, 2 2, 4 2)", false); +// test_geometry("LINESTRING(1 0, 1 1, 2 2, 3 2)", "LINESTRING(0 0, 2 2, 4 2)", false); +// test_geometry("LINESTRING(1 0, 0 0, 2 2, 3 2)", "LINESTRING(0 0, 2 2, 4 2)", false); + +// test_geometry("LINESTRING(0 0)", "LINESTRING(0 0)", false); +// test_geometry("LINESTRING(1 1)", "LINESTRING(0 0, 2 2)", true); +// test_geometry("LINESTRING(0 0)", "LINESTRING(0 0, 2 2)", false); +// test_geometry("LINESTRING(0 0, 1 1)", "LINESTRING(0 0)", false); + +// test_geometry("LINESTRING(0 0,5 0,3 0,6 0)", "LINESTRING(0 0,6 0)", true); +// test_geometry("LINESTRING(0 0,2 2,3 3,1 1)", "LINESTRING(0 0,3 3,6 3)", true); + + // SPIKES! + test_geometry("LINESTRING(0 0,2 2,3 3,1 1,5 3)", "LINESTRING(0 0,3 3,6 3)", "1F100F102"); + test_geometry("LINESTRING(5 3,1 1,3 3,2 2,0 0)", "LINESTRING(0 0,3 3,6 3)", "1F100F102"); + test_geometry("LINESTRING(0 0,2 2,3 3,1 1,5 3)", "LINESTRING(6 3,3 3,0 0)", "1F100F102"); + test_geometry("LINESTRING(5 3,1 1,3 3,2 2,0 0)", "LINESTRING(6 3,3 3,0 0)", "1F100F102"); + + test_geometry("LINESTRING(6 3,3 3,0 0)", "LINESTRING(0 0,2 2,3 3,1 1,5 3)", "101F001F2"); + + test_geometry("LINESTRING(0 0,10 0)", "LINESTRING(1 0,9 0,2 0)", "101FF0FF2"); + test_geometry("LINESTRING(0 0,2 2,3 3,1 1)", "LINESTRING(0 0,3 3,6 3)", "1FF00F102"); + // TODO: REWRITE MATRICES + // BEGIN + /*test_geometry("LINESTRING(0 0,2 2,3 3,1 1)", "LINESTRING(0 0,4 4,6 3)", "1FF00F102"); + + test_geometry("LINESTRING(0 0,2 0,1 0)", "LINESTRING(0 1,0 0,2 0)", "1FF00F102"); + test_geometry("LINESTRING(2 0,0 0,1 0)", "LINESTRING(0 1,0 0,2 0)", "1FF00F102"); + + test_geometry("LINESTRING(0 0,3 3,1 1)", "LINESTRING(3 0,3 3,3 1)", "0F1FF0102"); + test_geometry("LINESTRING(0 0,3 3,1 1)", "LINESTRING(2 0,2 3,2 1)", "0F1FF0102"); + test_geometry("LINESTRING(0 0,3 3,1 1)", "LINESTRING(2 0,2 2,2 1)", "0F1FF0102"); + + test_geometry("LINESTRING(0 0,2 2,3 3,4 4)", "LINESTRING(0 0,1 1,4 4)", "1FFF0FFF2");*/ + // END + + test_geometry("LINESTRING(0 0,2 2,3 3,4 4)", "LINESTRING(0 0,1 1,4 4)", "1FFF0FFF2"); + + // loop i/i i/i u/u u/u + test_geometry("LINESTRING(0 0,10 0)", + "LINESTRING(1 1,1 0,6 0,6 1,4 1,4 0,9 0,9 1)", "1F1FF0102"); + + // self-intersecting and self-touching equal + test_geometry("LINESTRING(0 5,5 5,10 5,10 10,5 10,5 5,5 0)", + "LINESTRING(0 5,5 5,5 10,10 10,10 5,5 5,5 0)", "1FFF0FFF2"); + // self-intersecting loop and self-touching equal + test_geometry("LINESTRING(0 5,5 5,10 5,10 10,5 10,5 5,10 5,10 10,5 10,5 5,5 0)", + "LINESTRING(0 5,5 5,5 10,10 10,10 5,5 5,5 0)", "1FFF0FFF2"); + + test_geometry("LINESTRING(0 0,1 1)", "LINESTRING(0 1,1 0)", "0F1FF0102"); + test_geometry("LINESTRING(0 0,1 1)", "LINESTRING(1 1,2 0)", "FF1F00102"); + test_geometry("LINESTRING(0 0,1 1)", "LINESTRING(2 0,1 1)", "FF1F00102"); + + test_geometry("LINESTRING(0 0,1 0,2 1,3 5,4 0)", "LINESTRING(1 0,2 1,3 5)", "101FF0FF2"); + test_geometry("LINESTRING(0 0,1 0,2 1,3 5,4 0)", "LINESTRING(3 5,2 1,1 0)", "101FF0FF2"); + test_geometry("LINESTRING(1 0,2 1,3 5)", "LINESTRING(4 0,3 5,2 1,1 0,0 0)", "1FF0FF102"); + test_geometry("LINESTRING(3 5,2 1,1 0)", "LINESTRING(4 0,3 5,2 1,1 0,0 0)", "1FF0FF102"); + + test_geometry("LINESTRING(0 0,10 0)", "LINESTRING(-1 -1,1 0,10 0,20 -1)", "1F10F0102"); + test_geometry("LINESTRING(0 0,10 0)", "LINESTRING(20 -1,10 0,1 0,-1 -1)", "1F10F0102"); + + test_geometry("LINESTRING(-1 1,0 0,1 0,5 0,5 5,10 5,15 0,31 0)", + "LINESTRING(-1 -1,0 0,1 0,2 0,3 1,4 0,30 0)", + "101FF0102"); + test_geometry("LINESTRING(-1 1,0 0,1 0,5 0,5 5,10 5,15 0,31 0)", + "LINESTRING(30 0,4 0,3 1,2 0,1 0,0 0,-1 -1)", + "101FF0102"); + test_geometry("LINESTRING(31 0,15 0,10 5,5 5,5 0,1 0,0 0,-1 1)", + "LINESTRING(-1 -1,0 0,1 0,2 0,3 1,4 0,30 0)", + "101FF0102"); + test_geometry("LINESTRING(31 0,15 0,10 5,5 5,5 0,1 0,0 0,-1 1)", + "LINESTRING(30 0,4 0,3 1,2 0,1 0,0 0,-1 -1)", + "101FF0102"); + + // self-IP + test_geometry("LINESTRING(1 0,9 0)", + "LINESTRING(0 0,10 0,10 10,5 0,0 10)", + "1FF0FF102"); + test_geometry("LINESTRING(1 0,5 0,9 0)", + "LINESTRING(0 0,10 0,10 10,5 0,0 10)", + "1FF0FF102"); + test_geometry("LINESTRING(1 0,9 0)", + "LINESTRING(0 0,10 0,10 10,5 10,5 -1)", + "1FF0FF102"); + test_geometry("LINESTRING(1 0,9 0)", + "LINESTRING(0 0,10 0,5 0,5 5)", + "1FF0FF102"); + test_geometry("LINESTRING(1 0,7 0)", "LINESTRING(0 0,10 0,10 10,4 -1)", + "1FF0FF102"); + test_geometry("LINESTRING(1 0,5 0,7 0)", "LINESTRING(0 0,10 0,10 10,4 -1)", + "1FF0FF102"); + test_geometry("LINESTRING(1 0,7 0,8 1)", "LINESTRING(0 0,10 0,10 10,4 -1)", + "1F10F0102"); + test_geometry("LINESTRING(1 0,5 0,7 0,8 1)", "LINESTRING(0 0,10 0,10 10,4 -1)", + "1F10F0102"); + + // self-IP going out and in on the same point + test_geometry("LINESTRING(2 0,5 0,5 5,6 5,5 0,8 0)", "LINESTRING(1 0,9 0)", + "1F10FF102"); + + // duplicated points + test_geometry("LINESTRING(1 1, 2 2, 2 2)", "LINESTRING(0 0, 2 2, 4 2)", "1FF0FF102"); + test_geometry("LINESTRING(1 1, 1 1, 2 2)", "LINESTRING(0 0, 2 2, 4 2)", "1FF0FF102"); + + // linear ring + test_geometry("LINESTRING(0 0,10 0)", "LINESTRING(5 0,9 0,5 5,1 0,5 0)", "1F1FF01F2"); + test_geometry("LINESTRING(0 0,5 0,10 0)", "LINESTRING(5 0,9 0,5 5,1 0,5 0)", "1F1FF01F2"); + test_geometry("LINESTRING(0 0,5 0,10 0)", "LINESTRING(5 0,10 0,5 5,1 0,5 0)", "1F10F01F2"); + + test_geometry("LINESTRING(0 0,5 0)", "LINESTRING(5 0,10 0,5 5,0 0,5 0)", "1FF0FF1F2"); + test_geometry("LINESTRING(0 0,5 0)", "LINESTRING(5 0,10 0,5 5,5 0)", "FF10F01F2"); + + test_geometry("LINESTRING(1 0,1 6)", "LINESTRING(0 0,5 0,5 5,0 5)", "0F10F0102"); + + // point-size Linestring + // FOR NOW DISABLED, THE ROBUSTNESS UPGRADES BROKE POINT-SIZED LINESTRINGS + /*test_geometry("LINESTRING(1 0,1 0)", "LINESTRING(0 0,5 0)", "0FFFFF102"); + test_geometry("LINESTRING(1 0,1 0)", "LINESTRING(1 0,5 0)", "F0FFFF102"); + test_geometry("LINESTRING(1 0,1 0)", "LINESTRING(0 0,1 0)", "F0FFFF102"); + test_geometry("LINESTRING(1 0,1 0)", "LINESTRING(1 0,1 0)", "0FFFFFFF2"); + test_geometry("LINESTRING(1 0,1 0)", "LINESTRING(0 0,0 0)", "FF0FFF0F2");*/ + + //to_svg("LINESTRING(0 0,5 0)", "LINESTRING(5 0,10 0,5 5,5 0)", "test_relate_00.svg"); + + // INVALID LINESTRINGS + // 1-point LS (a Point) NOT disjoint + //test_geometry("LINESTRING(1 0)", "LINESTRING(0 0,5 0)", "0FFFFF102"); + //test_geometry("LINESTRING(0 0,5 0)", "LINESTRING(1 0)", "0F1FF0FF2"); + //test_geometry("LINESTRING(0 0,5 0)", "LINESTRING(1 0,1 0,1 0)", "0F1FF0FF2"); + // Point/Point + //test_geometry("LINESTRING(0 0)", "LINESTRING(0 0)", "0FFFFFFF2"); + + // OTHER MASKS + { + namespace bgdr = bg::detail::relate; + ls ls1, ls2, ls3, ls4; + bg::read_wkt("LINESTRING(0 0,2 0)", ls1); + bg::read_wkt("LINESTRING(2 0,4 0)", ls2); + bg::read_wkt("LINESTRING(1 0,1 1)", ls3); + bg::read_wkt("LINESTRING(1 0,4 0)", ls4); + BOOST_CHECK(bgdr::relate(ls1, ls2, bgdr::mask9("FT*******") + || bgdr::mask9("F**T*****") + || bgdr::mask9("F***T****"))); + BOOST_CHECK(bgdr::relate(ls1, ls3, bgdr::mask9("FT*******") + || bgdr::mask9("F**T*****") + || bgdr::mask9("F***T****"))); + BOOST_CHECK(bgdr::relate(ls3, ls1, bgdr::mask9("FT*******") + || bgdr::mask9("F**T*****") + || bgdr::mask9("F***T****"))); + BOOST_CHECK(bgdr::relate(ls2, ls4, bgdr::mask9("T*F**F***"))); // within + } +} + +template +void test_linestring_multi_linestring() +{ + typedef bg::model::linestring

ls; + typedef bg::model::multi_linestring mls; + + // LS disjoint + test_geometry("LINESTRING(0 0,10 0)", "MULTILINESTRING((1 0,2 0),(1 1,2 1))", "101FF0102"); + // linear ring disjoint + test_geometry("LINESTRING(0 0,10 0)", "MULTILINESTRING((1 0,2 0),(1 1,2 1,2 2,1 1))", "101FF01F2"); + // 2xLS forming non-simple linear ring disjoint + test_geometry("LINESTRING(0 0,10 0)", "MULTILINESTRING((1 0,2 0),(1 1,2 1,2 2),(1 1,2 2))", "101FF01F2"); + + test_geometry("LINESTRING(0 0,10 0)", + "MULTILINESTRING((1 0,9 0),(9 0,2 0))", + "101FF0FF2"); + + // INVALID LINESTRINGS + // 1-point LS (a Point) disjoint + //test_geometry("LINESTRING(0 0,10 0)", "MULTILINESTRING((1 0,2 0),(1 1))", "101FF00F2"); + //test_geometry("LINESTRING(0 0,10 0)", "MULTILINESTRING((1 0,2 0),(1 1,1 1))", "101FF00F2"); + //test_geometry("LINESTRING(0 0,10 0)", "MULTILINESTRING((1 0,2 0),(1 1,1 1,1 1))", "101FF00F2"); + // 1-point LS (a Point) NOT disjoint + //test_geometry("LINESTRING(0 0,10 0)", "MULTILINESTRING((1 0,9 0),(2 0))", "101FF0FF2"); + //test_geometry("LINESTRING(0 0,10 0)", "MULTILINESTRING((1 0,9 0),(2 0,2 0))", "101FF0FF2"); + //test_geometry("LINESTRING(0 0,10 0)", "MULTILINESTRING((1 0,9 0),(2 0,2 0,2 0))", "101FF0FF2"); + + // point-like + // FOR NOW DISABLED, THE ROBUSTNESS UPGRADES BROKE POINT-SIZED LINESTRINGS + //test_geometry("LINESTRING(0 0, 5 0)", // |--------------| + // "MULTILINESTRING((0 0, 1 0),(2 0, 2 0))", // |------| * + // "101F00FF2"); + //test_geometry("LINESTRING(0 0, 5 0)", // |--------------| + // "MULTILINESTRING((0 0, 1 0),(1 0, 1 0))", // |------* + // "101F00FF2"); + //test_geometry("LINESTRING(0 0, 5 0)", // |--------------| + // "MULTILINESTRING((5 0, 1 0),(1 0, 1 0))", // *-------| + // "101F00FF2"); + //test_geometry("LINESTRING(0 0, 5 0)", // |--------------| + // "MULTILINESTRING((0 0, 1 0),(5 0, 5 0))", // |------| * + // "10100FFF2"); + //test_geometry("LINESTRING(0 0, 5 0)", // |--------------| + // "MULTILINESTRING((0 0, 1 0),(0 0, 0 0))", // *------| + // "101000FF2"); + //test_geometry("LINESTRING(0 0, 5 0)", // |--------------| + // "MULTILINESTRING((4 0, 5 0),(5 0, 5 0))", // |------* + // "101000FF2"); + //test_geometry("LINESTRING(0 0, 5 0)", // |--------------| + // "MULTILINESTRING((1 0, 2 0),(0 0, 0 0))", // * |------| + // "1010F0FF2"); + + //test_geometry("LINESTRING(0 0, 5 0)", // |--------------| + // "MULTILINESTRING((2 0, 2 0),(2 0, 2 2))", // * + // "001FF0102"); // | + + // for consistency + test_geometry("LINESTRING(0 0, 5 0)", // |--------------| + "MULTILINESTRING((0 0, 5 0),(0 0, 2 0))", // |--------------| + "10F00FFF2"); // |------| + + test_geometry("LINESTRING(0 0, 5 0)", // |--------------| + "MULTILINESTRING((0 0, 5 0),(3 0, 5 0))", // |--------------| + "10F00FFF2"); // |------| + + test_geometry("LINESTRING(0 0, 5 0)", // |--------------| + "MULTILINESTRING((0 0, 5 0),(0 0, 6 0))", // |--------------| + "1FF00F102"); // |----------------| + + test_geometry("LINESTRING(0 0, 5 0)", // |--------------| + "MULTILINESTRING((0 0, 5 0),(-1 0, 5 0))", // |--------------| + "1FF00F102"); // |----------------| + + test_geometry("LINESTRING(0 0, 5 0)", // |--------------| + "MULTILINESTRING((0 0, 5 0),(-1 0, 6 0))", // |--------------| + "1FF00F102"); // |------------------| + + test_geometry("LINESTRING(0 0, 5 0)", // |--------------| + "MULTILINESTRING((0 0, 5 0),(-1 0, 2 0))", // |--------------| + "10F00F102"); // |-------| + + test_geometry("LINESTRING(0 0, 5 0)", // |--------------| + "MULTILINESTRING((0 0, 5 0),(2 0, 6 0))", // |--------------| + "10F00F102"); // |-------| + + test_geometry("LINESTRING(0 0, 5 0)", // |--------------| + "MULTILINESTRING((0 0, 5 0),(2 0, 2 2))", // |--------------| + "10FF0F102"); // | + // | +} + +template +void test_multi_linestring_multi_linestring() +{ + typedef bg::model::linestring

ls; + typedef bg::model::multi_linestring mls; + + test_geometry("MULTILINESTRING((0 0,0 0,18 0,18 0,19 0,19 0,19 0,30 0,30 0))", + "MULTILINESTRING((0 10,5 0,20 0,20 0,30 0))", + "1F1F00102"); + test_geometry("MULTILINESTRING((0 0,0 0,18 0,18 0,19 0,19 0,19 0,30 0,30 0))", + //"MULTILINESTRING((0 10,5 0,20 0,20 0,30 0),(1 10,1 10,1 0,1 0,1 -10),(2 0,2 0),(3 0,3 0,3 0),(0 0,0 0,0 10,0 10),(30 0,30 0,31 0,31 0))", + "MULTILINESTRING((0 10,5 0,20 0,20 0,30 0),(1 10,1 10,1 0,1 0,1 -10),(0 0,0 0,0 10,0 10),(30 0,30 0,31 0,31 0))", + "1F100F102"); + test_geometry("MULTILINESTRING((0 0,0 0,18 0,18 0,19 0,19 0,19 0,30 0,30 0))", + "MULTILINESTRING((0 10,5 0,20 0,20 0,30 0),(0 0,0 0,0 10,0 10))", + "1F1F0F1F2"); + + // point-like + // FOR NOW DISABLED, THE ROBUSTNESS UPGRADES BROKE POINT-SIZED LINESTRINGS + /*test_geometry("MULTILINESTRING((0 0, 0 0),(1 1, 1 1))", + "MULTILINESTRING((0 0, 0 0))", + "0F0FFFFF2"); + test_geometry("MULTILINESTRING((0 0, 0 0),(1 1, 1 1))", + "MULTILINESTRING((0 0, 0 0),(1 1, 1 1))", + "0FFFFFFF2"); + test_geometry("MULTILINESTRING((0 0, 0 0),(1 1, 1 1))", + "MULTILINESTRING((2 2, 2 2),(3 3, 3 3))", + "FF0FFF0F2");*/ +} + +template +void test_all() +{ + test_linestring_linestring

(); + test_linestring_multi_linestring

(); + test_multi_linestring_multi_linestring

(); +} + +int test_main( int , char* [] ) +{ + test_all >(); + test_all >(); + +#if defined(HAVE_TTMATH) + test_all >(); +#endif + + return 0; +} diff --git a/test/algorithms/relate_pointlike_xxx.cpp b/test/algorithms/relate_pointlike_xxx.cpp new file mode 100644 index 000000000..407fb90fb --- /dev/null +++ b/test/algorithms/relate_pointlike_xxx.cpp @@ -0,0 +1,106 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. + +// This file was modified by Oracle on 2013, 2014. +// Modifications copyright (c) 2013-2014 Oracle and/or its affiliates. + +// 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) + +// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle + +#include + +#include +#include + +//TEST +//#include + +template +void test_point_point() +{ + test_geometry("POINT(0 0)", "POINT(0 0)", "0FFFFFFF2"); + test_geometry("POINT(1 0)", "POINT(0 0)", "FF0FFF0F2"); +} + +template +void test_point_multipoint() +{ + typedef bg::model::multi_point

mpt; + + test_geometry("POINT(0 0)", "MULTIPOINT(0 0)", "0FFFFFFF2"); + test_geometry("POINT(1 0)", "MULTIPOINT(0 0)", "FF0FFF0F2"); + test_geometry("POINT(0 0)", "MULTIPOINT(0 0, 1 0)", "0FFFFF0F2"); +} + +template +void test_multipoint_multipoint() +{ + typedef bg::model::multi_point

mpt; + + test_geometry("MULTIPOINT(0 0)", "MULTIPOINT(0 0)", "0FFFFFFF2"); + test_geometry("MULTIPOINT(1 0)", "MULTIPOINT(0 0)", "FF0FFF0F2"); + test_geometry("MULTIPOINT(0 0)", "MULTIPOINT(0 0, 1 0)", "0FFFFF0F2"); + test_geometry("MULTIPOINT(0 0, 1 0)", "MULTIPOINT(0 0)", "0F0FFFFF2"); + test_geometry("MULTIPOINT(0 0, 1 1)", "MULTIPOINT(0 0, 1 0)", "0F0FFF0F2"); + + //typedef bg::model::d2::point_xy ptf; + //typedef bg::model::multi_point mptf; + //test_geometry("MULTIPOINT(0 0)", "MULTIPOINT(0 0)", "0FFFFFFF2"); +} + +template +void test_point_linestring() +{ + typedef bg::model::linestring

ls; + + test_geometry("POINT(0 0)", "LINESTRING(0 0, 2 2, 3 2)", "F0FFFF102"); + test_geometry("POINT(1 1)", "LINESTRING(0 0, 2 2, 3 2)", "0FFFFF102"); + test_geometry("POINT(3 2)", "LINESTRING(0 0, 2 2, 3 2)", "F0FFFF102"); + test_geometry("POINT(1 0)", "LINESTRING(0 0, 2 2, 3 2)", "FF0FFF102"); + + test_geometry("POINT(0 0)", "LINESTRING(0 0, 2 2, 3 2, 0 0)", "0FFFFF1F2"); + test_geometry("POINT(1 1)", "LINESTRING(0 0, 2 2, 3 2, 0 0)", "0FFFFF1F2"); + test_geometry("POINT(3 2)", "LINESTRING(0 0, 2 2, 3 2, 0 0)", "0FFFFF1F2"); + test_geometry("POINT(1 0)", "LINESTRING(0 0, 2 2, 3 2, 0 0)", "FF0FFF1F2"); +} + +template +void test_point_multilinestring() +{ + typedef bg::model::linestring

ls; + typedef bg::model::multi_linestring mls; + + test_geometry("POINT(0 0)", "MULTILINESTRING((0 0, 2 0, 2 2),(0 0, 0 2))", "0FFFFF102"); + test_geometry("POINT(0 0)", "MULTILINESTRING((0 0, 2 0, 2 2),(0 0, 0 2, 2 2))", "0FFFFF1F2"); + test_geometry("POINT(0 0)", "MULTILINESTRING((0 0, 2 0, 2 2),(0 0, 0 2, 2 2),(0 0, 1 1))", "F0FFFF102"); + + test_geometry("POINT(0 0)", "MULTILINESTRING((0 0,5 0),(0 0,0 5,5 0),(0 0,-5 0),(0 0,0 -5,-5 0))", "0FFFFF1F2"); + test_geometry("POINT(5 0)", "MULTILINESTRING((0 0,5 0),(0 0,0 5,5 0),(0 0,-5 0),(0 0,0 -5,-5 0))", "0FFFFF1F2"); + test_geometry("POINT(1 0)", "MULTILINESTRING((0 0,5 0),(0 0,0 5,5 0),(0 0,-5 0),(0 0,0 -5,-5 0))", "0FFFFF1F2"); +} + +template +void test_all() +{ + test_point_point

(); + test_point_multipoint

(); + test_multipoint_multipoint

(); + test_point_linestring

(); + test_point_multilinestring

(); +} + +int test_main( int , char* [] ) +{ + test_all >(); + test_all >(); + +#if defined(HAVE_TTMATH) + test_all >(); +#endif + + return 0; +} diff --git a/test/algorithms/remove_spikes.cpp b/test/algorithms/remove_spikes.cpp index 97552e570..2545e10ba 100644 --- a/test/algorithms/remove_spikes.cpp +++ b/test/algorithms/remove_spikes.cpp @@ -134,6 +134,32 @@ void test_polygons() test_geometry("spike_with_corner", "POLYGON((0 0,0 4,4 4,4 2,6 2,6 4,6 2,4 2,4 0,0 0))", 16, 16); + + test_geometry("triangle0", + "POLYGON((0 0,0 4,2 0,4 0,0 0))", + 4, 6 + sqrt(20.0)); + test_geometry("triangle1", + "POLYGON((0 4,2 0,4 0,0 0,0 4))", + 4, 6 + sqrt(20.0)); + test_geometry("triangle2", + "POLYGON((2 0,4 0,0 0,0 4,2 0))", + 4, 6 + sqrt(20.0)); + test_geometry("triangle3", + "POLYGON((4 0,0 0,0 4,2 0,4 0))", + 4, 6 + sqrt(20.0)); + + test_geometry("only_spike1", + "POLYGON((0 0,2 2,0 0))", + 0, 0); + test_geometry("only_spike2", + "POLYGON((0 0,2 2,4 4,2 2,0 0))", + 0, 0); + test_geometry("only_spike3", + "POLYGON((0 0,2 2,4 4,0 0))", + 0, 0); + test_geometry("only_spike4", + "POLYGON((0 0,4 4,2 2,0 0))", + 0, 0); } diff --git a/test/algorithms/sym_difference_linear_linear.cpp b/test/algorithms/sym_difference_linear_linear.cpp index ca06eba45..ec58da2f9 100644 --- a/test/algorithms/sym_difference_linear_linear.cpp +++ b/test/algorithms/sym_difference_linear_linear.cpp @@ -18,7 +18,7 @@ #define BOOST_GEOMETRY_DEBUG_SEGMENT_IDENTIFIER #endif -#include +#include #include "test_sym_difference_linear_linear.hpp" diff --git a/test/algorithms/test_difference.hpp b/test/algorithms/test_difference.hpp index 3e38534e8..41e084aac 100644 --- a/test/algorithms/test_difference.hpp +++ b/test/algorithms/test_difference.hpp @@ -57,6 +57,9 @@ void difference_output(std::string const& caseid, G1 const& g1, G2 const& g2, Ou filename << "difference_" << caseid << "_" << string_from_type::name() +#if defined(BOOST_GEOMETRY_NO_ROBUSTNESS) + << "_no_rob" +#endif << ".svg"; std::ofstream svg(filename.str().c_str()); @@ -82,7 +85,7 @@ void difference_output(std::string const& caseid, G1 const& g1, G2 const& g2, Ou template void test_difference(std::string const& caseid, G1 const& g1, G2 const& g2, - std::size_t expected_count, int expected_point_count, + int expected_count, int expected_point_count, double expected_area, double percentage = 0.0001, bool sym = false) @@ -120,15 +123,26 @@ void test_difference(std::string const& caseid, G1 const& g1, G2 const& g2, { // Test inserter functionality // Test if inserter returns output-iterator (using Boost.Range copy) + typedef typename bg::point_type::type point_type; + typedef typename bg::rescale_policy_type::type + rescale_policy_type; + + rescale_policy_type rescale_policy + = bg::get_rescale_policy(g1, g2); + std::vector inserted, array_with_one_empty_geometry; array_with_one_empty_geometry.push_back(OutputType()); if (sym) { - boost::copy(array_with_one_empty_geometry, bg::detail::sym_difference::sym_difference_insert(g1, g2, std::back_inserter(inserted))); + boost::copy(array_with_one_empty_geometry, + bg::detail::sym_difference::sym_difference_insert + (g1, g2, rescale_policy, std::back_inserter(inserted))); } else { - boost::copy(array_with_one_empty_geometry, bg::detail::difference::difference_insert(g1, g2, std::back_inserter(inserted))); + boost::copy(array_with_one_empty_geometry, + bg::detail::difference::difference_insert( + g1, g2, rescale_policy, std::back_inserter(inserted))); } BOOST_CHECK_EQUAL(boost::size(clip), boost::size(inserted) - 1); @@ -148,9 +162,9 @@ void test_difference(std::string const& caseid, G1 const& g1, G2 const& g2, ); } - if (expected_count > 0) + if (expected_count >= 0) { - BOOST_CHECK_MESSAGE(clip.size() == expected_count, + BOOST_CHECK_MESSAGE(int(clip.size()) == expected_count, "difference: " << caseid << " #outputs expected: " << expected_count << " detected: " << clip.size() @@ -173,11 +187,11 @@ static int counter = 0; template void test_one(std::string const& caseid, std::string const& wkt1, std::string const& wkt2, - std::size_t expected_count1, + int expected_count1, int expected_point_count1, double expected_area1, - std::size_t expected_count2, + int expected_count2, int expected_point_count2, double expected_area2, @@ -216,7 +230,8 @@ void test_one(std::string const& caseid, expected_area2, percentage); test_difference(caseid + "_s", g1, g2, expected_count1 + expected_count2, - expected_point_count1 + expected_point_count2, + expected_point_count1 >= 0 && expected_point_count2 >= 0 + ? (expected_point_count1 + expected_point_count2) : -1, expected_area1 + expected_area2, percentage, true); diff --git a/test/algorithms/test_difference_linear_linear.hpp b/test/algorithms/test_difference_linear_linear.hpp index 60c4cbdb5..00146ed1c 100644 --- a/test/algorithms/test_difference_linear_linear.hpp +++ b/test/algorithms/test_difference_linear_linear.hpp @@ -55,7 +55,11 @@ private: bg::reverse(mls_output); } - BOOST_CHECK( equals::apply(mls_diff, mls_output) ); + BOOST_CHECK_MESSAGE( equals::apply(mls_diff, mls_output), + "difference L/L: " << bg::wkt(geometry1) + << " " << bg::wkt(geometry2) + << " -> Expected: " << bg::wkt(mls_diff) + << " computed: " << bg::wkt(mls_output) ); set_operation_output("difference", case_id, geometry1, geometry2, mls_output); diff --git a/test/algorithms/test_get_turns_ll_invariance.hpp b/test/algorithms/test_get_turns_ll_invariance.hpp index 0b6103e47..460face4e 100644 --- a/test/algorithms/test_get_turns_ll_invariance.hpp +++ b/test/algorithms/test_get_turns_ll_invariance.hpp @@ -21,7 +21,6 @@ #include #include -#include namespace bg_detail = ::boost::geometry::detail; namespace bg_turns = bg_detail::turns; @@ -48,11 +47,9 @@ private: typename IntersectionInfo, typename DirInfo > - static inline void apply(Info& info, Point1 const& p1, Point2 const& p2, - IntersectionInfo const& ii, DirInfo const& di) + static inline void apply(Info& , Point1 const& , Point2 const& , + IntersectionInfo const& , DirInfo const& ) { - bg_detail::overlay::calculate_distance_policy::apply - (info, p1, p2, ii, di); } }; diff --git a/test/algorithms/test_intersection.hpp b/test/algorithms/test_intersection.hpp index c9be39cd9..4050af8a6 100644 --- a/test/algorithms/test_intersection.hpp +++ b/test/algorithms/test_intersection.hpp @@ -53,29 +53,31 @@ typename bg::default_area_result::type test_intersection(std::string const& typedef typename bg::coordinate_type::type coordinate_type; typedef typename bg::point_type::type point_type; - typedef bg::strategy_intersection - < - typename bg::cs_tag::type, - G1, - G2, - point_type, - CalculationType - > strategy; - - // Check both normal behaviour, and _inserter behaviour if (! debug) { - std::vector out; - bg::intersection(g1, g2, out); + // Check _inserter behaviour with stratey + typedef bg::strategy_intersection + < + typename bg::cs_tag::type, + G1, + G2, + point_type, + typename bg::rescale_policy_type::type, + CalculationType + > strategy; + std::vector clip; + bg::detail::intersection::intersection_insert(g1, g2, std::back_inserter(clip), strategy()); } - std::vector clip; - bg::detail::intersection::intersection_insert(g1, g2, std::back_inserter(clip), strategy()); + + // Check normal behaviour + std::vector intersection_output; + bg::intersection(g1, g2, intersection_output); typename bg::default_area_result::type length_or_area = 0; int n = 0; - for (typename std::vector::iterator it = clip.begin(); - it != clip.end(); + for (typename std::vector::iterator it = intersection_output.begin(); + it != intersection_output.end(); ++it) { if (expected_point_count > 0) @@ -96,6 +98,7 @@ typename bg::default_area_result::type test_intersection(std::string const& #if ! defined(BOOST_GEOMETRY_NO_BOOST_TEST) +#if ! defined(BOOST_GEOMETRY_NO_ROBUSTNESS) if (expected_point_count > 0) { BOOST_CHECK_MESSAGE(bg::math::abs(n - expected_point_count) < 3, @@ -105,13 +108,14 @@ typename bg::default_area_result::type test_intersection(std::string const& << " type: " << (type_for_assert_message()) ); } +#endif if (expected_count > 0) { - BOOST_CHECK_MESSAGE(clip.size() == expected_count, + BOOST_CHECK_MESSAGE(intersection_output.size() == expected_count, "intersection: " << caseid << " #outputs expected: " << expected_count - << " detected: " << clip.size() + << " detected: " << intersection_output.size() << " type: " << (type_for_assert_message()) ); } @@ -137,6 +141,9 @@ typename bg::default_area_result::type test_intersection(std::string const& << string_from_type::name() << (ccw ? "_ccw" : "") << (open ? "_open" : "") +#if defined(BOOST_GEOMETRY_NO_ROBUSTNESS) + << "_no_rob" +#endif << ".svg"; std::ofstream svg(filename.str().c_str()); @@ -153,8 +160,8 @@ typename bg::default_area_result::type test_intersection(std::string const& mapper.map(g2, "fill-opacity:0.3;fill:rgb(51,51,153);" "stroke:rgb(51,51,153);stroke-width:3"); - for (typename std::vector::const_iterator it = clip.begin(); - it != clip.end(); ++it) + for (typename std::vector::const_iterator it = intersection_output.begin(); + it != intersection_output.end(); ++it) { mapper.map(*it, "fill-opacity:0.2;stroke-opacity:0.4;fill:rgb(255,0,0);" "stroke:rgb(255,0,255);stroke-width:8"); diff --git a/test/algorithms/test_intersection_linear_linear.hpp b/test/algorithms/test_intersection_linear_linear.hpp index 7a55d853f..ae079956b 100644 --- a/test/algorithms/test_intersection_linear_linear.hpp +++ b/test/algorithms/test_intersection_linear_linear.hpp @@ -51,10 +51,15 @@ private: bg::intersection(geometry1, geometry2, mls_output); - BOOST_CHECK( equals::apply(mls_int1, mls_output) - || equals::apply(mls_int2, mls_output) ); + BOOST_CHECK_MESSAGE( equals::apply(mls_int1, mls_output) + || equals::apply(mls_int2, mls_output), + "intersection L/L: " << bg::wkt(geometry1) + << " " << bg::wkt(geometry2) + << " -> Expected: " << bg::wkt(mls_int1) + << " or: " << bg::wkt(mls_int2) + << " computed: " << bg::wkt(mls_output) ); - set_operation_output("intersection", case_id, + set_operation_output("intersection", case_id, geometry1, geometry2, mls_output); #ifdef GEOMETRY_TEST_DEBUG std::cout << "Geometry #1: " << bg::wkt(geometry1) << std::endl; @@ -95,8 +100,13 @@ private: bg::clear(mls_output); bg::intersection(geometry2, geometry1, mls_output); - BOOST_CHECK( equals::apply(mls_int1, mls_output) - || equals::apply(mls_int2, mls_output) ); + BOOST_CHECK_MESSAGE( equals::apply(mls_int1, mls_output) + || equals::apply(mls_int2, mls_output), + "intersection L/L: " << bg::wkt(geometry1) + << " " << bg::wkt(geometry2) + << " -> Expected: " << bg::wkt(mls_int1) + << " or: " << bg::wkt(mls_int2) + << " computed: " << bg::wkt(mls_output) ); #ifdef GEOMETRY_TEST_DEBUG std::cout << "Geometry #1: " << bg::wkt(geometry2) << std::endl; diff --git a/test/algorithms/test_relate.hpp b/test/algorithms/test_relate.hpp index a83c917cf..d3dc358ea 100644 --- a/test/algorithms/test_relate.hpp +++ b/test/algorithms/test_relate.hpp @@ -1,33 +1,130 @@ // Boost.Geometry (aka GGL, Generic Geometry Library) -// Unit Test -// Copyright (c) 2010-2012 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. + +// This file was modified by Oracle on 2013, 2014. +// Modifications copyright (c) 2013-2014 Oracle and/or its affiliates. + // 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) +// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle + #ifndef BOOST_GEOMETRY_TEST_RELATE_HPP #define BOOST_GEOMETRY_TEST_RELATE_HPP -#include +#include +#include +#include +#include +#include +#include -static std::string disjoint_simplex[2] = - {"POLYGON((0 0,0 2,2 2,0 0))", - "POLYGON((1 0,3 2,3 0,1 0))"}; +#include -static std::string touch_simplex[2] = - {"POLYGON((0 0,0 2,2 2,0 0))", - "POLYGON((2 2,3 2,3 0,2 2))"}; +#include +#include +#include -static std::string overlaps_box[2] = - {"POLYGON((0 0,0 2,2 2,0 0))", - "POLYGON((1 1,3 2,3 0,1 1))"}; +#include +#include +#include -static std::string within_simplex[2] = - {"POLYGON((0 0,1 4,4 1,0 0))", - "POLYGON((1 1,1 3,3 1,1 1))"}; +#include +#include +#include +namespace bgdr = bg::detail::relate; -#endif +std::string transposed(std::string matrix) +{ + std::swap(matrix[1], matrix[3]); + std::swap(matrix[2], matrix[6]); + std::swap(matrix[5], matrix[7]); + return matrix; +} + +template +void check_geometry(Geometry1 const& geometry1, + Geometry2 const& geometry2, + std::string const& wkt1, + std::string const& wkt2, + std::string const& expected) +{ + { + std::string res_str = bgdr::relate(geometry1, geometry2); + bool ok = boost::equal(res_str, expected); + BOOST_CHECK_MESSAGE(ok, + "relate: " << wkt1 + << " and " << wkt2 + << " -> Expected: " << expected + << " detected: " << res_str); + } + + // changed sequence of geometries - transposed result + { + std::string res_str = bgdr::relate(geometry2, geometry1, bgdr::matrix9()); + std::string expected_tr = transposed(expected); + bool ok = boost::equal(res_str, expected_tr); + BOOST_CHECK_MESSAGE(ok, + "relate: " << wkt2 + << " and " << wkt1 + << " -> Expected: " << expected_tr + << " detected: " << res_str); + } + + { + bool result = bgdr::relate(geometry1, geometry2, bgdr::mask9(expected)); + // TODO: SHOULD BE !interrupted - CHECK THIS! + BOOST_CHECK_MESSAGE(result, + "relate: " << wkt1 + << " and " << wkt2 + << " -> Expected: " << expected); + } + + if ( bg::detail::relate::interruption_enabled::value ) + { + // brake the expected output + std::string expected_interrupt = expected; + bool changed = false; + BOOST_FOREACH(char & c, expected_interrupt) + { + if ( c >= '0' && c <= '9' ) + { + if ( c == '0' ) + c = 'F'; + else + --c; + + changed = true; + } + } + + if ( changed ) + { + bool result = bgdr::relate(geometry1, geometry2, bgdr::mask9(expected_interrupt)); + // TODO: SHOULD BE interrupted - CHECK THIS! + BOOST_CHECK_MESSAGE(!result, + "relate: " << wkt1 + << " and " << wkt2 + << " -> Expected interrupt for:" << expected_interrupt); + } + } +} + +template +void test_geometry(std::string const& wkt1, + std::string const& wkt2, + std::string const& expected) +{ + Geometry1 geometry1; + Geometry2 geometry2; + bg::read_wkt(wkt1, geometry1); + bg::read_wkt(wkt2, geometry2); + check_geometry(geometry1, geometry2, wkt1, wkt2, expected); +} + +#endif // BOOST_GEOMETRY_TEST_RELATE_HPP diff --git a/test/algorithms/test_set_ops_pl_pl.hpp b/test/algorithms/test_set_ops_pl_pl.hpp index 7919b992e..607592e82 100644 --- a/test/algorithms/test_set_ops_pl_pl.hpp +++ b/test/algorithms/test_set_ops_pl_pl.hpp @@ -196,9 +196,14 @@ private: set_op::apply(geometry1, geometry2, mp_output); - BOOST_CHECK( equals::apply(mp_expected, mp_output) ); - std::string op_name = set_op::name(); + + BOOST_CHECK_MESSAGE( equals::apply(mp_expected, mp_output), + op_name << " P/P: " << bg::wkt(geometry1) + << " " << bg::wkt(geometry2) + << " -> Expected: " << bg::wkt(mp_expected) + << " computed: " << bg::wkt(mp_output) ); + set_operation_output(op_name, case_id, geometry1, geometry2, mp_output); diff --git a/test/algorithms/test_sym_difference_linear_linear.hpp b/test/algorithms/test_sym_difference_linear_linear.hpp index 50ab1d042..d7b9d7f07 100644 --- a/test/algorithms/test_sym_difference_linear_linear.hpp +++ b/test/algorithms/test_sym_difference_linear_linear.hpp @@ -49,7 +49,12 @@ private: bg::sym_difference(geometry1, geometry2, mls_output); - BOOST_CHECK( equals::apply(mls_sym_diff, mls_output) ); + BOOST_CHECK_MESSAGE( equals::apply(mls_sym_diff, mls_output), + "sym diff L/L: " << bg::wkt(geometry1) + << " " << bg::wkt(geometry2) + << " -> Expected: " << bg::wkt(mls_sym_diff) + << " computed: " << bg::wkt(mls_output) ); + set_operation_output("sym_difference", case_id, geometry1, geometry2, mls_output); @@ -93,7 +98,11 @@ private: bg::clear(mls_output); bg::sym_difference(geometry2, geometry1, mls_output); - BOOST_CHECK( equals::apply(mls_sym_diff, mls_output) ); + BOOST_CHECK_MESSAGE( equals::apply(mls_sym_diff, mls_output), + "sym diff L/L: " << bg::wkt(geometry2) + << " " << bg::wkt(geometry1) + << " -> Expected: " << bg::wkt(mls_sym_diff) + << " computed: " << bg::wkt(mls_output) ); #ifdef GEOMETRY_TEST_DEBUG std::cout << "Geometry #1: " << bg::wkt(geometry2) << std::endl; diff --git a/test/algorithms/test_union.hpp b/test/algorithms/test_union.hpp index 710b92101..70dd3783e 100644 --- a/test/algorithms/test_union.hpp +++ b/test/algorithms/test_union.hpp @@ -97,12 +97,14 @@ void test_union(std::string const& caseid, G1 const& g1, G2 const& g2, << std::endl; #endif +#if ! defined(BOOST_GEOMETRY_NO_ROBUSTNESS) BOOST_CHECK_MESSAGE(expected_point_count < 0 || std::abs(int(n) - expected_point_count) < 3, "union: " << caseid << " #points expected: " << expected_point_count << " detected: " << n << " type: " << (type_for_assert_message()) ); +#endif BOOST_CHECK_MESSAGE(expected_count < 0 || int(clip.size()) == expected_count, "union: " << caseid @@ -135,6 +137,9 @@ void test_union(std::string const& caseid, G1 const& g1, G2 const& g2, << string_from_type::name() << (ccw ? "_ccw" : "") << (open ? "_open" : "") +#if defined(BOOST_GEOMETRY_NO_ROBUSTNESS) + << "_no_rob" +#endif << ".svg"; std::ofstream svg(filename.str().c_str()); diff --git a/test/algorithms/test_union_linear_linear.hpp b/test/algorithms/test_union_linear_linear.hpp index a8a0417c0..35f5eb791 100644 --- a/test/algorithms/test_union_linear_linear.hpp +++ b/test/algorithms/test_union_linear_linear.hpp @@ -50,9 +50,13 @@ private: bg::union_(geometry1, geometry2, mls_output); - BOOST_CHECK( equals::apply(mls_union1, mls_output) ); + BOOST_CHECK_MESSAGE( equals::apply(mls_union1, mls_output), + "union L/L: " << bg::wkt(geometry1) + << " " << bg::wkt(geometry2) + << " -> Expected: " << bg::wkt(mls_union1) + << " computed: " << bg::wkt(mls_output) ); - set_operation_output("union", case_id, + set_operation_output("union", case_id, geometry1, geometry2, mls_output); #ifdef GEOMETRY_TEST_DEBUG @@ -94,7 +98,11 @@ private: bg::clear(mls_output); bg::union_(geometry2, geometry1, mls_output); - BOOST_CHECK( equals::apply(mls_union2, mls_output) ); + BOOST_CHECK_MESSAGE( equals::apply(mls_union2, mls_output), + "union L/L: " << bg::wkt(geometry2) + << " " << bg::wkt(geometry1) + << " -> Expected: " << bg::wkt(mls_union2) + << " computed: " << bg::wkt(mls_output) ); #ifdef GEOMETRY_TEST_DEBUG std::cout << "Geometry #1: " << bg::wkt(geometry2) << std::endl; diff --git a/test/algorithms/touches.cpp b/test/algorithms/touches.cpp index 551b30bb1..fd696217b 100644 --- a/test/algorithms/touches.cpp +++ b/test/algorithms/touches.cpp @@ -2,24 +2,28 @@ // // Copyright (c) 2012 Barend Gehrels, Amsterdam, the Netherlands. -// This file was modified by Oracle on 2013. -// Modifications copyright (c) 2013, Oracle and/or its affiliates. +// This file was modified by Oracle on 2013, 2014. +// Modifications copyright (c) 2013, 2014, Oracle and/or its affiliates. // 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) +// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle + #include #include #include - +#include template void test_all() { + typedef bg::model::box

box; + typedef bg::model::ring

ring; typedef bg::model::polygon

polygon; typedef bg::model::linestring

linestring; typedef bg::model::multi_polygon mpolygon; @@ -134,6 +138,7 @@ void test_all() ); // Point-Polygon + test_touches("POINT(40 50)", "POLYGON((40 40,40 60,60 60,60 40,40 40))", true); test_touches("POINT(40 50)", "POLYGON((40 40,40 60,60 60,60 40,40 40))", true); test_touches("POINT(60 60)", "POLYGON((40 40,40 60,60 60,60 40,40 40))", true); test_touches("POINT(50 50)", "POLYGON((40 40,40 60,60 60,60 40,40 40))", false); @@ -179,22 +184,53 @@ void test_all() test_touches("LINESTRING(0 0,1 1,2 2)", "LINESTRING(1 1,1 2,2 2,2 0)", true); test_touches("LINESTRING(2 2,1 1,0 0)", "LINESTRING(1 1,1 2,2 2,2 0)", true); + test_touches("LINESTRING(0 0,1 1,0 1)", "LINESTRING(1 1,2 2,1 2,1 1)", false); + + test_touches("LINESTRING(0 0,1 1,0 1)", "MULTILINESTRING((1 1,2 2),(1 2,1 1))", false); + //Linestring-Polygon test_touches("LINESTRING(10 0,15 5,10 10,5 15,5 10,0 10,5 15,5 10)", "POLYGON((0 0,0 10,10 10,10 0,0 0))", true); test_touches("LINESTRING(5 10,5 15,0 10,5 10,5 15,10 10,15 5,10 0)", "POLYGON((0 0,0 10,10 10,10 0,0 0))", true); test_touches("LINESTRING(5 10,5 15,0 10,5 10,5 15,10 10,5 5,10 0)", "POLYGON((0 0,0 10,10 10,10 0,0 0))", false); + test_touches("LINESTRING(0 15,5 5)", "POLYGON((0 0,0 10,10 10,10 0,0 0))", false); test_touches("LINESTRING(0 15,5 5)", "POLYGON((0 0,0 10,10 10,10 0,0 0))", false); test_touches("LINESTRING(0 15,5 10,5 5)", "POLYGON((0 0,0 10,10 10,10 0,0 0))", false); test_touches("LINESTRING(10 15,5 10,0 5)", "POLYGON((0 0,0 10,10 10,10 0,0 0))", false); + + test_touches("LINESTRING(0 0,3 3)", "POLYGON((0 0,0 10,10 10,10 0,0 0),(0 0,9 1,9 9,1 9,0 0))", true); + + test_touches("LINESTRING(-1 -1,3 3)", "MULTIPOLYGON(((0 0,0 10,10 10,10 0,0 0),(0 0,9 1,9 9,1 9,0 0)))", true); + + test_touches("MULTILINESTRING((0 0,11 11))", "MULTIPOLYGON(((0 0,0 10,10 10,10 0,0 0),(0 0,9 1,9 9,1 9,0 0)))", false); + + test_touches("POLYGON((0 0,0 5,5 5,5 0,0 0))", "POLYGON((5 1,5 2,6 2,6 1,5 1))", true); + test_touches("POLYGON((0 0,0 5,5 5,5 0,0 0))", "POLYGON((4 1,4 2,5 2,5 1,4 1))", false); + test_touches("POLYGON((0 0,0 5,5 5,5 0,0 0))", "POLYGON((4 1,4 2,6 2,6 1,4 1))", false); + + // Point-size + test_touches("POLYGON((0 0,0 5,5 5,5 0,0 0))", "POLYGON((5 5,5 5,5 5,5 5,5 5))", true); + // TODO: should it be TRUE? + test_touches("POLYGON((5 5,5 5,5 5,5 5,5 5))", "POLYGON((5 5,5 5,5 5,5 5,5 5))", true); } +template +void test_box_3d() +{ + typedef bg::model::box

box; + check_touches(box(P(0,0,0),P(5,5,5)), box(P(5,1,2),P(6,6,6)), + "box(P(0,0,0),P(5,5,5))", "box(P(5,1,2),P(6,6,6))", + true); + check_touches(box(P(0,0,0),P(5,5,5)), box(P(5,5,5),P(6,6,6)), + "box(P(0,0,0),P(5,5,5))", "box(P(5,5,5),P(6,6,6))", + true); +} int test_main( int , char* [] ) { test_all >(); - + test_box_3d >(); #if defined(HAVE_TTMATH) test_all >(); diff --git a/test/algorithms/union.cpp b/test/algorithms/union.cpp index 8479369fe..a806e5221 100644 --- a/test/algorithms/union.cpp +++ b/test/algorithms/union.cpp @@ -15,6 +15,10 @@ #include #include +// If defined, tests are run without rescaling-to-integer or robustness policy +// Test which would fail then are disabled automatically +// #define BOOST_GEOMETRY_NO_ROBUSTNESS + #include #include @@ -221,17 +225,11 @@ void test_areal() test_one("ggl_list_20110627_phillip", ggl_list_20110627_phillip[0], ggl_list_20110627_phillip[1], - 1, 0, - if_typed(5, if_typed_tt(8, 8)), - 14729.07145); + 1, 0, 8, 14729.07145); - - // FP might return different amount of points test_one("ggl_list_20110716_enrico", ggl_list_20110716_enrico[0], ggl_list_20110716_enrico[1], - 1, 1, - if_typed(18, if_typed(-1, 17)), - 129904.197692871); + 1, 1, 15, 129904.197692871); test_one("ggl_list_20110820_christophe", ggl_list_20110820_christophe[0], ggl_list_20110820_christophe[1], @@ -272,14 +270,37 @@ void test_areal() test_one("ticket_8310c", ticket_8310c[0], ticket_8310c[1], 1, 0, 5, 10.5000019595); + test_one("ticket_9081_15", + ticket_9081_15[0], ticket_9081_15[1], + 1, 0, 7, 0.0403425433); + +#if ! defined(BOOST_GEOMETRY_NO_ROBUSTNESS) + test_one("ticket_9563", ticket_9563[0], ticket_9563[1], + 1, 0, 13, 150.0); +#endif + + test_one("ticket_9756", ticket_9756[0], ticket_9756[1], + 1, 0, 10, 1289.08374); + + test_one("geos_1", geos_1[0], geos_1[1], + 1, 0, -1, 3461.3203125); + test_one("geos_2", geos_2[0], geos_2[1], + 1, 0, -1, 350.55102539); + test_one("geos_3", geos_3[0], geos_3[1], + 1, 0, -1, 29391548.4998779); + test_one("geos_4", geos_4[0], geos_4[1], + 1, 0, -1, 2304.4163115); + test_one("buffer_rt_a", buffer_rt_a[0], buffer_rt_a[1], 1, 0, 265, 19.280667); // Robustness issues, followed out buffer-robustness-tests, test them also reverse +#if ! defined(BOOST_GEOMETRY_NO_ROBUSTNESS) test_one("buffer_rt_f", buffer_rt_f[0], buffer_rt_f[1], 1, 0, if_typed(21, 23), 4.60853); test_one("buffer_rt_f_rev", buffer_rt_f[1], buffer_rt_f[0], 1, 0, if_typed(21, 23), 4.60853); +#endif test_one("buffer_rt_g", buffer_rt_g[0], buffer_rt_g[1], 1, 0, if_typed(18, 17), 16.571); @@ -288,31 +309,20 @@ void test_areal() test_one("buffer_rt_i", buffer_rt_i[0], buffer_rt_i[1], 1, 0, if_typed(14, 13), 13.6569); - - bool test_rt_i_rev = true; -#ifndef _MSC_VER - if (boost::is_same::type::value) - { - // TODO: this case has to be fixed for gcc/float on non-Windows - test_rt_i_rev = false; - } - -#endif - if (test_rt_i_rev) - { - test_one("buffer_rt_i_rev", buffer_rt_i[1], buffer_rt_i[0], + test_one("buffer_rt_i_rev", buffer_rt_i[1], buffer_rt_i[0], 1, 0, 13, 13.6569); - } test_one("buffer_rt_j", buffer_rt_j[0], buffer_rt_j[1], 1, 0, -1, 16.5711); test_one("buffer_rt_j_rev", buffer_rt_j[1], buffer_rt_j[0], 1, 0, -1, 16.5711); +#if ! defined(BOOST_GEOMETRY_NO_ROBUSTNESS) test_one("buffer_rt_l", buffer_rt_l[0], buffer_rt_l[1], 1, 0, -1, 19.3995); test_one("buffer_rt_l_rev", buffer_rt_l[1], buffer_rt_l[0], 1, 0, -1, 19.3995); +#endif test_one("buffer_rt_m1", buffer_rt_m1[0], buffer_rt_m1[1], 1, 0, if_typed_tt(14, 13), 19.4852); @@ -329,18 +339,24 @@ void test_areal() test_one("buffer_rt_q_rev", buffer_rt_q[1], buffer_rt_q[0], 1, 0, 18, 18.5710); +#if ! defined(BOOST_GEOMETRY_NO_ROBUSTNESS) test_one("buffer_rt_r", buffer_rt_r[0], buffer_rt_r[1], 1, 0, 19, 21.07612); test_one("buffer_rt_r_rev", buffer_rt_r[1], buffer_rt_r[0], 1, 0, if_typed_tt(20, 19), 21.07612); +#endif +#if ! defined(BOOST_GEOMETRY_NO_ROBUSTNESS) test_one("buffer_rt_t", buffer_rt_t[0], buffer_rt_t[1], 1, 0, if_typed_tt(16, 14), 15.6569); +#endif test_one("buffer_rt_t_ref", buffer_rt_t[1], buffer_rt_t[0], 1, 0, if_typed_tt(16, if_typed(15, 14)), 15.6569); +#if ! defined(BOOST_GEOMETRY_NO_ROBUSTNESS) test_one("buffer_mp1", buffer_mp1[0], buffer_mp1[1], 1, 0, if_typed_tt(93, 91), 22.815); +#endif test_one("buffer_mp2", buffer_mp2[0], buffer_mp2[1], 1, 0, 217, 36.752837); @@ -409,7 +425,10 @@ int test_main(int, char* []) test_all >(); #if ! defined(BOOST_GEOMETRY_TEST_ONLY_ONE_TYPE) + +#if ! defined(BOOST_GEOMETRY_NO_ROBUSTNESS) test_all >(); +#endif //test_all >(); #if defined(HAVE_TTMATH) diff --git a/test/algorithms/union_linear_linear.cpp b/test/algorithms/union_linear_linear.cpp index 4ebfe2eda..c454564f0 100644 --- a/test/algorithms/union_linear_linear.cpp +++ b/test/algorithms/union_linear_linear.cpp @@ -18,7 +18,7 @@ #define BOOST_GEOMETRY_DEBUG_SEGMENT_IDENTIFIER #endif -#include +#include #include "test_union_linear_linear.hpp" diff --git a/test/algorithms/union_pl_pl.cpp b/test/algorithms/union_pl_pl.cpp index 2d74964d8..f458d9fba 100644 --- a/test/algorithms/union_pl_pl.cpp +++ b/test/algorithms/union_pl_pl.cpp @@ -18,7 +18,7 @@ #define BOOST_GEOMETRY_DEBUG_SEGMENT_IDENTIFIER #endif -#include +#include #include "test_set_ops_pl_pl.hpp" diff --git a/test/algorithms/within.cpp b/test/algorithms/within.cpp index fbb75f756..824129a50 100644 --- a/test/algorithms/within.cpp +++ b/test/algorithms/within.cpp @@ -22,227 +22,9 @@ #include #include -template -void test_p_p() -{ - typedef bg::model::multi_point

mpt; - - test_geometry("POINT(0 0)", "POINT(0 0)", true); - test_geometry("POINT(0 0)", "POINT(1 1)", false); - - test_geometry("POINT(0 0)", "MULTIPOINT(0 0, 1 1)", true); - test_geometry("POINT(0 0)", "MULTIPOINT(1 1, 2 2)", false); -} - -template -void test_p_l() -{ - typedef bg::model::linestring

ls; - typedef bg::model::multi_linestring mls; - - test_geometry("POINT(0 0)", "LINESTRING(0 0,1 1,2 2)", false); - test_geometry("POINT(3 3)", "LINESTRING(0 0,1 1,2 2)", false); - test_geometry("POINT(1 1)", "LINESTRING(0 0,2 2,3 3)", true); - - test_geometry("POINT(1 1)", "LINESTRING(0 0, 2 2)", true); - test_geometry("POINT(0 0)", "LINESTRING(0 0, 1 1)", false); - - test_geometry("POINT(0 0)", "MULTILINESTRING((0 0,1 1,2 2),(0 0,0 1))", true); - test_geometry("POINT(0 0)", "MULTILINESTRING((0 0,1 1,2 2),(0 0,0 1),(0 0,1 0))", false); - - test_geometry("POINT(1 1)", "MULTILINESTRING((0 0, 1 1),(1 1, 2 2))", true); - test_geometry("POINT(1 1)", "MULTILINESTRING((0 0, 1 1),(2 2, 3 3))", false); -} - -template -void test_p_a() -{ - // trivial case - test_ring

("POINT(1 1)", "POLYGON((0 0,0 2,2 2,2 0,0 0))", true, false); - - // on border/corner - test_ring

("POINT(0 0)", "POLYGON((0 0,0 2,2 2,2 0,0 0))", false, true); - test_ring

("POINT(0 1)", "POLYGON((0 0,0 2,2 2,2 0,0 0))", false, true); - - // aligned to segment/vertex - test_ring

("POINT(1 1)", "POLYGON((0 0,0 3,3 3,3 1,2 1,2 0,0 0))", true, false); - test_ring

("POINT(1 1)", "POLYGON((0 0,0 3,4 3,3 1,2 2,2 0,0 0))", true, false); - - // same polygon, but point on border - test_ring

("POINT(3 3)", "POLYGON((0 0,0 3,3 3,3 1,2 1,2 0,0 0))", false, true); - test_ring

("POINT(3 3)", "POLYGON((0 0,0 3,4 3,3 1,2 2,2 0,0 0))", false, true); - - // holes - test_geometry >("POINT(2 2)", - "POLYGON((0 0,0 4,4 4,4 0,0 0),(1 1,3 1,3 3,1 3,1 1))", false); - - // Real-life problem (solved now), point is in the middle, 409623 is also a coordinate - // on the border, has been wrong in the past (2009) - test_ring

("POINT(146383 409623)", - "POLYGON((146351 410597,146521 410659,147906 410363,148088 410420" - ",148175 410296,148281 409750,148215 409623,148154 409666,148154 409666" - ",148130 409625,148035 409626,148035 409626,148008 409544,147963 409510" - ",147993 409457,147961 409352,147261 408687,147008 408586,145714 408840" - ",145001 409033,144486 409066,144616 409308,145023 410286,145254 410488" - ",145618 410612,145618 410612,146015 410565,146190 410545,146351 410597))", - true, false); -} - -template -void test_l_l() -{ - typedef bg::model::linestring

ls; - typedef bg::model::multi_linestring mls; - - test_geometry("LINESTRING(0 0, 2 2, 3 2)", "LINESTRING(0 0, 2 2, 3 2)", true); - - test_geometry("LINESTRING(0 0, 1 1, 2 2, 3 2)", "LINESTRING(0 0, 2 2, 3 2)", true); - test_geometry("LINESTRING(3 2, 2 2, 1 1, 0 0)", "LINESTRING(0 0, 2 2, 3 2)", true); - test_geometry("LINESTRING(0 0, 1 1, 2 2, 3 2)", "LINESTRING(3 2, 2 2, 0 0)", true); - test_geometry("LINESTRING(3 2, 2 2, 1 1, 0 0)", "LINESTRING(3 2, 2 2, 0 0)", true); - - test_geometry("LINESTRING(1 1, 2 2, 3 2)", "LINESTRING(0 0, 2 2, 4 2)", true); - test_geometry("LINESTRING(3 2, 2 2, 1 1)", "LINESTRING(0 0, 2 2, 4 2)", true); - test_geometry("LINESTRING(1 1, 2 2, 3 2)", "LINESTRING(4 2, 2 2, 0 0)", true); - test_geometry("LINESTRING(3 2, 2 2, 1 1)", "LINESTRING(4 2, 2 2, 0 0)", true); - - test_geometry("LINESTRING(1 1, 2 2, 3 3)", "LINESTRING(0 0, 2 2, 4 2)", false); - test_geometry("LINESTRING(1 1, 2 2, 3 2, 3 3)", "LINESTRING(0 0, 2 2, 4 2)", false); - test_geometry("LINESTRING(1 1, 2 2, 3 1)", "LINESTRING(0 0, 2 2, 4 2)", false); - test_geometry("LINESTRING(1 1, 2 2, 3 2, 3 1)", "LINESTRING(0 0, 2 2, 4 2)", false); - - test_geometry("LINESTRING(0 1, 1 1, 2 2, 3 2)", "LINESTRING(0 0, 2 2, 4 2)", false); - test_geometry("LINESTRING(0 1, 0 0, 2 2, 3 2)", "LINESTRING(0 0, 2 2, 4 2)", false); - test_geometry("LINESTRING(1 0, 1 1, 2 2, 3 2)", "LINESTRING(0 0, 2 2, 4 2)", false); - test_geometry("LINESTRING(1 0, 0 0, 2 2, 3 2)", "LINESTRING(0 0, 2 2, 4 2)", false); - - // duplicated points - test_geometry("LINESTRING(1 1, 2 2, 2 2)", "LINESTRING(0 0, 2 2, 4 2)", true); - test_geometry("LINESTRING(1 1, 1 1, 2 2)", "LINESTRING(0 0, 2 2, 4 2)", true); - - test_geometry("LINESTRING(0 0, 0 0, 0 0, 1 1, 2 2, 2 2, 2 2, 2 2, 2 2, 2 2, 2 2, 2 2, 2 2, 2 2, 2 2, 2 2, 2 2, 2 2, 2 2, 2 2, 2 2, 2 2, 3 3)", - "LINESTRING(0 0, 2 2, 4 4)", true); - - // invalid linestrings -// test_geometry("LINESTRING(0 0)", "LINESTRING(0 0)", false); -// test_geometry("LINESTRING(1 1)", "LINESTRING(0 0, 2 2)", true); -// test_geometry("LINESTRING(0 0)", "LINESTRING(0 0, 2 2)", false); -// test_geometry("LINESTRING(0 0, 1 1)", "LINESTRING(0 0)", false); - - // spikes - // FOR NOW DISABLED - - /*test_geometry("LINESTRING(0 0,5 0,3 0,6 0)", "LINESTRING(0 0,6 0)", true); - - test_geometry("LINESTRING(0 0,2 2,3 3,1 1)", "LINESTRING(0 0,3 3,6 3)", true); - test_geometry("LINESTRING(0 0,3 3,6 3)", "LINESTRING(0 0,2 2,3 3,1 1)", false); - test_geometry("LINESTRING(0 0,2 2,3 3,1 1)", "LINESTRING(0 0,4 4,6 3)", true); - test_geometry("LINESTRING(0 0,4 4,6 3)", "LINESTRING(0 0,2 2,3 3,1 1)", false); - - test_geometry("LINESTRING(0 0,2 2,3 3,1 1,5 3)", "LINESTRING(0 0,3 3,6 3)", false);*/ - - test_geometry("LINESTRING(1 1, 2 2)", "MULTILINESTRING((0 0, 2 2),(3 3, 4 4))", true); - - test_geometry("MULTILINESTRING((0 0, 2 2),(3 3, 4 4))", "LINESTRING(0 0, 5 5)", true); - - test_geometry("MULTILINESTRING((1 1, 2 2),(3 3, 4 4))", "MULTILINESTRING((1 1, 2 2),(2 2, 5 5))", true); -} - -template -void test_l_a() -{ - typedef bg::model::linestring

ls; - typedef bg::model::multi_linestring mls; - typedef bg::model::polygon

poly; - typedef bg::model::ring

ring; - typedef bg::model::multi_polygon mpoly; - - // B,I - test_geometry("LINESTRING(0 0, 2 2)", "POLYGON((0 0,0 5,5 5,5 0,0 0))", true); - - // B,I - test_geometry("LINESTRING(0 0, 2 2)", "POLYGON((0 0,0 5,5 5,5 0,0 0))", true); - // I - test_geometry("LINESTRING(1 1, 2 2)", "POLYGON((0 0,0 5,5 5,5 0,0 0))", true); - // I,E - test_geometry("LINESTRING(1 1, 6 6)", "POLYGON((0 0,0 5,5 5,5 0,0 0))", false); - // B - test_geometry("LINESTRING(0 0, 5 0)", "POLYGON((0 0,0 5,5 5,5 0,0 0))", false); - test_geometry("LINESTRING(0 0, 0 5)", "POLYGON((0 0,0 5,5 5,5 0,0 0))", false); - // E - test_geometry("LINESTRING(6 0, 6 5)", "POLYGON((0 0,0 5,5 5,5 0,0 0))", false); - - // BIBIB - test_geometry("LINESTRING(0 0, 10 10)", "MULTIPOLYGON(((0 0,0 5,5 5,5 0,0 0)),((5 5,5 10,10 10,10 5,5 5)))", true); - // BIBEBIB - test_geometry("LINESTRING(0 0, 10 10)", "MULTIPOLYGON(((0 0,0 5,5 5,5 0,0 0)),((6 6,5 10,10 10,10 5,6 6)))", false); - - // BI - test_geometry("MULTILINESTRING((0 0,2 2),(2 2,3 3))", "POLYGON((0 0,0 5,5 5,5 0,0 0))", true); - // I E - test_geometry("MULTILINESTRING((1 1,2 2),(6 6,7 7))", "POLYGON((0 0,0 5,5 5,5 0,0 0))", false); - - // I I - test_geometry("MULTILINESTRING((1 1,5 5),(6 6,7 7))", - "MULTIPOLYGON(((0 0,0 5,5 5,5 0,0 0)),((5 5,5 10,10 10,10 5,5 5)))", - true); - // I E - test_geometry("MULTILINESTRING((1 1,5 5),(11 11,12 12))", - "MULTIPOLYGON(((0 0,0 5,5 5,5 0,0 0)),((5 5,5 10,10 10,10 5,5 5)))", - false); -} - -template -void test_a_a() -{ - typedef bg::model::polygon

poly; - typedef bg::model::ring

ring; - typedef bg::model::multi_polygon mpoly; - - test_geometry("POLYGON((0 0,0 2,2 2,2 0,0 0))", "POLYGON((0 0,0 5,5 5,5 0,0 0))", true); - test_geometry("POLYGON((0 0,0 5,5 5,5 0,0 0))", "POLYGON((0 0,0 5,5 5,5 0,0 0))", true); - test_geometry("POLYGON((0 0,0 6,6 6,6 0,0 0))", "POLYGON((0 0,0 5,5 5,5 0,0 0))", false); - - test_geometry("POLYGON((0 0,0 9,9 9,9 0,0 0),(3 3,6 3,6 6,3 6,3 3))", - "POLYGON((0 0,0 9,9 9,9 0,0 0),(3 3,6 3,6 6,3 6,3 3))", true); - test_geometry("POLYGON((0 0,0 9,9 9,9 0,0 0),(3 3,6 3,6 6,3 6,3 3))", - "POLYGON((0 0,0 9,9 9,9 0,0 0),(4 4,5 4,5 5,4 5,4 4))", true); - test_geometry("POLYGON((1 1,1 8,8 8,8 1,1 1),(3 3,6 3,6 6,3 6,3 3))", - "POLYGON((0 0,0 9,9 9,9 0,0 0),(3 3,6 3,6 6,3 6,3 3))", true); - test_geometry("POLYGON((1 1,1 8,8 8,8 1,1 1),(3 3,6 3,6 6,3 6,3 3))", - "POLYGON((0 0,0 9,9 9,9 0,0 0),(4 4,5 4,5 5,4 5,4 4))", true); - - test_geometry("POLYGON((0 0,0 2,2 2,2 0,0 0))", - "MULTIPOLYGON(((0 0,0 5,5 5,5 0,0 0)),((5 5,5 10,10 10,10 5,5 5)))", true); - test_geometry("POLYGON((0 0,0 2,2 2,2 0,0 0))", - "MULTIPOLYGON(((0 0,0 5,5 5,5 0,0 0)),((5 5,5 10,10 10,10 5,5 5)))", true); - - test_geometry("MULTIPOLYGON(((0 0,0 5,5 5,5 0,0 0)),((5 5,5 10,10 10,10 5,5 5)))", - "POLYGON((0 0,0 10,10 10,10 0,0 0))", true); - test_geometry("MULTIPOLYGON(((0 0,0 5,5 5,5 0,0 0)),((15 15,15 110,110 110,110 15,15 15)))", - "POLYGON((0 0,0 10,10 10,10 0,0 0))", false); - - test_geometry("MULTIPOLYGON(((0 0,0 1,1 0,0 0)),((3 3,3 4,4 3,3 3)))", - "POLYGON((0 0,0 10,10 10,10 0,0 0),(3 3,4 3,4 4,3 4,3 3))", false); - - test_geometry("MULTIPOLYGON(((0 0,0 1,1 0,0 0)),((3 3,3 4,4 3,3 3)))", - "MULTIPOLYGON(((0 0,0 1,1 0,0 0)),((3 3,3 4,4 3,3 3)))", true); - test_geometry("MULTIPOLYGON(((0 0,0 1,1 0,0 0)),((3 3,3 4,4 3,3 3)))", - "MULTIPOLYGON(((0 0,0 5,5 5,5 0,0 0)),((5 5,5 10,10 10,10 5,5 5)))", true); - test_geometry("MULTIPOLYGON(((0 0,0 5,5 5,5 0,0 0)),((5 5,5 10,10 10,10 5,5 5)))", - "MULTIPOLYGON(((0 0,0 1,1 0,0 0)),((3 3,3 4,4 3,3 3)))", false); -} - template void test_all() { - test_p_p

(); - test_p_l

(); - test_p_a

(); - test_l_l

(); - test_l_a

(); - test_a_a

(); - typedef bg::model::box

box_type; test_geometry("POINT(1 1)", "BOX(0 0,2 2)", true); @@ -276,48 +58,6 @@ void test_all() template void test_spherical() { - typedef typename bg::coordinate_type::type ct; - bg::model::polygon wrangel; - - // SQL Server check (no geography::STWithin, so check with intersection trick) - /* - - with q as ( - select geography::STGeomFromText('POLYGON((-178.569 71.5641,-179.034 71.5977,-179.305 71.5514,-179.629 71.5772,-180 71.5358,179.53 71.4383,178.872 71.2175,178.618 71.0355,178.791 70.7964,179.273 70.8886,179.678 70.8955,-180 70.9972,-179.274 70.9078,-178.819 70.98,-177.939 71.0375,-177.62 71.1166,-177.439 71.2269,-177.503 71.2775,-177.833 71.3461,-178.018 71.4497,-178.569 71.5641))',4326) as wrangel - ) - - select wrangel.STArea()/1000000.0 - ,geography::STGeomFromText('POINT(-179.3 71.27)',4326).STIntersection(wrangel).STAsText() as workaround_within_1 - ,geography::STGeomFromText('POINT(-179.9 70.95)',4326).STIntersection(wrangel).STAsText() as workaround_within_2 - ,geography::STGeomFromText('POINT(179.9 70.95)',4326).STIntersection(wrangel).STAsText() as workaround_within_3 - from q - - -> 7669.10402181435 POINT (-179.3 71.27) GEOMETRYCOLLECTION EMPTY GEOMETRYCOLLECTION EMPTY - - PostGIS knows Within for Geography neither, and the intersection trick gives the same result - - */ - - bg::read_wkt("POLYGON((-178.568604 71.564148,-178.017548 71.449692,-177.833313 71.3461,-177.502838 71.277466 ,-177.439453 71.226929,-177.620026 71.116638,-177.9389 71.037491,-178.8186 70.979965,-179.274445 70.907761,-180 70.9972,179.678314 70.895538,179.272766 70.888596,178.791016 70.7964,178.617737 71.035538,178.872192 71.217484,179.530273 71.4383 ,-180 71.535843 ,-179.628601 71.577194,-179.305298 71.551361,-179.03421 71.597748,-178.568604 71.564148))", wrangel); - - bool within = bg::within(Point(-179.3, 71.27), wrangel); - BOOST_CHECK_EQUAL(within, true); - - within = bg::within(Point(-179.9, 70.95), wrangel); - BOOST_CHECK_EQUAL(within, false); - - within = bg::within(Point(179.9, 70.95), wrangel); - BOOST_CHECK_EQUAL(within, false); - - // Test using great circle mapper - // http://www.gcmap.com/mapui?P=5E52N-9E53N-7E50N-5E52N,7E52.5N,8E51.5N,6E51N - - bg::model::polygon triangle; - bg::read_wkt("POLYGON((5 52,9 53,7 50,5 52))", triangle); - BOOST_CHECK_EQUAL(bg::within(Point(7, 52.5), triangle), true); - BOOST_CHECK_EQUAL(bg::within(Point(8.0, 51.5), triangle), false); - BOOST_CHECK_EQUAL(bg::within(Point(6.0, 51.0), triangle), false); - // Test spherical boxes // See also http://www.gcmap.com/mapui?P=1E45N-19E45N-19E55N-1E55N-1E45N,10E55.1N,10E45.1N bg::model::box box; @@ -431,33 +171,8 @@ void test_strategy() } -void test_large_integers() -{ - typedef bg::model::point int_point_type; - typedef bg::model::point double_point_type; - - std::string const polygon_li = "POLYGON((1872000 528000,1872000 192000,1536119 192000,1536000 528000,1200000 528000,1200000 863880,1536000 863880,1872000 863880,1872000 528000))"; - bg::model::polygon int_poly; - bg::model::polygon double_poly; - bg::read_wkt(polygon_li, int_poly); - bg::read_wkt(polygon_li, double_poly); - - std::string const point_li = "POINT(1592000 583950)"; - int_point_type int_point; - double_point_type double_point; - bg::read_wkt(point_li, int_point); - bg::read_wkt(point_li, double_point); - - bool wi = bg::within(int_point, int_poly); - bool wd = bg::within(double_point, double_poly); - - BOOST_CHECK_MESSAGE(wi == wd, "within different from within"); -} - int test_main( int , char* [] ) { - test_large_integers(); - test_all >(); test_all >(); diff --git a/test/algorithms/within_areal_areal.cpp b/test/algorithms/within_areal_areal.cpp new file mode 100644 index 000000000..57f417d95 --- /dev/null +++ b/test/algorithms/within_areal_areal.cpp @@ -0,0 +1,80 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2013 Adam Wulkiewicz, Lodz, Poland. + +// This file was modified by Oracle on 2014. +// Modifications copyright (c) 2014 Oracle and/or its affiliates. + +// 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) + +// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle + +#include + + +#include +#include +#include +#include + +template +void test_a_a() +{ + typedef bg::model::polygon

poly; + typedef bg::model::ring

ring; + typedef bg::model::multi_polygon mpoly; + + test_geometry("POLYGON((0 0,0 2,2 2,2 0,0 0))", "POLYGON((0 0,0 5,5 5,5 0,0 0))", true); + test_geometry("POLYGON((0 0,0 5,5 5,5 0,0 0))", "POLYGON((0 0,0 5,5 5,5 0,0 0))", true); + test_geometry("POLYGON((0 0,0 6,6 6,6 0,0 0))", "POLYGON((0 0,0 5,5 5,5 0,0 0))", false); + + test_geometry("POLYGON((0 0,0 9,9 9,9 0,0 0),(3 3,6 3,6 6,3 6,3 3))", + "POLYGON((0 0,0 9,9 9,9 0,0 0),(3 3,6 3,6 6,3 6,3 3))", true); + test_geometry("POLYGON((0 0,0 9,9 9,9 0,0 0),(3 3,6 3,6 6,3 6,3 3))", + "POLYGON((0 0,0 9,9 9,9 0,0 0),(4 4,5 4,5 5,4 5,4 4))", true); + test_geometry("POLYGON((1 1,1 8,8 8,8 1,1 1),(3 3,6 3,6 6,3 6,3 3))", + "POLYGON((0 0,0 9,9 9,9 0,0 0),(3 3,6 3,6 6,3 6,3 3))", true); + test_geometry("POLYGON((1 1,1 8,8 8,8 1,1 1),(3 3,6 3,6 6,3 6,3 3))", + "POLYGON((0 0,0 9,9 9,9 0,0 0),(4 4,5 4,5 5,4 5,4 4))", true); + + test_geometry("POLYGON((0 0,0 2,2 2,2 0,0 0))", + "MULTIPOLYGON(((0 0,0 5,5 5,5 0,0 0)),((5 5,5 10,10 10,10 5,5 5)))", true); + test_geometry("POLYGON((0 0,0 2,2 2,2 0,0 0))", + "MULTIPOLYGON(((0 0,0 5,5 5,5 0,0 0)),((5 5,5 10,10 10,10 5,5 5)))", true); + + test_geometry("MULTIPOLYGON(((0 0,0 5,5 5,5 0,0 0)),((5 5,5 10,10 10,10 5,5 5)))", + "POLYGON((0 0,0 10,10 10,10 0,0 0))", true); + test_geometry("MULTIPOLYGON(((0 0,0 5,5 5,5 0,0 0)),((15 15,15 110,110 110,110 15,15 15)))", + "POLYGON((0 0,0 10,10 10,10 0,0 0))", false); + + test_geometry("MULTIPOLYGON(((0 0,0 1,1 0,0 0)),((3 3,3 4,4 3,3 3)))", + "POLYGON((0 0,0 10,10 10,10 0,0 0),(3 3,4 3,4 4,3 4,3 3))", false); + + test_geometry("MULTIPOLYGON(((0 0,0 1,1 0,0 0)),((3 3,3 4,4 3,3 3)))", + "MULTIPOLYGON(((0 0,0 1,1 0,0 0)),((3 3,3 4,4 3,3 3)))", true); + test_geometry("MULTIPOLYGON(((0 0,0 1,1 0,0 0)),((3 3,3 4,4 3,3 3)))", + "MULTIPOLYGON(((0 0,0 5,5 5,5 0,0 0)),((5 5,5 10,10 10,10 5,5 5)))", true); + test_geometry("MULTIPOLYGON(((0 0,0 5,5 5,5 0,0 0)),((5 5,5 10,10 10,10 5,5 5)))", + "MULTIPOLYGON(((0 0,0 1,1 0,0 0)),((3 3,3 4,4 3,3 3)))", false); +} + +template +void test_all() +{ + test_a_a

(); +} + +int test_main( int , char* [] ) +{ + test_all >(); + test_all >(); + +#if defined(HAVE_TTMATH) + test_all >(); +#endif + + return 0; +} diff --git a/test/algorithms/within_linear_areal.cpp b/test/algorithms/within_linear_areal.cpp new file mode 100644 index 000000000..68f9ce396 --- /dev/null +++ b/test/algorithms/within_linear_areal.cpp @@ -0,0 +1,85 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2013 Adam Wulkiewicz, Lodz, Poland. + +// This file was modified by Oracle on 2014. +// Modifications copyright (c) 2014 Oracle and/or its affiliates. + +// 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) + +// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle + +#include + + +#include +#include +#include +#include +#include + +template +void test_l_a() +{ + typedef bg::model::linestring

ls; + typedef bg::model::multi_linestring mls; + typedef bg::model::polygon

poly; + typedef bg::model::ring

ring; + typedef bg::model::multi_polygon mpoly; + + // B,I + test_geometry("LINESTRING(0 0, 2 2)", "POLYGON((0 0,0 5,5 5,5 0,0 0))", true); + + // B,I + test_geometry("LINESTRING(0 0, 2 2)", "POLYGON((0 0,0 5,5 5,5 0,0 0))", true); + // I + test_geometry("LINESTRING(1 1, 2 2)", "POLYGON((0 0,0 5,5 5,5 0,0 0))", true); + // I,E + test_geometry("LINESTRING(1 1, 6 6)", "POLYGON((0 0,0 5,5 5,5 0,0 0))", false); + // B + test_geometry("LINESTRING(0 0, 5 0)", "POLYGON((0 0,0 5,5 5,5 0,0 0))", false); + test_geometry("LINESTRING(0 0, 0 5)", "POLYGON((0 0,0 5,5 5,5 0,0 0))", false); + // E + test_geometry("LINESTRING(6 0, 6 5)", "POLYGON((0 0,0 5,5 5,5 0,0 0))", false); + + // BIBIB + test_geometry("LINESTRING(0 0, 10 10)", "MULTIPOLYGON(((0 0,0 5,5 5,5 0,0 0)),((5 5,5 10,10 10,10 5,5 5)))", true); + // BIBEBIB + test_geometry("LINESTRING(0 0, 10 10)", "MULTIPOLYGON(((0 0,0 5,5 5,5 0,0 0)),((6 6,5 10,10 10,10 5,6 6)))", false); + + // BI + test_geometry("MULTILINESTRING((0 0,2 2),(2 2,3 3))", "POLYGON((0 0,0 5,5 5,5 0,0 0))", true); + // I E + test_geometry("MULTILINESTRING((1 1,2 2),(6 6,7 7))", "POLYGON((0 0,0 5,5 5,5 0,0 0))", false); + + // I I + test_geometry("MULTILINESTRING((1 1,5 5),(6 6,7 7))", + "MULTIPOLYGON(((0 0,0 5,5 5,5 0,0 0)),((5 5,5 10,10 10,10 5,5 5)))", + true); + // I E + test_geometry("MULTILINESTRING((1 1,5 5),(11 11,12 12))", + "MULTIPOLYGON(((0 0,0 5,5 5,5 0,0 0)),((5 5,5 10,10 10,10 5,5 5)))", + false); +} + +template +void test_all() +{ + test_l_a

(); +} + +int test_main( int , char* [] ) +{ + test_all >(); + test_all >(); + + +#if defined(HAVE_TTMATH) + test_all >(); +#endif + + return 0; +} diff --git a/test/algorithms/within_linear_linear.cpp b/test/algorithms/within_linear_linear.cpp new file mode 100644 index 000000000..bf77d4cb8 --- /dev/null +++ b/test/algorithms/within_linear_linear.cpp @@ -0,0 +1,99 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2013 Adam Wulkiewicz, Lodz, Poland. + +// This file was modified by Oracle on 2014. +// Modifications copyright (c) 2014 Oracle and/or its affiliates. + +// 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) + +// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle + +#include + + +#include +#include +#include +#include + +template +void test_l_l() +{ + typedef bg::model::linestring

ls; + typedef bg::model::multi_linestring mls; + + test_geometry("LINESTRING(0 0, 2 2, 3 2)", "LINESTRING(0 0, 2 2, 3 2)", true); + + test_geometry("LINESTRING(0 0, 1 1, 2 2, 3 2)", "LINESTRING(0 0, 2 2, 3 2)", true); + test_geometry("LINESTRING(3 2, 2 2, 1 1, 0 0)", "LINESTRING(0 0, 2 2, 3 2)", true); + test_geometry("LINESTRING(0 0, 1 1, 2 2, 3 2)", "LINESTRING(3 2, 2 2, 0 0)", true); + test_geometry("LINESTRING(3 2, 2 2, 1 1, 0 0)", "LINESTRING(3 2, 2 2, 0 0)", true); + + test_geometry("LINESTRING(1 1, 2 2, 3 2)", "LINESTRING(0 0, 2 2, 4 2)", true); + test_geometry("LINESTRING(3 2, 2 2, 1 1)", "LINESTRING(0 0, 2 2, 4 2)", true); + test_geometry("LINESTRING(1 1, 2 2, 3 2)", "LINESTRING(4 2, 2 2, 0 0)", true); + test_geometry("LINESTRING(3 2, 2 2, 1 1)", "LINESTRING(4 2, 2 2, 0 0)", true); + + test_geometry("LINESTRING(1 1, 2 2, 3 3)", "LINESTRING(0 0, 2 2, 4 2)", false); + test_geometry("LINESTRING(1 1, 2 2, 3 2, 3 3)", "LINESTRING(0 0, 2 2, 4 2)", false); + test_geometry("LINESTRING(1 1, 2 2, 3 1)", "LINESTRING(0 0, 2 2, 4 2)", false); + test_geometry("LINESTRING(1 1, 2 2, 3 2, 3 1)", "LINESTRING(0 0, 2 2, 4 2)", false); + + test_geometry("LINESTRING(0 1, 1 1, 2 2, 3 2)", "LINESTRING(0 0, 2 2, 4 2)", false); + test_geometry("LINESTRING(0 1, 0 0, 2 2, 3 2)", "LINESTRING(0 0, 2 2, 4 2)", false); + test_geometry("LINESTRING(1 0, 1 1, 2 2, 3 2)", "LINESTRING(0 0, 2 2, 4 2)", false); + test_geometry("LINESTRING(1 0, 0 0, 2 2, 3 2)", "LINESTRING(0 0, 2 2, 4 2)", false); + + // duplicated points + test_geometry("LINESTRING(1 1, 2 2, 2 2)", "LINESTRING(0 0, 2 2, 4 2)", true); + test_geometry("LINESTRING(1 1, 1 1, 2 2)", "LINESTRING(0 0, 2 2, 4 2)", true); + + test_geometry("LINESTRING(0 0, 0 0, 0 0, 1 1, 2 2, 2 2, 2 2, 2 2, 2 2, 2 2, 2 2, 2 2, 2 2, 2 2, 2 2, 2 2, 2 2, 2 2, 2 2, 2 2, 2 2, 2 2, 3 3)", + "LINESTRING(0 0, 2 2, 4 4)", true); + + // invalid linestrings +// test_geometry("LINESTRING(0 0)", "LINESTRING(0 0)", false); +// test_geometry("LINESTRING(1 1)", "LINESTRING(0 0, 2 2)", true); +// test_geometry("LINESTRING(0 0)", "LINESTRING(0 0, 2 2)", false); +// test_geometry("LINESTRING(0 0, 1 1)", "LINESTRING(0 0)", false); + + // spikes + // FOR NOW DISABLED + + /*test_geometry("LINESTRING(0 0,5 0,3 0,6 0)", "LINESTRING(0 0,6 0)", true); + + test_geometry("LINESTRING(0 0,2 2,3 3,1 1)", "LINESTRING(0 0,3 3,6 3)", true); + test_geometry("LINESTRING(0 0,3 3,6 3)", "LINESTRING(0 0,2 2,3 3,1 1)", false); + test_geometry("LINESTRING(0 0,2 2,3 3,1 1)", "LINESTRING(0 0,4 4,6 3)", true); + test_geometry("LINESTRING(0 0,4 4,6 3)", "LINESTRING(0 0,2 2,3 3,1 1)", false); + + test_geometry("LINESTRING(0 0,2 2,3 3,1 1,5 3)", "LINESTRING(0 0,3 3,6 3)", false);*/ + + test_geometry("LINESTRING(1 1, 2 2)", "MULTILINESTRING((0 0, 2 2),(3 3, 4 4))", true); + + test_geometry("MULTILINESTRING((0 0, 2 2),(3 3, 4 4))", "LINESTRING(0 0, 5 5)", true); + + test_geometry("MULTILINESTRING((1 1, 2 2),(3 3, 4 4))", "MULTILINESTRING((1 1, 2 2),(2 2, 5 5))", true); +} + +template +void test_all() +{ + test_l_l

(); +} + +int test_main( int , char* [] ) +{ + test_all >(); + test_all >(); + +#if defined(HAVE_TTMATH) + test_all >(); +#endif + + return 0; +} diff --git a/test/algorithms/within_pointlike_xxx.cpp b/test/algorithms/within_pointlike_xxx.cpp new file mode 100644 index 000000000..8d463cdbb --- /dev/null +++ b/test/algorithms/within_pointlike_xxx.cpp @@ -0,0 +1,195 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2013 Adam Wulkiewicz, Lodz, Poland. + +// This file was modified by Oracle on 2014. +// Modifications copyright (c) 2014 Oracle and/or its affiliates. + +// 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) + +// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle + +#include + + +#include +#include +#include +#include +#include +#include + +template +void test_p_p() +{ + typedef bg::model::multi_point

mpt; + + test_geometry("POINT(0 0)", "POINT(0 0)", true); + test_geometry("POINT(0 0)", "POINT(1 1)", false); + + test_geometry("POINT(0 0)", "MULTIPOINT(0 0, 1 1)", true); + test_geometry("POINT(0 0)", "MULTIPOINT(1 1, 2 2)", false); +} + +template +void test_p_l() +{ + typedef bg::model::linestring

ls; + typedef bg::model::multi_linestring mls; + + test_geometry("POINT(0 0)", "LINESTRING(0 0,1 1,2 2)", false); + test_geometry("POINT(3 3)", "LINESTRING(0 0,1 1,2 2)", false); + test_geometry("POINT(1 1)", "LINESTRING(0 0,2 2,3 3)", true); + + test_geometry("POINT(1 1)", "LINESTRING(0 0, 2 2)", true); + test_geometry("POINT(0 0)", "LINESTRING(0 0, 1 1)", false); + + test_geometry("POINT(0 0)", "MULTILINESTRING((0 0,1 1,2 2),(0 0,0 1))", true); + test_geometry("POINT(0 0)", "MULTILINESTRING((0 0,1 1,2 2),(0 0,0 1),(0 0,1 0))", false); + + test_geometry("POINT(1 1)", "MULTILINESTRING((0 0, 1 1),(1 1, 2 2))", true); + test_geometry("POINT(1 1)", "MULTILINESTRING((0 0, 1 1),(2 2, 3 3))", false); +} + +template +void test_p_a() +{ + typedef bg::model::polygon

poly; + typedef bg::model::multi_polygon mpoly; + + // trivial case + test_ring

("POINT(1 1)", "POLYGON((0 0,0 2,2 2,2 0,0 0))", true, false); + + // on border/corner + test_ring

("POINT(0 0)", "POLYGON((0 0,0 2,2 2,2 0,0 0))", false, true); + test_ring

("POINT(0 1)", "POLYGON((0 0,0 2,2 2,2 0,0 0))", false, true); + + // aligned to segment/vertex + test_ring

("POINT(1 1)", "POLYGON((0 0,0 3,3 3,3 1,2 1,2 0,0 0))", true, false); + test_ring

("POINT(1 1)", "POLYGON((0 0,0 3,4 3,3 1,2 2,2 0,0 0))", true, false); + + // same polygon, but point on border + test_ring

("POINT(3 3)", "POLYGON((0 0,0 3,3 3,3 1,2 1,2 0,0 0))", false, true); + test_ring

("POINT(3 3)", "POLYGON((0 0,0 3,4 3,3 1,2 2,2 0,0 0))", false, true); + + // holes + test_geometry("POINT(2 2)", + "POLYGON((0 0,0 4,4 4,4 0,0 0),(1 1,3 1,3 3,1 3,1 1))", false); + + // Real-life problem (solved now), point is in the middle, 409623 is also a coordinate + // on the border, has been wrong in the past (2009) + test_ring

("POINT(146383 409623)", + "POLYGON((146351 410597,146521 410659,147906 410363,148088 410420" + ",148175 410296,148281 409750,148215 409623,148154 409666,148154 409666" + ",148130 409625,148035 409626,148035 409626,148008 409544,147963 409510" + ",147993 409457,147961 409352,147261 408687,147008 408586,145714 408840" + ",145001 409033,144486 409066,144616 409308,145023 410286,145254 410488" + ",145618 410612,145618 410612,146015 410565,146190 410545,146351 410597))", + true, false); + + test_geometry("POINT(2 2)", + "MULTIPOLYGON(((0 0,0 4,4 4,4 0,0 0),(1 1,3 1,3 3,1 3,1 1)),((5 5,5 9,9 9,9 5,5 5)))", false); + test_geometry("POINT(1 1)", + "MULTIPOLYGON(((0 0,0 4,4 4,4 0,0 0),(1 1,3 1,3 3,1 3,1 1)),((5 5,5 9,9 9,9 5,5 5)))", false); + test_geometry("POINT(1 1)", + "MULTIPOLYGON(((0 0,0 5,5 5,5 0,0 0),(2 2,4 2,4 4,2 4,2 2)),((5 5,5 9,9 9,9 5,5 5)))", true); + test_geometry("POINT(6 6)", + "MULTIPOLYGON(((0 0,0 4,4 4,4 0,0 0),(1 1,3 1,3 3,1 3,1 1)),((5 5,5 9,9 9,9 5,5 5)))", true); +} + +template +void test_all() +{ + test_p_p

(); + test_p_l

(); + test_p_a

(); +} + +template +void test_spherical() +{ + typedef typename bg::coordinate_type::type ct; + bg::model::polygon wrangel; + + // SQL Server check (no geography::STWithin, so check with intersection trick) + /* + + with q as ( + select geography::STGeomFromText('POLYGON((-178.569 71.5641,-179.034 71.5977,-179.305 71.5514,-179.629 71.5772,-180 71.5358,179.53 71.4383,178.872 71.2175,178.618 71.0355,178.791 70.7964,179.273 70.8886,179.678 70.8955,-180 70.9972,-179.274 70.9078,-178.819 70.98,-177.939 71.0375,-177.62 71.1166,-177.439 71.2269,-177.503 71.2775,-177.833 71.3461,-178.018 71.4497,-178.569 71.5641))',4326) as wrangel + ) + + select wrangel.STArea()/1000000.0 + ,geography::STGeomFromText('POINT(-179.3 71.27)',4326).STIntersection(wrangel).STAsText() as workaround_within_1 + ,geography::STGeomFromText('POINT(-179.9 70.95)',4326).STIntersection(wrangel).STAsText() as workaround_within_2 + ,geography::STGeomFromText('POINT(179.9 70.95)',4326).STIntersection(wrangel).STAsText() as workaround_within_3 + from q + + -> 7669.10402181435 POINT (-179.3 71.27) GEOMETRYCOLLECTION EMPTY GEOMETRYCOLLECTION EMPTY + + PostGIS knows Within for Geography neither, and the intersection trick gives the same result + + */ + + bg::read_wkt("POLYGON((-178.568604 71.564148,-178.017548 71.449692,-177.833313 71.3461,-177.502838 71.277466 ,-177.439453 71.226929,-177.620026 71.116638,-177.9389 71.037491,-178.8186 70.979965,-179.274445 70.907761,-180 70.9972,179.678314 70.895538,179.272766 70.888596,178.791016 70.7964,178.617737 71.035538,178.872192 71.217484,179.530273 71.4383 ,-180 71.535843 ,-179.628601 71.577194,-179.305298 71.551361,-179.03421 71.597748,-178.568604 71.564148))", wrangel); + + bool within = bg::within(Point(-179.3, 71.27), wrangel); + BOOST_CHECK_EQUAL(within, true); + + within = bg::within(Point(-179.9, 70.95), wrangel); + BOOST_CHECK_EQUAL(within, false); + + within = bg::within(Point(179.9, 70.95), wrangel); + BOOST_CHECK_EQUAL(within, false); + + // Test using great circle mapper + // http://www.gcmap.com/mapui?P=5E52N-9E53N-7E50N-5E52N,7E52.5N,8E51.5N,6E51N + + bg::model::polygon triangle; + bg::read_wkt("POLYGON((5 52,9 53,7 50,5 52))", triangle); + BOOST_CHECK_EQUAL(bg::within(Point(7, 52.5), triangle), true); + BOOST_CHECK_EQUAL(bg::within(Point(8.0, 51.5), triangle), false); + BOOST_CHECK_EQUAL(bg::within(Point(6.0, 51.0), triangle), false); +} + +void test_large_integers() +{ + typedef bg::model::point int_point_type; + typedef bg::model::point double_point_type; + + std::string const polygon_li = "POLYGON((1872000 528000,1872000 192000,1536119 192000,1536000 528000,1200000 528000,1200000 863880,1536000 863880,1872000 863880,1872000 528000))"; + bg::model::polygon int_poly; + bg::model::polygon double_poly; + bg::read_wkt(polygon_li, int_poly); + bg::read_wkt(polygon_li, double_poly); + + std::string const point_li = "POINT(1592000 583950)"; + int_point_type int_point; + double_point_type double_point; + bg::read_wkt(point_li, int_point); + bg::read_wkt(point_li, double_point); + + bool wi = bg::within(int_point, int_poly); + bool wd = bg::within(double_point, double_poly); + + BOOST_CHECK_MESSAGE(wi == wd, "within different from within"); +} + +int test_main( int , char* [] ) +{ + test_large_integers(); + + test_all >(); + test_all >(); + + test_spherical > >(); + +#if defined(HAVE_TTMATH) + test_all >(); + test_spherical > >(); +#endif + + return 0; +} diff --git a/test/geometry_test_common.hpp b/test/geometry_test_common.hpp index 3990e6619..fdaec1e57 100644 --- a/test/geometry_test_common.hpp +++ b/test/geometry_test_common.hpp @@ -98,9 +98,15 @@ template <> struct string_from_type template <> struct string_from_type { static std::string name() { return "e"; } }; +template <> struct string_from_type +{ static std::string name() { return "s"; } }; + template <> struct string_from_type { static std::string name() { return "i"; } }; +template <> struct string_from_type +{ static std::string name() { return "l"; } }; + #if defined(HAVE_TTMATH) template <> struct string_from_type { static std::string name() { return "t"; } }; @@ -129,6 +135,7 @@ inline T1 if_typed_tt(T1 value_tt, T2 value) #if defined(HAVE_TTMATH) return boost::is_same::type::value ? value_tt : value; #else + boost::ignore_unused_variable_warning(value_tt); return value; #endif } diff --git a/test/multi/algorithms/multi_difference.cpp b/test/multi/algorithms/multi_difference.cpp index 44513b7b5..49c8fae2c 100644 --- a/test/multi/algorithms/multi_difference.cpp +++ b/test/multi/algorithms/multi_difference.cpp @@ -10,6 +10,10 @@ #include #include +// If defined, tests are run without rescaling-to-integer or robustness policy +// This multi_difference currently contains no tests for double which then fail +// #define BOOST_GEOMETRY_NO_ROBUSTNESS + //#define HAVE_TTMATH //#define BOOST_GEOMETRY_DEBUG_ASSEMBLE //#define BOOST_GEOMETRY_CHECK_WITH_SQLSERVER diff --git a/test/multi/algorithms/multi_difference_spike.cpp b/test/multi/algorithms/multi_difference_spike.cpp index 335de20f9..6753a2380 100644 --- a/test/multi/algorithms/multi_difference_spike.cpp +++ b/test/multi/algorithms/multi_difference_spike.cpp @@ -39,22 +39,22 @@ void test_spikes_in_ticket_8364() test_one("ticket_8364_step3", "MULTIPOLYGON(((3232 2532,2136 2790,1032 1764,1032 1458,1032 1212,2136 2328,3232 2220,3232 1056,1031 1056,1031 2856,3232 2856,3232 2532)))", "MULTIPOLYGON(((1032 2130,2052 2712,1032 1764,1032 2130)),((3234 2580,3234 2532,2558 2690,3234 2580)),((2558 2690,2136 2760,2052 2712,2136 2790,2558 2690)))", - if_typed(1, 2), - if_typed(15, 22), - if_typed(2775561.0, 2775256.487954), // SQL Server: 2775256.47588724 + 2, + if_typed(19, 22), + if_typed(2775595.5, 2775256.487954), // SQL Server: 2775256.47588724 3, - 14, - if_typed(7710.5, 7810.487954)); // SQL Server: 7810.48711165739 + -1, // don't check point-count + if_typed(7907.0, 7810.487954)); // SQL Server: 7810.48711165739 test_one("ticket_8364_step4", "MULTIPOLYGON(((2567 2688,2136 2790,2052 2712,1032 2130,1032 1764,1032 1458,1032 1212,2136 2328,3232 2220,3232 1056,1031 1056,1031 2856,3232 2856,3232 2580,2567 2688)))", "MULTIPOLYGON(((1032 2556,1778 2556,1032 2130,1032 2556)),((3234 2580,3234 2556,1778 2556,2136 2760,3234 2580)))", 1, if_typed(17, 20), - if_typed(2616292.0, 2616029.559567), // SQL Server: 2616029.55616044 + if_typed(2616125.0, 2616029.559567), // SQL Server: 2616029.55616044 1, if_typed(9, 11), - if_typed(160996.0, 161054.559567)); // SQL Server: 161054.560110092 + if_typed(161211.5, 161054.559567)); // SQL Server: 161054.560110092 } template @@ -74,8 +74,8 @@ void test_spikes_in_ticket_8365() if_typed(17, 21), if_typed(7974930.5, 7975207.6047877), // SQL Server: 2, - 9, - if_typed(199.0, 197.1047877)); // SQL Server: + -1, + if_typed(196.5, 197.1047877)); // SQL Server: } @@ -85,13 +85,13 @@ void test_spikes_in_ticket_8365() int test_main(int, char* []) { test_spikes_in_ticket_8364, true, true>(); - test_spikes_in_ticket_8364, true, true>(); test_spikes_in_ticket_8364, false, false>(); - test_spikes_in_ticket_8364, false, false>(); - test_spikes_in_ticket_8365, true, true>(); - test_spikes_in_ticket_8365, true, true >(); test_spikes_in_ticket_8365, false, false>(); + + test_spikes_in_ticket_8364, true, true>(); + test_spikes_in_ticket_8364, false, false>(); + test_spikes_in_ticket_8365, true, true >(); test_spikes_in_ticket_8365, false, false >(); #ifdef HAVE_TTMATH diff --git a/test/multi/algorithms/multi_disjoint.cpp b/test/multi/algorithms/multi_disjoint.cpp index b61a0ad75..070bfbb6e 100644 --- a/test/multi/algorithms/multi_disjoint.cpp +++ b/test/multi/algorithms/multi_disjoint.cpp @@ -29,7 +29,7 @@ #include -#include +#include template diff --git a/test/multi/algorithms/multi_intersection.cpp b/test/multi/algorithms/multi_intersection.cpp index 0370e14a3..625ff1415 100644 --- a/test/multi/algorithms/multi_intersection.cpp +++ b/test/multi/algorithms/multi_intersection.cpp @@ -10,6 +10,10 @@ #include #include +// If defined, tests are run without rescaling-to-integer or robustness policy +// This multi_intersection currently contains no tests for double then failing +// #define BOOST_GEOMETRY_NO_ROBUSTNESS + // #define BOOST_GEOMETRY_DEBUG_ASSEMBLE #include diff --git a/test/multi/algorithms/multi_touches.cpp b/test/multi/algorithms/multi_touches.cpp index 0389cc8e9..8774beaf2 100644 --- a/test/multi/algorithms/multi_touches.cpp +++ b/test/multi/algorithms/multi_touches.cpp @@ -16,6 +16,7 @@ #include #include #include +#include #include #include diff --git a/test/multi/algorithms/multi_union.cpp b/test/multi/algorithms/multi_union.cpp index 0eee17c65..2e1e309a6 100644 --- a/test/multi/algorithms/multi_union.cpp +++ b/test/multi/algorithms/multi_union.cpp @@ -10,6 +10,9 @@ #include #include +// If defined, tests are run without rescaling-to-integer or robustness policy +// This multi_union currently contains no tests for double which then fail +// #define BOOST_GEOMETRY_NO_ROBUSTNESS #include #include @@ -114,6 +117,10 @@ void test_areal() ggl_list_20120915_h2[0], ggl_list_20120915_h2[2], 1, 0, 12, 23.0); // Area from SQL Server + test_one("ggl_list_20140212_sybren", + ggl_list_20140212_sybren[0], ggl_list_20140212_sybren[1], + 2, 0, 16, 0.002471626); + test_one("ticket_9081", ticket_9081[0], ticket_9081[1], 3, 0, 31, 0.2187385); diff --git a/test/multi/algorithms/overlay/Jamfile.v2 b/test/multi/algorithms/overlay/Jamfile.v2 index a2e9a0ce5..2ea7594e1 100644 --- a/test/multi/algorithms/overlay/Jamfile.v2 +++ b/test/multi/algorithms/overlay/Jamfile.v2 @@ -10,5 +10,5 @@ test-suite boost-geometry-multi-algorithms-overlay : - [ run multi_traverse.cpp ] + [ run multi_traverse.cpp : : : BOOST_GEOMETRY_TEST_ONLY_ONE_TYPE BOOST_GEOMETRY_RESCALE_TO_ROBUST ] ; diff --git a/test/multi/algorithms/overlay/multi_overlay_cases.hpp b/test/multi/algorithms/overlay/multi_overlay_cases.hpp index eaa346a8f..c44b17adb 100644 --- a/test/multi/algorithms/overlay/multi_overlay_cases.hpp +++ b/test/multi/algorithms/overlay/multi_overlay_cases.hpp @@ -442,6 +442,12 @@ static std::string ggl_list_20120221_volker[2] = "MULTIPOLYGON(((3232 2532.469945355191,2136 2790,1032 1764,1032 1458,1032 1212,2136 2328,3232 2220.196721311475,3232 1056,1031 1056,1031 2856,3232 2856,3232 2532.469945355191),(3232 2412.426229508197,2136 2646,3232 2412.426229508197)))" }; +static std::string ggl_list_20140212_sybren[2] = + { + "MULTIPOLYGON(((0.494062 0.659354,0.471383 0.64654,0.446639 0.616561,0.47291 0.61171,0.495396 0.625263,0.494964 0.679709,0.494062 0.659354)))", + "MULTIPOLYGON(((0.4951091661995328 0.6614133543986973,0.495396 0.625263,0.50092 0.6492750000000001,0.494964 0.679709,0.477258 0.698703,0.4951091661995328 0.6614133543986973)),((0.452167 0.706562,0.433379 0.696888,0.442673 0.65792,0.464729 0.671387,0.452167 0.706562)))" + }; + static std::string ticket_9081[2] = { "MULTIPOLYGON(((0.5489109414010371 0.5774835110050927,0.4099611282054447 0.4644351568071598,0.4294011278595494 0.4843224236729239,0.4205359995313906 0.5115225580860201,0.4441572412013468 0.5184999851878852,0.5489109414010371 0.5774835110050927)),((0.562085028126843 0.5882018328808966,0.5644349663154944 0.591180348361206,0.568218114394707 0.5970364466647042,0.5838690879677763 0.6212632646137447,0.5873787029417971 0.6412877041753083,0.468699602592386 0.5866280231830688,0.4171010902425981 0.5220616039851281,0.4059124592966251 0.5563907478354578,0.3909547828925878 0.6022841397455458,0.520859401226844 0.9508041627246925,0.8595233008819849 0.8301950132755517,0.562085028126843 0.5882018328808966)))", diff --git a/test/multi/algorithms/overlay/multi_traverse.cpp b/test/multi/algorithms/overlay/multi_traverse.cpp index faacd3615..7cab06c96 100644 --- a/test/multi/algorithms/overlay/multi_traverse.cpp +++ b/test/multi/algorithms/overlay/multi_traverse.cpp @@ -23,6 +23,7 @@ #include #include +#include #include #include #include @@ -159,7 +160,7 @@ void test_geometries() ); test_traverse_intersection::apply ( - "case_96_multi", 2, 1.0, + "case_96_multi", 1, 0.5, case_96_multi[0], case_96_multi[1] ); test_traverse_intersection::apply diff --git a/test/policies/Jamfile.v2 b/test/policies/Jamfile.v2 index 741c4d1bc..22c58c89c 100644 --- a/test/policies/Jamfile.v2 +++ b/test/policies/Jamfile.v2 @@ -11,4 +11,5 @@ test-suite boost-geometry-policies : [ run compare.cpp ] + [ run rescale_policy.cpp ] ; diff --git a/test/policies/rescale_policy.cpp b/test/policies/rescale_policy.cpp new file mode 100644 index 000000000..c579819c0 --- /dev/null +++ b/test/policies/rescale_policy.cpp @@ -0,0 +1,295 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) +// Unit Test + +// Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. +// Copyright (c) 2008-2012 Bruno Lalande, Paris, France. +// Copyright (c) 2009-2012 Mateusz Loskot, London, UK. + +// 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) + +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + + +#if defined(TEST_WITH_SVG) +# include +#endif + +#include + + +namespace boost { namespace geometry +{ + + +// Overload with rescale-policy specified (temporary here - to be worked out) +template +< + typename Geometry1, + typename Geometry2, + typename RescalePolicy, + typename GeometryOut +> +inline bool intersection(Geometry1 const& geometry1, + Geometry2 const& geometry2, + RescalePolicy const& rescale_policy, + GeometryOut& geometry_out) +{ + concept::check(); + concept::check(); + + typedef strategy_intersection + < + typename cs_tag::type, + Geometry1, + Geometry2, + typename geometry::point_type::type, + RescalePolicy + > strategy; + + return dispatch::intersection + < + Geometry1, + Geometry2 + >::apply(geometry1, geometry2, rescale_policy, geometry_out, strategy()); +} + + +}} // namespace boost::geometry + + +template +< + typename OutputType, + typename CalculationType, + typename Geometry1, + typename Geometry2, + typename RescalePolicy +> +typename bg::default_area_result::type test_intersection(std::string const& caseid, + Geometry1 const& geometry1, Geometry2 const& geometry2, + RescalePolicy const& rescale_policy, + std::size_t expected_count = 0, int expected_point_count = 0, + double expected_length_or_area = 0, + double percentage = 0.0001, + bool debug = false) +{ + typedef typename bg::coordinate_type::type coordinate_type; + typedef typename bg::point_type::type point_type; + +// if (debug) + { + std::cout << std::endl + << "case " << caseid + << " " << typeid(coordinate_type).name() + << " " << string_from_type::name() + << std::endl; + } + + + + std::vector out; + bg::intersection(geometry1, geometry2, rescale_policy, out); + + typename bg::default_area_result::type length_or_area = 0; + int n = 0; + for (typename std::vector::iterator it = out.begin(); + it != out.end(); + ++it) + { + if (expected_point_count > 0) + { + n += bg::num_points(*it, true); + } + + length_or_area += bg::area(*it); + + if (debug) + { + std::cout << std::setprecision(20) << bg::wkt(*it) << std::endl; + } + } + + +#if ! defined(BOOST_GEOMETRY_NO_BOOST_TEST) + if (expected_point_count > 0) + { + BOOST_CHECK_MESSAGE(bg::math::abs(n - expected_point_count) < 3, + "intersection: " << caseid + << " #points expected: " << expected_point_count + << " detected: " << n + << " type: " << (type_for_assert_message()) + ); + } + + if (expected_count > 0) + { + BOOST_CHECK_MESSAGE(out.size() == expected_count, + "intersection: " << caseid + << " #outputs expected: " << expected_count + << " detected: " << out.size() + << " type: " << (type_for_assert_message()) + ); + } + + double const detected_length_or_area = boost::numeric_cast(length_or_area); + BOOST_CHECK_CLOSE(detected_length_or_area, expected_length_or_area, percentage); +#endif + + +#if defined(TEST_WITH_SVG) + { + bool const ccw = + bg::point_order::value == bg::counterclockwise + || bg::point_order::value == bg::counterclockwise; + bool const open = + bg::closure::value == bg::open + || bg::closure::value == bg::open; + + std::ostringstream filename; + filename << "rescale_policy_intersection_" + << caseid << "_" + << string_from_type::name() + << string_from_type::name() + << (ccw ? "_ccw" : "") + << (open ? "_open" : "") + << ".svg"; + + std::ofstream svg(filename.str().c_str()); + + bg::svg_mapper mapper(svg, 500, 500); + + mapper.add(geometry1); + mapper.add(geometry2); + + mapper.map(geometry1, "fill-opacity:0.5;fill:rgb(153,204,0);" + "stroke:rgb(153,204,0);stroke-width:3"); + mapper.map(geometry2, "fill-opacity:0.3;fill:rgb(51,51,153);" + "stroke:rgb(51,51,153);stroke-width:3"); + + for (typename std::vector::const_iterator it = out.begin(); + it != out.end(); ++it) + { + mapper.map(*it, "fill-opacity:0.2;stroke-opacity:0.4;fill:rgb(255,0,0);" + "stroke:rgb(255,0,255);stroke-width:8"); + } + } +#endif + + if (debug) + { + std::cout << "end case " << caseid << std::endl; + } + + return length_or_area; +} + +template +< + typename RescalePolicy, + typename OutputType, + typename Geometry1, + typename Geometry2 +> +typename bg::default_area_result::type test_one(std::string const& caseid, + std::string const& wkt1, std::string const& wkt2, + std::size_t expected_count = 0, int expected_point_count = 0, + double expected_length_or_area = 0, + double percentage = 0.02, + bool debug = false) +{ + Geometry1 geometry1; + bg::read_wkt(wkt1, geometry1); + + Geometry2 geometry2; + bg::read_wkt(wkt2, geometry2); + + // Reverse if necessary + bg::correct(geometry1); + bg::correct(geometry2); + + RescalePolicy rescale_policy + = bg::get_rescale_policy(geometry1, geometry2); + + return test_intersection(caseid, + geometry1, geometry2, + rescale_policy, + expected_count, expected_point_count, + expected_length_or_area, percentage, + debug); +} + +static std::string simplex_normal[2] = + {"POLYGON((0 1,2 5,5 3,0 1))", + "POLYGON((3 0,0 3,4 5,3 0))"}; + +static std::string simplex_large[2] = + {"POLYGON((0 1000,2000 5000,5000 3000,0 1000))", + "POLYGON((3000 0,0 3000,4000 5000,3000 0))"}; + + +template +void test_rescale() +{ + typedef bg::model::polygon

polygon; + + typedef typename boost::mpl::if_c + < + Rescale, + typename bg::rescale_policy_type

::type , + bg::detail::no_rescale_policy + >::type rescale_policy_type; + + std::string suffix = Rescale ? "rescale" : "no_rescale"; + + typedef typename bg::coordinate_type

::type coordinate_type; + if (! boost::is_integral::type::value) + { + test_one("simplex_normal_" + suffix, + simplex_normal[0], simplex_normal[1], + 1, 7, 5.47363293); + } + test_one("simplex_large_" + suffix, + simplex_large[0], simplex_large[1], + 1, 7, 5473632.93); +} + +template +void test_all() +{ + typedef bg::model::d2::point_xy point_type; + test_rescale(); + test_rescale(); +} + + +int test_main(int, char* []) +{ + test_all(); + test_all(); + test_all(); + test_all(); + // test_all(); // compiles but overflows + + return 0; +} + diff --git a/test/strategies/Jamfile.v2 b/test/strategies/Jamfile.v2 index 889ce66a9..9475f6a5d 100644 --- a/test/strategies/Jamfile.v2 +++ b/test/strategies/Jamfile.v2 @@ -15,6 +15,7 @@ test-suite boost-geometry-strategies [ run projected_point.cpp ] [ run pythagoras.cpp ] [ run spherical_side.cpp ] + [ run segment_intersection_collinear.cpp ] [ run transform_cs.cpp ] [ run transformer.cpp ] [ run within.cpp ] diff --git a/test/strategies/segment_intersection.cpp b/test/strategies/segment_intersection.cpp index c0191c18f..fdd66eeb9 100644 --- a/test/strategies/segment_intersection.cpp +++ b/test/strategies/segment_intersection.cpp @@ -103,16 +103,23 @@ static void test_segment_intersection(int caseno, segment_type s34(p3,p4); // Get the intersection point (or two points) - segment_intersection_points

is - = strategy::intersection::relate_cartesian_segments + typedef bg::detail::no_rescale_policy rescale_policy_type; + rescale_policy_type rescale_policy; + + typedef bg::segment_intersection_points + < + P, + typename bg::segment_ratio_type < - policies::relate::segments_intersection_points - < - segment_type, - segment_type, - segment_intersection_points

- > - >::apply(s12, s34); + P, + rescale_policy_type + >::type + > result_type; + + result_type is = strategy::intersection::relate_cartesian_segments + < + bg::policies::relate::segments_intersection_points + >::apply(s12, s34, rescale_policy); // Get the Dimension Extended 9 Intersection Matrix (de9im) for Segments // (this one is extended by GGL having opposite) @@ -127,8 +134,8 @@ static void test_segment_intersection(int caseno, // Get just a character for Left/Right/intersects/etc, purpose is more for debugging policies::relate::direction_type dir = strategy::intersection::relate_cartesian_segments < - policies::relate::segments_direction - >::apply(s12, s34); + policies::relate::segments_direction + >::apply(s12, s34, rescale_policy); int expected_count = 0; diff --git a/test/strategies/segment_intersection_collinear.cpp b/test/strategies/segment_intersection_collinear.cpp index 0466c0955..43693892a 100644 --- a/test/strategies/segment_intersection_collinear.cpp +++ b/test/strategies/segment_intersection_collinear.cpp @@ -12,6 +12,7 @@ // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) +#define BOOST_GEOMETRY_DEFINE_STREAM_OPERATOR_SEGMENT_RATIO #include @@ -31,6 +32,7 @@ #include #include + template static int check(IntersectionPoints const& is, std::size_t index, double expected_x, double expected_y) @@ -58,6 +60,8 @@ static void test_segment_intersection(std::string const& case_id, int expected_x2 = -99, int expected_y2 = -99) { + boost::ignore_unused_variable_warning(case_id); + typedef typename bg::coordinate_type

::type coordinate_type; typedef bg::model::referring_segment segment_type; @@ -70,30 +74,34 @@ static void test_segment_intersection(std::string const& case_id, segment_type s12(p1,p2); segment_type s34(p3,p4); + typedef bg::detail::no_rescale_policy rescale_policy_type; + rescale_policy_type rescale_policy; + + typedef bg::segment_intersection_points + < + P, + typename bg::segment_ratio_type + < + P, + rescale_policy_type + >::type + > result_type; + // Get the intersection point (or two points) - bg::segment_intersection_points

is + result_type is = bg::strategy::intersection::relate_cartesian_segments < - bg::policies::relate::segments_intersection_points - < - segment_type, - segment_type, - bg::segment_intersection_points

- > - >::apply(s12, s34); + bg::policies::relate::segments_intersection_points + >::apply(s12, s34, rescale_policy, p1, p2, p3, p4); // Get just a character for Left/Right/intersects/etc, purpose is more for debugging bg::policies::relate::direction_type dir = bg::strategy::intersection::relate_cartesian_segments < bg::policies::relate::segments_direction - < - segment_type, - segment_type - > - >::apply(s12, s34); + >::apply(s12, s34, rescale_policy, p1, p2, p3, p4); - int expected_count = + std::size_t expected_count = check(is, 0, expected_x1, expected_y1) + check(is, 1, expected_x2, expected_y2); @@ -104,6 +112,63 @@ static void test_segment_intersection(std::string const& case_id, BOOST_CHECK_EQUAL(dir.arrival[1], expected_arrival2); } +template +static void test_segment_ratio(std::string const& case_id, + int x1, int y1, int x2, int y2, + int x3, int y3, int x4, int y4, + Pair expected_pair_a1, Pair expected_pair_a2, + Pair expected_pair_b1, Pair expected_pair_b2, + int exp_ax1, int exp_ay1, int exp_ax2, int exp_ay2) + +{ + boost::ignore_unused_variable_warning(case_id); + + typedef typename bg::coordinate_type

::type coordinate_type; + typedef bg::model::referring_segment segment_type; + + P p1, p2, p3, p4; + bg::assign_values(p1, x1, y1); + bg::assign_values(p2, x2, y2); + bg::assign_values(p3, x3, y3); + bg::assign_values(p4, x4, y4); + + segment_type s12(p1, p2); + segment_type s34(p3, p4); + + typedef bg::detail::no_rescale_policy rescale_policy_type; + rescale_policy_type rescale_policy; + + typedef typename bg::segment_ratio_type::type ratio_type; + typedef bg::segment_intersection_points + < + P, + ratio_type + > result_type; + + // Get the intersection point (or two points) + result_type is + = bg::strategy::intersection::relate_cartesian_segments + < + bg::policies::relate::segments_intersection_points + >::apply(s12, s34, rescale_policy, p1, p2, p3, p4); + + ratio_type expected_a1(expected_pair_a1.first, expected_pair_a1.second); + ratio_type expected_a2(expected_pair_a2.first, expected_pair_a2.second); + ratio_type expected_b1(expected_pair_b1.first, expected_pair_b1.second); + ratio_type expected_b2(expected_pair_b2.first, expected_pair_b2.second); + + BOOST_CHECK_EQUAL(is.count, 2u); + BOOST_CHECK_EQUAL(is.fractions[0].robust_ra, expected_a1); + BOOST_CHECK_EQUAL(is.fractions[1].robust_ra, expected_a2); + BOOST_CHECK_EQUAL(is.fractions[0].robust_rb, expected_b1); + BOOST_CHECK_EQUAL(is.fractions[1].robust_rb, expected_b2); + + BOOST_CHECK_EQUAL(bg::get<0>(is.intersections[0]), exp_ax1); + BOOST_CHECK_EQUAL(bg::get<1>(is.intersections[0]), exp_ay1); + BOOST_CHECK_EQUAL(bg::get<0>(is.intersections[1]), exp_ax2); + BOOST_CHECK_EQUAL(bg::get<1>(is.intersections[1]), exp_ay2); +} + template void test_all() @@ -239,8 +304,9 @@ void test_all() 'e', true, 0, 0, 2, 0, 6, 0); - // a1---------->a2 - // b2<----------b1 + // Disjoint (in vertical direction, picture still horizontal) + // a2<---a1 + // b2<---b1 test_segment_intersection

("case_recursive_boxes_1", 10, 7, 10, 6, 10, 10, 10, 9, @@ -249,8 +315,191 @@ void test_all() } + +template +void test_ratios() +{ + // B inside A + // a1------------>a2 + // b1--->b2 + test_segment_ratio

("n4", + 2, 0, 7, 0, + 3, 0, 5, 0, + std::make_pair(1, 5), std::make_pair(3, 5), // IP located on 1/5, 3/5 w.r.t A + std::make_pair(0, 1), std::make_pair(1, 1), // IP located on 0, 1 w.r.t. B + // IP's are ordered as in A (currently) + 3, 0, 5, 0); + + // a1------------>a2 + // b2<---b1 + test_segment_ratio

("o4", + 2, 0, 7, 0, + 5, 0, 3, 0, + std::make_pair(1, 5), std::make_pair(3, 5), + std::make_pair(1, 1), std::make_pair(0, 1), + 3, 0, 5, 0); + + // a2<------------a1 + // b2<---b1 + test_segment_ratio

("o4b", + 7, 0, 2, 0, + 5, 0, 3, 0, + std::make_pair(2, 5), std::make_pair(4, 5), + std::make_pair(0, 1), std::make_pair(1, 1), + 5, 0, 3, 0); + + // a2<------------a1 + // b1--->b2 + test_segment_ratio

("o4c", + 7, 0, 2, 0, + 3, 0, 5, 0, + std::make_pair(2, 5), std::make_pair(4, 5), + std::make_pair(1, 1), std::make_pair(0, 1), + 5, 0, 3, 0); + + // Touch-interior + // a1---------->a2 + // b1--->b2 + test_segment_ratio

("n3", + 2, 0, 7, 0, + 2, 0, 4, 0, + std::make_pair(0, 1), std::make_pair(2, 5), + std::make_pair(0, 1), std::make_pair(1, 1), + 2, 0, 4, 0); + + // a2<-------------a1 + // b2<----b1 + test_segment_ratio

("n3b", + 7, 0, 2, 0, + 7, 0, 5, 0, + std::make_pair(0, 1), std::make_pair(2, 5), + std::make_pair(0, 1), std::make_pair(1, 1), + 7, 0, 5, 0); + + + // A inside B + // a1--->a2 + // b1------------>b2 + test_segment_ratio

("rn4", + 3, 0, 5, 0, + 2, 0, 7, 0, + std::make_pair(0, 1), std::make_pair(1, 1), + std::make_pair(1, 5), std::make_pair(3, 5), + 3, 0, 5, 0); + + // a2<---a1 + // b1------------>b2 + test_segment_ratio

("ro4", + 5, 0, 3, 0, + 2, 0, 7, 0, + std::make_pair(0, 1), std::make_pair(1, 1), + std::make_pair(3, 5), std::make_pair(1, 5), + 5, 0, 3, 0); + + // a2<---a1 + // b2<------------b1 + test_segment_ratio

("ro4b", + 5, 0, 3, 0, + 7, 0, 2, 0, + std::make_pair(0, 1), std::make_pair(1, 1), + std::make_pair(2, 5), std::make_pair(4, 5), + 5, 0, 3, 0); + + // a1--->a2 + // b2<------------b1 + test_segment_ratio

("ro4c", + 3, 0, 5, 0, + 7, 0, 2, 0, + std::make_pair(0, 1), std::make_pair(1, 1), + std::make_pair(4, 5), std::make_pair(2, 5), + 3, 0, 5, 0); + + // B inside A, boundaries intersect + // We change the coordinates a bit (w.r.t. n3 above) to have it asymmetrical + // a1---------->a2 + // b1--->b2 + test_segment_ratio

("n3", + 2, 0, 7, 0, + 2, 0, 4, 0, + std::make_pair(0, 1), std::make_pair(2, 5), + std::make_pair(0, 1), std::make_pair(1, 1), + 2, 0, 4, 0); + + // a1---------->a2 + // b2<---b1 + test_segment_ratio

("o3", + 2, 0, 7, 0, + 4, 0, 2, 0, + std::make_pair(0, 1), std::make_pair(2, 5), + std::make_pair(1, 1), std::make_pair(0, 1), + 2, 0, 4, 0); + + // a1---------->a2 + // b1--->b2 + test_segment_ratio

("n5", + 2, 0, 7, 0, + 5, 0, 7, 0, + std::make_pair(3, 5), std::make_pair(1, 1), + std::make_pair(0, 1), std::make_pair(1, 1), + 5, 0, 7, 0); + + // a1---------->a2 + // b2<---b1 + test_segment_ratio

("o5", + 2, 0, 7, 0, + 7, 0, 5, 0, + std::make_pair(3, 5), std::make_pair(1, 1), + std::make_pair(1, 1), std::make_pair(0, 1), + 5, 0, 7, 0); + + // Generic (overlaps) + // a1---------->a2 + // b1----->b2 + test_segment_ratio

("n2", + 2, 0, 7, 0, + 1, 0, 4, 0, + std::make_pair(0, 1), std::make_pair(2, 5), + std::make_pair(1, 3), std::make_pair(1, 1), + 2, 0, 4, 0); + + // Same, b reversed + test_segment_ratio

("n2_b", + 2, 0, 7, 0, + 4, 0, 1, 0, + std::make_pair(0, 1), std::make_pair(2, 5), + std::make_pair(2, 3), std::make_pair(0, 1), + 2, 0, 4, 0); + + // Same, both reversed + test_segment_ratio

("n2_c", + 7, 0, 2, 0, + 4, 0, 1, 0, + std::make_pair(3, 5), std::make_pair(1, 1), + std::make_pair(0, 1), std::make_pair(2, 3), + 4, 0, 2, 0); + + // a1---------->a2 + // b1----->b2 + test_segment_ratio

("n6", + 2, 0, 6, 0, + 5, 0, 8, 0, + std::make_pair(3, 4), std::make_pair(1, 1), + std::make_pair(0, 1), std::make_pair(1, 3), + 5, 0, 6, 0); + + // Vertical one like in box_poly5 but in integer + test_segment_ratio

("box_poly5", + 45, 25, 45, 15, + 45, 22, 45, 19, + std::make_pair(3, 10), std::make_pair(6, 10), + std::make_pair(0, 1), std::make_pair(1, 1), + 45, 22, 45, 19); +} + int test_main(int, char* []) { - test_all >(); + // We don't rescale but use integer points as, by nature, robust points + test_all >(); + test_ratios >(); return 0; } diff --git a/test/to_svg.hpp b/test/to_svg.hpp index 53e10ca27..54891b7bf 100644 --- a/test/to_svg.hpp +++ b/test/to_svg.hpp @@ -188,7 +188,7 @@ inline void turns_to_svg(Turns const& turns, Mapper & mapper, bool enrich = fals } struct to_svg_assign_policy - : bg::detail::overlay::calculate_distance_policy + : bg::detail::overlay::assign_null_policy { static bool const include_no_turn = false; static bool const include_degenerate = false; @@ -213,8 +213,9 @@ inline void to_svg(G const& g, std::string const& filename, bool sort = true) // GET TURNS - typedef bg::detail::overlay::traversal_turn_info

turn_info; - typedef bg::detail::overlay::calculate_distance_policy AssignPolicy; + typedef bg::segment_ratio sr; + typedef bg::detail::overlay::traversal_turn_info turn_info; + typedef bg::detail::overlay::assign_null_policy AssignPolicy; //typedef to_svg_assign_policy AssignPolicy; typedef std::deque Turns; @@ -257,7 +258,7 @@ inline void to_svg(G1 const& g1, G2 const& g2, std::string const& filename, bool typedef typename bg::detail::relate::turns::get_turns::turn_info turn_info; //typedef bg::detail::overlay::traversal_turn_info turn_info; - //typedef bg::detail::overlay::calculate_distance_policy AssignPolicy; + //typedef bg::detail::overlay::assign_null_policy AssignPolicy; typedef to_svg_assign_policy AssignPolicy; typedef std::deque Turns;