mirror of
https://github.com/boostorg/geometry.git
synced 2025-05-11 13:34:10 +00:00
[buffer] fix for integer overflow
This commit is contained in:
parent
756412ae0f
commit
1837ddc7f1
@ -24,8 +24,6 @@
|
|||||||
#include <boost/geometry/strategies/buffer.hpp>
|
#include <boost/geometry/strategies/buffer.hpp>
|
||||||
|
|
||||||
|
|
||||||
#include <boost/geometry/io/wkt/wkt.hpp>
|
|
||||||
|
|
||||||
namespace boost { namespace geometry
|
namespace boost { namespace geometry
|
||||||
{
|
{
|
||||||
|
|
||||||
|
@ -89,8 +89,8 @@ public:
|
|||||||
// Check the distance ip-vertex (= miter distance)
|
// Check the distance ip-vertex (= miter distance)
|
||||||
// (We calculate it manually (not using Pythagoras strategy) to reuse
|
// (We calculate it manually (not using Pythagoras strategy) to reuse
|
||||||
// dx and dy)
|
// dx and dy)
|
||||||
coordinate_type const dx = get<0>(p) - get<0>(vertex);
|
promoted_type const dx = get<0>(p) - get<0>(vertex);
|
||||||
coordinate_type const dy = get<1>(p) - get<1>(vertex);
|
promoted_type const dy = get<1>(p) - get<1>(vertex);
|
||||||
|
|
||||||
promoted_type const distance = geometry::math::sqrt(dx * dx + dy * dy);
|
promoted_type const distance = geometry::math::sqrt(dx * dx + dy * dy);
|
||||||
|
|
||||||
|
@ -149,20 +149,8 @@ public :
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Generate 'vectors'
|
|
||||||
coordinate_type vix = (get<0>(ip) - get<0>(vertex));
|
|
||||||
coordinate_type viy = (get<1>(ip) - get<1>(vertex));
|
|
||||||
|
|
||||||
promoted_type length_i = geometry::math::sqrt(vix * vix + viy * viy);
|
|
||||||
DistanceType const bd = geometry::math::abs(buffer_distance);
|
|
||||||
promoted_type prop = bd / length_i;
|
|
||||||
|
|
||||||
Point bp;
|
|
||||||
set<0>(bp, get<0>(vertex) + vix * prop);
|
|
||||||
set<1>(bp, get<1>(vertex) + viy * prop);
|
|
||||||
|
|
||||||
range_out.push_back(perp1);
|
range_out.push_back(perp1);
|
||||||
generate_points<promoted_type>(vertex, perp1, perp2, bd, range_out);
|
generate_points<promoted_type>(vertex, perp1, perp2, geometry::math::abs(buffer_distance), range_out);
|
||||||
range_out.push_back(perp2);
|
range_out.push_back(perp2);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -48,23 +48,21 @@ public :
|
|||||||
RangeOut& range_out,
|
RangeOut& range_out,
|
||||||
std::size_t level = 1) const
|
std::size_t level = 1) const
|
||||||
{
|
{
|
||||||
typedef typename coordinate_type<Point>::type coordinate_type;
|
|
||||||
|
|
||||||
// Generate 'vectors'
|
// Generate 'vectors'
|
||||||
coordinate_type const vp1_x = get<0>(p1) - get<0>(vertex);
|
PromotedType const vp1_x = get<0>(p1) - get<0>(vertex);
|
||||||
coordinate_type const vp1_y = get<1>(p1) - get<1>(vertex);
|
PromotedType const vp1_y = get<1>(p1) - get<1>(vertex);
|
||||||
|
|
||||||
coordinate_type const vp2_x = (get<0>(p2) - get<0>(vertex));
|
PromotedType const vp2_x = (get<0>(p2) - get<0>(vertex));
|
||||||
coordinate_type const vp2_y = (get<1>(p2) - get<1>(vertex));
|
PromotedType const vp2_y = (get<1>(p2) - get<1>(vertex));
|
||||||
|
|
||||||
// Average them to generate vector in between
|
// Average them to generate vector in between
|
||||||
coordinate_type const two = 2;
|
PromotedType const two = 2;
|
||||||
coordinate_type const v_x = (vp1_x + vp2_x) / two;
|
PromotedType const v_x = (vp1_x + vp2_x) / two;
|
||||||
coordinate_type const v_y = (vp1_y + vp2_y) / two;
|
PromotedType const v_y = (vp1_y + vp2_y) / two;
|
||||||
|
|
||||||
PromotedType const length2 = geometry::math::sqrt(v_x * v_x + v_y * v_y);
|
PromotedType const length2 = geometry::math::sqrt(v_x * v_x + v_y * v_y);
|
||||||
|
|
||||||
PromotedType prop = buffer_distance / length2;
|
PromotedType const prop = buffer_distance / length2;
|
||||||
|
|
||||||
Point mid_point;
|
Point mid_point;
|
||||||
set<0>(mid_point, get<0>(vertex) + v_x * prop);
|
set<0>(mid_point, get<0>(vertex) + v_x * prop);
|
||||||
@ -106,13 +104,13 @@ public :
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Generate 'vectors'
|
// Generate 'vectors'
|
||||||
coordinate_type const vix = (get<0>(ip) - get<0>(vertex));
|
promoted_type const vix = (get<0>(ip) - get<0>(vertex));
|
||||||
coordinate_type const viy = (get<1>(ip) - get<1>(vertex));
|
promoted_type const viy = (get<1>(ip) - get<1>(vertex));
|
||||||
|
|
||||||
promoted_type const length_i = geometry::math::sqrt(vix * vix + viy * viy);
|
promoted_type const length_i = geometry::math::sqrt(vix * vix + viy * viy);
|
||||||
|
|
||||||
promoted_type const bd = geometry::math::abs(buffer_distance);
|
promoted_type const bd = geometry::math::abs(buffer_distance);
|
||||||
promoted_type prop = bd / length_i;
|
promoted_type const prop = bd / length_i;
|
||||||
|
|
||||||
Point bp;
|
Point bp;
|
||||||
set<0>(bp, get<0>(vertex) + vix * prop);
|
set<0>(bp, get<0>(vertex) + vix * prop);
|
||||||
|
@ -76,8 +76,8 @@ public :
|
|||||||
// Generate a block along (left or right of) the segment
|
// Generate a block along (left or right of) the segment
|
||||||
|
|
||||||
// Simulate a vector d (dx,dy)
|
// Simulate a vector d (dx,dy)
|
||||||
coordinate_type const dx = get<0>(input_p2) - get<0>(input_p1);
|
promoted_type const dx = get<0>(input_p2) - get<0>(input_p1);
|
||||||
coordinate_type const dy = get<1>(input_p2) - get<1>(input_p1);
|
promoted_type const dy = get<1>(input_p2) - get<1>(input_p1);
|
||||||
|
|
||||||
// For normalization [0,1] (=dot product d.d, sqrt)
|
// For normalization [0,1] (=dot product d.d, sqrt)
|
||||||
promoted_type const length = geometry::math::sqrt(dx * dx + dy * dy);
|
promoted_type const length = geometry::math::sqrt(dx * dx + dy * dy);
|
||||||
|
@ -18,6 +18,8 @@
|
|||||||
test-suite boost-geometry-strategies
|
test-suite boost-geometry-strategies
|
||||||
:
|
:
|
||||||
[ run andoyer.cpp : : : : strategies_andoyer ]
|
[ run andoyer.cpp : : : : strategies_andoyer ]
|
||||||
|
[ run buffer_join.cpp : : : : strategies_buffer_join ]
|
||||||
|
[ run buffer_side_straight.cpp : : : : strategies_buffer_side_straight ]
|
||||||
[ run cross_track.cpp : : : : strategies_cross_track ]
|
[ run cross_track.cpp : : : : strategies_cross_track ]
|
||||||
[ run crossings_multiply.cpp : : : : strategies_crossings_multiply ]
|
[ run crossings_multiply.cpp : : : : strategies_crossings_multiply ]
|
||||||
[ run distance_default_result.cpp : : : : strategies_distance_default_result ]
|
[ run distance_default_result.cpp : : : : strategies_distance_default_result ]
|
||||||
|
87
test/strategies/buffer_join.cpp
Normal file
87
test/strategies/buffer_join.cpp
Normal file
@ -0,0 +1,87 @@
|
|||||||
|
// Boost.Geometry
|
||||||
|
// Unit Test
|
||||||
|
|
||||||
|
// Copyright (c) 2022 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
|
||||||
|
// http://www.boost.org/LICENSE_1_0.txt)
|
||||||
|
|
||||||
|
#include <geometry_test_common.hpp>
|
||||||
|
|
||||||
|
#include <boost/geometry/geometries/point.hpp>
|
||||||
|
#include <boost/geometry/geometries/ring.hpp>
|
||||||
|
#include <boost/geometry/strategies/cartesian/buffer_join_round.hpp>
|
||||||
|
#include <boost/geometry/strategies/cartesian/buffer_join_round_by_divide.hpp>
|
||||||
|
#include <boost/geometry/io/wkt/wkt.hpp>
|
||||||
|
#include <boost/geometry/algorithms/area.hpp>
|
||||||
|
#include <boost/geometry/algorithms/distance.hpp>
|
||||||
|
#include <boost/geometry/algorithms/equals.hpp>
|
||||||
|
|
||||||
|
template <typename JoinStrategy, typename P, typename T>
|
||||||
|
void test_join(JoinStrategy const& join,
|
||||||
|
P const& ip, P const& vertex,
|
||||||
|
P const& perp1, P const& perp2,
|
||||||
|
T const& buffer_distance, std::size_t expected_size)
|
||||||
|
{
|
||||||
|
// Use a deque to be able to use push_front
|
||||||
|
bg::model::ring<P, true, true, std::deque> output_ring;
|
||||||
|
|
||||||
|
auto const result = join.apply(ip, vertex, perp1, perp2, buffer_distance, output_ring);
|
||||||
|
BOOST_CHECK_EQUAL(true, result);
|
||||||
|
BOOST_CHECK_EQUAL(expected_size , output_ring.size());
|
||||||
|
BOOST_CHECK(bg::equals(perp1, output_ring.front()));
|
||||||
|
BOOST_CHECK(bg::equals(perp2, output_ring.back()));
|
||||||
|
|
||||||
|
// All the generated points should be located
|
||||||
|
// at or close to the specified buffer distance from the vertex
|
||||||
|
for (const auto& p : output_ring)
|
||||||
|
{
|
||||||
|
auto const d = bg::distance(vertex, p);
|
||||||
|
auto const fraction = d / buffer_distance;
|
||||||
|
BOOST_CHECK_MESSAGE(fraction > 0.92 && fraction < 1.02,
|
||||||
|
"Unexpected distance = " << d << " fraction=" << fraction);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Start with the vertex itself, and close it,
|
||||||
|
// to calculate the area of the buffered corner
|
||||||
|
output_ring.push_front(vertex);
|
||||||
|
output_ring.push_back(vertex);
|
||||||
|
|
||||||
|
// Area should be around 0.25 * PI * sqr(specified buffer distance)
|
||||||
|
// It is a bit less because there are less than infinite points in the circle
|
||||||
|
double const area = bg::area(output_ring) ;
|
||||||
|
double const expected = 0.25 * buffer_distance * buffer_distance * 3.1415;
|
||||||
|
double const fraction_area = area / expected;
|
||||||
|
BOOST_CHECK_MESSAGE(fraction_area > 0.95 && fraction_area < 1.05,
|
||||||
|
"Unexpected area = " << area << " fraction=" << fraction_area);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename P>
|
||||||
|
void test_case(typename bg::coordinate_type<P>::type c)
|
||||||
|
{
|
||||||
|
// For round strategy (36 points per circle) we expect 10 points in a corner.
|
||||||
|
// Using divide on level 3, we get 17
|
||||||
|
test_join(bg::strategy::buffer::join_round(36), P{c, c}, P{0, 0}, P{0, c}, P{c, 0}, double(c), 10);
|
||||||
|
test_join(bg::strategy::buffer::join_round_by_divide(3), P{c, c}, P{0, 0}, P{0, c}, P{c, 0}, double(c), 17);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename P>
|
||||||
|
void test_all()
|
||||||
|
{
|
||||||
|
// Also test for large coordinates.
|
||||||
|
// For integer coordinates there was an overflow with them (now fixed)
|
||||||
|
test_case<P>(100);
|
||||||
|
test_case<P>(10000);
|
||||||
|
test_case<P>(1000000);
|
||||||
|
test_case<P>(100000000);
|
||||||
|
}
|
||||||
|
|
||||||
|
int test_main(int, char *[])
|
||||||
|
{
|
||||||
|
test_all<bg::model::point<int, 2, bg::cs::cartesian>>();
|
||||||
|
test_all<bg::model::point<float, 2, bg::cs::cartesian>>();
|
||||||
|
test_all<bg::model::point<double, 2, bg::cs::cartesian>>();
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
59
test/strategies/buffer_side_straight.cpp
Normal file
59
test/strategies/buffer_side_straight.cpp
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
// Boost.Geometry
|
||||||
|
// Unit Test
|
||||||
|
|
||||||
|
// Copyright (c) 2022 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
|
||||||
|
// http://www.boost.org/LICENSE_1_0.txt)
|
||||||
|
|
||||||
|
#include <geometry_test_common.hpp>
|
||||||
|
|
||||||
|
#include <boost/geometry/geometries/point.hpp>
|
||||||
|
|
||||||
|
#include <boost/geometry/strategies/cartesian/buffer_side_straight.hpp>
|
||||||
|
#include <boost/geometry/strategies/agnostic/buffer_distance_symmetric.hpp>
|
||||||
|
|
||||||
|
#include <boost/geometry/algorithms/distance.hpp>
|
||||||
|
|
||||||
|
template <typename P>
|
||||||
|
void test_side_straight(P const &input_p1, P const &input_p2)
|
||||||
|
{
|
||||||
|
using bg::strategy::buffer::side_straight;
|
||||||
|
|
||||||
|
bg::strategy::buffer::distance_symmetric<typename bg::coordinate_type<P>::type> ds(1.0);
|
||||||
|
|
||||||
|
std::vector<P> output_range;
|
||||||
|
|
||||||
|
auto const result = side_straight::apply(input_p1, input_p2, bg::strategy::buffer::buffer_side_right, ds, output_range);
|
||||||
|
|
||||||
|
BOOST_CHECK_EQUAL(bg::strategy::buffer::result_normal, result);
|
||||||
|
BOOST_CHECK_EQUAL(2u, output_range.size());
|
||||||
|
|
||||||
|
#ifdef BOOST_GEOMETRY_TEST_DEBUG
|
||||||
|
if (output_range.size() == 2)
|
||||||
|
{
|
||||||
|
std::cout << bg::distance(output_range.front(), output_range.back()) << std::endl;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename P>
|
||||||
|
void test_all()
|
||||||
|
{
|
||||||
|
// Also test for large coordinates.
|
||||||
|
// For integer coordinates there was an overflow with them (now fixed)
|
||||||
|
test_side_straight(P{0, 0}, P{1, 1});
|
||||||
|
test_side_straight(P{0, 0}, P{100, 100});
|
||||||
|
test_side_straight(P{0, 0}, P{10000, 10000});
|
||||||
|
test_side_straight(P{0, 0}, P{1000000, 1000000});
|
||||||
|
test_side_straight(P{0, 0}, P{100000000, 100000000});
|
||||||
|
}
|
||||||
|
|
||||||
|
int test_main(int, char *[])
|
||||||
|
{
|
||||||
|
test_all<bg::model::point<int, 2, bg::cs::cartesian>>();
|
||||||
|
test_all<bg::model::point<double, 2, bg::cs::cartesian>>();
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user