mirror of
https://github.com/boostorg/geometry.git
synced 2026-02-22 03:22:14 +00:00
[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:
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user