Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-07-12 08:14:05

0001 // Boost.Geometry (aka GGL, Generic Geometry Library)
0002 
0003 // Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
0004 // Copyright (c) 2017-2023 Adam Wulkiewicz, Lodz, Poland.
0005 
0006 // This file was modified by Oracle on 2013, 2014, 2015, 2017, 2018.
0007 // Modifications copyright (c) 2013-2018 Oracle and/or its affiliates.
0008 // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
0009 
0010 // Use, modification and distribution is subject to the Boost Software License,
0011 // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
0012 // http://www.boost.org/LICENSE_1_0.txt)
0013 
0014 #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_GET_TURN_INFO_LL_HPP
0015 #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_GET_TURN_INFO_LL_HPP
0016 
0017 #include <boost/throw_exception.hpp>
0018 
0019 #include <boost/geometry/core/assert.hpp>
0020 
0021 #include <boost/geometry/algorithms/detail/overlay/get_turn_info.hpp>
0022 #include <boost/geometry/algorithms/detail/overlay/get_turn_info_for_endpoint.hpp>
0023 
0024 #include <boost/geometry/util/constexpr.hpp>
0025 
0026 namespace boost { namespace geometry {
0027 
0028 #ifndef DOXYGEN_NO_DETAIL
0029 namespace detail { namespace overlay {
0030 
0031 template<typename AssignPolicy>
0032 struct get_turn_info_linear_linear
0033 {
0034     static const bool handle_spikes = true;
0035 
0036     template
0037     <
0038         typename UniqueSubRange1,
0039         typename UniqueSubRange2,
0040         typename TurnInfo,
0041         typename UmbrellaStrategy,
0042         typename RobustPolicy,
0043         typename OutputIterator
0044     >
0045     static inline OutputIterator apply(
0046                 UniqueSubRange1 const& range_p,
0047                 UniqueSubRange2 const& range_q,
0048                 TurnInfo const& tp_model,
0049                 UmbrellaStrategy const& umbrella_strategy,
0050                 RobustPolicy const& robust_policy,
0051                 OutputIterator out)
0052     {
0053         typedef intersection_info
0054             <
0055                 UniqueSubRange1, UniqueSubRange2,
0056                 typename TurnInfo::point_type,
0057                 UmbrellaStrategy,
0058                 RobustPolicy
0059             > inters_info;
0060 
0061         inters_info inters(range_p, range_q, umbrella_strategy, robust_policy);
0062 
0063         char const method = inters.d_info().how;
0064 
0065         // Copy, to copy possibly extended fields
0066         TurnInfo tp = tp_model;
0067 
0068         // Select method and apply
0069         switch(method)
0070         {
0071             case 'a' : // collinear, "at"
0072             case 'f' : // collinear, "from"
0073             case 's' : // starts from the middle
0074                 get_turn_info_for_endpoint<true, true>
0075                     ::apply(range_p, range_q,
0076                             tp_model, inters, method_none, out,
0077                             umbrella_strategy);
0078                 break;
0079 
0080             case 'd' : // disjoint: never do anything
0081                 break;
0082 
0083             case 'm' :
0084             {
0085                 using handler = touch_interior<TurnInfo, verify_policy_ll>;
0086 
0087                 if ( get_turn_info_for_endpoint<false, true>
0088                         ::apply(range_p, range_q,
0089                                 tp_model, inters, method_touch_interior, out,
0090                                 umbrella_strategy) )
0091                 {
0092                     // do nothing
0093                 }
0094                 else
0095                 {
0096                     // If Q (1) arrives (1)
0097                     if ( inters.d_info().arrival[1] == 1)
0098                     {
0099                         handler::template apply<0>(range_p, range_q, tp,
0100                                                   inters.i_info(), inters.d_info(),
0101                                                   inters.sides(),
0102                                                   umbrella_strategy);
0103                     }
0104                     else
0105                     {
0106                         // Swap p/q
0107                         handler::template apply<1>(range_q, range_p, tp,
0108                                                   inters.i_info(), inters.d_info(),
0109                                                   inters.swapped_sides(),
0110                                                   umbrella_strategy);
0111                     }
0112 
0113                     if ( tp.operations[0].operation == operation_blocked )
0114                     {
0115                         tp.operations[1].is_collinear = true;
0116                     }
0117                     if ( tp.operations[1].operation == operation_blocked )
0118                     {
0119                         tp.operations[0].is_collinear = true;
0120                     }
0121 
0122                     replace_method_and_operations_tm(tp.method,
0123                                                      tp.operations[0].operation,
0124                                                      tp.operations[1].operation);
0125 
0126                     *out++ = tp;
0127                 }
0128             }
0129             break;
0130             case 'i' :
0131             {
0132                 crosses<TurnInfo>::apply(tp, inters.i_info(), inters.d_info());
0133 
0134                 replace_operations_i(tp.operations[0].operation, tp.operations[1].operation);
0135 
0136                 *out++ = tp;
0137             }
0138             break;
0139             case 't' :
0140             {
0141                 using handler = touch<TurnInfo, verify_policy_ll>;
0142 
0143                 // Both touch (both arrive there)
0144                 if ( get_turn_info_for_endpoint<false, true>
0145                         ::apply(range_p, range_q,
0146                                 tp_model, inters, method_touch, out,
0147                                 umbrella_strategy) )
0148                 {
0149                     // do nothing
0150                 }
0151                 else
0152                 {
0153                     handler::apply(range_p, range_q, tp,
0154                                    inters.i_info(), inters.d_info(),
0155                                    inters.sides(),
0156                                    umbrella_strategy);
0157 
0158                     // workarounds for touch<> not taking spikes into account starts here
0159                     // those was discovered empirically
0160                     // touch<> is not symmetrical!
0161                     // P spikes and Q spikes may produce various operations!
0162                     // TODO: this is not optimal solution - think about rewriting touch<>
0163 
0164                     if ( tp.operations[0].operation == operation_blocked
0165                       && tp.operations[1].operation == operation_blocked )
0166                     {
0167                         // two touching spikes on the same line
0168                         if ( inters.is_spike_p() && inters.is_spike_q() )
0169                         {
0170                             tp.operations[0].operation = operation_union;
0171                             tp.operations[1].operation = operation_union;
0172                         }
0173                         else
0174                         {
0175                             tp.operations[0].is_collinear = true;
0176                             tp.operations[1].is_collinear = true;
0177                         }
0178                     }
0179                     else if ( tp.operations[0].operation == operation_blocked )
0180                     {
0181                         // a spike on P on the same line with Q1
0182                         if ( inters.is_spike_p() )
0183                         {
0184                             if ( inters.sides().qk_wrt_p1() == 0 )
0185                             {
0186                                 tp.operations[0].is_collinear = true;
0187                             }
0188                             else
0189                             {
0190                                 tp.operations[0].operation = operation_union;
0191                             }
0192                         }
0193                         else
0194                         {
0195                             tp.operations[1].is_collinear = true;
0196                         }
0197                     }
0198                     else if ( tp.operations[1].operation == operation_blocked )
0199                     {
0200                         // a spike on Q on the same line with P1
0201                         if ( inters.is_spike_q() )
0202                         {
0203                             if ( inters.sides().pk_wrt_q1() == 0 )
0204                             {
0205                                 tp.operations[1].is_collinear = true;
0206                             }
0207                             else
0208                             {
0209                                 tp.operations[1].operation = operation_union;
0210                             }
0211                         }
0212                         else
0213                         {
0214                             tp.operations[0].is_collinear = true;
0215                         }
0216                     }
0217                     else if ( tp.operations[0].operation == operation_continue
0218                            && tp.operations[1].operation == operation_continue )
0219                     {
0220                         // P spike on the same line with Q2 (opposite)
0221                         if ( inters.sides().pk_wrt_q1() == -inters.sides().qk_wrt_q1()
0222                           && inters.is_spike_p() )
0223                         {
0224                             tp.operations[0].operation = operation_union;
0225                             tp.operations[1].operation = operation_union;
0226                         }
0227                     }
0228                     else if ( tp.operations[0].operation == operation_none
0229                            && tp.operations[1].operation == operation_none )
0230                     {
0231                         // spike not handled by touch<>
0232                         bool const is_p = inters.is_spike_p();
0233                         bool const is_q = inters.is_spike_q();
0234 
0235                         if ( is_p || is_q )
0236                         {
0237                             tp.operations[0].operation = operation_union;
0238                             tp.operations[1].operation = operation_union;
0239 
0240                             if ( inters.sides().pk_wrt_q2() == 0 )
0241                             {
0242                                 tp.operations[0].operation = operation_continue; // will be converted to i
0243                                 if ( is_p )
0244                                 {
0245                                     tp.operations[0].is_collinear = true;
0246                                 }
0247                             }
0248 
0249                             if ( inters.sides().qk_wrt_p2() == 0 )
0250                             {
0251                                 tp.operations[1].operation = operation_continue; // will be converted to i
0252                                 if ( is_q )
0253                                 {
0254                                     tp.operations[1].is_collinear = true;
0255                                 }
0256                             }
0257                         }
0258                     }
0259 
0260                     // workarounds for touch<> not taking spikes into account ends here
0261 
0262                     replace_method_and_operations_tm(tp.method,
0263                                                      tp.operations[0].operation,
0264                                                      tp.operations[1].operation);
0265 
0266                     if BOOST_GEOMETRY_CONSTEXPR (! handle_spikes)
0267                     {
0268                         *out++ = tp;
0269                     }
0270                     else if (! append_opposite_spikes<append_touches>(tp, inters, out))
0271                     {
0272                         *out++ = tp;
0273                     }
0274                 }
0275             }
0276             break;
0277             case 'e':
0278             {
0279                 using handler = equal<TurnInfo, verify_policy_ll>;
0280 
0281                 if ( get_turn_info_for_endpoint<true, true>
0282                         ::apply(range_p, range_q,
0283                                 tp_model, inters, method_equal, out,
0284                                 umbrella_strategy) )
0285                 {
0286                     // do nothing
0287                 }
0288                 else
0289                 {
0290                     tp.operations[0].is_collinear = true;
0291                     tp.operations[1].is_collinear = true;
0292 
0293                     if ( ! inters.d_info().opposite )
0294                     {
0295                         // Both equal
0296                         // or collinear-and-ending at intersection point
0297                         handler::apply(range_p, range_q, tp,
0298                             inters.i_info(), inters.d_info(), inters.sides(),
0299                             umbrella_strategy);
0300 
0301                         operation_type spike_op
0302                             = ( tp.operations[0].operation != operation_continue
0303                              || tp.operations[1].operation != operation_continue ) ?
0304                                 operation_union :
0305                                 operation_continue;
0306 
0307                         // transform turn
0308                         turn_transformer_ec transformer(method_touch);
0309                         transformer(tp);
0310 
0311                         // conditionally handle spikes
0312                         if BOOST_GEOMETRY_CONSTEXPR (! handle_spikes)
0313                         {
0314                             *out++ = tp;
0315                         }
0316                         else if (! append_collinear_spikes(tp, inters, method_touch,
0317                                                            spike_op, out))
0318                         {
0319                             *out++ = tp; // no spikes
0320                         }
0321                     }
0322                     else
0323                     {
0324                         // TODO: ignore for spikes or generate something else than opposite?
0325 
0326                         equal_opposite
0327                             <
0328                                 TurnInfo,
0329                                 AssignPolicy
0330                             >::apply(range_p, range_q, tp, out, inters);
0331                     }
0332                 }
0333             }
0334             break;
0335             case 'c' :
0336             {
0337                 // Collinear
0338                 if ( get_turn_info_for_endpoint<true, true>
0339                         ::apply(range_p, range_q,
0340                                 tp_model, inters,  method_collinear, out,
0341                                 umbrella_strategy) )
0342                 {
0343                     // do nothing
0344                 }
0345                 else
0346                 {
0347                     // NOTE: this is for spikes since those are set in the turn_transformer_ec
0348                     tp.operations[0].is_collinear = true;
0349                     tp.operations[1].is_collinear = true;
0350 
0351                     if ( ! inters.d_info().opposite )
0352                     {
0353                         method_type method_replace = method_touch_interior;
0354                         operation_type spike_op = operation_continue;
0355 
0356                         if ( inters.d_info().arrival[0] == 0 )
0357                         {
0358                             // Collinear, but similar thus handled as equal
0359                             using handler = equal<TurnInfo, verify_policy_ll>;
0360 
0361                             handler::apply(range_p, range_q, tp,
0362                                 inters.i_info(), inters.d_info(), inters.sides(),
0363                                 umbrella_strategy);
0364 
0365                             method_replace = method_touch;
0366                             if ( tp.operations[0].operation != operation_continue
0367                               || tp.operations[1].operation != operation_continue )
0368                             {
0369                                 spike_op = operation_union;
0370                             }
0371                         }
0372                         else
0373                         {
0374                             using handler = collinear<TurnInfo, verify_policy_ll>;
0375                             handler::apply(range_p, range_q, tp,
0376                                            inters.i_info(), inters.d_info(),
0377                                            inters.sides());
0378 
0379                             //method_replace = method_touch_interior;
0380                             //spike_op = operation_continue;
0381                         }
0382 
0383                         // transform turn
0384                         turn_transformer_ec transformer(method_replace);
0385                         transformer(tp);
0386 
0387                         // conditionally handle spikes
0388                         if BOOST_GEOMETRY_CONSTEXPR (! handle_spikes)
0389                         {
0390                             *out++ = tp;
0391                         }
0392                         else if (! append_collinear_spikes(tp, inters, method_replace,
0393                                                            spike_op, out))
0394                         {
0395                             // no spikes
0396                             *out++ = tp;
0397                         }
0398                     }
0399                     else
0400                     {
0401                         // If this always 'm' ?
0402                         turn_transformer_ec transformer(method_touch_interior);
0403 
0404                         // conditionally handle spikes
0405                         if BOOST_GEOMETRY_CONSTEXPR (handle_spikes)
0406                         {
0407                             append_opposite_spikes<append_collinear_opposite>(tp, inters, out);
0408                         }
0409 
0410                         // TODO: ignore for spikes?
0411                         //       E.g. pass is_p_valid = !is_p_last && !is_pj_spike,
0412                         //       the same with is_q_valid
0413 
0414                         collinear_opposite
0415                             <
0416                                 TurnInfo,
0417                                 AssignPolicy
0418                             >::apply(range_p, range_q,
0419                                 tp, out, inters, inters.sides(),
0420                                 transformer);
0421                     }
0422                 }
0423             }
0424             break;
0425             case '0' :
0426             {
0427                 // degenerate points
0428                 if BOOST_GEOMETRY_CONSTEXPR (AssignPolicy::include_degenerate)
0429                 {
0430                     only_convert::apply(tp, inters.i_info());
0431 
0432                     // if any, only one of those should be true
0433                     if ( range_p.is_first_segment()
0434                       && equals::equals_point_point(range_p.at(0), tp.point, umbrella_strategy) )
0435                     {
0436                         tp.operations[0].position = position_front;
0437                     }
0438                     else if ( range_p.is_last_segment()
0439                            && equals::equals_point_point(range_p.at(1), tp.point, umbrella_strategy) )
0440                     {
0441                         tp.operations[0].position = position_back;
0442                     }
0443                     else if ( range_q.is_first_segment()
0444                            && equals::equals_point_point(range_q.at(0), tp.point, umbrella_strategy) )
0445                     {
0446                         tp.operations[1].position = position_front;
0447                     }
0448                     else if ( range_q.is_last_segment()
0449                            && equals::equals_point_point(range_q.at(1), tp.point, umbrella_strategy) )
0450                     {
0451                         tp.operations[1].position = position_back;
0452                     }
0453 
0454                     *out++ = tp;
0455                 }
0456             }
0457             break;
0458             default :
0459             {
0460 #if defined(BOOST_GEOMETRY_DEBUG_ROBUSTNESS)
0461                 std::cout << "TURN: Unknown method: " << method << std::endl;
0462 #endif
0463 #if ! defined(BOOST_GEOMETRY_OVERLAY_NO_THROW)
0464                 BOOST_THROW_EXCEPTION(turn_info_exception(method));
0465 #endif
0466             }
0467             break;
0468         }
0469 
0470         return out;
0471     }
0472 
0473     template <typename TurnInfo,
0474               typename IntersectionInfo,
0475               typename OutIt>
0476     static inline bool append_collinear_spikes(TurnInfo & tp,
0477                                                IntersectionInfo const& inters_info,
0478                                                method_type method, operation_type spike_op,
0479                                                OutIt out)
0480     {
0481         // method == touch || touch_interior
0482         // both position == middle
0483 
0484         bool is_p_spike = tp.operations[0].operation == spike_op
0485                        && inters_info.is_spike_p();
0486         bool is_q_spike = tp.operations[1].operation == spike_op
0487                        && inters_info.is_spike_q();
0488 
0489         if ( is_p_spike && is_q_spike )
0490         {
0491             if ( tp.method == method_equal
0492               && tp.operations[0].operation == operation_continue
0493               && tp.operations[1].operation == operation_continue )
0494             {
0495                 // treat both non-opposite collinear spikes as no-spikes
0496                 return false;
0497             }
0498 
0499             tp.method = method;
0500             tp.operations[0].operation = operation_blocked;
0501             tp.operations[1].operation = operation_blocked;
0502             *out++ = tp;
0503             tp.operations[0].operation = operation_intersection;
0504             tp.operations[1].operation = operation_intersection;
0505             *out++ = tp;
0506 
0507             return true;
0508         }
0509         else if ( is_p_spike )
0510         {
0511             tp.method = method;
0512             tp.operations[0].operation = operation_blocked;
0513             tp.operations[1].operation = operation_union;
0514             *out++ = tp;
0515             tp.operations[0].operation = operation_intersection;
0516             //tp.operations[1].operation = operation_union;
0517             *out++ = tp;
0518 
0519             return true;
0520         }
0521         else if ( is_q_spike )
0522         {
0523             tp.method = method;
0524             tp.operations[0].operation = operation_union;
0525             tp.operations[1].operation = operation_blocked;
0526             *out++ = tp;
0527             //tp.operations[0].operation = operation_union;
0528             tp.operations[1].operation = operation_intersection;
0529             *out++ = tp;
0530 
0531             return true;
0532         }
0533 
0534         return false;
0535     }
0536 
0537     enum append_version { append_touches, append_collinear_opposite };
0538 
0539     template <append_version Version,
0540               typename TurnInfo,
0541               typename IntersectionInfo,
0542               typename OutIt>
0543     static inline bool append_opposite_spikes(TurnInfo & tp,
0544                                               IntersectionInfo const& inters,
0545                                               OutIt out)
0546     {
0547         static const bool is_version_touches = (Version == append_touches);
0548 
0549         bool is_p_spike = ( is_version_touches ?
0550                             ( tp.operations[0].operation == operation_continue
0551                            || tp.operations[0].operation == operation_intersection ) :
0552                             true )
0553                        && inters.is_spike_p();
0554         bool is_q_spike = ( is_version_touches ?
0555                             ( tp.operations[1].operation == operation_continue
0556                            || tp.operations[1].operation == operation_intersection ) :
0557                             true )
0558                        && inters.is_spike_q();
0559 
0560         bool res = false;
0561 
0562         if (is_p_spike)
0563         {
0564             bool output_spike = false;
0565             if BOOST_GEOMETRY_CONSTEXPR (is_version_touches)
0566             {
0567                 tp.operations[0].is_collinear = true;
0568                 tp.operations[1].is_collinear = false;
0569                 tp.method = method_touch;
0570 
0571                 output_spike = true;
0572             }
0573             else if (inters.d_info().arrival[0] == 1) // Version == append_collinear_opposite
0574             {
0575                 tp.operations[0].is_collinear = true;
0576                 tp.operations[1].is_collinear = false;
0577 
0578                 BOOST_GEOMETRY_ASSERT(inters.i_info().count > 1);
0579                 base_turn_handler::assign_point(tp, method_touch_interior,
0580                                                 inters.i_info(), 1);
0581 
0582                 output_spike = true;
0583             }
0584 
0585             if (output_spike)
0586             {
0587                 tp.operations[0].operation = operation_blocked;
0588                 tp.operations[1].operation = operation_intersection;
0589                 *out++ = tp;
0590                 tp.operations[0].operation = operation_intersection;
0591                 //tp.operations[1].operation = operation_intersection;
0592                 *out++ = tp;
0593 
0594                 res = true;
0595             }
0596         }
0597 
0598         if (is_q_spike)
0599         {
0600             bool output_spike = false;
0601             if BOOST_GEOMETRY_CONSTEXPR (is_version_touches)
0602             {
0603                 tp.operations[0].is_collinear = false;
0604                 tp.operations[1].is_collinear = true;
0605                 tp.method = method_touch;
0606 
0607                 output_spike = true;
0608             }
0609             else if (inters.d_info().arrival[1] == 1) // Version == append_collinear_opposite
0610             {
0611                 tp.operations[0].is_collinear = false;
0612                 tp.operations[1].is_collinear = true;
0613 
0614                 BOOST_GEOMETRY_ASSERT(inters.i_info().count > 0);
0615                 base_turn_handler::assign_point(tp, method_touch_interior, inters.i_info(), 0);
0616 
0617                 output_spike = true;
0618             }
0619 
0620             if (output_spike)
0621             {
0622                 tp.operations[0].operation = operation_intersection;
0623                 tp.operations[1].operation = operation_blocked;
0624                 *out++ = tp;
0625                 //tp.operations[0].operation = operation_intersection;
0626                 tp.operations[1].operation = operation_intersection;
0627                 *out++ = tp;
0628 
0629                 res = true;
0630             }
0631         }
0632 
0633         return res;
0634     }
0635 
0636     static inline void replace_method_and_operations_tm(method_type & method,
0637                                                         operation_type & op0,
0638                                                         operation_type & op1)
0639     {
0640         if ( op0 == operation_blocked && op1 == operation_blocked )
0641         {
0642             // NOTE: probably only if methods are WRT IPs, not segments!
0643             method = (method == method_touch ? method_equal : method_collinear);
0644             op0 = operation_continue;
0645             op1 = operation_continue;
0646         }
0647         else
0648         {
0649             if ( op0 == operation_continue || op0 == operation_blocked )
0650             {
0651                 op0 = operation_intersection;
0652             }
0653             else if ( op0 == operation_intersection )
0654             {
0655                 op0 = operation_union;
0656             }
0657 
0658             if ( op1 == operation_continue || op1 == operation_blocked )
0659             {
0660                 op1 = operation_intersection;
0661             }
0662             else if ( op1 == operation_intersection )
0663             {
0664                 op1 = operation_union;
0665             }
0666 
0667             // spikes in 'm'
0668             if ( method == method_error )
0669             {
0670                 method = method_touch_interior;
0671                 op0 = operation_union;
0672                 op1 = operation_union;
0673             }
0674         }
0675     }
0676 
0677     class turn_transformer_ec
0678     {
0679     public:
0680         explicit turn_transformer_ec(method_type method_t_or_m)
0681             : m_method(method_t_or_m)
0682         {}
0683 
0684         template <typename Turn>
0685         void operator()(Turn & turn) const
0686         {
0687             operation_type & op0 = turn.operations[0].operation;
0688             operation_type & op1 = turn.operations[1].operation;
0689 
0690             BOOST_GEOMETRY_ASSERT(op0 != operation_blocked || op1 != operation_blocked );
0691 
0692             if ( op0 == operation_blocked )
0693             {
0694                 op0 = operation_intersection;
0695             }
0696             else if ( op0 == operation_intersection )
0697             {
0698                 op0 = operation_union;
0699             }
0700 
0701             if ( op1 == operation_blocked )
0702             {
0703                 op1 = operation_intersection;
0704             }
0705             else if ( op1 == operation_intersection )
0706             {
0707                 op1 = operation_union;
0708             }
0709 
0710             if ( op0 == operation_intersection || op0 == operation_union
0711               || op1 == operation_intersection || op1 == operation_union )
0712             {
0713                 turn.method = m_method;
0714             }
0715 
0716 // TODO: is this correct?
0717 //       it's equivalent to comparing to operation_blocked at the beginning of the function
0718             turn.operations[0].is_collinear = op0 != operation_intersection;
0719             turn.operations[1].is_collinear = op1 != operation_intersection;
0720         }
0721 
0722     private:
0723         method_type m_method;
0724     };
0725 
0726     static inline void replace_operations_i(operation_type & op0, operation_type & op1)
0727     {
0728         if ( op0 == operation_intersection )
0729         {
0730             op0 = operation_union;
0731         }
0732 
0733         if ( op1 == operation_intersection )
0734         {
0735             op1 = operation_union;
0736         }
0737     }
0738 };
0739 
0740 }} // namespace detail::overlay
0741 #endif // DOXYGEN_NO_DETAIL
0742 
0743 }} // namespace boost::geometry
0744 
0745 #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_GET_TURN_INFO_LL_HPP