mirror of
https://github.com/boostorg/geometry.git
synced 2026-02-01 08:32:10 +00:00
added generation of IP for the first point of a Linestring - c+c/c, c+i/u or c+u/i
This commit is contained in:
@@ -14,13 +14,18 @@
|
||||
|
||||
#include <boost/geometry/strategies/distance.hpp>
|
||||
#include <boost/geometry/algorithms/detail/overlay/get_turns.hpp>
|
||||
#include <boost/geometry/algorithms/detail/overlay/get_turn_info.hpp>
|
||||
#include <boost/geometry/algorithms/detail/overlay/calculate_distance_policy.hpp>
|
||||
|
||||
#include <boost/type_traits/is_base_of.hpp>
|
||||
|
||||
namespace boost { namespace geometry {
|
||||
|
||||
#ifndef DOXYGEN_NO_DETAIL
|
||||
namespace detail { namespace relate { namespace turns {
|
||||
|
||||
// TURN_INFO
|
||||
|
||||
template<typename P>
|
||||
struct distance_info
|
||||
{
|
||||
@@ -50,7 +55,285 @@ struct turn_operation_with_distance : public overlay::turn_operation
|
||||
distance_info<P> enriched;
|
||||
};
|
||||
|
||||
template <typename Geometry1, typename Geometry2>
|
||||
// GET_TURN_INFO
|
||||
|
||||
template<typename AssignPolicy>
|
||||
struct get_turn_info_linear_linear
|
||||
{
|
||||
template
|
||||
<
|
||||
typename Point1,
|
||||
typename Point2,
|
||||
typename TurnInfo,
|
||||
typename RescalePolicy,
|
||||
typename OutputIterator
|
||||
>
|
||||
static inline OutputIterator apply(
|
||||
Point1 const& pi, Point1 const& pj, Point1 const& pk,
|
||||
Point2 const& qi, Point2 const& qj, Point2 const& qk,
|
||||
TurnInfo const& tp_model,
|
||||
RescalePolicy const& , // TODO: this will be used. rescale_policy,
|
||||
OutputIterator out)
|
||||
{
|
||||
typedef model::referring_segment<Point1 const> segment_type1;
|
||||
typedef model::referring_segment<Point2 const> segment_type2;
|
||||
segment_type1 p1(pi, pj), p2(pj, pk);
|
||||
segment_type2 q1(qi, qj), q2(qj, qk);
|
||||
|
||||
overlay::side_calculator<Point1, Point2> side_calc(pi, pj, pk, qi, qj, qk);
|
||||
|
||||
typedef strategy_intersection
|
||||
<
|
||||
typename cs_tag<typename TurnInfo::point_type>::type,
|
||||
Point1,
|
||||
Point2,
|
||||
typename TurnInfo::point_type
|
||||
> si;
|
||||
|
||||
typedef typename si::segment_intersection_strategy_type strategy;
|
||||
|
||||
typename strategy::return_type result = strategy::apply(p1, q1);
|
||||
|
||||
char const method = result.template get<1>().how;
|
||||
|
||||
// Copy, to copy possibly extended fields
|
||||
TurnInfo tp = tp_model;
|
||||
|
||||
// Select method and apply
|
||||
switch(method)
|
||||
{
|
||||
case 'a' : // collinear, "at"
|
||||
case 'f' : // collinear, "from"
|
||||
case 's' : // starts from the middle
|
||||
handle_first(pi, pj, pk, qi, qj, qk, tp_model, result, out);
|
||||
break;
|
||||
|
||||
case 'd' : // disjoint: never do anything
|
||||
break;
|
||||
|
||||
case 'm' :
|
||||
{
|
||||
typedef overlay::touch_interior
|
||||
<
|
||||
TurnInfo
|
||||
> policy;
|
||||
|
||||
// If Q (1) arrives (1)
|
||||
if (result.template get<1>().arrival[1] == 1)
|
||||
{
|
||||
policy::template apply<0>(pi, pj, pk, qi, qj, qk,
|
||||
tp, result.template get<0>(), result.template get<1>(),
|
||||
side_calc);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Swap p/q
|
||||
overlay::side_calculator<Point1, Point2> swapped_side_calc(qi, qj, qk, pi, pj, pk);
|
||||
policy::template apply<1>(qi, qj, qk, pi, pj, pk,
|
||||
tp, result.template get<0>(), result.template get<1>(),
|
||||
swapped_side_calc);
|
||||
}
|
||||
AssignPolicy::apply(tp, pi, qi, result.template get<0>(), result.template get<1>());
|
||||
*out++ = tp;
|
||||
}
|
||||
break;
|
||||
case 'i' :
|
||||
{
|
||||
overlay::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>());
|
||||
*out++ = tp;
|
||||
}
|
||||
break;
|
||||
case 't' :
|
||||
{
|
||||
// Both touch (both arrive there)
|
||||
overlay::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>());
|
||||
*out++ = tp;
|
||||
}
|
||||
break;
|
||||
case 'e':
|
||||
{
|
||||
handle_first(pi, pj, pk, qi, qj, qk, tp_model, result, out);
|
||||
|
||||
if (! result.template get<1>().opposite)
|
||||
{
|
||||
// Both equal
|
||||
// or collinear-and-ending at intersection point
|
||||
overlay::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>());
|
||||
*out++ = tp;
|
||||
}
|
||||
else
|
||||
{
|
||||
overlay::equal_opposite
|
||||
<
|
||||
TurnInfo,
|
||||
AssignPolicy
|
||||
>::apply(pi, qi,
|
||||
tp, out, result.template get<0>(), result.template get<1>());
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 'c' :
|
||||
{
|
||||
handle_first(pi, pj, pk, qi, qj, qk, tp_model, result, out);
|
||||
|
||||
// Collinear
|
||||
if (! result.template get<1>().opposite)
|
||||
{
|
||||
|
||||
if (result.template get<1>().arrival[0] == 0)
|
||||
{
|
||||
// Collinear, but similar thus handled as equal
|
||||
overlay::equal<TurnInfo>::apply(pi, pj, pk, qi, qj, qk,
|
||||
tp, result.template get<0>(), result.template get<1>(), side_calc);
|
||||
|
||||
// override assigned method
|
||||
tp.method = overlay::method_collinear;
|
||||
}
|
||||
else
|
||||
{
|
||||
overlay::collinear<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>());
|
||||
*out++ = tp;
|
||||
}
|
||||
else
|
||||
{
|
||||
overlay::collinear_opposite
|
||||
<
|
||||
TurnInfo,
|
||||
AssignPolicy
|
||||
>::apply(pi, pj, pk, qi, qj, qk,
|
||||
tp, out, result.template get<0>(), result.template get<1>(), side_calc);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case '0' :
|
||||
{
|
||||
// degenerate points
|
||||
if (AssignPolicy::include_degenerate)
|
||||
{
|
||||
overlay::only_convert<TurnInfo>::apply(tp, result.template get<0>());
|
||||
AssignPolicy::apply(tp, pi, qi, result.template get<0>(), result.template get<1>());
|
||||
*out++ = tp;
|
||||
}
|
||||
}
|
||||
break;
|
||||
default :
|
||||
{
|
||||
#if defined(BOOST_GEOMETRY_DEBUG_ROBUSTNESS)
|
||||
std::cout << "TURN: Unknown method: " << method << std::endl;
|
||||
#endif
|
||||
#if ! defined(BOOST_GEOMETRY_OVERLAY_NO_THROW)
|
||||
throw turn_info_exception(method);
|
||||
#endif
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
template
|
||||
<
|
||||
typename Point1,
|
||||
typename Point2,
|
||||
typename TurnInfo,
|
||||
typename IntersectionResult,
|
||||
typename OutputIterator
|
||||
>
|
||||
static inline void handle_first(Point1 const& pi, Point1 const& pj, Point1 const& pk,
|
||||
Point2 const& qi, Point2 const& qj, Point2 const& qk,
|
||||
TurnInfo const& tp_model,
|
||||
IntersectionResult const& result,
|
||||
OutputIterator out)
|
||||
{
|
||||
bool has_intersections = result.template get<0>().count > 0;
|
||||
if ( !has_intersections )
|
||||
return;
|
||||
|
||||
bool is_p_first_ip = tp_model.operations[0].seg_id.segment_index == 0
|
||||
&& equals::equals_point_point(pi, result.template get<0>().intersections[0]);
|
||||
bool is_q_first_ip = tp_model.operations[1].seg_id.segment_index == 0
|
||||
&& equals::equals_point_point(qi, result.template get<0>().intersections[0]);
|
||||
|
||||
bool should_handle = has_intersections && ( is_p_first_ip || is_q_first_ip );
|
||||
|
||||
if ( !should_handle )
|
||||
return;
|
||||
|
||||
TurnInfo tp = tp_model;
|
||||
|
||||
overlay::side_calculator<Point1, Point2> side_calc(pi, pi, pj, qi, qi, qj);
|
||||
|
||||
// FROM SWITCH FOR COLINEAR
|
||||
if (result.template get<1>().arrival[0] == 0)
|
||||
{
|
||||
// Collinear, but similar thus handled as equal
|
||||
overlay::equal<TurnInfo>::apply(pi, pi, pj, qi, qi, qj,
|
||||
tp, result.template get<0>(), result.template get<1>(), side_calc);
|
||||
|
||||
// override assigned method
|
||||
tp.method = overlay::method_collinear;
|
||||
}
|
||||
else
|
||||
{
|
||||
overlay::collinear<TurnInfo>::apply(pi, pi, pj, qi, qi, qj,
|
||||
tp, result.template get<0>(), result.template get<1>(), side_calc);
|
||||
}
|
||||
|
||||
geometry::convert(result.template get<0>().intersections[0], tp.point);
|
||||
|
||||
AssignPolicy::apply(tp, pi, qi, result.template get<0>(), result.template get<1>());
|
||||
*out++ = tp;
|
||||
}
|
||||
};
|
||||
|
||||
// GET_TURN_INFO_TYPE
|
||||
|
||||
template <typename Tag,
|
||||
bool IsLinear = boost::is_base_of<linear_tag, Tag>::value,
|
||||
bool IsAreal = boost::is_base_of<areal_tag, Tag>::value>
|
||||
struct tag_base : not_implemented<Tag>
|
||||
{};
|
||||
|
||||
template <typename Tag>
|
||||
struct tag_base<Tag, true, false>
|
||||
{
|
||||
typedef linear_tag type;
|
||||
};
|
||||
|
||||
template <typename Tag>
|
||||
struct tag_base<Tag, false, true>
|
||||
{
|
||||
typedef areal_tag type;
|
||||
};
|
||||
|
||||
template <typename Geometry1, typename Geometry2, typename AssignPolicy = overlay::calculate_distance_policy,
|
||||
typename Tag1 = typename tag<Geometry1>::type, typename Tag2 = typename tag<Geometry2>::type,
|
||||
typename TagBase1 = typename tag_base<Tag1>::type, typename TagBase2 = typename tag_base<Tag2>::type>
|
||||
struct get_turn_info
|
||||
: overlay::get_turn_info<AssignPolicy>
|
||||
{};
|
||||
|
||||
template <typename Geometry1, typename Geometry2, typename AssignPolicy, typename Tag1, typename Tag2>
|
||||
struct get_turn_info<Geometry1, Geometry2, AssignPolicy, Tag1, Tag2, linear_tag, linear_tag>
|
||||
: get_turn_info_linear_linear<AssignPolicy>
|
||||
{};
|
||||
|
||||
// GET_TURNS
|
||||
|
||||
template <typename Geometry1,
|
||||
typename Geometry2,
|
||||
typename GetTurnPolicy
|
||||
= get_turn_info<Geometry1, Geometry2, overlay::calculate_distance_policy> >
|
||||
struct get_turns
|
||||
{
|
||||
typedef typename geometry::point_type<Geometry1>::type point1_type;
|
||||
@@ -64,33 +347,22 @@ struct get_turns
|
||||
template <typename Turns>
|
||||
static inline void apply(Turns & turns, Geometry1 const& geometry1, Geometry2 const& geometry2)
|
||||
{
|
||||
typedef //overlay::assign_null_policy
|
||||
overlay::calculate_distance_policy assign_policy;
|
||||
|
||||
detail::get_turns::no_interrupt_policy interrupt_policy;
|
||||
|
||||
static const bool reverse1 = detail::overlay::do_reverse<geometry::point_order<Geometry1>::value>::value;
|
||||
static const bool reverse2 = detail::overlay::do_reverse<geometry::point_order<Geometry2>::value>::value;
|
||||
|
||||
// boost::geometry::get_turns
|
||||
// <
|
||||
// reverse1, reverse2, assign_policy
|
||||
// >(geometry1, geometry2, detail::no_rescale_policy(), turns, interrupt_policy);
|
||||
|
||||
typedef detail::overlay::get_turn_info
|
||||
<
|
||||
assign_policy
|
||||
> turn_policy;
|
||||
|
||||
dispatch::get_turns
|
||||
<
|
||||
typename bg::tag<Geometry1>::type, typename bg::tag<Geometry2>::type,
|
||||
Geometry1, Geometry2, reverse1, reverse2,
|
||||
turn_policy
|
||||
GetTurnPolicy
|
||||
>::apply(0, geometry1, 1, geometry2, bg::detail::no_rescale_policy(), turns, interrupt_policy);
|
||||
}
|
||||
};
|
||||
|
||||
// TURNS SORTING AND SEARCHING
|
||||
|
||||
struct operation_order_uibc
|
||||
{
|
||||
template <typename Op> static inline
|
||||
|
||||
@@ -74,6 +74,17 @@ template <typename P>
|
||||
void test_linestring_linestring()
|
||||
{
|
||||
typedef bg::model::linestring<P> ls;
|
||||
|
||||
to_svg<ls, ls>("LINESTRING(0 0,2 0,4 0,6 0,8 0)", "LINESTRING(1 0,3 0,5 0,6 0,9 0)", "lsls01.svg");
|
||||
to_svg<ls, ls>("LINESTRING(0 0,2 0,4 0,4 4)", "LINESTRING(1 0,3 0,4 0,4 2,4 5)", "lsls02.svg");
|
||||
to_svg<ls, ls>("LINESTRING(0 0,2 0,4 0,4 4)", "LINESTRING(1 0,4 0,4 4)", "lsls03.svg");
|
||||
to_svg<ls, ls>("LINESTRING(0 0,2 0,4 0,4 4)", "LINESTRING(1 0,4 0,4 3)", "lsls04.svg");
|
||||
to_svg<ls, ls>("LINESTRING(1 0,2 0,4 0,6 0,8 0)", "LINESTRING(0 0,3 0,5 0,6 0,9 0)", "lsls05.svg");
|
||||
|
||||
to_svg<ls, ls>("LINESTRING(0 0,10 0,10 10)", "LINESTRING(1 0,10 9)", "lsls06.svg");
|
||||
to_svg<ls, ls>("LINESTRING(0 0,10 0,10 10)", "LINESTRING(1 0,9 9)", "lsls07.svg");
|
||||
to_svg<ls, ls>("LINESTRING(0 0,1 0,10 0,10 10)", "LINESTRING(1 0,9 9)", "lsls08.svg");
|
||||
|
||||
test_geometry<ls, ls>("LINESTRING(0 0, 2 2, 3 2)", "LINESTRING(0 0, 2 2, 3 2)", "1FFF0FFFT");
|
||||
test_geometry<ls, ls>("LINESTRING(0 0,3 2)", "LINESTRING(0 0, 2 2, 3 2)", "FF1F0F1FT");
|
||||
|
||||
@@ -131,7 +142,9 @@ void test_linestring_linestring()
|
||||
to_svg<ls, ls>("LINESTRING(0 5,10 5,10 10,5 10,5 0)", "LINESTRING(5 0,5 10,10 10,10 5,0 5)", "lsls16.svg");
|
||||
to_svg<ls, ls>("LINESTRING(0 5,10 5)", "LINESTRING(5 0,5 10,10 10,10 5,0 5)", "lsls161.svg");
|
||||
to_svg<ls, ls>("LINESTRING(0 5,8 5,10 5)", "LINESTRING(5 0,5 10,10 10,10 5,0 5)", "lsls162.svg");
|
||||
to_svg<ls, ls>("LINESTRING(0 5,8 5)", "LINESTRING(5 0,5 10,10 10,10 5,0 5)", "lsls163.svg");
|
||||
to_svg<ls, ls>("LINESTRING(0 5,8 5)", "LINESTRING(5 0,5 10,10 10,10 5,0 5)", "lsls1631.svg");
|
||||
to_svg<ls, ls>("LINESTRING(0 5,1 5,7 5,8 5)", "LINESTRING(5 0,5 10,10 10,10 5,0 5)", "lsls1632.svg");
|
||||
to_svg<ls, ls>("LINESTRING(0 5,1 5,7 5,8 5)", "LINESTRING(5 10,10 10,10 5,0 5)", "lsls1633.svg");
|
||||
to_svg<ls, ls>("LINESTRING(0 5,8 4)", "LINESTRING(5 0,5 10,10 10,10 5,0 5)", "lsls164.svg");
|
||||
to_svg<ls, ls>("LINESTRING(0 5,5 5,8 4)", "LINESTRING(5 0,5 10,10 10,10 5,0 5)", "lsls165.svg");
|
||||
to_svg<ls, ls>("LINESTRING(0 5,5 5,8 5)", "LINESTRING(5 0,5 10,10 10,10 5,0 5)", "lsls166.svg");
|
||||
|
||||
@@ -172,13 +172,13 @@ inline void turns_to_svg(Turns const& turns, Mapper & mapper, bool enrich = fals
|
||||
}
|
||||
}
|
||||
|
||||
//struct to_svg_assign_policy
|
||||
// : bg::detail::overlay::calculate_distance_policy
|
||||
//{
|
||||
// static bool const include_no_turn = true;
|
||||
// static bool const include_degenerate = true;
|
||||
// static bool const include_opposite = true;
|
||||
//};
|
||||
struct to_svg_assign_policy
|
||||
: bg::detail::overlay::calculate_distance_policy
|
||||
{
|
||||
static bool const include_no_turn = false;
|
||||
static bool const include_degenerate = false;
|
||||
static bool const include_opposite = true;
|
||||
};
|
||||
|
||||
template <typename G>
|
||||
inline void to_svg(G const& g, std::string const& filename, bool sort = true)
|
||||
@@ -200,6 +200,7 @@ inline void to_svg(G const& g, std::string const& filename, bool sort = true)
|
||||
|
||||
typedef bg::detail::overlay::traversal_turn_info<P> turn_info;
|
||||
typedef bg::detail::overlay::calculate_distance_policy AssignPolicy;
|
||||
//typedef to_svg_assign_policy AssignPolicy;
|
||||
|
||||
typedef std::deque<turn_info> Turns;
|
||||
typedef bg::detail::self_get_turn_points::no_interrupt_policy InterruptPolicy;
|
||||
@@ -218,7 +219,7 @@ inline void to_svg(G const& g, std::string const& filename, bool sort = true)
|
||||
}
|
||||
|
||||
template <typename G1, typename G2>
|
||||
inline void to_svg(G1 const& g1, G2 const& g2, std::string const& filename, bool sort = true, bool reverse_by_geometry_id = false, bool enrich = false)
|
||||
inline void to_svg(G1 const& g1, G2 const& g2, std::string const& filename, bool sort = true, bool use_old_turns_policy = false, bool enrich = false)
|
||||
{
|
||||
namespace bg = boost::geometry;
|
||||
|
||||
@@ -240,7 +241,8 @@ inline void to_svg(G1 const& g1, G2 const& g2, std::string const& filename, bool
|
||||
// GET TURNS
|
||||
|
||||
typedef bg::detail::overlay::traversal_turn_info<P1> turn_info;
|
||||
typedef bg::detail::overlay::calculate_distance_policy AssignPolicy;
|
||||
//typedef bg::detail::overlay::calculate_distance_policy AssignPolicy;
|
||||
typedef to_svg_assign_policy AssignPolicy;
|
||||
|
||||
typedef std::deque<turn_info> Turns;
|
||||
typedef bg::detail::get_turns::no_interrupt_policy InterruptPolicy;
|
||||
@@ -250,7 +252,7 @@ inline void to_svg(G1 const& g1, G2 const& g2, std::string const& filename, bool
|
||||
Turns turns;
|
||||
InterruptPolicy interrupt_policy;
|
||||
|
||||
if ( reverse_by_geometry_id )
|
||||
if ( use_old_turns_policy )
|
||||
{
|
||||
boost::geometry::get_turns
|
||||
<
|
||||
@@ -259,17 +261,15 @@ inline void to_svg(G1 const& g1, G2 const& g2, std::string const& filename, bool
|
||||
}
|
||||
else
|
||||
{
|
||||
typedef bg::detail::overlay::get_turn_info
|
||||
typedef bg::detail::relate::turns::get_turn_info
|
||||
<
|
||||
AssignPolicy
|
||||
G1, G2, AssignPolicy
|
||||
> TurnPolicy;
|
||||
|
||||
bg::dispatch::get_turns
|
||||
bg::detail::relate::turns::get_turns
|
||||
<
|
||||
typename bg::tag<G1>::type, typename bg::tag<G2>::type,
|
||||
G1, G2, Reverse1, Reverse2,
|
||||
TurnPolicy
|
||||
>::apply(0, g1, 1, g2, bg::detail::no_rescale_policy(), turns, interrupt_policy);
|
||||
G1, G2, TurnPolicy
|
||||
>::apply(turns, g1, g2);
|
||||
}
|
||||
|
||||
if ( sort )
|
||||
|
||||
Reference in New Issue
Block a user