// Boost.Geometry // Copyright (c) 2017-2018, Oracle and/or its affiliates. // Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle // Licensed under the Boost Software License version 1.0. // http://www.boost.org/users/license.html #ifndef BOOST_GEOMETRY_ALGORITHMS_DENSIFY_HPP #define BOOST_GEOMETRY_ALGORITHMS_DENSIFY_HPP #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace boost { namespace geometry { #ifndef DOXYGEN_NO_DETAIL namespace detail { namespace densify { template struct push_back_policy { typedef typename boost::range_value::type point_type; inline explicit push_back_policy(Range & rng) : m_rng(rng) {} inline void apply(point_type const& p) { range::push_back(m_rng, p); } private: Range & m_rng; }; template inline void convert_and_push_back(Range & range, Point const& p) { typename boost::range_value::type p2; geometry::detail::conversion::convert_point_to_point(p, p2); range::push_back(range, p2); } template struct densify_range { template static inline void apply(FwdRng const& rng, MutRng & rng_out, T const& len, Strategy const& strategy) { typedef typename boost::range_iterator::type iterator_t; typedef typename boost::range_value::type point_t; iterator_t it = boost::begin(rng); iterator_t end = boost::end(rng); if (it == end) // empty(rng) { return; } push_back_policy policy(rng_out); iterator_t prev = it; for ( ++it ; it != end ; prev = it++) { point_t const& p0 = *prev; point_t const& p1 = *it; convert_and_push_back(rng_out, p0); strategy.apply(p0, p1, policy, len); } if (BOOST_GEOMETRY_CONDITION(AppendLastPoint)) { convert_and_push_back(rng_out, *prev); // back(rng) } } }; template // false, X struct densify_ring { template static inline void apply(Geometry const& ring, GeometryOut & ring_out, T const& len, Strategy const& strategy) { geometry::detail::densify::densify_range ::apply(ring, ring_out, len, strategy); if (boost::size(ring) <= 1) return; typedef typename point_type::type point_t; point_t const& p0 = range::back(ring); point_t const& p1 = range::front(ring); push_back_policy policy(ring_out); strategy.apply(p0, p1, policy, len); if (BOOST_GEOMETRY_CONDITION(IsClosed2)) { convert_and_push_back(ring_out, p1); } } }; template <> struct densify_ring : densify_range {}; template <> struct densify_ring : densify_range {}; }} // namespace detail::densify #endif // DOXYGEN_NO_DETAIL #ifndef DOXYGEN_NO_DISPATCH namespace dispatch { template < typename Geometry, typename GeometryOut, typename Tag1 = typename tag::type, typename Tag2 = typename tag::type > struct densify : not_implemented {}; template struct densify : geometry::detail::densify::densify_range<> {}; template struct densify { template static void apply(Geometry const& mls, GeometryOut & mls_out, T const& len, Strategy const& strategy) { std::size_t count = boost::size(mls); range::resize(mls_out, count); for (std::size_t i = 0 ; i < count ; ++i) { geometry::detail::densify::densify_range<> ::apply(range::at(mls, i), range::at(mls_out, i), len, strategy); } } }; template struct densify : geometry::detail::densify::densify_ring < geometry::closure::value != geometry::open, geometry::closure::value != geometry::open > {}; template struct densify { template static void apply(Geometry const& poly, GeometryOut & poly_out, T const& len, Strategy const& strategy) { apply_ring(exterior_ring(poly), exterior_ring(poly_out), len, strategy); std::size_t count = boost::size(interior_rings(poly)); range::resize(interior_rings(poly_out), count); for (std::size_t i = 0 ; i < count ; ++i) { apply_ring(range::at(interior_rings(poly), i), range::at(interior_rings(poly_out), i), len, strategy); } } template static void apply_ring(Ring const& ring, RingOut & ring_out, T const& len, Strategy const& strategy) { densify ::apply(ring, ring_out, len, strategy); } }; template struct densify { template static void apply(Geometry const& mpoly, GeometryOut & mpoly_out, T const& len, Strategy const& strategy) { std::size_t count = boost::size(mpoly); range::resize(mpoly_out, count); for (std::size_t i = 0 ; i < count ; ++i) { apply_poly(range::at(mpoly, i), range::at(mpoly_out, i), len, strategy); } } template static void apply_poly(Poly const& poly, PolyOut & poly_out, T const& len, Strategy const& strategy) { densify:: apply(poly, poly_out, len, strategy); } }; } // namespace dispatch #endif // DOXYGEN_NO_DISPATCH namespace resolve_strategy { struct densify { template static inline void apply(Geometry const& geometry, Geometry& out, Distance const& max_distance, Strategy const& strategy) { dispatch::densify ::apply(geometry, out, max_distance, strategy); } template static inline void apply(Geometry const& geometry, Geometry& out, Distance const& max_distance, default_strategy) { typedef typename strategy::densify::services::default_strategy < typename cs_tag::type >::type strategy_type; /*BOOST_CONCEPT_ASSERT( (concepts::DensifyStrategy) );*/ apply(geometry, out, max_distance, strategy_type()); } }; } // namespace resolve_strategy namespace resolve_variant { template struct densify { template static inline void apply(Geometry const& geometry, Geometry& out, Distance const& max_distance, Strategy const& strategy) { resolve_strategy::densify::apply(geometry, out, max_distance, strategy); } }; template struct densify > { template struct visitor: boost::static_visitor { Distance const& m_max_distance; Strategy const& m_strategy; visitor(Distance const& max_distance, Strategy const& strategy) : m_max_distance(max_distance) , m_strategy(strategy) {} template void operator()(Geometry const& geometry, Geometry& out) const { densify::apply(geometry, out, m_max_distance, m_strategy); } }; template static inline void apply(boost::variant const& geometry, boost::variant& out, Distance const& max_distance, Strategy const& strategy) { boost::apply_visitor( visitor(max_distance, strategy), geometry, out ); } }; } // namespace resolve_variant /*! \brief Densify a geometry using a specified strategy \ingroup densify \tparam Geometry \tparam_geometry \tparam Distance A numerical distance measure \tparam Strategy A type fulfilling a DensifyStrategy concept \param geometry Input geometry, to be densified \param out Output geometry, densified version of the input geometry \param max_distance Distance threshold (in units depending on strategy) \param strategy Densify strategy to be used for densification \qbk{distinguish,with strategy} \qbk{[include reference/algorithms/densify.qbk]} \qbk{ [heading Available Strategies] \* [link geometry.reference.strategies.strategy_densify_cartesian Cartesian] \* [link geometry.reference.strategies.strategy_densify_spherical Spherical] \* [link geometry.reference.strategies.strategy_densify_geographic Geographic] [heading Example] [densify_strategy] [densify_strategy_output] [heading See also] \* [link geometry.reference.algorithms.line_interpolate line_interpolate] } */ template inline void densify(Geometry const& geometry, Geometry& out, Distance const& max_distance, Strategy const& strategy) { concepts::check(); if (max_distance <= Distance(0)) { BOOST_THROW_EXCEPTION(geometry::invalid_input_exception()); } geometry::clear(out); resolve_variant::densify < Geometry >::apply(geometry, out, max_distance, strategy); } /*! \brief Densify a geometry \ingroup densify \tparam Geometry \tparam_geometry \tparam Distance A numerical distance measure \param geometry Input geometry, to be densified \param out Output geometry, densified version of the input geometry \param max_distance Distance threshold (in units depending on coordinate system) \qbk{[include reference/algorithms/densify.qbk]} \qbk{ [heading Example] [densify] [densify_output] [heading See also] \* [link geometry.reference.algorithms.line_interpolate line_interpolate] } */ template inline void densify(Geometry const& geometry, Geometry& out, Distance const& max_distance) { densify(geometry, out, max_distance, default_strategy()); } }} // namespace boost::geometry #endif // BOOST_GEOMETRY_ALGORITHMS_DENSIFY_HPP