1 // Boost.Geometry (aka GGL, Generic Geometry Library)
3 // Copyright (c) 2007-2012 Barend Gehrels, Amsterdam, the Netherlands.
5 // This file was modified by Oracle on 2020.
6 // Modifications copyright (c) 2020 Oracle and/or its affiliates.
7 // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
9 // Use, modification and distribution is subject to the Boost Software License,
10 // Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
11 // http://www.boost.org/LICENSE_1_0.txt)
13 #ifndef BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_GET_RING_HPP
14 #define BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_GET_RING_HPP
17 #include <boost/range/size.hpp>
18 #include <boost/range/value_type.hpp>
20 #include <boost/geometry/core/assert.hpp>
21 #include <boost/geometry/core/exterior_ring.hpp>
22 #include <boost/geometry/core/interior_rings.hpp>
23 #include <boost/geometry/core/ring_type.hpp>
24 #include <boost/geometry/core/tags.hpp>
25 #include <boost/geometry/algorithms/detail/ring_identifier.hpp>
26 #include <boost/geometry/algorithms/detail/overlay/segment_identifier.hpp>
27 #include <boost/geometry/algorithms/num_points.hpp>
28 #include <boost/geometry/geometries/concepts/check.hpp>
29 #include <boost/geometry/util/range.hpp>
32 namespace boost { namespace geometry
36 #ifndef DOXYGEN_NO_DETAIL
37 namespace detail { namespace overlay
41 template<typename Tag>
45 // A range of rings (multi-ring but that does not exist)
46 // gets the "void" tag and is dispatched here.
50 template<typename Range>
51 static inline typename boost::range_value<Range>::type const&
52 apply(ring_identifier const& id, Range const& container)
54 return range::at(container, id.multi_index);
60 struct get_ring<ring_tag>
62 template<typename Ring>
63 static inline Ring const& apply(ring_identifier const& , Ring const& ring)
71 struct get_ring<box_tag>
73 template<typename Box>
74 static inline Box const& apply(ring_identifier const& ,
83 struct get_ring<polygon_tag>
85 template<typename Polygon>
86 static inline typename ring_return_type<Polygon const>::type const apply(
87 ring_identifier const& id,
88 Polygon const& polygon)
93 && id.ring_index < int(boost::size(interior_rings(polygon)))
95 return id.ring_index < 0
96 ? exterior_ring(polygon)
97 : range::at(interior_rings(polygon), id.ring_index);
103 struct get_ring<multi_polygon_tag>
105 template<typename MultiPolygon>
106 static inline typename ring_type<MultiPolygon>::type const& apply(
107 ring_identifier const& id,
108 MultiPolygon const& multi_polygon)
110 BOOST_GEOMETRY_ASSERT
113 && id.multi_index < int(boost::size(multi_polygon))
115 return get_ring<polygon_tag>::apply(id,
116 range::at(multi_polygon, id.multi_index));
120 // Returns the number of segments on a ring (regardless whether the ring is open or closed)
121 template <typename Geometry>
122 inline signed_size_type segment_count_on_ring(Geometry const& geometry,
123 ring_identifier const& ring_id)
125 using tag = typename geometry::tag<Geometry>::type;
127 // A closed polygon, a triangle of 4 points, including starting point,
128 // contains 3 segments. So handle as if it is closed, and subtract one.
129 return geometry::num_points(detail::overlay::get_ring<tag>::apply(ring_id, geometry), true) - 1;
132 // Returns the number of segments on a ring (regardless whether the ring is open or closed)
133 template <typename Geometry>
134 inline signed_size_type segment_count_on_ring(Geometry const& geometry,
135 segment_identifier const& seg_id)
137 return segment_count_on_ring(geometry, ring_identifier(0, seg_id.multi_index, seg_id.ring_index));
141 // Returns the distance between the second and the first segment identifier (second-first)
142 // It supports circular behavior and for this it is necessary to pass the geometry.
143 // It will not report negative values
144 template <typename Geometry>
145 inline signed_size_type segment_distance(Geometry const& geometry,
146 segment_identifier const& first, segment_identifier const& second)
148 // It is an internal function, make sure the preconditions are met
149 BOOST_ASSERT(second.source_index == first.source_index);
150 BOOST_ASSERT(second.multi_index == first.multi_index);
151 BOOST_ASSERT(second.ring_index == first.ring_index);
153 signed_size_type const result = second.segment_index - first.segment_index;
154 if (second.segment_index >= first.segment_index)
158 // Take wrap into account, counting segments on the ring (passing any of the ids is fine).
159 // Suppose point_count=10 (10 points, 9 segments), first.seg_id=7, second.seg_id=2,
160 // then distance=9-7+2=4, being segments 7,8,0,1
161 return segment_count_on_ring(geometry, first) + result;
164 }} // namespace detail::overlay
165 #endif // DOXYGEN_NO_DETAIL
168 }} // namespace boost::geometry
171 #endif // BOOST_GEOMETRY_ALGORITHMS_DETAIL_OVERLAY_GET_RING_HPP