diff --git a/include/boost/geometry/algorithms/detail/group_dim.hpp b/include/boost/geometry/algorithms/detail/group_dim.hpp deleted file mode 100644 index a5c445b88..000000000 --- a/include/boost/geometry/algorithms/detail/group_dim.hpp +++ /dev/null @@ -1,79 +0,0 @@ -// Boost.Geometry (aka GGL, Generic Geometry Library) - -// 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 - -#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_GROUP_DIM_HPP -#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_GROUP_DIM_HPP - -#include - -#include - -namespace boost { namespace geometry { - -#ifndef DOXYGEN_NO_DETAIL -namespace detail { - -template ::type, - bool IsPoint = boost::is_base_of::value, - bool IsLinear = boost::is_base_of::value, - bool IsAreal = boost::is_base_of::value> -struct group_tag - : not_implemented -{}; - -template -struct group_tag -{ - typedef pointlike_tag type; -}; - -template -struct group_tag -{ - typedef linear_tag type; -}; - -template -struct group_tag -{ - typedef areal_tag type; -}; - -template ::type> -struct group_dim - : not_implemented -{}; - -template -struct group_dim -{ - static const int value = 0; -}; - -template -struct group_dim -{ - static const int value = 1; -}; - -template -struct group_dim -{ - static const int value = 2; -}; - -} // namespace detail -#endif // DOXYGEN_NO_DETAIL - -}} // namespace boost::geometry - -#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_GROUP_DIM_HPP 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 720f83e3a..7d882d003 100644 --- a/include/boost/geometry/algorithms/detail/overlay/get_intersection_points.hpp +++ b/include/boost/geometry/algorithms/detail/overlay/get_intersection_points.hpp @@ -52,9 +52,8 @@ struct get_turn_without_info static inline OutputIterator apply( Point1 const& pi, Point1 const& pj, Point1 const& pk, Point2 const& qi, Point2 const& qj, Point2 const& qk, -// TODO: should this always be std::size_t or replace with template parameter? - std::size_t /*p_segments_count*/, - std::size_t /*q_segments_count*/, + bool /*is_p_first*/, bool /*is_p_last*/, + bool /*is_q_first*/, bool /*is_q_last*/, TurnInfo const& , RescalePolicy const& rescale_policy, OutputIterator out) 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 0088c7b4c..5192b3aac 100644 --- a/include/boost/geometry/algorithms/detail/overlay/get_turn_info.hpp +++ b/include/boost/geometry/algorithms/detail/overlay/get_turn_info.hpp @@ -975,9 +975,8 @@ struct get_turn_info static inline OutputIterator apply( Point1 const& pi, Point1 const& pj, Point1 const& pk, Point2 const& qi, Point2 const& qj, Point2 const& qk, -// TODO: should this always be std::size_t or replace with template parameter? - std::size_t /*p_segments_count*/, - std::size_t /*q_segments_count*/, + 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, OutputIterator out) 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 fe1938496..d960dd0aa 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 @@ -130,9 +130,8 @@ struct get_turn_info_for_endpoint > static inline bool apply(Point1 const& pi, Point1 const& pj, Point1 const& pk, Point2 const& qi, Point2 const& qj, Point2 const& qk, -// TODO: should this always be std::size_t or replace with template parameter? - std::size_t p_segments_count, - std::size_t q_segments_count, + 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, @@ -147,11 +146,6 @@ struct get_turn_info_for_endpoint int segment_index1 = tp_model.operations[1].seg_id.segment_index; BOOST_ASSERT(segment_index0 >= 0 && segment_index1 >= 0); - bool is_p_first = segment_index0 == 0; - bool is_q_first = segment_index1 == 0; - bool is_p_last = static_cast(segment_index0) + 1 == p_segments_count; - bool is_q_last = static_cast(segment_index1) + 1 == q_segments_count; - if ( !is_p_first && !is_p_last && !is_q_first && !is_q_last ) return false; @@ -418,14 +412,13 @@ struct get_turn_info_for_endpoint geometry::convert(i2, i2_conv); side_calculator side_calc(i2_conv, i1, j1, i2, j2, k2); - TurnInfo tp = tp_model; - equal::apply(i2_conv, i1, j1, i2, j2, k2, - tp, result.template get<0>(), result.template get<1>(), side_calc); + std::pair + operations = operations_of_equal(side_calc); // TODO: must the above be calculated? // wouldn't it be enough to check if segments are collinear? - if ( tp.both(operation_continue) ) + if ( operations_both(operations, operation_continue) ) { // THIS IS WRT THE ORIGINAL SEGMENTS! NOT THE ONES ABOVE! bool opposite = result.template get<1>().opposite; @@ -435,7 +428,7 @@ struct get_turn_info_for_endpoint } else { - BOOST_ASSERT(tp.combination(operation_intersection, operation_union)); + BOOST_ASSERT(operations_combination(operations, operation_intersection, operation_union)); //op1 = operation_union; //op2 = operation_union; } @@ -466,14 +459,13 @@ struct get_turn_info_for_endpoint side_calculator side_calc(i2_conv, j1, i1, i2, j2, k2); - TurnInfo tp = tp_model; - equal::apply(i2_conv, j1, i1, i2, j2, k2, - tp, result.template get<0>(), result.template get<1>(), side_calc); + std::pair + operations = operations_of_equal(side_calc); // TODO: must the above be calculated? // wouldn't it be enough to check if segments are collinear? - if ( tp.both(operation_continue) ) + if ( operations_both(operations, operation_continue) ) { // THIS IS WRT THE ORIGINAL SEGMENTS! NOT THE ONES ABOVE! bool second_going_out = result.template get<0>().count > 1; @@ -483,7 +475,7 @@ struct get_turn_info_for_endpoint } else { - BOOST_ASSERT(tp.combination(operation_intersection, operation_union)); + BOOST_ASSERT(operations_combination(operations, operation_intersection, operation_union)); //op1 = operation_blocked; //op2 = operation_union; } @@ -558,6 +550,66 @@ struct get_turn_info_for_endpoint AssignPolicy::apply(tp, pi, qi, result.template get<0>(), result.template get<1>()); *out++ = tp; } + + template + static inline std::pair operations_of_equal(SidePolicy const& side) + { + int const side_pk_q2 = side.pk_wrt_q2(); + int const side_pk_p = side.pk_wrt_p1(); + int const side_qk_p = side.qk_wrt_p1(); + + // If pk is collinear with qj-qk, they continue collinearly. + // This can be on either side of p1 (== q1), or collinear + // The second condition checks if they do not continue + // oppositely + if ( side_pk_q2 == 0 && side_pk_p == side_qk_p ) + { + return std::make_pair(operation_continue, operation_continue); + } + + // If they turn to same side (not opposite sides) + if ( ! base_turn_handler::opposite(side_pk_p, side_qk_p) ) + { + int const side_pk_q2 = side.pk_wrt_q2(); + // If pk is left of q2 or collinear: p: union, q: intersection + if ( side_pk_q2 != -1 ) + { + return std::make_pair(operation_union, operation_intersection); + } + else + { + return std::make_pair(operation_intersection, operation_union); + } + } + else + { + // They turn opposite sides. If p turns left (or collinear), + // p: union, q: intersection + if ( side_pk_p != -1 ) + { + return std::make_pair(operation_union, operation_intersection); + } + else + { + return std::make_pair(operation_intersection, operation_union); + } + } + } + + static inline bool operations_both( + std::pair const& operations, + operation_type const op) + { + return operations.first == op && operations.second == op; + } + + static inline bool operations_combination( + std::pair const& operations, + operation_type const op1, operation_type const op2) + { + return ( operations.first == op1 && operations.second == op2 ) + || ( operations.first == op2 && operations.second == op1 ); + } }; }} // namespace detail::overlay 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 db74ec40b..73b811aea 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 @@ -17,6 +17,9 @@ #include #include +// TEMP, for spikes detector +//#include + namespace boost { namespace geometry { #ifndef DOXYGEN_NO_DETAIL @@ -36,9 +39,8 @@ struct get_turn_info_linear_areal static inline OutputIterator apply( Point1 const& pi, Point1 const& pj, Point1 const& pk, Point2 const& qi, Point2 const& qj, Point2 const& qk, -// TODO: should this always be std::size_t or replace with template parameter? - std::size_t p_segments_count, - std::size_t q_segments_count, + 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, OutputIterator out) @@ -74,7 +76,8 @@ struct get_turn_info_linear_areal case 'f' : // collinear, "from" case 's' : // starts from the middle get_turn_info_for_endpoint( - pi, pj, pk, qi, qj, qk, p_segments_count, q_segments_count, + pi, pj, pk, qi, qj, qk, + is_p_first, is_p_last, is_q_first, is_q_last, tp_model, result, method_none, out); break; @@ -84,7 +87,8 @@ struct get_turn_info_linear_areal case 'm' : { if ( get_turn_info_for_endpoint( - pi, pj, pk, qi, qj, qk, p_segments_count, q_segments_count, + 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) ) { // do nothing @@ -139,7 +143,8 @@ struct get_turn_info_linear_areal { // Both touch (both arrive there) if ( get_turn_info_for_endpoint( - pi, pj, pk, qi, qj, qk, p_segments_count, q_segments_count, + pi, pj, pk, qi, qj, qk, + is_p_first, is_p_last, is_q_first, is_q_last, tp_model, result, method_touch, out) ) { // do nothing @@ -164,7 +169,8 @@ struct get_turn_info_linear_areal case 'e': { if ( get_turn_info_for_endpoint( - pi, pj, pk, qi, qj, qk, p_segments_count, q_segments_count, + pi, pj, pk, qi, qj, qk, + is_p_first, is_p_last, is_q_first, is_q_last, tp_model, result, method_equal, out) ) { // do nothing @@ -183,6 +189,14 @@ struct get_turn_info_linear_areal 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; + }*/ + AssignPolicy::apply(tp, pi, qi, result.template get<0>(), result.template get<1>()); *out++ = tp; } @@ -202,7 +216,8 @@ struct get_turn_info_linear_areal { // Collinear if ( get_turn_info_for_endpoint( - pi, pj, pk, qi, qj, qk, p_segments_count, q_segments_count, + pi, pj, pk, qi, qj, qk, + is_p_first, is_p_last, is_q_first, is_q_last, tp_model, result, method_collinear, out) ) { // do nothing @@ -219,6 +234,13 @@ struct get_turn_info_linear_areal equal::apply(pi, pj, pk, qi, qj, qk, tp, result.template get<0>(), result.template get<1>(), side_calc); + 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); } @@ -288,12 +310,18 @@ struct get_turn_info_linear_areal // Assuming G1 is always Linear if ( op0 == operation_blocked ) + { op0 = operation_continue; + } if ( op1 == operation_blocked ) + { op1 = operation_continue; + } else if ( op1 == operation_intersection ) + { op1 = operation_union; + } } template @@ -318,12 +346,18 @@ struct get_turn_info_linear_areal // Assuming G1 is always Linear if ( op0 == operation_blocked ) + { op0 = operation_continue; + } if ( op1 == operation_blocked ) + { op1 = operation_continue; + } else if ( op1 == operation_intersection ) + { op1 = operation_union; + } } private: @@ -347,9 +381,8 @@ struct get_turn_info_linear_areal static inline bool get_turn_info_for_endpoint( Point1 const& pi, Point1 const& pj, Point1 const& pk, Point2 const& qi, Point2 const& qj, Point2 const& qk, -// TODO: should this always be std::size_t or replace with template parameter? - std::size_t p_segments_count, - std::size_t q_segments_count, + 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, @@ -367,11 +400,6 @@ struct get_turn_info_linear_areal const int segment_index1 = tp_model.operations[1].seg_id.segment_index; BOOST_ASSERT(segment_index0 >= 0 && segment_index1 >= 0); - const bool is_p_first = segment_index0 == 0; - const bool is_q_first = segment_index1 == 0; // not used - const bool is_p_last = static_cast(segment_index0) + 1 == p_segments_count; - const bool is_q_last = static_cast(segment_index1) + 1 == q_segments_count; // not used - if ( !is_p_first && !is_p_last ) return false; @@ -430,8 +458,11 @@ struct get_turn_info_linear_areal { side_calculator side_calc(qi_conv, pi, pj, qi, qj, qk); - equal::apply(qi_conv, pi, pj, qi, qj, qk, - tp, result.template get<0>(), result.template get<1>(), side_calc); + std::pair + operations = get_info_e::operations_of_equal(side_calc); + + tp.operations[0].operation = operations.first; + tp.operations[1].operation = operations.second; replaced_method = method_touch; } @@ -443,9 +474,11 @@ struct get_turn_info_linear_areal side_calculator side_calc(qi_conv, pi, pj, qi, pi_conv, qj); - // Collinear, but similar thus handled as equal - equal::apply(qi_conv, pi, pj, qi, pi_conv, qj, - tp, result.template get<0>(), result.template get<1>(), side_calc); + std::pair + operations = get_info_e::operations_of_equal(side_calc); + + tp.operations[0].operation = operations.first; + tp.operations[1].operation = operations.second; } replacer_of_method_and_operations_ec replacer(replaced_method); @@ -491,8 +524,11 @@ struct get_turn_info_linear_areal geometry::convert(qi, qi_conv); side_calculator side_calc(qi_conv, pj, pi, qi, qj, qk); - equal::apply(qi_conv, pj, pi, qi, qj, qk, - tp, result.template get<0>(), result.template get<1>(), side_calc); + std::pair + operations = get_info_e::operations_of_equal(side_calc); + + tp.operations[0].operation = operations.first; + tp.operations[1].operation = operations.second; replacer_of_method_and_operations_ec replacer(method_none); replacer(tp.method, tp.operations[0].operation, tp.operations[1].operation); 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 2cee246dc..586bc3f91 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,6 +22,62 @@ 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 { @@ -36,9 +92,8 @@ struct get_turn_info_linear_linear static inline OutputIterator apply( Point1 const& pi, Point1 const& pj, Point1 const& pk, Point2 const& qi, Point2 const& qj, Point2 const& qk, -// TODO: should this always be std::size_t or replace with template parameter? - std::size_t p_segments_count, - std::size_t q_segments_count, + 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, OutputIterator out) @@ -74,8 +129,9 @@ struct get_turn_info_linear_linear case 'f' : // collinear, "from" case 's' : // starts from the middle get_turn_info_for_endpoint - ::apply(pi, pj, pk, qi, qj, qk, p_segments_count, q_segments_count, - tp_model, result, method_none, out); + ::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); break; case 'd' : // disjoint: never do anything @@ -84,8 +140,9 @@ struct get_turn_info_linear_linear case 'm' : { if ( get_turn_info_for_endpoint - ::apply(pi, pj, pk, qi, qj, qk, p_segments_count, q_segments_count, - tp_model, result, method_touch_interior, out) ) + ::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) ) { // do nothing } @@ -143,7 +200,8 @@ struct get_turn_info_linear_linear { // Both touch (both arrive there) if ( get_turn_info_for_endpoint - ::apply(pi, pj, pk, qi, qj, qk, p_segments_count, q_segments_count, + ::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) ) { // do nothing @@ -172,7 +230,8 @@ struct get_turn_info_linear_linear case 'e': { if ( get_turn_info_for_endpoint - ::apply(pi, pj, pk, qi, qj, qk, p_segments_count, q_segments_count, + ::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) ) { // do nothing @@ -191,6 +250,19 @@ struct get_turn_info_linear_linear 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; + }*/ AssignPolicy::apply(tp, pi, qi, result.template get<0>(), result.template get<1>()); *out++ = tp; @@ -211,7 +283,8 @@ struct get_turn_info_linear_linear { // Collinear if ( get_turn_info_for_endpoint - ::apply(pi, pj, pk, qi, qj, qk, p_segments_count, q_segments_count, + ::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) ) { // do nothing @@ -236,6 +309,19 @@ struct get_turn_info_linear_linear 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; + }*/ } else { @@ -244,6 +330,11 @@ struct get_turn_info_linear_linear 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(); } AssignPolicy::apply(tp, pi, qi, result.template get<0>(), result.template get<1>()); @@ -305,14 +396,22 @@ struct get_turn_info_linear_linear else { if ( op0 == operation_continue || op0 == operation_blocked ) + { op0 = operation_intersection; + } else if ( op0 == operation_intersection ) + { op0 = operation_union; + } if ( op1 == operation_continue || op1 == operation_blocked ) + { op1 = operation_intersection; + } else if ( op1 == operation_intersection ) + { op1 = operation_union; + } } } @@ -330,14 +429,22 @@ struct get_turn_info_linear_linear BOOST_ASSERT(op0 != operation_blocked || op1 != operation_blocked ); if ( op0 == operation_blocked ) + { op0 = operation_intersection; + } else if ( op0 == operation_intersection ) + { op0 = operation_union; + } if ( op1 == operation_blocked ) + { op1 = operation_intersection; + } else if ( op1 == operation_intersection ) + { op1 = operation_union; + } if ( op0 == operation_intersection || op0 == operation_union || op1 == operation_intersection || op1 == operation_union ) @@ -353,13 +460,15 @@ struct get_turn_info_linear_linear static inline void replace_operations_i(operation_type & op0, operation_type & op1) { if ( op0 == operation_intersection ) + { op0 = operation_union; + } if ( op1 == operation_intersection ) + { op1 = operation_union; + } } - - }; }} // namespace detail::overlay diff --git a/include/boost/geometry/algorithms/detail/overlay/get_turns.hpp b/include/boost/geometry/algorithms/detail/overlay/get_turns.hpp index fb0287466..4ca5c81bd 100644 --- a/include/boost/geometry/algorithms/detail/overlay/get_turns.hpp +++ b/include/boost/geometry/algorithms/detail/overlay/get_turns.hpp @@ -54,7 +54,6 @@ #include #include #include -#include #include @@ -287,8 +286,13 @@ public : std::size_t const size_before = boost::size(turns); + bool const is_1_first = sec1.is_non_duplicate_first && index1 == sec1.begin_index; + bool const is_1_last = sec1.is_non_duplicate_last && index1+1 >= sec1.end_index; + bool const is_2_first = sec2.is_non_duplicate_first && index2 == sec2.begin_index; + bool const is_2_last = sec2.is_non_duplicate_last && index2+1 >= sec2.end_index; + TurnPolicy::apply(*prev1, *it1, *nd_next1, *prev2, *it2, *nd_next2, - sec1.range_count - 1, sec2.range_count - 1, + is_1_first, is_1_last, is_2_first, is_2_last, ti, rescale_policy, std::back_inserter(turns)); if (InterruptPolicy::enabled) @@ -598,7 +602,9 @@ struct get_turns_cs get_turns_with_box(seg_id, source_id2, *prev, *it, *next, bp[0], bp[1], bp[2], bp[3], - segments_count1, + // 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, turns, interrupt_policy); // Future performance enhancement: @@ -639,7 +645,8 @@ private: box_point_type const& bp1, box_point_type const& bp2, box_point_type const& bp3, - std::size_t segments_count1, + bool const is_range_first, + bool const is_range_last, RescalePolicy const& rescale_policy, // Output Turns& turns, @@ -658,22 +665,26 @@ private: ti.operations[1].seg_id = segment_identifier(source_id2, -1, -1, 0); TurnPolicy::apply(rp0, rp1, rp2, bp0, bp1, bp2, - segments_count1, 4, + is_range_first, is_range_last, + true, false, ti, rescale_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, - segments_count1, 4, + is_range_first, is_range_last, + false, false, ti, rescale_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, - segments_count1, 4, + is_range_first, is_range_last, + false, false, ti, rescale_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, - segments_count1, 4, + is_range_first, is_range_last, + false, true, ti, rescale_policy, std::back_inserter(turns)); if (InterruptPolicy::enabled) @@ -738,9 +749,15 @@ struct get_turns_polygon_cs // GET_TURN_INFO_TYPE +template +struct topological_tag_base +{ + typedef typename tag_cast::type, pointlike_tag, linear_tag, areal_tag>::type type; +}; + template ::type, typename Tag2 = typename tag::type, - typename TagBase1 = typename group_tag::type, typename TagBase2 = typename group_tag::type> + typename TagBase1 = typename topological_tag_base::type, typename TagBase2 = typename topological_tag_base::type> struct get_turn_info_type : overlay::get_turn_info {}; @@ -757,7 +774,7 @@ struct get_turn_info_type::type, typename Tag2 = typename tag::type, - typename TagBase1 = typename group_tag::type, typename TagBase2 = typename group_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; diff --git a/include/boost/geometry/algorithms/detail/range_helpers.hpp b/include/boost/geometry/algorithms/detail/range_helpers.hpp deleted file mode 100644 index 6f546e0a4..000000000 --- a/include/boost/geometry/algorithms/detail/range_helpers.hpp +++ /dev/null @@ -1,78 +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 - -#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_RANGE_HELPERS_HPP -#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_RANGE_HELPERS_HPP - -#include - -namespace boost { namespace geometry -{ - -#ifndef DOXYGEN_NO_DETAIL -namespace detail { namespace range { - -template -inline typename boost::range_value::type const& -at(Range const& rng, typename boost::range_size::type i) -{ - BOOST_ASSERT(i < boost::size(rng)); - return *(boost::begin(rng) + i); -} - -template -inline typename boost::range_value::type & -at(Range & rng, typename boost::range_size::type i) -{ - BOOST_ASSERT(i < boost::size(rng)); - return *(boost::begin(rng) + i); -} - -template -inline typename boost::range_value::type const& -front(Range const& rng) -{ - BOOST_ASSERT(!boost::empty(rng)); - return *boost::begin(rng); -} - -template -inline typename boost::range_value::type & -front(Range & rng) -{ - BOOST_ASSERT(!boost::empty(rng)); - return *boost::begin(rng); -} - -template -inline typename boost::range_value::type const& -back(Range const& rng) -{ - BOOST_ASSERT(!boost::empty(rng)); - return *(--boost::end(rng)); -} - -template -inline typename boost::range_value::type & -back(Range & rng) -{ - BOOST_ASSERT(!boost::empty(rng)); - return *(--boost::end(rng)); -} - -}} // namespace detail::range -#endif // DOXYGEN_NO_DETAIL - -}} // namespace boost::geometry - -#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_RANGE_HELPERS_HPP diff --git a/include/boost/geometry/algorithms/detail/relate/boundary_checker.hpp b/include/boost/geometry/algorithms/detail/relate/boundary_checker.hpp index b16e6bae6..d7506a40e 100644 --- a/include/boost/geometry/algorithms/detail/relate/boundary_checker.hpp +++ b/include/boost/geometry/algorithms/detail/relate/boundary_checker.hpp @@ -11,8 +11,10 @@ #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_RELATE_BOUNDARY_CHECKER_HPP #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_RELATE_BOUNDARY_CHECKER_HPP +#include +#include + #include -#include namespace boost { namespace geometry { @@ -112,14 +114,14 @@ public: if ( BoundaryQuery == boundary_back ) { - if ( sid.segment_index + 2 != geometry::num_points(sub_geometry::get(geometry, sid)) ) + 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_geometry::get(geometry, sid)) ) + && sid.segment_index + 2 != geometry::num_points(sub_range(geometry, sid)) ) return false; } diff --git a/include/boost/geometry/algorithms/detail/relate/less.hpp b/include/boost/geometry/algorithms/detail/relate/less.hpp index f281458b7..6a9434090 100644 --- a/include/boost/geometry/algorithms/detail/relate/less.hpp +++ b/include/boost/geometry/algorithms/detail/relate/less.hpp @@ -18,47 +18,37 @@ namespace boost { namespace geometry { -#ifndef DOXYGEN_NO_DETAIL -namespace detail { namespace relate { +#ifndef DOXYGEN_NO_DISPATCH +namespace detail_dispatch { namespace relate { -// TODO: should this be integrated with geometry::less? +// TODO: Integrate it with geometry::less? -template -< - typename Point1, - typename Point2, - std::size_t I = 0, - std::size_t D1 = geometry::dimension::value, - std::size_t D2 = geometry::dimension::value -> -struct less_dispatch - : not_implemented -{}; - - -template -struct less_dispatch +template ::value> +struct less { - static inline bool apply(Point1 const& l, Point2 const& r) + static inline bool apply(Point1 const& left, Point2 const& right) { typename geometry::coordinate_type::type - cl = geometry::get(l); + cleft = geometry::get(left); typename geometry::coordinate_type::type - cr = geometry::get(r); + cright = geometry::get(right); - if ( geometry::math::equals(cl, cr) ) + if ( geometry::math::equals(cleft, cright) ) { - return less_dispatch::apply(l, r); + return less::apply(left, right); } else { - return cl < cr; + return cleft < cright; } } }; template -struct less_dispatch +struct less { static inline bool apply(Point1 const&, Point2 const&) { @@ -66,12 +56,19 @@ struct less_dispatch } }; +}} // namespace detail_dispatch::relate + +#endif + +#ifndef DOXYGEN_NO_DETAIL +namespace detail { namespace relate { + struct less { template inline bool operator()(Point1 const& point1, Point2 const& point2) const { - return less_dispatch::apply(point1, point2); + return detail_dispatch::relate::less::apply(point1, point2); } }; diff --git a/include/boost/geometry/algorithms/detail/relate/linear_areal.hpp b/include/boost/geometry/algorithms/detail/relate/linear_areal.hpp index eb3cc7e76..8dd1fa896 100644 --- a/include/boost/geometry/algorithms/detail/relate/linear_areal.hpp +++ b/include/boost/geometry/algorithms/detail/relate/linear_areal.hpp @@ -14,9 +14,10 @@ #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_RELATE_LINEAR_AREAL_HPP #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_RELATE_LINEAR_AREAL_HPP -#include -#include -#include +#include +#include + +#include #include #include @@ -185,8 +186,8 @@ template struct linear_areal { // check Linear / Areal - BOOST_STATIC_ASSERT(detail::group_dim::value == 1 - && detail::group_dim::value == 2); + BOOST_STATIC_ASSERT(topological_dimension::value == 1 + && topological_dimension::value == 2); static const bool interruption_enabled = true; @@ -607,6 +608,7 @@ struct linear_areal && !fake_enter_detected && it->operations[op_id].position != overlay::position_front ) { +// TODO: calculate_from_inside() is only needed if the current Linestring is not closed bool from_inside = first_in_range && calculate_from_inside(geometry, other_geometry, @@ -621,7 +623,7 @@ struct linear_areal if ( first_in_range ) { bool front_b = is_endpoint_on_boundary( - range::front(sub_geometry::get(geometry, seg_id)), + range::front(sub_range(geometry, seg_id)), boundary_checker); // if there is a boundary on the first point @@ -692,6 +694,7 @@ struct linear_areal // TODO: very similar code is used in the handling of intersection if ( it->operations[op_id].position != overlay::position_front ) { +// TODO: calculate_from_inside() is only needed if the current Linestring is not closed bool first_from_inside = first_in_range && calculate_from_inside(geometry, other_geometry, @@ -712,7 +715,7 @@ struct linear_areal if ( first_in_range && ( !this_b || op_blocked ) ) { bool front_b = is_endpoint_on_boundary( - range::front(sub_geometry::get(geometry, seg_id)), + range::front(sub_range(geometry, seg_id)), boundary_checker); // if there is a boundary on the first point @@ -758,7 +761,7 @@ struct linear_areal 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)), + range::back(sub_range(geometry, prev_seg_id)), boundary_checker); // if there is a boundary on the last point @@ -779,7 +782,7 @@ struct linear_areal 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)), + range::back(sub_range(geometry, prev_seg_id)), boundary_checker); // if there is a boundary on the last point @@ -832,10 +835,10 @@ struct linear_areal reverse2 ? iterate_reverse : iterate_forward >::type range2_view; - typedef typename sub_geometry::result_type::type range1_ref; + typedef typename sub_range_return_type::type range1_ref; - range1_ref range1 = sub_geometry::get(geometry1, turn.operations[op_id].seg_id); - range2_cview const cview(sub_geometry::get(geometry2, turn.operations[other_op_id].seg_id)); + 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); std::size_t s1 = boost::size(range1); @@ -855,18 +858,23 @@ struct linear_areal geometry::convert(qi, qi_conv); bool is_ip_qj = equals::equals_point_point(turn.point, qj); // TODO: test this! - BOOST_ASSERT(!equals::equals_point_point(turn.point, pi)); - BOOST_ASSERT(!equals::equals_point_point(turn.point, qi)); +// BOOST_ASSERT(!equals::equals_point_point(turn.point, pi)); +// BOOST_ASSERT(!equals::equals_point_point(turn.point, qi)); point1_type new_pj; geometry::convert(turn.point, new_pj); if ( is_ip_qj ) { std::size_t q_seg_jk = (q_seg_ij + 1) % seg_count2; - BOOST_ASSERT(q_seg_jk + 1 < s2); - point2_type const& qk = range::at(range2, q_seg_jk + 1); - // Will this sequence of point be always correct? - overlay::side_calculator side_calc(qi_conv, new_pj, pi, qi, qj, qk); +// 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)); + + // Will this sequence of points be always correct? + overlay::side_calculator side_calc(qi_conv, new_pj, pi, qi, qj, *qk_it); return calculate_from_inside_sides(side_calc); } @@ -881,6 +889,29 @@ struct linear_areal } } + template + static inline It find_next_non_duplicated(It first, It current, It last) + { + BOOST_ASSERT( current != last ); + + It it = current; + + for ( ++it ; it != last ; ++it ) + { + if ( !equals::equals_point_point(*current, *it) ) + return it; + } + + // if not found start from the beginning + for ( it = first ; it != current ; ++it ) + { + if ( !equals::equals_point_point(*current, *it) ) + return it; + } + + return current; + } + // calculate inside or outside based on side_calc // this is simplified version of a check from equal<> template diff --git a/include/boost/geometry/algorithms/detail/relate/linear_linear.hpp b/include/boost/geometry/algorithms/detail/relate/linear_linear.hpp index cce713e5e..ab21274b6 100644 --- a/include/boost/geometry/algorithms/detail/relate/linear_linear.hpp +++ b/include/boost/geometry/algorithms/detail/relate/linear_linear.hpp @@ -14,8 +14,9 @@ #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_RELATE_LINEAR_LINEAR_HPP #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_RELATE_LINEAR_LINEAR_HPP -#include -#include +#include + +#include #include #include @@ -454,7 +455,7 @@ struct linear_linear if ( first_in_range ) { bool front_b = is_endpoint_on_boundary( - range::front(sub_geometry::get(geometry, seg_id)), + range::front(sub_range(geometry, seg_id)), boundary_checker); // if there is a boundary on the first point @@ -529,7 +530,7 @@ struct linear_linear if ( first_in_range ) { bool front_b = is_endpoint_on_boundary( - range::front(sub_geometry::get(geometry, seg_id)), + range::front(sub_range(geometry, seg_id)), boundary_checker); // if there is a boundary on the first point @@ -557,25 +558,33 @@ struct linear_linear { // it's also the boundary of the other geometry if ( other_b ) + { update(res); + } else + { update(res); + } } // if current IP is not on boundary of the geometry else { // it's also the boundary of the other geometry if ( other_b ) + { update(res); + } else + { update(res); + } } // first IP on the last segment point - this means that the first point is outside if ( first_in_range && ( !this_b || op_blocked ) && was_outside /*&& !is_collinear*/ ) { bool front_b = is_endpoint_on_boundary( - range::front(sub_geometry::get(geometry, seg_id)), + range::front(sub_range(geometry, seg_id)), boundary_checker); // if there is a boundary on the first point @@ -611,7 +620,7 @@ struct linear_linear 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)), + range::back(sub_range(geometry, prev_seg_id)), boundary_checker); // if there is a boundary on the last point diff --git a/include/boost/geometry/algorithms/detail/relate/result.hpp b/include/boost/geometry/algorithms/detail/relate/result.hpp index 18d4c61c3..f32e7db7e 100644 --- a/include/boost/geometry/algorithms/detail/relate/result.hpp +++ b/include/boost/geometry/algorithms/detail/relate/result.hpp @@ -15,8 +15,15 @@ #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_RELATE_RESULT_HPP #include -#include + +#include +#include +#include +#include #include +#include + +#include // TEMP - move this header to geometry/detail #include @@ -796,8 +803,8 @@ typedef static_mask<'F', 'F', '*', 'F', 'F', '*', '*', '*', '*'> static_mask_dis // TOUCHES - NOT P/P template ::value, - std::size_t Dim2 = detail::group_dim::value> + std::size_t Dim1 = topological_dimension::value, + std::size_t Dim2 = topological_dimension::value> struct static_mask_touches_type { typedef boost::mpl::vector< @@ -829,8 +836,8 @@ typedef boost::mpl::vector< // dim(G1) < dim(G2) - P/L P/A L/A template ::value, - std::size_t Dim2 = detail::group_dim::value, + std::size_t Dim1 = topological_dimension::value, + std::size_t Dim2 = topological_dimension::value, bool D1LessD2 = (Dim1 < Dim2) > struct static_mask_crosses_type @@ -866,8 +873,8 @@ struct static_mask_crosses_type // dim(G1) != dim(G2) - NOT P/P, L/L, A/A template ::value, - std::size_t Dim2 = detail::group_dim::value + std::size_t Dim1 = topological_dimension::value, + std::size_t Dim2 = topological_dimension::value > struct static_mask_overlaps_type : not_implemented::type, diff --git a/include/boost/geometry/algorithms/detail/relate/topology_check.hpp b/include/boost/geometry/algorithms/detail/relate/topology_check.hpp index 37acb70d8..95bd88db9 100644 --- a/include/boost/geometry/algorithms/detail/relate/topology_check.hpp +++ b/include/boost/geometry/algorithms/detail/relate/topology_check.hpp @@ -11,8 +11,9 @@ #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_RELATE_TOPOLOGY_CHECK_HPP #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_RELATE_TOPOLOGY_CHECK_HPP +#include + #include -#include namespace boost { namespace geometry { diff --git a/include/boost/geometry/algorithms/detail/sections/sectionalize.hpp b/include/boost/geometry/algorithms/detail/sections/sectionalize.hpp index 82d9f7d32..71c3a9bb1 100644 --- a/include/boost/geometry/algorithms/detail/sections/sectionalize.hpp +++ b/include/boost/geometry/algorithms/detail/sections/sectionalize.hpp @@ -4,6 +4,9 @@ // 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. @@ -11,6 +14,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_DETAIL_SECTIONS_SECTIONALIZE_HPP #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_SECTIONS_SECTIONALIZE_HPP @@ -72,6 +77,9 @@ struct section bool duplicate; int non_duplicate_index; + bool is_non_duplicate_first; + bool is_non_duplicate_last; + inline section() : id(-1) , begin_index(-1) @@ -80,6 +88,8 @@ struct section , range_count(0) , duplicate(false) , non_duplicate_index(-1) + , is_non_duplicate_first(false) + , is_non_duplicate_last(false) { assign_inverse(bounding_box); for (std::size_t i = 0; i < DimensionCount; i++) @@ -251,13 +261,11 @@ struct sectionalize_part typename Sections > static inline void apply(Sections& sections, - typename boost::range_value::type& section, - int& index, int& ndi, - Range const& range, - RescalePolicy const& rescale_policy, - bool make_rescaled_boxes, - ring_identifier ring_id, - std::size_t max_count) + Range const& range, + RescalePolicy const& rescale_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(make_rescaled_boxes); @@ -267,19 +275,20 @@ struct sectionalize_part typedef typename boost::range_iterator::type iterator_type; - if (int(boost::size(range)) <= index) + if ( boost::empty(range) ) { return; } - if (index == 0) - { - ndi = 0; - } + int index = 0; + int ndi = 0; // non duplicate index + section_type section; + + bool mark_first_non_duplicated = true; + std::size_t last_non_duplicate_index = 0; iterator_type it = boost::begin(range); - it += index; - + for(iterator_type previous = it++; it != boost::end(range); ++previous, ++it, index++) @@ -329,6 +338,11 @@ struct sectionalize_part ) ) { + if ( !section.duplicate ) + { + last_non_duplicate_index = sections.size(); + } + sections.push_back(section); section = section_type(); } @@ -341,6 +355,12 @@ struct sectionalize_part section.non_duplicate_index = ndi; section.range_count = boost::size(range); + if ( mark_first_non_duplicated && !duplicate ) + { + section.is_non_duplicate_first = true; + mark_first_non_duplicated = false; + } + copy_loop < int, 0, DimensionCount @@ -356,6 +376,23 @@ struct sectionalize_part ndi++; } } + + // Add last section if applicable + if (section.count > 0) + { + if ( !section.duplicate ) + { + last_non_duplicate_index = sections.size(); + } + + sections.push_back(section); + } + + if ( last_non_duplicate_index < sections.size() + && !sections[last_non_duplicate_index].duplicate ) + { + sections[last_non_duplicate_index].is_non_duplicate_last = true; + } } }; @@ -375,10 +412,11 @@ struct sectionalize_range typename Sections > static inline void apply(Range const& range, - RescalePolicy const& rescale_policy, - bool make_rescaled_boxes, - Sections& sections, - ring_identifier ring_id, std::size_t max_count) + RescalePolicy const& rescale_policy, + bool make_rescaled_boxes, + Sections& sections, + ring_identifier ring_id, + std::size_t max_count) { typedef typename closeable_view::type cview_type; typedef typename reversible_view @@ -403,20 +441,8 @@ struct sectionalize_range return; } - int index = 0; - int ndi = 0; // non duplicate index - - typedef typename boost::range_value::type section_type; - section_type section; - sectionalize_part - ::apply(sections, section, index, ndi, view, rescale_policy, make_rescaled_boxes, ring_id, max_count); - - // Add last section if applicable - if (section.count > 0) - { - sections.push_back(section); - } + ::apply(sections, view, rescale_policy, make_rescaled_boxes, ring_id, max_count); } }; diff --git a/include/boost/geometry/algorithms/detail/sub_geometry.hpp b/include/boost/geometry/algorithms/detail/sub_geometry.hpp deleted file mode 100644 index 98a1d617e..000000000 --- a/include/boost/geometry/algorithms/detail/sub_geometry.hpp +++ /dev/null @@ -1,131 +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 - -#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_SUB_GEOMETRY_HPP -#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_SUB_GEOMETRY_HPP - -namespace boost { namespace geometry { - -#ifndef DOXYGEN_NO_DETAIL -namespace detail { namespace sub_geometry { - -// TODO: later implement Geometry-specialized index_type -// polygons/multi_polygons also need ring_index member -struct index_type -{ - index_type() : multi_index(-1) {} - - int multi_index; - - inline bool operator<(index_type const& i) const - { - return multi_index < i.multi_index; - } - - inline bool operator==(index_type const& i) const - { - return multi_index == i.multi_index; - } -}; - -}} // namespace detail::sub_geometry - -namespace detail_dispatch { namespace sub_geometry { - -// TODO: later remove IsMulti and move to multi directory -template ::type, - bool IsMulti = boost::is_base_of::value> -struct get : not_implemented -{}; - -template -struct get -{ - typedef Geometry & result_type; - - template static inline - result_type apply(Geometry & geometry, Id const&) - { - return geometry; - } -}; - -template -struct get -{ - typedef typename geometry::ring_type::type & result_type; - - template static inline - result_type apply(Geometry & geometry, Id const& id) - { - if ( id.ring_index < 0 ) - { - return geometry::exterior_ring(geometry); - } - else - { - std::size_t ri = static_cast(id.ring_index); - BOOST_ASSERT( ri < boost::size(geometry::interior_rings(geometry)) ); - - return *(boost::begin(geometry::interior_rings(geometry)) + ri); - } - } -}; - -template -struct get -{ - typedef typename boost::range_value::type value_type; - typedef typename boost::mpl::if_c - < - boost::is_const::value, - typename boost::add_const::type, - value_type - >::type sub_type; - typedef detail_dispatch::sub_geometry::get get_type; - typedef typename get_type::result_type result_type; - - template static inline - result_type apply(Geometry & geometry, Id const& id) - { - BOOST_ASSERT(0 <= id.multi_index); - return get_type::apply(*(boost::begin(geometry) + id.multi_index), id); - } -}; - -}} // namespace detail_dispatch::sub_geometry - -namespace detail { namespace sub_geometry { - -template -struct result_type -{ - typedef typename detail_dispatch::sub_geometry::get::result_type type; -}; - -// This function also works for geometry::segment_identifier - -template inline -typename detail_dispatch::sub_geometry::get::result_type -get(Geometry & geometry, Id const& id) -{ - return detail_dispatch::sub_geometry::get::apply(geometry, id); -}; - -}} // namespace detail::sub_geometry -#endif - -}} // namespace boost::geometry - -#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_SUB_GEOMETRY_HPP diff --git a/include/boost/geometry/algorithms/detail/sub_range.hpp b/include/boost/geometry/algorithms/detail/sub_range.hpp new file mode 100644 index 000000000..5c5b2f9c0 --- /dev/null +++ b/include/boost/geometry/algorithms/detail/sub_range.hpp @@ -0,0 +1,113 @@ +// 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 + +#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_SUB_RANGE_HPP +#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_SUB_RANGE_HPP + +#include + +namespace boost { namespace geometry { + +#ifndef DOXYGEN_NO_DETAIL + +#ifndef DOXYGEN_NO_DISPATCH +namespace detail_dispatch { + +template ::type, + bool IsMulti = boost::is_base_of::value> +struct sub_range : not_implemented +{}; + +template +struct sub_range +{ + typedef Geometry & return_type; + + template static inline + return_type apply(Geometry & geometry, Id const&) + { + return geometry; + } +}; + +template +struct sub_range +{ + typedef typename geometry::ring_type::type & return_type; + + template static inline + return_type apply(Geometry & geometry, Id const& id) + { + if ( id.ring_index < 0 ) + { + return geometry::exterior_ring(geometry); + } + else + { + std::size_t ri = static_cast(id.ring_index); + return range::at(geometry::interior_rings(geometry), ri); + } + } +}; + +template +struct sub_range +{ + typedef typename boost::range_value::type value_type; + typedef typename boost::mpl::if_c + < + boost::is_const::value, + typename boost::add_const::type, + value_type + >::type sub_type; + + typedef detail_dispatch::sub_range sub_sub_range; + + // TODO: shouldn't it be return_type? + typedef typename sub_sub_range::return_type return_type; + + template static inline + return_type apply(Geometry & geometry, Id const& id) + { + BOOST_ASSERT(0 <= id.multi_index); + return sub_sub_range::apply(range::at(geometry, id.multi_index), id); + } +}; + +} // namespace detail_dispatch +#endif // DOXYGEN_NO_DISPATCH + +namespace detail { + +template +struct sub_range_return_type +{ + typedef typename detail_dispatch::sub_range::return_type type; +}; + +// This function also works for geometry::segment_identifier + +template inline +typename sub_range_return_type::type +sub_range(Geometry & geometry, Id const& id) +{ + return detail_dispatch::sub_range::apply(geometry, id); +}; + +} // namespace detail +#endif // DOXYGEN_NO_DETAIL + +}} // namespace boost::geometry + +#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_SUB_RANGE_HPP diff --git a/include/boost/geometry/algorithms/touches.hpp b/include/boost/geometry/algorithms/touches.hpp index 9992f6073..a34ac777e 100644 --- a/include/boost/geometry/algorithms/touches.hpp +++ b/include/boost/geometry/algorithms/touches.hpp @@ -28,7 +28,7 @@ #include #include #include -#include +#include #include #include #include @@ -207,8 +207,8 @@ struct linear_areal_interrupt_policy template inline bool is_turn_on_last_point(Turn const& turn) { - typename sub_geometry::result_type::type - g = sub_geometry::get(linear, turn.operations[0].seg_id); + typename sub_range_return_type::type + g = sub_range(linear, turn.operations[0].seg_id); std::size_t s = boost::size(g); diff --git a/include/boost/geometry/algorithms/within.hpp b/include/boost/geometry/algorithms/within.hpp index 75040782b..4bedf9469 100644 --- a/include/boost/geometry/algorithms/within.hpp +++ b/include/boost/geometry/algorithms/within.hpp @@ -4,8 +4,8 @@ // Copyright (c) 2008-2012 Bruno Lalande, Paris, France. // Copyright (c) 2009-2012 Mateusz Loskot, London, UK. -// 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. @@ -14,6 +14,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_WITHIN_HPP #define BOOST_GEOMETRY_ALGORITHMS_WITHIN_HPP @@ -61,81 +63,21 @@ namespace boost { namespace geometry #ifndef DOXYGEN_NO_DETAIL namespace detail { namespace within { -// currently works only for linestrings -template -struct linear_linear +struct use_point_in_geometry { - template + template + static inline bool apply(Geometry1 const& geometry1, Geometry2 const& geometry2, Strategy const& strategy) + { + return detail::within::point_in_geometry(geometry1, geometry2, strategy) == 1; + } +}; + +struct use_relate +{ + template static inline bool apply(Geometry1 const& geometry1, Geometry2 const& geometry2, Strategy const& /*strategy*/) { - // TODO within() should return FALSE if a length(geometry1) == 0 and is contained entirely within a boundary, - // also if geometry2 has length(geometry2) == 0, it should be considered as a point. - - // TODO: currently only for linestrings - std::size_t s1 = boost::size(geometry1); - std::size_t s2 = boost::size(geometry2); - if ( s1 == 0 || s2 == 0 || s2 == 1 ) - return false; - if ( s1 == 1 && s2 == 1 ) // within(Pt, Pt) - return false; - if ( s1 == 1 ) - return point_in_geometry(*boost::begin(geometry1), geometry2) > 0; - - typedef typename geometry::point_type::type point1_type; - typedef detail::overlay::turn_info turn_info; - - typedef detail::overlay::get_turn_info - < - detail::overlay::assign_null_policy - > policy_type; - - std::deque turns; - - detail::get_turns::no_interrupt_policy policy; - boost::geometry::get_turns - < - detail::overlay::do_reverse::value>::value, // should be false - detail::overlay::do_reverse::value>::value, // should be false - detail::overlay::assign_null_policy - >(geometry1, geometry2, detail::no_rescale_policy(), turns, policy); - - return analyse_turns(turns.begin(), turns.end()) - // TODO: currently only for linestrings - && point_in_geometry(*boost::begin(geometry1), geometry2) >= 0 - && point_in_geometry(*(boost::end(geometry1) - 1), geometry2) >= 0; - } - - template - static inline bool analyse_turns(TurnIt first, TurnIt last) - { - bool has_turns = false; - for ( TurnIt it = first ; it != last ; ++it ) - { - switch ( it->method ) - { - case overlay::method_crosses: - return false; - case overlay::method_touch: - case overlay::method_touch_interior: - if ( it->both(overlay::operation_continue) - || it->both(overlay::operation_blocked) ) - { - has_turns = true; - } - else - return false; - case overlay::method_equal: - case overlay::method_collinear: - has_turns = true; - break; - case overlay::method_none : - case overlay::method_disjoint : - case overlay::method_error : - break; - } - } - - return has_turns; + return Strategy::apply(geometry1, geometry2); } }; @@ -180,48 +122,73 @@ struct within } }; - +// P/A template struct within -{ - template - static inline bool apply(Point const& point, Ring const& ring, Strategy const& strategy) - { - return detail::within::point_in_geometry(point, ring, strategy) == 1; - } -}; + : public detail::within::use_point_in_geometry +{}; template struct within -{ - template - static inline bool apply(Point const& point, Polygon const& polygon, Strategy const& strategy) - { - return detail::within::point_in_geometry(point, polygon, strategy) == 1; - } -}; + : public detail::within::use_point_in_geometry +{}; + +// P/L template struct within -{ - template static inline - bool apply(Point const& point, Linestring const& linestring, Strategy const& strategy) - { - return detail::within::point_in_geometry(point, linestring, strategy) == 1; - } -}; + : public detail::within::use_point_in_geometry +{}; + +// L/L template struct within -{ - template static inline - bool apply(Linestring1 const& linestring1, Linestring2 const& linestring2, Strategy const& strategy) - { - return detail::within::linear_linear - ::apply(linestring1, linestring2, strategy); - } -}; + : public detail::within::use_relate +{}; + +template +struct within + : public detail::within::use_relate +{}; + +template +struct within + : public detail::within::use_relate +{}; + +// L/A + +template +struct within + : public detail::within::use_relate +{}; + +template +struct within + : public detail::within::use_relate +{}; + +template +struct within + : public detail::within::use_relate +{}; + +template +struct within + : public detail::within::use_relate +{}; + +template +struct within + : public detail::within::use_relate +{}; + +template +struct within + : public detail::within::use_relate +{}; } // namespace dispatch #endif // DOXYGEN_NO_DISPATCH diff --git a/include/boost/geometry/iterators/concatenate_iterator.hpp b/include/boost/geometry/iterators/concatenate_iterator.hpp new file mode 100644 index 000000000..32a8b2332 --- /dev/null +++ b/include/boost/geometry/iterators/concatenate_iterator.hpp @@ -0,0 +1,109 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2014, Oracle and/or its affiliates. + +// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle + +// Licensed under the Boost Software License version 1.0. +// http://www.boost.org/users/license.html + +#ifndef BOOST_GEOMETRY_ITERATORS_CONCATENATE_ITERATOR_HPP +#define BOOST_GEOMETRY_ITERATORS_CONCATENATE_ITERATOR_HPP + +#include +#include +#include +#include +#include + + +namespace boost { namespace geometry +{ + + + +template +struct concatenate_iterator + : public boost::iterator_facade + < + concatenate_iterator, + Value, + boost::forward_traversal_tag + > +{ +private: + Iterator1 m_it1, m_end1; + Iterator2 m_it2; + + struct enabler {}; + +public: + typedef Iterator1 first_iterator_type; + typedef Iterator2 second_iterator_type; + + // default constructor + concatenate_iterator() {} + + // for begin + concatenate_iterator(Iterator1 it1, Iterator1 end1, + Iterator2 it2) + : m_it1(it1), m_end1(end1), m_it2(it2) + {} + + // for end + concatenate_iterator(Iterator1 end1, Iterator2 end2) + : m_it1(end1), m_end1(end1), m_it2(end2) + {} + + template + concatenate_iterator + (concatenate_iterator const& other, + typename boost::enable_if_c + < + boost::is_convertible::value + && boost::is_convertible::value, + enabler + >::type = enabler()) + : m_it1(other.m_it1), m_end1(other.m_end1), m_it2(other.m_it2) + {} + + + +private: + friend class boost::iterator_core_access; + + template + friend class concatenate_iterator; + + Value& dereference() const + { + if ( m_it1 == m_end1 ) + { + return *m_it2; + } + return *m_it1; + } + + bool equal(concatenate_iterator const& other) const + { + return m_it1 == other.m_it1 && m_it2 == other.m_it2; + } + + void increment() + { + if ( m_it1 == m_end1 ) + { + ++m_it2; + } + else + { + ++m_it1; + } + } +}; + + + +}} // namespace boost::geometry + +#endif // BOOST_GEOMETRY_ITERATORS_CONCATENATE_ITERATOR_HPP diff --git a/include/boost/geometry/iterators/dispatch/point_iterator.hpp b/include/boost/geometry/iterators/dispatch/point_iterator.hpp new file mode 100644 index 000000000..c07f3a865 --- /dev/null +++ b/include/boost/geometry/iterators/dispatch/point_iterator.hpp @@ -0,0 +1,47 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2014, Oracle and/or its affiliates. + +// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle + +// Licensed under the Boost Software License version 1.0. +// http://www.boost.org/users/license.html + +#ifndef BOOST_GEOMETRY_ITERATORS_DISPATCH_POINT_ITERATOR_HPP +#define BOOST_GEOMETRY_ITERATORS_DISPATCH_POINT_ITERATOR_HPP + +#include +#include + +namespace boost { namespace geometry +{ + + +#ifndef DOXYGEN_NO_DISPATCH +namespace dispatch +{ + + +// dispatch for points_begin +template ::type> +struct points_begin + : not_implemented +{}; + + + +// dispatch for points_end +template ::type> +struct points_end + : not_implemented +{}; + + + +} // namespace core_dispatch +#endif // DOXYGEN_NO_DISPATCH + + +}} // namespace boost::geometry + +#endif // BOOST_GEOMETRY_ITERATORS_DISPATCH_POINT_ITERATOR_HPP diff --git a/include/boost/geometry/iterators/dispatch/point_iterator_type.hpp b/include/boost/geometry/iterators/dispatch/point_iterator_type.hpp new file mode 100644 index 000000000..02c40acae --- /dev/null +++ b/include/boost/geometry/iterators/dispatch/point_iterator_type.hpp @@ -0,0 +1,37 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2014, Oracle and/or its affiliates. + +// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle + +// Licensed under the Boost Software License version 1.0. +// http://www.boost.org/users/license.html + +#ifndef BOOST_GEOMETRY_ITERATORS_DISPATCH_POINT_ITERATOR_TYPE_HPP +#define BOOST_GEOMETRY_ITERATORS_DISPATCH_POINT_ITERATOR_TYPE_HPP + +#include +#include + +namespace boost { namespace geometry +{ + + +#ifndef DOXYGEN_NO_DISPATCH +namespace dispatch +{ + +template ::type> +struct point_iterator_type + : not_implemented +{}; + + + +} // namespace dispatch +#endif // DOXYGEN_NO_DISPATCH + + +}} // namespace boost::geometry + +#endif // BOOST_GEOMETRY_ITERATORS_DISPATCH_POINT_ITERATOR_TYPE_HPP diff --git a/include/boost/geometry/iterators/flatten_iterator.hpp b/include/boost/geometry/iterators/flatten_iterator.hpp new file mode 100644 index 000000000..9e3983cc4 --- /dev/null +++ b/include/boost/geometry/iterators/flatten_iterator.hpp @@ -0,0 +1,208 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2014, Oracle and/or its affiliates. + +// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle + +// Licensed under the Boost Software License version 1.0. +// http://www.boost.org/users/license.html + +#ifndef BOOST_GEOMETRY_ITERATORS_FLATTEN_ITERATOR_HPP +#define BOOST_GEOMETRY_ITERATORS_FLATTEN_ITERATOR_HPP + +#include +#include +#include +#include +#include + + +namespace boost { namespace geometry +{ + + + +template +< + typename OuterIterator, + typename InnerIterator, + typename Value, + typename AccessInnerBegin, + typename AccessInnerEnd +> +struct flatten_iterator + : public boost::iterator_facade + < + flatten_iterator + < + OuterIterator, + InnerIterator, + Value, + AccessInnerBegin, + AccessInnerEnd>, + Value, + boost::forward_traversal_tag + > +{ +private: + OuterIterator m_outer_it, m_outer_end; + InnerIterator m_inner_it; + + struct enabler {}; + +public: + typedef OuterIterator outer_iterator_type; + typedef InnerIterator inner_iterator_type; + + // default constructor + flatten_iterator() {} + + // for begin + flatten_iterator(OuterIterator outer_it, OuterIterator outer_end) + : m_outer_it(outer_it), m_outer_end(outer_end) + { + advance_through_empty(); + } + + // for end + flatten_iterator(OuterIterator outer_end) + : m_outer_it(outer_end), m_outer_end(outer_end) + {} + + template + < + typename OtherOuterIterator, typename OtherInnerIterator, + typename OtherValue, + typename OtherAccessInnerBegin, typename OtherAccessInnerEnd + > + flatten_iterator(flatten_iterator + < + OtherOuterIterator, + OtherInnerIterator, + OtherValue, + OtherAccessInnerBegin, + OtherAccessInnerEnd + > const& other, + typename boost::enable_if + < + boost::is_convertible, + enabler + >::type = enabler()) + : m_outer_it(other.m_outer_it), + m_outer_end(other.m_outer_end), + m_inner_it(other.m_inner_it) + {} + + template + < + typename OtherOuterIterator, + typename OtherInnerIterator, + typename OtherValue, + typename OtherAccessInnerBegin, + typename OtherAccessInnerEnd + > + flatten_iterator operator=(flatten_iterator + < + OtherOuterIterator, + OtherInnerIterator, + OtherValue, + OtherAccessInnerBegin, + OtherAccessInnerEnd + > const& other) + { + m_outer_it = other.m_outer_it; + m_outer_end = other.m_outer_end; + m_inner_it = other.m_inner_it; + return *this; + } + +private: + friend class boost::iterator_core_access; + + template + < + typename Outer, + typename Inner, + typename V, + typename InnerBegin, + typename InnerEnd + > + friend class flatten_iterator; + + static inline bool empty(OuterIterator outer_it) + { + return + AccessInnerBegin::apply(*outer_it) == AccessInnerEnd::apply(*outer_it); + } + + inline void advance_through_empty() + { + while ( m_outer_it != m_outer_end && empty(m_outer_it) ) + { + ++m_outer_it; + } + + if ( m_outer_it != m_outer_end ) + { + m_inner_it = AccessInnerBegin::apply(*m_outer_it); + } + } + + Value& dereference() const + { + BOOST_ASSERT( m_outer_it != m_outer_end ); + BOOST_ASSERT( m_inner_it != AccessInnerEnd::apply(*m_outer_it) ); + return *m_inner_it; + } + + + template + < + typename OtherOuterIterator, + typename OtherInnerIterator, + typename OtherValue, + typename OtherAccessInnerBegin, + typename OtherAccessInnerEnd + > + inline bool equal(flatten_iterator + < + OtherOuterIterator, + OtherInnerIterator, + OtherValue, + OtherAccessInnerBegin, + OtherAccessInnerEnd + > const& other) const + { + if ( this->m_outer_it != other.m_outer_it ) + { + return false; + } + + if ( this->m_outer_it == m_outer_end ) + { + return true; + } + + return this->m_inner_it == other.m_inner_it; + } + + inline void increment() + { + BOOST_ASSERT( m_outer_it != m_outer_end ); + BOOST_ASSERT( m_inner_it != AccessInnerEnd::apply(*m_outer_it) ); + + ++m_inner_it; + if ( m_inner_it == AccessInnerEnd::apply(*m_outer_it) ) + { + ++m_outer_it; + advance_through_empty(); + } + } +}; + + + +}} // namespace boost::geometry + + +#endif // BOOST_GEOMETRY_ITERATORS_FLATTEN_ITERATOR_HPP diff --git a/include/boost/geometry/iterators/point_iterator.hpp b/include/boost/geometry/iterators/point_iterator.hpp new file mode 100644 index 000000000..07a70c4e0 --- /dev/null +++ b/include/boost/geometry/iterators/point_iterator.hpp @@ -0,0 +1,278 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2014, Oracle and/or its affiliates. + +// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle + +// Licensed under the Boost Software License version 1.0. +// http://www.boost.org/users/license.html + +#ifndef BOOST_GEOMETRY_ITERATORS_POINT_ITERATOR_HPP +#define BOOST_GEOMETRY_ITERATORS_POINT_ITERATOR_HPP + +#include +#include +#include + + +namespace boost { namespace geometry +{ + + +#ifndef DOXYGEN_NO_DISPATCH +namespace dispatch +{ + + +// specializations for points_begin + + +template +struct points_begin +{ + static inline typename point_iterator_type::type + apply(Linestring& linestring) + { + return boost::begin(linestring); + } +}; + + +template +struct points_begin +{ + static inline typename point_iterator_type::type + apply(Ring& ring) + { + return boost::begin(ring); + } +}; + + +template +struct points_begin +{ + typedef typename point_iterator_type::type return_type; + + static inline return_type apply(Polygon& polygon) + { + typedef typename return_type::second_iterator_type flatten_iterator; + + return return_type + (boost::begin(geometry::exterior_ring(polygon)), + boost::end(geometry::exterior_ring(polygon)), + flatten_iterator(boost::begin(geometry::interior_rings(polygon)), + boost::end(geometry::interior_rings(polygon)) + ) + ); + } +}; + + +template +struct points_begin +{ + static inline typename point_iterator_type::type + apply(MultiPoint& multipoint) + { + return boost::begin(multipoint); + } +}; + + +template +struct points_begin +{ + static inline typename point_iterator_type::type + apply(MultiLinestring& multilinestring) + { + return typename point_iterator_type + < + MultiLinestring + >::type(boost::begin(multilinestring), boost::end(multilinestring)); + } +}; + + +template +struct points_begin +{ + static inline typename point_iterator_type::type + apply(MultiPolygon& multipolygon) + { + return typename point_iterator_type + < + MultiPolygon + >::type(boost::begin(multipolygon), boost::end(multipolygon)); + } +}; + +} // namespace dispatch +#endif // DOXYGEN_NO_DISPATCH + + + + + +#ifndef DOXYGEN_NO_DISPATCH +namespace dispatch +{ + + +// specializations for points_end + + +template +struct points_end +{ + static inline typename point_iterator_type::type + apply(Linestring& linestring) + { + return boost::end(linestring); + } +}; + + +template +struct points_end +{ + static inline typename point_iterator_type::type + apply(Ring& ring) + { + return boost::end(ring); + } +}; + + +template +struct points_end +{ + typedef typename point_iterator_type::type return_type; + + static inline return_type apply(Polygon& polygon) + { + typedef typename return_type::second_iterator_type flatten_iterator; + + return return_type + (boost::end(geometry::exterior_ring(polygon)), + flatten_iterator( boost::end(geometry::interior_rings(polygon)) ) + ); + } +}; + + +template +struct points_end +{ + static inline typename point_iterator_type::type + apply(MultiPoint& multipoint) + { + return boost::end(multipoint); + } +}; + + +template +struct points_end +{ + static inline typename point_iterator_type::type + apply(MultiLinestring& multilinestring) + { + return typename point_iterator_type + < + MultiLinestring + >::type(boost::end(multilinestring)); + } +}; + + +template +struct points_end +{ + static inline typename point_iterator_type::type + apply(MultiPolygon& multipolygon) + { + return typename point_iterator_type + < + MultiPolygon + >::type(boost::end(multipolygon)); + } +}; + + +} // namespace dispatch +#endif // DOXYGEN_NO_DISPATCH + + +// MK:: need to add doc here +template +class point_iterator + : public dispatch::point_iterator_type::type +{ +private: + typedef typename dispatch::point_iterator_type::type base; + + base* base_ptr() + { + return this; + } + + base const* base_ptr() const + { + return this; + } + + template + struct is_convertible + : boost::is_convertible + < + typename dispatch::point_iterator_type::type, + typename dispatch::point_iterator_type::type + > + {}; + + struct enabler {}; + + template friend class point_iterator; + template friend inline point_iterator points_begin(G&); + template friend inline point_iterator points_end(G&); + + point_iterator(base const& base_it) : base(base_it) {} + +public: + point_iterator() {} + + template + point_iterator(point_iterator const& other, + typename boost::enable_if + < + is_convertible, + enabler + >::type = enabler()) + + : base(*other.base_ptr()) + {} +}; + + +// MK:: need to add doc here +template +inline point_iterator +points_begin(Geometry& geometry) +{ + return dispatch::points_begin::apply(geometry); +} + + +// MK:: need to add doc here +template +inline point_iterator +points_end(Geometry& geometry) +{ + return dispatch::points_end::apply(geometry); +} + + +}} // namespace boost::geometry + +#endif // BOOST_GEOMETRY_ITERATORS_POINT_ITERATOR_HPP diff --git a/include/boost/geometry/iterators/point_iterator_type.hpp b/include/boost/geometry/iterators/point_iterator_type.hpp new file mode 100644 index 000000000..4d50e42c4 --- /dev/null +++ b/include/boost/geometry/iterators/point_iterator_type.hpp @@ -0,0 +1,203 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// Copyright (c) 2014, Oracle and/or its affiliates. + +// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle + +// Licensed under the Boost Software License version 1.0. +// http://www.boost.org/users/license.html + +#ifndef BOOST_GEOMETRY_ITERATORS_POINT_ITERATOR_TYPE_HPP +#define BOOST_GEOMETRY_ITERATORS_POINT_ITERATOR_TYPE_HPP + +#include +#include + +#include +#include +#include +#include +#include +#include + + +namespace boost { namespace geometry +{ + + + +#ifndef DOXYGEN_NO_DETAIL +namespace detail_dispatch +{ + + +template +struct point_iterator_value_type +{ + typedef typename boost::mpl::if_c + < + !boost::is_const::type::value, + typename geometry::point_type::type, + typename geometry::point_type::type const + >::type type; +}; + + + + +template +< + typename Geometry, + typename Tag = typename tag::type +> +struct point_iterator_inner_range_type +{ + typedef typename boost::mpl::if_c + < + !boost::is_const::type::value, + typename boost::range_value::type, + typename boost::range_value::type const + >::type type; +}; + + +template +struct point_iterator_inner_range_type +{ + typedef typename boost::mpl::if_c + < + !boost::is_const::type::value, + typename geometry::ring_type::type, + typename geometry::ring_type::type const + >::type type; +}; + + + +} // namespace detail_dispatch +#endif // DOXYGEN_NO_DETAIL + + + + + +#ifndef DOXYGEN_NO_DISPATCH +namespace dispatch +{ + + +template +struct point_iterator_type +{ + typedef typename boost::range_iterator::type type; +}; + + +template +struct point_iterator_type +{ + typedef typename boost::range_iterator::type type; +}; + + +template +class point_iterator_type +{ +private: + typedef typename detail_dispatch::point_iterator_inner_range_type + < + Polygon + >::type InnerRange; + +public: + typedef concatenate_iterator + < + typename boost::range_iterator::type, + flatten_iterator + < + typename boost::range_iterator + < + typename geometry::interior_type::type + >::type, + typename dispatch::point_iterator_type + < + InnerRange + >::type, + typename detail_dispatch::point_iterator_value_type + < + Polygon + >::type, + dispatch::points_begin, + dispatch::points_end + >, + typename detail_dispatch::point_iterator_value_type::type + > type; +}; + + +template +struct point_iterator_type +{ + typedef typename boost::range_iterator::type type; +}; + + +template +class point_iterator_type +{ +private: + typedef typename detail_dispatch::point_iterator_inner_range_type + < + MultiLinestring + >::type InnerRange; + +public: + typedef flatten_iterator + < + typename boost::range_iterator::type, + typename dispatch::point_iterator_type::type, + typename detail_dispatch::point_iterator_value_type + < + MultiLinestring + >::type, + dispatch::points_begin, + dispatch::points_end + > type; +}; + + +template +class point_iterator_type +{ +private: + typedef typename detail_dispatch::point_iterator_inner_range_type + < + MultiPolygon + >::type InnerRange; + +public: + typedef flatten_iterator + < + typename boost::range_iterator::type, + typename dispatch::point_iterator_type::type, + typename detail_dispatch::point_iterator_value_type + < + MultiPolygon + >::type, + dispatch::points_begin, + dispatch::points_end + > type; +}; + + + + + +} // namespace dispatch +#endif // DOXYGEN_NO_DISPATCH + + +}} // namespace boost::geometry + + +#endif // BOOST_GEOMETRY_ITERATORS_POINT_ITERATOR_TYPE_HPP diff --git a/include/boost/geometry/multi/algorithms/within.hpp b/include/boost/geometry/multi/algorithms/within.hpp index ef33029df..8c8917abd 100644 --- a/include/boost/geometry/multi/algorithms/within.hpp +++ b/include/boost/geometry/multi/algorithms/within.hpp @@ -81,7 +81,8 @@ struct within { template static inline bool apply(Point const& point, - MultiPolygon const& multi_polygon, Strategy const& strategy) + MultiPolygon const& multi_polygon, + Strategy const& strategy) { return detail::within::geometry_multi_within_code < @@ -101,12 +102,25 @@ struct within { template static inline bool apply(Point const& point, - MultiLinestring const& multi_linestring, Strategy const& strategy) + MultiLinestring const& multi_linestring, + Strategy const& strategy) { return detail::within::point_in_geometry(point, multi_linestring, strategy) == 1; } }; +template +struct within +{ + template + static inline bool apply(Point const& point, + MultiPoint const& multi_point, + Strategy const& strategy) + { + return detail::within::point_in_geometry(point, multi_point, strategy) == 1; + } +}; + } // namespace dispatch #endif // DOXYGEN_NO_DISPATCH diff --git a/include/boost/geometry/policies/relate/intersection_points.hpp b/include/boost/geometry/policies/relate/intersection_points.hpp index 8a315ef57..7a378475b 100644 --- a/include/boost/geometry/policies/relate/intersection_points.hpp +++ b/include/boost/geometry/policies/relate/intersection_points.hpp @@ -21,6 +21,7 @@ #include #include #include +#include namespace boost { namespace geometry { @@ -28,37 +29,6 @@ namespace boost { namespace geometry namespace policies { namespace relate { -template ::is_integer> -struct round_dispatch -{ - template - static inline Result apply(T const& v) - { - return v < 0 ? - boost::numeric_cast(ceil(v - 0.5f)) : - boost::numeric_cast(floor(v + 0.5f)); - } -}; - -template -struct round_dispatch -{ - template - static inline Result apply(T const& v) - { - return boost::numeric_cast(v); - } -}; - -template -inline Result round(T const& v) -{ - // NOTE: boost::round() could be used instead but it throws in some situations - - //BOOST_STATIC_ASSERT(!std::numeric_limits::is_integer); - return round_dispatch::apply(v); -} - template struct segments_intersection_points { @@ -89,9 +59,9 @@ struct segments_intersection_points return_type result; result.count = 1; set<0>(result.intersections[0], - round(R(s1x) + r * R(dx1))); + geometry::math::round(R(s1x) + r * R(dx1))); set<1>(result.intersections[0], - round(R(s1y) + r * R(dy1))); + geometry::math::round(R(s1y) + r * R(dy1))); return result; } diff --git a/include/boost/geometry/strategies/agnostic/point_in_poly_winding.hpp b/include/boost/geometry/strategies/agnostic/point_in_poly_winding.hpp index eac68cbc8..ae7fcb7ec 100644 --- a/include/boost/geometry/strategies/agnostic/point_in_poly_winding.hpp +++ b/include/boost/geometry/strategies/agnostic/point_in_poly_winding.hpp @@ -3,8 +3,8 @@ // Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands. // 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. @@ -13,6 +13,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_STRATEGY_AGNOSTIC_POINT_IN_POLY_WINDING_HPP #define BOOST_GEOMETRY_STRATEGY_AGNOSTIC_POINT_IN_POLY_WINDING_HPP @@ -198,23 +200,30 @@ struct default_strategy::type> type; }; +// TODO: use linear_tag and pointlike_tag the same way how areal_tag is used + template struct default_strategy { - typedef strategy::within::winding::type> type; + typedef winding::type> type; +}; + +template +struct default_strategy +{ + typedef winding::type> type; }; -// TODO: later move it to multi/strategies/agnostic template struct default_strategy { - typedef strategy::within::winding::type> type; + typedef winding::type> type; }; -template -struct default_strategy +template +struct default_strategy { - typedef strategy::within::winding::type, typename geometry::point_type::type> type; + typedef winding::type> type; }; } // namespace services @@ -243,19 +252,32 @@ struct default_strategy::type> type; }; +// TODO: use linear_tag and pointlike_tag the same way how areal_tag is used + template struct default_strategy { typedef strategy::within::winding::type> type; }; -// TODO: later move it to multi/strategies/agnostic +template +struct default_strategy +{ + typedef strategy::within::winding::type> type; +}; + template struct default_strategy { typedef strategy::within::winding::type> type; }; +template +struct default_strategy +{ + typedef strategy::within::winding::type> type; +}; + }}} // namespace strategy::covered_by::services #endif diff --git a/include/boost/geometry/strategies/agnostic/relate.hpp b/include/boost/geometry/strategies/agnostic/relate.hpp new file mode 100644 index 000000000..c61046fc8 --- /dev/null +++ b/include/boost/geometry/strategies/agnostic/relate.hpp @@ -0,0 +1,207 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) + +// 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 + +#ifndef BOOST_GEOMETRY_STRATEGY_AGNOSTIC_RELATE_HPP +#define BOOST_GEOMETRY_STRATEGY_AGNOSTIC_RELATE_HPP + +#include + + +namespace boost { namespace geometry +{ + +namespace strategy { namespace relate +{ + +template +struct relate +{ + template + static inline bool apply(Geometry1 const& geometry1, Geometry2 const& geometry2) + { + return detail::relate::relate(geometry1, geometry2); + } +}; + +} // namespace relate + +namespace within +{ + +#ifndef DOXYGEN_NO_STRATEGY_SPECIALIZATIONS + +namespace services +{ + +// P/L + +//template +//struct default_strategy +//{ +// typedef strategy::relate::relate type; +//}; +// +//template +//struct default_strategy +//{ +// typedef strategy::relate::relate type; +//}; + +// L/L + +template +struct default_strategy +{ + typedef strategy::relate::relate type; +}; + +template +struct default_strategy +{ + typedef strategy::relate::relate type; +}; + +template +struct default_strategy +{ + typedef strategy::relate::relate type; +}; + +// L/A + +template +struct default_strategy +{ + typedef strategy::relate::relate type; +}; + +template +struct default_strategy +{ + typedef strategy::relate::relate type; +}; + +template +struct default_strategy +{ + typedef strategy::relate::relate type; +}; + +template +struct default_strategy +{ + typedef strategy::relate::relate type; +}; + +template +struct default_strategy +{ + typedef strategy::relate::relate type; +}; + +template +struct default_strategy +{ + typedef strategy::relate::relate type; +}; + +} // namespace services + +#endif + + +}} // namespace strategy::within + + + +#ifndef DOXYGEN_NO_STRATEGY_SPECIALIZATIONS +namespace strategy { namespace covered_by { namespace services +{ + +// P/L + +//template +//struct default_strategy +//{ +// typedef strategy::relate::relate type; +//}; +// +//template +//struct default_strategy +//{ +// typedef strategy::relate::relate type; +//}; + +// L/L + +template +struct default_strategy +{ + typedef strategy::relate::relate type; +}; + +template +struct default_strategy +{ + typedef strategy::relate::relate type; +}; + +template +struct default_strategy +{ + typedef strategy::relate::relate type; +}; + +// L/A + +template +struct default_strategy +{ + typedef strategy::relate::relate type; +}; + +template +struct default_strategy +{ + typedef strategy::relate::relate type; +}; + +template +struct default_strategy +{ + typedef strategy::relate::relate type; +}; + +template +struct default_strategy +{ + typedef strategy::relate::relate type; +}; + +template +struct default_strategy +{ + typedef strategy::relate::relate type; +}; + +template +struct default_strategy +{ + typedef strategy::relate::relate type; +}; + +}}} // namespace strategy::covered_by::services +#endif + + +}} // namespace boost::geometry + + +#endif // BOOST_GEOMETRY_STRATEGY_AGNOSTIC_RELATE_HPP diff --git a/include/boost/geometry/strategies/strategies.hpp b/include/boost/geometry/strategies/strategies.hpp index 70cb2d95f..491c1d858 100644 --- a/include/boost/geometry/strategies/strategies.hpp +++ b/include/boost/geometry/strategies/strategies.hpp @@ -55,6 +55,8 @@ #include #include +#include + #include #include diff --git a/include/boost/geometry/util/math.hpp b/include/boost/geometry/util/math.hpp index 1296321b4..4d9ca6b8a 100644 --- a/include/boost/geometry/util/math.hpp +++ b/include/boost/geometry/util/math.hpp @@ -111,6 +111,29 @@ struct relaxed_epsilon } }; +// ItoF ItoI FtoF +template ::is_integer, + bool SourceIsInteger = std::numeric_limits::is_integer> +struct round +{ + static inline Result apply(Source const& v) + { + return boost::numeric_cast(v); + } +}; + +// FtoI +template +struct round +{ + static inline Result apply(Source const& v) + { + return v < 0 + ? boost::numeric_cast(ceil(v - 0.5f)) + : boost::numeric_cast(floor(v + 0.5f)); + } +}; } // namespace detail #endif @@ -239,6 +262,19 @@ static inline int sign(T const& value) return value > zero ? 1 : value < zero ? -1 : 0; } +/*! +\brief Short utility to calculate the rounded value of a number. +\ingroup utility +\note If the source T is NOT an integral type and Result is an integral type + the value is rounded towards the closest integral value. Otherwise it's + just casted. +*/ +template +inline Result round(T const& v) +{ + // NOTE: boost::round() could be used instead but it throws in some situations + return detail::round::apply(v); +} } // namespace math diff --git a/include/boost/geometry/util/range.hpp b/include/boost/geometry/util/range.hpp new file mode 100644 index 000000000..986aba660 --- /dev/null +++ b/include/boost/geometry/util/range.hpp @@ -0,0 +1,110 @@ +// 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 + +#ifndef BOOST_GEOMETRY_UTIL_RANGE_HPP +#define BOOST_GEOMETRY_UTIL_RANGE_HPP + +#include +#include +#include +#include +#include +#include + +namespace boost { namespace geometry { namespace range { + +// NOTE: For SinglePassRanges at could iterate over all elements until the i-th element is met. + +/*! +\brief Short utility to conveniently return an element of a RandomAccessRange. +\ingroup utility +*/ +template +inline typename boost::range_value::type const& +at(RandomAccessRange const& rng, + typename boost::range_size::type i) +{ + BOOST_RANGE_CONCEPT_ASSERT(( boost::RandomAccessRangeConcept )); + BOOST_ASSERT(i < boost::size(rng)); + return *(boost::begin(rng) + i); +} + +/*! +\brief Short utility to conveniently return an element of a RandomAccessRange. +\ingroup utility +*/ +template +inline typename boost::range_value::type & +at(RandomAccessRange & rng, + typename boost::range_size::type i) +{ + BOOST_RANGE_CONCEPT_ASSERT(( boost::RandomAccessRangeConcept )); + BOOST_ASSERT(i < boost::size(rng)); + return *(boost::begin(rng) + i); +} + +/*! +\brief Short utility to conveniently return the front element of a Range. +\ingroup utility +*/ +template +inline typename boost::range_value::type const& +front(Range const& rng) +{ + BOOST_ASSERT(!boost::empty(rng)); + return *boost::begin(rng); +} + +/*! +\brief Short utility to conveniently return the front element of a Range. +\ingroup utility +*/ +template +inline typename boost::range_value::type & +front(Range & rng) +{ + BOOST_ASSERT(!boost::empty(rng)); + return *boost::begin(rng); +} + +// NOTE: For SinglePassRanges back() could iterate over all elements until the last element is met. + +/*! +\brief Short utility to conveniently return the back element of a BidirectionalRange. +\ingroup utility +*/ +template +inline typename boost::range_value::type const& +back(BidirectionalRange const& rng) +{ + BOOST_RANGE_CONCEPT_ASSERT(( boost::BidirectionalRangeConcept )); + BOOST_ASSERT(!boost::empty(rng)); + return *(--boost::end(rng)); +} + +/*! +\brief Short utility to conveniently return the back element of a BidirectionalRange. +\ingroup utility +*/ +template +inline typename boost::range_value::type & +back(BidirectionalRange & rng) +{ + BOOST_RANGE_CONCEPT_ASSERT(( boost::BidirectionalRangeConcept )); + BOOST_ASSERT(!boost::empty(rng)); + return *(--boost::end(rng)); +} + +}}} // namespace boost::geometry::range + +#endif // BOOST_GEOMETRY_UTIL_RANGE_HPP diff --git a/test/algorithms/detail/sections/sectionalize.cpp b/test/algorithms/detail/sections/sectionalize.cpp index 212e95ea1..b4569fa24 100644 --- a/test/algorithms/detail/sections/sectionalize.cpp +++ b/test/algorithms/detail/sections/sectionalize.cpp @@ -61,13 +61,11 @@ void test_sectionalize_part() bg::detail::no_rescale_policy rescale_policy; bg::ring_identifier ring_id; - int index = 0; - int ndi = 0; - sectionalize_part::apply(sections, section, index, ndi, geometry, rescale_policy, false, ring_id, 10); + sectionalize_part::apply(sections, geometry, rescale_policy, false, ring_id, 10); // There should not yet be anything generated, because it is only ONE point geometry.push_back(bg::make(2, 2)); - sectionalize_part::apply(sections, section, index, ndi, geometry, rescale_policy, false, ring_id, 10); + sectionalize_part::apply(sections, geometry, rescale_policy, false, ring_id, 10); } diff --git a/test/algorithms/intersection.cpp b/test/algorithms/intersection.cpp index a9b0617f0..fa5f385fd 100644 --- a/test/algorithms/intersection.cpp +++ b/test/algorithms/intersection.cpp @@ -198,6 +198,14 @@ void test_areal() ggl_list_20131119_james[0], ggl_list_20131119_james[1], 1, 4, 6.6125873045, 0.1); +#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 + test_one("ggl_list_20140321_7415963", + ggl_list_20140321_7415963[0], ggl_list_20140321_7415963[1], + 0, 0, 0, 0.1); +#endif + test_one("buffer_rt_f", buffer_rt_f[0], buffer_rt_f[1], 1, 4, 0.00029437899183903937, 0.01); diff --git a/test/algorithms/overlay/Jamfile.v2 b/test/algorithms/overlay/Jamfile.v2 index b18744d41..a97c6b256 100644 --- a/test/algorithms/overlay/Jamfile.v2 +++ b/test/algorithms/overlay/Jamfile.v2 @@ -20,6 +20,7 @@ test-suite boost-geometry-algorithms-overlay [ run get_turn_info.cpp ] [ run get_turns.cpp ] [ run get_turns_linear_linear.cpp ] + [ run get_turns_linear_areal.cpp ] [ run relative_order.cpp ] [ run select_rings.cpp ] [ run self_intersection_points.cpp ] diff --git a/test/algorithms/overlay/get_turn_info.cpp b/test/algorithms/overlay/get_turn_info.cpp index e6dca7db8..a58fcadaf 100644 --- a/test/algorithms/overlay/get_turn_info.cpp +++ b/test/algorithms/overlay/get_turn_info.cpp @@ -51,7 +51,7 @@ void test_with_point(std::string const& caseid, < bg::detail::overlay::assign_null_policy >::apply(pi, pj, pk, qi, qj, qk, - 10, 10, // dummy max numbers of segments + false, false, false, false, // dummy parameters model, bg::detail::no_rescale_policy(), std::back_inserter(info)); diff --git a/test/algorithms/overlay/overlay_cases.hpp b/test/algorithms/overlay/overlay_cases.hpp index d600b6297..fa6647a02 100644 --- a/test/algorithms/overlay/overlay_cases.hpp +++ b/test/algorithms/overlay/overlay_cases.hpp @@ -538,6 +538,12 @@ static std::string ggl_list_20131119_james[2] = }; +static std::string ggl_list_20140321_7415963[2] = +{ + "POLYGON((-6.0 3.2500000000000013, -9.0 3.2500000000000022, -9.0 6.5, -6.0 6.5, -6.0 3.2500000000000013))", + "POLYGON((-3.0 0.0, -6.0 0.0, -6.0 3.2500000000000013, -3.0 3.2500000000000009, -3.0 0.0))", +}; + // 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] = diff --git a/test/algorithms/overlay/test_get_turns.hpp b/test/algorithms/overlay/test_get_turns.hpp index 4ca5198d3..41ee8400c 100644 --- a/test/algorithms/overlay/test_get_turns.hpp +++ b/test/algorithms/overlay/test_get_turns.hpp @@ -152,8 +152,8 @@ struct expected_pusher typedef std::vector::iterator iterator; typedef std::vector::const_iterator const_iterator; - //iterator begin() { return vec.begin(); } - //iterator end() { return vec.end(); } + iterator begin() { return vec.begin(); } + iterator end() { return vec.end(); } const_iterator begin() const { return vec.begin(); } const_iterator end() const { return vec.end(); } diff --git a/test/algorithms/relate.cpp b/test/algorithms/relate.cpp index 2ae078d25..47ae063b0 100644 --- a/test/algorithms/relate.cpp +++ b/test/algorithms/relate.cpp @@ -40,7 +40,7 @@ #include //TEST -#include +//#include namespace bgdr = bg::detail::relate; @@ -75,8 +75,8 @@ void check_geometry(Geometry1 const& geometry1, std::string expected_tr = transposed(expected); bool ok = boost::equal(res_str, expected_tr); BOOST_CHECK_MESSAGE(ok, - "relate: " << wkt1 - << " and " << wkt2 + "relate: " << wkt2 + << " and " << wkt1 << " -> Expected: " << expected_tr << " detected: " << res_str); } @@ -251,9 +251,14 @@ void test_linestring_linestring() 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"); - // spike - test_geometry("LINESTRING(0 0,10 0)", + // 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)", @@ -313,6 +318,10 @@ void test_linestring_linestring() test_geometry("LINESTRING(1 0,5 0,7 0,8 1)", "LINESTRING(0 0,10 0,10 10,4 -1)", "1F10F0102"); + // 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"); @@ -426,8 +435,28 @@ void test_linestring_polygon() // IB1 IE test_geometry("LINESTRING(10 10,10 5,15 5)", "POLYGON((0 0,0 10,10 10,10 0,0 0))", "F11F00212"); - // II IB0 IE - test_geometry("LINESTRING(5 5,10 5,15 10)", "POLYGON((0 0,0 10,10 10,10 0,0 0))", "1010F0212"); + // 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)", diff --git a/test/algorithms/within.cpp b/test/algorithms/within.cpp index bf15c8385..dcc65c31b 100644 --- a/test/algorithms/within.cpp +++ b/test/algorithms/within.cpp @@ -29,8 +29,6 @@ void test_linestring_linestring() 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, 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); @@ -41,14 +39,30 @@ void test_linestring_linestring() 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); + // 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,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)", false); + 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);*/ } template diff --git a/test/iterators/Jamfile.v2 b/test/iterators/Jamfile.v2 index 72091f21f..40273145d 100644 --- a/test/iterators/Jamfile.v2 +++ b/test/iterators/Jamfile.v2 @@ -1,8 +1,13 @@ # 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. +# Copyright (c) 2007-2014 Barend Gehrels, Amsterdam, the Netherlands. +# Copyright (c) 2008-2014 Bruno Lalande, Paris, France. +# Copyright (c) 2009-2014 Mateusz Loskot, London, UK. +# +# 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 @@ -12,4 +17,7 @@ test-suite boost-geometry-iterators : [ run closing_iterator.cpp ] [ run ever_circling_iterator.cpp ] + [ run point_iterator.cpp ] + [ run concatenate_iterator.cpp ] + [ run flatten_iterator.cpp ] ; diff --git a/test/iterators/concatenate_iterator.cpp b/test/iterators/concatenate_iterator.cpp new file mode 100644 index 000000000..6a488bcde --- /dev/null +++ b/test/iterators/concatenate_iterator.cpp @@ -0,0 +1,260 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) +// Unit Test + +// Copyright (c) 2014, Oracle and/or its affiliates. + +// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle + +// Licensed under the Boost Software License version 1.0. +// http://www.boost.org/users/license.html + +#ifndef BOOST_TEST_MODULE +#define BOOST_TEST_MODULE test_concatenate_iterator +#endif + +#include + +#include +#include +#include + +#include +#include + +#include +#include +#include + +using namespace boost::assign; + +template +std::ostream& print_container(std::ostream& os, + Iterator begin, Iterator end, + std::string const& header) +{ + std::cout << header; + for (Iterator it = begin; it != end; ++it) + { + os << " " << *it; + } + return os; +} + + +template +struct is_odd +{ + inline bool operator()(T const& t) const + { + return t % 2 != 0; + } +}; + +struct test_concatenate_iterator +{ + template + static inline void apply(Container1& c1, Container2& c2, + std::string const& case_id) + { +#ifdef GEOMETRY_TEST_DEBUG + std::cout << "case id: " << case_id << std::endl; +#endif + typedef typename Container1::const_iterator const_iterator1; + typedef typename Container2::const_iterator const_iterator2; + typedef typename Container1::iterator iterator1; + typedef typename Container2::iterator iterator2; + + typedef boost::geometry::concatenate_iterator + < + const_iterator1, const_iterator2, + typename Container1::value_type const + > const_concat_iterator; + + typedef boost::geometry::concatenate_iterator + < + iterator1, iterator2, typename Container1::value_type + > concat_iterator; + + + concat_iterator begin(c1.begin(), c1.end(), c2.begin()); + concat_iterator end(c1.end(), c2.end()); + const_concat_iterator const_begin(begin); + const_concat_iterator const_end(end); + const_begin = begin; + const_end = end; + + std::size_t size(0); + for (const_concat_iterator it = const_begin; it != const_end; ++it) + { + ++size; + } + BOOST_CHECK( c1.size() + c2.size() == size ); + + size = 0; + for (concat_iterator it = begin; it != end; ++it) + { + ++size; + } + BOOST_CHECK( c1.size() + c2.size() == size ); + +#ifdef GEOMETRY_TEST_DEBUG + print_container(std::cout, c1.begin(), c1.end(), "first :") + << std::endl; + print_container(std::cout, c2.begin(), c2.end(), "second :") + << std::endl; + print_container(std::cout, begin, end, "combined:") + << std::endl; + + if ( begin != end ) + { + std::cout << "min element: " + << *std::min_element(begin, end) + << std::endl; + std::cout << "max element: " + << *std::max_element(const_begin, const_end) + << std::endl; + } +#endif + + { + const_iterator1 it1 = c1.begin(); + const_iterator2 it2 = c2.begin(); + for (const_concat_iterator it = const_begin; it != const_end; ++it) + { + if ( it1 != c1.end() ) + { + BOOST_CHECK( *it == *it1 ); + ++it1; + } + else + { + BOOST_CHECK( *it == *it2 ); + ++it2; + } + } + } + + typedef typename std::iterator_traits + < + concat_iterator + >::value_type value_type; + + if ( c1.size() != 0 ) + { + concat_iterator it_max = std::max_element(begin, end); + const_concat_iterator const_it_max = + std::max_element(const_begin, const_end); + + BOOST_CHECK( it_max == const_it_max ); + + value_type old_value = *const_begin; + value_type new_value = *it_max + 1; + + *begin = *it_max + 1; + BOOST_CHECK( *c1.begin() == new_value ); + +#ifdef GEOMETRY_TEST_DEBUG + std::cout << std::endl; + std::cout << "modified element of 1st container:" << std::endl; + print_container(std::cout, c1.begin(), c1.end(), "first :") + << std::endl; + print_container(std::cout, begin, end, "combined:") + << std::endl; +#endif + + *begin = old_value; + BOOST_CHECK( *c1.begin() == old_value ); + } + + if ( c2.size() != 0 ) + { + concat_iterator begin2 = begin; + std::size_t counter(0); + while ( counter != c1.size() ) + { + ++counter; + begin2++; + } + + concat_iterator it_max = std::max_element(begin, end); + const_concat_iterator const_it_max = + std::max_element(const_begin, const_end); + + BOOST_CHECK( it_max == const_it_max ); + + value_type old_value = *begin2; + value_type new_value = *it_max + 1; + + *begin2 = *it_max + 1; + BOOST_CHECK( *c2.begin() == new_value ); + +#ifdef GEOMETRY_TEST_DEBUG + std::cout << std::endl; + std::cout << "modified element of 2nd container:" << std::endl; + print_container(std::cout, c2.begin(), c2.end(), "second :") + << std::endl; + print_container(std::cout, begin, end, "combined:") + << std::endl; +#endif + + *begin2 = old_value; + BOOST_CHECK( *c2.begin() == old_value ); + } + +#ifdef GEOMETRY_TEST_DEBUG + std::cout << std::endl; + std::cout << "odd elements removed:" << std::endl; + print_container(std::cout, begin, end, "before:") + << std::endl; +#endif + concat_iterator new_end = + std::remove_if(begin, end, is_odd()); + + for (const_concat_iterator it = const_begin; it != new_end; ++it) + { + BOOST_CHECK( !is_odd()(*it) ); + } + +#ifdef GEOMETRY_TEST_DEBUG + print_container(std::cout, begin, new_end, "after :") + << std::endl; +#endif + +#ifdef GEOMETRY_TEST_DEBUG + std::cout << "====================" << std::endl << std::endl; +#endif + } +}; + + +BOOST_AUTO_TEST_CASE( test_concatenate_iterator_all ) +{ + { + std::vector v; + std::list l; + + test_concatenate_iterator::apply(v, l, "empty_both"); + } + { + std::vector v; + std::list l; + l += 10,11,12,13,14,15,16,17,18,19,20; + + test_concatenate_iterator::apply(v, l, "empty_first"); + } + { + std::vector v; + v += 0,1,2,3,4,5,6; + std::list l; + + test_concatenate_iterator::apply(v, l, "empty_second"); + } + { + std::vector v; + v += 0,1,2,3,4,5,6; + std::list l; + l += 10,11,12,13,14,15,16,17,18,19,20; + + test_concatenate_iterator::apply(l, v, "non_empty"); + } +} diff --git a/test/iterators/flatten_iterator.cpp b/test/iterators/flatten_iterator.cpp new file mode 100644 index 000000000..98e8643e2 --- /dev/null +++ b/test/iterators/flatten_iterator.cpp @@ -0,0 +1,430 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) +// Unit Test + +// Copyright (c) 2014, Oracle and/or its affiliates. + +// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle + +// Licensed under the Boost Software License version 1.0. +// http://www.boost.org/users/license.html + +#ifndef BOOST_TEST_MODULE +#define BOOST_TEST_MODULE test_flatten_iterator +#endif + +#include + +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include + +using namespace boost::assign; + +template +std::ostream& print_container(std::ostream& os, + Iterator begin, Iterator end, + std::string const& header) +{ + std::cout << header; + for (Iterator it = begin; it != end; ++it) + { + os << " " << *it; + } + return os; +} + + +template +std::ostream& print_nested_container(std::ostream& os, + Iterator begin, Iterator end, + std::string const& header) +{ + std::cout << header; + for (Iterator outer = begin; outer != end; ++outer) + { + os << " ("; + for (BOOST_AUTO_TPL(inner, outer->begin()); + inner != outer->end(); ++inner) + { + if ( inner != outer->begin() ) + { + os << " "; + } + os << *inner; + } + os << ") "; + } + return os; +} + + +template +struct is_odd +{ + inline bool operator()(T const& t) const + { + return t % 2 != 0; + } +}; + + +template +struct is_even +{ + inline bool operator()(T const& t) const + { + return !is_odd()(t); + } +}; + + + +template +struct access_begin +{ + typedef typename boost::mpl::if_ + < + typename boost::is_const::type, + typename InnerContainer::const_iterator, + typename InnerContainer::iterator + >::type return_type; + + static inline return_type apply(InnerContainer& inner) + { + return inner.begin(); + } +}; + + +template +struct access_end +{ + typedef typename boost::mpl::if_ + < + typename boost::is_const::type, + typename InnerContainer::const_iterator, + typename InnerContainer::iterator + >::type return_type; + + static inline return_type apply(InnerContainer& inner) + { + return inner.end(); + } +}; + + +template +std::size_t number_of_elements(NestedContainer const& c) +{ + std::size_t num_elements(0); + for (typename NestedContainer::const_iterator outer = c.begin(); + outer != c.end(); ++outer) + { + num_elements += outer->size(); + } + return num_elements; +} + + +struct test_flatten_iterator +{ + template + static inline void apply(NestedContainer& c, + std::string const& case_id, + std::string const& container_id) + { +#ifdef GEOMETRY_TEST_DEBUG + std::stringstream sstream; + sstream << case_id << " " << "[" << container_id << "]"; + + std::cout << "case id: " << sstream.str() << std::endl; +#endif + typedef typename NestedContainer::const_iterator const_outer_iterator; + typedef typename NestedContainer::iterator outer_iterator; + typedef typename NestedContainer::value_type inner_container; + + typedef typename inner_container::const_iterator const_inner_iterator; + typedef typename inner_container::iterator inner_iterator; + + typedef boost::geometry::flatten_iterator + < + const_outer_iterator, + const_inner_iterator, + typename inner_container::value_type const, + access_begin, + access_end + > const_flatten_iterator; + + typedef boost::geometry::flatten_iterator + < + outer_iterator, + inner_iterator, + typename inner_container::value_type, + access_begin, + access_end + > flatten_iterator; + + + flatten_iterator begin(c.begin(), c.end()); + flatten_iterator end(c.end()); + const_flatten_iterator const_begin(begin); + const_flatten_iterator const_end(end); + const_begin = begin; + const_end = end; + + std::size_t size(0); + for (const_flatten_iterator it = const_begin; it != const_end; ++it) + { + ++size; + } + BOOST_CHECK( number_of_elements(c) == size ); + + size = 0; + for (flatten_iterator it = begin; it != end; ++it) + { + ++size; + } + BOOST_CHECK( number_of_elements(c) == size ); + +#ifdef GEOMETRY_TEST_DEBUG + print_nested_container(std::cout, c.begin(), c.end(), "nested :") + << std::endl; + print_container(std::cout, begin, end, "flattened :") + << std::endl; + + if ( begin != end ) + { + std::cout << "min element: " + << *std::min_element(begin, end) + << std::endl; + std::cout << "max element: " + << *std::max_element(const_begin, const_end) + << std::endl; + } +#endif + + { + const_flatten_iterator it = begin; + const_outer_iterator outer_begin = c.begin(); + const_outer_iterator outer_end = c.end(); + for (const_outer_iterator outer = outer_begin; + outer != outer_end; ++outer) + { + const_inner_iterator inner_begin = outer->begin(); + const_inner_iterator inner_end = outer->end(); + for (const_inner_iterator inner = inner_begin; + inner != inner_end; ++inner, it++) + // it++, instead of ++it, on purpose here + { + BOOST_CHECK( *it == *inner ); + } + } + } + + typedef typename std::iterator_traits + < + flatten_iterator + >::value_type value_type; + + if ( begin != end ) + { + flatten_iterator it_max = std::max_element(begin, end); + const_flatten_iterator const_it_max = + std::max_element(const_begin, const_end); + + BOOST_CHECK( it_max == const_it_max ); + BOOST_CHECK( *it_max == *const_it_max ); + + value_type old_value = *const_begin; + value_type new_value = *it_max + 1; + + *begin = *it_max + 1; + const_outer_iterator outer = c.begin(); + while ( outer->begin() == outer->end() ) + { + ++outer; + } + const_inner_iterator inner = outer->begin(); + + BOOST_CHECK( *inner == new_value ); + +#ifdef GEOMETRY_TEST_DEBUG + std::cout << std::endl; + std::cout << "modified 1st element of 1st non-empty " + << "inner container:" << std::endl; + print_nested_container(std::cout, c.begin(), c.end(), "nested :") + << std::endl; + print_container(std::cout, begin, end, "flattened:") + << std::endl; +#endif + + *begin = old_value; + BOOST_CHECK( *inner == old_value ); + } + + + if ( begin != end ) + { +#ifdef GEOMETRY_TEST_DEBUG + std::cout << std::endl; + std::cout << "odd elements removed:" << std::endl; + print_nested_container(std::cout, c.begin(), c.end(), + "nested before:") + << std::endl; + print_container(std::cout, begin, end, + "flattended before:") + << std::endl; +#endif + typename std::iterator_traits::difference_type + num_even = std::count_if(begin, end, is_even()); + + flatten_iterator new_end = + std::remove_if(begin, end, is_odd()); + + std::size_t new_size(0); + for (const_flatten_iterator it = const_begin; it != new_end; ++it) + { + ++new_size; + BOOST_CHECK( !is_odd()(*it) ); + } + BOOST_CHECK( new_size == static_cast(num_even) ); + +#ifdef GEOMETRY_TEST_DEBUG + std::cout << std::endl; + print_nested_container(std::cout, c.begin(), c.end(), + "nested after (all elements) :") + << std::endl; + print_container(std::cout, begin, new_end, "flattened after :") + << std::endl; +#endif + } + +#ifdef GEOMETRY_TEST_DEBUG + std::cout << "====================" << std::endl << std::endl; +#endif + } +}; + + + +// the actual test cases -- START +template +struct test_case_per_container; + +template<> +struct test_case_per_container<0> +{ + template + static inline void apply(std::string const& case_id, + std::string const& container_id) + { + NestedContainer c; + test_flatten_iterator::apply(c, case_id, container_id); + } +}; + +template<> +struct test_case_per_container<1> +{ + template + static inline void apply(std::string const& case_id, + std::string const& container_id) + { + NestedContainer c; + for (int i = 0; i < 5; ++i) + { + c += typename NestedContainer::value_type(); + } + test_flatten_iterator::apply(c, case_id, container_id); + } +}; + +template<> +struct test_case_per_container<2> +{ + template + static inline void apply(std::string const& case_id, + std::string const& container_id) + { + NestedContainer c; + typename NestedContainer::value_type ic[4]; + + ic[0] += 5,4,3,2,1; + ic[1] += 6,7,8; + ic[2] += 9; + ic[3] += 9,8,7,6,5; + c += ic[0],ic[1],ic[2],ic[3]; + + test_flatten_iterator::apply(c, case_id, container_id); + } +}; + +template<> +struct test_case_per_container<3> +{ + template + static inline void apply(std::string const& case_id, + std::string const& container_id) + { + NestedContainer c; + typename NestedContainer::value_type ic[20]; + + ic[2] += 5,4,3,2,1; + ic[3] += 6,7,8; + ic[8] += 9; + ic[9] += 9,8,7,6,5; + ic[14] += 4,3,2,1; + for (std::size_t i = 0; i < 20; ++i) + { + c += ic[i]; + } + + test_flatten_iterator::apply(c, case_id, container_id); + } +}; +// the actual test cases -- END + + + +template +inline void test_case_all_containers(std::string const& case_id) +{ + typedef typename std::vector > VV; + typedef typename std::vector > VL; + typedef typename std::list > LV; + typedef typename std::list > LL; + +#ifdef GEOMETRY_TEST_DEBUG + std::cout << std::endl << std::endl; +#endif + test_case_per_container::template apply(case_id, "VV"); + test_case_per_container::template apply(case_id, "VL"); + test_case_per_container::template apply(case_id, "LV"); + test_case_per_container::template apply(case_id, "LL"); + +#ifdef GEOMETRY_TEST_DEBUG + std::cout << std::endl; + std::cout << "********************************************************" + << std::endl << std::endl; +#endif +} + + + +BOOST_AUTO_TEST_CASE( test_flatten_iterator_all ) +{ + test_case_all_containers<0>("empty"); + test_case_all_containers<1>("case1"); + test_case_all_containers<2>("case2"); + test_case_all_containers<3>("case3"); +} diff --git a/test/iterators/point_iterator.cpp b/test/iterators/point_iterator.cpp new file mode 100644 index 000000000..13d77fdf8 --- /dev/null +++ b/test/iterators/point_iterator.cpp @@ -0,0 +1,468 @@ +// Boost.Geometry (aka GGL, Generic Geometry Library) +// Unit Test + +// Copyright (c) 2014, Oracle and/or its affiliates. + +// Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle + +// Licensed under the Boost Software License version 1.0. +// http://www.boost.org/users/license.html + + +#include + +#ifndef BOOST_TEST_MODULE +#define BOOST_TEST_MODULE test_point_iterator +#endif + +#include + +#include + +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include + +#include + +namespace bg = ::boost::geometry; +namespace ba = ::boost::assign; + +typedef bg::model::point point_type; +typedef bg::model::point point_type_3d; +typedef bg::model::linestring linestring_type; +typedef bg::model::polygon polygon_type; //ccw, open + +// multi geometries +typedef bg::model::multi_point multi_point_type; +typedef bg::model::multi_point multi_point_type_3d; +typedef bg::model::multi_linestring multi_linestring_type; +typedef bg::model::multi_polygon multi_polygon_type; + +typedef boost::tuple tuple_point_type; +typedef boost::tuple tuple_point_type_3d; +typedef std::vector tuple_multi_point_type; +typedef std::vector tuple_multi_point_type_3d; + +BOOST_GEOMETRY_REGISTER_BOOST_TUPLE_CS(cs::cartesian) +BOOST_GEOMETRY_REGISTER_MULTI_POINT(tuple_multi_point_type) +BOOST_GEOMETRY_REGISTER_MULTI_POINT(tuple_multi_point_type_3d) + + +template +Geometry from_wkt(std::string const& wkt) +{ + Geometry geometry; + boost::geometry::read_wkt(wkt, geometry); + return geometry; +} + + +struct equals +{ + template + static inline std::size_t number_of_elements(Iterator begin, + Iterator end) + { + std::size_t num_elems(0); + for (Iterator it = begin; it != end; ++it) + { + ++num_elems; + } + return num_elems; + } + + template + static inline bool apply(Iterator1 begin1, Iterator1 end1, + Iterator2 begin2, Iterator2 end2) + { + std::size_t num_points1 = number_of_elements(begin1, end1); + std::size_t num_points2 = number_of_elements(begin2, end2); + + if ( num_points1 != num_points2 ) + { + return false; + } + + Iterator1 it1 = begin1; + Iterator2 it2 = begin2; + for (; it1 != end1; ++it1, ++it2) + { + if ( !bg::equals(*it1, *it2) ) + { + return false; + } + } + return true; + } +}; + + +struct test_assignment +{ + template + static inline void apply(Iterator it, ConstIterator cit, + Value const& value1, Value const& value2) + { +#ifdef GEOMETRY_TEST_DEBUG + std::cout << "== before assignment ==" << std::endl; + std::cout << "value1: " << bg::wkt(value1) << std::endl; + std::cout << "value2: " << bg::wkt(value2) << std::endl; + std::cout << "*it : " << bg::wkt(*it) << std::endl; + std::cout << "*cit : " << bg::wkt(*cit) << std::endl; +#endif + + BOOST_CHECK( bg::equals(*it, value1) ); + BOOST_CHECK( !bg::equals(*it, value2) ); + BOOST_CHECK( bg::equals(*cit, value1) ); + BOOST_CHECK( !bg::equals(*cit, value2) ); + + *it = value2; + BOOST_CHECK( bg::equals(*it, value2) ); + BOOST_CHECK( !bg::equals(*it, value1) ); + BOOST_CHECK( bg::equals(*cit, value2) ); + BOOST_CHECK( !bg::equals(*cit, value1) ); + +#ifdef GEOMETRY_TEST_DEBUG + std::cout << "== after 1st assignment ==" << std::endl; + std::cout << "value1: " << bg::wkt(value1) << std::endl; + std::cout << "value2: " << bg::wkt(value2) << std::endl; + std::cout << "*it : " << bg::wkt(*it) << std::endl; + std::cout << "*cit : " << bg::wkt(*cit) << std::endl; +#endif + + *it = value1; + BOOST_CHECK( bg::equals(*it, value1) ); + BOOST_CHECK( !bg::equals(*it, value2) ); + BOOST_CHECK( bg::equals(*cit, value1) ); + BOOST_CHECK( !bg::equals(*cit, value2) ); + +#ifdef GEOMETRY_TEST_DEBUG + std::cout << "== after 2nd assignment ==" << std::endl; + std::cout << "value1: " << bg::wkt(value1) << std::endl; + std::cout << "value2: " << bg::wkt(value2) << std::endl; + std::cout << "*it : " << bg::wkt(*it) << std::endl; + std::cout << "*cit : " << bg::wkt(*cit) << std::endl; + std::cout << std::endl; +#endif + } +}; + + +template +struct test_point_iterator_of_geometry +{ + template + static inline void base_test(G& geometry, + PointRange const& point_range, + std::string const& header) + { + typedef bg::point_iterator point_iterator; + typedef bg::point_iterator const_point_iterator; + + point_iterator begin = bg::points_begin(geometry); + point_iterator end = bg::points_end(geometry); + + BOOST_CHECK( equals::apply(begin, end, + bg::points_begin(point_range), + bg::points_end(point_range)) + ); + +#ifdef GEOMETRY_TEST_DEBUG + std::cout << header << " geometry: " << bg::wkt(geometry) << std::endl; + std::cout << "point range: ("; + for (point_iterator pit = begin; pit != end; ++pit) + { + std::cout << " " << bg::dsv(*pit); + } + std::cout << " )" << std::endl; + + typedef bg::point_iterator point_range_iterator; + + point_range_iterator rng_begin = bg::points_begin(point_range); + point_range_iterator rng_end = bg::points_end(point_range); + std::cout << "expected point range: ("; + for (point_range_iterator pit = rng_begin; pit != rng_end; ++pit) + { + std::cout << " " << bg::dsv(*pit); + } + std::cout << " )" << std::endl; +#endif + } + + static inline void apply(Geometry geometry, PointRange const& point_range) + { + base_test(geometry, point_range, "non-const"); + +#ifdef GEOMETRY_TEST_DEBUG + std::cout << std::endl; +#endif + + base_test(geometry, point_range, "const"); + +#ifdef GEOMETRY_TEST_DEBUG + std::cout << std::endl << std::endl; +#endif + + // testing construction of const and non-const iterator + typedef bg::point_iterator point_iterator; + typedef bg::point_iterator const_point_iterator; + + point_iterator begin = bg::points_begin(geometry); + point_iterator end = bg::points_end(geometry); + + const_point_iterator const_begin = bg::points_begin(geometry); + const_point_iterator const_end = bg::points_end(geometry); + + // testing assignment of non-const to const iterator + const_begin = begin; + const_end = end; + + // testing dereferencing/assignment + if ( begin != end ) + { + typedef typename bg::point_type::type point; + + point p = *begin; + point q = bg::make_zero(); + + test_assignment::apply(begin, const_begin, p, q); + + *begin = q; + test_assignment::apply(begin, const_begin, q, p); + + *begin = p; + } + } +}; + + +//====================================================================== +//====================================================================== + + +BOOST_AUTO_TEST_CASE( test_linestring_point_iterator ) +{ +#ifdef GEOMETRY_TEST_DEBUG + std::cout << "*** LINESTRING ***" << std::endl; +#endif + + typedef tuple_multi_point_type TMP; + typedef linestring_type L; + + typedef test_point_iterator_of_geometry tester; + + tester::apply(from_wkt("LINESTRING()"), + TMP() + ); + + tester::apply(from_wkt("LINESTRING(3 3,4 4,5 5)"), + ba::tuple_list_of(3,3)(4,4)(5,5) + ); + +#ifdef GEOMETRY_TEST_DEBUG + std::cout << std::endl << std::endl << std::endl; +#endif +} + + +//====================================================================== +//====================================================================== + + +BOOST_AUTO_TEST_CASE( test_polygon_point_iterator ) +{ +#ifdef GEOMETRY_TEST_DEBUG + std::cout << "*** POLYGON ***" << std::endl; +#endif + + typedef tuple_multi_point_type TMP; + typedef polygon_type P; + + typedef test_point_iterator_of_geometry tester; + + tester::apply(from_wkt

("POLYGON()"), + TMP() + ); + + tester::apply(from_wkt

("POLYGON(())"), + TMP() + ); + + tester::apply(from_wkt

("POLYGON((1 1,9 1,9 9,1 9),(5 5,6 5,6 6,5 6))"), + ba::tuple_list_of(1,1)(9,1)(9,9)(1,9)(5,5)(6,5)(6,6)(5,6) + ); + + tester::apply(from_wkt

("POLYGON((3 3,4 4,5 5),(),(),(),(6 6,7 7,8 8),(),(),(9 9),())"), + ba::tuple_list_of(3,3)(4,4)(5,5)(6,6)(7,7)(8,8)(9,9) + ); + + tester::apply(from_wkt

("POLYGON((),(3 3,4 4,5 5),(),(),(6 6,7 7,8 8),(),(),(9 9),())"), + ba::tuple_list_of(3,3)(4,4)(5,5)(6,6)(7,7)(8,8)(9,9) + ); + +#ifdef GEOMETRY_TEST_DEBUG + std::cout << std::endl << std::endl; +#endif +} + + +//====================================================================== +//====================================================================== + + +BOOST_AUTO_TEST_CASE( test_multipoint_point_iterator ) +{ +#ifdef GEOMETRY_TEST_DEBUG + std::cout << "*** MULTIPOINT ***" << std::endl; +#endif + + typedef tuple_multi_point_type TMP; + typedef multi_point_type MP; + + typedef test_point_iterator_of_geometry tester; + + tester::apply(from_wkt("MULTIPOINT()"), + TMP() + ); + + tester::apply(from_wkt("MULTIPOINT(3 3,4 4,5 5)"), + ba::tuple_list_of(3,3)(4,4)(5,5) + ); + +#ifdef GEOMETRY_TEST_DEBUG + std::cout << std::endl << std::endl << std::endl; +#endif +} + + +//====================================================================== +//====================================================================== + + +BOOST_AUTO_TEST_CASE( test_multipoint_3d_point_iterator ) +{ +#ifdef GEOMETRY_TEST_DEBUG + std::cout << "*** MULTIPOINT 3D ***" << std::endl; +#endif + + typedef tuple_multi_point_type_3d TMP; + typedef multi_point_type_3d MP; + + typedef test_point_iterator_of_geometry tester; + + tester::apply(from_wkt("MULTIPOINT()"), + TMP() + ); + + tester::apply(from_wkt("MULTIPOINT(3 3 3,4 4 4,5 5 5)"), + ba::tuple_list_of(3,3,3)(4,4,4)(5,5,5) + ); + +#ifdef GEOMETRY_TEST_DEBUG + std::cout << std::endl << std::endl << std::endl; +#endif +} + + +//====================================================================== +//====================================================================== + + +BOOST_AUTO_TEST_CASE( test_multilinestring_point_iterator ) +{ +#ifdef GEOMETRY_TEST_DEBUG + std::cout << "*** MULTILINESTRING ***" << std::endl; +#endif + + typedef tuple_multi_point_type TMP; + typedef multi_linestring_type ML; + + typedef test_point_iterator_of_geometry tester; + + tester::apply(from_wkt("MULTILINESTRING()"), + TMP() + ); + + tester::apply(from_wkt("MULTILINESTRING(())"), + TMP() + ); + + tester::apply(from_wkt("MULTILINESTRING((),(),())"), + TMP() + ); + + tester::apply(from_wkt("MULTILINESTRING((1 1,2 2,3 3),(3 3,4 4,5 5),(6 6))"), + ba::tuple_list_of(1,1)(2,2)(3,3)(3,3)(4,4)(5,5)(6,6) + ); + + tester::apply(from_wkt("MULTILINESTRING((),(),(1 1,2 2,3 3),(),(),(3 3,4 4,5 5),(),(6 6),(),(),())"), + ba::tuple_list_of(1,1)(2,2)(3,3)(3,3)(4,4)(5,5)(6,6) + ); + +#ifdef GEOMETRY_TEST_DEBUG + std::cout << std::endl << std::endl; +#endif +} + + +//====================================================================== +//====================================================================== + + +BOOST_AUTO_TEST_CASE( test_multipolygon_point_iterator ) +{ +#ifdef GEOMETRY_TEST_DEBUG + std::cout << "*** MULTIPOLYGON ***" << std::endl; +#endif + + typedef tuple_multi_point_type TMP; + typedef multi_polygon_type MPL; + + typedef test_point_iterator_of_geometry tester; + + tester::apply(from_wkt("MULTIPOLYGON()"), + TMP() + ); + + tester::apply(from_wkt("MULTIPOLYGON( () )"), + TMP() + ); + + tester::apply(from_wkt("MULTIPOLYGON( (()) )"), + TMP() + ); + + tester::apply(from_wkt("MULTIPOLYGON( ((),()) )"), + TMP() + ); + + tester::apply(from_wkt("MULTIPOLYGON(((3 3,4 4,5 5),(6 6,7 7,8 8),(9 9)),((1 1,2 2,10 10),(11 11,12 12)))"), + ba::tuple_list_of(3,3)(4,4)(5,5)(6,6)(7,7)(8,8)(9,9)\ + (1,1)(2,2)(10,10)(11,11)(12,12) + ); + + tester::apply(from_wkt("MULTIPOLYGON(((3 3,4 4,5 5),(),(),(),(6 6,7 7,8 8),(),(),(9 9),()),((),(1 1,2 2,10 10),(),(),(),(11 11,12 12),(),(),(13 13),()))"), + ba::tuple_list_of(3,3)(4,4)(5,5)(6,6)(7,7)(8,8)(9,9)\ + (1,1)(2,2)(10,10)(11,11)(12,12)(13,13) + ); + + tester::apply(from_wkt("MULTIPOLYGON(((3 3,4 4,5 5),(),(),(),(6 6,7 7,8 8),(),(),(9 9),()),((),(1 1,2 2,10 10),(),(),(),(11 11,12 12),(),(),(13 13),()),((),(),()))"), + ba::tuple_list_of(3,3)(4,4)(5,5)(6,6)(7,7)(8,8)(9,9)\ + (1,1)(2,2)(10,10)(11,11)(12,12)(13,13) + ); + +#ifdef GEOMETRY_TEST_DEBUG + std::cout << std::endl << std::endl; +#endif +}