From ee4ebca3c6c6fd6852b3db1eb462980b216accbb Mon Sep 17 00:00:00 2001 From: Adam Wulkiewicz Date: Sat, 15 Dec 2018 01:53:12 +0100 Subject: [PATCH] [get_turns] Make side calculation for linear endpoints clearer. Don't calculate unnecessary sides. --- .../overlay/get_turn_info_for_endpoint.hpp | 48 ++++++------ .../detail/overlay/get_turn_info_la.hpp | 76 +++++++++++++------ 2 files changed, 74 insertions(+), 50 deletions(-) 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 c91afcd7c..fef551715 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 @@ -225,6 +225,8 @@ private: template struct get_turn_info_for_endpoint { + typedef std::pair operations_pair; + BOOST_STATIC_ASSERT(EnableFirst || EnableLast); template - operations = operations_of_equal(side_pj_q2, side_pj_x, side_qk_x); + operations_pair operations = operations_of_equal(side_pj_q2, side_pj_q1, side_qk_q1); // TODO: must the above be calculated? // wouldn't it be enough to check if segments are collinear? @@ -468,11 +467,10 @@ struct get_turn_info_for_endpoint else if ( ip_j2 ) { int const side_pi_q2 = sides.apply(range2.at(1), range2.at(2), range1.at(0)); - int const side_pi_x = sides.apply(range2.at(0), range1.at(1), range1.at(0)); - int const side_qk_x = sides.apply(range2.at(0), range1.at(1), range2.at(2)); + int const side_pi_q1 = sides.apply(range2.at(0), range2.at(1), range1.at(0)); + int const side_qk_q1 = sides.apply(range2.at(0), range2.at(1), range2.at(2)); - std::pair - operations = operations_of_equal(side_pi_q2, side_pi_x, side_qk_x); + operations_pair operations = operations_of_equal(side_pi_q2, side_pi_q1, side_qk_q1); // TODO: must the above be calculated? // wouldn't it be enough to check if segments are collinear? @@ -578,23 +576,24 @@ struct get_turn_info_for_endpoint *out++ = tp; } - static inline std::pair - operations_of_equal(int side_1, int side_2, int side_3) + static inline operations_pair operations_of_equal(int side_px_q2, + int side_px_q1, + int side_qk_q1) { - // If pk is collinear with qj-qk, they continue collinearly. - // This can be on either side of p1 (== q1), or collinear + // If px (pi or pj) is collinear with qj-qk (q2), they continue collinearly. + // This can be on either side of q1, or collinear // The second condition checks if they do not continue // oppositely - if ( side_1 == 0 && side_2 == side_3 ) + if (side_px_q2 == 0 && side_px_q1 == side_qk_q1) { return std::make_pair(operation_continue, operation_continue); } // If they turn to same side (not opposite sides) - if ( ! base_turn_handler::opposite(side_2, side_3) ) + if ( ! base_turn_handler::opposite(side_px_q1, side_qk_q1) ) { - // If pk is left of q2 or collinear: p: union, q: intersection - if ( side_1 != -1 ) + // If px is left of q2 or collinear: p: union, q: intersection + if (side_px_q2 != -1 ) { return std::make_pair(operation_union, operation_intersection); } @@ -607,7 +606,7 @@ struct get_turn_info_for_endpoint { // They turn opposite sides. If p turns left (or collinear), // p: union, q: intersection - if ( side_2 != -1 ) + if (side_px_q1 != -1 ) { return std::make_pair(operation_union, operation_intersection); } @@ -618,16 +617,15 @@ struct get_turn_info_for_endpoint } } - static inline bool operations_both( - std::pair const& operations, - operation_type const op) + static inline bool operations_both(operations_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) + static inline bool operations_combination(operations_pair const& operations, + operation_type const op1, + operation_type const op2) { return ( operations.first == op1 && operations.second == op2 ) || ( operations.first == op2 && operations.second == op1 ); 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 6207eae23..476569603 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 @@ -725,8 +725,6 @@ struct get_turn_info_linear_areal } else { - method_type replaced_method = method_touch_interior; - // The code below should avoid using a side_calculator. // Mainly because it is constructed with the wrong points. // It should never be constructed other than pi,pj,pk / qi,qj,qk @@ -735,33 +733,40 @@ struct get_turn_info_linear_areal // (and that method can assign the operations, no need to return // a pair, that is not done anywhere in all turns/operations) + // pi is the intersection point at qj or in the middle of q1 + // so consider segments + // 1. pi at qj: qi-qj-pj and qi-qj-qk + // x: qi-qj, y: qj-qk, qz: qk + // 2. pi in the middle of q1: qi-pi-pj and qi-pi-qj + // x: qi-pi, y: pi-qj, qz: qj + // qi-pi, side the same as WRT q1 + // pi-qj, side the same as WRT q1 + // qj WRT q1 is 0 + method_type replaced_method = method_none; + int side_pj_y = 0, side_pj_x = 0, side_qz_x = 0; + // 1. ip0 or pi at qj if ( ip0.is_qj ) { - int const side_pj_q2 = sides.apply(range_q.at(1), range_q.at(2), range_p.at(1)); - int const side_pj_x = sides.apply(range_q.at(0), range_p.at(0), range_p.at(1)); - int const side_qk_x = sides.apply(range_q.at(0), range_p.at(0), range_q.at(2)); - - std::pair operations - = get_info_e::operations_of_equal(side_pj_q2, side_pj_x, side_qk_x); - - tp.operations[0].operation = operations.first; - tp.operations[1].operation = operations.second; - replaced_method = method_touch; + side_pj_y = sides.apply(range_q.at(1), range_q.at(2), range_p.at(1)); // pj wrt q2 + side_pj_x = sides.apply(range_q.at(0), range_q.at(1), range_p.at(1)); // pj wrt q1 + side_qz_x = sides.apply(range_q.at(0), range_q.at(1), range_q.at(2)); // qk wrt q1 } + // 2. ip0 or pi in the middle of q1 else { - int const side_pj_y = sides.apply(range_p.at(0), range_q.at(1), range_p.at(1)); - int const side_pj_x = sides.apply(range_q.at(0), range_p.at(0), range_p.at(1)); - int const side_qj_x = sides.apply(range_q.at(0), range_p.at(0), range_q.at(1)); - - std::pair operations - = get_info_e::operations_of_equal(side_pj_y, side_pj_x, side_qj_x); - - tp.operations[0].operation = operations.first; - tp.operations[1].operation = operations.second; + replaced_method = method_touch_interior; + side_pj_y = sides.apply(range_q.at(0), range_q.at(1), range_p.at(1)); // pj wrt q1 + side_pj_x = side_pj_y; // pj wrt q1 + side_qz_x = 0; // qj wrt q1 } + std::pair operations + = get_info_e::operations_of_equal(side_pj_y, side_pj_x, side_qz_x); + + tp.operations[0].operation = operations.first; + tp.operations[1].operation = operations.second; + turn_transformer_ec transformer(replaced_method); transformer(tp); } @@ -797,12 +802,33 @@ struct get_turn_info_linear_areal } else //if ( result.template get<0>().count == 1 ) { - int const side_pi_q2 = sides.apply(range_q.at(1), range_q.at(2), range_p.at(0)); - int const side_pi_x = sides.apply(range_q.at(0), range_p.at(1), range_p.at(0)); - int const side_qk_x = sides.apply(range_q.at(0), range_p.at(1), range_q.at(2)); + // pj is the intersection point at qj or in the middle of q1 + // so consider segments + // 1. pj at qj: qi-qj-pi and qi-qj-qk + // x: qi-qj, y: qj-qk, qz: qk + // 2. pj in the middle of q1: qi-pj-pi and qi-pj-qj + // x: qi-pj, y: pj-qj, qz: qj + // qi-pj, the side is the same as WRT q1 + // pj-qj, the side is the same as WRT q1 + // side of qj WRT q1 is 0 + int side_pi_y = 0, side_pi_x = 0, side_qz_x = 0; + // 1. ip0 or pj at qj + if ( ip0.is_qj ) + { + side_pi_y = sides.apply(range_q.at(1), range_q.at(2), range_p.at(0)); // pi wrt q2 + side_pi_x = sides.apply(range_q.at(0), range_q.at(1), range_p.at(0)); // pi wrt q1 + side_qz_x = sides.apply(range_q.at(0), range_q.at(1), range_q.at(2)); // qk wrt q1 + } + // 2. ip0 or pj in the middle of q1 + else + { + side_pi_y = sides.apply(range_q.at(0), range_q.at(1), range_p.at(0)); // pi wrt q1 + side_pi_x = side_pi_y; // pi wrt q1 + side_qz_x = 0; // qj wrt q1 + } std::pair operations - = get_info_e::operations_of_equal(side_pi_q2, side_pi_x, side_qk_x); + = get_info_e::operations_of_equal(side_pi_y, side_pi_x, side_qz_x); tp.operations[0].operation = operations.first; tp.operations[1].operation = operations.second;