File indexing completed on 2025-01-18 09:35:21
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011 #ifndef BOOST_GEOMETRY_ALGORITHMS_LINE_INTERPOLATE_HPP
0012 #define BOOST_GEOMETRY_ALGORITHMS_LINE_INTERPOLATE_HPP
0013
0014 #include <type_traits>
0015
0016 #include <boost/range/begin.hpp>
0017 #include <boost/range/end.hpp>
0018 #include <boost/range/value_type.hpp>
0019 #include <boost/variant/apply_visitor.hpp>
0020 #include <boost/variant/static_visitor.hpp>
0021 #include <boost/variant/variant_fwd.hpp>
0022
0023 #include <boost/geometry/algorithms/detail/convert_point_to_point.hpp>
0024 #include <boost/geometry/algorithms/detail/dummy_geometries.hpp>
0025
0026 #include <boost/geometry/core/exception.hpp>
0027 #include <boost/geometry/core/static_assert.hpp>
0028 #include <boost/geometry/core/tags.hpp>
0029
0030 #include <boost/geometry/geometries/concepts/check.hpp>
0031
0032 #include <boost/geometry/strategies/default_strategy.hpp>
0033 #include <boost/geometry/strategies/detail.hpp>
0034 #include <boost/geometry/strategies/line_interpolate/cartesian.hpp>
0035 #include <boost/geometry/strategies/line_interpolate/geographic.hpp>
0036 #include <boost/geometry/strategies/line_interpolate/spherical.hpp>
0037
0038 #include <boost/geometry/util/condition.hpp>
0039 #include <boost/geometry/util/range.hpp>
0040 #include <boost/geometry/util/type_traits.hpp>
0041
0042 #include <boost/geometry/views/segment_view.hpp>
0043
0044 namespace boost { namespace geometry
0045 {
0046
0047
0048 #ifndef DOXYGEN_NO_DETAIL
0049 namespace detail { namespace line_interpolate
0050 {
0051
0052 struct convert_and_push_back
0053 {
0054 template <typename Range, typename Point>
0055 static inline void apply(Point const& p, Range& range)
0056 {
0057 typename boost::range_value<Range>::type p2;
0058 geometry::detail::conversion::convert_point_to_point(p, p2);
0059 range::push_back(range, p2);
0060 }
0061 };
0062
0063 struct convert_and_assign
0064 {
0065 template <typename Point1, typename Point2>
0066 static inline void apply(Point1 const& p1, Point2& p2)
0067 {
0068 geometry::detail::conversion::convert_point_to_point(p1, p2);
0069 }
0070
0071 };
0072
0073
0074
0075
0076
0077
0078 template <typename Policy>
0079 struct interpolate_range
0080 {
0081 template
0082 <
0083 typename Range,
0084 typename Distance,
0085 typename PointLike,
0086 typename Strategies
0087 >
0088 static inline void apply(Range const& range,
0089 Distance const& max_distance,
0090 PointLike & pointlike,
0091 Strategies const& strategies)
0092 {
0093 typedef typename boost::range_value<Range const>::type point_t;
0094
0095 auto it = boost::begin(range);
0096 auto const end = boost::end(range);
0097
0098 if (it == end)
0099 {
0100 BOOST_THROW_EXCEPTION(empty_input_exception());
0101 return;
0102 }
0103 if (max_distance <= 0)
0104 {
0105 Policy::apply(*it, pointlike);
0106 return;
0107 }
0108
0109 auto const pp_strategy = strategies.distance(dummy_point(), dummy_point());
0110 auto const strategy = strategies.line_interpolate(range);
0111
0112 typedef decltype(pp_strategy.apply(
0113 std::declval<point_t>(), std::declval<point_t>())) distance_type;
0114
0115 auto prev = it++;
0116 distance_type repeated_distance = max_distance;
0117 distance_type prev_distance = 0;
0118 distance_type current_distance = 0;
0119 point_t start_p = *prev;
0120
0121 for ( ; it != end ; ++it)
0122 {
0123 distance_type dist = pp_strategy.apply(*prev, *it);
0124 current_distance = prev_distance + dist;
0125
0126 while (current_distance >= repeated_distance)
0127 {
0128 point_t p;
0129 distance_type diff_distance = current_distance - prev_distance;
0130 BOOST_ASSERT(diff_distance != distance_type(0));
0131 strategy.apply(start_p, *it,
0132 (repeated_distance - prev_distance)/diff_distance,
0133 p,
0134 diff_distance);
0135 Policy::apply(p, pointlike);
0136 if ( BOOST_GEOMETRY_CONDITION(util::is_point<PointLike>::value) )
0137 {
0138 return;
0139 }
0140 start_p = p;
0141 prev_distance = repeated_distance;
0142 repeated_distance += max_distance;
0143 }
0144 prev_distance = current_distance;
0145 prev = it;
0146 start_p = *prev;
0147 }
0148
0149
0150
0151 if (repeated_distance == max_distance)
0152 {
0153 Policy::apply(*(end-1), pointlike);
0154 }
0155 }
0156 };
0157
0158 template <typename Policy>
0159 struct interpolate_segment
0160 {
0161 template <typename Segment, typename Distance, typename Pointlike, typename Strategy>
0162 static inline void apply(Segment const& segment,
0163 Distance const& max_distance,
0164 Pointlike & point,
0165 Strategy const& strategy)
0166 {
0167 interpolate_range<Policy>().apply(segment_view<Segment>(segment),
0168 max_distance, point, strategy);
0169 }
0170 };
0171
0172 }}
0173 #endif
0174
0175
0176 #ifndef DOXYGEN_NO_DISPATCH
0177 namespace dispatch
0178 {
0179
0180
0181 template
0182 <
0183 typename Geometry,
0184 typename Pointlike,
0185 typename Tag1 = typename tag<Geometry>::type,
0186 typename Tag2 = typename tag<Pointlike>::type
0187 >
0188 struct line_interpolate
0189 {
0190 BOOST_GEOMETRY_STATIC_ASSERT_FALSE(
0191 "Not implemented for this Geometry type.",
0192 Geometry, Pointlike);
0193 };
0194
0195
0196 template <typename Geometry, typename Pointlike>
0197 struct line_interpolate<Geometry, Pointlike, linestring_tag, point_tag>
0198 : detail::line_interpolate::interpolate_range
0199 <
0200 detail::line_interpolate::convert_and_assign
0201 >
0202 {};
0203
0204 template <typename Geometry, typename Pointlike>
0205 struct line_interpolate<Geometry, Pointlike, linestring_tag, multi_point_tag>
0206 : detail::line_interpolate::interpolate_range
0207 <
0208 detail::line_interpolate::convert_and_push_back
0209 >
0210 {};
0211
0212 template <typename Geometry, typename Pointlike>
0213 struct line_interpolate<Geometry, Pointlike, segment_tag, point_tag>
0214 : detail::line_interpolate::interpolate_segment
0215 <
0216 detail::line_interpolate::convert_and_assign
0217 >
0218 {};
0219
0220 template <typename Geometry, typename Pointlike>
0221 struct line_interpolate<Geometry, Pointlike, segment_tag, multi_point_tag>
0222 : detail::line_interpolate::interpolate_segment
0223 <
0224 detail::line_interpolate::convert_and_push_back
0225 >
0226 {};
0227
0228 }
0229 #endif
0230
0231
0232 namespace resolve_strategy {
0233
0234 template
0235 <
0236 typename Strategies,
0237 bool IsUmbrella = strategies::detail::is_umbrella_strategy<Strategies>::value
0238 >
0239 struct line_interpolate
0240 {
0241 template <typename Geometry, typename Distance, typename Pointlike>
0242 static inline void apply(Geometry const& geometry,
0243 Distance const& max_distance,
0244 Pointlike & pointlike,
0245 Strategies const& strategies)
0246 {
0247 dispatch::line_interpolate
0248 <
0249 Geometry, Pointlike
0250 >::apply(geometry, max_distance, pointlike, strategies);
0251 }
0252 };
0253
0254 template <typename Strategy>
0255 struct line_interpolate<Strategy, false>
0256 {
0257 template <typename Geometry, typename Distance, typename Pointlike>
0258 static inline void apply(Geometry const& geometry,
0259 Distance const& max_distance,
0260 Pointlike & pointlike,
0261 Strategy const& strategy)
0262 {
0263 using strategies::line_interpolate::services::strategy_converter;
0264
0265 dispatch::line_interpolate
0266 <
0267 Geometry, Pointlike
0268 >::apply(geometry, max_distance, pointlike,
0269 strategy_converter<Strategy>::get(strategy));
0270 }
0271 };
0272
0273 template <>
0274 struct line_interpolate<default_strategy, false>
0275 {
0276 template <typename Geometry, typename Distance, typename Pointlike>
0277 static inline void apply(Geometry const& geometry,
0278 Distance const& max_distance,
0279 Pointlike & pointlike,
0280 default_strategy)
0281 {
0282 typedef typename strategies::line_interpolate::services::default_strategy
0283 <
0284 Geometry
0285 >::type strategy_type;
0286
0287 dispatch::line_interpolate
0288 <
0289 Geometry, Pointlike
0290 >::apply(geometry, max_distance, pointlike, strategy_type());
0291 }
0292 };
0293
0294 }
0295
0296
0297 namespace resolve_variant {
0298
0299 template <typename Geometry>
0300 struct line_interpolate
0301 {
0302 template <typename Distance, typename Pointlike, typename Strategy>
0303 static inline void apply(Geometry const& geometry,
0304 Distance const& max_distance,
0305 Pointlike & pointlike,
0306 Strategy const& strategy)
0307 {
0308 return resolve_strategy::line_interpolate
0309 <
0310 Strategy
0311 >::apply(geometry, max_distance, pointlike, strategy);
0312 }
0313 };
0314
0315 template <BOOST_VARIANT_ENUM_PARAMS(typename T)>
0316 struct line_interpolate<boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> >
0317 {
0318 template <typename Pointlike, typename Strategy>
0319 struct visitor: boost::static_visitor<void>
0320 {
0321 Pointlike const& m_pointlike;
0322 Strategy const& m_strategy;
0323
0324 visitor(Pointlike const& pointlike, Strategy const& strategy)
0325 : m_pointlike(pointlike)
0326 , m_strategy(strategy)
0327 {}
0328
0329 template <typename Geometry, typename Distance>
0330 void operator()(Geometry const& geometry, Distance const& max_distance) const
0331 {
0332 line_interpolate<Geometry>::apply(geometry, max_distance,
0333 m_pointlike, m_strategy);
0334 }
0335 };
0336
0337 template <typename Distance, typename Pointlike, typename Strategy>
0338 static inline void
0339 apply(boost::variant<BOOST_VARIANT_ENUM_PARAMS(T)> const& geometry,
0340 Distance const& max_distance,
0341 Pointlike & pointlike,
0342 Strategy const& strategy)
0343 {
0344 boost::apply_visitor(
0345 visitor<Pointlike, Strategy>(pointlike, strategy),
0346 geometry,
0347 max_distance
0348 );
0349 }
0350 };
0351
0352 }
0353
0354
0355
0356
0357
0358
0359
0360
0361
0362
0363
0364
0365
0366
0367
0368
0369
0370
0371
0372
0373
0374
0375
0376
0377
0378
0379
0380
0381
0382
0383
0384
0385
0386
0387 template
0388 <
0389 typename Geometry,
0390 typename Distance,
0391 typename Pointlike,
0392 typename Strategy
0393 >
0394 inline void line_interpolate(Geometry const& geometry,
0395 Distance const& max_distance,
0396 Pointlike & pointlike,
0397 Strategy const& strategy)
0398 {
0399 concepts::check<Geometry const>();
0400
0401
0402
0403 return resolve_variant::line_interpolate<Geometry>
0404 ::apply(geometry, max_distance, pointlike, strategy);
0405 }
0406
0407
0408
0409
0410
0411
0412
0413
0414
0415
0416
0417
0418
0419
0420
0421
0422
0423
0424
0425
0426
0427
0428
0429
0430 template<typename Geometry, typename Distance, typename Pointlike>
0431 inline void line_interpolate(Geometry const& geometry,
0432 Distance const& max_distance,
0433 Pointlike & pointlike)
0434 {
0435 concepts::check<Geometry const>();
0436
0437
0438
0439 return resolve_variant::line_interpolate<Geometry>
0440 ::apply(geometry, max_distance, pointlike, default_strategy());
0441 }
0442
0443 }}
0444
0445 #endif