]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
1 | // Boost.Geometry (aka GGL, Generic Geometry Library) |
2 | ||
3 | // Copyright (c) 2009-2015 Mateusz Loskot, London, UK. | |
4 | // Copyright (c) 2009-2015 Barend Gehrels, Amsterdam, the Netherlands. | |
5 | ||
6 | // This file was modified by Oracle on 2015. | |
7 | // Modifications copyright (c) 2015, Oracle and/or its affiliates. | |
8 | ||
9 | // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle | |
10 | ||
11 | // Parts of Boost.Geometry are redesigned from Geodan's Geographic Library | |
12 | // (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands. | |
13 | ||
14 | // Use, modification and distribution is subject to the Boost Software License, | |
15 | // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at | |
16 | // http://www.boost.org/LICENSE_1_0.txt) | |
17 | ||
18 | #ifndef BOOST_GEOMETRY_STRATEGIES_CARTESIAN_CENTROID_WEIGHTED_LENGTH_HPP | |
19 | #define BOOST_GEOMETRY_STRATEGIES_CARTESIAN_CENTROID_WEIGHTED_LENGTH_HPP | |
20 | ||
21 | #include <boost/math/special_functions/fpclassify.hpp> | |
22 | #include <boost/numeric/conversion/cast.hpp> | |
23 | ||
24 | #include <boost/geometry/algorithms/detail/distance/interface.hpp> | |
25 | #include <boost/geometry/algorithms/detail/distance/point_to_geometry.hpp> | |
26 | #include <boost/geometry/arithmetic/arithmetic.hpp> | |
27 | #include <boost/geometry/util/for_each_coordinate.hpp> | |
28 | #include <boost/geometry/util/select_most_precise.hpp> | |
29 | #include <boost/geometry/strategies/centroid.hpp> | |
30 | #include <boost/geometry/strategies/default_distance_result.hpp> | |
31 | ||
32 | // Helper geometry | |
33 | #include <boost/geometry/geometries/point.hpp> | |
34 | ||
35 | ||
36 | namespace boost { namespace geometry | |
37 | { | |
38 | ||
39 | namespace strategy { namespace centroid | |
40 | { | |
41 | ||
42 | namespace detail | |
43 | { | |
44 | ||
45 | template <typename Type, std::size_t DimensionCount> | |
46 | struct weighted_length_sums | |
47 | { | |
48 | typedef typename geometry::model::point | |
49 | < | |
50 | Type, DimensionCount, | |
51 | cs::cartesian | |
52 | > work_point; | |
53 | ||
54 | Type length; | |
55 | work_point average_sum; | |
56 | ||
57 | inline weighted_length_sums() | |
58 | : length(Type()) | |
59 | { | |
60 | geometry::assign_zero(average_sum); | |
61 | } | |
62 | }; | |
63 | } | |
64 | ||
65 | template | |
66 | < | |
67 | typename Point, | |
68 | typename PointOfSegment = Point | |
69 | > | |
70 | class weighted_length | |
71 | { | |
72 | private : | |
73 | typedef typename select_most_precise | |
74 | < | |
75 | typename default_distance_result<Point>::type, | |
76 | typename default_distance_result<PointOfSegment>::type | |
77 | >::type distance_type; | |
78 | ||
79 | public : | |
80 | typedef detail::weighted_length_sums | |
81 | < | |
82 | distance_type, | |
83 | geometry::dimension<Point>::type::value | |
84 | > state_type; | |
85 | ||
86 | static inline void apply(PointOfSegment const& p1, | |
87 | PointOfSegment const& p2, state_type& state) | |
88 | { | |
89 | distance_type const d = geometry::distance(p1, p2); | |
90 | state.length += d; | |
91 | ||
92 | typename state_type::work_point weighted_median; | |
93 | geometry::assign_zero(weighted_median); | |
94 | geometry::add_point(weighted_median, p1); | |
95 | geometry::add_point(weighted_median, p2); | |
96 | geometry::multiply_value(weighted_median, d/2); | |
97 | geometry::add_point(state.average_sum, weighted_median); | |
98 | } | |
99 | ||
100 | static inline bool result(state_type const& state, Point& centroid) | |
101 | { | |
102 | distance_type const zero = distance_type(); | |
103 | if (! geometry::math::equals(state.length, zero) | |
104 | && boost::math::isfinite(state.length)) // Prevent NaN centroid coordinates | |
105 | { | |
106 | // NOTE: above distance_type is checked, not the centroid coordinate_type | |
107 | // which means that the centroid can still be filled with INF | |
108 | // if e.g. distance_type is double and centroid contains floats | |
109 | geometry::for_each_coordinate(centroid, set_sum_div_length(state)); | |
110 | return true; | |
111 | } | |
112 | ||
113 | return false; | |
114 | } | |
115 | ||
116 | struct set_sum_div_length | |
117 | { | |
118 | state_type const& m_state; | |
119 | set_sum_div_length(state_type const& state) | |
120 | : m_state(state) | |
121 | {} | |
122 | template <typename Pt, std::size_t Dimension> | |
123 | void apply(Pt & centroid) const | |
124 | { | |
125 | typedef typename geometry::coordinate_type<Pt>::type coordinate_type; | |
126 | geometry::set<Dimension>( | |
127 | centroid, | |
128 | boost::numeric_cast<coordinate_type>( | |
129 | geometry::get<Dimension>(m_state.average_sum) / m_state.length | |
130 | ) | |
131 | ); | |
132 | } | |
133 | }; | |
134 | }; | |
135 | ||
136 | #ifndef DOXYGEN_NO_STRATEGY_SPECIALIZATIONS | |
137 | ||
138 | namespace services | |
139 | { | |
140 | ||
141 | ||
142 | // Register this strategy for linear geometries, in all dimensions | |
143 | ||
144 | template <std::size_t N, typename Point, typename Geometry> | |
145 | struct default_strategy | |
146 | < | |
147 | cartesian_tag, | |
148 | linear_tag, | |
149 | N, | |
150 | Point, | |
151 | Geometry | |
152 | > | |
153 | { | |
154 | typedef weighted_length | |
155 | < | |
156 | Point, | |
157 | typename point_type<Geometry>::type | |
158 | > type; | |
159 | }; | |
160 | ||
161 | ||
162 | } // namespace services | |
163 | ||
164 | ||
165 | #endif // DOXYGEN_NO_STRATEGY_SPECIALIZATIONS | |
166 | ||
167 | ||
168 | }} // namespace strategy::centroid | |
169 | ||
170 | ||
171 | }} // namespace boost::geometry | |
172 | ||
173 | ||
174 | #endif // BOOST_GEOMETRY_STRATEGIES_CARTESIAN_CENTROID_WEIGHTED_LENGTH_HPP |