[buffer] Fix direction code for some new cases.

The similar_direction function could be erroneous for corner cases,
refactored it out.
This also makes it a bit less dependent on infinite_line (cartesian)
This commit is contained in:
Barend Gehrels
2020-05-06 13:04:08 +02:00
parent ef66e923cc
commit 70ecdfdd19
9 changed files with 70 additions and 253 deletions

View File

@@ -1,6 +1,6 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// Copyright (c) 2012-2014 Barend Gehrels, Amsterdam, the Netherlands.
// Copyright (c) 2012-2020 Barend Gehrels, Amsterdam, the Netherlands.
// This file was modified by Oracle on 2017.
// Modifications copyright (c) 2017 Oracle and/or its affiliates.
@@ -31,16 +31,13 @@
#include <boost/geometry/strategies/buffer.hpp>
#include <boost/geometry/strategies/side.hpp>
#include <boost/geometry/algorithms/detail/make/make.hpp>
#include <boost/geometry/algorithms/detail/direction_code.hpp>
#include <boost/geometry/algorithms/detail/buffer/buffered_piece_collection.hpp>
#include <boost/geometry/algorithms/detail/buffer/line_line_intersection.hpp>
#include <boost/geometry/algorithms/assign.hpp>
#include <boost/geometry/algorithms/num_interior_rings.hpp>
#include <boost/geometry/algorithms/simplify.hpp>
#include <boost/geometry/arithmetic/infinite_line_functions.hpp>
#include <boost/geometry/views/detail/normalized_view.hpp>
@@ -113,23 +110,11 @@ struct buffer_range
JoinStrategy const& join_strategy,
EndStrategy const& end_strategy,
RobustPolicy const& ,
SideStrategy const& side_strategy) // side strategy
SideStrategy const& side_strategy)
{
output_point_type intersection_point;
geometry::assign_zero(intersection_point);
geometry::strategy::buffer::join_selector join
= get_join_type(penultimate_input, previous_input, input, side_strategy);
if (join == geometry::strategy::buffer::join_convex)
{
// Calculate the intersection-point formed by the two sides.
// It might be that the two sides are not convex, but continue
// or spikey, we then change the join-type
join = line_line_intersection::apply(
perp1, perp2, prev_perp1, prev_perp2,
intersection_point);
}
geometry::strategy::buffer::join_selector const join
= get_join_type(penultimate_input, previous_input, input,
side_strategy);
switch(join)
{
@@ -163,6 +148,11 @@ struct buffer_range
{
// The corner is convex, we create a join
// TODO (future) - avoid a separate vector, add the piece directly
output_point_type const
intersection_point
= line_line_intersection::apply(perp1, perp2,
prev_perp1, prev_perp2);
std::vector<output_point_type> range_out;
if (join_strategy.apply(intersection_point,
previous_input, prev_perp2, perp1,
@@ -177,14 +167,14 @@ struct buffer_range
}
}
static inline bool similar_direction(output_point_type const& p0,
// Returns true if collinear point p2 continues after p0 and p1.
// If it turns back (spike), it returns false.
static inline bool same_direction(output_point_type const& p0,
output_point_type const& p1,
output_point_type const& p2)
{
typedef model::infinite_line<coordinate_type> line_type;
line_type const p = detail::make::make_infinite_line<coordinate_type>(p0, p1);
line_type const q = detail::make::make_infinite_line<coordinate_type>(p1, p2);
return arithmetic::similar_direction(p, q);
typedef typename cs_tag<output_point_type>::type cs_tag;
return direction_code<cs_tag>(p0, p1, p2) == 1;
}
template <typename SideStrategy>
@@ -197,8 +187,7 @@ struct buffer_range
int const side = side_strategy.apply(p0, p1, p2);
return side == -1 ? geometry::strategy::buffer::join_convex
: side == 1 ? geometry::strategy::buffer::join_concave
: similar_direction(p0, p1, p2)
? geometry::strategy::buffer::join_continue
: same_direction(p0, p1, p2) ? geometry::strategy::buffer::join_continue
: geometry::strategy::buffer::join_spike;
}

View File

@@ -1,6 +1,6 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// Copyright (c) 2012-2019 Barend Gehrels, Amsterdam, the Netherlands.
// Copyright (c) 2012-2020 Barend Gehrels, Amsterdam, the Netherlands.
// Use, modification and distribution is subject to the Boost Software License,
// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
@@ -9,10 +9,12 @@
#ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_BUFFER_LINE_LINE_INTERSECTION_HPP
#define BOOST_GEOMETRY_ALGORITHMS_DETAIL_BUFFER_LINE_LINE_INTERSECTION_HPP
#include <boost/geometry/core/assert.hpp>
#include <boost/geometry/arithmetic/infinite_line_functions.hpp>
#include <boost/geometry/algorithms/detail/make/make.hpp>
#include <boost/geometry/strategies/buffer.hpp>
#include <boost/core/ignore_unused.hpp>
namespace boost { namespace geometry
{
@@ -26,10 +28,8 @@ namespace detail { namespace buffer
struct line_line_intersection
{
template <typename Point>
static inline strategy::buffer::join_selector
apply(Point const& pi, Point const& pj,
Point const& qi, Point const& qj,
Point& ip)
static inline Point
apply(Point const& pi, Point const& pj, Point const& qi, Point const& qj)
{
typedef typename coordinate_type<Point>::type ct;
typedef model::infinite_line<ct> line_type;
@@ -37,18 +37,14 @@ struct line_line_intersection
line_type const p = detail::make::make_infinite_line<ct>(pi, pj);
line_type const q = detail::make::make_infinite_line<ct>(qi, qj);
if (arithmetic::intersection_point(p, q, ip))
{
return strategy::buffer::join_convex;
}
// The input lines are not parallel, they intersect, because
// their join type is checked before.
Point ip;
bool const intersecting = arithmetic::intersection_point(p, q, ip);
BOOST_GEOMETRY_ASSERT(intersecting);
boost::ignore_unused(intersecting);
// The lines do not intersect.
// Distinguish between continuing lines (having a similar direction)
// and spikes (having the opposite direction).
return arithmetic::similar_direction(p, q)
? strategy::buffer::join_continue
: strategy::buffer::join_spike
;
return ip;
}
};

View File

@@ -1,6 +1,6 @@
// Boost.Geometry (aka GGL, Generic Geometry Library)
// Copyright (c) 2015 Barend Gehrels, Amsterdam, the Netherlands.
// Copyright (c) 2015-2020 Barend Gehrels, Amsterdam, the Netherlands.
// This file was modified by Oracle on 2015, 2017, 2019.
// Modifications copyright (c) 2015-2019 Oracle and/or its affiliates.
@@ -54,21 +54,29 @@ struct direction_code_impl<cartesian_tag>
typedef model::infinite_line<calc_t> line_type;
// point b is often equal to the specified point, check that first
line_type const q = detail::make::make_infinite_line<calc_t>(segment_b, point);
if (arithmetic::is_degenerate(q))
// Situation and construction of perpendicular line
//
// P1 a--------------->b P2
// |
// |
// v
//
// P1 is located right of the (directional) perpendicular line
// and therefore gets a negative side_value, and returns -1.
// P2 is to the left of the perpendicular line and returns 1.
// If the specified point is located on top of b, it returns 0.
line_type const line
= detail::make::make_perpendicular_line<calc_t>(segment_a,
segment_b, segment_b);
if (arithmetic::is_degenerate(line))
{
return 0;
}
line_type const p = detail::make::make_infinite_line<calc_t>(segment_a, segment_b);
if (arithmetic::is_degenerate(p))
{
return 0;
}
// p extends a-b if direction is similar
return arithmetic::similar_direction(p, q) ? 1 : -1;
calc_t const sv = arithmetic::side_value(line, point);
return sv == 0 ? 0 : sv > 0 ? 1 : -1;
}
};

View File

@@ -76,19 +76,6 @@ side_value(model::infinite_line<Type> const& line, Point const& p)
return side_value(line, geometry::get<0>(p), geometry::get<1>(p));
}
// Returns true for two lines which are supposed to be (close to) collinear
// (which is not checked) and have a similar direction
// (in practice up to 45 degrees, TO BE VERIFIED)
// true: -----------------> p -----------------> q
// false: -----------------> p <----------------- q
template <typename Type>
inline
bool similar_direction(const model::infinite_line<Type>& p,
const model::infinite_line<Type>& q)
{
return p.a * q.a >= 0 && p.b * q.b >= 0;
}
template <typename Type>
inline bool is_degenerate(const model::infinite_line<Type>& line)
{