Skip to content

Commit 3374cda

Browse files
authored
Merge pull request #749 from vissarion/feature/robust_area
Area strategy for more accurate computations in cartesian CS
2 parents cb9c710 + e842950 commit 3374cda

File tree

6 files changed

+189
-4
lines changed

6 files changed

+189
-4
lines changed

include/boost/geometry/extensions/triangulation/strategies/cartesian/in_circle_robust.hpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
#ifndef BOOST_GEOMETRY_EXTENSIONS_TRIANGULATION_STRATEGIES_CARTESIAN_IN_CIRCLE_ROBUST_HPP
1313
#define BOOST_GEOMETRY_EXTENSIONS_TRIANGULATION_STRATEGIES_CARTESIAN_IN_CIRCLE_ROBUST_HPP
1414

15-
#include<boost/geometry/extensions/triangulation/strategies/cartesian/detail/precise_math.hpp>
15+
#include<boost/geometry/util/precise_math.hpp>
1616

1717
namespace boost { namespace geometry
1818
{

include/boost/geometry/extensions/triangulation/strategies/cartesian/side_robust.hpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414

1515
#include <boost/geometry/util/select_most_precise.hpp>
1616
#include <boost/geometry/util/select_calculation_type.hpp>
17-
#include <boost/geometry/extensions/triangulation/strategies/cartesian/detail/precise_math.hpp>
17+
#include <boost/geometry/util/precise_math.hpp>
1818

1919
namespace boost { namespace geometry
2020
{

include/boost/geometry/strategy/cartesian/area.hpp

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -112,8 +112,7 @@ public :
112112
}
113113

114114
template <typename Geometry>
115-
static inline typename result_type<Geometry>::type
116-
result(state<Geometry>& st)
115+
static inline auto result(state<Geometry>& st)
117116
{
118117
return st.area();
119118
}
Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
// Boost.Geometry
2+
3+
// Copyright (c) 2020, Oracle and/or its affiliates.
4+
5+
// Contributed and/or modified by Vissarion Fysikopoulos, on behalf of Oracle
6+
7+
// Licensed under the Boost Software License version 1.0.
8+
// http://www.boost.org/users/license.html
9+
10+
#ifndef BOOST_GEOMETRY_STRATEGY_CARTESIAN_AREA_ACCURATE_HPP
11+
#define BOOST_GEOMETRY_STRATEGY_CARTESIAN_AREA_ACCURATE_HPP
12+
13+
#include <boost/mpl/if.hpp>
14+
15+
//#include <boost/geometry/arithmetic/determinant.hpp>
16+
#include <boost/geometry/core/access.hpp>
17+
#include <boost/geometry/core/coordinate_type.hpp>
18+
#include <boost/geometry/core/coordinate_dimension.hpp>
19+
#include <boost/geometry/strategy/area.hpp>
20+
#include <boost/geometry/util/select_most_precise.hpp>
21+
#include <boost/geometry/util/precise_math.hpp>
22+
23+
namespace boost { namespace geometry
24+
{
25+
26+
namespace strategy { namespace area
27+
{
28+
29+
/*!
30+
\brief Cartesian area calculation
31+
\ingroup strategies
32+
\details Calculates cartesian area using the trapezoidal rule and precise
33+
summation (useful to increase precision with floating point arithmetic)
34+
\tparam CalculationType \tparam_calculation
35+
36+
\qbk{
37+
[heading See also]
38+
[link geometry.reference.algorithms.area.area_2_with_strategy area (with strategy)]
39+
}
40+
41+
*/
42+
template
43+
<
44+
typename CalculationType = void
45+
>
46+
class precise_cartesian
47+
{
48+
public :
49+
template <typename Geometry>
50+
struct result_type
51+
: strategy::area::detail::result_type
52+
<
53+
Geometry,
54+
CalculationType
55+
>
56+
{};
57+
58+
template <typename Geometry>
59+
class state
60+
{
61+
friend class precise_cartesian;
62+
63+
typedef typename result_type<Geometry>::type return_type;
64+
65+
public:
66+
inline state()
67+
: sum1(0)
68+
, sum2(0)
69+
{
70+
// Strategy supports only 2D areas
71+
assert_dimension<Geometry, 2>();
72+
}
73+
74+
private:
75+
inline return_type area() const
76+
{
77+
return_type const two = 2;
78+
return (sum1 + sum2) / two;
79+
}
80+
81+
return_type sum1;
82+
return_type sum2;
83+
};
84+
85+
template <typename PointOfSegment, typename Geometry>
86+
static inline void apply(PointOfSegment const& p1,
87+
PointOfSegment const& p2,
88+
state<Geometry>& st)
89+
{
90+
typedef typename state<Geometry>::return_type return_type;
91+
92+
auto const det = (return_type(get<0>(p1)) + return_type(get<0>(p2)))
93+
* (return_type(get<1>(p1)) - return_type(get<1>(p2)));
94+
95+
auto const res = boost::geometry::detail::precise_math::two_sum(st.sum1, det);
96+
97+
st.sum1 = res[0];
98+
st.sum2 += res[1];
99+
}
100+
101+
template <typename Geometry>
102+
static inline auto result(state<Geometry>& st)
103+
{
104+
return st.area();
105+
}
106+
107+
};
108+
109+
110+
}} // namespace strategy::area
111+
112+
113+
114+
}} // namespace boost::geometry
115+
116+
117+
#endif // BOOST_GEOMETRY_STRATEGIES_CARTESIAN_AREA_ACCURATE_HPP

test/algorithms/area/area.cpp

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,10 +27,13 @@
2727
#include <boost/geometry/geometries/ring.hpp>
2828
#include <boost/geometry/geometries/polygon.hpp>
2929

30+
#include <boost/geometry/strategy/cartesian/precise_area.hpp>
31+
3032
#include <test_geometries/all_custom_ring.hpp>
3133
#include <test_geometries/all_custom_polygon.hpp>
3234
//#define BOOST_GEOMETRY_TEST_DEBUG
3335

36+
#include <boost/multiprecision/cpp_dec_float.hpp>
3437
#include <boost/variant/variant.hpp>
3538

3639
template <typename Polygon>
@@ -175,6 +178,70 @@ void test_large_integers()
175178
BOOST_CHECK_CLOSE(int_area, double_area, 0.0001);
176179
}
177180

181+
struct precise_cartesian : bg::strategies::detail::cartesian_base
182+
{
183+
template <typename Geometry>
184+
static auto area(Geometry const&)
185+
{
186+
return bg::strategy::area::precise_cartesian<>();
187+
}
188+
};
189+
190+
void test_accurate_sum_strategy()
191+
{
192+
typedef bg::model::point<double, 2, bg::cs::cartesian> point_type;
193+
typedef bg::model::point
194+
<
195+
boost::multiprecision::cpp_dec_float_50,
196+
2,
197+
bg::cs::cartesian
198+
> mp_point_type;
199+
200+
auto const poly0_string = "POLYGON((0 0,0 1,1 0,0 0))";
201+
202+
bg::model::polygon<point_type> poly0;
203+
bg::read_wkt(poly0_string, poly0);
204+
205+
BOOST_CHECK_CLOSE(bg::area(poly0), 0.5, 0.0001);
206+
BOOST_CHECK_CLOSE(bg::area(poly0, precise_cartesian()), 0.5, 0.0001);
207+
208+
bg::model::polygon<mp_point_type> mp_poly0;
209+
bg::read_wkt(poly0_string, mp_poly0);
210+
211+
BOOST_CHECK_CLOSE(bg::area(mp_poly0), 0.5, 0.0001);
212+
213+
auto const poly1_string = "POLYGON((0.10000000000000001 0.10000000000000001,\
214+
0.20000000000000001 0.20000000000000004,\
215+
0.79999999999999993 0.80000000000000004,\
216+
1.267650600228229e30 1.2676506002282291e30,\
217+
0.10000000000000001 0.10000000000000001))";
218+
219+
bg::model::polygon<point_type> poly1;
220+
bg::read_wkt(poly1_string, poly1);
221+
222+
BOOST_CHECK_CLOSE(bg::area(poly1), 0, 0.0001);
223+
BOOST_CHECK_CLOSE(bg::area(poly1, precise_cartesian()), -0.315, 0.0001);
224+
225+
bg::model::polygon<mp_point_type> mp_poly1;
226+
bg::read_wkt(poly1_string, mp_poly1);
227+
228+
BOOST_CHECK_CLOSE(bg::area(mp_poly1), 34720783012552.6, 0.0001);
229+
230+
auto const poly2_string = "POLYGON((1.267650600228229e30 1.2676506002282291e30,\
231+
0.8 0.8,0.2 0.2,0.1 0.1,1.267650600228229e30 1.2676506002282291e30))";
232+
233+
bg::model::polygon<point_type> poly2;
234+
bg::read_wkt(poly2_string, poly2);
235+
236+
BOOST_CHECK_CLOSE(bg::area(poly2), 0, 0.0001);
237+
BOOST_CHECK_CLOSE(bg::area(poly2, precise_cartesian()), 0.315, 0.0001);
238+
239+
bg::model::polygon<mp_point_type> mp_poly2;
240+
bg::read_wkt(poly2_string, mp_poly2);
241+
242+
BOOST_CHECK_CLOSE(bg::area(mp_poly2), 35000000000000, 0.0001);
243+
}
244+
178245
void test_variant()
179246
{
180247
typedef bg::model::point<double, 2, bg::cs::cartesian> double_point_type;
@@ -231,6 +298,8 @@ int test_main(int, char* [])
231298

232299
test_variant();
233300

301+
test_accurate_sum_strategy();
302+
234303
// test_empty_input<bg::model::d2::point_xy<int> >();
235304

236305
return 0;

0 commit comments

Comments
 (0)