File indexing completed on 2025-01-18 09:35:22
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017 #ifndef BOOST_GEOMETRY_ALGORITHMS_REMOVE_SPIKES_HPP
0018 #define BOOST_GEOMETRY_ALGORITHMS_REMOVE_SPIKES_HPP
0019
0020 #include <boost/range/begin.hpp>
0021 #include <boost/range/end.hpp>
0022 #include <boost/range/size.hpp>
0023
0024 #include <boost/variant/apply_visitor.hpp>
0025 #include <boost/variant/static_visitor.hpp>
0026 #include <boost/variant/variant_fwd.hpp>
0027
0028 #include <boost/geometry/core/closure.hpp>
0029 #include <boost/geometry/core/cs.hpp>
0030 #include <boost/geometry/core/interior_rings.hpp>
0031 #include <boost/geometry/core/tags.hpp>
0032
0033 #include <boost/geometry/geometries/concepts/check.hpp>
0034
0035 #include <boost/geometry/algorithms/detail/point_is_spike_or_equal.hpp>
0036 #include <boost/geometry/algorithms/clear.hpp>
0037
0038 #include <boost/geometry/strategies/default_strategy.hpp>
0039
0040 #include <boost/geometry/util/condition.hpp>
0041 #include <boost/geometry/util/range.hpp>
0042
0043
0044
0045
0046
0047
0048
0049
0050
0051
0052
0053
0054
0055
0056
0057 namespace boost { namespace geometry
0058 {
0059
0060
0061 #ifndef DOXYGEN_NO_DETAIL
0062 namespace detail { namespace remove_spikes
0063 {
0064
0065
0066 struct range_remove_spikes
0067 {
0068 template <typename Range, typename SideStrategy>
0069 static inline void apply(Range& range, SideStrategy const& strategy)
0070 {
0071 typedef typename point_type<Range>::type point_type;
0072
0073 std::size_t n = boost::size(range);
0074 std::size_t const min_num_points = core_detail::closure::minimum_ring_size
0075 <
0076 geometry::closure<Range>::value
0077 >::value - 1;
0078 if (n < min_num_points)
0079 {
0080 return;
0081 }
0082
0083 std::vector<point_type> cleaned;
0084 cleaned.reserve(n);
0085
0086 for (auto const& p : range)
0087 {
0088
0089 cleaned.push_back(p);
0090
0091 while(cleaned.size() >= 3
0092 && detail::is_spike_or_equal(range::at(cleaned, cleaned.size() - 3),
0093 range::at(cleaned, cleaned.size() - 2),
0094 range::back(cleaned),
0095 strategy))
0096 {
0097
0098 cleaned.erase(cleaned.end() - 2);
0099 }
0100 }
0101
0102 auto cleaned_b = cleaned.begin();
0103 auto cleaned_e = cleaned.end();
0104 std::size_t cleaned_count = cleaned.size();
0105
0106
0107 if ( BOOST_GEOMETRY_CONDITION(geometry::closure<Range>::value == geometry::closed) )
0108 {
0109 --cleaned_e;
0110 --cleaned_count;
0111 }
0112
0113 bool found = false;
0114 do
0115 {
0116 found = false;
0117
0118 while(cleaned_count >= 3
0119 && detail::is_spike_or_equal(*(cleaned_e - 2),
0120 *(cleaned_e - 1),
0121 *(cleaned_b),
0122 strategy))
0123 {
0124 --cleaned_e;
0125 --cleaned_count;
0126 found = true;
0127 }
0128
0129 while(cleaned_count >= 3
0130 && detail::is_spike_or_equal(*(cleaned_e - 1),
0131 *(cleaned_b),
0132 *(cleaned_b + 1),
0133 strategy))
0134 {
0135 ++cleaned_b;
0136 --cleaned_count;
0137 found = true;
0138 }
0139 }
0140 while (found);
0141
0142 if (cleaned_count == 2)
0143 {
0144
0145
0146 --cleaned_e;
0147
0148 }
0149
0150
0151 if ( BOOST_GEOMETRY_CONDITION(geometry::closure<Range>::value == geometry::closed) )
0152 {
0153 BOOST_GEOMETRY_ASSERT(cleaned_e != cleaned.end());
0154 *cleaned_e = *cleaned_b;
0155 ++cleaned_e;
0156
0157 }
0158
0159
0160 geometry::clear(range);
0161 std::copy(cleaned_b, cleaned_e, range::back_inserter(range));
0162 }
0163 };
0164
0165
0166 struct polygon_remove_spikes
0167 {
0168 template <typename Polygon, typename SideStrategy>
0169 static inline void apply(Polygon& polygon, SideStrategy const& strategy)
0170 {
0171 typedef range_remove_spikes per_range;
0172 per_range::apply(exterior_ring(polygon), strategy);
0173
0174 auto&& rings = interior_rings(polygon);
0175
0176 for (auto it = boost::begin(rings); it != boost::end(rings); ++it)
0177 {
0178 per_range::apply(*it, strategy);
0179 }
0180 }
0181 };
0182
0183
0184 template <typename SingleVersion>
0185 struct multi_remove_spikes
0186 {
0187 template <typename MultiGeometry, typename SideStrategy>
0188 static inline void apply(MultiGeometry& multi, SideStrategy const& strategy)
0189 {
0190 for (auto it = boost::begin(multi); it != boost::end(multi); ++it)
0191 {
0192 SingleVersion::apply(*it, strategy);
0193 }
0194 }
0195 };
0196
0197
0198 }}
0199 #endif
0200
0201
0202
0203 #ifndef DOXYGEN_NO_DISPATCH
0204 namespace dispatch
0205 {
0206
0207
0208 template
0209 <
0210 typename Geometry,
0211 typename Tag = typename tag<Geometry>::type
0212 >
0213 struct remove_spikes
0214 {
0215 template <typename SideStrategy>
0216 static inline void apply(Geometry&, SideStrategy const&)
0217 {}
0218 };
0219
0220
0221 template <typename Ring>
0222 struct remove_spikes<Ring, ring_tag>
0223 : detail::remove_spikes::range_remove_spikes
0224 {};
0225
0226
0227
0228 template <typename Polygon>
0229 struct remove_spikes<Polygon, polygon_tag>
0230 : detail::remove_spikes::polygon_remove_spikes
0231 {};
0232
0233
0234 template <typename MultiPolygon>
0235 struct remove_spikes<MultiPolygon, multi_polygon_tag>
0236 : detail::remove_spikes::multi_remove_spikes
0237 <
0238 detail::remove_spikes::polygon_remove_spikes
0239 >
0240 {};
0241
0242
0243 }
0244 #endif
0245
0246
0247 namespace resolve_variant {
0248
0249 template <typename Geometry>
0250 struct remove_spikes
0251 {
0252 template <typename Strategy>
0253 static void apply(Geometry& geometry, Strategy const& strategy)
0254 {
0255 concepts::check<Geometry>();
0256 dispatch::remove_spikes<Geometry>::apply(geometry, strategy);
0257 }
0258
0259 static void apply(Geometry& geometry, geometry::default_strategy const&)
0260 {
0261 typedef typename strategy::side::services::default_strategy
0262 <
0263 typename cs_tag<Geometry>::type
0264 >::type side_strategy;
0265
0266 apply(geometry, side_strategy());
0267 }
0268 };
0269
0270 template <BOOST_VARIANT_ENUM_PARAMS(typename T)>
0271 struct remove_spikes<boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> >
0272 {
0273 template <typename Strategy>
0274 struct visitor: boost::static_visitor<void>
0275 {
0276 Strategy const& m_strategy;
0277
0278 visitor(Strategy const& strategy) : m_strategy(strategy) {}
0279
0280 template <typename Geometry>
0281 void operator()(Geometry& geometry) const
0282 {
0283 remove_spikes<Geometry>::apply(geometry, m_strategy);
0284 }
0285 };
0286
0287 template <typename Strategy>
0288 static inline void apply(boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)>& geometry,
0289 Strategy const& strategy)
0290 {
0291 boost::apply_visitor(visitor<Strategy>(strategy), geometry);
0292 }
0293 };
0294
0295 }
0296
0297
0298
0299
0300
0301
0302
0303 template <typename Geometry>
0304 inline void remove_spikes(Geometry& geometry)
0305 {
0306 resolve_variant::remove_spikes<Geometry>::apply(geometry, geometry::default_strategy());
0307 }
0308
0309
0310
0311
0312
0313
0314
0315
0316 template <typename Geometry, typename Strategy>
0317 inline void remove_spikes(Geometry& geometry, Strategy const& strategy)
0318 {
0319 resolve_variant::remove_spikes<Geometry>::apply(geometry, strategy);
0320 }
0321
0322
0323 }}
0324
0325
0326 #endif