1 // Boost.Geometry (aka GGL, Generic Geometry Library)
2 
3 // Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
4 // Copyright (c) 2008-2012 Bruno Lalande, Paris, France.
5 // Copyright (c) 2009-2012 Mateusz Loskot, London, UK.
6 
7 // This file was modified by Oracle on 2016, 2017.
8 // Modifications copyright (c) 2016-2017, Oracle and/or its affiliates.
9 
10 // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
11 
12 // Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
13 // (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
14 
15 // Use, modification and distribution is subject to the Boost Software License,
16 // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
17 // http://www.boost.org/LICENSE_1_0.txt)
18 
19 #ifndef BOOST_GEOMETRY_STRATEGIES_CARTESIAN_AREA_SURVEYOR_HPP
20 #define BOOST_GEOMETRY_STRATEGIES_CARTESIAN_AREA_SURVEYOR_HPP
21 
22 
23 #include <boost/mpl/if.hpp>
24 
25 //#include <boost/geometry/arithmetic/determinant.hpp>
26 #include <boost/geometry/core/coordinate_type.hpp>
27 #include <boost/geometry/core/coordinate_dimension.hpp>
28 #include <boost/geometry/strategies/area.hpp>
29 #include <boost/geometry/util/select_most_precise.hpp>
30 
31 
32 namespace boost { namespace geometry
33 {
34 
35 namespace strategy { namespace area
36 {
37 
38 /*!
39 \brief Area calculation for cartesian points
40 \ingroup strategies
41 \details Calculates area using the Surveyor's formula, a well-known
42     triangulation algorithm
43 \tparam PointOfSegment \tparam_segment_point
44 \tparam CalculationType \tparam_calculation
45 
46 \qbk{
47 [heading See also]
48 [link geometry.reference.algorithms.area.area_2_with_strategy area (with strategy)]
49 }
50 
51 */
52 template
53 <
54     typename PointOfSegment,
55     typename CalculationType = void
56 >
57 class surveyor
58 {
59 public :
60     // If user specified a calculation type, use that type,
61     //   whatever it is and whatever the point-type is.
62     // Else, use the pointtype, but at least double
63     typedef typename
64         boost::mpl::if_c
65         <
66             boost::is_void<CalculationType>::type::value,
67             typename select_most_precise
68             <
69                 typename coordinate_type<PointOfSegment>::type,
70                 double
71             >::type,
72             CalculationType
73         >::type return_type;
74 
75 
76 private :
77 
78     class summation
79     {
80         friend class surveyor;
81 
82         return_type sum;
83     public :
84 
summation()85         inline summation() : sum(return_type())
86         {
87             // Strategy supports only 2D areas
88             assert_dimension<PointOfSegment, 2>();
89         }
area() const90         inline return_type area() const
91         {
92             return_type result = sum;
93             return_type const two = 2;
94             result /= two;
95             return result;
96         }
97     };
98 
99 public :
100     typedef summation state_type;
101     typedef PointOfSegment segment_point_type;
102 
apply(PointOfSegment const & p1,PointOfSegment const & p2,summation & state)103     static inline void apply(PointOfSegment const& p1,
104                 PointOfSegment const& p2,
105                 summation& state)
106     {
107         // Below formulas are equivalent, however the two lower ones
108         // suffer less from accuracy loss for great values of coordinates.
109         // See: https://svn.boost.org/trac/boost/ticket/11928
110 
111         // SUM += x2 * y1 - x1 * y2;
112         // state.sum += detail::determinant<return_type>(p2, p1);
113 
114         // SUM += (x2 - x1) * (y2 + y1)
115         //state.sum += (return_type(get<0>(p2)) - return_type(get<0>(p1)))
116         //           * (return_type(get<1>(p2)) + return_type(get<1>(p1)));
117 
118         // SUM += (x1 + x2) * (y1 - y2)
119         state.sum += (return_type(get<0>(p1)) + return_type(get<0>(p2)))
120                    * (return_type(get<1>(p1)) - return_type(get<1>(p2)));
121     }
122 
result(summation const & state)123     static inline return_type result(summation const& state)
124     {
125         return state.area();
126     }
127 
128 };
129 
130 #ifndef DOXYGEN_NO_STRATEGY_SPECIALIZATIONS
131 
132 namespace services
133 {
134     template <typename Point>
135     struct default_strategy<cartesian_tag, Point>
136     {
137         typedef strategy::area::surveyor<Point> type;
138     };
139 
140 } // namespace services
141 
142 #endif // DOXYGEN_NO_STRATEGY_SPECIALIZATIONS
143 
144 
145 }} // namespace strategy::area
146 
147 
148 
149 }} // namespace boost::geometry
150 
151 
152 #endif // BOOST_GEOMETRY_STRATEGIES_CARTESIAN_AREA_SURVEYOR_HPP
153