mirror of
https://github.com/boostorg/geometry.git
synced 2025-05-09 23:24:02 +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/io/wkt/wkt.hpp>
|
||||
|
||||
namespace boost { namespace geometry
|
||||
{
|
||||
|
||||
|
@ -89,8 +89,8 @@ public:
|
||||
// Check the distance ip-vertex (= miter distance)
|
||||
// (We calculate it manually (not using Pythagoras strategy) to reuse
|
||||
// dx and dy)
|
||||
coordinate_type const dx = get<0>(p) - get<0>(vertex);
|
||||
coordinate_type const dy = get<1>(p) - get<1>(vertex);
|
||||
promoted_type const dx = get<0>(p) - get<0>(vertex);
|
||||
promoted_type const dy = get<1>(p) - get<1>(vertex);
|
||||
|
||||
promoted_type const distance = geometry::math::sqrt(dx * dx + dy * dy);
|
||||
|
||||
|
@ -149,20 +149,8 @@ public :
|
||||
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);
|
||||
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);
|
||||
return true;
|
||||
}
|
||||
|
@ -48,23 +48,21 @@ public :
|
||||
RangeOut& range_out,
|
||||
std::size_t level = 1) const
|
||||
{
|
||||
typedef typename coordinate_type<Point>::type coordinate_type;
|
||||
|
||||
// Generate 'vectors'
|
||||
coordinate_type const vp1_x = get<0>(p1) - get<0>(vertex);
|
||||
coordinate_type const vp1_y = get<1>(p1) - get<1>(vertex);
|
||||
PromotedType const vp1_x = get<0>(p1) - get<0>(vertex);
|
||||
PromotedType const vp1_y = get<1>(p1) - get<1>(vertex);
|
||||
|
||||
coordinate_type const vp2_x = (get<0>(p2) - get<0>(vertex));
|
||||
coordinate_type const vp2_y = (get<1>(p2) - get<1>(vertex));
|
||||
PromotedType const vp2_x = (get<0>(p2) - get<0>(vertex));
|
||||
PromotedType const vp2_y = (get<1>(p2) - get<1>(vertex));
|
||||
|
||||
// Average them to generate vector in between
|
||||
coordinate_type const two = 2;
|
||||
coordinate_type const v_x = (vp1_x + vp2_x) / two;
|
||||
coordinate_type const v_y = (vp1_y + vp2_y) / two;
|
||||
PromotedType const two = 2;
|
||||
PromotedType const v_x = (vp1_x + vp2_x) / 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 prop = buffer_distance / length2;
|
||||
PromotedType const prop = buffer_distance / length2;
|
||||
|
||||
Point mid_point;
|
||||
set<0>(mid_point, get<0>(vertex) + v_x * prop);
|
||||
@ -106,13 +104,13 @@ public :
|
||||
}
|
||||
|
||||
// Generate 'vectors'
|
||||
coordinate_type const vix = (get<0>(ip) - get<0>(vertex));
|
||||
coordinate_type const viy = (get<1>(ip) - get<1>(vertex));
|
||||
promoted_type const vix = (get<0>(ip) - get<0>(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 bd = geometry::math::abs(buffer_distance);
|
||||
promoted_type prop = bd / length_i;
|
||||
promoted_type const prop = bd / length_i;
|
||||
|
||||
Point bp;
|
||||
set<0>(bp, get<0>(vertex) + vix * prop);
|
||||
|
@ -76,8 +76,8 @@ public :
|
||||
// Generate a block along (left or right of) the segment
|
||||
|
||||
// Simulate a vector d (dx,dy)
|
||||
coordinate_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 dx = get<0>(input_p2) - get<0>(input_p1);
|
||||
promoted_type const dy = get<1>(input_p2) - get<1>(input_p1);
|
||||
|
||||
// For normalization [0,1] (=dot product d.d, sqrt)
|
||||
promoted_type const length = geometry::math::sqrt(dx * dx + dy * dy);
|
||||
|
@ -18,6 +18,8 @@
|
||||
test-suite boost-geometry-strategies
|
||||
:
|
||||
[ 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 crossings_multiply.cpp : : : : strategies_crossings_multiply ]
|
||||
[ 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