1 // Boost.Geometry (aka GGL, Generic Geometry Library)
2 
3 // Copyright (c) 2007-2014 Barend Gehrels, Amsterdam, the Netherlands.
4 // Copyright (c) 2008-2014 Bruno Lalande, Paris, France.
5 // Copyright (c) 2009-2014 Mateusz Loskot, London, UK.
6 
7 // This file was modified by Oracle on 2014-2021.
8 // Modifications copyright (c) 2014-2021, Oracle and/or its affiliates.
9 
10 // Contributed and/or modified by Menelaos Karavelas, on behalf of Oracle
11 // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
12 
13 // Parts of Boost.Geometry are redesigned from Geodan's Geographic Library
14 // (geolib/GGL), copyright (c) 1995-2010 Geodan, Amsterdam, the Netherlands.
15 
16 // Use, modification and distribution is subject to the Boost Software License,
17 // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
18 // http://www.boost.org/LICENSE_1_0.txt)
19 
20 #ifndef BOOST_GEOMETRY_ALGORITHMS_LENGTH_HPP
21 #define BOOST_GEOMETRY_ALGORITHMS_LENGTH_HPP
22 
23 #include <iterator>
24 
25 #include <boost/core/ignore_unused.hpp>
26 #include <boost/range/begin.hpp>
27 #include <boost/range/end.hpp>
28 #include <boost/range/iterator.hpp>
29 #include <boost/range/value_type.hpp>
30 
31 #include <boost/geometry/algorithms/assign.hpp>
32 #include <boost/geometry/algorithms/detail/calculate_null.hpp>
33 #include <boost/geometry/algorithms/detail/dummy_geometries.hpp>
34 #include <boost/geometry/algorithms/detail/multi_sum.hpp>
35 // #include <boost/geometry/algorithms/detail/throw_on_empty_input.hpp>
36 #include <boost/geometry/algorithms/detail/visit.hpp>
37 
38 #include <boost/geometry/core/cs.hpp>
39 #include <boost/geometry/core/closure.hpp>
40 #include <boost/geometry/core/tag.hpp>
41 #include <boost/geometry/core/tags.hpp>
42 #include <boost/geometry/core/visit.hpp>
43 
44 #include <boost/geometry/geometries/adapted/boost_variant.hpp> // For backward compatibility
45 #include <boost/geometry/geometries/concepts/check.hpp>
46 
47 #include <boost/geometry/strategies/default_strategy.hpp>
48 #include <boost/geometry/strategies/default_length_result.hpp> // TODO: Move to algorithms
49 #include <boost/geometry/strategies/detail.hpp>
50 #include <boost/geometry/strategies/length/cartesian.hpp>
51 #include <boost/geometry/strategies/length/geographic.hpp>
52 #include <boost/geometry/strategies/length/spherical.hpp>
53 
54 #include <boost/geometry/views/closeable_view.hpp>
55 
56 namespace boost { namespace geometry
57 {
58 
59 
60 #ifndef DOXYGEN_NO_DETAIL
61 namespace detail { namespace length
62 {
63 
64 
65 template<typename Segment>
66 struct segment_length
67 {
68     template <typename Strategies>
69     static inline typename default_length_result<Segment>::type
applyboost::geometry::detail::length::segment_length70     apply(Segment const& segment, Strategies const& strategies)
71     {
72         typedef typename point_type<Segment>::type point_type;
73         point_type p1, p2;
74         geometry::detail::assign_point_from_index<0>(segment, p1);
75         geometry::detail::assign_point_from_index<1>(segment, p2);
76         return strategies.distance(p1, p2).apply(p1, p2);
77     }
78 };
79 
80 /*!
81 \brief Internal, calculates length of a linestring using iterator pairs and
82     specified strategy
83 \note for_each could be used here, now that point_type is changed by boost
84     range iterator
85 */
86 template<typename Range, closure_selector Closure>
87 struct range_length
88 {
89     typedef typename default_length_result<Range>::type return_type;
90 
91     template <typename Strategies>
92     static inline return_type
applyboost::geometry::detail::length::range_length93     apply(Range const& range, Strategies const& strategies)
94     {
95         return_type sum = return_type();
96         detail::closed_view<Range const> const view(range);
97         auto it = boost::begin(view);
98         auto const end = boost::end(view);
99         if (it != end)
100         {
101             auto const strategy = strategies.distance(dummy_point(), dummy_point());
102 
103             for(auto previous = it++; it != end; ++previous, ++it)
104             {
105                 // Add point-point distance using the return type belonging
106                 // to strategy
107                 sum += strategy.apply(*previous, *it);
108             }
109         }
110 
111         return sum;
112     }
113 };
114 
115 
116 }} // namespace detail::length
117 #endif // DOXYGEN_NO_DETAIL
118 
119 
120 #ifndef DOXYGEN_NO_DISPATCH
121 namespace dispatch
122 {
123 
124 
125 template <typename Geometry, typename Tag = typename tag<Geometry>::type>
126 struct length : detail::calculate_null
127 {
128     typedef typename default_length_result<Geometry>::type return_type;
129 
130     template <typename Strategy>
applyboost::geometry::dispatch::length131     static inline return_type apply(Geometry const& geometry, Strategy const& strategy)
132     {
133         return calculate_null::apply<return_type>(geometry, strategy);
134     }
135 };
136 
137 
138 template <typename Geometry>
139 struct length<Geometry, linestring_tag>
140     : detail::length::range_length<Geometry, closed>
141 {};
142 
143 
144 // RING: length is currently 0; it might be argued that it is the "perimeter"
145 
146 
147 template <typename Geometry>
148 struct length<Geometry, segment_tag>
149     : detail::length::segment_length<Geometry>
150 {};
151 
152 
153 template <typename MultiLinestring>
154 struct length<MultiLinestring, multi_linestring_tag> : detail::multi_sum
155 {
156     template <typename Strategy>
157     static inline typename default_length_result<MultiLinestring>::type
applyboost::geometry::dispatch::length158     apply(MultiLinestring const& multi, Strategy const& strategy)
159     {
160         return multi_sum::apply
161                <
162                    typename default_length_result<MultiLinestring>::type,
163                    detail::length::range_length
164                    <
165                        typename boost::range_value<MultiLinestring>::type,
166                        closed // no need to close it explicitly
167                    >
168                >(multi, strategy);
169 
170     }
171 };
172 
173 
174 } // namespace dispatch
175 #endif // DOXYGEN_NO_DISPATCH
176 
177 
178 namespace resolve_strategy {
179 
180 template
181 <
182     typename Strategies,
183     bool IsUmbrella = strategies::detail::is_umbrella_strategy<Strategies>::value
184 >
185 struct length
186 {
187     template <typename Geometry>
188     static inline typename default_length_result<Geometry>::type
applyboost::geometry::resolve_strategy::length189     apply(Geometry const& geometry, Strategies const& strategies)
190     {
191         return dispatch::length<Geometry>::apply(geometry, strategies);
192     }
193 };
194 
195 template <typename Strategy>
196 struct length<Strategy, false>
197 {
198     template <typename Geometry>
199     static inline typename default_length_result<Geometry>::type
applyboost::geometry::resolve_strategy::length200     apply(Geometry const& geometry, Strategy const& strategy)
201     {
202         using strategies::length::services::strategy_converter;
203         return dispatch::length<Geometry>::apply(
204                 geometry, strategy_converter<Strategy>::get(strategy));
205     }
206 };
207 
208 template <>
209 struct length<default_strategy, false>
210 {
211     template <typename Geometry>
212     static inline typename default_length_result<Geometry>::type
applyboost::geometry::resolve_strategy::length213     apply(Geometry const& geometry, default_strategy const&)
214     {
215         typedef typename strategies::length::services::default_strategy
216             <
217                 Geometry
218             >::type strategies_type;
219 
220         return dispatch::length<Geometry>::apply(geometry, strategies_type());
221     }
222 };
223 
224 } // namespace resolve_strategy
225 
226 
227 namespace resolve_dynamic {
228 
229 template <typename Geometry, typename Tag = typename geometry::tag<Geometry>::type>
230 struct length
231 {
232     template <typename Strategy>
233     static inline typename default_length_result<Geometry>::type
applyboost::geometry::resolve_dynamic::length234     apply(Geometry const& geometry, Strategy const& strategy)
235     {
236         return resolve_strategy::length<Strategy>::apply(geometry, strategy);
237     }
238 };
239 
240 template <typename Geometry>
241 struct length<Geometry, dynamic_geometry_tag>
242 {
243     template <typename Strategy>
244     static inline typename default_length_result<Geometry>::type
applyboost::geometry::resolve_dynamic::length245         apply(Geometry const& geometry, Strategy const& strategy)
246     {
247         typename default_length_result<Geometry>::type result = 0;
248         traits::visit<Geometry>::apply([&](auto const& g)
249         {
250             result = length<util::remove_cref_t<decltype(g)>>::apply(g, strategy);
251         }, geometry);
252         return result;
253     }
254 };
255 
256 template <typename Geometry>
257 struct length<Geometry, geometry_collection_tag>
258 {
259     template <typename Strategy>
260     static inline typename default_length_result<Geometry>::type
applyboost::geometry::resolve_dynamic::length261         apply(Geometry const& geometry, Strategy const& strategy)
262     {
263         typename default_length_result<Geometry>::type result = 0;
264         detail::visit_breadth_first([&](auto const& g)
265         {
266             result += length<util::remove_cref_t<decltype(g)>>::apply(g, strategy);
267             return true;
268         }, geometry);
269         return result;
270     }
271 };
272 
273 } // namespace resolve_dynamic
274 
275 
276 /*!
277 \brief \brief_calc{length}
278 \ingroup length
279 \details \details_calc{length, length (the sum of distances between consecutive points)}. \details_default_strategy
280 \tparam Geometry \tparam_geometry
281 \param geometry \param_geometry
282 \return \return_calc{length}
283 
284 \qbk{[include reference/algorithms/length.qbk]}
285 \qbk{[length] [length_output]}
286  */
287 template<typename Geometry>
288 inline typename default_length_result<Geometry>::type
length(Geometry const & geometry)289 length(Geometry const& geometry)
290 {
291     concepts::check<Geometry const>();
292 
293     // detail::throw_on_empty_input(geometry);
294 
295     return resolve_dynamic::length<Geometry>::apply(geometry, default_strategy());
296 }
297 
298 
299 /*!
300 \brief \brief_calc{length} \brief_strategy
301 \ingroup length
302 \details \details_calc{length, length (the sum of distances between consecutive points)} \brief_strategy. \details_strategy_reasons
303 \tparam Geometry \tparam_geometry
304 \tparam Strategy \tparam_strategy{distance}
305 \param geometry \param_geometry
306 \param strategy \param_strategy{distance}
307 \return \return_calc{length}
308 
309 \qbk{distinguish,with strategy}
310 \qbk{[include reference/algorithms/length.qbk]}
311 \qbk{[length_with_strategy] [length_with_strategy_output]}
312  */
313 template<typename Geometry, typename Strategy>
314 inline typename default_length_result<Geometry>::type
length(Geometry const & geometry,Strategy const & strategy)315 length(Geometry const& geometry, Strategy const& strategy)
316 {
317     concepts::check<Geometry const>();
318 
319     // detail::throw_on_empty_input(geometry);
320 
321     return resolve_dynamic::length<Geometry>::apply(geometry, strategy);
322 }
323 
324 
325 }} // namespace boost::geometry
326 
327 #endif // BOOST_GEOMETRY_ALGORITHMS_LENGTH_HPP
328