mirror of
https://github.com/boostorg/geometry.git
synced 2026-02-10 23:42:12 +00:00
[get_turns] Use RobustPolicy in a unified way in all three get_turn_info* policies (A/A, L/A, and L/L).
Newly introduced intersection_info containing IntersectionResult, SideCalculator and Point refs is used also in get_turn_info for A/A.
Robust points are stored only if RobustPolicy is not no_rescale_policy.
This commit also fixes an error in get_turn_info - swapped_side_calc created for method_touch_interior ('m') should use robust points just like the original one.
This commit is contained in:
@@ -21,7 +21,7 @@
|
||||
#include <boost/geometry/geometries/segment.hpp>
|
||||
|
||||
#include <boost/geometry/policies/robustness/robust_point_type.hpp>
|
||||
|
||||
#include <boost/geometry/algorithms/detail/overlay/get_turn_info_helpers.hpp>
|
||||
|
||||
// Silence warning C4127: conditional expression is constant
|
||||
#if defined(_MSC_VER)
|
||||
@@ -60,36 +60,6 @@ public:
|
||||
namespace detail { namespace overlay
|
||||
{
|
||||
|
||||
template <typename PointP, typename PointQ,
|
||||
typename Pi = PointP, typename Pj = PointP, typename Pk = PointP,
|
||||
typename Qi = PointQ, typename Qj = PointQ, typename Qk = PointQ
|
||||
>
|
||||
struct side_calculator
|
||||
{
|
||||
typedef boost::geometry::strategy::side::side_by_triangle<> side; // todo: get from coordinate system
|
||||
|
||||
inline side_calculator(Pi const& pi, Pj const& pj, Pk const& pk,
|
||||
Qi const& qi, Qj const& qj, Qk const& qk)
|
||||
: m_pi(pi), m_pj(pj), m_pk(pk)
|
||||
, m_qi(qi), m_qj(qj), m_qk(qk)
|
||||
{}
|
||||
|
||||
inline int pk_wrt_p1() const { return side::apply(m_pi, m_pj, m_pk); }
|
||||
inline int pk_wrt_q1() const { return side::apply(m_qi, m_qj, m_pk); }
|
||||
inline int qk_wrt_p1() const { return side::apply(m_pi, m_pj, m_qk); }
|
||||
inline int qk_wrt_q1() const { return side::apply(m_qi, m_qj, m_qk); }
|
||||
|
||||
inline int pk_wrt_q2() const { return side::apply(m_qj, m_qk, m_pk); }
|
||||
inline int qk_wrt_p2() const { return side::apply(m_pj, m_pk, m_qk); }
|
||||
|
||||
Pi const& m_pi;
|
||||
Pj const& m_pj;
|
||||
Pk const& m_pk;
|
||||
Qi const& m_qi;
|
||||
Qj const& m_qj;
|
||||
Qk const& m_qk;
|
||||
};
|
||||
|
||||
struct base_turn_handler
|
||||
{
|
||||
// Returns true if both sides are opposite
|
||||
@@ -947,41 +917,12 @@ struct get_turn_info
|
||||
RobustPolicy const& robust_policy,
|
||||
OutputIterator out)
|
||||
{
|
||||
typedef typename geometry::robust_point_type
|
||||
<
|
||||
Point1, RobustPolicy
|
||||
>::type robust_point_type;
|
||||
typedef intersection_info<Point1, Point2, typename TurnInfo::point_type, RobustPolicy>
|
||||
inters_info;
|
||||
|
||||
robust_point_type pi_rob, pj_rob, pk_rob, qi_rob, qj_rob, qk_rob;
|
||||
geometry::recalculate(pi_rob, pi, robust_policy);
|
||||
geometry::recalculate(pj_rob, pj, robust_policy);
|
||||
geometry::recalculate(pk_rob, pk, robust_policy);
|
||||
geometry::recalculate(qi_rob, qi, robust_policy);
|
||||
geometry::recalculate(qj_rob, qj, robust_policy);
|
||||
geometry::recalculate(qk_rob, qk, robust_policy);
|
||||
inters_info inters(pi, pj, pk, qi, qj, qk, robust_policy);
|
||||
|
||||
typedef model::referring_segment<Point1 const> segment_type1;
|
||||
typedef model::referring_segment<Point2 const> segment_type2;
|
||||
segment_type1 p1(pi, pj);
|
||||
segment_type2 q1(qi, qj);
|
||||
|
||||
side_calculator<robust_point_type, robust_point_type> side_calc(pi_rob, pj_rob, pk_rob, qi_rob, qj_rob, qk_rob);
|
||||
|
||||
typedef strategy_intersection
|
||||
<
|
||||
typename cs_tag<typename TurnInfo::point_type>::type,
|
||||
Point1,
|
||||
Point2,
|
||||
typename TurnInfo::point_type,
|
||||
RobustPolicy
|
||||
> si;
|
||||
|
||||
typedef typename si::segment_intersection_strategy_type strategy;
|
||||
|
||||
typename strategy::return_type result = strategy::apply(p1, q1,
|
||||
robust_policy, pi_rob, pj_rob, qi_rob, qj_rob);
|
||||
|
||||
char const method = result.template get<1>().how;
|
||||
char const method = inters.d_info().how;
|
||||
|
||||
// Copy, to copy possibly extended fields
|
||||
TurnInfo tp = tp_model;
|
||||
@@ -993,11 +934,10 @@ struct get_turn_info
|
||||
case 'f' : // collinear, "from"
|
||||
case 's' : // starts from the middle
|
||||
if (AssignPolicy::include_no_turn
|
||||
&& result.template get<0>().count > 0)
|
||||
&& inters.i_info().count > 0)
|
||||
{
|
||||
only_convert::apply(tp,
|
||||
result.template get<0>());
|
||||
AssignPolicy::apply(tp, pi, qi, result.template get<0>(), result.template get<1>());
|
||||
only_convert::apply(tp, inters.i_info());
|
||||
AssignPolicy::apply(tp, pi, qi, inters.i_info(), inters.d_info());
|
||||
*out++ = tp;
|
||||
}
|
||||
break;
|
||||
@@ -1013,29 +953,34 @@ struct get_turn_info
|
||||
> policy;
|
||||
|
||||
// If Q (1) arrives (1)
|
||||
if (result.template get<1>().arrival[1] == 1)
|
||||
if ( inters.d_info().arrival[1] == 1 )
|
||||
{
|
||||
policy::template apply<0>(pi, pj, pk, qi, qj, qk,
|
||||
tp, result.template get<0>(), result.template get<1>(),
|
||||
side_calc);
|
||||
tp, inters.i_info(), inters.d_info(),
|
||||
inters.sides());
|
||||
}
|
||||
else
|
||||
{
|
||||
// Swap p/q
|
||||
side_calculator<Point2, Point1> swapped_side_calc(qi, qj, qk, pi, pj, pk);
|
||||
side_calculator
|
||||
<
|
||||
typename inters_info::robust_point2_type,
|
||||
typename inters_info::robust_point1_type
|
||||
> swapped_side_calc(inters.rqi(), inters.rqj(), inters.rqk(),
|
||||
inters.rpi(), inters.rpj(), inters.rpk());
|
||||
policy::template apply<1>(qi, qj, qk, pi, pj, pk,
|
||||
tp, result.template get<0>(), result.template get<1>(),
|
||||
tp, inters.i_info(), inters.d_info(),
|
||||
swapped_side_calc);
|
||||
}
|
||||
AssignPolicy::apply(tp, pi, qi, result.template get<0>(), result.template get<1>());
|
||||
AssignPolicy::apply(tp, pi, qi, inters.i_info(), inters.d_info());
|
||||
*out++ = tp;
|
||||
}
|
||||
break;
|
||||
case 'i' :
|
||||
{
|
||||
crosses<TurnInfo>::apply(pi, pj, pk, qi, qj, qk,
|
||||
tp, result.template get<0>(), result.template get<1>());
|
||||
AssignPolicy::apply(tp, pi, qi, result.template get<0>(), result.template get<1>());
|
||||
tp, inters.i_info(), inters.d_info());
|
||||
AssignPolicy::apply(tp, pi, qi, inters.i_info(), inters.d_info());
|
||||
*out++ = tp;
|
||||
}
|
||||
break;
|
||||
@@ -1043,20 +988,20 @@ struct get_turn_info
|
||||
{
|
||||
// Both touch (both arrive there)
|
||||
touch<TurnInfo>::apply(pi, pj, pk, qi, qj, qk,
|
||||
tp, result.template get<0>(), result.template get<1>(), side_calc);
|
||||
AssignPolicy::apply(tp, pi, qi, result.template get<0>(), result.template get<1>());
|
||||
tp, inters.i_info(), inters.d_info(), inters.sides());
|
||||
AssignPolicy::apply(tp, pi, qi, inters.i_info(), inters.d_info());
|
||||
*out++ = tp;
|
||||
}
|
||||
break;
|
||||
case 'e':
|
||||
{
|
||||
if (! result.template get<1>().opposite)
|
||||
if ( ! inters.d_info().opposite )
|
||||
{
|
||||
// Both equal
|
||||
// or collinear-and-ending at intersection point
|
||||
equal<TurnInfo>::apply(pi, pj, pk, qi, qj, qk,
|
||||
tp, result.template get<0>(), result.template get<1>(), side_calc);
|
||||
AssignPolicy::apply(tp, pi, qi, result.template get<0>(), result.template get<1>());
|
||||
tp, inters.i_info(), inters.d_info(), inters.sides());
|
||||
AssignPolicy::apply(tp, pi, qi, inters.i_info(), inters.d_info());
|
||||
*out++ = tp;
|
||||
}
|
||||
else
|
||||
@@ -1066,21 +1011,21 @@ struct get_turn_info
|
||||
TurnInfo,
|
||||
AssignPolicy
|
||||
>::apply(pi, qi,
|
||||
tp, out, result.template get<0>(), result.template get<1>());
|
||||
tp, out, inters.i_info(), inters.d_info());
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 'c' :
|
||||
{
|
||||
// Collinear
|
||||
if (! result.template get<1>().opposite)
|
||||
if ( ! inters.d_info().opposite )
|
||||
{
|
||||
|
||||
if (result.template get<1>().arrival[0] == 0)
|
||||
if ( inters.d_info().arrival[0] == 0 )
|
||||
{
|
||||
// Collinear, but similar thus handled as equal
|
||||
equal<TurnInfo>::apply(pi, pj, pk, qi, qj, qk,
|
||||
tp, result.template get<0>(), result.template get<1>(), side_calc);
|
||||
tp, inters.i_info(), inters.d_info(), inters.sides());
|
||||
|
||||
// override assigned method
|
||||
tp.method = method_collinear;
|
||||
@@ -1088,10 +1033,10 @@ struct get_turn_info
|
||||
else
|
||||
{
|
||||
collinear<TurnInfo>::apply(pi, pj, pk, qi, qj, qk,
|
||||
tp, result.template get<0>(), result.template get<1>(), side_calc);
|
||||
tp, inters.i_info(), inters.d_info(), inters.sides());
|
||||
}
|
||||
|
||||
AssignPolicy::apply(tp, pi, qi, result.template get<0>(), result.template get<1>());
|
||||
AssignPolicy::apply(tp, pi, qi, inters.i_info(), inters.d_info());
|
||||
*out++ = tp;
|
||||
}
|
||||
else
|
||||
@@ -1101,7 +1046,7 @@ struct get_turn_info
|
||||
TurnInfo,
|
||||
AssignPolicy
|
||||
>::apply(pi, pj, pk, qi, qj, qk,
|
||||
tp, out, result.template get<0>(), result.template get<1>(), side_calc);
|
||||
tp, out, inters.i_info(), inters.d_info(), inters.sides());
|
||||
}
|
||||
}
|
||||
break;
|
||||
@@ -1110,8 +1055,8 @@ struct get_turn_info
|
||||
// degenerate points
|
||||
if (AssignPolicy::include_degenerate)
|
||||
{
|
||||
only_convert::apply(tp, result.template get<0>());
|
||||
AssignPolicy::apply(tp, pi, qi, result.template get<0>(), result.template get<1>());
|
||||
only_convert::apply(tp, inters.i_info());
|
||||
AssignPolicy::apply(tp, pi, qi, inters.i_info(), inters.d_info());
|
||||
*out++ = tp;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,177 +15,13 @@
|
||||
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_GET_TURN_INFO_FOR_ENDPOINT_HPP
|
||||
|
||||
#include <boost/geometry/algorithms/detail/overlay/get_turn_info.hpp>
|
||||
#include <boost/geometry/policies/robustness/no_rescale_policy.hpp>
|
||||
|
||||
namespace boost { namespace geometry {
|
||||
|
||||
#ifndef DOXYGEN_NO_DETAIL
|
||||
namespace detail { namespace overlay {
|
||||
|
||||
// TURN_OPERATION
|
||||
|
||||
enum turn_position { position_middle, position_front, position_back };
|
||||
|
||||
template <typename SegmentRatio>
|
||||
struct turn_operation_linear
|
||||
: public turn_operation<SegmentRatio>
|
||||
{
|
||||
turn_operation_linear()
|
||||
: position(position_middle)
|
||||
, is_collinear(false)
|
||||
{}
|
||||
|
||||
turn_position position;
|
||||
bool is_collinear; // valid only for Linear geometry
|
||||
};
|
||||
|
||||
template <typename Point1, typename Point2, typename TurnPoint, typename RobustPolicy>
|
||||
class intersection_info
|
||||
{
|
||||
typedef typename strategy_intersection
|
||||
<
|
||||
typename cs_tag<TurnPoint>::type,
|
||||
Point1,
|
||||
Point2,
|
||||
TurnPoint,
|
||||
RobustPolicy
|
||||
>::segment_intersection_strategy_type strategy;
|
||||
|
||||
public:
|
||||
typedef model::referring_segment<Point1 const> segment_type1;
|
||||
typedef model::referring_segment<Point2 const> segment_type2;
|
||||
typedef side_calculator<Point1, Point2> side_calculator_type;
|
||||
|
||||
typedef typename strategy::return_type result_type;
|
||||
typedef typename boost::tuples::element<0, result_type>::type i_info_type; // intersection_info
|
||||
typedef typename boost::tuples::element<1, result_type>::type d_info_type; // dir_info
|
||||
|
||||
intersection_info(Point1 const& pi, Point1 const& pj, Point1 const& pk,
|
||||
Point2 const& qi, Point2 const& qj, Point2 const& qk,
|
||||
RobustPolicy const& robust_policy)
|
||||
: m_result(strategy::apply(segment_type1(pi, pj),
|
||||
segment_type2(qi, qj),
|
||||
robust_policy))
|
||||
, m_side_calc(pi, pj, pk, qi, qj, qk)
|
||||
, m_robust_policy(robust_policy)
|
||||
{}
|
||||
|
||||
inline Point1 const& pi() const { return m_side_calc.m_pi; }
|
||||
inline Point1 const& pj() const { return m_side_calc.m_pj; }
|
||||
inline Point1 const& pk() const { return m_side_calc.m_pk; }
|
||||
|
||||
inline Point2 const& qi() const { return m_side_calc.m_qi; }
|
||||
inline Point2 const& qj() const { return m_side_calc.m_qj; }
|
||||
inline Point2 const& qk() const { return m_side_calc.m_qk; }
|
||||
|
||||
inline side_calculator_type const& sides() const { return m_side_calc; }
|
||||
inline result_type const& result() const { return m_result; }
|
||||
inline i_info_type const& i_info() const { return m_result.template get<0>(); }
|
||||
inline d_info_type const& d_info() const { return m_result.template get<1>(); }
|
||||
|
||||
// TODO: not it's more like is_spike_ip_p
|
||||
inline bool is_spike_p() const
|
||||
{
|
||||
if ( m_side_calc.pk_wrt_p1() == 0 )
|
||||
{
|
||||
if ( ! is_ip_j<0>() )
|
||||
return false;
|
||||
|
||||
int const qk_p1 = m_side_calc.qk_wrt_p1();
|
||||
int const qk_p2 = m_side_calc.qk_wrt_p2();
|
||||
|
||||
if ( qk_p1 == -qk_p2 )
|
||||
{
|
||||
if ( qk_p1 == 0 )
|
||||
{
|
||||
return is_spike_of_collinear(pi(), pj(), pk());
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// TODO: not it's more like is_spike_ip_q
|
||||
inline bool is_spike_q() const
|
||||
{
|
||||
if ( m_side_calc.qk_wrt_q1() == 0 )
|
||||
{
|
||||
if ( ! is_ip_j<1>() )
|
||||
return false;
|
||||
|
||||
int const pk_q1 = m_side_calc.pk_wrt_q1();
|
||||
int const pk_q2 = m_side_calc.pk_wrt_q2();
|
||||
|
||||
if ( pk_q1 == -pk_q2 )
|
||||
{
|
||||
if ( pk_q1 == 0 )
|
||||
{
|
||||
return is_spike_of_collinear(qi(), qj(), qk());
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private:
|
||||
template <typename Point>
|
||||
inline bool is_spike_of_collinear(Point const& i, Point const& j, Point const& k) const
|
||||
{
|
||||
typedef model::referring_segment<Point const> seg_t;
|
||||
|
||||
typedef strategy_intersection
|
||||
<
|
||||
typename cs_tag<Point>::type, Point, Point, Point, RobustPolicy
|
||||
> si;
|
||||
|
||||
typedef typename si::segment_intersection_strategy_type strategy;
|
||||
|
||||
typename strategy::return_type result
|
||||
= strategy::apply(seg_t(i, j), seg_t(j, k), m_robust_policy);
|
||||
|
||||
return result.template get<0>().count == 2;
|
||||
}
|
||||
|
||||
template <std::size_t OpId>
|
||||
bool is_ip_j() const
|
||||
{
|
||||
int arrival = d_info().arrival[OpId];
|
||||
bool same_dirs = d_info().dir_a == 0 && d_info().dir_b == 0;
|
||||
|
||||
if ( same_dirs )
|
||||
{
|
||||
if ( i_info().count == 2 )
|
||||
{
|
||||
if ( ! d_info().opposite )
|
||||
{
|
||||
return arrival != -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
return arrival != -1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return arrival == 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return arrival == 1;
|
||||
}
|
||||
}
|
||||
|
||||
result_type m_result;
|
||||
side_calculator_type m_side_calc;
|
||||
RobustPolicy const& m_robust_policy;
|
||||
};
|
||||
|
||||
// SEGMENT_INTERSECTION RESULT
|
||||
|
||||
// C H0 H1 A0 A1 O IP1 IP2
|
||||
@@ -485,6 +321,8 @@ struct get_turn_info_for_endpoint
|
||||
if ( append_first || append_last )
|
||||
{
|
||||
bool handled = handle_internal<0>(pi, pj, pk, qi, qj, qk,
|
||||
inters.rpi(), inters.rpj(), inters.rpk(),
|
||||
inters.rqi(), inters.rqj(), inters.rqk(),
|
||||
is_p_first_ip, is_p_last_ip,
|
||||
is_q_first_ip, is_q_last_ip,
|
||||
ip_info.is_qi, ip_info.is_qj,
|
||||
@@ -493,6 +331,8 @@ struct get_turn_info_for_endpoint
|
||||
if ( !handled )
|
||||
{
|
||||
handle_internal<1>(qi, qj, qk, pi, pj, pk,
|
||||
inters.rqi(), inters.rqj(), inters.rqk(),
|
||||
inters.rpi(), inters.rpj(), inters.rpk(),
|
||||
is_q_first_ip, is_q_last_ip,
|
||||
is_p_first_ip, is_p_last_ip,
|
||||
ip_info.is_pi, ip_info.is_pj,
|
||||
@@ -549,11 +389,15 @@ struct get_turn_info_for_endpoint
|
||||
template<std::size_t G1Index,
|
||||
typename Point1,
|
||||
typename Point2,
|
||||
typename RobustPoint1,
|
||||
typename RobustPoint2,
|
||||
typename TurnInfo,
|
||||
typename IntersectionInfo
|
||||
>
|
||||
static inline bool handle_internal(Point1 const& i1, Point1 const& j1, Point1 const& /*k1*/,
|
||||
Point2 const& i2, Point2 const& j2, Point2 const& k2,
|
||||
RobustPoint1 const& ri1, RobustPoint1 const& rj1, RobustPoint1 const& /*rk1*/,
|
||||
RobustPoint2 const& ri2, RobustPoint2 const& rj2, RobustPoint2 const& rk2,
|
||||
bool first1, bool last1, bool first2, bool last2,
|
||||
bool ip_i2, bool ip_j2, TurnInfo const& tp_model,
|
||||
IntersectionInfo const& inters, int ip_index,
|
||||
@@ -582,7 +426,8 @@ struct get_turn_info_for_endpoint
|
||||
}
|
||||
else if ( ip_j2 )
|
||||
{
|
||||
side_calculator<Point1, Point2, Point2> side_calc(i2, i1, j1, i2, j2, k2);
|
||||
side_calculator<RobustPoint1, RobustPoint2, RobustPoint2>
|
||||
side_calc(ri2, ri1, rj1, ri2, rj2, rk2);
|
||||
|
||||
std::pair<operation_type, operation_type>
|
||||
operations = operations_of_equal(side_calc);
|
||||
@@ -632,7 +477,8 @@ struct get_turn_info_for_endpoint
|
||||
}
|
||||
else if ( ip_j2 )
|
||||
{
|
||||
side_calculator<Point1, Point2, Point2> side_calc(i2, j1, i1, i2, j2, k2);
|
||||
side_calculator<RobustPoint1, RobustPoint2, RobustPoint2>
|
||||
side_calc(ri2, rj1, ri1, ri2, rj2, rk2);
|
||||
|
||||
std::pair<operation_type, operation_type>
|
||||
operations = operations_of_equal(side_calc);
|
||||
|
||||
@@ -0,0 +1,336 @@
|
||||
// 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_OVERLAY_GET_TURN_INFO_HELPERS_HPP
|
||||
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_GET_TURN_INFO_HELPERS_HPP
|
||||
|
||||
#include <boost/geometry/policies/robustness/no_rescale_policy.hpp>
|
||||
|
||||
namespace boost { namespace geometry {
|
||||
|
||||
#ifndef DOXYGEN_NO_DETAIL
|
||||
namespace detail { namespace overlay {
|
||||
|
||||
enum turn_position { position_middle, position_front, position_back };
|
||||
|
||||
template <typename SegmentRatio>
|
||||
struct turn_operation_linear
|
||||
: public turn_operation<SegmentRatio>
|
||||
{
|
||||
turn_operation_linear()
|
||||
: position(position_middle)
|
||||
, is_collinear(false)
|
||||
{}
|
||||
|
||||
turn_position position;
|
||||
bool is_collinear; // valid only for Linear geometry
|
||||
};
|
||||
|
||||
template <typename PointP, typename PointQ,
|
||||
typename Pi = PointP, typename Pj = PointP, typename Pk = PointP,
|
||||
typename Qi = PointQ, typename Qj = PointQ, typename Qk = PointQ
|
||||
>
|
||||
struct side_calculator
|
||||
{
|
||||
typedef boost::geometry::strategy::side::side_by_triangle<> side; // todo: get from coordinate system
|
||||
|
||||
inline side_calculator(Pi const& pi, Pj const& pj, Pk const& pk,
|
||||
Qi const& qi, Qj const& qj, Qk const& qk)
|
||||
: m_pi(pi), m_pj(pj), m_pk(pk)
|
||||
, m_qi(qi), m_qj(qj), m_qk(qk)
|
||||
{}
|
||||
|
||||
inline int pk_wrt_p1() const { return side::apply(m_pi, m_pj, m_pk); }
|
||||
inline int pk_wrt_q1() const { return side::apply(m_qi, m_qj, m_pk); }
|
||||
inline int qk_wrt_p1() const { return side::apply(m_pi, m_pj, m_qk); }
|
||||
inline int qk_wrt_q1() const { return side::apply(m_qi, m_qj, m_qk); }
|
||||
|
||||
inline int pk_wrt_q2() const { return side::apply(m_qj, m_qk, m_pk); }
|
||||
inline int qk_wrt_p2() const { return side::apply(m_pj, m_pk, m_qk); }
|
||||
|
||||
Pi const& m_pi;
|
||||
Pj const& m_pj;
|
||||
Pk const& m_pk;
|
||||
Qi const& m_qi;
|
||||
Qj const& m_qj;
|
||||
Qk const& m_qk;
|
||||
};
|
||||
|
||||
template <typename Point1, typename Point2, typename RobustPolicy>
|
||||
struct robust_points
|
||||
{
|
||||
typedef typename geometry::robust_point_type
|
||||
<
|
||||
Point1, RobustPolicy
|
||||
>::type robust_point1_type;
|
||||
// TODO: define robust_point2_type using Point2?
|
||||
typedef robust_point1_type robust_point2_type;
|
||||
|
||||
inline robust_points(Point1 const& pi, Point1 const& pj, Point1 const& pk,
|
||||
Point2 const& qi, Point2 const& qj, Point2 const& qk,
|
||||
RobustPolicy const& robust_policy)
|
||||
{
|
||||
geometry::recalculate(m_rpi, pi, robust_policy);
|
||||
geometry::recalculate(m_rpj, pj, robust_policy);
|
||||
geometry::recalculate(m_rpk, pk, robust_policy);
|
||||
geometry::recalculate(m_rqi, qi, robust_policy);
|
||||
geometry::recalculate(m_rqj, qj, robust_policy);
|
||||
geometry::recalculate(m_rqk, qk, robust_policy);
|
||||
}
|
||||
|
||||
robust_point1_type m_rpi, m_rpj, m_rpk;
|
||||
robust_point2_type m_rqi, m_rqj, m_rqk;
|
||||
};
|
||||
|
||||
template <typename Point1, typename Point2, typename RobustPolicy>
|
||||
class intersection_info_base
|
||||
: private robust_points<Point1, Point2, RobustPolicy>
|
||||
{
|
||||
typedef robust_points<Point1, Point2, RobustPolicy> base_t;
|
||||
|
||||
public:
|
||||
typedef Point1 point1_type;
|
||||
typedef Point2 point2_type;
|
||||
|
||||
typedef typename base_t::robust_point1_type robust_point1_type;
|
||||
typedef typename base_t::robust_point2_type robust_point2_type;
|
||||
|
||||
typedef side_calculator<robust_point1_type, robust_point2_type> side_calculator_type;
|
||||
|
||||
intersection_info_base(Point1 const& pi, Point1 const& pj, Point1 const& pk,
|
||||
Point2 const& qi, Point2 const& qj, Point2 const& qk,
|
||||
RobustPolicy const& robust_policy)
|
||||
: base_t(pi, pj, pk, qi, qj, qk, robust_policy)
|
||||
, m_side_calc(base_t::m_rpi, base_t::m_rpj, base_t::m_rpk,
|
||||
base_t::m_rqi, base_t::m_rqj, base_t::m_rqk)
|
||||
, m_pi(pi), m_pj(pj), m_pk(pk)
|
||||
, m_qi(qi), m_qj(qj), m_qk(qk)
|
||||
{}
|
||||
|
||||
inline Point1 const& pi() const { return m_pi; }
|
||||
inline Point1 const& pj() const { return m_pj; }
|
||||
inline Point1 const& pk() const { return m_pk; }
|
||||
|
||||
inline Point2 const& qi() const { return m_qi; }
|
||||
inline Point2 const& qj() const { return m_qj; }
|
||||
inline Point2 const& qk() const { return m_qk; }
|
||||
|
||||
inline robust_point1_type const& rpi() const { return base_t::m_rpi; }
|
||||
inline robust_point1_type const& rpj() const { return base_t::m_rpj; }
|
||||
inline robust_point1_type const& rpk() const { return base_t::m_rpk; }
|
||||
|
||||
inline robust_point2_type const& rqi() const { return base_t::m_rqi; }
|
||||
inline robust_point2_type const& rqj() const { return base_t::m_rqj; }
|
||||
inline robust_point2_type const& rqk() const { return base_t::m_rqk; }
|
||||
|
||||
inline side_calculator_type const& sides() const { return m_side_calc; }
|
||||
|
||||
private:
|
||||
side_calculator_type m_side_calc;
|
||||
|
||||
point1_type const& m_pi;
|
||||
point1_type const& m_pj;
|
||||
point1_type const& m_pk;
|
||||
point2_type const& m_qi;
|
||||
point2_type const& m_qj;
|
||||
point2_type const& m_qk;
|
||||
};
|
||||
|
||||
template <typename Point1, typename Point2>
|
||||
class intersection_info_base<Point1, Point2, detail::no_rescale_policy>
|
||||
{
|
||||
public:
|
||||
typedef Point1 point1_type;
|
||||
typedef Point2 point2_type;
|
||||
|
||||
typedef Point1 robust_point1_type;
|
||||
typedef Point2 robust_point2_type;
|
||||
|
||||
typedef side_calculator<Point1, Point2> side_calculator_type;
|
||||
|
||||
intersection_info_base(Point1 const& pi, Point1 const& pj, Point1 const& pk,
|
||||
Point2 const& qi, Point2 const& qj, Point2 const& qk,
|
||||
no_rescale_policy const& robust_policy)
|
||||
: m_side_calc(pi, pj, pk, qi, qj, qk)
|
||||
{}
|
||||
|
||||
inline Point1 const& pi() const { return m_side_calc.m_pi; }
|
||||
inline Point1 const& pj() const { return m_side_calc.m_pj; }
|
||||
inline Point1 const& pk() const { return m_side_calc.m_pk; }
|
||||
|
||||
inline Point2 const& qi() const { return m_side_calc.m_qi; }
|
||||
inline Point2 const& qj() const { return m_side_calc.m_qj; }
|
||||
inline Point2 const& qk() const { return m_side_calc.m_qk; }
|
||||
|
||||
inline Point1 const& rpi() const { return pi(); }
|
||||
inline Point1 const& rpj() const { return pj(); }
|
||||
inline Point1 const& rpk() const { return pk(); }
|
||||
|
||||
inline Point2 const& rqi() const { return qi(); }
|
||||
inline Point2 const& rqj() const { return qj(); }
|
||||
inline Point2 const& rqk() const { return qk(); }
|
||||
|
||||
inline side_calculator_type const& sides() const { return m_side_calc; }
|
||||
|
||||
private:
|
||||
side_calculator_type m_side_calc;
|
||||
};
|
||||
|
||||
|
||||
template <typename Point1, typename Point2, typename TurnPoint, typename RobustPolicy>
|
||||
class intersection_info
|
||||
: public intersection_info_base<Point1, Point2, RobustPolicy>
|
||||
{
|
||||
typedef intersection_info_base<Point1, Point2, RobustPolicy> base_t;
|
||||
|
||||
typedef typename strategy_intersection
|
||||
<
|
||||
typename cs_tag<TurnPoint>::type,
|
||||
Point1,
|
||||
Point2,
|
||||
TurnPoint,
|
||||
RobustPolicy
|
||||
>::segment_intersection_strategy_type strategy;
|
||||
|
||||
public:
|
||||
typedef model::referring_segment<Point1 const> segment_type1;
|
||||
typedef model::referring_segment<Point2 const> segment_type2;
|
||||
typedef typename base_t::side_calculator_type side_calculator_type;
|
||||
|
||||
typedef typename strategy::return_type result_type;
|
||||
typedef typename boost::tuples::element<0, result_type>::type i_info_type; // intersection_info
|
||||
typedef typename boost::tuples::element<1, result_type>::type d_info_type; // dir_info
|
||||
|
||||
intersection_info(Point1 const& pi, Point1 const& pj, Point1 const& pk,
|
||||
Point2 const& qi, Point2 const& qj, Point2 const& qk,
|
||||
RobustPolicy const& robust_policy)
|
||||
: base_t(pi, pj, pk, qi, qj, qk, robust_policy)
|
||||
, m_result(strategy::apply(segment_type1(pi, pj),
|
||||
segment_type2(qi, qj),
|
||||
robust_policy))
|
||||
, m_robust_policy(robust_policy)
|
||||
{}
|
||||
|
||||
inline result_type const& result() const { return m_result; }
|
||||
inline i_info_type const& i_info() const { return m_result.template get<0>(); }
|
||||
inline d_info_type const& d_info() const { return m_result.template get<1>(); }
|
||||
|
||||
// TODO: it's more like is_spike_ip_p
|
||||
inline bool is_spike_p() const
|
||||
{
|
||||
if ( base_t::sides().pk_wrt_p1() == 0 )
|
||||
{
|
||||
if ( ! is_ip_j<0>() )
|
||||
return false;
|
||||
|
||||
int const qk_p1 = base_t::sides().qk_wrt_p1();
|
||||
int const qk_p2 = base_t::sides().qk_wrt_p2();
|
||||
|
||||
if ( qk_p1 == -qk_p2 )
|
||||
{
|
||||
if ( qk_p1 == 0 )
|
||||
{
|
||||
return is_spike_of_collinear(base_t::pi(), base_t::pj(), base_t::pk());
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// TODO: it's more like is_spike_ip_q
|
||||
inline bool is_spike_q() const
|
||||
{
|
||||
if ( base_t::sides().qk_wrt_q1() == 0 )
|
||||
{
|
||||
if ( ! is_ip_j<1>() )
|
||||
return false;
|
||||
|
||||
int const pk_q1 = base_t::sides().pk_wrt_q1();
|
||||
int const pk_q2 = base_t::sides().pk_wrt_q2();
|
||||
|
||||
if ( pk_q1 == -pk_q2 )
|
||||
{
|
||||
if ( pk_q1 == 0 )
|
||||
{
|
||||
return is_spike_of_collinear(base_t::qi(), base_t::qj(), base_t::qk());
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private:
|
||||
template <typename Point>
|
||||
inline bool is_spike_of_collinear(Point const& i, Point const& j, Point const& k) const
|
||||
{
|
||||
typedef model::referring_segment<Point const> seg_t;
|
||||
|
||||
typedef strategy_intersection
|
||||
<
|
||||
typename cs_tag<Point>::type, Point, Point, Point, RobustPolicy
|
||||
> si;
|
||||
|
||||
typedef typename si::segment_intersection_strategy_type strategy;
|
||||
|
||||
typename strategy::return_type result
|
||||
= strategy::apply(seg_t(i, j), seg_t(j, k), m_robust_policy);
|
||||
|
||||
return result.template get<0>().count == 2;
|
||||
}
|
||||
|
||||
template <std::size_t OpId>
|
||||
bool is_ip_j() const
|
||||
{
|
||||
int arrival = d_info().arrival[OpId];
|
||||
bool same_dirs = d_info().dir_a == 0 && d_info().dir_b == 0;
|
||||
|
||||
if ( same_dirs )
|
||||
{
|
||||
if ( i_info().count == 2 )
|
||||
{
|
||||
if ( ! d_info().opposite )
|
||||
{
|
||||
return arrival != -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
return arrival != -1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return arrival == 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return arrival == 1;
|
||||
}
|
||||
}
|
||||
|
||||
result_type m_result;
|
||||
RobustPolicy const& m_robust_policy;
|
||||
};
|
||||
|
||||
}} // namespace detail::overlay
|
||||
#endif // DOXYGEN_NO_DETAIL
|
||||
|
||||
}} // namespace boost::geometry
|
||||
|
||||
#endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_GET_TURN_INFO_HELPERS_HPP
|
||||
@@ -47,8 +47,10 @@ struct get_turn_info_linear_areal
|
||||
RobustPolicy const& robust_policy,
|
||||
OutputIterator out)
|
||||
{
|
||||
intersection_info<Point1, Point2, typename TurnInfo::point_type, RobustPolicy>
|
||||
inters(pi, pj, pk, qi, qj, qk, robust_policy);
|
||||
typedef intersection_info<Point1, Point2, typename TurnInfo::point_type, RobustPolicy>
|
||||
inters_info;
|
||||
|
||||
inters_info inters(pi, pj, pk, qi, qj, qk, robust_policy);
|
||||
|
||||
char const method = inters.d_info().how;
|
||||
|
||||
@@ -64,7 +66,7 @@ struct get_turn_info_linear_areal
|
||||
get_turn_info_for_endpoint<true, true>(
|
||||
pi, pj, pk, qi, qj, qk,
|
||||
is_p_first, is_p_last, is_q_first, is_q_last,
|
||||
tp_model, inters.result(), method_none, out);
|
||||
tp_model, inters, method_none, out);
|
||||
break;
|
||||
|
||||
case 'd' : // disjoint: never do anything
|
||||
@@ -75,7 +77,7 @@ struct get_turn_info_linear_areal
|
||||
if ( get_turn_info_for_endpoint<false, true>(
|
||||
pi, pj, pk, qi, qj, qk,
|
||||
is_p_first, is_p_last, is_q_first, is_q_last,
|
||||
tp_model, inters.result(), method_touch_interior, out) )
|
||||
tp_model, inters, method_touch_interior, out) )
|
||||
{
|
||||
// do nothing
|
||||
}
|
||||
@@ -96,7 +98,12 @@ struct get_turn_info_linear_areal
|
||||
else
|
||||
{
|
||||
// Swap p/q
|
||||
side_calculator<Point2, Point1> swapped_side_calc(qi, qj, qk, pi, pj, pk);
|
||||
side_calculator
|
||||
<
|
||||
typename inters_info::robust_point2_type,
|
||||
typename inters_info::robust_point1_type
|
||||
> swapped_side_calc(inters.rqi(), inters.rqj(), inters.rqk(),
|
||||
inters.rpi(), inters.rpj(), inters.rpk());
|
||||
policy::template apply<1>(qi, qj, qk, pi, pj, pk,
|
||||
tp, inters.i_info(), inters.d_info(),
|
||||
swapped_side_calc);
|
||||
@@ -138,7 +145,7 @@ struct get_turn_info_linear_areal
|
||||
if ( get_turn_info_for_endpoint<false, true>(
|
||||
pi, pj, pk, qi, qj, qk,
|
||||
is_p_first, is_p_last, is_q_first, is_q_last,
|
||||
tp_model, inters.result(), method_touch, out) )
|
||||
tp_model, inters, method_touch, out) )
|
||||
{
|
||||
// do nothing
|
||||
}
|
||||
@@ -230,7 +237,7 @@ struct get_turn_info_linear_areal
|
||||
if ( get_turn_info_for_endpoint<true, true>(
|
||||
pi, pj, pk, qi, qj, qk,
|
||||
is_p_first, is_p_last, is_q_first, is_q_last,
|
||||
tp_model, inters.result(), method_equal, out) )
|
||||
tp_model, inters, method_equal, out) )
|
||||
{
|
||||
// do nothing
|
||||
}
|
||||
@@ -277,7 +284,7 @@ struct get_turn_info_linear_areal
|
||||
if ( get_turn_info_for_endpoint<true, true>(
|
||||
pi, pj, pk, qi, qj, qk,
|
||||
is_p_first, is_p_last, is_q_first, is_q_last,
|
||||
tp_model, inters.result(), method_collinear, out) )
|
||||
tp_model, inters, method_collinear, out) )
|
||||
{
|
||||
// do nothing
|
||||
}
|
||||
@@ -621,7 +628,7 @@ struct get_turn_info_linear_areal
|
||||
typename Point1,
|
||||
typename Point2,
|
||||
typename TurnInfo,
|
||||
typename IntersectionResult,
|
||||
typename IntersectionInfo,
|
||||
typename OutputIterator>
|
||||
static inline bool get_turn_info_for_endpoint(
|
||||
Point1 const& pi, Point1 const& pj, Point1 const& pk,
|
||||
@@ -629,14 +636,14 @@ struct get_turn_info_linear_areal
|
||||
bool is_p_first, bool is_p_last,
|
||||
bool is_q_first, bool is_q_last,
|
||||
TurnInfo const& tp_model,
|
||||
IntersectionResult const& result,
|
||||
IntersectionInfo const& inters,
|
||||
method_type /*method*/,
|
||||
OutputIterator out)
|
||||
{
|
||||
namespace ov = overlay;
|
||||
typedef ov::get_turn_info_for_endpoint<AssignPolicy, EnableFirst, EnableLast> get_info_e;
|
||||
|
||||
const std::size_t ip_count = result.template get<0>().count;
|
||||
const std::size_t ip_count = inters.i_info().count;
|
||||
// no intersection points
|
||||
if ( ip_count == 0 )
|
||||
return false;
|
||||
@@ -648,11 +655,11 @@ struct get_turn_info_linear_areal
|
||||
if ( !is_p_first && !is_p_last )
|
||||
return false;
|
||||
|
||||
linear_intersections intersections(pi, qi, result, is_p_last, is_q_last);
|
||||
linear_intersections intersections(pi, qi, inters.result(), is_p_last, is_q_last);
|
||||
linear_intersections::ip_info const& ip0 = intersections.template get<0>();
|
||||
linear_intersections::ip_info const& ip1 = intersections.template get<1>();
|
||||
|
||||
const bool opposite = result.template get<1>().opposite;
|
||||
const bool opposite = inters.d_info().opposite;
|
||||
|
||||
// ANALYSE AND ASSIGN FIRST
|
||||
|
||||
@@ -675,7 +682,13 @@ struct get_turn_info_linear_areal
|
||||
|
||||
if ( ip0.is_qj )
|
||||
{
|
||||
side_calculator<Point1, Point2, Point2> side_calc(qi, pi, pj, qi, qj, qk);
|
||||
side_calculator
|
||||
<
|
||||
typename IntersectionInfo::robust_point1_type,
|
||||
typename IntersectionInfo::robust_point2_type,
|
||||
typename IntersectionInfo::robust_point2_type
|
||||
> side_calc(inters.rqi(), inters.rpi(), inters.rpj(),
|
||||
inters.rqi(), inters.rqj(), inters.rqk());
|
||||
|
||||
std::pair<operation_type, operation_type>
|
||||
operations = get_info_e::operations_of_equal(side_calc);
|
||||
@@ -687,9 +700,18 @@ struct get_turn_info_linear_areal
|
||||
}
|
||||
else
|
||||
{
|
||||
side_calculator<Point1, Point2,
|
||||
Point2, Point1, Point1,
|
||||
Point2, Point1, Point2> side_calc(qi, pi, pj, qi, pi, qj);
|
||||
side_calculator
|
||||
<
|
||||
typename IntersectionInfo::robust_point1_type,
|
||||
typename IntersectionInfo::robust_point2_type,
|
||||
typename IntersectionInfo::robust_point2_type,
|
||||
typename IntersectionInfo::robust_point1_type,
|
||||
typename IntersectionInfo::robust_point1_type,
|
||||
typename IntersectionInfo::robust_point2_type,
|
||||
typename IntersectionInfo::robust_point1_type,
|
||||
typename IntersectionInfo::robust_point2_type
|
||||
> side_calc(inters.rqi(), inters.rpi(), inters.rpj(),
|
||||
inters.rqi(), inters.rpi(), inters.rqj());
|
||||
|
||||
std::pair<operation_type, operation_type>
|
||||
operations = get_info_e::operations_of_equal(side_calc);
|
||||
@@ -704,17 +726,17 @@ struct get_turn_info_linear_areal
|
||||
|
||||
// equals<> or collinear<> will assign the second point,
|
||||
// we'd like to assign the first one
|
||||
base_turn_handler::assign_point(tp, tp.method, result.template get<0>(), 0);
|
||||
base_turn_handler::assign_point(tp, tp.method, inters.i_info(), 0);
|
||||
|
||||
// NOTE: not really needed especially for the first point
|
||||
// for which there is no preceding segment (but consistent with the L/L)
|
||||
if ( result.template get<0>().count > 1 )
|
||||
if ( inters.i_info().count > 1 )
|
||||
{
|
||||
//BOOST_ASSERT( result.template get<1>().dir_a == 0 && result.template get<1>().dir_b == 0 );
|
||||
tp.operations[0].is_collinear = true;
|
||||
}
|
||||
|
||||
AssignPolicy::apply(tp, pi, qi, result.template get<0>(), result.template get<1>());
|
||||
AssignPolicy::apply(tp, pi, qi, inters.i_info(), inters.d_info());
|
||||
*out++ = tp;
|
||||
}
|
||||
|
||||
@@ -727,7 +749,7 @@ struct get_turn_info_linear_areal
|
||||
{
|
||||
TurnInfo tp = tp_model;
|
||||
|
||||
if ( result.template get<0>().count > 1 )
|
||||
if ( inters.i_info().count > 1 )
|
||||
{
|
||||
//BOOST_ASSERT( result.template get<1>().dir_a == 0 && result.template get<1>().dir_b == 0 );
|
||||
tp.operations[0].is_collinear = true;
|
||||
@@ -735,7 +757,13 @@ struct get_turn_info_linear_areal
|
||||
}
|
||||
else //if ( result.template get<0>().count == 1 )
|
||||
{
|
||||
side_calculator<Point1, Point2, Point2> side_calc(qi, pj, pi, qi, qj, qk);
|
||||
side_calculator
|
||||
<
|
||||
typename IntersectionInfo::robust_point1_type,
|
||||
typename IntersectionInfo::robust_point2_type,
|
||||
typename IntersectionInfo::robust_point2_type
|
||||
> side_calc(inters.rqi(), inters.rpj(), inters.rpi(),
|
||||
inters.rqi(), inters.rqj(), inters.rqk());
|
||||
|
||||
std::pair<operation_type, operation_type>
|
||||
operations = get_info_e::operations_of_equal(side_calc);
|
||||
@@ -760,9 +788,9 @@ struct get_turn_info_linear_areal
|
||||
// equals<> or collinear<> will assign the second point,
|
||||
// we'd like to assign the first one
|
||||
std::size_t ip_index = ip_count > 1 ? 1 : 0;
|
||||
base_turn_handler::assign_point(tp, tp.method, result.template get<0>(), ip_index);
|
||||
base_turn_handler::assign_point(tp, tp.method, inters.i_info(), ip_index);
|
||||
|
||||
AssignPolicy::apply(tp, pi, qi, result.template get<0>(), result.template get<1>());
|
||||
AssignPolicy::apply(tp, pi, qi, inters.i_info(), inters.d_info());
|
||||
*out++ = tp;
|
||||
|
||||
return true;
|
||||
|
||||
@@ -44,8 +44,10 @@ struct get_turn_info_linear_linear
|
||||
RobustPolicy const& robust_policy,
|
||||
OutputIterator out)
|
||||
{
|
||||
intersection_info<Point1, Point2, typename TurnInfo::point_type, RobustPolicy>
|
||||
inters(pi, pj, pk, qi, qj, qk, robust_policy);
|
||||
typedef intersection_info<Point1, Point2, typename TurnInfo::point_type, RobustPolicy>
|
||||
inters_info;
|
||||
|
||||
inters_info inters(pi, pj, pk, qi, qj, qk, robust_policy);
|
||||
|
||||
char const method = inters.d_info().how;
|
||||
|
||||
@@ -93,7 +95,13 @@ struct get_turn_info_linear_linear
|
||||
else
|
||||
{
|
||||
// Swap p/q
|
||||
side_calculator<Point2, Point1> swapped_side_calc(qi, qj, qk, pi, pj, pk);
|
||||
side_calculator
|
||||
<
|
||||
typename inters_info::robust_point2_type,
|
||||
typename inters_info::robust_point1_type
|
||||
> swapped_side_calc(inters.rqi(), inters.rqj(), inters.rqk(),
|
||||
inters.rpi(), inters.rpj(), inters.rpk());
|
||||
|
||||
policy::template apply<1>(qi, qj, qk, pi, pj, pk,
|
||||
tp, inters.i_info(), inters.d_info(),
|
||||
swapped_side_calc);
|
||||
|
||||
Reference in New Issue
Block a user